@shapeshift-labs/frontier-lang-compiler 0.2.150 → 0.2.151

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 (276) hide show
  1. package/README.md +315 -9
  2. package/bench/real-repo-corpus-checkout-identity.mjs +134 -0
  3. package/bench/real-repo-corpus-checkout-proof.mjs +263 -0
  4. package/bench/real-repo-corpus-command-execution.mjs +314 -0
  5. package/bench/real-repo-corpus-evidence.mjs +165 -0
  6. package/bench/real-repo-corpus-suite.mjs +273 -0
  7. package/bench/smoke.mjs +109 -7
  8. package/dist/declarations/import-adapter-core.d.ts +4 -3
  9. package/dist/declarations/import-adapter-options-native.d.ts +21 -0
  10. package/dist/declarations/js-ts-project-merge-admission-routes.d.ts +35 -0
  11. package/dist/declarations/js-ts-project-merge-commonjs-interop.d.ts +29 -0
  12. package/dist/declarations/js-ts-project-merge-confidence.d.ts +64 -0
  13. package/dist/declarations/js-ts-project-merge-declaration-emit-parity.d.ts +37 -0
  14. package/dist/declarations/js-ts-project-merge-declarations.d.ts +65 -0
  15. package/dist/declarations/js-ts-project-merge-diagnostics.d.ts +97 -0
  16. package/dist/declarations/js-ts-project-merge-global-augmentation.d.ts +30 -0
  17. package/dist/declarations/js-ts-project-merge-jsx-render-branch.d.ts +48 -0
  18. package/dist/declarations/js-ts-project-merge-proof-levels.d.ts +109 -0
  19. package/dist/declarations/js-ts-project-merge-quality-gates.d.ts +38 -0
  20. package/dist/declarations/js-ts-project-merge-semantic-equivalence-proof.d.ts +45 -0
  21. package/dist/declarations/js-ts-project-merge-tsconfig.d.ts +43 -0
  22. package/dist/declarations/js-ts-safe-merge.d.ts +47 -0
  23. package/dist/declarations/js-ts-safe-project-merge.d.ts +120 -38
  24. package/dist/declarations/native-project-compiler-assignability-oracle.d.ts +41 -0
  25. package/dist/declarations/native-project-compiler-callable-signatures.d.ts +31 -0
  26. package/dist/declarations/native-project-compiler-class-member-runtime-proof.d.ts +87 -0
  27. package/dist/declarations/native-project-compiler-composite-types.d.ts +23 -0
  28. package/dist/declarations/native-project-compiler-enum-proof.d.ts +58 -0
  29. package/dist/declarations/native-project-compiler-index-signature.d.ts +7 -0
  30. package/dist/declarations/native-project-compiler-public-api-source-binding.d.ts +8 -0
  31. package/dist/declarations/native-project-compiler-scope.d.ts +37 -0
  32. package/dist/declarations/native-project-compiler-type-reference-targets.d.ts +38 -0
  33. package/dist/declarations/native-project-css-modules.d.ts +90 -0
  34. package/dist/declarations/native-project-decorator-metadata.d.ts +126 -0
  35. package/dist/declarations/native-project-jsx-graph.d.ts +313 -0
  36. package/dist/declarations/native-project-module-declarations.d.ts +52 -0
  37. package/dist/declarations/native-project-module-resolution.d.ts +76 -1
  38. package/dist/declarations/native-project-runtime-effect-target.d.ts +29 -0
  39. package/dist/declarations/native-project-runtime-executable-effect-evidence.d.ts +107 -0
  40. package/dist/declarations/native-project-runtime-mutation-target.d.ts +33 -0
  41. package/dist/declarations/native-project-runtime-promise-chain.d.ts +30 -0
  42. package/dist/declarations/native-project-runtime-promise-combinator.d.ts +22 -0
  43. package/dist/declarations/native-project-runtime-reachability.d.ts +30 -0
  44. package/dist/declarations/native-project-runtime-resource-management.d.ts +27 -0
  45. package/dist/declarations/native-project-runtime-yield-delegation.d.ts +10 -0
  46. package/dist/declarations/native-project-scope-template-reference.d.ts +13 -0
  47. package/dist/declarations/native-project-source-evidence.d.ts +8 -0
  48. package/dist/declarations/native-project.d.ts +40 -39
  49. package/dist/declarations/semantic-edit-script.d.ts +10 -8
  50. package/dist/declarations/semantic-graph-layers.d.ts +79 -0
  51. package/dist/declarations/semantic-sidecar.d.ts +3 -2
  52. package/dist/declarations/semantic-structural-diff.d.ts +94 -0
  53. package/dist/declarations/source-preservation.d.ts +32 -1
  54. package/dist/declarations/target-adapters.d.ts +22 -2
  55. package/dist/index.d.ts +31 -0
  56. package/dist/index.js +5 -0
  57. package/dist/internal/index-impl/compileNativeSource.js +53 -5
  58. package/dist/internal/index-impl/createLightweightNativeImport.js +58 -4
  59. package/dist/internal/index-impl/createNativeImportFromSyntaxAst.js +17 -1
  60. package/dist/internal/index-impl/createNativeImportFromTypeScriptAst.js +28 -4
  61. package/dist/internal/index-impl/createNativeProjectImportResult.js +31 -27
  62. package/dist/internal/index-impl/createNativeProjectModuleResolutionFromPackageManifests.js +145 -0
  63. package/dist/internal/index-impl/createNativeSourcePreservation.js +34 -7
  64. package/dist/internal/index-impl/createSemanticImportSidecar.js +27 -1
  65. package/dist/internal/index-impl/createTypeScriptCompilerNativeImporterAdapter.js +16 -5
  66. package/dist/internal/index-impl/dynamicImportExpressionMetadata.js +80 -0
  67. package/dist/internal/index-impl/importMetaUrlDependencyMetadata.js +176 -0
  68. package/dist/internal/index-impl/importNativeSource.js +2 -3
  69. package/dist/internal/index-impl/moduleImportAttributeMetadata.js +232 -0
  70. package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +8 -1
  71. package/dist/internal/index-impl/projectSymbolGraphClassStaticBlocks.js +148 -0
  72. package/dist/internal/index-impl/projectSymbolGraphCompilerAdvancedTypeMetadata.js +45 -0
  73. package/dist/internal/index-impl/projectSymbolGraphCompilerCallableSignatureEquivalence.js +107 -0
  74. package/dist/internal/index-impl/projectSymbolGraphCompilerClassPrivateAccessorRuntimeProof.js +280 -0
  75. package/dist/internal/index-impl/projectSymbolGraphCompilerClassShapeEquivalence.js +103 -0
  76. package/dist/internal/index-impl/projectSymbolGraphCompilerConditionalTypeEquivalence.js +242 -0
  77. package/dist/internal/index-impl/projectSymbolGraphCompilerDecoratorRuntimeProof.js +197 -0
  78. package/dist/internal/index-impl/projectSymbolGraphCompilerEnumEquivalence.js +188 -0
  79. package/dist/internal/index-impl/projectSymbolGraphCompilerFacts.js +244 -0
  80. package/dist/internal/index-impl/projectSymbolGraphCompilerIndexSignatureEquivalence.js +58 -0
  81. package/dist/internal/index-impl/projectSymbolGraphCompilerMetadata.js +168 -0
  82. package/dist/internal/index-impl/projectSymbolGraphCompilerTypeEquivalence.js +199 -0
  83. package/dist/internal/index-impl/projectSymbolGraphCompilerTypeEquivalenceProof.js +204 -0
  84. package/dist/internal/index-impl/projectSymbolGraphCompilerTypeReferenceTargetEquivalence.js +99 -0
  85. package/dist/internal/index-impl/projectSymbolGraphCssModuleRecords.js +264 -0
  86. package/dist/internal/index-impl/projectSymbolGraphCssModuleScanners.js +242 -0
  87. package/dist/internal/index-impl/projectSymbolGraphCssModuleUtils.js +152 -0
  88. package/dist/internal/index-impl/projectSymbolGraphCssModules.js +82 -0
  89. package/dist/internal/index-impl/projectSymbolGraphJsxComponentImports.js +170 -0
  90. package/dist/internal/index-impl/projectSymbolGraphJsxComponentProviderLookup.js +167 -0
  91. package/dist/internal/index-impl/projectSymbolGraphJsxComponentWrappers.js +150 -0
  92. package/dist/internal/index-impl/projectSymbolGraphJsxContextTargets.js +71 -0
  93. package/dist/internal/index-impl/projectSymbolGraphJsxContextValues.js +212 -0
  94. package/dist/internal/index-impl/projectSymbolGraphJsxEventHandlers.js +172 -0
  95. package/dist/internal/index-impl/projectSymbolGraphJsxHookEffects.js +124 -0
  96. package/dist/internal/index-impl/projectSymbolGraphJsxHooks.js +281 -0
  97. package/dist/internal/index-impl/projectSymbolGraphJsxMemberComponents.js +139 -0
  98. package/dist/internal/index-impl/projectSymbolGraphJsxPropFlows.js +320 -0
  99. package/dist/internal/index-impl/projectSymbolGraphJsxPropValues.js +145 -0
  100. package/dist/internal/index-impl/projectSymbolGraphJsxProviderFlows.js +133 -0
  101. package/dist/internal/index-impl/projectSymbolGraphJsxRecords.js +315 -0
  102. package/dist/internal/index-impl/projectSymbolGraphJsxRenderCollections.js +155 -0
  103. package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturns.js +291 -0
  104. package/dist/internal/index-impl/projectSymbolGraphJsxRenderRisk.js +279 -0
  105. package/dist/internal/index-impl/projectSymbolGraphModuleDeclarationShapes.js +138 -0
  106. package/dist/internal/index-impl/projectSymbolGraphModuleResolution.js +89 -87
  107. package/dist/internal/index-impl/projectSymbolGraphPackageConditions.js +314 -0
  108. package/dist/internal/index-impl/projectSymbolGraphReExportImportTargets.js +43 -0
  109. package/dist/internal/index-impl/projectSymbolGraphReExports.js +55 -1
  110. package/dist/internal/index-impl/projectSymbolGraphRuntimeRegions.js +108 -0
  111. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefAliases.js +307 -0
  112. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefLexical.js +320 -0
  113. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefOwners.js +50 -0
  114. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefRecordBuilders.js +112 -0
  115. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefRecords.js +238 -0
  116. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefStructural.js +104 -0
  117. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefStructuralNormalize.js +242 -0
  118. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefUseHashes.js +107 -0
  119. package/dist/internal/index-impl/projectSymbolGraphSourceMapGeneratedBoundary.js +111 -0
  120. package/dist/internal/index-impl/projectSymbolGraphSourceRecords.js +268 -0
  121. package/dist/internal/index-impl/projectSymbolGraphSourceRecordsOwnership.js +309 -0
  122. package/dist/internal/index-impl/replaySemanticEditProjection.js +53 -39
  123. package/dist/internal/index-impl/runtimeOrderEvidenceBinding.js +151 -0
  124. package/dist/internal/index-impl/runtimeOrderProofSurfaces.js +253 -0
  125. package/dist/internal/index-impl/semanticEditCallsiteArgumentMerge.js +319 -0
  126. package/dist/internal/index-impl/semanticEditExplicitSourceReplacement.js +7 -2
  127. package/dist/internal/index-impl/semanticEditProjectionRecord.js +8 -0
  128. package/dist/internal/index-impl/semanticEditReplayDiagnostics.js +7 -2
  129. package/dist/internal/index-impl/semanticEditReplayOutputBinding.js +61 -0
  130. package/dist/internal/index-impl/semanticEditReplayRerunRoute.js +27 -0
  131. package/dist/internal/index-impl/semanticEditReplaySourceReplacement.js +6 -1
  132. package/dist/internal/index-impl/semanticEditRuntimeOrderReasons.js +320 -0
  133. package/dist/internal/index-impl/semanticEditScriptClassification.js +90 -5
  134. package/dist/internal/index-impl/semanticEditScripts.js +42 -5
  135. package/dist/internal/index-impl/semanticEditTypeSyntaxReasons.js +134 -0
  136. package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +11 -5
  137. package/dist/internal/index-impl/semanticStructuralDiffRecords.js +150 -0
  138. package/dist/internal/index-impl/sourceMapGeneratedBoundaryGate.js +185 -0
  139. package/dist/internal/index-impl/staticMemberLiteral.js +31 -0
  140. package/dist/internal/index-impl/staticOptionalMemberReference.js +22 -0
  141. package/dist/internal/index-impl/syntaxAstSourcePreservation.js +273 -0
  142. package/dist/internal/index-impl/syntaxCommonJsModuleDeclarationEntries.js +297 -0
  143. package/dist/internal/index-impl/syntaxModuleDeclarationEntries.js +56 -132
  144. package/dist/internal/index-impl/syntaxModuleEntryRecords.js +160 -0
  145. package/dist/internal/index-impl/typeScriptCompilerAdvancedTypeShapes.js +160 -0
  146. package/dist/internal/index-impl/typeScriptCompilerAssignabilityOracle.js +97 -0
  147. package/dist/internal/index-impl/typeScriptCompilerClassApi.js +238 -0
  148. package/dist/internal/index-impl/typeScriptCompilerDecoratorMetadata.js +290 -0
  149. package/dist/internal/index-impl/typeScriptCompilerEnumShape.js +279 -0
  150. package/dist/internal/index-impl/typeScriptCompilerFacts.js +294 -0
  151. package/dist/internal/index-impl/typeScriptCompilerInferenceSyntax.js +170 -0
  152. package/dist/internal/index-impl/typeScriptCompilerReferenceGraph.js +186 -0
  153. package/dist/internal/index-impl/typeScriptCompilerSymbolIdentity.js +294 -0
  154. package/dist/internal/index-impl/typeScriptCompilerTypeReferenceTargets.js +142 -0
  155. package/dist/internal/index-impl/typeScriptDeclaration.js +10 -38
  156. package/dist/internal/index-impl/typeScriptModuleDeclarationEntries.js +52 -15
  157. package/dist/internal/index-impl/typeScriptSourceFilePreservation.js +296 -0
  158. package/dist/js-ts-safe-member-class-invariants.js +247 -0
  159. package/dist/js-ts-safe-member-merge-result.js +23 -3
  160. package/dist/js-ts-safe-member-merge.js +28 -4
  161. package/dist/js-ts-safe-merge-binding-patterns.js +170 -0
  162. package/dist/js-ts-safe-merge-jsx-attribute-fallback.js +151 -157
  163. package/dist/js-ts-safe-merge-jsx-attribute-parser.js +277 -0
  164. package/dist/js-ts-safe-merge-jsx-child-expression-fallback.js +161 -0
  165. package/dist/js-ts-safe-merge-jsx-child-expression-merge.js +319 -0
  166. package/dist/js-ts-safe-merge-jsx-child-expression-parser.js +300 -0
  167. package/dist/js-ts-safe-merge-parse-declarations.js +46 -2
  168. package/dist/js-ts-safe-merge-parse-statements.js +8 -0
  169. package/dist/js-ts-safe-merge-semantic-edit-fallback.js +13 -5
  170. package/dist/js-ts-safe-merge-source-shape-fallbacks.js +3 -1
  171. package/dist/js-ts-safe-merge-top-level-rename-fallback.js +31 -5
  172. package/dist/js-ts-safe-merge-top-level-rename-result.js +7 -2
  173. package/dist/js-ts-safe-merge-variable-declarator-fallback.js +124 -6
  174. package/dist/js-ts-safe-merge-variable-declarator-parser.js +34 -4
  175. package/dist/js-ts-safe-merge.js +136 -0
  176. package/dist/js-ts-safe-project-merge-admission-routes.js +216 -0
  177. package/dist/js-ts-safe-project-merge-admission.js +161 -0
  178. package/dist/js-ts-safe-project-merge-ambient.js +110 -0
  179. package/dist/js-ts-safe-project-merge-core.js +85 -0
  180. package/dist/js-ts-safe-project-merge-css-module-conflicts.js +60 -0
  181. package/dist/js-ts-safe-project-merge-declaration-emit-parity.js +186 -0
  182. package/dist/js-ts-safe-project-merge-declarations.js +227 -0
  183. package/dist/js-ts-safe-project-merge-diagnostics-metadata.js +42 -0
  184. package/dist/js-ts-safe-project-merge-diagnostics-ts.js +73 -0
  185. package/dist/js-ts-safe-project-merge-diagnostics.js +283 -0
  186. package/dist/js-ts-safe-project-merge-evidence-routing.js +38 -0
  187. package/dist/js-ts-safe-project-merge-files.js +70 -0
  188. package/dist/js-ts-safe-project-merge-global-augmentation-compatibility.js +99 -0
  189. package/dist/js-ts-safe-project-merge-graph-conflicts.js +90 -2
  190. package/dist/js-ts-safe-project-merge-graph-delta-commonjs-interop.js +108 -0
  191. package/dist/js-ts-safe-project-merge-graph-delta-compiler-conflicts.js +179 -0
  192. package/dist/js-ts-safe-project-merge-graph-delta-compiler-details.js +189 -0
  193. package/dist/js-ts-safe-project-merge-graph-delta-conflicts.js +51 -184
  194. package/dist/js-ts-safe-project-merge-graph-delta-identity-conflicts.js +202 -0
  195. package/dist/js-ts-safe-project-merge-graph-delta-inference-syntax.js +80 -0
  196. package/dist/js-ts-safe-project-merge-graph-delta-module-declarations.js +155 -0
  197. package/dist/js-ts-safe-project-merge-graph-limits.js +16 -1
  198. package/dist/js-ts-safe-project-merge-graph.js +37 -5
  199. package/dist/js-ts-safe-project-merge-import-removal.js +292 -0
  200. package/dist/js-ts-safe-project-merge-jsx-graph-conflict-details.js +235 -0
  201. package/dist/js-ts-safe-project-merge-jsx-graph-conflicts.js +173 -0
  202. package/dist/js-ts-safe-project-merge-jsx-prop-contracts.js +86 -0
  203. package/dist/js-ts-safe-project-merge-jsx-render-branch-proof.js +189 -0
  204. package/dist/js-ts-safe-project-merge-missing-evidence.js +310 -0
  205. package/dist/js-ts-safe-project-merge-move-rename.js +209 -0
  206. package/dist/js-ts-safe-project-merge-proof-conflicts.js +44 -0
  207. package/dist/js-ts-safe-project-merge-proof-levels.js +320 -0
  208. package/dist/js-ts-safe-project-merge-quality-gates.js +140 -0
  209. package/dist/js-ts-safe-project-merge-routing-calibration.js +125 -0
  210. package/dist/js-ts-safe-project-merge-runtime-region-conflicts.js +156 -0
  211. package/dist/js-ts-safe-project-merge-scope-use-def-conflicts.js +292 -0
  212. package/dist/js-ts-safe-project-merge-semantic-equivalence-proof.js +175 -0
  213. package/dist/js-ts-safe-project-merge-semantic-replay-proof.js +311 -0
  214. package/dist/js-ts-safe-project-merge-semantic-replay-routes.js +179 -0
  215. package/dist/js-ts-safe-project-merge-source-span-conflicts.js +310 -0
  216. package/dist/js-ts-safe-project-merge-source-span-roundtrip-proof.js +172 -0
  217. package/dist/js-ts-safe-project-merge-split-merge-admission.js +96 -0
  218. package/dist/js-ts-safe-project-merge-split-merge-records.js +320 -0
  219. package/dist/js-ts-safe-project-merge-split-merge-shapes.js +234 -0
  220. package/dist/js-ts-safe-project-merge-split-merge.js +218 -0
  221. package/dist/js-ts-safe-project-merge-summary.js +320 -0
  222. package/dist/js-ts-safe-project-merge-symbol-move-admission.js +63 -0
  223. package/dist/js-ts-safe-project-merge-symbol-move-default-admission.js +143 -0
  224. package/dist/js-ts-safe-project-merge-symbol-move-risks.js +213 -0
  225. package/dist/js-ts-safe-project-merge-symbol-move.js +316 -0
  226. package/dist/js-ts-safe-project-merge-symbol-rename-admission.js +59 -0
  227. package/dist/js-ts-safe-project-merge-symbol-rename-default-admission.js +111 -0
  228. package/dist/js-ts-safe-project-merge-symbol-rename.js +319 -0
  229. package/dist/js-ts-safe-project-merge-ts-options.js +205 -0
  230. package/dist/js-ts-safe-project-merge-ts-program.js +268 -0
  231. package/dist/js-ts-safe-project-merge-typed-property-rename-rebase-utils.js +69 -0
  232. package/dist/js-ts-safe-project-merge-typed-property-rename-rebase.js +317 -0
  233. package/dist/js-ts-safe-project-merge-unsupported-surfaces.js +319 -0
  234. package/dist/js-ts-safe-project-merge.js +170 -171
  235. package/dist/js-ts-semantic-scope-use-def-bindings.js +287 -0
  236. package/dist/js-ts-semantic-scope-use-def-scan.js +241 -0
  237. package/dist/js-ts-semantic-scope-use-def-utils.js +132 -0
  238. package/dist/js-ts-semantic-scope-use-def.js +217 -0
  239. package/dist/lightweight-dependency-effects.js +28 -4
  240. package/dist/lightweight-dependency-relations.js +13 -7
  241. package/dist/lightweight-dependency-top-level.js +63 -0
  242. package/dist/native-import-language-profiles.js +27 -1
  243. package/dist/native-js-ts-importers.js +9 -5
  244. package/dist/native-parser-ast-format-profiles.js +12 -0
  245. package/dist/native-parser-html-css-format-profiles.js +85 -0
  246. package/dist/native-region-scanner-core.js +5 -3
  247. package/dist/native-region-scanner-js-commonjs.js +155 -0
  248. package/dist/native-region-scanner-js-imports.js +51 -13
  249. package/dist/native-region-scanner-js-reexports.js +79 -0
  250. package/dist/native-region-scanner-js-ts-helpers.js +23 -0
  251. package/dist/native-source-ledger-helpers.js +1 -1
  252. package/dist/native-source-ledger.js +24 -10
  253. package/dist/native-source-maps-ecma426.js +316 -0
  254. package/dist/native-source-maps.js +36 -6
  255. package/dist/native-source-preservation-ownership.js +292 -0
  256. package/dist/native-source-preservation-scanner.js +63 -25
  257. package/dist/native-source-preservation-types.d.ts +3 -0
  258. package/dist/semantic-import-effect-occurrences.js +242 -0
  259. package/dist/semantic-import-effect-regions.js +95 -58
  260. package/dist/semantic-import-graph-layers.js +224 -0
  261. package/dist/semantic-import-runtime-conditional-evidence.js +135 -0
  262. package/dist/semantic-import-runtime-effect-target-evidence.js +145 -0
  263. package/dist/semantic-import-runtime-exit-evidence.js +32 -0
  264. package/dist/semantic-import-runtime-import-meta-evidence.js +33 -0
  265. package/dist/semantic-import-runtime-mutation-evidence.js +155 -0
  266. package/dist/semantic-import-runtime-order-evidence.js +318 -0
  267. package/dist/semantic-import-runtime-promise-chain-evidence.js +103 -0
  268. package/dist/semantic-import-runtime-promise-combinator-evidence.js +166 -0
  269. package/dist/semantic-import-runtime-reachability-evidence.js +269 -0
  270. package/dist/semantic-import-runtime-resource-management-evidence.js +293 -0
  271. package/dist/semantic-import-runtime-switch-evidence.js +304 -0
  272. package/dist/semantic-import-runtime-throw-evidence.js +44 -0
  273. package/dist/semantic-import-runtime-try-finally-evidence.js +172 -0
  274. package/dist/semantic-import-sidecar-entry.js +4 -0
  275. package/dist/semantic-import-source-preservation.js +6 -2
  276. package/package.json +1 -1
