From ca1a921551cbad34ba5bda89957d5648c35d7389 Mon Sep 17 00:00:00 2001 From: maxprilutskiy Date: Fri, 23 Aug 2024 16:49:17 +0200 Subject: [PATCH 1/2] feat: add support for `.properties` files --- .changeset/large-bees-pull.md | 7 +++ packages/cli/package.json | 4 ++ packages/cli/src/workers/bucket/v2/index.ts | 7 +++ .../cli/src/workers/bucket/v2/properties.ts | 18 ++++++++ packages/spec/src/formats.ts | 1 + pnpm-lock.yaml | 45 +++++++++++++++++++ 6 files changed, 82 insertions(+) create mode 100644 .changeset/large-bees-pull.md create mode 100644 packages/cli/src/workers/bucket/v2/properties.ts diff --git a/.changeset/large-bees-pull.md b/.changeset/large-bees-pull.md new file mode 100644 index 000000000..3962b9ff0 --- /dev/null +++ b/.changeset/large-bees-pull.md @@ -0,0 +1,7 @@ +--- +"@replexica/spec": minor +"@replexica/cli": minor +"replexica": minor +--- + +Added support for .properties file diff --git a/packages/cli/package.json b/packages/cli/package.json index 37deca626..ef01d1960 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -37,6 +37,8 @@ "open": "^10.1.0", "ora": "^8.0.1", "p-limit": "^6.1.0", + "properties-parser": "^0.6.0", + "properties-reader": "^2.3.0", "slugify": "^1.6.6", "typescript": "^5.4.5", "vitest": "^2.0.0", @@ -53,6 +55,8 @@ "@types/markdown-it": "^14.1.2", "@types/node": "^20.14.10", "@types/object-hash": "^3.0.6", + "@types/properties-parser": "^0.3.3", + "@types/properties-reader": "^2.1.3", "@types/xml2js": "^0.4.14", "tsup": "^8.1.0" } diff --git a/packages/cli/src/workers/bucket/v2/index.ts b/packages/cli/src/workers/bucket/v2/index.ts index c612fcb2d..1cf910448 100644 --- a/packages/cli/src/workers/bucket/v2/index.ts +++ b/packages/cli/src/workers/bucket/v2/index.ts @@ -12,6 +12,7 @@ import { rootKeyLoader } from './root-key'; import { markdownLoader } from './markdown'; import { xcodeLoader } from './xcode'; import { androidLoader } from './android'; +import { propertiesLoader } from './properties'; // Path expansion export function expandPlaceholderedGlob(pathPattern: string, sourceLocale: string): string[] { @@ -126,5 +127,11 @@ export function createBucketLoader(params: CreateBucketLoaderParams) { jsonLoader(), flatLoader(), ); + case 'properties': + return composeLoaders>( + textLoader(filepath), + propertiesLoader(), + flatLoader(), + ); } } diff --git a/packages/cli/src/workers/bucket/v2/properties.ts b/packages/cli/src/workers/bucket/v2/properties.ts new file mode 100644 index 000000000..5b69a40c2 --- /dev/null +++ b/packages/cli/src/workers/bucket/v2/properties.ts @@ -0,0 +1,18 @@ +import { parse, createEditor, read } from 'properties-parser'; +import { BucketLoader } from './_base'; + +export const propertiesLoader = (): BucketLoader> => ({ + async load(text: string) { + return parse(text || ''); + }, + async save(payload) { + const editor = createEditor(); + + // Update or add new key-value pairs + for (const [key, value] of Object.entries(payload)) { + editor.set(key, value); + } + + return editor.toString(); + } +}); diff --git a/packages/spec/src/formats.ts b/packages/spec/src/formats.ts index 426ac40ce..a7d02affc 100644 --- a/packages/spec/src/formats.ts +++ b/packages/spec/src/formats.ts @@ -8,6 +8,7 @@ export const bucketTypes = [ 'yaml-root-key', 'xcode', 'android', + 'properties', ] as const; export const bucketTypeSchema = Z.enum(bucketTypes); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a24a9dfc..f29f783cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,6 +149,12 @@ importers: p-limit: specifier: ^6.1.0 version: 6.1.0 + properties-parser: + specifier: ^0.6.0 + version: 0.6.0 + properties-reader: + specifier: ^2.3.0 + version: 2.3.0 slugify: specifier: ^1.6.6 version: 1.6.6 @@ -192,6 +198,12 @@ importers: '@types/object-hash': specifier: ^3.0.6 version: 3.0.6 + '@types/properties-parser': + specifier: ^0.3.3 + version: 0.3.3 + '@types/properties-reader': + specifier: ^2.1.3 + version: 2.1.3 '@types/xml2js': specifier: ^0.4.14 version: 0.4.14 @@ -1202,6 +1214,12 @@ packages: '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + '@types/properties-parser@0.3.3': + resolution: {integrity: sha512-VZhGpE+QQ2JNbaY4B4Y2iM/jdUsq3HO75uBKLk07VT6P2Kg1aifeYL6I3RosFniSdAb4PtuH5UaY8jXU7JeIYA==} + + '@types/properties-reader@2.1.3': + resolution: {integrity: sha512-k4fBDScfZ9xQjIrZm0HcJlyWVZ5ltE9W8N2AIecsgFXfg5REhKKHEwmpRvSQvEPWnIEsL67K70P1tx7kGo+cjQ==} + '@types/qs@6.9.14': resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==} @@ -2613,6 +2631,11 @@ packages: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -2917,6 +2940,14 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + properties-parser@0.6.0: + resolution: {integrity: sha512-qvr2cSmoA0dln0MARAKwBzPkkXn7FqwX+RVVNpMdMJc7rt9mqO2cXwluxtux9fHrLhjnPFaQkS8BM0kFrTCnSw==} + engines: {node: '>= 0.3.1'} + + properties-reader@2.3.0: + resolution: {integrity: sha512-z597WicA7nDZxK12kZqHr2TcvwNU1GCfA5UwfDY/HDp3hXPoPlb5rlEx9bwGTiJnc0OqbBTkU975jDToth8Gxw==} + engines: {node: '>=14'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4669,6 +4700,12 @@ snapshots: '@types/prop-types@15.7.12': {} + '@types/properties-parser@0.3.3': + dependencies: + '@types/node': 20.14.10 + + '@types/properties-reader@2.1.3': {} + '@types/qs@6.9.14': {} '@types/range-parser@1.2.7': {} @@ -6155,6 +6192,8 @@ snapshots: mixme@0.5.10: {} + mkdirp@1.0.4: {} + ms@2.0.0: {} ms@2.1.2: {} @@ -6428,6 +6467,12 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + properties-parser@0.6.0: {} + + properties-reader@2.3.0: + dependencies: + mkdirp: 1.0.4 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 From 3bf0a7b555b5c8f09c917b7f0391ab420f171a02 Mon Sep 17 00:00:00 2001 From: maxprilutskiy Date: Fri, 23 Aug 2024 16:52:15 +0200 Subject: [PATCH 2/2] feat: add tests --- packages/cli/package.json | 2 - .../src/workers/bucket/v2/properties.spec.ts | 46 +++++++++++++++++++ .../cli/src/workers/bucket/v2/properties.ts | 2 +- pnpm-lock.yaml | 26 ----------- 4 files changed, 47 insertions(+), 29 deletions(-) create mode 100644 packages/cli/src/workers/bucket/v2/properties.spec.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index ef01d1960..5ef566184 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -38,7 +38,6 @@ "ora": "^8.0.1", "p-limit": "^6.1.0", "properties-parser": "^0.6.0", - "properties-reader": "^2.3.0", "slugify": "^1.6.6", "typescript": "^5.4.5", "vitest": "^2.0.0", @@ -56,7 +55,6 @@ "@types/node": "^20.14.10", "@types/object-hash": "^3.0.6", "@types/properties-parser": "^0.3.3", - "@types/properties-reader": "^2.1.3", "@types/xml2js": "^0.4.14", "tsup": "^8.1.0" } diff --git a/packages/cli/src/workers/bucket/v2/properties.spec.ts b/packages/cli/src/workers/bucket/v2/properties.spec.ts new file mode 100644 index 000000000..c86eb32e3 --- /dev/null +++ b/packages/cli/src/workers/bucket/v2/properties.spec.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from 'vitest'; +import { propertiesLoader } from './properties'; // Adjust the import path as needed + +describe('propertiesLoader', () => { + const loader = propertiesLoader(); + + const sampleProperties = ` +# General messages +welcome.message=Welcome to our application! +error.message=An error has occurred. Please try again later. + +# User-related messages +user.login=Please enter your username and password. +user.username=Username +user.password=Password + `.trim(); + + it('should load properties correctly', async () => { + const result = await loader.load(sampleProperties); + expect(result).toEqual({ + 'welcome.message': 'Welcome to our application!', + 'error.message': 'An error has occurred. Please try again later.', + 'user.login': 'Please enter your username and password.', + 'user.username': 'Username', + 'user.password': 'Password' + }); + }); + + it('should save properties correctly', async () => { + const input = { + 'app.name': 'My App', + 'app.version': '1.0.0', + 'user.greeting': 'Hello, {0}!' + }; + + const result = await loader.save(input); + expect(result).toContain('app.name=My App'); + expect(result).toContain('app.version=1.0.0'); + expect(result).toContain('user.greeting=Hello, {0}!'); + }); + + it('should handle empty input when loading', async () => { + const result = await loader.load(''); + expect(result).toEqual({}); + }); +}); diff --git a/packages/cli/src/workers/bucket/v2/properties.ts b/packages/cli/src/workers/bucket/v2/properties.ts index 5b69a40c2..948c3a650 100644 --- a/packages/cli/src/workers/bucket/v2/properties.ts +++ b/packages/cli/src/workers/bucket/v2/properties.ts @@ -1,4 +1,4 @@ -import { parse, createEditor, read } from 'properties-parser'; +import { parse, createEditor } from 'properties-parser'; import { BucketLoader } from './_base'; export const propertiesLoader = (): BucketLoader> => ({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f29f783cf..9975c3c2d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,9 +152,6 @@ importers: properties-parser: specifier: ^0.6.0 version: 0.6.0 - properties-reader: - specifier: ^2.3.0 - version: 2.3.0 slugify: specifier: ^1.6.6 version: 1.6.6 @@ -201,9 +198,6 @@ importers: '@types/properties-parser': specifier: ^0.3.3 version: 0.3.3 - '@types/properties-reader': - specifier: ^2.1.3 - version: 2.1.3 '@types/xml2js': specifier: ^0.4.14 version: 0.4.14 @@ -1217,9 +1211,6 @@ packages: '@types/properties-parser@0.3.3': resolution: {integrity: sha512-VZhGpE+QQ2JNbaY4B4Y2iM/jdUsq3HO75uBKLk07VT6P2Kg1aifeYL6I3RosFniSdAb4PtuH5UaY8jXU7JeIYA==} - '@types/properties-reader@2.1.3': - resolution: {integrity: sha512-k4fBDScfZ9xQjIrZm0HcJlyWVZ5ltE9W8N2AIecsgFXfg5REhKKHEwmpRvSQvEPWnIEsL67K70P1tx7kGo+cjQ==} - '@types/qs@6.9.14': resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==} @@ -2631,11 +2622,6 @@ packages: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -2944,10 +2930,6 @@ packages: resolution: {integrity: sha512-qvr2cSmoA0dln0MARAKwBzPkkXn7FqwX+RVVNpMdMJc7rt9mqO2cXwluxtux9fHrLhjnPFaQkS8BM0kFrTCnSw==} engines: {node: '>= 0.3.1'} - properties-reader@2.3.0: - resolution: {integrity: sha512-z597WicA7nDZxK12kZqHr2TcvwNU1GCfA5UwfDY/HDp3hXPoPlb5rlEx9bwGTiJnc0OqbBTkU975jDToth8Gxw==} - engines: {node: '>=14'} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4704,8 +4686,6 @@ snapshots: dependencies: '@types/node': 20.14.10 - '@types/properties-reader@2.1.3': {} - '@types/qs@6.9.14': {} '@types/range-parser@1.2.7': {} @@ -6192,8 +6172,6 @@ snapshots: mixme@0.5.10: {} - mkdirp@1.0.4: {} - ms@2.0.0: {} ms@2.1.2: {} @@ -6469,10 +6447,6 @@ snapshots: properties-parser@0.6.0: {} - properties-reader@2.3.0: - dependencies: - mkdirp: 1.0.4 - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0