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

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 (30) hide show
  1. package/dist/internal/index-impl/moduleHostResourceImportMetadata.js +47 -0
  2. package/dist/internal/index-impl/projectSymbolGraphCompilerAdvancedTypeMetadata.js +215 -1
  3. package/dist/internal/index-impl/projectSymbolGraphCompilerFacts.js +1 -1
  4. package/dist/internal/index-impl/projectSymbolGraphCssModuleUtils.js +56 -1
  5. package/dist/internal/index-impl/projectSymbolGraphCssModules.js +48 -4
  6. package/dist/internal/index-impl/projectSymbolGraphJsxPropRecordFields.js +91 -0
  7. package/dist/internal/index-impl/projectSymbolGraphJsxPropValues.js +35 -7
  8. package/dist/internal/index-impl/projectSymbolGraphJsxRecords.js +4 -31
  9. package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturnCollectionHelpers.js +201 -0
  10. package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturnCollections.js +210 -0
  11. package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturns.js +12 -5
  12. package/dist/internal/index-impl/projectSymbolGraphJsxSpreadPropValues.js +196 -0
  13. package/dist/internal/index-impl/projectSymbolGraphJsxStaticLiterals.js +207 -0
  14. package/dist/internal/index-impl/projectSymbolGraphModuleResolution.js +12 -14
  15. package/dist/internal/index-impl/projectSymbolGraphPackageConditions.js +33 -31
  16. package/dist/internal/index-impl/projectSymbolGraphPackageRuntimeConditions.js +22 -0
  17. package/dist/internal/index-impl/projectSymbolGraphScopeUseDefLexical.js +11 -19
  18. package/dist/internal/index-impl/syntaxModuleDeclarationEntries.js +27 -1
  19. package/dist/js-ts-safe-project-merge-admission.js +10 -0
  20. package/dist/js-ts-safe-project-merge-evidence-routing.js +30 -2
  21. package/dist/js-ts-safe-project-merge-graph-delta-compiler-conflicts.js +7 -0
  22. package/dist/js-ts-safe-project-merge-html-css-matrix.js +7 -2
  23. package/dist/js-ts-safe-project-merge-html-css-summary.js +110 -2
  24. package/dist/js-ts-safe-project-merge-html-css.js +137 -3
  25. package/dist/js-ts-safe-project-merge-jsx-graph-conflict-details.js +9 -0
  26. package/dist/js-ts-safe-project-merge.js +3 -0
  27. package/dist/native-source-preservation-scanner.js +10 -0
  28. package/dist/semantic-import-runtime-dynamic-import-evidence.js +141 -0
  29. package/dist/semantic-import-runtime-order-evidence.js +5 -4
  30. package/package.json +1 -1
