@shapeshift-labs/frontier-lang-compiler 0.2.103 → 0.2.104

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 (124) hide show
  1. package/README.md +13 -0
  2. package/dist/declarations/bidirectional-target-change-source-edit.d.ts +30 -0
  3. package/dist/declarations/bidirectional-target-change.d.ts +10 -0
  4. package/dist/declarations/js-ts-safe-member-merge.d.ts +58 -0
  5. package/dist/declarations/js-ts-safe-merge.d.ts +120 -0
  6. package/dist/declarations/js-ts-semantic-conflict-sidecars.d.ts +235 -0
  7. package/dist/declarations/js-ts-semantic-merge-contracts.d.ts +287 -0
  8. package/dist/declarations/js-ts-semantic-merge.d.ts +4 -0
  9. package/dist/declarations/native-import-losses.d.ts +3 -0
  10. package/dist/declarations/semantic-edit-replay-diagnostics.d.ts +12 -0
  11. package/dist/declarations/semantic-edit-script.d.ts +7 -4
  12. package/dist/declarations/semantic-patch-bundle-index.d.ts +45 -0
  13. package/dist/declarations/semantic-patch-bundle.d.ts +6 -4
  14. package/dist/declarations/semantic-sidecar-example.d.ts +18 -0
  15. package/dist/declarations/semantic-transform-identity.d.ts +3 -0
  16. package/dist/declarations/source-preservation.d.ts +72 -0
  17. package/dist/declarations/universal-capability.d.ts +4 -0
  18. package/dist/declarations/universal-conversion-artifacts.d.ts +61 -1
  19. package/dist/declarations/universal-conversion-compact-counts.d.ts +51 -0
  20. package/dist/declarations/universal-conversion-plan.d.ts +6 -1
  21. package/dist/declarations/universal-representation-coverage.d.ts +90 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.js +3 -0
  24. package/dist/internal/index-impl/bidirectionalExactSourceBackprojection.js +199 -0
  25. package/dist/internal/index-impl/bidirectionalSameLanguageSourceProjection.js +112 -0
  26. package/dist/internal/index-impl/bidirectionalSourceEditProjection.js +319 -0
  27. package/dist/internal/index-impl/bidirectionalSourceEditProjectionArtifacts.js +67 -0
  28. package/dist/internal/index-impl/bidirectionalTargetChangeRecordInternals.js +17 -5
  29. package/dist/internal/index-impl/bidirectionalTargetRoundtripEvidence.js +58 -20
  30. package/dist/internal/index-impl/createBidirectionalTargetChangeRecord.js +60 -7
  31. package/dist/internal/index-impl/createLightweightNativeImport.js +1 -0
  32. package/dist/internal/index-impl/createNativeSourcePreservation.js +28 -2
  33. package/dist/internal/index-impl/diffNativeSymbols.js +3 -3
  34. package/dist/internal/index-impl/nativeChangeProjectionSourceMapLinks.js +2 -0
  35. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +43 -8
  36. package/dist/internal/index-impl/replaySemanticEditLineEndings.js +34 -0
  37. package/dist/internal/index-impl/replaySemanticEditProjection.js +39 -19
  38. package/dist/internal/index-impl/semanticEditBundleAdmission.js +7 -3
  39. package/dist/internal/index-impl/semanticEditBundleIndex.js +47 -1
  40. package/dist/internal/index-impl/semanticEditExplicitSourceReplacement.js +40 -0
  41. package/dist/internal/index-impl/semanticEditOperationCoverage.js +33 -3
  42. package/dist/internal/index-impl/semanticEditProjectionRecord.js +29 -0
  43. package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +39 -0
  44. package/dist/internal/index-impl/semanticEditReplaySourceReplacement.js +85 -0
  45. package/dist/internal/index-impl/semanticEditScripts.js +4 -0
  46. package/dist/internal/index-impl/semanticEditSourceRanges.js +27 -0
  47. package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +1 -0
  48. package/dist/internal/index-impl/semanticPatchBundleAdmission.js +41 -7
  49. package/dist/internal/index-impl/semanticPatchBundleRecords.js +16 -0
  50. package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +2 -0
  51. package/dist/internal/index-impl/semanticSidecarQuality.js +111 -0
  52. package/dist/internal/index-impl/semanticSourceEditDedupe.js +69 -9
  53. package/dist/internal/index-impl/semanticTransformIdentityRecords.js +85 -9
  54. package/dist/js-ts-safe-member-merge-result.js +158 -0
  55. package/dist/js-ts-safe-member-merge.js +202 -0
  56. package/dist/js-ts-safe-merge-analyze.js +279 -0
  57. package/dist/js-ts-safe-merge-constants.js +50 -0
  58. package/dist/js-ts-safe-merge-context.js +118 -0
  59. package/dist/js-ts-safe-merge-ledger-validation.js +92 -0
  60. package/dist/js-ts-safe-merge-ledger.js +85 -0
  61. package/dist/js-ts-safe-merge-parse-declarations.js +210 -0
  62. package/dist/js-ts-safe-merge-parse-statements.js +155 -0
  63. package/dist/js-ts-safe-merge-plan.js +190 -0
  64. package/dist/js-ts-safe-merge.js +175 -0
  65. package/dist/js-ts-semantic-conflict-sidecar-constants.js +77 -0
  66. package/dist/js-ts-semantic-conflict-sidecar-detectors.js +195 -0
  67. package/dist/js-ts-semantic-conflict-sidecar-normalize.js +203 -0
  68. package/dist/js-ts-semantic-conflict-sidecar-utils.js +190 -0
  69. package/dist/js-ts-semantic-conflict-sidecars.js +81 -0
  70. package/dist/js-ts-semantic-merge-contract-helpers.js +128 -0
  71. package/dist/js-ts-semantic-merge-contracts.js +217 -0
  72. package/dist/js-ts-semantic-merge-member-containers.js +100 -0
  73. package/dist/js-ts-semantic-merge-member-keys.js +142 -0
  74. package/dist/js-ts-semantic-merge-member-segments.js +185 -0
  75. package/dist/js-ts-semantic-merge-member-source.js +64 -0
  76. package/dist/js-ts-semantic-merge-member-utils.js +18 -0
  77. package/dist/js-ts-semantic-merge-parse.js +15 -0
  78. package/dist/js-ts-semantic-merge.js +21 -0
  79. package/dist/lightweight-dependency-effects.js +51 -0
  80. package/dist/lightweight-dependency-language.js +12 -1
  81. package/dist/lightweight-dependency-relations.js +14 -27
  82. package/dist/native-region-scanner-core.js +33 -1
  83. package/dist/native-region-scanner-csharp.js +151 -0
  84. package/dist/native-region-scanner-dart.js +91 -0
  85. package/dist/native-region-scanner-dynamic.js +21 -151
  86. package/dist/native-region-scanner-functional.js +40 -13
  87. package/dist/native-region-scanner-java.js +97 -0
  88. package/dist/native-region-scanner-js-class.js +100 -0
  89. package/dist/native-region-scanner-js-helpers.js +28 -86
  90. package/dist/native-region-scanner-js-imports.js +121 -1
  91. package/dist/native-region-scanner-js-nested.js +96 -8
  92. package/dist/native-region-scanner-js-structure.js +27 -0
  93. package/dist/native-region-scanner-js-types.js +99 -0
  94. package/dist/native-region-scanner-js.js +70 -118
  95. package/dist/native-region-scanner-kotlin.js +94 -0
  96. package/dist/native-region-scanner-main.js +15 -181
  97. package/dist/native-region-scanner-php.js +80 -0
  98. package/dist/native-region-scanner-python.js +62 -0
  99. package/dist/native-region-scanner-ruby.js +72 -0
  100. package/dist/native-region-scanner-scala.js +91 -0
  101. package/dist/native-region-scanner-spans.js +74 -0
  102. package/dist/native-region-scanner-swift.js +155 -0
  103. package/dist/native-region-scanner.js +14 -10
  104. package/dist/native-source-ledger-helpers.js +195 -0
  105. package/dist/native-source-ledger.js +306 -0
  106. package/dist/native-source-preservation-scanner.js +4 -0
  107. package/dist/semantic-import-callsite-regions.js +136 -0
  108. package/dist/semantic-import-effect-regions.js +283 -0
  109. package/dist/semantic-import-regions.js +11 -2
  110. package/dist/semantic-import-sidecar-entry.js +16 -2
  111. package/dist/semantic-import-sidecar-types.d.ts +2 -0
  112. package/dist/semantic-sidecar-example.js +68 -0
  113. package/dist/universal-capability-matrix.js +23 -0
  114. package/dist/universal-conversion-artifact-query.js +79 -2
  115. package/dist/universal-conversion-artifact-semantic-edit.js +103 -0
  116. package/dist/universal-conversion-artifact-summary.js +33 -1
  117. package/dist/universal-conversion-artifacts.js +13 -48
  118. package/dist/universal-conversion-plan-scoring.js +21 -1
  119. package/dist/universal-conversion-plan-summary.js +30 -0
  120. package/dist/universal-conversion-plan.js +25 -9
  121. package/dist/universal-conversion-route-metadata.js +96 -0
  122. package/dist/universal-conversion-route-operations.js +7 -0
  123. package/dist/universal-representation-coverage.js +193 -0
  124. package/package.json +1 -1