@@ -1,6 +1,8 @@
1
- import { JsTsSafeMergeStatuses } from './js-ts-safe-merge-constants.js';
1
+ import { JsTsSafeMergeStatuses, jsTsSafeMergeGateOrder } from './js-ts-safe-merge-constants.js';
2
2
  import { createJsTsSafeMergeSemanticArtifacts } from './js-ts-safe-merge-semantic-artifacts.js';
3
3
  import { uniqueStrings } from './js-ts-safe-merge-context.js';
4
+ import { attributeMap, isJsxComponentTag, isJsxSpreadAttribute, parseJsxTags, sameAttributeNames, sameAttrText, sameTagText } from './js-ts-safe-merge-jsx-attribute-parser.js';
5
+ import { hasConditionalChildExpressionOperator, parseDirectChildren, parseJsxSource } from './js-ts-safe-merge-jsx-child-expression-parser.js';
4
6
  import { semanticFallbackChangedExistingDeclarations } from './js-ts-safe-merge-semantic-edit-fallback-utils.js';
5
7
 
6
8
  function createJsxAttributeSemanticFallbackResult(input, topLevelResult, stagedFallback) {
@@ -13,7 +15,8 @@ function createJsxAttributeSemanticFallbackResult(input, topLevelResult, stagedF
13
15
  headSourceText: input.headSourceText,
14
16
  currentSourceText
15
17
  });
