@shapeshift-labs/frontier-lang-compiler 0.2.161 → 0.2.162

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.
@@ -14,11 +14,14 @@ function compilerAdvancedTypeMetadata(value) {
14
14
  intersectionTypeCount: numberValue(value.intersectionTypeCount) ?? countKind(advancedTypeShapes, 'intersection-type'),
15
15
  tupleTypeCount: numberValue(value.tupleTypeCount) ?? countKind(advancedTypeShapes, 'tuple-type')
16
16
  };
17
+ const proofRequirement = advancedTypeProofRequirement(advancedTypeShapes, counts);
17
18
  return {
18
19
  counts,
19
20
  record: compactRecord({
20
21
  advancedTypeShapeCount: counts.advancedTypeShapeCount || undefined,
21
22
  advancedTypeShapeKinds: value.advancedTypeShapeKinds ?? nonEmptyArray(uniqueStrings(advancedTypeShapes.map((shape) => shape.kind))),
23
+ advancedTypeProofRequirement: proofRequirement.requirement,
24
+ advancedTypeMissingProof: proofRequirement.missingProof,
22
25
  typeReferenceTargetCount: counts.typeReferenceTargetCount || undefined,
23
26
  conditionalTypeCount: counts.conditionalTypeCount || undefined,
24
27
  mappedTypeCount: counts.mappedTypeCount || undefined,
@@ -35,6 +38,145 @@ function compilerAdvancedTypeMetadata(value) {
35
38
  };
36
39
  }
37
40
 
41
+ const AdvancedTypeProofRequirementKind = 'typescript-checker-public-api-advanced-type-shape-equivalence';
42
+ const AdvancedTypeProofRequiredEvidence = 'typescript-checker-public-api-type-equivalence';
43
+ const AdvancedTypeProofShapeSpecs = [
44
+ proofShapeSpec('conditional-type', 'conditionalTypeCount', [
45
+ proofField('nodeText', 'compiler-conditional-type-node-texts'),
46
+ proofField('typeText', 'compiler-conditional-type-type-texts'),
47
+ proofField('checkTypeText', 'compiler-conditional-type-check-type-texts'),
48
+ proofField('extendsTypeText', 'compiler-conditional-type-extends-type-texts'),
49
+ proofField('trueTypeText', 'compiler-conditional-type-true-type-texts'),
50
+ proofField('falseTypeText', 'compiler-conditional-type-false-type-texts')
51
+ ]),
52
+ proofShapeSpec('mapped-type', 'mappedTypeCount', [
53
+ proofField('nodeText', 'compiler-mapped-type-node-texts'),
54
+ proofField('typeText', 'compiler-mapped-type-type-texts'),
55
+ proofField('mappedConstraintTypeText', 'compiler-mapped-type-constraint-type-texts'),
56
+ proofField('mappedValueTypeText', 'compiler-mapped-type-value-type-texts')
57
+ ]),
58
+ proofShapeSpec('indexed-access-type', 'indexedAccessTypeCount', [
59
+ proofField('nodeText', 'compiler-indexed-access-type-node-texts'),
60
+ proofField('typeText', 'compiler-indexed-access-type-type-texts'),
61
+ proofField('objectTypeText', 'compiler-indexed-access-type-object-type-texts'),
62
+ proofField('indexTypeText', 'compiler-indexed-access-type-index-type-texts')
63
+ ]),
64
+ proofShapeSpec('keyof-type-operator', 'keyofTypeOperatorCount', [
65
+ proofField('nodeText', 'compiler-keyof-type-operator-node-texts'),
66
+ proofField('typeText', 'compiler-keyof-type-operator-type-texts'),
67
+ proofField('keyofTargetTypeText', 'compiler-keyof-type-operator-target-type-texts')
68
+ ]),
69
+ proofShapeSpec('template-literal-type', 'templateLiteralTypeCount', [
70
+ proofField('nodeText', 'compiler-template-literal-type-node-texts'),
71
+ proofField('typeText', 'compiler-template-literal-type-type-texts'),
72
+ proofField('templateHeadText', 'compiler-template-literal-type-head-texts'),
73
+ proofField('templateSpanTexts', 'compiler-template-literal-type-span-texts'),
74
+ proofField('templateSpanTypeTexts', 'compiler-template-literal-type-span-type-texts'),
75
+ proofField('templateLiteralTexts', 'compiler-template-literal-type-literal-texts')
76
+ ]),
77
+ proofShapeSpec('infer-type', 'inferTypeCount', [
78
+ proofField('nodeText', 'compiler-infer-type-node-texts'),
79
+ proofField('typeText', 'compiler-infer-type-type-texts'),
80
+ proofField('typeParameterText', 'compiler-infer-type-type-parameter-texts'),
81
+ proofField('typeParameterName', 'compiler-infer-type-type-parameter-names')
82
+ ]),
83
+ proofShapeSpec('union-type', 'unionTypeCount', [
84
+ proofField('nodeText', 'compiler-union-type-node-texts'),
85
+ proofField('typeText', 'compiler-union-type-type-texts'),
86
+ proofField('memberTypeTexts', 'compiler-union-type-member-type-texts')
87
+ ]),
88
+ proofShapeSpec('intersection-type', 'intersectionTypeCount', [
89
+ proofField('nodeText', 'compiler-intersection-type-node-texts'),
90
+ proofField('typeText', 'compiler-intersection-type-type-texts'),
91
+ proofField('memberTypeTexts', 'compiler-intersection-type-member-type-texts')
92
+ ]),
93
+ proofShapeSpec('tuple-type', 'tupleTypeCount', [
94
+ proofField('nodeText', 'compiler-tuple-type-node-texts'),
95
+ proofField('typeText', 'compiler-tuple-type-type-texts'),
96
+ proofField('tupleElementTexts', 'compiler-tuple-type-element-texts'),
97
+ proofField('tupleElementTypeTexts', 'compiler-tuple-type-element-type-texts')
98
+ ])
99
+ ];
100
+
101
+ function advancedTypeProofRequirement(advancedTypeShapes, counts) {
102
+ if (!counts.advancedTypeShapeCount) return {};
103
+ const requiredSignals = advancedTypeRequiredProofSignals(counts);
104
+ const missingSignals = missingAdvancedTypeProofSignals(advancedTypeShapes, counts);
105
+ const unsupportedSignals = unsupportedAdvancedTypeProofSignals(counts);
106
+ const status = unsupportedSignals.length
107
+ ? 'requires-review'
108
+ : missingSignals.length ? 'missing-compiler-evidence' : 'requires-type-equivalence-proof';
109
+ const requirement = compactRecord({
110
+ kind: AdvancedTypeProofRequirementKind,
111
+ requiredEvidence: AdvancedTypeProofRequiredEvidence,
112
+ status,
113
+ requiredSignals,
114
+ missingSignals: nonEmptyArray(missingSignals),
115
+ unsupportedSignals: nonEmptyArray(unsupportedSignals),
116
+ advancedTypeShapeCount: counts.advancedTypeShapeCount,
117
+ advancedTypeShapeKinds: nonEmptyArray(uniqueStrings(advancedTypeShapes.map((shape) => shape.kind))),
118
+ conditionalTypeCount: counts.conditionalTypeCount || undefined,
119
+ mappedTypeCount: counts.mappedTypeCount || undefined,
120
+ indexedAccessTypeCount: counts.indexedAccessTypeCount || undefined,
121
+ keyofTypeOperatorCount: counts.keyofTypeOperatorCount || undefined,
122
+ templateLiteralTypeCount: counts.templateLiteralTypeCount || undefined,
123
+ inferTypeCount: counts.inferTypeCount || undefined,
124
+ unionTypeCount: counts.unionTypeCount || undefined,
125
+ intersectionTypeCount: counts.intersectionTypeCount || undefined,
126
+ tupleTypeCount: counts.tupleTypeCount || undefined,
127
+ autoMergeClaim: false,
128
+ semanticEquivalenceClaim: false
129
+ });
130
+ return {
131
+ requirement,
132
+ missingProof: status === 'requires-type-equivalence-proof' ? undefined : compactRecord({
133
+ kind: AdvancedTypeProofRequirementKind,
134
+ requiredEvidence: AdvancedTypeProofRequiredEvidence,
135
+ status,
136
+ reasonCode: status === 'missing-compiler-evidence'
137
+ ? 'typescript-public-api-advanced-type-shape-proof-missing'
138
+ : 'typescript-public-api-advanced-type-shape-proof-requires-review',
139
+ missingSignals: nonEmptyArray(missingSignals),
140
+ unsupportedSignals: nonEmptyArray(unsupportedSignals),
141
+ autoMergeClaim: false,
142
+ semanticEquivalenceClaim: false
143
+ })
144
+ };
145
+ }
146
+
147
+ function advancedTypeRequiredProofSignals(counts) {
148
+ return uniqueStrings(AdvancedTypeProofShapeSpecs.flatMap((spec) => (
149
+ counts[spec.countKey] > 0 ? [countSignal(spec.kind), ...spec.fields.map((field) => field.signal)] : []
150
+ )));
151
+ }
152
+
153
+ function missingAdvancedTypeProofSignals(advancedTypeShapes, counts) {
154
+ return uniqueStrings(AdvancedTypeProofShapeSpecs.flatMap((spec) => {
155
+ const count = counts[spec.countKey] || 0;
156
+ if (!count) return [];
157
+ const shapes = advancedTypeShapes.filter((shape) => shape?.kind === spec.kind);
158
+ const missing = [];
159
+ if (shapes.length !== count) missing.push(countSignal(spec.kind));
160
+ for (const field of spec.fields) {
161
+ if (shapes.some((shape) => fieldMissing(shape?.[field.key]))) missing.push(field.signal);
162
+ }
163
+ return missing;
164
+ }));
165
+ }
166
+
167
+ function unsupportedAdvancedTypeProofSignals(counts) {
168
+ const knownShapeCount = AdvancedTypeProofShapeSpecs.reduce((sum, spec) => sum + (counts[spec.countKey] || 0), 0);
169
+ return counts.advancedTypeShapeCount > knownShapeCount ? ['compiler-unknown-advanced-type-shape'] : [];
170
+ }
171
+
172
+ function fieldMissing(value) {
173
+ if (Array.isArray(value)) return !value.length || value.some((item) => item === undefined || item === null);
174
+ return value === undefined || value === null;
175
+ }
176
+
177
+ function proofShapeSpec(kind, countKey, fields) { return { kind, countKey, fields }; }
178
+ function proofField(key, signal) { return { key, signal }; }
179
+ function countSignal(kind) { return `compiler-${kind}-count`; }
38
180
  function countKind(records, kind) { return records.filter((record) => record.kind === kind).length; }
39
181
  function arrayValue(value) { return Array.isArray(value) ? value : []; }
40
182
  function compactRecord(record) { return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)); }