@@ -1,9 +1,8 @@
1
1
  import {
2
- jsControlKeyword,
3
2
  nativeDeclaration,
4
3
  splitParameters
5
4
  } from './native-region-scanner-core.js';
6
- import { jsImportDeclarations } from './native-region-scanner-js-imports.js';
5
+ import { jsExportDeclarations, jsImportDeclarations } from './native-region-scanner-js-imports.js';
7
6
  function jsCommentOnlyLine(trimmed) {
8
7
  return trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*');
9
8
  }
@@ -71,13 +70,8 @@ function jsObjectRegionContext(name, declarationLine, lineNumber, regionKind) {
71
70
  if (initializerKind !== 'object' && initializerKind !== 'array') return undefined;
72
71
  const depth = jsContainerDelta(declarationLine);
73
72
  if (depth <= 0) return undefined;
74
- return {
75
- name,
76
- regionKind: regionKind ?? jsRegionKindForDeclarationName(name, declarationLine),
77
- initializerKind,
78
- depth,
79
- startLine: lineNumber
80
- };
73
+ return { name, regionKind: regionKind ?? jsRegionKindForDeclarationName(name, declarationLine), initializerKind, depth, startLine: lineNumber,
74
+ arrayRecords: initializerKind === 'array' && /(?:define|create|make|build)\w*(?:tools?|actions?|handlers?|commands?|events?|effects?|workflows?)/i.test(declarationLine) };
81
75
  }
82
76
 
