@translation-cms/sync 1.1.99 → 1.2.3

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.
Files changed (161) hide show
  1. package/dist/bin.d.ts +25 -0
  2. package/dist/bin.d.ts.map +1 -0
  3. package/dist/bin.js +173 -0
  4. package/dist/bin.js.map +1 -0
  5. package/dist/commands/init.d.ts +2 -0
  6. package/dist/commands/init.d.ts.map +1 -0
  7. package/dist/commands/init.js +68 -0
  8. package/dist/commands/init.js.map +1 -0
  9. package/dist/commands/pull.d.ts +3 -0
  10. package/dist/commands/pull.d.ts.map +1 -0
  11. package/dist/commands/pull.js +22 -0
  12. package/dist/commands/pull.js.map +1 -0
  13. package/dist/commands/status.d.ts +3 -0
  14. package/dist/commands/status.d.ts.map +1 -0
  15. package/dist/commands/status.js +46 -0
  16. package/dist/commands/status.js.map +1 -0
  17. package/dist/commands/sync.d.ts +10 -0
  18. package/dist/commands/sync.d.ts.map +1 -0
  19. package/dist/commands/sync.js +20 -0
  20. package/dist/commands/sync.js.map +1 -0
  21. package/dist/commands/watch.d.ts +4 -0
  22. package/dist/commands/watch.d.ts.map +1 -0
  23. package/dist/commands/watch.js +51 -0
  24. package/dist/commands/watch.js.map +1 -0
  25. package/dist/{load-config.d.ts → config/resolve-config.d.ts} +13 -10
  26. package/dist/config/resolve-config.d.ts.map +1 -0
  27. package/dist/{resolve-config.js → config/resolve-config.js} +21 -0
  28. package/dist/config/resolve-config.js.map +1 -0
  29. package/dist/core/api-internals/helpers.d.ts +9 -0
  30. package/dist/core/api-internals/helpers.d.ts.map +1 -0
  31. package/dist/core/api-internals/helpers.js +14 -0
  32. package/dist/core/api-internals/helpers.js.map +1 -0
  33. package/dist/core/api-internals/pull.d.ts +11 -0
  34. package/dist/core/api-internals/pull.d.ts.map +1 -0
  35. package/dist/core/api-internals/pull.js +124 -0
  36. package/dist/core/api-internals/pull.js.map +1 -0
  37. package/dist/core/api-internals/route-config.d.ts +13 -0
  38. package/dist/core/api-internals/route-config.d.ts.map +1 -0
  39. package/dist/core/api-internals/route-config.js +34 -0
  40. package/dist/core/api-internals/route-config.js.map +1 -0
  41. package/dist/core/api-internals/sync.d.ts +12 -0
  42. package/dist/core/api-internals/sync.d.ts.map +1 -0
  43. package/dist/core/api-internals/sync.js +95 -0
  44. package/dist/core/api-internals/sync.js.map +1 -0
  45. package/dist/core/api-internals/types.d.ts +25 -0
  46. package/dist/core/api-internals/types.d.ts.map +1 -0
  47. package/dist/core/api-internals/types.js +5 -0
  48. package/dist/core/api-internals/types.js.map +1 -0
  49. package/dist/core/api.d.ts +11 -0
  50. package/dist/core/api.d.ts.map +1 -0
  51. package/dist/core/api.js +11 -0
  52. package/dist/core/api.js.map +1 -0
  53. package/dist/{sync.d.ts → core/cache.d.ts} +5 -25
  54. package/dist/core/cache.d.ts.map +1 -0
  55. package/dist/core/cache.js +143 -0
  56. package/dist/core/cache.js.map +1 -0
  57. package/dist/core/scanner-internals/ast.d.ts +22 -0
  58. package/dist/core/scanner-internals/ast.d.ts.map +1 -0
  59. package/dist/core/scanner-internals/ast.js +80 -0
  60. package/dist/core/scanner-internals/ast.js.map +1 -0
  61. package/dist/core/scanner-internals/file-walker.d.ts +9 -0
  62. package/dist/core/scanner-internals/file-walker.d.ts.map +1 -0
  63. package/dist/core/scanner-internals/file-walker.js +25 -0
  64. package/dist/core/scanner-internals/file-walker.js.map +1 -0
  65. package/dist/core/scanner-internals/import-resolver.d.ts +13 -0
  66. package/dist/core/scanner-internals/import-resolver.d.ts.map +1 -0
  67. package/dist/core/scanner-internals/import-resolver.js +124 -0
  68. package/dist/core/scanner-internals/import-resolver.js.map +1 -0
  69. package/dist/core/scanner-internals/key-extractor.d.ts +16 -0
  70. package/dist/core/scanner-internals/key-extractor.d.ts.map +1 -0
  71. package/dist/core/scanner-internals/key-extractor.js +168 -0
  72. package/dist/core/scanner-internals/key-extractor.js.map +1 -0
  73. package/dist/core/scanner-internals/route-detector.d.ts +19 -0
  74. package/dist/core/scanner-internals/route-detector.d.ts.map +1 -0
  75. package/dist/core/scanner-internals/route-detector.js +74 -0
  76. package/dist/core/scanner-internals/route-detector.js.map +1 -0
  77. package/dist/core/scanner-internals/types.d.ts +53 -0
  78. package/dist/core/scanner-internals/types.d.ts.map +1 -0
  79. package/dist/core/scanner-internals/types.js +29 -0
  80. package/dist/core/scanner-internals/types.js.map +1 -0
  81. package/dist/core/scanner.d.ts +20 -0
  82. package/dist/core/scanner.d.ts.map +1 -0
  83. package/dist/core/scanner.js +113 -0
  84. package/dist/core/scanner.js.map +1 -0
  85. package/dist/index.d.ts +2 -2
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +2 -2
  88. package/dist/index.js.map +1 -1
  89. package/dist/preview/index.d.ts +38 -0
  90. package/dist/preview/index.d.ts.map +1 -0
  91. package/dist/preview/index.js +114 -0
  92. package/dist/preview/index.js.map +1 -0
  93. package/dist/preview/internals/highlight.d.ts +22 -0
  94. package/dist/preview/internals/highlight.d.ts.map +1 -0
  95. package/dist/preview/internals/highlight.js +153 -0
  96. package/dist/preview/internals/highlight.js.map +1 -0
  97. package/dist/preview/internals/interactions.d.ts +15 -0
  98. package/dist/preview/internals/interactions.d.ts.map +1 -0
  99. package/dist/preview/internals/interactions.js +38 -0
  100. package/dist/preview/internals/interactions.js.map +1 -0
  101. package/dist/preview/internals/locales.d.ts +9 -0
  102. package/dist/preview/internals/locales.d.ts.map +1 -0
  103. package/dist/preview/internals/locales.js +24 -0
  104. package/dist/preview/internals/locales.js.map +1 -0
  105. package/dist/preview/internals/state.d.ts +35 -0
  106. package/dist/preview/internals/state.d.ts.map +1 -0
  107. package/dist/preview/internals/state.js +65 -0
  108. package/dist/preview/internals/state.js.map +1 -0
  109. package/dist/preview/internals/styles.d.ts +8 -0
  110. package/dist/preview/internals/styles.d.ts.map +1 -0
  111. package/dist/preview/internals/styles.js +28 -0
  112. package/dist/preview/internals/styles.js.map +1 -0
  113. package/dist/preview/internals/types.d.ts +49 -0
  114. package/dist/preview/internals/types.d.ts.map +1 -0
  115. package/dist/preview/internals/types.js +5 -0
  116. package/dist/preview/internals/types.js.map +1 -0
  117. package/dist/scaffold/index.d.ts +3 -0
  118. package/dist/scaffold/index.d.ts.map +1 -0
  119. package/dist/scaffold/index.js +3 -0
  120. package/dist/scaffold/index.js.map +1 -0
  121. package/dist/scaffold/intenrals/scaffold.d.ts +7 -0
  122. package/dist/scaffold/intenrals/scaffold.d.ts.map +1 -0
  123. package/dist/scaffold/intenrals/scaffold.js +34 -0
  124. package/dist/scaffold/intenrals/scaffold.js.map +1 -0
  125. package/dist/scaffold/intenrals/templates.d.ts +10 -0
  126. package/dist/scaffold/intenrals/templates.d.ts.map +1 -0
  127. package/dist/{scaffold.js → scaffold/intenrals/templates.js} +10 -38
  128. package/dist/scaffold/intenrals/templates.js.map +1 -0
  129. package/dist/{scaffold.d.ts → scaffold/intenrals/types.d.ts} +4 -2
  130. package/dist/scaffold/intenrals/types.d.ts.map +1 -0
  131. package/dist/scaffold/intenrals/types.js +5 -0
  132. package/dist/scaffold/intenrals/types.js.map +1 -0
  133. package/package.json +7 -7
  134. package/schema.json +64 -0
  135. package/dist/cli-entry.d.ts +0 -3
  136. package/dist/cli-entry.d.ts.map +0 -1
  137. package/dist/cli-entry.js +0 -382
  138. package/dist/cli-entry.js.map +0 -1
  139. package/dist/cli.d.ts +0 -16
  140. package/dist/cli.d.ts.map +0 -1
  141. package/dist/cli.js +0 -16
  142. package/dist/cli.js.map +0 -1
  143. package/dist/load-config.d.ts.map +0 -1
  144. package/dist/load-config.js +0 -24
  145. package/dist/load-config.js.map +0 -1
  146. package/dist/preview.d.ts +0 -88
  147. package/dist/preview.d.ts.map +0 -1
  148. package/dist/preview.js +0 -461
  149. package/dist/preview.js.map +0 -1
  150. package/dist/resolve-config.d.ts +0 -15
  151. package/dist/resolve-config.d.ts.map +0 -1
  152. package/dist/resolve-config.js.map +0 -1
  153. package/dist/scaffold.d.ts.map +0 -1
  154. package/dist/scaffold.js.map +0 -1
  155. package/dist/scanner.d.ts +0 -77
  156. package/dist/scanner.d.ts.map +0 -1
  157. package/dist/scanner.js +0 -555
  158. package/dist/scanner.js.map +0 -1
  159. package/dist/sync.d.ts.map +0 -1
  160. package/dist/sync.js +0 -340
  161. package/dist/sync.js.map +0 -1
