@dialexjs/cli 0.9.1 → 0.9.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.
@@ -1,8 +1,8 @@
1
- import fs from "node:fs";
2
1
  import path from "node:path";
3
2
  import pc from "picocolors";
4
- import { pathToFileURL } from "node:url";
3
+ import fs from "node:fs";
5
4
  import { generateCode, parseExpression, parseModule, writeFile } from "magicast";
5
+ import { pathToFileURL } from "node:url";
6
6
  import fg from "fast-glob";
7
7
  import ignore from "ignore";
8
8
  import { argumentSignature, findPlurals, getArguments, isIcuStructured, parseMessage } from "dialexjs/icu";
@@ -10,6 +10,9 @@ import { createHash } from "node:crypto";
10
10
  import { DEFAULT_CONFIG } from "dialexjs";
11
11
  import { loadConfigSync } from "unconfig";
12
12
  import chokidar from "chokidar";
13
+ //#region src/utils/dictionary/types.ts
14
+ const TODO_PREFIX = "[TODO] ";
15
+ //#endregion
13
16
  //#region src/utils/ast.ts
14
17
  /** Strips `as`, `satisfies` and parentheses around an expression. */
15
18
  function unwrapNode(node) {
@@ -31,8 +34,7 @@ function findProperty(obj, key) {
31
34
  return obj.properties.find((p) => isPropLike$1(p) && propertyKeyName(p) === key);
32
35
  }
33
36
  //#endregion
34
- //#region src/utils/dictionary-edit.ts
35
- const TODO_PREFIX = "[TODO] ";
37
+ //#region src/utils/dictionary/ast-helpers.ts
36
38
  const IDENTIFIER$1 = /^[A-Za-z_$][\w$]*$/;
37
39
  const isPropLike = (p) => p?.type === "ObjectProperty" || p?.type === "Property" || p?.type === "ObjectMethod";
38
40
  function stringValue(node) {
@@ -99,6 +101,8 @@ function isStaticallyComplete(localesObj) {
99
101
  return isObjectNode(value) && walk(value);
100
102
  });
101
103
  }