16
- if (!merge.ok || merge.sourceText === currentSourceText) return undefined;
18
+ if (!merge.ok) return merge.policyBlocker ? jsxAttributeBlockedResult(input, topLevelResult, merge, stagedFallback) : undefined;
19
+ if (merge.sourceText === currentSourceText) return undefined;
17
20
  const resultBase = stagedFallback?.stagedTopLevelResult ?? topLevelResult;
18
21
  const language = input.language ?? topLevelResult.language ?? 'tsx';
19
22
  const sourcePath = input.sourcePath ?? topLevelResult.sourcePath ?? 'inline.tsx';
@@ -63,6 +66,8 @@ function createJsxAttributeSemanticFallbackResult(input, topLevelResult, stagedF
63
66
  semanticEditReplayStatus: artifacts.replay.status,
64
67
  jsxAttributeTags: merge.summary.tags,
65
68
  jsxAttributeEdits: merge.summary.edits,
69
+ jsxComponentPropContractCandidates: merge.summary.componentPropContracts.length,
70
+ jsxComponentPropContractAttributes: merge.summary.componentPropContractAttributes,
66
71
  composedPhases: 2
67
72
  },
68
73
  metadata: {
@@ -84,6 +89,62 @@ function createJsxAttributeSemanticFallbackResult(input, topLevelResult, stagedF
84
89
  };
85
90
  }