@@ -19,10 +19,11 @@ function cssModuleSourceRecord(imported) {
19
19
  );
20
20
  const sourceText = nativeImportSourceText(imported);
21
21
  const inferredEvidence = suppliedEvidence ? undefined : inferCssModuleEvidence(sourceText, sourcePath, metadata, nativeMetadata, astMetadata);
22
+ const cssModuleEvidence = normalizeCssModuleEvidence(suppliedEvidence ?? inferredEvidence);
22
23
  return compactRecord({
23
24
  sourcePath,
24
25
  sourceHash: imported?.nativeSource?.sourceHash ?? imported?.metadata?.sourceHash,
25
- cssModuleEvidence: suppliedEvidence ?? inferredEvidence,
26
+ cssModuleEvidence,
26
27
  cssModuleEvidenceSource: suppliedEvidence ? 'supplied' : inferredEvidence ? 'inferred-source' : undefined,
27
28
  bundlerTransformHash: firstString(metadata.bundlerTransformHash, nativeMetadata.bundlerTransformHash, astMetadata.bundlerTransformHash),
28
29
  sourceMapProofHash: firstString(metadata.sourceMapProofHash, nativeMetadata.sourceMapProofHash, astMetadata.sourceMapProofHash)
@@ -134,6 +135,48 @@ function semanticSpanForHash(span) {
134
135
  return span ? { path: span.path, start: span.start, end: span.end, startLine: span.startLine, startColumn: span.startColumn, endLine: span.endLine, endColumn: span.endColumn } : undefined;
135
136
  }
136
137
 
138
+ function normalizeCssModuleEvidence(evidence) {
139
+ if (!evidence || typeof evidence !== 'object' || Array.isArray(evidence)) return undefined;
140
+ const icssExportNames = cssModuleIcssExportNames(evidence);
141
+ const exportNames = uniqueSortedStrings([
142
+ ...cssModuleEvidenceExportNames(evidence),
143
+ ...(evidence.icssGraphHash ? icssExportNames : [])
144
+ ]);
145
+ return compactRecord({
146
+ ...evidence,
147
+ icssExportNames: icssExportNames.length ? icssExportNames : undefined,
148
+ exportNames: exportNames.length ? exportNames : evidence.exportNames
149
+ });
150
+ }
151
+
152
+ function cssModuleEvidenceExportNames(evidence) {
153
+ return uniqueSortedStrings([
154
+ ...arrayValue(evidence?.exportNames),
155
+ ...arrayValue(evidence?.localClassNames),
156
+ ...arrayValue(evidence?.classNames),
157
+ ...cssModuleExportRecordNames(evidence?.exports),
158
+ ...objectKeys(evidence?.exports),
159
+ ...objectKeys(evidence?.generatedClassNameMap),
160
+ ...objectKeys(evidence?.classMap)
161
+ ]);
162
+ }
163
+
164
+ function cssModuleIcssExportNames(evidence) {
165
+ return uniqueSortedStrings([
166
+ ...arrayValue(evidence?.icssExportNames),
167
+ ...cssModuleExportRecordNames(evidence?.icssExports),
168
+ ...objectKeys(evidence?.icssExports),
169
+ ...cssModuleExportRecordNames(evidence?.icss?.exports),
170
+ ...objectKeys(evidence?.icss?.exports)
171
+ ]);
172
+ }
173
+
174
+ function cssModuleExportRecordNames(value) {
175
+ return Array.isArray(value)
176
+ ? value.map((entry) => entry?.name ?? entry?.localName ?? entry?.exportedName).filter(Boolean)
177
+ : [];
178
+ }
179
+
137
180
  function compactRecord(record) {
138
181
  return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
139
182
  }
@@ -150,6 +193,18 @@ function objectValue(value) {
150
193
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
151
194
  }
152
195
 
196
+ function arrayValue(value) {
197
+ return Array.isArray(value) ? value : [];
198
+ }
199
+
200
+ function objectKeys(value) {
201
+ return Object.keys(objectValue(value));
202
+ }
203
+
204
+ function uniqueSortedStrings(values) {
205
+ return [...new Set(values.filter((value) => typeof value === 'string' && value.length > 0))].sort();
206
+ }
207
+
153
208
  function firstObject(...values) {
154
209
  return values.find((value) => value && typeof value === 'object' && !Array.isArray(value));
155
210
  }
@@ -119,9 +119,145 @@ function staticLiteralKind(text) {
119
119
  if (value === 'undefined') return 'undefined';
120
120
  if (/^[-]?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(value)) return 'number';
121
121
  if (quotedLiteralText(value)) return 'string';
122
+ return staticStructuredLiteralKind(value);
123
+ }
124
+
125
+ function staticStructuredLiteralKind(text) {
126
+ const parsed = parseStaticLiteralExpression(text);
127
+ return parsed && ['object-literal', 'array-literal', 'template-string'].includes(parsed.kind)
128
+ ? parsed.kind
129
+ : undefined;
130
+ }
131
+
132
+ function parseStaticLiteralExpression(text) {
133
+ const state = { text: String(text ?? ''), index: 0 };
134
+ const parsed = parseStaticLiteralValue(state);
135
+ skipWhitespace(state);
136
+ return parsed && state.index === state.text.length ? parsed : undefined;
137
+ }
138
+
139
+ function parseStaticLiteralValue(state) {
140
+ skipWhitespace(state);
141
+ const char = state.text[state.index];
142
+ if (char === '"' || char === "'") return parseQuotedStaticString(state) ? { kind: 'string' } : undefined;
143
+ if (char === '`') return parseStaticTemplateString(state) ? { kind: 'template-string' } : undefined;
144
+ if (char === '{') return parseStaticObjectLiteral(state) ? { kind: 'object-literal' } : undefined;
145
+ if (char === '[') return parseStaticArrayLiteral(state) ? { kind: 'array-literal' } : undefined;
146
+ const primitive = parseStaticPrimitiveToken(state);
147
+ return primitive ? { kind: primitive } : undefined;
148
+ }
149
+
150
+ function parseStaticObjectLiteral(state) {
151
+ state.index += 1;
152
+ skipWhitespace(state);
153
+ if (consumeChar(state, '}')) return true;
154
+ while (state.index < state.text.length) {
155
+ if (state.text.startsWith('...', state.index) || state.text[state.index] === '[') return false;
156
+ if (!parseStaticObjectKey(state)) return false;
157
+ skipWhitespace(state);
158
+ if (!consumeChar(state, ':')) return false;
159
+ if (!parseStaticLiteralValue(state)) return false;
160
+ skipWhitespace(state);
161
+ if (consumeChar(state, '}')) return true;
162
+ if (!consumeChar(state, ',')) return false;
163
+ skipWhitespace(state);
164
+ if (consumeChar(state, '}')) return true;
165
+ }
166
+ return false;
167
+ }
168
+
169
+ function parseStaticArrayLiteral(state) {
170
+ state.index += 1;
171
+ skipWhitespace(state);
172
+ if (consumeChar(state, ']')) return true;
173
+ while (state.index < state.text.length) {
174
+ if (state.text.startsWith('...', state.index) || state.text[state.index] === ',') return false;
175
+ if (!parseStaticLiteralValue(state)) return false;
176
+ skipWhitespace(state);
177
+ if (consumeChar(state, ']')) return true;
178
+ if (!consumeChar(state, ',')) return false;
179
+ skipWhitespace(state);
180
+ if (consumeChar(state, ']')) return true;
181
+ }
182
+ return false;
183
+ }
184
+
185
+ function parseStaticObjectKey(state) {
186
+ skipWhitespace(state);
187
+ const char = state.text[state.index];
188
+ if (char === '"' || char === "'") return parseQuotedStaticString(state);
189
+ const numberStart = state.index;
190
+ if (parseStaticNumberToken(state)) return true;
191
+ state.index = numberStart;
192
+ return Boolean(parseIdentifierToken(state));
193
+ }
194
+
195
+ function parseQuotedStaticString(state) {
196
+ const quote = state.text[state.index];
197
+ if (quote !== '"' && quote !== "'") return false;
198
+ state.index += 1;
199
+ while (state.index < state.text.length) {
200
+ const char = state.text[state.index];
201
+ if (char === '\\') {
202
+ state.index += 2;
203
+ continue;
204
+ }
205
+ state.index += 1;
206
+ if (char === quote) return true;
207
+ }
208
+ return false;
209
+ }
210
+
211
+ function parseStaticTemplateString(state) {
212
+ if (state.text[state.index] !== '`') return false;
213
+ state.index += 1;
214
+ while (state.index < state.text.length) {
215
+ const char = state.text[state.index];
216
+ if (char === '\\') {
217
+ state.index += 2;
218
+ continue;
219
+ }
220
+ if (char === '$' && state.text[state.index + 1] === '{') return false;
221
+ state.index += 1;
222
+ if (char === '`') return true;
223
+ }
224
+ return false;
225
+ }
226
+
227
+ function parseStaticPrimitiveToken(state) {
228
+ const number = parseStaticNumberToken(state);
229
+ if (number) return 'number';
230
+ const identifier = parseIdentifierToken(state);
231
+ if (['true', 'false'].includes(identifier)) return 'boolean';
232
+ if (identifier === 'null') return 'null';
233
+ if (identifier === 'undefined') return 'undefined';
122
234
  return undefined;
123
235
  }
124
236
 
237
+ function parseStaticNumberToken(state) {
238
+ const match = /^[-]?(?:0|[1-9]\d*)(?:\.\d+)?/.exec(state.text.slice(state.index));
239
+ if (!match) return undefined;
240
+ state.index += match[0].length;
241
+ return match[0];
242
+ }
243
+
244
+ function parseIdentifierToken(state) {
245
+ const match = /^[A-Za-z_$][\w$]*/.exec(state.text.slice(state.index));
246
+ if (!match) return undefined;
247
+ state.index += match[0].length;
248
+ return match[0];
249
+ }
250
+
251
+ function consumeChar(state, char) {
252
+ if (state.text[state.index] !== char) return false;
253
+ state.index += 1;
254
+ return true;
255
+ }
256
+
257
+ function skipWhitespace(state) {
258
+ while (/\s/.test(state.text[state.index] ?? '')) state.index += 1;
259
+ }
260
+
125
261
  function staticPropReference(text) {
126
262
  const value = normalizedText(text);
127
263
  if (!/^(?:this|[A-Za-z_$][\w$]*)(?:\s*\.\s*[A-Za-z_$][\w$]*)*$/.test(value)) return undefined;
@@ -133,6 +269,7 @@ function staticPropReference(text) {
133
269
  function jsxPropValueDynamicBlockerReasonCode(text) {
134
270
  const value = normalizedText(text);
135
271
  if (/\[[\s\S]*\]/.test(value)) return 'jsx-render-prop-value-computed-reference-unsupported';
272
+ if (/^`[\s\S]*\$\{[\s\S]*`$/.test(value)) return 'jsx-render-prop-value-template-interpolation-unsupported';
136
273
  if (/\?\.\s*\(/.test(value) || /\b[A-Za-z_$][\w$]*(?:\s*(?:\.|\?\.)\s*[A-Za-z_$][\w$]*)*\s*\(/.test(value)) return 'jsx-render-prop-value-call-expression-unsupported';
137
274
  if (/\?\./.test(value)) return 'jsx-render-prop-value-optional-reference-unsupported';
138
275
  return 'jsx-render-prop-value-expression-unsupported';
@@ -295,7 +295,7 @@ function packageSpecifierInfo(moduleSpecifier) {
295
295
 
296
296
  function packageResolutionFields(candidate, packageInfo) {
297
297
  if (!candidate.packageName && candidate.kind !== 'package') return {};
298
- return { packageName: candidate.packageName ?? packageInfo?.packageName, packageSubpath: candidate.packageSubpath ?? packageInfo?.packageSubpath, packageExportKey: candidate.packageExportKey, packageExportCondition: candidate.packageExportCondition, packageExportTarget: candidate.packageExportTarget, packageImportKey: candidate.packageImportKey, packageImportCondition: candidate.packageImportCondition, packageImportTarget: candidate.packageImportTarget, packageRuntimeCondition: candidate.packageRuntimeCondition, packageRuntimeConditionEvidenceSource: candidate.packageRuntimeConditionEvidenceSource, packageRuntimeConditionEdgeKind: candidate.packageRuntimeConditionEdgeKind, packageRuntimeConditionCandidates: candidate.packageRuntimeConditionCandidates, packageRuntimeConditionReasonCode: candidate.packageRuntimeConditionReasonCode, packageEnvironmentCondition: candidate.packageEnvironmentCondition, packageEnvironmentConditionEvidenceSource: candidate.packageEnvironmentConditionEvidenceSource, packageEnvironmentConditionCandidates: candidate.packageEnvironmentConditionCandidates, packageEnvironmentConditionReasonCode: candidate.packageEnvironmentConditionReasonCode, packageType: candidate.packageType, packageWorkspaceRootAmbiguous: candidate.packageWorkspaceRootAmbiguous, packageWorkspaceRoots: candidate.packageWorkspaceRoots, packageResolutionReasonCode: candidate.packageResolutionReasonCode };
298
+ return { packageName: candidate.packageName ?? packageInfo?.packageName, packageSubpath: candidate.packageSubpath ?? packageInfo?.packageSubpath, packageExportKey: candidate.packageExportKey, packageExportCondition: candidate.packageExportCondition, packageExportTarget: candidate.packageExportTarget, packageImportKey: candidate.packageImportKey, packageImportCondition: candidate.packageImportCondition, packageImportTarget: candidate.packageImportTarget, packageRuntimeCondition: candidate.packageRuntimeCondition, packageRuntimeConditionEvidenceSource: candidate.packageRuntimeConditionEvidenceSource, packageRuntimeConditionEdgeKind: candidate.packageRuntimeConditionEdgeKind, packageRuntimeConditionCandidates: candidate.packageRuntimeConditionCandidates, packageRuntimeConditionExcludedConditions: candidate.packageRuntimeConditionExcludedConditions, packageRuntimeConditionReasonCode: candidate.packageRuntimeConditionReasonCode, packageEnvironmentCondition: candidate.packageEnvironmentCondition, packageEnvironmentConditionEvidenceSource: candidate.packageEnvironmentConditionEvidenceSource, packageEnvironmentConditionCandidates: candidate.packageEnvironmentConditionCandidates, packageEnvironmentConditionReasonCode: candidate.packageEnvironmentConditionReasonCode, packageType: candidate.packageType, packageWorkspaceRootAmbiguous: candidate.packageWorkspaceRootAmbiguous, packageWorkspaceRoots: candidate.packageWorkspaceRoots, packageResolutionReasonCode: candidate.packageResolutionReasonCode };
299
299
  }
300
300
 
301
301
  function environmentAmbiguityFields(ambiguity) { return { packageEnvironmentConditionCandidates: ambiguity.split('|'), packageEnvironmentConditionReasonCode: 'package-environment-condition-ambiguous-missing' }; }
@@ -1,3 +1,5 @@
1
+ import { runtimeAdmittedConditions, runtimeConditionRecord } from './projectSymbolGraphPackageRuntimeConditions.js';
2
+
1
3
  const EnvironmentPackageConditions = Object.freeze([
2
4
  'browser',
3
5
  'node',
@@ -30,7 +32,10 @@ function exportMapMatch(exportsValue, subpath) {
30
32
 
31
33
  function packageConditions(moduleResolution = {}, sourcePath, packageContext, edgeMetadata) {
32
34
  return prioritizeConditions(
33
- moduleResolution.packageExportConditions ?? moduleResolution.conditions ?? ['types', 'import', 'module', 'require', 'default'],
35
+ runtimeAdmittedConditions(
36
+ moduleResolution.packageExportConditions ?? moduleResolution.conditions ?? ['types', 'import', 'module', 'require', 'default'],
37
+ packageRuntimeConditionEvidence(moduleResolution, sourcePath, packageContext, edgeMetadata).packageRuntimeCondition
38
+ ),
34
39
  packageConditionPreferences(sourcePath, moduleResolution, packageContext, edgeMetadata)
35
40
  );
36
41
  }
@@ -78,8 +83,8 @@ function packageRuntimeConditionEvidence(moduleResolution = {}, sourcePath, pack
78
83
  }
79
84
  const hostAmbiguity = edgeCondition ? undefined : packageRuntimeHostConditionAmbiguity(edgeMetadata, packageType);
80
85
  if (hostAmbiguity) return hostAmbiguity;
81
- if (extensionCondition) return { packageRuntimeCondition: extensionCondition, packageRuntimeConditionEvidenceSource: 'source-extension', packageType };
82
- if (packageTypeCondition) return { packageRuntimeCondition: packageTypeCondition, packageRuntimeConditionEvidenceSource: 'package-type', packageType };
86
+ if (extensionCondition) return runtimeConditionRecord({ packageRuntimeCondition: extensionCondition, packageRuntimeConditionEvidenceSource: 'source-extension', packageType });
87
+ if (packageTypeCondition) return runtimeConditionRecord({ packageRuntimeCondition: packageTypeCondition, packageRuntimeConditionEvidenceSource: 'package-type', packageType });
83
88
  return {};
84
89
  }
85
90
 
@@ -178,14 +183,14 @@ function packageRuntimeHostConditionAmbiguity(edgeMetadata = {}, packageType) {
178
183
  }
179
184
 
180
185
  function edgeCondition(packageRuntimeCondition, packageRuntimeConditionEdgeKind, packageRuntimeConditionReasonCode, preferred, conflictsWithSource) {
181
- return {
186
+ return runtimeConditionRecord({
182
187
  packageRuntimeCondition,
183
188
  packageRuntimeConditionEvidenceSource: 'edge-kind',
184
189
  packageRuntimeConditionEdgeKind,
185
190
  packageRuntimeConditionReasonCode,
186
191
  preferred,
187
192
  conflictsWithSource
188
- };
193
+ });
189
194
  }
190
195
 
191
196
  function staticImportKind(importKind) {
@@ -303,12 +308,4 @@ function pathInsideRoot(sourcePath, root) {
303
308
  return sourcePath === root || sourcePath.startsWith(`${root}/`);
304
309
  }
305
310
 
306
- export {
307
- exportMapMatch,
308
- exportTargetsForValue,
309
- packageConditions,
310
- packageEnvironmentConditionAmbiguity,
311
- packageEnvironmentConditionEvidence,
312
- packageRuntimeConditionAmbiguity,
313
- packageRuntimeConditionEvidence
314
- };
311
+ export { exportMapMatch, exportTargetsForValue, packageConditions, packageEnvironmentConditionAmbiguity, packageEnvironmentConditionEvidence, packageRuntimeConditionAmbiguity, packageRuntimeConditionEvidence };
@@ -0,0 +1,22 @@
1
+ function runtimeAdmittedConditions(conditions, runtimeCondition) {
2
+ const entries = Array.isArray(conditions) ? conditions : [conditions];
3
+ const excluded = new Set(runtimeExcludedConditions(runtimeCondition));
4
+ return excluded.size ? entries.filter((entry) => !excluded.has(String(entry))) : entries;
5
+ }
6
+
7
+ function runtimeConditionRecord(record) {
8
+ return compactRecord({
9
+ ...record,
10
+ packageRuntimeConditionExcludedConditions: runtimeExcludedConditions(record.packageRuntimeCondition)
11
+ });
12
+ }
13
+
14
+ function runtimeExcludedConditions(runtimeCondition) {
15
+ if (runtimeCondition === 'import') return ['require'];
16
+ if (runtimeCondition === 'require') return ['import', 'module'];
17
+ return [];
18
+ }
19
+
20
+ function compactRecord(record) { return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)); }
21
+
22
+ export { runtimeAdmittedConditions, runtimeConditionRecord };
@@ -8,6 +8,7 @@ import { nearestPublicOwnerForOffset } from './projectSymbolGraphScopeUseDefOwne
8
8
  import { readStaticMemberLiteral } from './staticMemberLiteral.js';
9
9
 
10
10
  const jsTsKeywords = new Set('abstract as async await break case catch class const continue debugger declare default delete do else enum export extends false finally for from function if implements import in infer instanceof interface keyof let module namespace new null of package private protected public readonly return satisfies static super switch this throw true try type typeof undefined unique unknown var void while with yield'.split(' '));
11
+ const namespaceComputedMemberDynamicUnsupportedReason = 'lexical-scope-namespace-computed-member-dynamic-unsupported', namespaceComputedMemberUnresolvedReason = 'lexical-scope-namespace-computed-member-unresolved';
11
12
 
12
13
  function lexicalScopeRecordsForImport(sourceText, context) {
13
14
  const masked = maskNonCode(sourceText);
@@ -230,15 +231,17 @@ function namespacePropertyAccess(code, token, binding, context) {
230
231
 
231
232
  function namespaceComputedPropertyAccess(sourceText, code, tokenStart, open) {
232
233
  const close = findMatchingBracket(code, open);
233
- if (close === -1) return blockedNamespaceComputedPropertyAccess();
234
+ if (close === -1) return blockedNamespaceComputedPropertyAccess(undefined, [namespaceComputedMemberUnresolvedReason]);
234
235
  const writeOperation = namespaceMemberWriteOperation(code, tokenStart, close + 1);
235
236
  let index = open + 1;
236
237
  while (index < close && /\s/.test(sourceText[index])) index += 1;
238
+ if (index >= close) return blockedNamespaceComputedPropertyAccess(writeOperation, [namespaceComputedMemberUnresolvedReason]);
237
239
  const literal = readStaticMemberLiteral(sourceText, index, close);
238
- if (!literal) return blockedNamespaceComputedPropertyAccess(writeOperation);
240
+ if (!literal) return blockedNamespaceComputedPropertyAccess(writeOperation, [namespaceComputedMemberDynamicUnsupportedReason]);
239
241
  let afterLiteral = literal.end + 1;
240
242
  while (afterLiteral < close && /\s/.test(sourceText[afterLiteral])) afterLiteral += 1;
241
- if (afterLiteral !== close || !identifierRegExp.test(literal.value)) return blockedNamespaceComputedPropertyAccess(writeOperation);
243
+ if (afterLiteral !== close) return blockedNamespaceComputedPropertyAccess(writeOperation, [namespaceComputedMemberDynamicUnsupportedReason]);
244
+ if (!identifierRegExp.test(literal.value)) return blockedNamespaceComputedPropertyAccess(writeOperation);
242
245
  if (writeOperation) {
243
246
  return blockedNamespaceMemberWrite('namespace-computed-property-write', {
244
247
  memberName: literal.value,
@@ -252,31 +255,18 @@ function namespaceComputedPropertyAccess(sourceText, code, tokenStart, open) {
252
255
  return { referenceKind: 'namespace-computed-property-read', memberName: literal.value, memberStart: literal.start, memberEnd: literal.end, memberComputed: true, memberLiteralKind: literal.literalKind };
253
256
  }
254
257
 
255
- function blockedNamespaceComputedPropertyAccess(writeOperation) {
258
+ function blockedNamespaceComputedPropertyAccess(writeOperation, reasonCodes = []) {
256
259
  return {
257
260
  referenceKind: writeOperation ? 'namespace-computed-property-write' : 'namespace-computed-property-read',
258
261
  memberComputed: true,
259
262
  writeOperation,
260
263
  status: 'blocked',
261
- reasonCodes: [
262
- LexicalUseDefReasonCodes.namespaceComputedMemberUnsupported,
263
- ...(writeOperation ? [LexicalUseDefReasonCodes.namespaceMemberWriteUnsupported] : [])
264
- ]
264
+ reasonCodes: uniqueReasonCodes([LexicalUseDefReasonCodes.namespaceComputedMemberUnsupported, ...reasonCodes, ...(writeOperation ? [LexicalUseDefReasonCodes.namespaceMemberWriteUnsupported] : [])])
265
265
  };
266
266
  }
267
267
 
268
268
  function blockedNamespaceMemberWrite(referenceKind, fields = {}) {
269
- return {
270
- referenceKind,
271
- memberName: fields.memberName,
272
- memberStart: fields.memberStart,
273
- memberEnd: fields.memberEnd,
274
- memberComputed: fields.memberComputed,
275
- memberLiteralKind: fields.memberLiteralKind,
276
- status: 'blocked',
277
- reasonCodes: [LexicalUseDefReasonCodes.namespaceMemberWriteUnsupported],
278
- writeOperation: fields.writeOperation
279
- };
269
+ return { referenceKind, memberName: fields.memberName, memberStart: fields.memberStart, memberEnd: fields.memberEnd, memberComputed: fields.memberComputed, memberLiteralKind: fields.memberLiteralKind, status: 'blocked', reasonCodes: [LexicalUseDefReasonCodes.namespaceMemberWriteUnsupported], writeOperation: fields.writeOperation };
280
270
  }
281
271
 
282
272
  function namespaceMemberWriteOperation(code, tokenStart, accessEnd) {
@@ -317,4 +307,6 @@ function findMatchingBracket(code, open) {
317
307
  return -1;
318
308
  }
319
309
 
310
+ function uniqueReasonCodes(reasonCodes) { return [...new Set(reasonCodes.filter(Boolean))]; }
311
+
320
312
  export { lexicalScopeRecordsForImport };
@@ -80,10 +80,18 @@ function exactBranchProjectSemanticEditAdmission(options) {
80
80
  if (requireOtherBranchUnchanged && !otherProjectBranchUnchanged(file, classification.branch, { requireBase: requireBaseForOtherBranchUnchanged })) return undefined;
81
81
  }
82
82
  const outputHash = hashProjectSourceText(branchText);
83
+ const admissionOutcome = 'safe';
84
+ const admissionOutcomeReasonCode = exactMergedOutput && allowExistingExactOutput
85
+ ? 'existing-exact-branch-output'
86
+ : typeof branchText === 'string'
87
+ ? 'exact-branch-output-other-branch-unchanged'
88
+ : 'exact-branch-deletion-other-branch-unchanged';
83
89
  const admission = {
84
90
  id: safeProjectEvidenceId(`${classification.details?.conflictKey ?? classification.code}_${file.sourcePath}`),
85
91
  kind: admissionKind,
86
92
  status: 'passed',
93
+ admissionOutcome,
94
+ admissionOutcomeReasonCode,
87
95
  branch: classification.branch,
88
96
  ...(admissionFields(classification) ?? {}),
89
97
  sourcePath: file.sourcePath,
@@ -94,6 +102,8 @@ function exactBranchProjectSemanticEditAdmission(options) {
94
102
  ...(details(classification) ?? {}),
95
103
  sourcePath: file.sourcePath,
96
104
  outputHash,
105
+ admissionOutcome,
106
+ admissionOutcomeReasonCode,
97
107
  exactBranchOutput: true,
98
108
  deletedOutput: typeof branchText !== 'string' || undefined,
99
109
  autoMergeClaim: false,
@@ -21,7 +21,7 @@ function fileAdmissionEvidenceRecords(files = []) {
21
21
  return files.flatMap((file) => [
22
22
  ...recordArraysWithSuffix(file.summary, 'AdmissionEvidence'),
23
23
  ...recordArraysWithSuffix(file.metadata, 'Admissions')
24
- ]);
24
+ ].map(admissionEvidenceRecordWithOutcome));
25
25
  }
26
26
 
27
27
  function recordArraysWithSuffix(record, suffix) {
@@ -32,7 +32,35 @@ function recordArraysWithSuffix(record, suffix) {
32
32
  .filter((value) => value?.kind && value?.id);
33
33
  }
34
34
 
35
+ function admissionEvidenceRecordWithOutcome(record) {
36
+ const admissionOutcome = admissionEvidenceOutcome(record);
37
+ return compactRecord({
38
+ ...record,
39
+ admissionOutcome,
40
+ admissionOutcomeReasonCode: admissionEvidenceOutcomeReasonCode(record, admissionOutcome)
41
+ });
42
+ }
43
+
44
+ function admissionEvidenceOutcome(record) {
45
+ if (['safe', 'review', 'blocked'].includes(record?.admissionOutcome)) return record.admissionOutcome;
46
+ const routeStatus = record?.admissionRoute?.status;
47
+ if (record?.status === 'passed' && (!routeStatus || routeStatus === 'passed')) return 'safe';
48
+ if (record?.status === 'failed' || routeStatus === 'failed' || routeStatus === 'blocked') return 'blocked';
49
+ return 'review';
50
+ }
51
+
52
+ function admissionEvidenceOutcomeReasonCode(record, admissionOutcome) {
53
+ if (typeof record?.admissionOutcomeReasonCode === 'string' && record.admissionOutcomeReasonCode.length > 0) return record.admissionOutcomeReasonCode;
54
+ const routeReasonCode = record?.admissionRoute?.reasonCodes?.[0];
55
+ if (typeof record?.details?.reasonCode === 'string' && record.details.reasonCode.length > 0) return record.details.reasonCode;
56
+ if (typeof routeReasonCode === 'string' && routeReasonCode.length > 0) return routeReasonCode;
57
+ if (admissionOutcome === 'safe' && record?.details?.exactBranchOutput === true) return 'passed-exact-branch-output';
58
+ if (admissionOutcome === 'safe') return 'passed-admission-evidence';
59
+ if (admissionOutcome === 'blocked') return 'failed-admission-evidence';
60
+ return 'review-admission-evidence';
61
+ }
62
+
35
63
  function isPlainObject(value) { return Boolean(value && typeof value === 'object' && !Array.isArray(value)); }
36
64
  function compactRecord(record) { return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)); }
37
65
 
38
- export { failedEvidenceMissingItems, fileAdmissionEvidenceRecords };
66
+ export { admissionEvidenceOutcome, failedEvidenceMissingItems, fileAdmissionEvidenceRecords };
@@ -117,6 +117,8 @@ function missingSharedCompilerTypeEquivalenceEvidence(workerRecord, headRecord)
117
117
  enumMemberCount: record.enumMemberCount,
118
118
  enumComputedMemberCount: record.enumComputedMemberCount,
119
119
  typeEquivalenceEnumRuntimeShapeHash: record.typeEquivalenceEnumRuntimeShapeHash,
120
+ advancedTypeProofRequirement: record.advancedTypeProofRequirement,
121
+ advancedTypeMissingProof: record.advancedTypeMissingProof,
120
122
  typeEquivalenceSignatureSetHash: record.typeEquivalenceSignatureSetHash,
121
123
  typeEquivalenceCallSignatureSetHash: record.typeEquivalenceCallSignatureSetHash, typeEquivalenceConstructSignatureSetHash: record.typeEquivalenceConstructSignatureSetHash,
122
124
  typeEquivalenceTypeParameterSetHash: record.typeEquivalenceTypeParameterSetHash,
@@ -169,9 +171,14 @@ function hasPassedCompilerTypeEquivalenceProof(record) {
169
171
  ];
170
172
  return Boolean(record?.typeEquivalenceStatus === 'compiler-backed-equivalent'
171
173
  && record?.typeEquivalenceProof?.status === 'passed'
174
+ && !hasMissingAdvancedTypeProof(record)
172
175
  && requiredHashes.every(([required, hash]) => !required || hash)
173
176
  && record?.apiSignatureHash);
174
177
  }
178
+ function hasMissingAdvancedTypeProof(record) {
179
+ const status = record?.advancedTypeMissingProof?.status ?? record?.advancedTypeProofRequirement?.status;
180
+ return status === 'missing-compiler-evidence' || status === 'requires-review';
181
+ }
175
182
  function recordsByIdentityKey(records, identityKey) { const result = new Map(); for (const record of records ?? []) { const key = identityKey(record); if (!key || result.has(key)) continue; result.set(key, record); } return result; }
176
183
  function optionalFingerprint(record, fingerprint) { return record ? fingerprint(record) : undefined; }
177
184
  function stableKey(parts) { const values = parts.map((part) => part === undefined || part === null ? '' : String(part)); return values.some(Boolean) ? values.join('#') : undefined; }
@@ -7,8 +7,11 @@ function htmlCssProjectSummary(files) {
7
7
  htmlParserEvidenceFiles: htmlFiles.filter(hasHtmlParserEvidence).length, cssParserEvidenceFiles: cssFiles.filter(hasCssParserEvidence).length, htmlCssParserEvidenceFiles: htmlCssFiles.filter((file) => hasHtmlParserEvidence(file) || hasCssParserEvidence(file)).length,
8
8
  htmlParserEvidenceFailedFiles: htmlFiles.filter(hasParserEvidenceFailure).length, cssParserEvidenceFailedFiles: cssFiles.filter(hasParserEvidenceFailure).length, htmlCssParserEvidenceFailedFiles: htmlCssFiles.filter(hasParserEvidenceFailure).length,
9
9
  htmlIdentityEvidenceFiles: htmlFiles.filter(hasHtmlIdentityEvidence).length, cssSelectorTargetEvidenceFiles: cssFiles.filter(hasCssSelectorTargetEvidence).length, htmlCssStructuralTargetEvidenceFiles: htmlCssFiles.filter((file) => hasHtmlIdentityEvidence(file) || hasCssSelectorTargetEvidence(file)).length,
10
+ htmlExplicitIdentityEvidenceFiles: htmlFiles.filter(hasHtmlExplicitIdentityEvidence).length, htmlPathOnlyIdentityResidualFiles: htmlFiles.filter(hasHtmlPathOnlyIdentityResidual).length,
11
+ htmlRuntimeBoundaryEvidenceFiles: htmlFiles.filter(hasHtmlRuntimeBoundaryEvidence).length, htmlFrameworkBoundaryEvidenceFiles: htmlFiles.filter(hasHtmlFrameworkBoundaryEvidence).length, htmlProofGapBlockedFiles: htmlFiles.filter(hasHtmlProofGapBlockedConflict).length,
10
12
  htmlIdentityEvidenceFailedFiles: htmlFiles.filter(hasHtmlIdentityEvidenceFailure).length, cssSelectorTargetConflictFiles: cssFiles.filter(hasCssSelectorTargetConflict).length, htmlCssStructuralTargetEvidenceFailedFiles: htmlCssFiles.filter((file) => hasHtmlIdentityEvidenceFailure(file) || hasCssSelectorTargetConflict(file)).length,
11
13
  cssSelectorTargetRebasedFiles: cssFiles.filter(hasCssSelectorTargetRebase).length,
14
+ cssScopedCascadeFiles: cssFiles.filter(hasCssScopedCascadeScope).length, cssScopedCascadeEvidenceFiles: cssFiles.filter(hasCssScopedCascadeEvidence).length, cssScopedCascadeBlockedFiles: cssFiles.filter(hasCssScopedCascadeMissingProof).length,
12
15
  htmlCssBrowserRuntimeProofs: htmlCssFiles.filter(hasBrowserRuntimeProof).length
13
16
  };
14
17
  }
@@ -31,6 +34,13 @@ function hasHtmlIdentityEvidence(file) {
31
34
  const evidence = file?.result?.identityEvidence;
32
35
  return evidence?.parserBackedStructuralSpans === true && evidence.structuralAddressability === true;
33
36
  }
37
+ function hasHtmlExplicitIdentityEvidence(file) {
38
+ const evidence = file?.result?.identityEvidence;
39
+ return hasHtmlIdentityEvidence(file) && evidence.explicitIdentityAvailable === true;
40
+ }
41
+ function hasHtmlPathOnlyIdentityResidual(file) { return (file?.result?.identityEvidence?.pathOnlyIdentityElements ?? 0) > 0; }
42
+ function hasHtmlRuntimeBoundaryEvidence(file) { return (file?.result?.identityEvidence?.runtimeBoundaryElements ?? 0) > 0; }
43
+ function hasHtmlFrameworkBoundaryEvidence(file) { return (file?.result?.identityEvidence?.frameworkBoundaryElements ?? 0) > 0; }
34
44
  function hasHtmlIdentityEvidenceFailure(file) {
35
45
  const evidence = file?.result?.identityEvidence;
36
46
  return Boolean(evidence) && (evidence.parserBackedStructuralSpans !== true || evidence.structuralAddressability !== true);
@@ -42,10 +52,26 @@ function hasCssSelectorTargetEvidence(file) {
42
52
  function hasCssSelectorTargetConflict(file) {
43
53
  return (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => conflict.code === 'css-selector-target-conflict');
44
54
  }
55
+ function hasHtmlProofGapBlockedConflict(file) {
56
+ return (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => conflict.code === 'html-proof-gap-blocked');
57
+ }
45
58
  function hasCssSelectorTargetRebase(file) { return (file?.result?.selectorTargetEvidence?.rebasedChangeCount ?? 0) > 0; }
59
+ function hasCssScopedCascadeScope(file) { return cssScopedRuleCount(file) > 0; }
60
+ function hasCssScopedCascadeEvidence(file) {
61
+ return hasCssScopedCascadeScope(file) && file?.result?.parserEvidence?.scopedCascadeGraphHashPresent === true;
62
+ }
63
+ function hasCssScopedCascadeMissingProof(file) {
64
+ return hasCssScopedCascadeScope(file) && (file?.result?.conflicts ?? file?.conflicts ?? []).some((conflict) => ScopedCascadeMissingProofReasonCodes.has(conflict?.details?.reasonCode));
65
+ }
66
+ function cssScopedRuleCount(file) {
67
+ const sides = Object.values(file?.result?.selectorTargetEvidence?.sides ?? {});
68
+ return sides.reduce((count, side) => Math.max(count, side?.scopedRuleCount ?? 0), 0);
69
+ }
46
70
  function hasBrowserRuntimeProof(file) {
47
71
  const admission = file?.result?.admission ?? file?.admission ?? {};
48
72
  return admission.browserRuntimeEquivalenceClaim === true || admission.browserCascadeEquivalenceClaim === true || admission.browserRenderEquivalenceClaim === true;
49
73
  }
50
74
 
75
+ const ScopedCascadeMissingProofReasonCodes = new Set(['css-scoped-cascade-equivalence-unproved', 'css-media-cascade-scope-unproved', 'css-supports-cascade-scope-unproved', 'css-container-cascade-scope-unproved', 'css-layer-cascade-scope-unproved', 'css-scope-cascade-scope-unproved']);
76
+
51
77
  export { htmlCssProjectSummary };
@@ -57,6 +57,16 @@ function scanPreservedSourceTokens(sourceText, input) {
57
57
  push(trivia, 'whitespace', text, start);
58
58
  continue;
59
59
  }
60
+ if (offset === 0 && char === '#' && next === '!') {
61
+ let text = '';
62
+ while (offset < sourceText.length && sourceText[offset] !== '\n' && sourceText[offset] !== '\r') {
63
+ text += sourceText[offset];
64
+ offset += 1;
65
+ column += 1;
66
+ }
67
+ push(trivia, 'shebang', text, start);
68
+ continue;
69
+ }
60
70
  if (char === '/' && next === '/') {
61
71
  let text = '';
62
72
  while (offset < sourceText.length && sourceText[offset] !== '\n' && sourceText[offset] !== '\r') {
@@ -0,0 +1,141 @@
1
+ function dynamicImportEvidenceRecords(line, start, end) {
2
+ const expression = String(line ?? '');
3
+ const records = [];
4
+ for (const call of dynamicImportCalls(expression)) {
5
+ if (!rangesOverlap(start, end, call.start, call.end) && !rangesOverlap(start, end, call.argumentStart, call.argumentEnd)) continue;
6
+ const specifier = normalizeOrderEvidenceText(call.argumentText);
7
+ const specifierKind = dynamicImportSpecifierKind(specifier, call.closed);
8
+ const staticSpecifier = dynamicImportStaticSpecifierEvidence(specifier, specifierKind);
9
+ records.push(compactRecord({
10
+ kind: 'dynamic-import',
11
+ ordinal: records.length + 1,
12
+ text: normalizeOrderEvidenceText(call.text),
13
+ specifierText: specifier,
14
+ specifierKind,
15
+ dynamicImportStaticSpecifierEvidence: staticSpecifier,
16
+ dynamicImportRuntimeResolutionClaim: false,
17
+ dynamicImportResolutionProofRequired: !staticSpecifier,
18
+ runtimeEquivalenceClaim: false
19
+ }));
20
+ }
21
+ return records;
22
+ }
23
+
24
+ function dynamicImportCalls(expression) {
25
+ const text = String(expression ?? '');
26
+ const records = [];
27
+ let quote;
28
+ let escaped = false;
29
+ for (let index = 0; index < text.length; index += 1) {
30
+ const char = text[index];
31
+ if (quote) {
32
+ if (escaped) escaped = false;
33
+ else if (char === '\\') escaped = true;
34
+ else if (char === quote) quote = undefined;
35
+ continue;
36
+ }
37
+ if (char === '\'' || char === '"' || char === '`') { quote = char; continue; }
38
+ const match = dynamicImportAt(text, index);
39
+ if (!match) continue;
40
+ records.push(match);
41
+ index = Math.max(index, match.end - 1);
42
+ }
43
+ return records;
44
+ }
45
+
46
+ function dynamicImportAt(text, index) {
47
+ if (text.slice(index, index + 6) !== 'import' || isIdentifierPart(text[index - 1]) || isIdentifierPart(text[index + 6])) return undefined;
48
+ let cursor = index + 6;
49
+ while (/\s/.test(text[cursor] ?? '')) cursor += 1;
50
+ if (text[cursor] !== '(') return undefined;
51
+ const close = matchingParenIndex(text, cursor);
52
+ const end = close === undefined ? statementEnd(text, cursor) : close + 1;
53
+ return {
54
+ start: index,
55
+ text: text.slice(index, end),
56
+ argumentText: firstCallArgumentText(text, cursor + 1, close ?? end),
57
+ argumentStart: cursor + 1,
58
+ argumentEnd: close ?? end,
59
+ end,
60
+ closed: close !== undefined
61
+ };
62
+ }
63
+
64
+ function firstCallArgumentText(text, start, end) {
65
+ let depth = 0;
66
+ let quote;
67
+ let escaped = false;
68
+ for (let index = start; index < end; index += 1) {
69
+ const char = text[index];
70
+ if (quote) {
71
+ if (escaped) escaped = false;
72
+ else if (char === '\\') escaped = true;
73
+ else if (char === quote) quote = undefined;
74
+ continue;
75
+ }
76
+ if (char === '\'' || char === '"' || char === '`') { quote = char; continue; }
77
+ if (char === '(' || char === '[' || char === '{') depth += 1;
78
+ else if (char === ')' || char === ']' || char === '}') depth = Math.max(0, depth - 1);
79
+ else if (char === ',' && depth === 0) return text.slice(start, index);
80
+ }
81
+ return text.slice(start, end);
82
+ }
83
+
84
+ function dynamicImportSpecifierKind(specifierText, closed) {
85
+ const text = String(specifierText ?? '').trim();
86
+ if (!closed || !text) return 'unparsed';
87
+ if (isStaticStringLiteral(text) || isStaticTemplateLiteral(text)) return 'literal';
88
+ if (text.startsWith('`')) return 'template';
89
+ if (/^[A-Za-z_$][\w$]*$/.test(text)) return 'identifier';
90
+ if (/^[A-Za-z_$][\w$]*(?:(?:\.|\?\.)[A-Za-z_$][\w$]*|\[[^\]]+\])+$/.test(text)) return 'member';
91
+ if (/\?/.test(text) && /:/.test(text)) return 'conditional';
92
+ if (/[+\-*/%]|\|\||&&|\?\?/.test(text)) return 'binary';
93
+ if (/\)\s*$/.test(text)) return 'call';
94
+ return 'expression';
95
+ }
96
+
97
+ function dynamicImportStaticSpecifierEvidence(specifierText, specifierKind) {
98
+ if (specifierKind !== 'literal') return false;
99
+ return isStaticStringLiteral(specifierText) || isStaticTemplateLiteral(specifierText);
100
+ }
101
+
102
+ function dynamicImportSignatureEvidence(record) {
103
+ return compactRecord({
104
+ specifierKind: record?.specifierKind,
105
+ specifierText: record?.specifierText,
106
+ dynamicImportStaticSpecifierEvidence: record?.dynamicImportStaticSpecifierEvidence,
107
+ dynamicImportRuntimeResolutionClaim: record?.dynamicImportRuntimeResolutionClaim,
108
+ dynamicImportResolutionProofRequired: record?.dynamicImportResolutionProofRequired,
109
+ runtimeEquivalenceClaim: record?.runtimeEquivalenceClaim
110
+ });
111
+ }
112
+
113
+ function matchingParenIndex(line, open) {
114
+ if (open < 0) return undefined;
115
+ let depth = 0;
116
+ let quote;
117
+ let escaped = false;
118
+ for (let index = open; index < line.length; index += 1) {
119
+ const char = line[index];
120
+ if (quote) {
121
+ if (escaped) escaped = false;
122
+ else if (char === '\\') escaped = true;
123
+ else if (char === quote) quote = undefined;
124
+ continue;
125
+ }
126
+ if (char === '\'' || char === '"' || char === '`') { quote = char; continue; }
127
+ if (char === '(') depth += 1;
128
+ else if (char === ')' && --depth === 0) return index;
129
+ }
130
+ return undefined;
131
+ }
132
+
133
+ function rangesOverlap(leftStart, leftEnd, rightStart, rightEnd) { return Math.max(leftStart, rightStart) < Math.min(leftEnd, rightEnd); }
134
+ function normalizeOrderEvidenceText(value) { return String(value ?? '').replace(/\s+/g, ' ').trim(); }
135
+ function isStaticStringLiteral(value) { const text = String(value ?? '').trim(), quote = text[0]; return (quote === '\'' || quote === '"') && text.endsWith(quote); }
136
+ function isStaticTemplateLiteral(value) { const text = String(value ?? '').trim(); return text.startsWith('`') && text.endsWith('`') && !text.includes('${'); }
137
+ function isIdentifierPart(char) { return /[A-Za-z0-9_$]/.test(char ?? ''); }
138
+ function statementEnd(line, start) { const semicolon = line.indexOf(';', start); return semicolon === -1 ? line.length : semicolon + 1; }
139
+ function compactRecord(record) { return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && (!Array.isArray(value) || value.length > 0))); }
140
+
141
+ export { dynamicImportEvidenceRecords, dynamicImportSignatureEvidence };
@@ -9,6 +9,7 @@ import { reachabilityOrderEvidence } from './semantic-import-runtime-reachabilit
9
9
  import { throwOrderEvidenceRecords } from './semantic-import-runtime-throw-evidence.js';
10
10
  import { promiseCombinatorEvidenceRecords } from './semantic-import-runtime-promise-combinator-evidence.js';
11
11
  import { promiseChainEvidenceRecords } from './semantic-import-runtime-promise-chain-evidence.js';
12
+ import { dynamicImportEvidenceRecords, dynamicImportSignatureEvidence } from './semantic-import-runtime-dynamic-import-evidence.js';
12
13
  function semanticFactOrderInfo(groups) {
13
14
  const bySubject = new Map();
14
15
  const info = new Map();
@@ -61,6 +62,7 @@ function semanticFactRuntimeOrderEvidence(sourceText, group, fact, spanInfo, ord
61
62
  sameLineAwaitOrder: sameLineEvidence.awaitOrder,
62
63
  sameLineOptionalChain: sameLineEvidence.optionalChain,
63
64
  sameLineConditionalExpression: sameLineEvidence.conditionalExpression,
65
+ sameLineDynamicImport: sameLineEvidence.dynamicImport,
64
66
  sameLinePromiseCombinator: sameLineEvidence.promiseCombinator,
65
67
  sameLinePromiseChain: sameLineEvidence.promiseChain,
66
68
  sameLineThrow: sameLineEvidence.throw,
@@ -85,6 +87,7 @@ function semanticFactRuntimeOrderSignatureEvidence(evidence) {
85
87
  sameLineAwaitOrder: evidence?.sameLineAwaitOrder,
86
88
  sameLineOptionalChain: evidence?.sameLineOptionalChain,
87
89
  sameLineConditionalExpression: evidence?.sameLineConditionalExpression,
90
+ sameLineDynamicImport: evidence?.sameLineDynamicImport?.map(dynamicImportSignatureEvidence),
88
91
  sameLinePromiseCombinator: evidence?.sameLinePromiseCombinator,
89
92
  sameLinePromiseChain: evidence?.sameLinePromiseChain,
90
93
  sameLineThrow: evidence?.sameLineThrow,
@@ -100,7 +103,7 @@ function sameLineRuntimeOrderEvidence(line, start, end) {
100
103
  const prefix = String(line ?? '').slice(0, start);
101
104
  const controlFlow = controlHeadEvidenceRecords(prefix), shortCircuit = shortCircuitEvidenceRecords(prefix), awaitOrder = awaitOrderEvidenceRecords(prefix);
102
105
  const optionalChain = optionalChainEvidenceRecords(line, start, end), conditionalExpression = conditionalExpressionEvidenceRecords(line, start, end);
103
- const promiseCombinator = promiseCombinatorEvidenceRecords(line, start, end), promiseChain = promiseChainEvidenceRecords(line, start, end), throwOrder = throwOrderEvidenceRecords(line, start, end);
106
+ const dynamicImport = dynamicImportEvidenceRecords(line, start, end), promiseCombinator = promiseCombinatorEvidenceRecords(line, start, end), promiseChain = promiseChainEvidenceRecords(line, start, end), throwOrder = throwOrderEvidenceRecords(line, start, end);
104
107
  return {
105
108
  controlFlow: controlFlow.length ? controlFlow : undefined,
106
109
  shortCircuit: shortCircuit.length ? shortCircuit : undefined,
@@ -108,6 +111,7 @@ function sameLineRuntimeOrderEvidence(line, start, end) {
108
111
  awaitOrder: awaitOrder.length ? awaitOrder : undefined,
109
112
  optionalChain: optionalChain.length ? optionalChain : undefined,
110
113
  conditionalExpression: conditionalExpression.length ? conditionalExpression : undefined,
114
+ dynamicImport: dynamicImport.length ? dynamicImport : undefined,
111
115
  promiseCombinator: promiseCombinator.length ? promiseCombinator : undefined,
112
116
  promiseChain: promiseChain.length ? promiseChain : undefined,
113
117
  throw: throwOrder.length ? true : /\bthrow\b/.test(prefix) || undefined,
@@ -126,7 +130,6 @@ function controlFlowOrderEvidence(line, lineNumber, group) {
126
130
  loop: records.filter((record) => record.kind === 'loop')
127
131
  };
128
132
  }
129
-
130
133
  function optionalChainEvidenceRecords(line, start, end) {
131
134
  const expression = String(line ?? '').slice(Math.max(0, start), Math.max(start, end));
132
135
  const matches = [...expression.matchAll(/\?\.(?:\s*\(|\s*[A-Za-z_$][\w$]*|\s*\[)/g)];
@@ -136,7 +139,6 @@ function optionalChainEvidenceRecords(line, start, end) {
136
139
  text: normalizeOrderEvidenceText(expression.slice(Math.max(0, match.index - 24), match.index + match[0].length + 24))
137
140
  }));
138
141
  }
139
-
140
142
  function awaitOrderEvidenceRecords(prefix) {
141
143
  const text = String(prefix ?? '');
142
144
  const tokens = awaitTokenIndexes(text);
@@ -164,7 +166,6 @@ function awaitTokenIndexes(text) {
164
166
  }
165
167
  return indexes;
166
168
  }
167
-
168
169
  function shortCircuitEvidenceRecords(prefix) {
169
170
  const text = String(prefix ?? '');
170
171
  const operators = shortCircuitOperators(text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.161",
3
+ "version": "0.2.162",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",