104
+ //#endregion
105
+ //#region src/utils/dictionary/io.ts
102
106
  /**
103
107
  * Parses dictionary source text (for example an unsaved editor buffer). Returns `undefined` when
104
108
  * the file does not have an editable shape; throws on syntax errors.
@@ -134,6 +138,8 @@ async function saveDictionaryFile(df) {
134
138
  if (!text.endsWith("\n")) fs.writeFileSync(df.file, text + "\n", "utf-8");
135
139
  }
136
140
  }
141
+ //#endregion
142
+ //#region src/utils/dictionary/read.ts
137
143
  function listLocales(df) {
138
144
  return df.localesObj.properties.filter(isPropLike).map(propertyKeyName).filter((k) => k !== void 0);
139
145
  }
@@ -184,6 +190,13 @@ function getString(df, locale, path) {
184
190
  const prop = getProp(df, locale, path);
185
191
  return prop && prop.type !== "ObjectMethod" ? stringValue(prop.value) : void 0;
186
192
  }
193
+ /** Leaf paths of a runtime dictionary value (plain objects recurse; everything else is a leaf). */
194
+ function flattenPaths(value, prefix = []) {
195
+ if (value && typeof value === "object" && !Array.isArray(value)) return Object.entries(value).flatMap(([k, v]) => flattenPaths(v, [...prefix, k]));
196
+ return prefix.length > 0 ? [prefix] : [];
197
+ }
198
+ //#endregion
199
+ //#region src/utils/dictionary/write.ts
187
200
  function ensureLocale(df, locale) {
188
201
  let obj = localeObject(df, locale);
189
202
  if (!obj) {
@@ -245,11 +258,8 @@ function copyLeaf(df, fromLocale, toLocale, path, mapString) {
245
258
  }
246
259
  return true;
247
260
  }
248
- /** Leaf paths of a runtime dictionary value (plain objects recurse; everything else is a leaf). */
249
- function flattenPaths(value, prefix = []) {
250
- if (value && typeof value === "object" && !Array.isArray(value)) return Object.entries(value).flatMap(([k, v]) => flattenPaths(v, [...prefix, k]));
251
- return prefix.length > 0 ? [prefix] : [];
252
- }
261
+ //#endregion
262
+ //#region src/utils/dictionary/locations.ts
253
263
  const toRange = (loc) => loc ? {
254
264
  start: {
255
265
  line: loc.start.line - 1,
@@ -279,6 +289,153 @@ function getLeafSource(df, locale, path) {
279
289
  return generateCode(prop.type === "ObjectMethod" ? prop : prop.value).code;
280
290
  }
281
291
  //#endregion
292
+ //#region src/analysis/cache.ts
293
+ function createAnalysisCache() {
294
+ return {
295
+ dictionaries: /* @__PURE__ */ new Map(),
296
+ sources: /* @__PURE__ */ new Map(),
297
+ gitignore: /* @__PURE__ */ new Map()
298
+ };
299
+ }
300
+ /** Forget the cached `.gitignore` rules, for example after a `.gitignore` file changed. */
301
+ function clearGitignore(cache) {
302
+ cache.gitignore.clear();
303
+ }
304
+ function stampOf(file) {
305
+ try {
306
+ const stat = fs.statSync(file);
307
+ return `${stat.mtimeMs}:${stat.size}`;
308
+ } catch {
309
+ return;
310
+ }
311
+ }
312
+ //#endregion
313
+ //#region src/analysis/load-dictionary.ts
314
+ function fromSyntaxTree(df) {
315
+ const locales = listLocales(df);
316
+ const leaves = /* @__PURE__ */ new Map();
317
+ for (const locale of locales) {
318
+ const entries = /* @__PURE__ */ new Map();
319
+ for (const leaf of listLeaves(df, locale)) entries.set(leaf.path.join("."), {
320
+ kind: leaf.kind,
321
+ value: leaf.value
322
+ });
323
+ leaves.set(locale, entries);
324
+ }
325
+ return {
326
+ name: df.name,
327
+ locales,
328
+ leaves,
329
+ df
330
+ };
331
+ }
332
+ async function fromRuntime(file) {
333
+ try {
334
+ const mod = await import(`${pathToFileURL(file).href}?t=${Date.now()}_${Math.random()}`);
335
+ const definition = mod.default || mod;
336
+ if (!definition || typeof definition !== "object" || !definition.dictionary) return {
337
+ ok: false,
338
+ level: "error",
339
+ code: "invalid-dictionary",
340
+ message: "Default export does not appear to be a valid defineDictionary output."
341
+ };
342
+ const dictionary = definition.dictionary;
343
+ const leaves = /* @__PURE__ */ new Map();
344
+ const invalid = [];
345
+ for (const [locale, content] of Object.entries(dictionary)) {
346
+ if (!content || typeof content !== "object") {
347
+ invalid.push(locale);
348
+ continue;
349
+ }
350
+ const entries = /* @__PURE__ */ new Map();
351
+ for (const leafPath of flattenPaths(content)) {
352
+ let value = content;
353
+ for (const segment of leafPath) value = value?.[segment];
354
+ entries.set(leafPath.join("."), typeof value === "string" ? {
355
+ kind: "string",
356
+ value
357
+ } : { kind: typeof value === "function" ? "function" : "other" });
358
+ }
359
+ leaves.set(locale, entries);
360
+ }
361
+ if (invalid.length > 0) return {
362
+ ok: false,
363
+ level: "error",
364
+ code: "invalid-locale",
365
+ message: invalid.map((l) => `Locale "${l}" content is empty or invalid.`).join("\n")
366
+ };
367
+ return {
368
+ ok: true,
369
+ data: {
370
+ name: String(definition.name ?? ""),
371
+ locales: [...leaves.keys()],
372
+ leaves
373
+ }
374
+ };
375
+ } catch (error) {
376
+ return {
377
+ ok: false,
378
+ level: "error",
379
+ code: "invalid-dictionary",
380
+ message: `Failed to import dictionary: ${error.message || String(error)}`
381
+ };
382
+ }
383
+ }
384
+ function fromParsed(parsed) {
385
+ try {
386
+ const df = parsed();
387
+ if (df?.complete && df.name) return {
388
+ ok: true,
389
+ data: fromSyntaxTree(df)
390
+ };
391
+ } catch (error) {
392
+ return {
393
+ ok: false,
394
+ level: "error",
395
+ code: "invalid-dictionary",
396
+ message: `Failed to parse dictionary: ${error.message}`
397
+ };
398
+ }
399
+ }
400
+ const UNANALYZABLE = {
401
+ ok: false,
402
+ level: "info",
403
+ code: "unanalyzable",
404
+ message: "This dictionary uses spreads, computed keys, imported values, or a computed name, so it cannot be analyzed statically."
405
+ };
406
+ /** Reads a dictionary from its syntax tree. Never runs project code. */
407
+ function loadDictionaryDataStatic(file) {
408
+ return fromParsed(() => parseDictionaryText(file, fs.readFileSync(file, "utf-8"))) ?? UNANALYZABLE;
409
+ }
410
+ async function loadDictionaryData(file, runtime) {
411
+ const parsed = fromParsed(() => parseDictionaryText(file, fs.readFileSync(file, "utf-8")));
412
+ if (parsed?.ok) return parsed;
413
+ if (runtime) return fromRuntime(file);
414
+ return parsed ?? UNANALYZABLE;
415
+ }
416
+ async function cachedDictionary(file, runtime, cache) {
417
+ const stamp = cache ? stampOf(file) : void 0;
418
+ const hit = stamp ? cache.dictionaries.get(file) : void 0;
419
+ if (hit && hit.stamp === stamp) return hit.loaded;
420
+ const loaded = await loadDictionaryData(file, runtime);
421
+ if (cache && stamp) cache.dictionaries.set(file, {
422
+ stamp,
423
+ loaded
424
+ });
425
+ return loaded;
426
+ }
427
+ function cachedDictionaryStatic(file, cache) {
428
+ const stamp = cache ? stampOf(file) : void 0;
429
+ const hit = stamp ? cache.dictionaries.get(file) : void 0;
430
+ if (hit && hit.stamp === stamp) return hit.loaded;
431
+ const loaded = loadDictionaryDataStatic(file);
432
+ if (cache && stamp) cache.dictionaries.set(file, {
433
+ stamp,
434
+ loaded
435
+ });
436
+ return loaded;
437
+ }
438
+ //#endregion
282
439
  //#region src/utils/files.ts
283
440
  /** Folders that never hold project dictionaries or sources, in every scanner. */
284
441
  const BUILTIN_IGNORE = [
@@ -523,22 +680,7 @@ function lockFor(root, sourceLocale) {
523
680
  };
524
681
  }
525
682
  //#endregion
526
- //#region src/analysis.ts
527
- function lintLevel(setting) {
528
- const level = Array.isArray(setting) ? setting[0] : setting;
529
- return level === "off" || level === "warn" || level === "error" ? level : void 0;
530
- }
531
- function createAnalysisCache() {
532
- return {
533
- dictionaries: /* @__PURE__ */ new Map(),
534
- sources: /* @__PURE__ */ new Map(),
535
- gitignore: /* @__PURE__ */ new Map()
536
- };
537
- }
538
- /** Forget the cached `.gitignore` rules, for example after a `.gitignore` file changed. */
539
- function clearGitignore(cache) {
540
- cache.gitignore.clear();
541
- }
683
+ //#region src/analysis/source-scan.ts
542
684
  const DEFAULT_SOURCE_GLOB = "**/*.{ts,tsx,js,jsx,mjs,cjs,vue,svelte,astro,mdx}";
543
685
  /** `getDictionary("x")`, `useDictionary("x")`, `@DialexDictionary("x")` */
544
686
  const DICTIONARY_CALL = /\b(?:getDictionary|useDictionary|DialexDictionary)\(\s*(["'`])([^"'`$\n]+)\1/dg;
@@ -694,138 +836,6 @@ function positionAt(starts, offset) {
694
836
  column: offset - starts[low]
695
837
  };
696
838
  }
697
- function fromSyntaxTree(df) {
698
- const locales = listLocales(df);
699
- const leaves = /* @__PURE__ */ new Map();
700
- for (const locale of locales) {
701
- const entries = /* @__PURE__ */ new Map();
702
- for (const leaf of listLeaves(df, locale)) entries.set(leaf.path.join("."), {
703
- kind: leaf.kind,
704
- value: leaf.value
705
- });
706
- leaves.set(locale, entries);
707
- }
708
- return {
709
- name: df.name,
710
- locales,
711
- leaves,
712
- df
713
- };
714
- }
715
- async function fromRuntime(file) {
716
- try {
717
- const mod = await import(`${pathToFileURL(file).href}?t=${Date.now()}_${Math.random()}`);
718
- const definition = mod.default || mod;
719
- if (!definition || typeof definition !== "object" || !definition.dictionary) return {
720
- ok: false,
721
- level: "error",
722
- code: "invalid-dictionary",
723
- message: "Default export does not appear to be a valid defineDictionary output."
724
- };
725
- const dictionary = definition.dictionary;
726
- const leaves = /* @__PURE__ */ new Map();
727
- const invalid = [];
728
- for (const [locale, content] of Object.entries(dictionary)) {
729
- if (!content || typeof content !== "object") {
730
- invalid.push(locale);
731
- continue;
732
- }
733
- const entries = /* @__PURE__ */ new Map();
734
- for (const leafPath of flattenPaths(content)) {
735
- let value = content;
736
- for (const segment of leafPath) value = value?.[segment];
737
- entries.set(leafPath.join("."), typeof value === "string" ? {
738
- kind: "string",
739
- value
740
- } : { kind: typeof value === "function" ? "function" : "other" });
741
- }
742
- leaves.set(locale, entries);
743
- }
744
- if (invalid.length > 0) return {
745
- ok: false,
746
- level: "error",
747
- code: "invalid-locale",
748
- message: invalid.map((l) => `Locale "${l}" content is empty or invalid.`).join("\n")
749
- };
750
- return {
751
- ok: true,
752
- data: {
753
- name: String(definition.name ?? ""),
754
- locales: [...leaves.keys()],
755
- leaves
756
- }
757
- };
758
- } catch (error) {
759
- return {
760
- ok: false,
761
- level: "error",
762
- code: "invalid-dictionary",
763
- message: `Failed to import dictionary: ${error.message || String(error)}`
764
- };
765
- }
766
- }
767
- function fromParsed(parsed) {
768
- try {
769
- const df = parsed();
770
- if (df?.complete && df.name) return {
771
- ok: true,
772
- data: fromSyntaxTree(df)
773
- };
774
- } catch (error) {
775
- return {
776
- ok: false,
777
- level: "error",
778
- code: "invalid-dictionary",
779
- message: `Failed to parse dictionary: ${error.message}`
780
- };
781
- }
782
- }
783
- const UNANALYZABLE = {
784
- ok: false,
785
- level: "info",
786
- code: "unanalyzable",
787
- message: "This dictionary uses spreads, computed keys, imported values, or a computed name, so it cannot be analyzed statically."
788
- };
789
- /** Reads a dictionary from its syntax tree. Never runs project code. */
790
- function loadDictionaryDataStatic(file) {
791
- return fromParsed(() => parseDictionaryText(file, fs.readFileSync(file, "utf-8"))) ?? UNANALYZABLE;
792
- }
793
- async function loadDictionaryData(file, runtime) {
794
- const parsed = fromParsed(() => parseDictionaryText(file, fs.readFileSync(file, "utf-8")));
795
- if (parsed?.ok) return parsed;
796
- if (runtime) return fromRuntime(file);
797
- return parsed ?? UNANALYZABLE;
798
- }
799
- function stampOf(file) {
800
- try {
801
- const stat = fs.statSync(file);
802
- return `${stat.mtimeMs}:${stat.size}`;
803
- } catch {
804
- return;
805
- }
806
- }
807
- async function cachedDictionary(file, runtime, cache) {
808
- const stamp = cache ? stampOf(file) : void 0;
809
- const hit = stamp ? cache.dictionaries.get(file) : void 0;
810
- if (hit && hit.stamp === stamp) return hit.loaded;
811
- const loaded = await loadDictionaryData(file, runtime);
812
- if (cache && stamp) cache.dictionaries.set(file, {
813
- stamp,
814
- loaded
815
- });
816
- return loaded;
817
- }
818
- function cachedDictionaryStatic(file, cache) {
819
- const stamp = cache ? stampOf(file) : void 0;
820
- const hit = stamp ? cache.dictionaries.get(file) : void 0;
821
- if (hit && hit.stamp === stamp) return hit.loaded;
822
- const loaded = loadDictionaryDataStatic(file);
823
- if (cache && stamp) cache.dictionaries.set(file, {
824
- stamp,
825
- loaded
826
- });
827
- return loaded;
828
- }
829
839
  function scanSource(text) {
830
840
  const starts = lineStarts(text);
831
841
  const rangeOf = (start, end) => ({
@@ -842,6 +852,12 @@ function scanSource(text) {
842
852
  inline
843
853
  };
844
854
  }
855
+ //#endregion
856
+ //#region src/analysis/steps.ts
857
+ function lintLevel(setting) {
858
+ const level = Array.isArray(setting) ? setting[0] : setting;
859
+ return level === "off" || level === "warn" || level === "error" ? level : void 0;
860
+ }
845
861
  /**
846
862
  * The analysis itself, written once. It yields a `LoadRequest` for every dictionary so that a
847
863
  * synchronous driver (`analyzeProjectSync`) and an asynchronous one (`analyzeProject`, which may
@@ -1086,6 +1102,8 @@ function* analysisSteps(options) {
1086
1102
  inlineDictionaries: [...inline]
1087
1103
  };
1088
1104
  }
1105
+ //#endregion
1106
+ //#region src/analysis/index.ts
1089
1107
  /** Analyzes a project. With `runtime: true`, dictionaries the syntax tree cannot describe are imported. */
1090
1108
  async function analyzeProject(options) {
1091
1109
  const steps = analysisSteps(options);
@@ -1721,7 +1739,7 @@ function relativeImportExtension(root) {
1721
1739
  return resolution === "node16" || resolution === "nodenext" ? ".js" : "";
1722
1740
  }
1723
1741
  //#endregion
1724
- //#region src/commands/generate.ts
1742
+ //#region src/commands/generate/render.ts
1725
1743
  /** The folder, next to `dialex.generated.ts`, that holds the per-locale modules. */
1726
1744
  const LOCALES_DIR = "dialex.locales";
1727
1745
  const safeName = (text) => text.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -1841,6 +1859,58 @@ export default dictionaries;
1841
1859
  notes
1842
1860
  };
1843
1861
  }
1862
+ //#endregion
1863
+ //#region src/commands/generate/watch.ts
1864
+ const WATCH_IGNORED = /(^|[\\/])(node_modules|dist|\.next|\.nuxt|\.output|\.turbo|\.git|dialex\.locales)([\\/]|$)/;
1865
+ const CONFIG_FILE = /(^|[\\/])(dialex|i18n)\.config\.[cm]?[jt]s(on)?$/;
1866
+ /**
1867
+ * Regenerates when a dictionary or config file is added, edited or removed. chokidar 4+ no longer
1868
+ * understands globs, so this watches the project directory and decides for itself which events
1869
+ * matter, using the same `include` glob as `generate`.
1870
+ */
1871
+ function startGenerateWatcher(root, options, regenerate, delay = 100, log = (message) => logger.info(message)) {
1872
+ const dictionaryFiles = () => new Set(renderGenerated(root, options).files);
1873
+ let known = dictionaryFiles();
1874
+ let outputs = /* @__PURE__ */ new Set();
1875
+ let timer;
1876
+ const trigger = () => {
1877
+ if (timer) clearTimeout(timer);
1878
+ timer = setTimeout(() => {
1879
+ regenerate();
1880
+ try {
1881
+ known = dictionaryFiles();
1882
+ const rendered = renderGenerated(root, options);
1883
+ outputs = /* @__PURE__ */ new Set([rendered.outputPath, rendered.dtsPath]);
1884
+ } catch {}
1885
+ }, delay);
1886
+ };
1887
+ const gitIgnored = createGitignoreFilter(root);
1888
+ const watcher = chokidar.watch(root, {
1889
+ ignoreInitial: true,
1890
+ ignored: (file) => WATCH_IGNORED.test(file) || gitIgnored(path.resolve(root, file))
1891
+ });
1892
+ watcher.on("all", (event, filePath) => {
1893
+ const file = path.resolve(root, filePath);
1894
+ if (outputs.has(file)) return;
1895
+ const isConfig = CONFIG_FILE.test(file);
1896
+ if (event === "change") {
1897
+ if (!known.has(file) && !isConfig) return;
1898
+ } else if (event === "add" || event === "unlink") {
1899
+ let now;
1900
+ try {
1901
+ now = dictionaryFiles();
1902
+ } catch {
1903
+ return;
1904
+ }
1905
+ if (!(now.size !== known.size || [...now].some((f) => !known.has(f))) && !isConfig) return;
1906
+ } else return;
1907
+ log(`[${event}] ${path.relative(root, file)} changed, regenerating...`);
1908
+ trigger();
1909
+ });
1910
+ return watcher;
1911
+ }
1912
+ //#endregion
1913
+ //#region src/commands/generate/write.ts
1844
1914
  function writeIfChanged(file, content) {
1845
1915
  if ((fs.existsSync(file) ? fs.readFileSync(file, "utf-8") : "") === content) return;
1846
1916
  fs.mkdirSync(path.dirname(file), { recursive: true });
@@ -1868,6 +1938,8 @@ function generateDictionaries(root, options = {}) {
1868
1938
  notes: rendered.notes
1869
1939
  };
1870
1940
  }
1941
+ //#endregion
1942
+ //#region src/commands/generate/index.ts
1871
1943
  async function runGenerate(options = {}) {
1872
1944
  const root = options.cwd || process.cwd();
1873
1945
  const quiet = options.json === true;
@@ -1904,54 +1976,6 @@ async function runGenerate(options = {}) {
1904
1976
  startGenerateWatcher(root, options, doGenerate);
1905
1977
  }
1906
1978
  }
1907
- const WATCH_IGNORED = /(^|[\\/])(node_modules|dist|\.next|\.nuxt|\.output|\.turbo|\.git|dialex\.locales)([\\/]|$)/;
1908
- const CONFIG_FILE = /(^|[\\/])(dialex|i18n)\.config\.[cm]?[jt]s(on)?$/;
1909
- /**
1910
- * Regenerates when a dictionary or config file is added, edited or removed. chokidar 4+ no longer
1911
- * understands globs, so this watches the project directory and decides for itself which events
1912
- * matter, using the same `include` glob as `generate`.
1913
- */
1914
- function startGenerateWatcher(root, options, regenerate, delay = 100, log = (message) => logger.info(message)) {
1915
- const dictionaryFiles = () => new Set(renderGenerated(root, options).files);
1916
- let known = dictionaryFiles();
1917
- let outputs = /* @__PURE__ */ new Set();
1918
- let timer;
1919
- const trigger = () => {
1920
- if (timer) clearTimeout(timer);
1921
- timer = setTimeout(() => {
1922
- regenerate();
1923
- try {
1924
- known = dictionaryFiles();
1925
- const rendered = renderGenerated(root, options);
1926
- outputs = /* @__PURE__ */ new Set([rendered.outputPath, rendered.dtsPath]);
1927
- } catch {}
1928
- }, delay);
1929
- };
1930
- const gitIgnored = createGitignoreFilter(root);
1931
- const watcher = chokidar.watch(root, {
1932
- ignoreInitial: true,
1933
- ignored: (file) => WATCH_IGNORED.test(file) || gitIgnored(path.resolve(root, file))
1934
- });
1935
- watcher.on("all", (event, filePath) => {
1936
- const file = path.resolve(root, filePath);
1937
- if (outputs.has(file)) return;
1938
- const isConfig = CONFIG_FILE.test(file);
1939
- if (event === "change") {
1940
- if (!known.has(file) && !isConfig) return;
1941
- } else if (event === "add" || event === "unlink") {
1942
- let now;
1943
- try {
1944
- now = dictionaryFiles();
1945
- } catch {
1946
- return;
1947
- }
1948
- if (!(now.size !== known.size || [...now].some((f) => !known.has(f))) && !isConfig) return;
1949
- } else return;
1950
- log(`[${event}] ${path.relative(root, file)} changed, regenerating...`);
1951
- trigger();
1952
- });
1953
- return watcher;
1954
- }
1955
1979
  //#endregion
1956
1980
  //#region src/utils/project.ts
1957
1981
  async function loadDictionaries(root, config) {
@@ -2006,6 +2030,6 @@ async function loadStaticProject(root, configFile) {
2006
2030
  /** `home` + `["nav", "about"]` -> `home.nav.about` */
2007
2031
  const toKey = (dictionary, keyPath) => [dictionary, ...keyPath].join(".");
2008
2032
  //#endregion
2009
- export { SOURCE_BUILTIN_IGNORE as A, listLocales as B, isStale as C, record as D, readLock as E, dictionaryLocation as F, saveDictionaryFile as G, locationOf as H, getLeafSource as I, setString as K, getString as L, scanFiles as M, TODO_PREFIX as N, writeLock as O, copyLeaf as P, hasPath as R, hashSource as S, lockPath as T, parseDictionaryText as U, loadDictionaryFile as V, renderDictionaryFile as W, createAnalysisCache as _, renderGenerated as a, scanText as b, DEFAULT_STATIC_CONFIG as c, resolveDialexConfig as d, logger as f, clearGitignore as g, analyzeProjectSync as h, generateDictionaries as i, createGitignoreFilter as j, BUILTIN_IGNORE as k, parseStaticConfig as l, analyzeProject as m, loadStaticProject as n, runGenerate as o, DEFAULT_SOURCE_GLOB as p, toKey as r, startGenerateWatcher as s, loadProject as t, readStaticConfig as u, relativeFile as v, lockFor as w, LOCK_FILE as x, scanReferences as y, listLeaves as z };
2033
+ export { scanFiles as A, listLeaves as B, lockPath as C, BUILTIN_IGNORE as D, writeLock as E, locationOf as F, saveDictionaryFile as G, loadDictionaryFile as H, copyLeaf as I, TODO_PREFIX as K, setString as L, createAnalysisCache as M, dictionaryLocation as N, SOURCE_BUILTIN_IGNORE as O, getLeafSource as P, getString as R, lockFor as S, record as T, parseDictionaryText as U, listLocales as V, renderDictionaryFile as W, scanReferences as _, generateDictionaries as a, hashSource as b, DEFAULT_STATIC_CONFIG as c, resolveDialexConfig as d, logger as f, DEFAULT_SOURCE_GLOB as g, relativeFile as h, runGenerate as i, clearGitignore as j, createGitignoreFilter as k, parseStaticConfig as l, analyzeProjectSync as m, loadStaticProject as n, startGenerateWatcher as o, analyzeProject as p, toKey as r, renderGenerated as s, loadProject as t, readStaticConfig as u, scanText as v, readLock as w, isStale as x, LOCK_FILE as y, hasPath as z };
2010
2034
 
2011
- //# sourceMappingURL=project-B27699T2.mjs.map
2035
+ //# sourceMappingURL=project-BTpZGNjh.mjs.map