83
77
  function jsInitializerKind(line, name) {
@@ -127,15 +121,17 @@ function jsExportedContainerDeclaration(input, lineNumber, trimmed) {
127
121
  }
128
122
 
129
123
  function jsExportedFunctionWrapperDeclaration(input, lineNumber, trimmed) {
130
- const match = trimmed.match(/^export\s+default\s+((?:React\.)?(?:forwardRef|memo|lazy|observer)|Object\.freeze)\s*(?:<[^>]+>)?\s*\(\s*(.+)$/);
124
+ const match = trimmed.match(/^export\s+default\s+(.+)$/);
131
125
  if (!match) return undefined;
132
- const wrapper = match[1];
133
- const argument = match[2].trim();
126
+ const unwrapped = jsUnwrapFunctionWrapperArgument(match[1]);
127
+ if (!unwrapped) return undefined;
128
+ const { wrapper, wrappers, argument } = unwrapped;
129
+ const wrapperFields = { wrapper, ...(wrappers.length > 1 ? { wrappers } : {}) };
134
130
  let functionMatch = argument.match(/^(?:async\s+)?function\*?\s*([A-Za-z_$][\w$]*)?\s*(?:<[^({;]+>)?\s*\(([^)]*)\)/);
135
131
  if (functionMatch) {
136
132
  return nativeDeclaration(input, lineNumber, 'ExportDefaultFunctionWrapperDeclaration', 'function', functionMatch[1] ?? 'default', {
137
133
  exportDefault: true,
138
- wrapper,
134
+ ...wrapperFields,
139
135
  parameters: splitParameters(functionMatch[2])
140
136
  }, true);
141
137
  }
@@ -143,7 +139,7 @@ function jsExportedFunctionWrapperDeclaration(input, lineNumber, trimmed) {
143
139
  if (functionMatch) {
144
140
  return nativeDeclaration(input, lineNumber, 'ExportDefaultFunctionWrapperDeclaration', 'function', 'default', {
145
141
  exportDefault: true,
146
- wrapper,
142
+ ...wrapperFields,
147
143
  parameters: splitParameters(functionMatch[1] ?? functionMatch[2])
148
144
  }, true);
149
145
  }
@@ -151,21 +147,33 @@ function jsExportedFunctionWrapperDeclaration(input, lineNumber, trimmed) {
151
147
  if (classMatch) {
152
148
  return nativeDeclaration(input, lineNumber, 'ExportDefaultClassWrapperDeclaration', 'class', classMatch[1] ?? 'default', {
153
149
  exportDefault: true,
154
- wrapper
150
+ ...wrapperFields
155
151
  }, true);
156
152
  }
157
153
  const aliasMatch = argument.match(/^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*(?:[,)]|$)/);
158
154
  if (!aliasMatch) return undefined;
159
155
  return nativeDeclaration(input, lineNumber, 'ExportDefaultWrappedAlias', 'variable', 'default', {
160
156
  exportDefault: true,
161
- wrapper,
157
+ ...wrapperFields,
162
158
  alias: aliasMatch[1],
163
159
  initializerKind: 'function-wrapper'
164
160
  }, false, {
165
- metadata: { exportDefault: true, wrapper, alias: aliasMatch[1], initializerKind: 'function-wrapper' }
161
+ metadata: { exportDefault: true, ...wrapperFields, alias: aliasMatch[1], initializerKind: 'function-wrapper' }
166
162
  });
167
163
  }
168
164
 
165
+ function jsUnwrapFunctionWrapperArgument(source) {
166
+ const wrappers = [];
167
+ let argument = String(source ?? '').trim();
168
+ let match;
169
+ while ((match = argument.match(/^((?:React\.)?(?:forwardRef|memo|lazy|observer)|Object\.freeze)\s*(?:<[^>]+>)?\s*\(\s*(.+)$/))) {
170
+ wrappers.push(match[1]);
171
+ argument = match[2].trim();
172
+ }
173
+ if (!wrappers.length) return undefined;
174
+ return { wrapper: wrappers[0], wrappers, argument };
175
+ }
176
+
169
177
  function jsExportAliasDeclaration(input, lineNumber, trimmed) {
170
178
  let match = trimmed.match(/^export\s+default\s+([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*;?$/);
171
179
  if (match) return jsAliasExport(input, lineNumber, 'ExportDefaultAlias', 'default', match[1], { exportDefault: true }, trimmed);
@@ -202,72 +210,6 @@ function jsContainerExport(input, lineNumber, languageKind, name, initializer, f
202
210
  return { declaration, context };
203
211
  }
204
212
 
205
- function jsObjectPropertyDeclaration(input, lineNumber, trimmed, context) {
206
- if (/^[}\])]/.test(trimmed) || trimmed.startsWith('...')) return undefined;
207
- const methodMatch = trimmed.match(/^(?:(?:async|get|set)\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\s*\(([^)]*)\)\s*(?:[:\w\s<>\[\]]*)?(?:\{|=>|,|$)/);
208
- if (methodMatch && !jsControlKeyword(methodMatch[2])) {
209
- const name = `${context.name}.${methodMatch[2]}`;
210
- return nativeDeclaration(input, lineNumber, 'ObjectMethod', 'function', name, {
211
- owner: context.name,
212
- propertyName: methodMatch[2],
213
- parameters: splitParameters(methodMatch[3])
214
- }, true, {
215
- regionKind: jsPropertyRegionKind(context, methodMatch[2], 'function'),
216
- metadata: { owner: context.name, propertyName: methodMatch[2], initializerKind: 'function' }
217
- });
218
- }
219
- const propertyMatch = trimmed.match(/^(?:(['"])([^'"]+)\1|([A-Za-z_$][\w$-]*))\s*:\s*(.+?)(?:,)?$/);
220
- if (!propertyMatch) return undefined;
221
- const propertyName = propertyMatch[2] ?? propertyMatch[3];
222
- if (!propertyName || jsControlKeyword(propertyName)) return undefined;
223
- const value = propertyMatch[4].trim();
224
- const initializerKind = jsPropertyInitializerKind(value);
225
- const functionLike = initializerKind === 'function';
226
- const name = `${context.name}.${propertyName}`;
227
- return nativeDeclaration(input, lineNumber, functionLike ? 'ObjectFunctionProperty' : 'ObjectProperty', functionLike ? 'function' : 'property', name, {
228
- owner: context.name,
229
- propertyName,
230
- initializerKind
231
- }, functionLike || initializerKind === 'object' || initializerKind === 'array', {
232
- regionKind: jsPropertyRegionKind(context, propertyName, value),
233
- metadata: { owner: context.name, propertyName, initializerKind }
234
- });
235
- }
236
-
237
- function jsRouteRecordDeclaration(input, lineNumber, trimmed, context) {
238
- if (context.regionKind !== 'route') return undefined;
239
- const match = trimmed.match(/^(?:\{\s*)?(?:path|route|href|url)\s*:\s*(['"`])([^'"`]+)\1/);
240
- if (!match) return undefined;
241
- const routePath = match[2];
242
- return nativeDeclaration(input, lineNumber, 'RouteRecord', 'route', `${context.name}.${routePath}`, {
243
- owner: context.name,
244
- routePath
245
- }, true, {
246
- regionKind: 'route',
247
- metadata: { owner: context.name, routePath, initializerKind: 'object' }
248
- });
249
- }
250
-
251
- function jsPropertyInitializerKind(value) {
252
- const text = String(value ?? '').trim();
253
- if (/^(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(text)) return 'function';
254
- const containerKind = jsContainerInitializerKind(text, undefined, text);
255
- if (containerKind) return containerKind;
256
- if (/^['"`]/.test(text)) return 'string';
257
- if (/^(?:true|false)\b/.test(text)) return 'boolean';
258
- if (/^[0-9]/.test(text)) return 'number';
259
- return 'expression';
260
- }
261
-
262
- function jsPropertyRegionKind(context, propertyName, value) {
263
- const named = jsRegionKindForDeclarationName(propertyName, value);
264
- if (named) return named;
265
- if (context.regionKind === 'route') return 'route';
266
- if (context.regionKind === 'content') return 'content';
267
- if (context.regionKind === 'config') return 'config';
268
- return 'property';
269
- }
270
-
271
213
  function jsContainerInitializerKind(initializer, name, source) {
272
214
  const text = String(initializer ?? '').trim();
273
215
  if (text.startsWith('{')) return 'object';
@@ -279,7 +221,7 @@ function jsContainerInitializerKind(initializer, name, source) {
279
221
 
280
222
  function jsContainerWrapperLooksSemantic(callee, name, source) {
281
223
  const signal = `${callee ?? ''} ${name ?? ''} ${source ?? ''}`.replace(/([a-z0-9])([A-Z])/g, '$1 $2').toLowerCase();
282
- return /\b(define|create|make|build|object\.freeze)\b/.test(signal) && /\b(config|settings|options|routes?|router|content|docs?|schema|registry|manifest|catalog|menu|nav)\b/.test(signal);
224
+ return /\b(define|create|make|build|object\.freeze)\b/.test(signal) && /\b(actions?|handlers?|tools?|commands?|events?|effects?|workflows?|config|settings|options|routes?|router|content|docs?|schema|registry|manifest|catalog|menu|nav)\b/.test(signal);
283
225
  }
284
226
 
285
227
  function jsContainerDelta(source) {
@@ -316,5 +258,5 @@ function findUnescapedBacktick(text, startIndex) {
316
258
 
317
259
  export { jsCommentOnlyLine, jsContainerDelta, jsDeclarationScanLine };
318
260
  export { jsExportAliasDeclaration, jsExportedContainerDeclaration, jsExportedFunctionWrapperDeclaration };
319
- export { jsInitializerKind, jsImportDeclarations, jsObjectPropertyDeclaration, jsObjectRegionContext };
320
- export { jsRegionKindForDeclarationName, jsRouteRecordDeclaration, jsVariableHasBody, jsVariableSymbolKind };
261
+ export { jsContainerInitializerKind, jsExportDeclarations, jsInitializerKind, jsImportDeclarations, jsObjectRegionContext };
262
+ export { jsRegionKindForDeclarationName, jsVariableHasBody, jsVariableSymbolKind };
@@ -1,7 +1,9 @@
1
1
  import {
2
+ nativeExportDeclaration,
2
3
  nativeImportBindingDeclaration,
3
4
  nativeImportDeclaration
4
5
  } from './native-region-scanner-core.js';
6
+ import { idFragment } from './native-import-utils.js';
5
7
 
6
8
  export function jsImportDeclarations(input, lineNumber, trimmed) {
7
9
  const importEquals = trimmed.match(/^import\s+(type\s+)?([A-Za-z_$][\w$]*)\s*=\s*require\s*\(\s*(['"])([^'"]+)\3\s*\)/);
@@ -28,7 +30,10 @@ export function jsImportDeclarations(input, lineNumber, trimmed) {
28
30
  : exportMatch[4]
29
31
  ? jsNamedImportBindings(exportMatch[4], { typeOnly, reexport: true })
30
32
  : [];
31
- return jsImportModuleDeclarations(input, lineNumber, importPath, 'ExportFromDeclaration', bindings, { typeOnly, reexport: true, exportStar: Boolean(exportMatch[2]) });
33
+ return [
34
+ ...jsImportModuleDeclarations(input, lineNumber, importPath, 'ExportFromDeclaration', bindings, { typeOnly, reexport: true, exportStar: Boolean(exportMatch[2]) }),
35
+ ...jsExportModuleDeclarations(input, lineNumber, importPath, bindings, { typeOnly, exportStar: Boolean(exportMatch[2]) })
36
+ ];
32
37
  }
33
38
  const destructuredRequireMatch = trimmed.match(/^(?:const|let|var)\s+\{([^}]+)\}\s*=\s*(?:await\s+)?(require|import)\s*\(\s*(['"])([^'"]+)\3\s*\)/);
34
39
  if (destructuredRequireMatch) {
@@ -54,6 +59,34 @@ export function jsImportDeclarations(input, lineNumber, trimmed) {
54
59
  return [];
55
60
  }
56
61
 
62
+ export function jsExportDeclarations(input, lineNumber, trimmed) {
63
+ if (/^export\s+(?:type\s+)?(?:\*|\{[^}]+\}\s+from\b)/.test(trimmed)) return [];
64
+ const named = trimmed.match(/^export\s+(type\s+)?\{([^}]+)\}\s*;?$/);
65
+ if (named) return jsLocalExportDeclarations(input, lineNumber, named[2], { typeOnly: Boolean(named[1]) });
66
+ const namespace = trimmed.match(/^export\s+as\s+namespace\s+([A-Za-z_$][\w$]*)\s*;?$/);
67
+ if (namespace) return [nativeExportDeclaration(input, lineNumber, namespace[1], 'ExportNamespaceDeclaration', {
68
+ exportKind: 'namespace'
69
+ })];
70
+ const assignment = trimmed.match(/^export\s*=\s*([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*;?$/);
71
+ if (assignment) return [nativeExportDeclaration(input, lineNumber, 'module.exports', 'ExportAssignment', {
72
+ exportKind: 'assignment',
73
+ localName: assignment[1]
74
+ }, { name: 'module.exports' })];
75
+ if (!trimmed.startsWith('export ')) return [];
76
+ const defaultMatch = trimmed.match(/^export\s+default\s+(.+)$/);
77
+ if (defaultMatch) return [nativeExportDeclaration(input, lineNumber, 'default', 'ExportDefaultDeclaration', {
78
+ exportDefault: true,
79
+ localName: jsExportedDeclarationName(defaultMatch[1])
80
+ }, { name: 'default' })];
81
+ const declarationSource = trimmed.replace(/^export\s+(?:declare\s+)?/, '');
82
+ if (!jsExportedDeclarationLooksComplete(declarationSource)) return [];
83
+ const exportedName = jsExportedDeclarationName(declarationSource);
84
+ if (!exportedName) return [];
85
+ return [nativeExportDeclaration(input, lineNumber, exportedName, 'ExportNamedDeclaration', {
86
+ declarationKind: jsExportedDeclarationKind(declarationSource)
87
+ })];
88
+ }
89
+
57
90
  function jsDestructuredImportBindings(raw, importKind) {
58
91
  return String(raw ?? '')
59
92
  .split(',')
@@ -100,6 +133,47 @@ function jsImportModuleDeclarations(input, lineNumber, importPath, languageKind,
100
133
  ];
101
134
  }
102
135
 
136
+ function jsExportModuleDeclarations(input, lineNumber, importPath, bindings = [], metadata = {}) {
137
+ const exports = bindings.map((binding) => ({
138
+ localName: binding.importedName,
139
+ exportedName: binding.exportedName ?? binding.localName,
140
+ exportKind: binding.importKind,
141
+ ...(binding.typeOnly ? { typeOnly: true } : {})
142
+ }));
143
+ const statementName = metadata.exportStar
144
+ ? `* from ${importPath}`
145
+ : exports.length
146
+ ? `{${exports.map((binding) => binding.exportedName).join(',')}} from ${importPath}`
147
+ : `from ${importPath}`;
148
+ return [
149
+ nativeExportDeclaration(input, lineNumber, statementName, 'ExportFromDeclaration', {
150
+ importPath: String(importPath),
151
+ exportBindings: exports,
152
+ ...(metadata.typeOnly ? { typeOnly: true } : {}),
153
+ ...(metadata.exportStar ? { exportStar: true } : {})
154
+ }, { symbolKind: 'module', metadata }),
155
+ ...exports.map((binding) => nativeExportDeclaration(input, lineNumber, binding.exportedName, 'ExportBinding', {
156
+ ...binding,
157
+ importPath: String(importPath)
158
+ }, { metadata: { ...binding, importPath: String(importPath) } }))
159
+ ];
160
+ }
161
+
162
+ function jsLocalExportDeclarations(input, lineNumber, raw, options = {}) {
163
+ const bindings = jsNamedExportBindings(raw, options);
164
+ if (!bindings.length) return [];
165
+ return [
166
+ nativeExportDeclaration(input, lineNumber, `{${bindings.map((binding) => binding.exportedName).join(',')}}`, 'ExportNamedDeclaration', {
167
+ exportBindings: bindings,
168
+ ...(options.typeOnly ? { typeOnly: true } : {})
169
+ }, {
170
+ symbolId: `symbol:${input.language}:export:statement:${idFragment(bindings.map((binding) => binding.exportedName).join('_'))}`,
171
+ metadata: { bindingCount: bindings.length, ...(options.typeOnly ? { typeOnly: true } : {}) }
172
+ }),
173
+ ...bindings.map((binding) => nativeExportDeclaration(input, lineNumber, binding.exportedName, 'ExportBinding', binding, { metadata: binding }))
174
+ ];
175
+ }
176
+
103
177
  function jsImportBindingsFromClause(clause, options = {}) {
104
178
  const source = String(clause ?? '').trim();
105
179
  if (!source) return [];
@@ -142,3 +216,49 @@ function jsNamedImportBinding(raw, options = {}) {
142
216
  typeOnly
143
217
  };
144
218
  }
219
+
220
+ function jsNamedExportBindings(raw, options = {}) {
221
+ return String(raw ?? '').split(',').map((part) => jsNamedExportBinding(part, options)).filter(Boolean);
222
+ }
223
+
224
+ function jsNamedExportBinding(raw, options = {}) {
225
+ let text = String(raw ?? '').trim();
226
+ if (!text) return undefined;
227
+ let typeOnly = Boolean(options.typeOnly);
228
+ if (text.startsWith('type ')) {
229
+ typeOnly = true;
230
+ text = text.slice(5).trim();
231
+ }
232
+ const match = text.match(/^([A-Za-z_$][\w$]*|\*)\s*(?:as\s+([A-Za-z_$][\w$]*|\*))?$/);
233
+ if (!match) return undefined;
234
+ const localName = match[1];
235
+ return { localName, exportedName: match[2] ?? localName, exportKind: typeOnly ? 'type-named' : 'named', typeOnly };
236
+ }
237
+
238
+ function jsExportedDeclarationName(source) {
239
+ const text = String(source ?? '').trim();
240
+ return text.match(/^(?:async\s+)?function\*?\s+([A-Za-z_$][\w$]*)/)?.[1]
241
+ ?? text.match(/^(?:abstract\s+)?class\s+([A-Za-z_$][\w$]*)/)?.[1]
242
+ ?? text.match(/^(?:const|let|var)\s+([A-Za-z_$][\w$]*)/)?.[1]
243
+ ?? text.match(/^type\s+([A-Za-z_$][\w$]*)/)?.[1]
244
+ ?? text.match(/^interface\s+([A-Za-z_$][\w$]*)/)?.[1]
245
+ ?? text.match(/^(?:const\s+)?enum\s+([A-Za-z_$][\w$]*)/)?.[1]
246
+ ?? text.match(/^([A-Za-z_$][\w$]*)\b/)?.[1]
247
+ ?? 'default';
248
+ }
249
+
250
+ function jsExportedDeclarationKind(source) {
251
+ const text = String(source ?? '').trim();
252
+ if (/^(?:async\s+)?function/.test(text)) return 'function';
253
+ if (/^(?:abstract\s+)?class/.test(text)) return 'class';
254
+ if (/^interface\b|^type\b|^(?:const\s+)?enum\b/.test(text)) return 'type';
255
+ if (/^(?:const|let|var)\b/.test(text)) return 'variable';
256
+ return 'value';
257
+ }
258
+
259
+ function jsExportedDeclarationLooksComplete(source) {
260
+ const text = String(source ?? '').trim();
261
+ if (/^(?:async\s+)?function/.test(text)) return text.includes(')') && /[;{]/.test(text);
262
+ if (/^(?:abstract\s+)?class/.test(text)) return text.includes('{') || text.endsWith(';');
263
+ return true;
264
+ }
@@ -1,5 +1,5 @@
1
- import { nativeDeclaration } from './native-region-scanner-core.js';
2
- import { jsContainerDelta, jsRegionKindForDeclarationName } from './native-region-scanner-js-helpers.js';
1
+ import { jsControlKeyword, nativeDeclaration, splitParameters } from './native-region-scanner-core.js';
2
+ import { jsContainerDelta, jsContainerInitializerKind, jsRegionKindForDeclarationName } from './native-region-scanner-js-helpers.js';
3
3
 
4
4
  function jsCurrentObjectContext(stack) {
5
5
  return stack[stack.length - 1];
@@ -9,6 +9,21 @@ function jsContextAllowsPropertyScan(context) {
9
9
  return context?.initializerKind === 'object';
10
10
  }
11
11
 
12
+ function jsArrayObjectContextFromLine(context, lineNumber, source) {
13
+ if (context?.initializerKind !== 'array' || context.arrayRecords !== true || !String(source ?? '').trim().startsWith('{')) return undefined;
14
+ const depth = jsContainerDelta(source);
15
+ if (depth <= 0) return undefined;
16
+ const index = (context.nextItemIndex ?? 0) + 1;
17
+ context.nextItemIndex = index;
18
+ return { name: `${context.name}.${index}`, ownerName: context.name, regionKind: context.regionKind, initializerKind: 'object', arrayItem: true, depth, startLine: lineNumber };
19
+ }
20
+
21
+ function updateJsArrayObjectContextName(context, source) {
22
+ if (!context?.arrayItem) return;
23
+ const match = String(source ?? '').trim().match(/^(?:name|id|key|slug|tool|command)\s*:\s*(['"`])([^'"`]+)\1/);
24
+ if (match) context.name = `${context.ownerName}.${match[2]}`;
25
+ }
26
+
12
27
  function jsNestedObjectContextFromDeclaration(declaration, lineNumber, source) {
13
28
  const initializerKind = declaration?.fields?.initializerKind ?? declaration?.metadata?.initializerKind;
14
29
  if (initializerKind !== 'object' && initializerKind !== 'array') return undefined;
@@ -32,9 +47,9 @@ function jsInlineNestedObjectDeclarations(input, lineNumber, source, parentDecla
32
47
  for (const entry of splitTopLevelEntries(body)) {
33
48
  const parsed = parseObjectEntry(entry);
34
49
  if (!parsed) continue;
35
- const initializerKind = nestedInitializerKind(parsed.value);
50
+ const initializerKind = parsed.method ? 'function' : nestedInitializerKind(parsed.value);
36
51
  const name = `${parentDeclaration.name}.${parsed.key}`;
37
- const regionKind = nestedPropertyRegionKind(parentDeclaration, parsed.key, parsed.value);
52
+ const regionKind = initializerKind === 'function' ? 'body' : nestedPropertyRegionKind(parentDeclaration, parsed.key, parsed.value);
38
53
  const declaration = nativeDeclaration(input, lineNumber, initializerKind === 'function' ? 'NestedObjectFunctionProperty' : 'NestedObjectProperty', initializerKind === 'function' ? 'function' : 'property', name, {
39
54
  owner: parentDeclaration.name,
40
55
  propertyName: parsed.key,
@@ -57,6 +72,73 @@ function updateJsObjectContextStack(stack, lineNumber, source) {
57
72
  while (stack.length && stack[stack.length - 1].depth <= 0) stack.pop();
58
73
  }
59
74
 
75
+ function jsObjectPropertyDeclaration(input, lineNumber, trimmed, context) {
76
+ if (/^[}\])]/.test(trimmed) || trimmed.startsWith('...')) return undefined;
77
+ const methodMatch = trimmed.match(/^(?:(?:async|get|set)\s+)?(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`]?)([A-Za-z_$][\w$-]*)\3)\s*\(([^)]*)\)\s*(?:[:\w\s<>\[\]]*)?(?:\{|=>|,|$)/);
78
+ const methodName = methodMatch?.[2] ?? methodMatch?.[4];
79
+ if (methodMatch && !jsControlKeyword(methodName)) {
80
+ const name = `${context.name}.${methodName}`;
81
+ return nativeDeclaration(input, lineNumber, 'ObjectMethod', 'function', name, {
82
+ owner: context.name,
83
+ propertyName: methodName,
84
+ parameters: splitParameters(methodMatch[5])
85
+ }, true, {
86
+ regionKind: 'body',
87
+ metadata: { owner: context.name, propertyName: methodName, initializerKind: 'function' }
88
+ });
89
+ }
90
+ const propertyMatch = trimmed.match(/^(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`])([^'"`]+)\3|([A-Za-z_$][\w$-]*))\s*:\s*(.+?)(?:,)?$/);
91
+ if (!propertyMatch) return undefined;
92
+ const propertyName = propertyMatch[2] ?? propertyMatch[4] ?? propertyMatch[5];
93
+ if (!propertyName || jsControlKeyword(propertyName)) return undefined;
94
+ const value = propertyMatch[6].trim();
95
+ const initializerKind = jsPropertyInitializerKind(value);
96
+ const functionLike = initializerKind === 'function';
97
+ const name = `${context.name}.${propertyName}`;
98
+ return nativeDeclaration(input, lineNumber, functionLike ? 'ObjectFunctionProperty' : 'ObjectProperty', functionLike ? 'function' : 'property', name, {
99
+ owner: context.name,
100
+ propertyName,
101
+ initializerKind
102
+ }, functionLike || initializerKind === 'object' || initializerKind === 'array', {
103
+ regionKind: functionLike ? 'body' : jsPropertyRegionKind(context, propertyName, value),
104
+ metadata: { owner: context.name, propertyName, initializerKind }
105
+ });
106
+ }
107
+
108
+ function jsRouteRecordDeclaration(input, lineNumber, trimmed, context) {
109
+ if (context.regionKind !== 'route') return undefined;
110
+ const match = trimmed.match(/^(?:\{\s*)?(?:path|route|href|url)\s*:\s*(['"`])([^'"`]+)\1/);
111
+ if (!match) return undefined;
112
+ const routePath = match[2];
113
+ return nativeDeclaration(input, lineNumber, 'RouteRecord', 'route', `${context.name}.${routePath}`, {
114
+ owner: context.name,
115
+ routePath
116
+ }, true, {
117
+ regionKind: 'route',
118
+ metadata: { owner: context.name, routePath, initializerKind: 'object' }
119
+ });
120
+ }
121
+
122
+ function jsPropertyInitializerKind(value) {
123
+ const text = String(value ?? '').trim();
124
+ if (/^(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/.test(text)) return 'function';
125
+ const containerKind = jsContainerInitializerKind(text, undefined, text);
126
+ if (containerKind) return containerKind;
127
+ if (/^['"`]/.test(text)) return 'string';
128
+ if (/^(?:true|false)\b/.test(text)) return 'boolean';
129
+ if (/^[0-9]/.test(text)) return 'number';
130
+ return 'expression';
131
+ }
132
+
133
+ function jsPropertyRegionKind(context, propertyName, value) {
134
+ const named = jsRegionKindForDeclarationName(propertyName, value);
135
+ if (named) return named;
136
+ if (context.regionKind === 'route') return 'route';
137
+ if (context.regionKind === 'content') return 'content';
138
+ if (context.regionKind === 'config') return 'config';
139
+ return 'property';
140
+ }
141
+
60
142
  function inlineObjectBody(source) {
61
143
  const text = String(source ?? '');
62
144
  const open = text.indexOf('{');
@@ -113,10 +195,12 @@ function splitTopLevelEntries(body) {
113
195
  }
114
196
 
115
197
  function parseObjectEntry(entry) {
116
- if (!entry || entry.startsWith('...') || entry.startsWith('[')) return undefined;
117
- const match = entry.match(/^(?:(['"])([^'"]+)\1|([A-Za-z_$][\w$-]*))\s*:\s*(.+)$/s);
118
- if (!match) return undefined;
119
- return { key: match[2] ?? match[3], value: match[4].trim() };
198
+ if (!entry || entry.startsWith('...')) return undefined;
199
+ const match = entry.match(/^(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`])([^'"`]+)\3|([A-Za-z_$][\w$-]*))\s*:\s*(.+)$/s);
200
+ if (match) return { key: match[2] ?? match[4] ?? match[5], value: match[6].trim() };
201
+ const methodMatch = entry.match(/^(?:(?:async|get|set)\s+)?(?:\[\s*(['"`])([^'"`]+)\1\s*\]|(['"`]?)([A-Za-z_$][\w$-]*)\3)\s*\(([^)]*)\)\s*(?:[:\w\s<>\[\]]*)?(?:\{|=>|$)/s);
202
+ if (!methodMatch) return undefined;
203
+ return { key: methodMatch[2] ?? methodMatch[4], value: entry.trim(), method: true };
120
204
  }
121
205
 
122
206
  function nestedInitializerKind(value) {
@@ -139,9 +223,13 @@ function nestedPropertyRegionKind(parentDeclaration, propertyName, value) {
139
223
  }
140
224
 
141
225
  export {
226
+ jsArrayObjectContextFromLine,
142
227
  jsContextAllowsPropertyScan,
143
228
  jsCurrentObjectContext,
144
229
  jsInlineNestedObjectDeclarations,
145
230
  jsNestedObjectContextFromDeclaration,
231
+ jsObjectPropertyDeclaration,
232
+ jsRouteRecordDeclaration,
233
+ updateJsArrayObjectContextName,
146
234
  updateJsObjectContextStack
147
235
  };
@@ -0,0 +1,27 @@
1
+ function jsStructureDelta(source) {
2
+ let value = 0;
3
+ let opened = false;
4
+ let quote;
5
+ let escaped = false;
6
+ for (const char of String(source ?? '')) {
7
+ if (quote) {
8
+ if (escaped) escaped = false;
9
+ else if (char === '\\') escaped = true;
10
+ else if (char === quote) quote = undefined;
11
+ continue;
12
+ }
13
+ if (char === '\'' || char === '"' || char === '`') {
14
+ quote = char;
15
+ continue;
16
+ }
17
+ if (char === '{' || char === '[' || char === '(') {
18
+ value += 1;
19
+ opened = true;
20
+ } else if (char === '}' || char === ']' || char === ')') {
21
+ value -= 1;
22
+ }
23
+ }
24
+ return { value, opened };
25
+ }
26
+
27
+ export { jsStructureDelta };
@@ -0,0 +1,99 @@
1
+ import {
2
+ jsControlKeyword,
3
+ nativeDeclaration,
4
+ nativeSignatureDeclaration,
5
+ splitParameters
6
+ } from './native-region-scanner-core.js';
7
+ import { jsRegionKindForDeclarationName } from './native-region-scanner-js-helpers.js';
8
+ import { jsStructureDelta } from './native-region-scanner-js-structure.js';
9
+
10
+ function jsTypeRegionContext(name, declarationLine, lineNumber, regionKind, typeKind) {
11
+ const depth = jsStructureDelta(declarationLine).value;
12
+ if (depth <= 0) return undefined;
13
+ return {
14
+ name,
15
+ typeKind,
16
+ regionKind,
17
+ depth,
18
+ startLine: lineNumber,
19
+ memberStack: []
20
+ };
21
+ }
22
+
23
+ function jsCurrentTypeMemberContext(context) {
24
+ return context.memberStack.at(-1) ?? context;
25
+ }
26
+
27
+ function updateJsTypeRegionContext(context, lineNumber, source) {
28
+ const delta = jsStructureDelta(source).value;
29
+ context.depth += delta;
30
+ for (const memberContext of context.memberStack) {
31
+ if (memberContext.startLine !== lineNumber) memberContext.depth += delta;
32
+ }
33
+ while (context.memberStack.length && context.memberStack.at(-1).depth <= 0) context.memberStack.pop();
34
+ }
35
+
36
+ function jsTypeMemberDeclaration(input, lineNumber, declarationLine, context) {
37
+ const text = String(declarationLine ?? '').trim();
38
+ if (!text || /^[}\])]/.test(text) || text.startsWith('//')) return undefined;
39
+ let match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*(?:<[^({;]+>)?\s*\(([^)]*)\)\s*(?::\s*([^;,]+))?[;,]?$/);
40
+ if (match && !jsControlKeyword(match[2])) {
41
+ return nativeSignatureDeclaration(input, lineNumber, 'TypeMethodSignature', 'method', `${context.name}.${match[2]}`, {
42
+ owner: context.name,
43
+ propertyName: match[2],
44
+ parameters: splitParameters(match[3]),
45
+ returnType: match[4]?.trim(),
46
+ typeKind: context.typeKind
47
+ }, false, {
48
+ regionKind: jsTypeMemberRegionKind(context, match[2], text),
49
+ metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
50
+ });
51
+ }
52
+ match = text.match(/^(?:readonly\s+)?(['"]?)([A-Za-z_$][\w$-]*)\1\??\s*:\s*(.+?)[;,]?$/);
53
+ if (!match || jsControlKeyword(match[2])) return undefined;
54
+ const valueType = match[3].trim();
55
+ const functionLike = /=>/.test(valueType) || /^\([^)]*\)\s*=>/.test(valueType);
56
+ const hasNestedTypeLiteralBody = jsTypeMemberValueStartsTypeLiteral(valueType) && jsStructureDelta(text).value > 0;
57
+ return (functionLike ? nativeSignatureDeclaration : nativeDeclaration)(input, lineNumber, functionLike ? 'TypeFunctionPropertySignature' : 'TypePropertySignature', functionLike ? 'function' : 'property', `${context.name}.${match[2]}`, {
58
+ owner: context.name,
59
+ propertyName: match[2],
60
+ valueType,
61
+ typeKind: context.typeKind
62
+ }, hasNestedTypeLiteralBody, {
63
+ regionKind: jsTypeMemberRegionKind(context, match[2], text),
64
+ metadata: { owner: context.name, propertyName: match[2], typeKind: context.typeKind }
65
+ });
66
+ }
67
+
68
+ function jsNestedTypeMemberContextFromDeclaration(declaration, lineNumber, source, parentContext) {
69
+ if (!declaration) return undefined;
70
+ const depth = jsStructureDelta(source).value;
71
+ if (depth <= 0) return undefined;
72
+ const valueType = declaration.fields?.valueType ?? declaration.fields?.returnType;
73
+ const nestedTypeLiteral = jsTypeMemberValueStartsTypeLiteral(valueType);
74
+ return {
75
+ name: nestedTypeLiteral ? declaration.name : parentContext.name,
76
+ typeKind: parentContext.typeKind,
77
+ regionKind: nestedTypeLiteral ? (declaration.regionKind ?? 'property') : parentContext.regionKind,
78
+ depth,
79
+ startLine: lineNumber,
80
+ suppressMembers: !nestedTypeLiteral
81
+ };
82
+ }
83
+
84
+ function jsTypeMemberValueStartsTypeLiteral(valueType) {
85
+ const text = String(valueType ?? '').trim();
86
+ return text.startsWith('{') || /=>\s*\{\s*$/.test(text);
87
+ }
88
+
89
+ function jsTypeMemberRegionKind(context, propertyName) {
90
+ return jsRegionKindForDeclarationName(propertyName) ?? (context.regionKind === 'type' ? 'property' : context.regionKind) ?? 'property';
91
+ }
92
+
93
+ export {
94
+ jsCurrentTypeMemberContext,
95
+ jsNestedTypeMemberContextFromDeclaration,
96
+ jsTypeMemberDeclaration,
97
+ jsTypeRegionContext,
98
+ updateJsTypeRegionContext
99
+ };