86
91
 
92
+ function jsxAttributeBlockedResult(input, topLevelResult, merge, stagedFallback) {
93
+ const reasonCodes = uniqueStrings(merge.reasonCodes);
94
+ const gates = jsTsSafeMergeGateOrder.map((id, index) => ({
95
+ id,
96
+ status: index === 0 ? 'blocked' : 'skipped',
97
+ reasonCodes: index === 0 ? reasonCodes : []
98
+ }));
99
+ return {
100
+ ...topLevelResult,
101
+ id: String(input.id ?? topLevelResult.id),
102
+ status: JsTsSafeMergeStatuses.blocked,
103
+ mergedSourceText: undefined,
104
+ outputSourceText: undefined,
105
+ conflicts: [{
106
+ code: 'jsx-attribute-policy-blocked',
107
+ gateId: 'parse-ledger',
108
+ message: 'JSX attribute merge policy could not prove stable prop identity and render ordering.',
109
+ side: 'worker',
110
+ sourcePath: input.sourcePath ?? topLevelResult.sourcePath,
111
+ details: { reasonCodes }
112
+ }],
113
+ gates,
114
+ admission: {
115
+ status: 'blocked',
116
+ action: 'human-review',
117
+ reviewRequired: true,
118
+ autoApplyCandidate: false,
119
+ autoMergeClaim: false,
120
+ semanticEquivalenceClaim: false,
121
+ reasonCodes
122
+ },
123
+ summary: {
124
+ ...topLevelResult.summary,
125
+ changedExistingDeclarations: semanticFallbackChangedExistingDeclarations(topLevelResult, topLevelResult, stagedFallback),
126
+ conflicts: 1,
127
+ gatesPassed: 0,
128
+ jsxAttributePolicyBlocked: true,
129
+ composedPhases: 2
130
+ },
131
+ metadata: {
132
+ ...topLevelResult.metadata,
133
+ composed: {
134
+ phase: stagedFallback ? 'staged-top-level-jsx-attribute-policy-blocked' : 'jsx-attribute-policy-blocked',
135
+ phases: stagedFallback
136
+ ? ['top-level-neutralization', 'top-level-ledger', 'jsx-attribute-policy']
137
+ : ['top-level-ledger', 'jsx-attribute-policy'],
138
+ originalReasonCodes: topLevelResult.admission?.reasonCodes ?? [],
139
+ stagedTopLevelSummary: stagedFallback?.stagedTopLevelResult?.summary,
140
+ neutralization: stagedFallback?.neutralization?.summary,
141
+ jsxAttributePolicy: { reasonCodes }
142
+ }
143
+ },
144
+ semanticArtifacts: topLevelResult.semanticArtifacts
145
+ };
146
+ }
147
+
87
148
  function mergeJsxAttributeSources(input) {
88
149
  if (![input.baseSourceText, input.workerSourceText, input.headSourceText, input.currentSourceText].every(isString)) {
89
150
  return blocked('missing-source-text');
@@ -91,7 +152,15 @@ function mergeJsxAttributeSources(input) {
91
152
  const parsed = ['base', 'worker', 'head', 'current'].map((side) => parseJsxTags(input[`${side}SourceText`]));
92
153
  if (parsed.some((source) => source.reasonCodes.length)) return blocked('jsx-attribute-parse-blocked');
93
154
  const [base, worker, head, current] = parsed;
155
+ if (![worker, head, current].every((source) => sameJsxTagIdentitySequence(base.tags, source.tags))) {
156
+ return blocked('jsx-attribute-element-identity-changed');
157
+ }
158
+ const conditionalChildExpressionRanges = Object.fromEntries(['base', 'worker', 'head', 'current'].map((side) => [
159
+ side,
160
+ jsxConditionalChildExpressionRanges(input[`${side}SourceText`])
161
+ ]));
94
162
  const edits = [];
163
+ const componentPropContracts = [];
95
164
  let changedTags = 0;
96
165
  for (const baseTag of base.tags) {
97
166
  const workerTag = worker.byKey.get(baseTag.key);
@@ -99,15 +168,28 @@ function mergeJsxAttributeSources(input) {
99
168
  const currentTag = current.byKey.get(baseTag.key);
100
169
  if (!workerTag || !headTag || !currentTag) continue;
101
170
  if (sameTagText(baseTag, workerTag)) continue;
171
+ if (tagInConditionalChildExpression({ base: baseTag, worker: workerTag, head: headTag, current: currentTag }, conditionalChildExpressionRanges)) {
172
+ return blocked('jsx-child-conditional-expression-unsupported');
173
+ }
102
174
  const merged = mergeTagAttributes(baseTag, workerTag, headTag, currentTag);
103
175
  if (merged.status === 'blocked') return blocked(...merged.reasonCodes);
104
176
  for (const edit of merged.edits) edits.push(edit);
177
+ for (const contract of merged.componentPropContracts ?? []) componentPropContracts.push(contract);
105
178
  if (merged.edits.length) changedTags += 1;
106
179
  }
107
180
  if (!edits.length) return blocked('no-jsx-attribute-merge-candidate');
108
181
  const sourceText = edits.sort((left, right) => right.start - left.start)
109
182
  .reduce((text, edit) => text.slice(0, edit.start) + edit.replacement + text.slice(edit.end), input.currentSourceText);
110
- return { ok: true, sourceText, summary: { tags: changedTags, edits: edits.length } };
183
+ return {
184
+ ok: true,
185
+ sourceText,
186
+ summary: {
187
+ tags: changedTags,
188
+ edits: edits.length,
189
+ componentPropContracts,
190
+ componentPropContractAttributes: componentPropContracts.reduce((total, contract) => total + contract.attributeCount, 0)
191
+ }
192
+ };
111
193
  }
112
194
 
113
195
  function mergeTagAttributes(base, worker, head, current) {
@@ -119,12 +201,23 @@ function mergeTagAttributes(base, worker, head, current) {
119
201
  }
120
202
  const [, workerAttrs, headAttrs, currentAttrs] = maps.map((map) => map.byName);
121
203
  const edits = [];
204
+ const changedAttributes = [];
205
+ let workerSpread = false, headSpread = false, workerNamed = false, headNamed = false;
122
206
  for (const baseAttr of base.attributes) {
123
207
  const workerAttr = workerAttrs.get(baseAttr.name);
124
208
  const headAttr = headAttrs.get(baseAttr.name);
125
209
  const currentAttr = currentAttrs.get(baseAttr.name);
126
210
  const workerChanged = !sameAttrText(baseAttr, workerAttr);
127
211
  const headChanged = !sameAttrText(baseAttr, headAttr);
212
+ if (baseAttr.name === 'key' && (workerChanged || headChanged)) {
213
+ return blockedTag('jsx-attribute-key-identity-changed');
214
+ }
215
+ if (workerChanged || headChanged) {
216
+ changedAttributes.push(baseAttr.name);
217
+ const spread = isJsxSpreadAttribute(baseAttr);
218
+ workerSpread ||= spread && workerChanged; headSpread ||= spread && headChanged;
219
+ workerNamed ||= !spread && workerChanged; headNamed ||= !spread && headChanged;
220
+ }
128
221
  if (workerChanged && headChanged && !sameAttrText(workerAttr, headAttr)) {
129
222
  return blockedTag('jsx-attribute-conflict');
130
223
  }
@@ -135,163 +228,34 @@ function mergeTagAttributes(base, worker, head, current) {
135
228
  edits.push({ start: currentAttr.start, end: currentAttr.end, replacement: workerAttr.text });
136
229
  }
137
230
  }
138
- return { status: 'merged', edits };
139
- }
140
-
141
- function parseJsxTags(sourceText) {
142
- const tags = [];
143
- const reasonCodes = [];
144
- const ordinals = new Map();
145
- let index = 0;
146
- while (index < sourceText.length) {
147
- const start = sourceText.indexOf('<', index);
148
- if (start === -1) break;
149
- const parsed = parseOpeningTag(sourceText, start);
150
- if (!parsed) {
151
- index = start + 1;
152
- continue;
153
- }
154
- if (parsed.reasonCodes.length) reasonCodes.push(...parsed.reasonCodes);
155
- const ordinal = (ordinals.get(parsed.tagName) ?? 0) + 1;
156
- ordinals.set(parsed.tagName, ordinal);
157
- tags.push({ ...parsed, key: `${parsed.tagName}#${ordinal}` });
158
- index = parsed.end;
159
- }
160
- return { tags, byKey: new Map(tags.map((tag) => [tag.key, tag])), reasonCodes: uniqueStrings(reasonCodes) };
161
- }
162
-
163
- function parseOpeningTag(sourceText, start) {
164
- const afterOpen = start + 1;
165
- if (/[/!?>]/.test(sourceText[afterOpen] ?? '')) return undefined;
166
- const nameMatch = /^[A-Za-z_$][\w$]*(?:[.:][A-Za-z_$][\w$]*|-[\w$]+)*/.exec(sourceText.slice(afterOpen));
167
- if (!nameMatch) return undefined;
168
- const tagName = nameMatch[0];
169
- const nameEnd = afterOpen + tagName.length;
170
- const end = openingTagEnd(sourceText, nameEnd);
171
- if (end === undefined) return undefined;
172
- const attributes = parseAttributes(sourceText, nameEnd, end - 1);
173
- return {
174
- tagName,
175
- start,
176
- end,
177
- text: sourceText.slice(start, end),
178
- attributes: attributes.values,
179
- reasonCodes: attributes.reasonCodes
180
- };
181
- }
182
-
183
- function parseAttributes(sourceText, start, end) {
184
- const values = [];
185
- const reasonCodes = [];
186
- let cursor = start;
187
- while (cursor < end) {
188
- while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
189
- if (sourceText[cursor] === '/') {
190
- cursor += 1;
191
- continue;
192
- }
193
- const attrStart = cursor;
194
- const nameMatch = /^[A-Za-z_$][\w$:-]*/.exec(sourceText.slice(cursor, end));
195
- if (!nameMatch) {
196
- reasonCodes.push('jsx-attribute-token-unsupported');
197
- break;
198
- }
199
- const name = nameMatch[0];
200
- cursor += name.length;
201
- while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
202
- if (sourceText[cursor] === '=') {
203
- cursor += 1;
204
- while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
205
- cursor = attributeValueEnd(sourceText, cursor, end);
206
- if (cursor === undefined) return { values, reasonCodes: ['jsx-attribute-value-unterminated'] };
207
- }
208
- values.push({ name, start: attrStart, end: cursor, text: sourceText.slice(attrStart, cursor) });
209
- }
210
- return { values, reasonCodes: uniqueStrings(reasonCodes) };
211
- }
212
-
213
- function openingTagEnd(sourceText, start) {
214
- let quote;
215
- let escaped = false;
216
- let braceDepth = 0;
217
- for (let index = start; index < sourceText.length; index += 1) {
218
- const char = sourceText[index];
219
- if (quote) {
220
- if (escaped) escaped = false;
221
- else if (char === '\\') escaped = true;
222
- else if (char === quote) quote = undefined;
223
- continue;
224
- }
225
- if (char === '"' || char === '\'' || char === '`') quote = char;
226
- else if (char === '{') braceDepth += 1;
227
- else if (char === '}') braceDepth = Math.max(0, braceDepth - 1);
228
- else if (char === '>' && braceDepth === 0) return index + 1;
229
- }
230
- return undefined;
231
- }
232
-
233
- function attributeValueEnd(sourceText, start, end) {
234
- const first = sourceText[start];
235
- if (first === '"' || first === '\'') return quotedValueEnd(sourceText, start, end, first);
236
- if (first === '{') return bracedValueEnd(sourceText, start, end);
237
- let cursor = start;
238
- while (cursor < end && !/[\s/]/.test(sourceText[cursor])) cursor += 1;
239
- return cursor;
240
- }
241
-
242
- function quotedValueEnd(sourceText, start, end, quote) {
243
- let escaped = false;
244
- for (let cursor = start + 1; cursor < end; cursor += 1) {
245
- const char = sourceText[cursor];
246
- if (escaped) escaped = false;
247
- else if (char === '\\') escaped = true;
248
- else if (char === quote) return cursor + 1;
249
- }
250
- return undefined;
251
- }
252
-
253
- function bracedValueEnd(sourceText, start, end) {
254
- let depth = 0;
255
- let quote;
256
- let escaped = false;
257
- for (let cursor = start; cursor < end; cursor += 1) {
258
- const char = sourceText[cursor];
259
- if (quote) {
260
- if (escaped) escaped = false;
261
- else if (char === '\\') escaped = true;
262
- else if (char === quote) quote = undefined;
263
- continue;
264
- }
265
- if (char === '"' || char === '\'' || char === '`') quote = char;
266
- else if (char === '{') depth += 1;
267
- else if (char === '}') {
268
- depth -= 1;
269
- if (depth === 0) return cursor + 1;
270
- }
271
- }
272
- return undefined;
231
+ if ((workerSpread && headNamed) || (headSpread && workerNamed)) return blockedTag('jsx-attribute-spread-explicit-precedence-unsupported');
232
+ const contractAttributes = uniqueStrings(changedAttributes);
233
+ const componentPropContracts = isJsxComponentTag(base.tagName) && contractAttributes.length
234
+ ? [{
235
+ tagName: base.tagName,
236
+ tagKey: base.key,
237
+ attributes: contractAttributes,
238
+ attributeCount: contractAttributes.length
239
+ }]
240
+ : [];
241
+ return { status: 'merged', edits, componentPropContracts };
273
242
  }
274
243
 
275
- function attributeMap(tag) {
276
- const byName = new Map();
277
- const duplicateNames = [];
278
- for (const attribute of tag.attributes) {
279
- if (byName.has(attribute.name)) duplicateNames.push(attribute.name);
280
- byName.set(attribute.name, attribute);
281
- }
282
- return { byName, reasonCodes: duplicateNames.length ? ['jsx-attribute-duplicate-name'] : [] };
283
- }
284
-
285
- function sameAttributeNames(left, right) {
286
- return left.attributes.map((attr) => attr.name).join('\0') === right.attributes.map((attr) => attr.name).join('\0');
287
- }
288
-
289
- function sameTagText(left, right) {
290
- return String(left?.text ?? '').trim() === String(right?.text ?? '').trim();
244
+ function jsxConditionalChildExpressionRanges(sourceText) {
245
+ const parsed = parseJsxSource(sourceText);
246
+ if (parsed.reasonCodes.length) return [];
247
+ return parsed.elements.flatMap((element) => {
248
+ if (element.selfClosing) return [];
249
+ const children = parseDirectChildren(sourceText, parsed, element);
250
+ if (children.reasonCodes.length) return [];
251
+ return children.tokens
252
+ .filter((token) => token.kind === 'expression' && hasConditionalChildExpressionOperator(token.text))
253
+ .map((token) => ({ start: token.start, end: token.end }));
254
+ });
291
255
  }
292
256
 
293
- function sameAttrText(left, right) {
294
- return String(left?.text ?? '').trim() === String(right?.text ?? '').trim();
257
+ function tagInConditionalChildExpression(tagsBySide, rangesBySide) {
258
+ return Object.entries(tagsBySide).some(([side, tag]) => (rangesBySide[side] ?? []).some((range) => range.start < tag.start && tag.end < range.end));
295
259
  }
296
260
 
297
261
  function semanticArtifactGates(artifacts) {
@@ -308,7 +272,12 @@ function gate(id, passed, reasonCodes = []) {
308
272
  }
309
273
 
310
274
  function blocked(...reasonCodes) {
311
- return { ok: false, reasonCodes: uniqueStrings(reasonCodes) };
275
+ const normalized = uniqueStrings(reasonCodes);
276
+ return {
277
+ ok: false,
278
+ reasonCodes: normalized,
279
+ policyBlocker: normalized.some((reason) => jsxAttributePolicyBlockers.has(reason))
280
+ };
312
281
  }
313
282
 
314
283
  function blockedTag(...reasonCodes) {
@@ -316,5 +285,30 @@ function blockedTag(...reasonCodes) {
316
285
  }
317
286
 
318
287
  function isString(value) { return typeof value === 'string'; }
288
+ function sameJsxTagIdentitySequence(leftTags, rightTags) {
289
+ return jsxTagIdentitySequence(leftTags) === jsxTagIdentitySequence(rightTags);
290
+ }
291
+ function jsxTagIdentitySequence(tags = []) {
292
+ return tags.map((tag, index) => {
293
+ const keyAttr = tag.attributes.find((attribute) => attribute.name === 'key');
294
+ return [tag.tagName, stableJsxKeyAttrText(keyAttr) ?? `ordinal:${index + 1}`].join('#');
295
+ }).join('\0');
296
+ }
297
+ function stableJsxKeyAttrText(attribute) {
298
+ if (!attribute) return undefined;
299
+ const match = /^key\s*=\s*(?:"([^"]*)"|'([^']*)')\s*$/.exec(String(attribute.text ?? '').trim());
300
+ if (!match) return undefined;
301
+ return `key:${match[1] ?? match[2] ?? ''}`;
302
+ }
303
+
304
+ const jsxAttributePolicyBlockers = new Set([
305
+ 'jsx-attribute-conflict',
306
+ 'jsx-attribute-current-diverged',
307
+ 'jsx-attribute-duplicate-name',
308
+ 'jsx-attribute-key-identity-changed',
309
+ 'jsx-attribute-shape-changed',
310
+ 'jsx-attribute-spread-explicit-precedence-unsupported',
311
+ 'jsx-child-conditional-expression-unsupported'
312
+ ]);
319
313
 
320
314
  export { createJsxAttributeSemanticFallbackResult };
@@ -0,0 +1,277 @@
1
+ import { uniqueStrings } from './js-ts-safe-merge-context.js';
2
+
3
+ export function parseJsxTags(sourceText) {
4
+ const tags = [];
5
+ const reasonCodes = [];
6
+ const ordinals = new Map();
7
+ let index = 0;
8
+ while (index < sourceText.length) {
9
+ const start = sourceText.indexOf('<', index);
10
+ if (start === -1) break;
11
+ const parsed = parseOpeningTag(sourceText, start);
12
+ if (!parsed) {
13
+ index = start + 1;
14
+ continue;
15
+ }
16
+ if (parsed.reasonCodes.length) reasonCodes.push(...parsed.reasonCodes);
17
+ const ordinal = (ordinals.get(parsed.tagName) ?? 0) + 1;
18
+ ordinals.set(parsed.tagName, ordinal);
19
+ tags.push({ ...parsed, key: `${parsed.tagName}#${ordinal}` });
20
+ index = parsed.end;
21
+ }
22
+ return { tags, byKey: new Map(tags.map((tag) => [tag.key, tag])), reasonCodes: uniqueStrings(reasonCodes) };
23
+ }
24
+
25
+ export function attributeMap(tag) {
26
+ const byName = new Map();
27
+ const duplicateNames = [];
28
+ for (const attribute of tag.attributes) {
29
+ if (byName.has(attribute.name)) duplicateNames.push(attribute.name);
30
+ byName.set(attribute.name, attribute);
31
+ }
32
+ return { byName, reasonCodes: duplicateNames.length ? ['jsx-attribute-duplicate-name'] : [] };
33
+ }
34
+
35
+ export function sameAttributeNames(left, right) {
36
+ return left.attributes.map((attr) => attr.name).join('\0') === right.attributes.map((attr) => attr.name).join('\0');
37
+ }
38
+
39
+ export function sameTagText(left, right) {
40
+ return String(left?.text ?? '').trim() === String(right?.text ?? '').trim();
41
+ }
42
+
43
+ export function sameAttrText(left, right) {
44
+ return String(left?.text ?? '').trim() === String(right?.text ?? '').trim();
45
+ }
46
+
47
+ export function isJsxSpreadAttribute(attribute) {
48
+ return attribute?.kind === 'spread' || attribute?.spread === true;
49
+ }
50
+
51
+ export function isJsxComponentTag(tagName) {
52
+ const firstSegment = String(tagName ?? '').split(/[.:]/)[0] ?? '';
53
+ return /^[A-Z]/.test(firstSegment);
54
+ }
55
+
56
+ export function jsxContextProviderBoundary(tagName) {
57
+ const segments = String(tagName ?? '').split(/[.:]/).filter(Boolean);
58
+ if (segments.length < 2 || segments[segments.length - 1] !== 'Provider') return undefined;
59
+ return { kind: 'context-provider', contextName: segments.slice(0, -1).join('.') };
60
+ }
61
+
62
+ export function jsxContextProviderAncestorMap(tags, sourceText) {
63
+ const tagsByStart = new Map(tags.map((tag) => [tag.start, tag]));
64
+ const ancestorsByStart = new Map();
65
+ const providerStack = [];
66
+ for (const token of jsxTagTokens(sourceText)) {
67
+ if (token.kind === 'closing') {
68
+ closeContextProviderStack(providerStack, token.tagName);
69
+ continue;
70
+ }
71
+ const tag = tagsByStart.get(token.start);
72
+ if (tag) ancestorsByStart.set(tag.start, providerStack.map((provider) => ({ ...provider })));
73
+ const boundary = jsxContextProviderBoundary(token.tagName);
74
+ if (boundary && !token.selfClosing) {
75
+ providerStack.push({
76
+ tagName: token.tagName,
77
+ contextName: boundary.contextName,
78
+ contextBoundaryKind: boundary.kind,
79
+ start: token.start,
80
+ end: token.end
81
+ });
82
+ }
83
+ }
84
+ return ancestorsByStart;
85
+ }
86
+
87
+ function closeContextProviderStack(providerStack, tagName) {
88
+ for (let index = providerStack.length - 1; index >= 0; index -= 1) {
89
+ if (providerStack[index].tagName !== tagName) continue;
90
+ providerStack.splice(index);
91
+ return;
92
+ }
93
+ }
94
+
95
+ export function jsxTagTokens(sourceText) {
96
+ const tokens = [];
97
+ let index = 0;
98
+ while (index < sourceText.length) {
99
+ const start = sourceText.indexOf('<', index);
100
+ if (start === -1) break;
101
+ if (sourceText[start + 1] === '/') {
102
+ const token = jsxClosingTagToken(sourceText, start);
103
+ if (token) tokens.push(token);
104
+ index = token?.end ?? start + 1;
105
+ continue;
106
+ }
107
+ const token = jsxOpeningTagToken(sourceText, start);
108
+ if (token) tokens.push(token);
109
+ index = token?.end ?? start + 1;
110
+ }
111
+ return tokens;
112
+ }
113
+
114
+ function jsxOpeningTagToken(sourceText, start) {
115
+ const parsed = parseOpeningTag(sourceText, start);
116
+ if (!parsed) return undefined;
117
+ return { kind: 'opening', tagName: parsed.tagName, start: parsed.start, end: parsed.end, selfClosing: jsxOpeningTagSelfClosing(sourceText, parsed.end) };
118
+ }
119
+
120
+ function jsxClosingTagToken(sourceText, start) {
121
+ const afterOpen = start + 2;
122
+ const nameMatch = /^[A-Za-z_$][\w$]*(?:[.:][A-Za-z_$][\w$]*|-[\w$]+)*/.exec(sourceText.slice(afterOpen));
123
+ if (!nameMatch) return undefined;
124
+ const end = sourceText.indexOf('>', afterOpen + nameMatch[0].length);
125
+ if (end === -1) return undefined;
126
+ return { kind: 'closing', tagName: nameMatch[0], start, end: end + 1 };
127
+ }
128
+
129
+ function jsxOpeningTagSelfClosing(sourceText, end) {
130
+ let cursor = end - 2;
131
+ while (cursor >= 0 && /\s/.test(sourceText[cursor])) cursor -= 1;
132
+ return sourceText[cursor] === '/';
133
+ }
134
+
135
+ function parseOpeningTag(sourceText, start) {
136
+ const afterOpen = start + 1;
137
+ if (/[/!?>]/.test(sourceText[afterOpen] ?? '')) return undefined;
138
+ const nameMatch = /^[A-Za-z_$][\w$]*(?:[.:][A-Za-z_$][\w$]*|-[\w$]+)*/.exec(sourceText.slice(afterOpen));
139
+ if (!nameMatch) return undefined;
140
+ const tagName = nameMatch[0];
141
+ const nameEnd = afterOpen + tagName.length;
142
+ const end = openingTagEnd(sourceText, nameEnd);
143
+ if (end === undefined) return undefined;
144
+ const attributes = parseAttributes(sourceText, nameEnd, end - 1);
145
+ return {
146
+ tagName,
147
+ start,
148
+ end,
149
+ text: sourceText.slice(start, end),
150
+ attributes: attributes.values,
151
+ reasonCodes: attributes.reasonCodes
152
+ };
153
+ }
154
+
155
+ function parseAttributes(sourceText, start, end) {
156
+ const values = [];
157
+ const reasonCodes = [];
158
+ let cursor = start;
159
+ let spreadOrdinal = 0;
160
+ while (cursor < end) {
161
+ while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
162
+ if (sourceText[cursor] === '/') {
163
+ cursor += 1;
164
+ continue;
165
+ }
166
+ const attrStart = cursor;
167
+ const spreadEnd = spreadAttributeEnd(sourceText, cursor, end);
168
+ if (spreadEnd !== undefined) {
169
+ spreadOrdinal += 1;
170
+ values.push({
171
+ kind: 'spread',
172
+ spread: true,
173
+ spreadOrdinal,
174
+ name: `...spread#${spreadOrdinal}`,
175
+ start: attrStart,
176
+ end: spreadEnd,
177
+ text: sourceText.slice(attrStart, spreadEnd),
178
+ expressionText: spreadExpressionText(sourceText, attrStart, spreadEnd)
179
+ });
180
+ cursor = spreadEnd;
181
+ continue;
182
+ }
183
+ const nameMatch = /^[A-Za-z_$][\w$:-]*/.exec(sourceText.slice(cursor, end));
184
+ if (!nameMatch) {
185
+ reasonCodes.push('jsx-attribute-token-unsupported');
186
+ break;
187
+ }
188
+ const name = nameMatch[0];
189
+ cursor += name.length;
190
+ while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
191
+ if (sourceText[cursor] === '=') {
192
+ cursor += 1;
193
+ while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
194
+ cursor = attributeValueEnd(sourceText, cursor, end);
195
+ if (cursor === undefined) return { values, reasonCodes: ['jsx-attribute-value-unterminated'] };
196
+ }
197
+ values.push({ name, start: attrStart, end: cursor, text: sourceText.slice(attrStart, cursor) });
198
+ }
199
+ return { values, reasonCodes: uniqueStrings(reasonCodes) };
200
+ }
201
+
202
+ function spreadAttributeEnd(sourceText, start, end) {
203
+ if (sourceText[start] !== '{') return undefined;
204
+ let cursor = start + 1;
205
+ while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
206
+ if (sourceText.slice(cursor, cursor + 3) !== '...') return undefined;
207
+ return bracedValueEnd(sourceText, start, end);
208
+ }
209
+
210
+ function spreadExpressionText(sourceText, start, end) {
211
+ let cursor = start + 1;
212
+ while (cursor < end && /\s/.test(sourceText[cursor])) cursor += 1;
213
+ cursor += 3;
214
+ return sourceText.slice(cursor, Math.max(cursor, end - 1)).trim();
215
+ }
216
+
217
+ function openingTagEnd(sourceText, start) {
218
+ let quote;
219
+ let escaped = false;
220
+ let braceDepth = 0;
221
+ for (let index = start; index < sourceText.length; index += 1) {
222
+ const char = sourceText[index];
223
+ if (quote) {
224
+ if (escaped) escaped = false;
225
+ else if (char === '\\') escaped = true;
226
+ else if (char === quote) quote = undefined;
227
+ continue;
228
+ }
229
+ if (char === '"' || char === '\'' || char === '`') quote = char;
230
+ else if (char === '{') braceDepth += 1;
231
+ else if (char === '}') braceDepth = Math.max(0, braceDepth - 1);
232
+ else if (char === '>' && braceDepth === 0) return index + 1;
233
+ }
234
+ return undefined;
235
+ }
236
+
237
+ function attributeValueEnd(sourceText, start, end) {
238
+ const first = sourceText[start];
239
+ if (first === '"' || first === '\'') return quotedValueEnd(sourceText, start, end, first);
240
+ if (first === '{') return bracedValueEnd(sourceText, start, end);
241
+ let cursor = start;
242
+ while (cursor < end && !/[\s/]/.test(sourceText[cursor])) cursor += 1;
243
+ return cursor;
244
+ }
245
+
246
+ function quotedValueEnd(sourceText, start, end, quote) {
247
+ let escaped = false;
248
+ for (let cursor = start + 1; cursor < end; cursor += 1) {
249
+ const char = sourceText[cursor];
250
+ if (escaped) escaped = false;
251
+ else if (char === '\\') escaped = true;
252
+ else if (char === quote) return cursor + 1;
253
+ }
254
+ return undefined;
255
+ }
256
+
257
+ function bracedValueEnd(sourceText, start, end) {
258
+ let depth = 0;
259
+ let quote;
260
+ let escaped = false;
261
+ for (let cursor = start; cursor < end; cursor += 1) {
262
+ const char = sourceText[cursor];
263
+ if (quote) {
264
+ if (escaped) escaped = false;
265
+ else if (char === '\\') escaped = true;
266
+ else if (char === quote) quote = undefined;
267
+ continue;
268
+ }
269
+ if (char === '"' || char === '\'' || char === '`') quote = char;
270
+ else if (char === '{') depth += 1;
271
+ else if (char === '}') {
272
+ depth -= 1;
273
+ if (depth === 0) return cursor + 1;
274
+ }
275
+ }
276
+ return undefined;
277
+ }