@@ -11,6 +11,7 @@ import { jsxImportedComponentOwnerIndexes, jsxImportedMemberComponentOwnerIndexe
11
11
  import { jsxSameFileMemberComponentObjectIndex, jsxSameFileMemberComponentOwnerIndex } from './projectSymbolGraphJsxMemberComponents.js';
12
12
  import { jsxProviderFlowAncestorMap, jsxProviderFlowRecords } from './projectSymbolGraphJsxProviderFlows.js';
13
13
  import { jsxComponentPropRenderFlowBoundary, jsxComponentPropRenderFlowRecords } from './projectSymbolGraphJsxPropFlows.js';
14
+ import { jsxPropComponentFlowRecordFields, jsxPropValueRecordFields } from './projectSymbolGraphJsxPropRecordFields.js';
14
15
  import { jsxPropValueEvidence } from './projectSymbolGraphJsxPropValues.js';
15
16
  import { lineColumnForOffset } from './lineColumnForOffset.js';
16
17
 
@@ -112,7 +113,7 @@ function jsxElementRecord(tag, index, context) {
112
113
  function jsxPropRecordsForTag(tag, index, element, context) {
113
114
  return tag.attributes.map((attribute, attrIndex) => {
114
115
  const sourceSpan = sourceSpanForRange(context, attribute.start, attribute.end);
115
- const valueEvidence = jsxPropValueEvidence(tag, attribute);
116
+ const valueEvidence = jsxPropValueEvidence(tag, attribute, context);
116
117
  const componentPropRenderFlow = jsxComponentPropRenderFlowBoundary(tag, attribute, valueEvidence, { componentOwners: context.componentOwners, componentMemberOwners: context.componentMemberOwners, sourcePath: context.sourcePath, sourceText: context.sourceText });
117
118
  return compactRecord({
118
119
  id: `jsx_prop_${idFragment(context.sourcePath)}_${index + 1}_${attrIndex + 1}`,
@@ -122,36 +123,8 @@ function jsxPropRecordsForTag(tag, index, element, context) {
122
123
  propKind: propKind(attribute), keyProp: attribute.name === 'key' || undefined,
123
124
  spread: isJsxSpreadAttribute(attribute) || undefined, spreadOrdinal: attribute.spreadOrdinal,
124
125
  spreadExpressionHash: spreadExpressionHash(attribute),
125
- propValueProofStatus: valueEvidence?.proofStatus, propValueReasonCode: valueEvidence?.reasonCode,
126
- propValueKind: valueEvidence?.valueKind, propValueText: valueEvidence?.valueText,
127
- propValueExpressionText: valueEvidence?.expressionText, propValueReferenceRoot: valueEvidence?.referenceRoot,
128
- propValueReferencePath: valueEvidence?.referencePath, propValueDynamicText: valueEvidence?.dynamicText,
129
- propValueOptionalReference: valueEvidence?.optionalReference, propValueOptionalReferenceSegments: valueEvidence?.optionalReferenceSegments,
130
- propValueOptionalReferenceSegmentIndexes: valueEvidence?.optionalReferenceSegmentIndexes, propValueOptionalNullishBoundaryCount: valueEvidence?.optionalNullishBoundaryCount,
131
- propValueDynamicBlockerReasonCode: valueEvidence?.dynamicBlockerReasonCode,
132
- propValueExpressionHash: valueEvidence?.expressionHash, propValueSignatureHash: valueEvidence?.signatureHash,
133
- componentPropRenderFlowStatus: componentPropRenderFlow?.status, componentPropRenderFlowReasonCode: componentPropRenderFlow?.reasonCode,
134
- componentPropRenderFlowClaim: componentPropRenderFlow?.claim, componentPropRenderFlowClaimScope: componentPropRenderFlow?.claimScope,
135
- componentPropRenderFlowRenderEquivalenceClaim: componentPropRenderFlow?.renderEquivalenceClaim,
136
- componentPropRenderFlowScope: componentPropRenderFlow?.scope,
137
- componentPropRenderFlowTargetName: componentPropRenderFlow?.targetName,
138
- componentPropRenderFlowTargetKind: componentPropRenderFlow?.targetKind,
139
- componentPropRenderFlowTargetOwnerName: componentPropRenderFlow?.targetOwnerName,
140
- componentPropRenderFlowTargetOwnerCount: componentPropRenderFlow?.targetOwnerCount,
141
- componentPropRenderFlowTargetSourcePath: componentPropRenderFlow?.targetSourcePath,
142
- componentPropRenderFlowTargetLookupStatus: componentPropRenderFlow?.targetLookupStatus, componentPropRenderFlowTargetLookupScope: componentPropRenderFlow?.targetLookupScope,
143
- componentPropRenderFlowImportEdgeId: componentPropRenderFlow?.importEdgeId, componentPropRenderFlowImportKind: componentPropRenderFlow?.importKind, componentPropRenderFlowImportedName: componentPropRenderFlow?.importedName, componentPropRenderFlowLocalName: componentPropRenderFlow?.localName, componentPropRenderFlowTargetExportName: componentPropRenderFlow?.targetExportName,
144
- componentPropRenderFlowReExportEdgeId: componentPropRenderFlow?.reExportEdgeId, componentPropRenderFlowReExportSourcePath: componentPropRenderFlow?.reExportSourcePath, componentPropRenderFlowReExportExportedName: componentPropRenderFlow?.reExportExportedName, componentPropRenderFlowReExportLocalName: componentPropRenderFlow?.reExportLocalName, componentPropRenderFlowReExportTargetSourcePath: componentPropRenderFlow?.reExportTargetSourcePath, componentPropRenderFlowReExportKind: componentPropRenderFlow?.reExportKind, componentPropRenderFlowReExportIdentityId: componentPropRenderFlow?.reExportIdentityId, componentPropRenderFlowTargetLookupHash: componentPropRenderFlow?.targetLookupHash,
145
- componentPropRenderFlowMemberObjectName: componentPropRenderFlow?.memberObjectName, componentPropRenderFlowMemberPropertyName: componentPropRenderFlow?.memberPropertyName, componentPropRenderFlowMemberLocalName: componentPropRenderFlow?.memberLocalName, componentPropRenderFlowMemberBindingKind: componentPropRenderFlow?.memberBindingKind, componentPropRenderFlowMemberBindingHash: componentPropRenderFlow?.memberBindingHash,
146
- componentPropRenderFlowComponentPropName: componentPropRenderFlow?.componentPropName,
147
- componentPropRenderFlowRenderedTagName: componentPropRenderFlow?.renderedTagName,
148
- componentPropRenderFlowRenderedPropName: componentPropRenderFlow?.renderedPropName,
149
- componentPropRenderFlowPassthroughExpressionText: componentPropRenderFlow?.passthroughExpressionText,
150
- componentPropRenderFlowBindingKind: componentPropRenderFlow?.bindingKind,
151
- componentPropRenderFlowReturnOrdinal: componentPropRenderFlow?.returnOrdinal,
152
- componentPropRenderFlowDynamicBlockerReasonCode: componentPropRenderFlow?.dynamicBlockerReasonCode,
153
- componentPropRenderFlowTargetSignatureHash: componentPropRenderFlow?.targetSignatureHash,
154
- componentPropRenderFlowSignatureHash: componentPropRenderFlow?.signatureHash,
126
+ ...jsxPropValueRecordFields(valueEvidence),
127
+ ...jsxPropComponentFlowRecordFields(componentPropRenderFlow),
155
128
  publicContract: element.publicContract, publicOwnerName: element.publicOwnerName,
156
129
  signatureHash: hashSemanticValue({
157
130
  kind: 'frontier.lang.projectJsxPropSignature', tagName: tag.tagName, tagKey: tag.key,
@@ -0,0 +1,201 @@
1
+ function staticMapCall(expressionText) {
2
+ const value = normalizedReturnExpression(expressionText);
3
+ const target = /^([A-Za-z_$][\w$]*)\s*\.\s*map\s*\(/.exec(value);
4
+ if (!target) return undefined;
5
+ const argsStart = target[0].length - 1;
6
+ const argsEnd = matchingClose(value, argsStart, '(', ')');
7
+ if (argsEnd !== value.length - 1) return undefined;
8
+ return {
9
+ arrayName: target[1],
10
+ callbackText: normalizedText(value.slice(argsStart + 1, argsEnd))
11
+ };
12
+ }
13
+
14
+ function staticMapCallback(callbackText) {
15
+ const value = normalizedText(callbackText);
16
+ const match = /^(?:\(\s*([A-Za-z_$][\w$]*)(?:\s*,\s*([A-Za-z_$][\w$]*))?\s*\)|([A-Za-z_$][\w$]*))\s*=>\s*([\s\S]*)$/.exec(value);
17
+ if (!match) return undefined;
18
+ const bodyExpressionText = normalizedReturnExpression(match[4]);
19
+ if (bodyExpressionText.startsWith('{')) return undefined;
20
+ return {
21
+ callbackText: value,
22
+ parameterName: match[1] ?? match[3],
23
+ indexParameterName: match[2],
24
+ bodyExpressionText
25
+ };
26
+ }
27
+
28
+ function constArrayLiteralBinding(sourceText, arrayName) {
29
+ const value = String(sourceText ?? '');
30
+ const declaration = new RegExp(`\\bconst\\s+${escapeRegExp(arrayName)}\\s*=\\s*\\[`, 'g').exec(value);
31
+ if (!declaration) return undefined;
32
+ const arrayStart = value.indexOf('[', declaration.index);
33
+ const arrayEnd = matchingClose(value, arrayStart, '[', ']');
34
+ if (arrayEnd < 0) return undefined;
35
+ return { arrayLiteralText: normalizedText(value.slice(arrayStart, arrayEnd + 1)) };
36
+ }
37
+
38
+ function staticMapSourceItemRecord(sourceItemExpressionText) {
39
+ const literal = staticLiteralValue(sourceItemExpressionText);
40
+ if (literal) return { kind: literal.kind, props: new Map() };
41
+ const props = staticObjectLiteralProps(sourceItemExpressionText);
42
+ return props ? { kind: 'object-literal', props } : undefined;
43
+ }
44
+
45
+ function staticObjectLiteralProps(sourceItemExpressionText) {
46
+ const value = normalizedReturnExpression(sourceItemExpressionText);
47
+ if (!value.startsWith('{') || !value.endsWith('}')) return undefined;
48
+ const parts = splitTopLevel(value.slice(1, -1), ',').filter((part) => normalizedText(part));
49
+ if (!parts.length) return undefined;
50
+ const props = new Map();
51
+ for (const part of parts) {
52
+ const match = /^\s*([A-Za-z_$][\w$]*)\s*:\s*([\s\S]*?)\s*$/.exec(part);
53
+ if (!match) return undefined;
54
+ const literal = staticLiteralValue(match[2]);
55
+ if (!literal) return undefined;
56
+ props.set(match[1], literal);
57
+ }
58
+ return props;
59
+ }
60
+
61
+ function staticLiteralValue(text) {
62
+ const value = normalizedText(text);
63
+ const string = /^"([^"]*)"|'([^']*)'$/.exec(value);
64
+ if (string) return { value: string[1] ?? string[2] ?? '', text: value, kind: 'string' };
65
+ if (/^-?\d+(?:\.\d+)?$/.test(value)) return { value: Number(value), text: value, kind: 'number' };
66
+ if (value === 'true' || value === 'false') return { value: value === 'true', text: value, kind: 'boolean' };
67
+ if (value === 'null') return { value: null, text: value, kind: 'null' };
68
+ return undefined;
69
+ }
70
+
71
+ function mapKeyResolution(keyEvidence, parameterName, sourceItemProps) {
72
+ if (!keyEvidence) return undefined;
73
+ if (keyEvidence.keyValue !== undefined) return { keyValue: keyEvidence.keyValue, keyStatic: true };
74
+ const prefix = `${parameterName}.`;
75
+ if (!keyEvidence.keyExpressionText?.startsWith(prefix)) return { keyStatic: false };
76
+ const keySourcePropName = keyEvidence.keyExpressionText.slice(prefix.length);
77
+ if (!/^[A-Za-z_$][\w$]*$/.test(keySourcePropName)) return { keyStatic: false };
78
+ const prop = sourceItemProps.get(keySourcePropName);
79
+ return prop ? { keyValue: prop.value, keySourcePropName, keyStatic: true } : { keySourcePropName, keyStatic: false };
80
+ }
81
+
82
+ function jsxKeyEvidence(expressionText) {
83
+ const openingTag = firstJsxOpeningTagText(expressionText);
84
+ if (!openingTag) return undefined;
85
+ const match = /\bkey\s*=\s*("[^"]*"|'[^']*'|\{[^}]*\})/.exec(openingTag);
86
+ if (!match) return undefined;
87
+ const rawValue = match[1].trim();
88
+ const quoted = /^"([^"]*)"|'([^']*)'$/.exec(rawValue);
89
+ const braced = /^\{\s*([\s\S]*?)\s*\}$/.exec(rawValue);
90
+ return compactRecord({
91
+ keyPropText: normalizedText(match[0]),
92
+ keyValue: quoted ? quoted[1] ?? quoted[2] ?? '' : undefined,
93
+ keyExpressionText: braced ? normalizedText(braced[1]) : undefined
94
+ });
95
+ }
96
+
97
+ function firstJsxOpeningTagText(expressionText) {
98
+ const value = normalizedReturnExpression(expressionText);
99
+ const start = value.indexOf('<');
100
+ if (start < 0 || value[start + 1] === '/' || value[start + 1] === '>') return undefined;
101
+ let quote;
102
+ let braceDepth = 0;
103
+ for (let index = start + 1; index < value.length; index += 1) {
104
+ const char = value[index];
105
+ if (quote) {
106
+ if (char === '\\') index += 1;
107
+ else if (char === quote) quote = undefined;
108
+ continue;
109
+ }
110
+ if (char === '"' || char === "'" || char === '`') quote = char;
111
+ else if (char === '{') braceDepth += 1;
112
+ else if (char === '}') braceDepth = Math.max(0, braceDepth - 1);
113
+ else if (char === '>' && braceDepth === 0) return value.slice(start, index + 1);
114
+ }
115
+ return undefined;
116
+ }
117
+
118
+ function directJsxChildren(text) {
119
+ const value = normalizedText(text);
120
+ const children = [];
121
+ const childPattern = /<([A-Za-z][\w.]*)\b[^>]*\/>|<([A-Za-z][\w.]*)\b[^>]*>[\s\S]*?<\/\2>/g;
122
+ for (const match of value.matchAll(childPattern)) children.push(normalizedText(match[0]));
123
+ return children;
124
+ }
125
+
126
+ function isJsxExpression(text) {
127
+ const value = normalizedReturnExpression(text);
128
+ return /^<[A-Za-z][\w.]*(?:\s|>|\/>)/.test(value) || /^React\s*\.\s*createElement\s*\(/.test(value);
129
+ }
130
+
131
+ function splitTopLevel(text, delimiter) {
132
+ const value = String(text ?? '');
133
+ const parts = [];
134
+ let quote;
135
+ let depth = 0;
136
+ let start = 0;
137
+ for (let index = 0; index < value.length; index += 1) {
138
+ const char = value[index];
139
+ if (quote) {
140
+ if (char === '\\') index += 1;
141
+ else if (char === quote) quote = undefined;
142
+ continue;
143
+ }
144
+ if (char === '"' || char === "'" || char === '`') quote = char;
145
+ else if (char === '(' || char === '[' || char === '{' || char === '<') depth += 1;
146
+ else if (char === ')' || char === ']' || char === '}') depth = Math.max(0, depth - 1);
147
+ else if (char === '>' && depth > 0) depth = Math.max(0, depth - 1);
148
+ else if (depth === 0 && value.slice(index, index + delimiter.length) === delimiter) {
149
+ parts.push(value.slice(start, index));
150
+ start = index + delimiter.length;
151
+ index += delimiter.length - 1;
152
+ }
153
+ }
154
+ parts.push(value.slice(start));
155
+ return parts;
156
+ }
157
+
158
+ function matchingClose(text, openIndex, openChar, closeChar) {
159
+ const value = String(text ?? '');
160
+ let quote;
161
+ let depth = 0;
162
+ for (let index = openIndex; index < value.length; index += 1) {
163
+ const char = value[index];
164
+ if (quote) {
165
+ if (char === '\\') index += 1;
166
+ else if (char === quote) quote = undefined;
167
+ continue;
168
+ }
169
+ if (char === '"' || char === "'" || char === '`') quote = char;
170
+ else if (char === openChar) depth += 1;
171
+ else if (char === closeChar) {
172
+ depth -= 1;
173
+ if (depth === 0) return index;
174
+ }
175
+ }
176
+ return -1;
177
+ }
178
+
179
+ function escapeRegExp(text) { return String(text ?? '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
180
+ function normalizedText(text) { return String(text ?? '').trim().replace(/\s+/g, ' '); }
181
+ function normalizedReturnExpression(text) {
182
+ const value = normalizedText(text);
183
+ const wrapped = /^\(([\s\S]*)\)$/.exec(value);
184
+ return wrapped ? normalizedText(wrapped[1]) : value;
185
+ }
186
+ function compactRecord(record) { return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined)); }
187
+
188
+ export {
189
+ compactRecord,
190
+ constArrayLiteralBinding,
191
+ directJsxChildren,
192
+ isJsxExpression,
193
+ jsxKeyEvidence,
194
+ mapKeyResolution,
195
+ normalizedReturnExpression,
196
+ normalizedText,
197
+ splitTopLevel,
198
+ staticMapCall,
199
+ staticMapCallback,
200
+ staticMapSourceItemRecord
201
+ };
@@ -0,0 +1,210 @@
1
+ import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
2
+ import {
3
+ compactRecord,
4
+ constArrayLiteralBinding,
5
+ directJsxChildren,
6
+ isJsxExpression,
7
+ jsxKeyEvidence,
8
+ mapKeyResolution,
9
+ normalizedReturnExpression,
10
+ splitTopLevel,
11
+ staticMapCall,
12
+ staticMapCallback,
13
+ staticMapSourceItemRecord
14
+ } from './projectSymbolGraphJsxRenderReturnCollectionHelpers.js';
15
+
16
+ function jsxRenderReturnCollectionRecord(expressionText, sourceText) {
17
+ const value = normalizedReturnExpression(expressionText);
18
+ return arrayLiteralCollectionRecord(value)
19
+ ?? fragmentCollectionRecord(value)
20
+ ?? staticConstArrayMapCollectionRecord(value, sourceText);
21
+ }
22
+
23
+ function arrayLiteralCollectionRecord(expressionText) {
24
+ if (!expressionText.startsWith('[') || !expressionText.endsWith(']')) return undefined;
25
+ const itemExpressionTexts = splitTopLevel(expressionText.slice(1, -1), ',').map(normalizedReturnExpression).filter(Boolean);
26
+ if (!itemExpressionTexts.length || itemExpressionTexts.some((item) => !isJsxExpression(item))) return undefined;
27
+ return jsxCollectionRecord({
28
+ proofStatus: 'static-render-return-array-evidence',
29
+ reasonCode: 'jsx-render-return-array-static-evidence',
30
+ collectionKind: 'array-literal',
31
+ itemExpressionTexts,
32
+ itemRecords: collectionItemRecords('array-literal', itemExpressionTexts)
33
+ });
34
+ }
35
+
36
+ function fragmentCollectionRecord(expressionText) {
37
+ if (expressionText.startsWith('<>') && expressionText.endsWith('</>')) {
38
+ const itemExpressionTexts = directJsxChildren(expressionText.slice(2, -3));
39
+ if (!itemExpressionTexts.length) return undefined;
40
+ return jsxCollectionRecord({
41
+ proofStatus: 'static-render-return-fragment-evidence',
42
+ reasonCode: 'jsx-render-return-fragment-static-evidence',
43
+ collectionKind: 'fragment-shorthand',
44
+ itemExpressionTexts,
45
+ itemRecords: collectionItemRecords('fragment-shorthand', itemExpressionTexts)
46
+ });
47
+ }
48
+ const named = /^<((?:React\.)?Fragment)\b[^>]*>([\s\S]*)<\/\1>$/.exec(expressionText);
49
+ if (!named) return undefined;
50
+ const itemExpressionTexts = directJsxChildren(named[2]);
51
+ if (!itemExpressionTexts.length) return undefined;
52
+ const collectionKind = named[1] === 'React.Fragment' ? 'fragment-react' : 'fragment-named';
53
+ return jsxCollectionRecord({
54
+ proofStatus: 'static-render-return-fragment-evidence',
55
+ reasonCode: 'jsx-render-return-fragment-static-evidence',
56
+ collectionKind,
57
+ itemExpressionTexts,
58
+ itemRecords: collectionItemRecords(collectionKind, itemExpressionTexts)
59
+ });
60
+ }
61
+
62
+ function staticConstArrayMapCollectionRecord(expressionText, sourceText) {
63
+ const mapCall = staticMapCall(expressionText);
64
+ if (!mapCall) return undefined;
65
+ const arrayBinding = constArrayLiteralBinding(sourceText, mapCall.arrayName);
66
+ if (!arrayBinding) return undefined;
67
+ const callback = staticMapCallback(mapCall.callbackText);
68
+ if (!callback || !isJsxExpression(callback.bodyExpressionText)) return undefined;
69
+ const sourceItemExpressionTexts = splitTopLevel(arrayBinding.arrayLiteralText.slice(1, -1), ',').map(normalizedReturnExpression).filter(Boolean);
70
+ if (!sourceItemExpressionTexts.length) return undefined;
71
+ const sourceItemRecords = sourceItemExpressionTexts.map(staticMapSourceItemRecord);
72
+ if (sourceItemRecords.some((record) => !record)) return undefined;
73
+ const keyEvidence = jsxKeyEvidence(callback.bodyExpressionText);
74
+ const itemExpressionTexts = sourceItemExpressionTexts.map(() => callback.bodyExpressionText);
75
+ const itemRecords = sourceItemExpressionTexts.map((sourceItemExpressionText, index) => staticConstArrayMapItemRecord({
76
+ callback,
77
+ index,
78
+ keyEvidence,
79
+ sourceItem: sourceItemRecords[index],
80
+ sourceItemExpressionText
81
+ }));
82
+ return jsxCollectionRecord({
83
+ proofStatus: 'static-render-return-map-evidence',
84
+ reasonCode: 'jsx-render-return-static-const-array-map-evidence',
85
+ collectionKind: 'static-const-array-map',
86
+ claimScope: 'static-const-array-map-structure-only',
87
+ renderEquivalenceClaim: false,
88
+ runtimeEquivalenceClaim: false,
89
+ sourceArrayName: mapCall.arrayName,
90
+ sourceArrayItemCount: sourceItemExpressionTexts.length,
91
+ sourceItemExpressionTexts,
92
+ mapCallbackExpressionText: callback.callbackText,
93
+ mapParameterName: callback.parameterName,
94
+ mapIndexParameterName: callback.indexParameterName,
95
+ callbackExpressionText: callback.bodyExpressionText,
96
+ itemExpressionTexts,
97
+ itemRecords
98
+ });
99
+ }
100
+
101
+ function staticConstArrayMapItemRecord(input) {
102
+ const { callback, index, keyEvidence, sourceItem, sourceItemExpressionText } = input;
103
+ const keyResolution = mapKeyResolution(keyEvidence, callback.parameterName, sourceItem.props);
104
+ return compactRecord({
105
+ ordinal: index + 1,
106
+ proofStatus: 'static-render-return-map-item-evidence',
107
+ expressionText: callback.bodyExpressionText,
108
+ expressionHash: hashSemanticValue({ kind: 'frontier.lang.projectJsxRenderReturnMapItemExpression', text: callback.bodyExpressionText }),
109
+ sourceItemExpressionText,
110
+ sourceItemExpressionHash: hashSemanticValue({ kind: 'frontier.lang.projectJsxRenderReturnMapSourceItem', text: sourceItemExpressionText }),
111
+ sourceItemKind: sourceItem.kind,
112
+ keyPropText: keyEvidence?.keyPropText,
113
+ keyExpressionText: keyEvidence?.keyExpressionText,
114
+ keyValue: keyResolution?.keyValue,
115
+ keySourcePropName: keyResolution?.keySourcePropName,
116
+ keyStatic: keyResolution?.keyStatic,
117
+ signatureHash: hashSemanticValue({
118
+ kind: 'frontier.lang.projectJsxRenderReturnMapItem',
119
+ ordinal: index + 1,
120
+ expressionText: callback.bodyExpressionText,
121
+ sourceItemExpressionText,
122
+ sourceItemKind: sourceItem.kind,
123
+ keyPropText: keyEvidence?.keyPropText,
124
+ keyExpressionText: keyEvidence?.keyExpressionText,
125
+ keyValue: keyResolution?.keyValue,
126
+ keySourcePropName: keyResolution?.keySourcePropName
127
+ })
128
+ });
129
+ }
130
+
131
+ function jsxCollectionRecord(record) {
132
+ const itemRecords = record.itemRecords ?? [];
133
+ const keyedListRecord = keyedListRecordFor(record.collectionKind, itemRecords);
134
+ return compactRecord({
135
+ ...record,
136
+ itemCount: itemRecords.length,
137
+ keyedListRecord,
138
+ signatureHash: hashSemanticValue({
139
+ kind: 'frontier.lang.projectJsxRenderReturnCollection',
140
+ proofStatus: record.proofStatus,
141
+ collectionKind: record.collectionKind,
142
+ sourceArrayName: record.sourceArrayName,
143
+ sourceItemExpressionTexts: record.sourceItemExpressionTexts,
144
+ mapCallbackExpressionText: record.mapCallbackExpressionText,
145
+ itemExpressionTexts: record.itemExpressionTexts,
146
+ itemRecords,
147
+ keyedListSignatureHash: keyedListRecord?.signatureHash,
148
+ claimScope: record.claimScope,
149
+ renderEquivalenceClaim: record.renderEquivalenceClaim,
150
+ runtimeEquivalenceClaim: record.runtimeEquivalenceClaim
151
+ })
152
+ });
153
+ }
154
+
155
+ function collectionItemRecords(collectionKind, itemExpressionTexts) {
156
+ return itemExpressionTexts.map((itemExpressionText, index) => {
157
+ const key = jsxKeyEvidence(itemExpressionText);
158
+ return compactRecord({
159
+ ordinal: index + 1,
160
+ proofStatus: 'static-render-return-collection-item-evidence',
161
+ expressionText: itemExpressionText,
162
+ expressionHash: hashSemanticValue({ kind: 'frontier.lang.projectJsxRenderReturnCollectionItemExpression', text: itemExpressionText }),
163
+ keyPropText: key?.keyPropText,
164
+ keyExpressionText: key?.keyExpressionText,
165
+ keyValue: key?.keyValue,
166
+ keyStatic: key ? key.keyValue !== undefined : undefined,
167
+ signatureHash: hashSemanticValue({
168
+ kind: 'frontier.lang.projectJsxRenderReturnCollectionItem',
169
+ collectionKind,
170
+ ordinal: index + 1,
171
+ expressionText: itemExpressionText,
172
+ keyPropText: key?.keyPropText,
173
+ keyExpressionText: key?.keyExpressionText,
174
+ keyValue: key?.keyValue
175
+ })
176
+ });
177
+ });
178
+ }
179
+
180
+ function keyedListRecordFor(collectionKind, itemRecords) {
181
+ if (!itemRecords.length || itemRecords.some((record) => record.keyStatic === false || (!record.keyPropText && !record.keyExpressionText && record.keyValue === undefined))) return undefined;
182
+ const keyRecords = itemRecords.map((record) => compactRecord({
183
+ ordinal: record.ordinal,
184
+ keyPropText: record.keyPropText,
185
+ keyExpressionText: record.keyExpressionText,
186
+ keyValue: record.keyValue,
187
+ keySourcePropName: record.keySourcePropName,
188
+ keyStatic: record.keyStatic
189
+ }));
190
+ return compactRecord({
191
+ proofStatus: 'static-render-return-keyed-list-evidence',
192
+ reasonCode: 'jsx-render-return-keyed-list-static-evidence',
193
+ claimScope: 'static-list-key-identity-only',
194
+ renderEquivalenceClaim: false,
195
+ runtimeEquivalenceClaim: false,
196
+ keyCount: keyRecords.length,
197
+ keyRecords,
198
+ keyValues: keyRecords.every((record) => record.keyValue !== undefined) ? keyRecords.map((record) => record.keyValue) : undefined,
199
+ signatureHash: hashSemanticValue({
200
+ kind: 'frontier.lang.projectJsxRenderReturnKeyedList',
201
+ collectionKind,
202
+ keyRecords,
203
+ claimScope: 'static-list-key-identity-only',
204
+ renderEquivalenceClaim: false,
205
+ runtimeEquivalenceClaim: false
206
+ })
207
+ });
208
+ }
209
+
210
+ export { jsxRenderReturnCollectionRecord };
@@ -1,12 +1,16 @@
1
1
  import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
2
- import { jsxRenderReturnCollectionRecord } from './projectSymbolGraphJsxRenderCollections.js';
2
+ import { jsxRenderReturnCollectionRecord } from './projectSymbolGraphJsxRenderReturnCollections.js';
3
3
 
4
4
  function jsxRenderReturnRecords(sourceText) {
5
5
  const statements = returnStatements(sourceText);
6
6
  const implicitArrows = statements.length ? [] : implicitArrowReturnStatements(sourceText);
7
7
  return [...statements, ...implicitArrows]
8
- .filter((statement) => isRenderableReturnExpression(statement.expressionText))
9
- .map((statement, index) => renderReturnRecord(statement, index));
8
+ .map((statement) => ({
9
+ statement,
10
+ collectionRecord: jsxRenderReturnCollectionRecord(statement.expressionText, sourceText)
11
+ }))
12
+ .filter(({ statement, collectionRecord }) => collectionRecord || isRenderableReturnExpression(statement.expressionText))
13
+ .map(({ statement, collectionRecord }, index) => renderReturnRecord(statement, index, collectionRecord));
10
14
  }
11
15
 
12
16
  function jsxRenderReturnRiskEvidence(owner) {
@@ -18,6 +22,8 @@ function jsxRenderReturnRiskEvidence(owner) {
18
22
  const hasLogicalBranchEvidence = records.some((record) => record.logicalBranchRecord);
19
23
  const hasArrayCollectionEvidence = records.some((record) => record.collectionRecord?.collectionKind === 'array-literal');
20
24
  const hasFragmentCollectionEvidence = records.some((record) => String(record.collectionRecord?.collectionKind ?? '').startsWith('fragment-'));
25
+ const hasMapCollectionEvidence = records.some((record) => record.collectionRecord?.collectionKind === 'static-const-array-map');
26
+ const hasKeyedListEvidence = records.some((record) => record.collectionRecord?.keyedListRecord);
21
27
  const renderRiskKinds = ['render-return-boundary', branched ? 'render-return-branch-control-flow' : undefined].filter(Boolean);
22
28
  const hasImplicitArrow = records.some((record) => record.returnKind === 'implicit-arrow-expression');
23
29
  const renderRiskReasonCodes = [
@@ -27,6 +33,8 @@ function jsxRenderReturnRiskEvidence(owner) {
27
33
  hasLogicalBranchEvidence ? 'jsx-render-return-logical-branch-static-evidence' : undefined,
28
34
  hasArrayCollectionEvidence ? 'jsx-render-return-array-static-evidence' : undefined,
29
35
  hasFragmentCollectionEvidence ? 'jsx-render-return-fragment-static-evidence' : undefined,
36
+ hasMapCollectionEvidence ? 'jsx-render-return-static-const-array-map-evidence' : undefined,
37
+ hasKeyedListEvidence ? 'jsx-render-return-keyed-list-static-evidence' : undefined,
30
38
  branched ? 'jsx-render-return-branch-unsupported' : undefined
31
39
  ].filter(Boolean);
32
40
  const record = compactRecord({
@@ -80,12 +88,11 @@ function implicitArrowReturnStatements(sourceText) {
80
88
  return statements;
81
89
  }
82
90
 
83
- function renderReturnRecord(statement, index) {
91
+ function renderReturnRecord(statement, index, collectionRecord) {
84
92
  const expressionText = normalizedText(statement.expressionText);
85
93
  const ifConditionText = normalizedText(statement.ifConditionText);
86
94
  const conditionalBranch = conditionalBranchRecord(expressionText);
87
95
  const logicalBranch = logicalBranchRecord(expressionText);
88
- const collectionRecord = jsxRenderReturnCollectionRecord(expressionText);
89
96
  return compactRecord({
90
97
  ordinal: index + 1,
91
98
  proofStatus: 'static-render-return-evidence',