@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.
- package/dist/internal/index-impl/moduleHostResourceImportMetadata.js +47 -0
- package/dist/internal/index-impl/projectSymbolGraphCompilerAdvancedTypeMetadata.js +215 -1
- package/dist/internal/index-impl/projectSymbolGraphCompilerFacts.js +1 -1
- package/dist/internal/index-impl/projectSymbolGraphCssModuleUtils.js +56 -1
- package/dist/internal/index-impl/projectSymbolGraphCssModules.js +48 -4
- package/dist/internal/index-impl/projectSymbolGraphJsxPropRecordFields.js +91 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxPropValues.js +35 -7
- package/dist/internal/index-impl/projectSymbolGraphJsxRecords.js +4 -31
- package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturnCollectionHelpers.js +201 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturnCollections.js +210 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxRenderReturns.js +12 -5
- package/dist/internal/index-impl/projectSymbolGraphJsxSpreadPropValues.js +196 -0
- package/dist/internal/index-impl/projectSymbolGraphJsxStaticLiterals.js +207 -0
- package/dist/internal/index-impl/projectSymbolGraphModuleResolution.js +12 -14
- package/dist/internal/index-impl/projectSymbolGraphPackageConditions.js +33 -31
- package/dist/internal/index-impl/projectSymbolGraphPackageRuntimeConditions.js +22 -0
- package/dist/internal/index-impl/projectSymbolGraphScopeUseDefLexical.js +11 -19
- package/dist/internal/index-impl/syntaxModuleDeclarationEntries.js +27 -1
- package/dist/js-ts-safe-project-merge-admission.js +10 -0
- package/dist/js-ts-safe-project-merge-evidence-routing.js +30 -2
- package/dist/js-ts-safe-project-merge-graph-delta-compiler-conflicts.js +7 -0
- package/dist/js-ts-safe-project-merge-html-css-matrix.js +7 -2
- package/dist/js-ts-safe-project-merge-html-css-summary.js +110 -2
- package/dist/js-ts-safe-project-merge-html-css.js +137 -3
- package/dist/js-ts-safe-project-merge-jsx-graph-conflict-details.js +9 -0
- package/dist/js-ts-safe-project-merge.js +3 -0
- package/dist/native-source-preservation-scanner.js +10 -0
- package/dist/semantic-import-runtime-dynamic-import-evidence.js +141 -0
- package/dist/semantic-import-runtime-order-evidence.js +5 -4
- 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
|
-
|
|
126
|
-
|
|
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 './
|
|
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
|
-
.
|
|
9
|
-
|
|
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',
|