@@ -0,0 +1,80 @@
1
+ /**
2
+ * AST parsing and traversal utilities.
3
+ */
4
+ import { parse } from '@babel/parser';
5
+ import path from 'path';
6
+ /**
7
+ * Walk an AST tree depth-first, calling visit() for each node.
8
+ */
9
+ export function walk(node, visit) {
10
+ if (!node || typeof node !== 'object')
11
+ return;
12
+ if (Array.isArray(node)) {
13
+ for (const item of node)
14
+ walk(item, visit);
15
+ return;
16
+ }
17
+ const n = node;
18
+ if (typeof n.type === 'string')
19
+ visit(n);
20
+ for (const value of Object.values(n)) {
21
+ if (value && typeof value === 'object')
22
+ walk(value, visit);
23
+ }
24
+ }
25
+ /**
26
+ * Parse source code using Babel with appropriate plugins based on file extension.
27
+ */
28
+ export function parseSource(filePath, source) {
29
+ const ext = path.extname(filePath);
30
+ const plugins = [];
31
+ if (ext === '.ts' || ext === '.tsx')
32
+ plugins.push('typescript');
33
+ if (ext !== '.ts')
34
+ plugins.push('jsx'); // .tsx, .jsx, .js
35
+ return parse(source, {
36
+ sourceType: 'module',
37
+ plugins,
38
+ errorRecovery: true,
39
+ });
40
+ }
41
+ /**
42
+ * Returns the string value of a StringLiteral or no-expression TemplateLiteral node.
43
+ */
44
+ export function stringValue(node) {
45
+ if (!node || typeof node !== 'object')
46
+ return null;
47
+ const n = node;
48
+ if (n.type === 'StringLiteral' && typeof n.value === 'string')
49
+ return n.value;
50
+ if (n.type === 'TemplateLiteral') {
51
+ const exprs = n.expressions;
52
+ const quasis = n.quasis;
53
+ if (exprs.length === 0 && quasis.length === 1) {
54
+ const quasi = quasis[0];
55
+ if (quasi?.value) {
56
+ return quasi.value.cooked ?? null;
57
+ }
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+ /**
63
+ * Extracts namespace string(s) from a useTranslation/getTranslation argument.
64
+ * Handles both single strings and arrays of strings.
65
+ */
66
+ export function namespacesFromArg(node) {
67
+ const single = stringValue(node);
68
+ if (single)
69
+ return [single];
70
+ if (!node || typeof node !== 'object')
71
+ return [];
72
+ const n = node;
73
+ if (n.type === 'ArrayExpression') {
74
+ return n.elements
75
+ .map(stringValue)
76
+ .filter((s) => s !== null);
77
+ }
78
+ return [];
79
+ }
80
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../../../src/core/scanner-internals/ast.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,eAAe,CAAC;AACzD,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,IAAa,EAAE,KAA8B;IAC9D,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,KAAK,MAAM,IAAI,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO;IACX,CAAC;IACD,MAAM,CAAC,GAAG,IAAe,CAAC;IAC1B,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;QAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,MAAc;IACxD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAChE,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB;IAC1D,OAAO,KAAK,CAAC,MAAM,EAAE;QACjB,UAAU,EAAE,QAAQ;QACpB,OAAO;QACP,aAAa,EAAE,IAAI;KACtB,CAAC,CAAC;AACP,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAa;IACrC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,CAAC,GAAG,IAAe,CAAC;IAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QACzD,OAAO,CAAC,CAAC,KAAK,CAAC;IACnB,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,CAAC,CAAC,WAAwB,CAAC;QACzC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAqD,CAAC;QACvE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;gBACf,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;YACtC,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC3C,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACjD,MAAM,CAAC,GAAG,IAAe,CAAC;IAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QAC/B,OAAQ,CAAC,CAAC,QAAsB;aAC3B,GAAG,CAAC,WAAW,CAAC;aAChB,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,CAAC;AACd,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * File system traversal utilities.
3
+ */
4
+ /**
5
+ * Recursively walk through files in a directory, yielding file paths that match
6
+ * the source extensions and are not in excluded directories.
7
+ */
8
+ export declare function walkFiles(dir: string, excludedDirs: Set<string>, sourceExtensions: Set<string>): Generator<string>;
9
+ //# sourceMappingURL=file-walker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-walker.d.ts","sourceRoot":"","sources":["../../../src/core/scanner-internals/file-walker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,wBAAiB,SAAS,CACtB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC9B,SAAS,CAAC,MAAM,CAAC,CAgBnB"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * File system traversal utilities.
3
+ */
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ /**
7
+ * Recursively walk through files in a directory, yielding file paths that match
8
+ * the source extensions and are not in excluded directories.
9
+ */
10
+ export function* walkFiles(dir, excludedDirs, sourceExtensions) {
11
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
12
+ for (const entry of entries) {
13
+ if (entry.isDirectory()) {
14
+ if (excludedDirs.has(entry.name))
15
+ continue;
16
+ yield* walkFiles(path.join(dir, entry.name), excludedDirs, sourceExtensions);
17
+ }
18
+ else if (entry.isFile()) {
19
+ if (sourceExtensions.has(path.extname(entry.name))) {
20
+ yield path.join(dir, entry.name);
21
+ }
22
+ }
23
+ }
24
+ }
25
+ //# sourceMappingURL=file-walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-walker.js","sourceRoot":"","sources":["../../../src/core/scanner-internals/file-walker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;GAGG;AACH,MAAM,SAAS,CAAC,CAAC,SAAS,CACtB,GAAW,EACX,YAAyB,EACzB,gBAA6B;IAE7B,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACtB,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC3C,KAAK,CAAC,CAAC,SAAS,CACZ,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAC1B,YAAY,EACZ,gBAAgB,CACnB,CAAC;QACN,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxB,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBACjD,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Import path resolution and traversal.
3
+ * Handles aliased imports (@/path), relative imports (../path), and layout chains.
4
+ */
5
+ /**
6
+ * Extract all local imports (relative and aliased) from a source file via AST.
7
+ */
8
+ export declare function extractLocalImports(filePath: string, sourceExtensions: Set<string>, root?: string, pathMappings?: Record<string, string[]>): string[];
9
+ /**
10
+ * For a given page file, find all wrapping layout files up to the app root.
11
+ */
12
+ export declare function getLayoutChain(root: string, pageFile: string, sourceExtensions: Set<string>): string[];
13
+ //# sourceMappingURL=import-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-resolver.d.ts","sourceRoot":"","sources":["../../../src/core/scanner-internals/import-resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA4EH;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAC7B,IAAI,CAAC,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACxC,MAAM,EAAE,CAoDV;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC9B,MAAM,EAAE,CAeV"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Import path resolution and traversal.
3
+ * Handles aliased imports (@/path), relative imports (../path), and layout chains.
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { parseSource, walk } from './ast.js';
8
+ /**
9
+ * Resolve an aliased import path (e.g., @/components/button) to an absolute file path.
10
+ * Uses tsconfig path mappings if provided.
11
+ */
12
+ function resolveAliasedImport(importPath, root, sourceExtensions, pathMappings) {
13
+ if (!pathMappings)
14
+ return null;
15
+ for (const [alias, targets] of Object.entries(pathMappings)) {
16
+ const pattern = alias.replace(/\*/g, '(.*)');
17
+ const regex = new RegExp(`^${pattern}$`);
18
+ const match = importPath.match(regex);
19
+ if (match) {
20
+ const captured = match[1] ?? '';
21
+ for (const target of targets) {
22
+ const resolved = target.replace(/\*/g, captured);
23
+ const fullPath = path.join(root, resolved);
24
+ if (sourceExtensions.has(path.extname(fullPath))) {
25
+ if (fs.existsSync(fullPath))
26
+ return fullPath;
27
+ }
28
+ else {
29
+ for (const ext of sourceExtensions) {
30
+ const candidate = fullPath + ext;
31
+ if (fs.existsSync(candidate))
32
+ return candidate;
33
+ }
34
+ for (const ext of sourceExtensions) {
35
+ const candidate = path.join(fullPath, 'index' + ext);
36
+ if (fs.existsSync(candidate))
37
+ return candidate;
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Resolve a relative import path to an absolute file path.
47
+ */
48
+ function resolveLocalImport(fromDir, importPath, sourceExtensions) {
49
+ const joined = path.join(fromDir, importPath);
50
+ if (sourceExtensions.has(path.extname(joined))) {
51
+ return fs.existsSync(joined) ? joined : null;
52
+ }
53
+ for (const ext of sourceExtensions) {
54
+ const candidate = joined + ext;
55
+ if (fs.existsSync(candidate))
56
+ return candidate;
57
+ }
58
+ for (const ext of sourceExtensions) {
59
+ const candidate = path.join(joined, 'index' + ext);
60
+ if (fs.existsSync(candidate))
61
+ return candidate;
62
+ }
63
+ return null;
64
+ }
65
+ /**
66
+ * Extract all local imports (relative and aliased) from a source file via AST.
67
+ */
68
+ export function extractLocalImports(filePath, sourceExtensions, root, pathMappings) {
69
+ let source;
70
+ try {
71
+ source = fs.readFileSync(filePath, 'utf-8');
72
+ }
73
+ catch {
74
+ return [];
75
+ }
76
+ let ast;
77
+ try {
78
+ ast = parseSource(filePath, source);
79
+ }
80
+ catch {
81
+ return [];
82
+ }
83
+ const fromDir = path.dirname(filePath);
84
+ const results = [];
85
+ walk(ast, node => {
86
+ if (node.type !== 'ImportDeclaration' &&
87
+ node.type !== 'ExportNamedDeclaration' &&
88
+ node.type !== 'ExportAllDeclaration')
89
+ return;
90
+ const src = node.source;
91
+ if (!src || typeof src.value !== 'string')
92
+ return;
93
+ const importPath = src.value;
94
+ let resolved = null;
95
+ if (importPath.startsWith('.')) {
96
+ resolved = resolveLocalImport(fromDir, importPath, sourceExtensions);
97
+ }
98
+ else if (root && pathMappings) {
99
+ resolved = resolveAliasedImport(importPath, root, sourceExtensions, pathMappings);
100
+ }
101
+ if (resolved && !results.includes(resolved)) {
102
+ results.push(resolved);
103
+ }
104
+ });
105
+ return results;
106
+ }
107
+ /**
108
+ * For a given page file, find all wrapping layout files up to the app root.
109
+ */
110
+ export function getLayoutChain(root, pageFile, sourceExtensions) {
111
+ const layouts = [];
112
+ let dir = path.dirname(pageFile);
113
+ while (dir.startsWith(root)) {
114
+ for (const ext of sourceExtensions) {
115
+ const candidate = path.join(dir, `layout${ext}`);
116
+ if (fs.existsSync(candidate)) {
117
+ layouts.push(candidate);
118
+ }
119
+ }
120
+ dir = path.dirname(dir);
121
+ }
122
+ return layouts;
123
+ }
124
+ //# sourceMappingURL=import-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-resolver.js","sourceRoot":"","sources":["../../../src/core/scanner-internals/import-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Extraction of translation keys from source files.
3
+ * Finds t('key') calls, useTranslation() bindings, and Trans components.
4
+ */
5
+ import type { NamespaceMap } from './types.js';
6
+ /**
7
+ * Extract translation keys from a source file.
8
+ * Handles:
9
+ * - const { t } = useTranslation('ns') / getTranslation('ns')
10
+ * - const { t: myT } = useTranslation(...)
11
+ * - const t = await client.getTranslations(locale, 'ns')
12
+ * - t('namespace:key') calls
13
+ * - <Trans i18nKey="namespace:key"> components
14
+ */
15
+ export declare function extractKeysFromFile(filePath: string, routes: string[], result: NamespaceMap): void;
16
+ //# sourceMappingURL=key-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-extractor.d.ts","sourceRoot":"","sources":["../../../src/core/scanner-internals/key-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAW,YAAY,EAAE,MAAM,YAAY,CAAC;AA0BxD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,MAAM,EAAE,YAAY,GACrB,IAAI,CAsJN"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Extraction of translation keys from source files.
3
+ * Finds t('key') calls, useTranslation() bindings, and Trans components.
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { parseSource, walk, stringValue, namespacesFromArg } from './ast.js';
8
+ /**
9
+ * Add a key to the namespace map with its associated routes.
10
+ * Skips keys that look like paths or are suspiciously short/numeric.
11
+ */
12
+ function addKey(map, namespace, key, routes) {
13
+ // Skip keys that look like URL paths or are suspiciously short/numeric
14
+ if (key.startsWith('/') || key.startsWith('.') || /^\d+$/.test(key))
15
+ return;
16
+ if (!map[namespace])
17
+ map[namespace] = new Map();
18
+ const existing = map[namespace].get(key) ?? [];
19
+ if (routes.length > 0) {
20
+ const merged = new Set(existing);
21
+ for (const route of routes)
22
+ merged.add(route);
23
+ map[namespace].set(key, Array.from(merged));
24
+ }
25
+ else if (existing.length === 0) {
26
+ map[namespace].set(key, []);
27
+ }
28
+ }
29
+ /**
30
+ * Extract translation keys from a source file.
31
+ * Handles:
32
+ * - const { t } = useTranslation('ns') / getTranslation('ns')
33
+ * - const { t: myT } = useTranslation(...)
34
+ * - const t = await client.getTranslations(locale, 'ns')
35
+ * - t('namespace:key') calls
36
+ * - <Trans i18nKey="namespace:key"> components
37
+ */
38
+ export function extractKeysFromFile(filePath, routes, result) {
39
+ let source;
40
+ try {
41
+ source = fs.readFileSync(filePath, 'utf-8');
42
+ }
43
+ catch {
44
+ return;
45
+ }
46
+ let ast;
47
+ try {
48
+ ast = parseSource(filePath, source);
49
+ }
50
+ catch {
51
+ return;
52
+ }
53
+ // --- Step 1: collect namespace bindings ---
54
+ // Maps the local variable name (e.g. 't') → the namespace(s) it's bound to.
55
+ const tBindings = new Map();
56
+ walk(ast, node => {
57
+ if (node.type !== 'VariableDeclaration')
58
+ return;
59
+ for (const decl of node.declarations) {
60
+ const init = decl.init;
61
+ if (!init)
62
+ continue;
63
+ // Unwrap await
64
+ const call = init.type === 'AwaitExpression'
65
+ ? init.argument
66
+ : init;
67
+ if (!call || call.type !== 'CallExpression')
68
+ continue;
69
+ const callee = call.callee;
70
+ const args = call.arguments;
71
+ // useTranslation('ns') / getTranslation('ns')
72
+ const isHook = callee.type === 'Identifier' &&
73
+ (callee.name === 'useTranslation' ||
74
+ callee.name === 'getTranslation');
75
+ // client.getTranslations(locale, 'ns') / client.getT(locale, 'ns')
76
+ const isCmsStyle = callee.type === 'MemberExpression' &&
77
+ callee.property.type === 'Identifier' &&
78
+ /^getTranslations(?:WithFallback)?$|^getT$/.test(callee.property.name);
79
+ if (!isHook && !isCmsStyle)
80
+ continue;
81
+ const namespaces = isHook
82
+ ? namespacesFromArg(args[0])
83
+ : namespacesFromArg(args[1]); // CMS style: getTranslations(locale, ns)
84
+ if (!namespaces.length)
85
+ continue;
86
+ const id = decl.id;
87
+ if (id.type === 'Identifier') {
88
+ // const t = useTranslation(...)
89
+ tBindings.set(id.name, namespaces);
90
+ }
91
+ else if (id.type === 'ObjectPattern') {
92
+ // const { t } = useTranslation(...) or const { t: myT } = useTranslation(...)
93
+ for (const prop of id.properties) {
94
+ if (prop.type !== 'ObjectProperty')
95
+ continue;
96
+ const keyNode = prop.key;
97
+ const valNode = prop.value;
98
+ const origName = keyNode.type === 'Identifier'
99
+ ? keyNode.name
100
+ : null;
101
+ if (!origName ||
102
+ (origName !== 't' && origName !== 'tDynamic'))
103
+ continue;
104
+ const boundName = valNode.type === 'Identifier'
105
+ ? valNode.name
106
+ : origName;
107
+ tBindings.set(boundName, namespaces);
108
+ }
109
+ }
110
+ }
111
+ });
112
+ // --- Step 2: extract keys from t('...') call expressions ---
113
+ walk(ast, node => {
114
+ if (node.type !== 'CallExpression')
115
+ return;
116
+ const callee = node.callee;
117
+ if (callee.type !== 'Identifier')
118
+ return;
119
+ const varName = callee.name;
120
+ const args = node.arguments;
121
+ const keyStr = stringValue(args[0]);
122
+ if (!keyStr)
123
+ return;
124
+ const colonIdx = keyStr.indexOf(':');
125
+ if (colonIdx > 0) {
126
+ // Explicit namespace: t('namespace:key')
127
+ addKey(result, keyStr.slice(0, colonIdx), keyStr.slice(colonIdx + 1), routes);
128
+ }
129
+ else if (tBindings.has(varName)) {
130
+ // Bare key: t('key') with a known namespace binding — warn and register
131
+ const namespaces = tBindings.get(varName);
132
+ console.warn(`[WARN] Bare key in ${path.relative(process.cwd(), filePath)}: ${varName}('${keyStr}') — use ${varName}('namespace:${keyStr}') instead`);
133
+ for (const ns of namespaces)
134
+ addKey(result, ns, keyStr, routes);
135
+ }
136
+ });
137
+ // --- Step 3: <Trans i18nKey="namespace:key"> ---
138
+ walk(ast, node => {
139
+ if (node.type !== 'JSXOpeningElement')
140
+ return;
141
+ const name = node.name;
142
+ if (name.type !== 'JSXIdentifier' || name.name !== 'Trans')
143
+ return;
144
+ for (const attr of node.attributes) {
145
+ if (attr.type !== 'JSXAttribute')
146
+ continue;
147
+ const attrName = attr.name;
148
+ if (attrName.type !== 'JSXIdentifier' ||
149
+ attrName.name !== 'i18nKey')
150
+ continue;
151
+ const value = attr.value;
152
+ let keyStr = null;
153
+ if (value?.type === 'StringLiteral') {
154
+ keyStr = value.value;
155
+ }
156
+ else if (value?.type === 'JSXExpressionContainer') {
157
+ keyStr = stringValue(value.expression);
158
+ }
159
+ if (!keyStr)
160
+ continue;
161
+ const colonIdx = keyStr.indexOf(':');
162
+ if (colonIdx <= 0)
163
+ continue;
164
+ addKey(result, keyStr.slice(0, colonIdx), keyStr.slice(colonIdx + 1), routes);
165
+ }
166
+ });
167
+ }
168
+ //# sourceMappingURL=key-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-extractor.js","sourceRoot":"","sources":["../../../src/core/scanner-internals/key-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Route detection from Next.js file paths.
3
+ * Maps source files (page.tsx, layout.tsx) to their corresponding route strings.
4
+ */
5
+ /**
6
+ * Returns true when a page file only calls redirect() without rendering any JSX.
7
+ * Such pages are skipped from the preview route list because they have no UI to preview.
8
+ */
9
+ export declare function isRedirectOnlyPage(filePath: string): boolean;
10
+ /**
11
+ * Maps a source file path to Next.js route string(s).
12
+ * - page.tsx → the route template it represents (e.g. /blog/[slug], /[locale]/about)
13
+ * - layout.tsx → the route template of its directory
14
+ * - Dynamic segments are kept as-is — resolved at preview time via project preview_params
15
+ * - Redirect-only pages (no JSX, just redirect()) → []
16
+ * - All other files (components, hooks, …) → []
17
+ */
18
+ export declare function filePathToRoute(root: string, filePath: string): string[];
19
+ //# sourceMappingURL=route-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-detector.d.ts","sourceRoot":"","sources":["../../../src/core/scanner-internals/route-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAuC5D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBxE"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Route detection from Next.js file paths.
3
+ * Maps source files (page.tsx, layout.tsx) to their corresponding route strings.
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { parseSource, walk } from './ast.js';
8
+ /**
9
+ * Returns true when a page file only calls redirect() without rendering any JSX.
10
+ * Such pages are skipped from the preview route list because they have no UI to preview.
11
+ */
12
+ export function isRedirectOnlyPage(filePath) {
13
+ let source;
14
+ try {
15
+ source = fs.readFileSync(filePath, 'utf-8');
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ let ast;
21
+ try {
22
+ ast = parseSource(filePath, source);
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ let hasRedirect = false;
28
+ let hasJsxReturn = false;
29
+ walk(ast, node => {
30
+ if (node.type === 'CallExpression') {
31
+ const callee = node.callee;
32
+ if (callee.type === 'Identifier' && callee.name === 'redirect') {
33
+ hasRedirect = true;
34
+ }
35
+ }
36
+ if (node.type === 'ReturnStatement') {
37
+ const arg = node.argument;
38
+ if (!arg)
39
+ return;
40
+ const expr = arg.type === 'ParenthesizedExpression'
41
+ ? arg.expression
42
+ : arg;
43
+ if (expr?.type === 'JSXElement' || expr?.type === 'JSXFragment') {
44
+ hasJsxReturn = true;
45
+ }
46
+ }
47
+ });
48
+ return hasRedirect && !hasJsxReturn;
49
+ }
50
+ /**
51
+ * Maps a source file path to Next.js route string(s).
52
+ * - page.tsx → the route template it represents (e.g. /blog/[slug], /[locale]/about)
53
+ * - layout.tsx → the route template of its directory
54
+ * - Dynamic segments are kept as-is — resolved at preview time via project preview_params
55
+ * - Redirect-only pages (no JSX, just redirect()) → []
56
+ * - All other files (components, hooks, …) → []
57
+ */
58
+ export function filePathToRoute(root, filePath) {
59
+ const base = path.basename(filePath, path.extname(filePath));
60
+ if (base !== 'page')
61
+ return [];
62
+ // Skip pages that only redirect — no UI to preview
63
+ if (isRedirectOnlyPage(filePath))
64
+ return [];
65
+ const rel = path.relative(root, filePath).replace(/\\/g, '/');
66
+ const appMatch = rel.match(/^(?:src\/)?app\/(.*?)page\.[jt]sx?$/);
67
+ if (!appMatch)
68
+ return [];
69
+ let routePath = appMatch[1] ?? '';
70
+ routePath = routePath.replace(/\([^)]+\)\//g, ''); // strip route groups
71
+ routePath = routePath.replace(/\/$/, ''); // strip trailing slash
72
+ return ['/' + routePath];
73
+ }
74
+ //# sourceMappingURL=route-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-detector.js","sourceRoot":"","sources":["../../../src/core/scanner-internals/route-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAG7C;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IAC/C,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACD,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACD,GAAG,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE;QACb,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAiB,CAAC;YACtC,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC7D,WAAW,GAAG,IAAI,CAAC;YACvB,CAAC;QACL,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAsC,CAAC;YACxD,IAAI,CAAC,GAAG;gBAAE,OAAO;YACjB,MAAM,IAAI,GACN,GAAG,CAAC,IAAI,KAAK,yBAAyB;gBAClC,CAAC,CAAE,GAAG,CAAC,UAAsB;gBAC7B,CAAC,CAAC,GAAG,CAAC;YACd,IAAI,IAAI,EAAE,IAAI,KAAK,YAAY,IAAI,IAAI,EAAE,IAAI,KAAK,aAAa,EAAE,CAAC;gBAC9D,YAAY,GAAG,IAAI,CAAC;YACxB,CAAC;QACL,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,WAAW,IAAI,CAAC,YAAY,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAgB;IAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7D,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAE/B,mDAAmD;IACnD,IAAI,kBAAkB,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAE5C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAClE,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAEzB,IAAI,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC,qBAAqB;IACxE,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,uBAAuB;IAEjE,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Types and constants used throughout the scanner module.
3
+ */
4
+ export declare const DEFAULT_EXCLUDED_DIRS: Set<string>;
5
+ export declare const DEFAULT_SOURCE_EXTENSIONS: Set<string>;
6
+ /** Options that control the file-system scan behaviour. */
7
+ export interface ScanOptions {
8
+ /**
9
+ * Extra directories to exclude on top of the built-in defaults.
10
+ * @example ["e2e", "fixtures"]
11
+ */
12
+ excludedDirs?: string[];
13
+ /**
14
+ * Override the full set of file extensions to scan.
15
+ * When omitted the defaults (.ts .tsx .js .jsx) are used.
16
+ */
17
+ sourceExtensions?: string[];
18
+ /**
19
+ * External preview routes from database or config (namespace:key → routes[])
20
+ * These are applied in Pass 3.
21
+ * Keys are route patterns, values are mock params for dynamic segments.
22
+ * @example
23
+ * {
24
+ * "/[locale]/blog/[slug]": { "slug": "first-post" },
25
+ * "/[locale]/products/[slug]": { "slug": "product-a" }
26
+ * }
27
+ */
28
+ routeParams?: Record<string, Record<string, string>>;
29
+ /**
30
+ * TypeScript path mappings from tsconfig.json (for resolving aliased imports).
31
+ * @example { "@/*": ["./src/*"] }
32
+ */
33
+ pathMappings?: Record<string, string[]>;
34
+ /**
35
+ * Project root directory (used for resolving path aliases).
36
+ * Defaults to the root directory passed to scanProject.
37
+ */
38
+ projectRoot?: string;
39
+ }
40
+ /** A preview route — either a plain path string or an object with per-route params. */
41
+ export type PreviewRoute = string | {
42
+ route: string;
43
+ params?: Record<string, string>;
44
+ };
45
+ /** namespace → (key → previewRoutes[]) */
46
+ export type NamespaceMap = Record<string, Map<string, PreviewRoute[]>>;
47
+ /** Return the route string key used for deduplication. */
48
+ export declare function routeKey(r: PreviewRoute): string;
49
+ /** AST node type for type-safe walking. */
50
+ export type AstNode = {
51
+ type: string;
52
+ } & Record<string, unknown>;
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/scanner-internals/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,eAAO,MAAM,qBAAqB,aAWhC,CAAC;AAEH,eAAO,MAAM,yBAAyB,aAKpC,CAAC;AAMH,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uFAAuF;AACvF,MAAM,MAAM,YAAY,GAClB,MAAM,GACN;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAEzD,0CAA0C;AAC1C,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;AAEvE,0DAA0D;AAC1D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAEhD;AAED,2CAA2C;AAC3C,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}