@lang-tag/cli 0.11.1 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config.d.ts CHANGED
@@ -99,9 +99,28 @@ export interface LangTagCLIConfig {
99
99
  * Allows dynamic modification of the tag's configuration (namespace, path, etc.)
100
100
  * based on the file path or other context.
101
101
  *
102
+ * **IMPORTANT:** The `event.config` object is deeply frozen and immutable. Any attempt
103
+ * to directly modify it will throw an error. To update the configuration, you must
104
+ * use `event.save(newConfig)` with a new configuration object.
105
+ *
102
106
  * Changes made inside this function are **applied only if you explicitly call**
103
107
  * `event.save(configuration)`. Returning a value or modifying the event object
104
108
  * without calling `save()` will **not** update the configuration.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * onConfigGeneration: async (event) => {
113
+ * // ❌ This will throw an error:
114
+ * // event.config.namespace = "new-namespace";
115
+ *
116
+ * // ✅ Correct way to update:
117
+ * event.save({
118
+ * ...event.config,
119
+ * namespace: "new-namespace",
120
+ * path: "new.path"
121
+ * });
122
+ * }
123
+ * ```
105
124
  */
106
125
  onConfigGeneration: (event: LangTagCLIConfigGenerationEvent) => Promise<void>;
107
126
  debug?: boolean;
@@ -163,14 +182,19 @@ export interface LangTagCLIConflict {
163
182
  }
164
183
  export interface LangTagCLIConfigGenerationEvent {
165
184
  /** The absolute path to the source file being processed. */
166
- absolutePath: string;
185
+ readonly absolutePath: string;
167
186
  /** The path of the source file relative to the project root (where the command was invoked). */
168
- relativePath: string;
187
+ readonly relativePath: string;
169
188
  /** True if the file being processed is located within the configured library import directory (`config.import.dir`). */
170
- isImportedLibrary: boolean;
171
- /** The configuration object extracted from the lang tag's options argument (e.g., `{ namespace: 'common', path: 'my.path' }`). */
172
- config: LangTagTranslationsConfig | undefined;
173
- langTagConfig: LangTagCLIConfig;
189
+ readonly isImportedLibrary: boolean;
190
+ /**
191
+ * The configuration object extracted from the lang tag's options argument (e.g., `{ namespace: 'common', path: 'my.path' }`).
192
+ *
193
+ * **This object is deeply frozen and immutable.** Any attempt to modify it will throw an error in strict mode.
194
+ * To update the configuration, use the `save()` method with a new configuration object.
195
+ */
196
+ readonly config: Readonly<LangTagTranslationsConfig> | undefined;
197
+ readonly langTagConfig: LangTagCLIConfig;
174
198
  /**
175
199
  * Tells CLI to replace tag configuration
176
200
  * undefined = means configuration will be removed
package/index.cjs CHANGED
@@ -168,7 +168,7 @@ class $LT_TagProcessor {
168
168
  replaceTags(fileContent, replacements) {
169
169
  const replaceMap = /* @__PURE__ */ new Map();
170
170
  replacements.forEach((R) => {
171
- if (!R.translations && !R.config) {
171
+ if (!R.translations && !R.config && R.config !== null) {
172
172
  throw new Error("Replacement data is required!");
173
173
  }
174
174
  const tag = R.tag;
@@ -182,7 +182,7 @@ class $LT_TagProcessor {
182
182
  throw new Error(`Tag translations are invalid object! Translations: ${newTranslationsString}`);
183
183
  }
184
184
  let newConfigString = R.config;
185
- if (!newConfigString) newConfigString = tag.parameterConfig;
185
+ if (!newConfigString && newConfigString !== null) newConfigString = tag.parameterConfig;
186
186
  if (newConfigString) {
187
187
  try {
188
188
  if (typeof newConfigString === "string") JSON5.parse(newConfigString);
@@ -426,6 +426,16 @@ function $LT_FilterEmptyNamespaceTags(tags, logger) {
426
426
  return true;
427
427
  });
428
428
  }
429
+ function deepFreezeObject(obj) {
430
+ const propNames = Object.getOwnPropertyNames(obj);
431
+ for (const name of propNames) {
432
+ const value = obj[name];
433
+ if (value && typeof value === "object") {
434
+ deepFreezeObject(value);
435
+ }
436
+ }
437
+ return Object.freeze(obj);
438
+ }
429
439
  async function checkAndRegenerateFileLangTags(config, logger, file, path$12) {
430
440
  let libraryImportsDir = config.import.dir;
431
441
  if (!libraryImportsDir.endsWith(path.sep)) libraryImportsDir += path.sep;
@@ -440,14 +450,15 @@ async function checkAndRegenerateFileLangTags(config, logger, file, path$12) {
440
450
  for (let tag of tags) {
441
451
  let newConfig = void 0;
442
452
  let shouldUpdate = false;
453
+ const frozenConfig = tag.parameterConfig ? deepFreezeObject(tag.parameterConfig) : tag.parameterConfig;
443
454
  await config.onConfigGeneration({
444
455
  langTagConfig: config,
445
- config: tag.parameterConfig,
456
+ config: frozenConfig,
446
457
  absolutePath: file,
447
458
  relativePath: path$12,
448
459
  isImportedLibrary: path$12.startsWith(libraryImportsDir),
449
460
  save: (updatedConfig) => {
450
- newConfig = updatedConfig;
461
+ newConfig = updatedConfig || null;
451
462
  shouldUpdate = true;
452
463
  }
453
464
  });
package/index.js CHANGED
@@ -148,7 +148,7 @@ class $LT_TagProcessor {
148
148
  replaceTags(fileContent, replacements) {
149
149
  const replaceMap = /* @__PURE__ */ new Map();
150
150
  replacements.forEach((R) => {
151
- if (!R.translations && !R.config) {
151
+ if (!R.translations && !R.config && R.config !== null) {
152
152
  throw new Error("Replacement data is required!");
153
153
  }
154
154
  const tag = R.tag;
@@ -162,7 +162,7 @@ class $LT_TagProcessor {
162
162
  throw new Error(`Tag translations are invalid object! Translations: ${newTranslationsString}`);
163
163
  }
164
164
  let newConfigString = R.config;
165
- if (!newConfigString) newConfigString = tag.parameterConfig;
165
+ if (!newConfigString && newConfigString !== null) newConfigString = tag.parameterConfig;
166
166
  if (newConfigString) {
167
167
  try {
168
168
  if (typeof newConfigString === "string") JSON5.parse(newConfigString);
@@ -406,6 +406,16 @@ function $LT_FilterEmptyNamespaceTags(tags, logger) {
406
406
  return true;
407
407
  });
408
408
  }
409
+ function deepFreezeObject(obj) {
410
+ const propNames = Object.getOwnPropertyNames(obj);
411
+ for (const name of propNames) {
412
+ const value = obj[name];
413
+ if (value && typeof value === "object") {
414
+ deepFreezeObject(value);
415
+ }
416
+ }
417
+ return Object.freeze(obj);
418
+ }
409
419
  async function checkAndRegenerateFileLangTags(config, logger, file, path2) {
410
420
  let libraryImportsDir = config.import.dir;
411
421
  if (!libraryImportsDir.endsWith(sep)) libraryImportsDir += sep;
@@ -420,14 +430,15 @@ async function checkAndRegenerateFileLangTags(config, logger, file, path2) {
420
430
  for (let tag of tags) {
421
431
  let newConfig = void 0;
422
432
  let shouldUpdate = false;
433
+ const frozenConfig = tag.parameterConfig ? deepFreezeObject(tag.parameterConfig) : tag.parameterConfig;
423
434
  await config.onConfigGeneration({
424
435
  langTagConfig: config,
425
- config: tag.parameterConfig,
436
+ config: frozenConfig,
426
437
  absolutePath: file,
427
438
  relativePath: path2,
428
439
  isImportedLibrary: path2.startsWith(libraryImportsDir),
429
440
  save: (updatedConfig) => {
430
- newConfig = updatedConfig;
441
+ newConfig = updatedConfig || null;
431
442
  shouldUpdate = true;
432
443
  }
433
444
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lang-tag/cli",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"