styled-components-to-stylex-codemod 0.0.53 → 0.0.55
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/{ast-walk-BOXS-DT7.mjs → ast-walk-C226poBl.mjs} +20 -3
- package/dist/{compute-leaf-set-ghdXvfbp.mjs → compute-leaf-set-Cu4lMMQ9.mjs} +1 -4
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +4 -7
- package/dist/{prop-usage-SADzZJdX.mjs → prop-usage-Bs2F3Wke.mjs} +1 -1
- package/dist/{run-prepass-BjTbmT-5.mjs → run-prepass-D3Ti1ryc.mjs} +4 -4
- package/dist/sx-surface-Cth8EesU.mjs +1280 -0
- package/dist/{transform-types-DVH8jgA2.d.mts → transform-types-BGGNjb8R.d.mts} +1 -1
- package/dist/transform.d.mts +1 -1
- package/dist/transform.mjs +31466 -30406
- package/dist/{typescript-analysis-CmIDxfLv.mjs → typescript-analysis-BLyx4wAJ.mjs} +475 -467
- package/package.json +1 -1
- package/dist/sx-surface-CEPFSTO1.mjs +0 -498
|
@@ -1,222 +1,84 @@
|
|
|
1
1
|
import { n as resolveExistingFilePath } from "./path-utils-BC4U8X_q.mjs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import ts from "typescript";
|
|
4
|
-
//#region src/internal/prepass/
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
version: 1,
|
|
9
|
-
files: []
|
|
10
|
-
};
|
|
11
|
-
const program = createProgram(rootNames, options.cwd ?? process.cwd());
|
|
12
|
-
const checker = program.getTypeChecker();
|
|
13
|
-
const rootNameSet = new Set(rootNames.map((filePath) => path.resolve(filePath)));
|
|
14
|
-
const compilerOptions = program.getCompilerOptions();
|
|
15
|
-
strictNullChecksOnForCurrentRun = Boolean(compilerOptions.strictNullChecks ?? compilerOptions.strict);
|
|
16
|
-
return {
|
|
17
|
-
version: 1,
|
|
18
|
-
files: program.getSourceFiles().filter((sourceFile) => rootNameSet.has(path.resolve(sourceFile.fileName))).map((sourceFile) => analyzeSourceFile(sourceFile, checker)).filter((file) => file.components.length > 0 || file.functions.length > 0).sort((a, b) => a.filePath.localeCompare(b.filePath))
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
function analyzeSourceFile(sourceFile, checker) {
|
|
22
|
-
const exportedNames = getExportedNames(sourceFile, checker);
|
|
23
|
-
const defaultExportedLocalNames = getDefaultExportedLocalNames(sourceFile);
|
|
24
|
-
const localFunctionInitializers = collectLocalFunctionInitializers(sourceFile);
|
|
25
|
-
const components = [];
|
|
26
|
-
const functions = [];
|
|
27
|
-
const visit = (node) => {
|
|
28
|
-
if (ts.isFunctionDeclaration(node) && (node.name || isDefaultExport(node))) {
|
|
29
|
-
const fn = readFunctionDeclaration(node, checker, exportedNames);
|
|
30
|
-
functions.push(fn);
|
|
31
|
-
if (isReactComponentFunction(node, checker)) components.push(readReactComponentFromFunction(node, checker, exportedNames, defaultExportedLocalNames));
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (ts.isVariableStatement(node)) {
|
|
35
|
-
for (const declaration of node.declarationList.declarations) {
|
|
36
|
-
if (!ts.isIdentifier(declaration.name)) continue;
|
|
37
|
-
if (declaration.initializer && isStyledComponentInitializer(declaration.initializer)) {
|
|
38
|
-
components.push(readStyledComponent(declaration, node, checker, exportedNames));
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
const componentInitializer = declaration.initializer ? getComponentFunctionInitializerInfo(declaration.initializer, localFunctionInitializers) : void 0;
|
|
42
|
-
if (componentInitializer) {
|
|
43
|
-
functions.push(readVariableFunction(declaration.name.text, componentInitializer.fn, node, checker));
|
|
44
|
-
if (isReactComponentName(declaration.name.text) || returnsJsx(componentInitializer.fn)) components.push(readReactComponentFromVariable(declaration.name.text, componentInitializer.fn, componentInitializer.propTypeNode, node, checker, exportedNames, defaultExportedLocalNames));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
ts.forEachChild(node, visit);
|
|
50
|
-
};
|
|
51
|
-
ts.forEachChild(sourceFile, visit);
|
|
52
|
-
return {
|
|
53
|
-
filePath: normalizeFilePath(sourceFile.fileName),
|
|
54
|
-
components: components.sort(byName),
|
|
55
|
-
functions: functions.sort(byName)
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function readFunctionDeclaration(node, checker, exportedNames) {
|
|
59
|
-
const name = node.name?.text ?? "default";
|
|
60
|
-
return {
|
|
61
|
-
name,
|
|
62
|
-
exported: exportedNames.has(name),
|
|
63
|
-
defaultExport: isDefaultExport(node),
|
|
64
|
-
typeParameters: readTypeParameters(node.typeParameters),
|
|
65
|
-
parameters: readParameters(node.parameters, checker)
|
|
66
|
-
};
|
|
4
|
+
//#region src/internal/prepass/ts-ast-shared.ts
|
|
5
|
+
function resolveAliasedSymbol(symbol, checker) {
|
|
6
|
+
if (!symbol || (symbol.flags & ts.SymbolFlags.Alias) === 0) return symbol;
|
|
7
|
+
return checker.getAliasedSymbol(symbol);
|
|
67
8
|
}
|
|
68
|
-
function
|
|
9
|
+
function readUtilityTypeReference(typeNode) {
|
|
69
10
|
return {
|
|
70
|
-
name,
|
|
71
|
-
|
|
72
|
-
defaultExport: false,
|
|
73
|
-
typeParameters: readTypeParameters(node.typeParameters),
|
|
74
|
-
parameters: readParameters(node.parameters, checker)
|
|
11
|
+
name: typeNode.typeName.getText(),
|
|
12
|
+
typeArgs: typeNode.typeArguments ?? []
|
|
75
13
|
};
|
|
76
14
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
const typeNode = declaration.initializer ? findStyledPropsTypeNode(declaration.initializer) : void 0;
|
|
80
|
-
return buildComponentMetadata({
|
|
81
|
-
name,
|
|
82
|
-
kind: "styled",
|
|
83
|
-
exported: exportedNames.has(name) || isExported(statement),
|
|
84
|
-
defaultExport: false,
|
|
85
|
-
typeParameters: [],
|
|
86
|
-
propTypeNode: typeNode,
|
|
87
|
-
parameters: [],
|
|
88
|
-
restProps: [],
|
|
89
|
-
checker,
|
|
90
|
-
location: declaration
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
function readReactComponentFromFunction(node, checker, exportedNames, defaultExportedLocalNames) {
|
|
94
|
-
const name = node.name?.text ?? "default";
|
|
95
|
-
return buildComponentMetadata({
|
|
96
|
-
name,
|
|
97
|
-
kind: "react",
|
|
98
|
-
exported: exportedNames.has(name),
|
|
99
|
-
defaultExport: isDefaultExport(node) || defaultExportedLocalNames.has(name),
|
|
100
|
-
typeParameters: readTypeParameters(node.typeParameters),
|
|
101
|
-
propTypeNode: node.parameters[0]?.type,
|
|
102
|
-
parameters: readParameters(node.parameters, checker),
|
|
103
|
-
restProps: readRestProps(node.parameters[0], node.body),
|
|
104
|
-
bodySupportsSxProp: readsSxProp(node.parameters[0], node.body),
|
|
105
|
-
bodySxTarget: detectSxTarget(node.parameters[0], node.body),
|
|
106
|
-
checker,
|
|
107
|
-
location: node
|
|
108
|
-
});
|
|
15
|
+
function isTransparentUtilityTypeName(typeName) {
|
|
16
|
+
return typeName === "Partial" || typeName === "Required" || typeName === "Readonly";
|
|
109
17
|
}
|
|
110
|
-
function
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
defaultExport: defaultExportedLocalNames.has(name),
|
|
116
|
-
typeParameters: readTypeParameters(node.typeParameters),
|
|
117
|
-
propTypeNode: propTypeNode ?? node.parameters[0]?.type,
|
|
118
|
-
parameters: readParameters(node.parameters, checker),
|
|
119
|
-
restProps: readRestProps(node.parameters[0], node.body),
|
|
120
|
-
bodySupportsSxProp: readsSxProp(node.parameters[0], node.body),
|
|
121
|
-
bodySxTarget: detectSxTarget(node.parameters[0], node.body),
|
|
122
|
-
checker,
|
|
123
|
-
location: node
|
|
124
|
-
});
|
|
18
|
+
function typeNodeKeyIncludes(typeNode, key) {
|
|
19
|
+
if (!typeNode) return false;
|
|
20
|
+
if (ts.isLiteralTypeNode(typeNode) && ts.isStringLiteral(typeNode.literal)) return typeNode.literal.text === key;
|
|
21
|
+
if (ts.isUnionTypeNode(typeNode)) return typeNode.types.some((part) => typeNodeKeyIncludes(part, key));
|
|
22
|
+
return false;
|
|
125
23
|
}
|
|
126
|
-
function
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
const explicitPropNames = args.propTypeNode ? collectExplicitPropNames(args.propTypeNode, args.checker) : [];
|
|
130
|
-
const supportsResolvedSxProp = props.some((prop) => prop.name === "sx") && args.propTypeNode !== void 0 && typeNodeHasResolvableSxSurface(args.propTypeNode, args.checker, /* @__PURE__ */ new Set());
|
|
131
|
-
const sxExcludedProperties = args.propTypeNode !== void 0 ? collectSxExcludedProperties(args.propTypeNode, args.checker, /* @__PURE__ */ new Set()) : [];
|
|
132
|
-
const sxAllowedProperties = args.propTypeNode !== void 0 ? collectSxAllowedProperties(args.propTypeNode, args.checker, /* @__PURE__ */ new Set()) : void 0;
|
|
133
|
-
return {
|
|
134
|
-
name: args.name,
|
|
135
|
-
kind: args.kind,
|
|
136
|
-
exported: args.exported,
|
|
137
|
-
defaultExport: args.defaultExport,
|
|
138
|
-
typeParameters: args.typeParameters,
|
|
139
|
-
propType: args.propTypeNode ? describeTypeNode(args.propTypeNode, args.checker) : null,
|
|
140
|
-
props,
|
|
141
|
-
explicitPropNames,
|
|
142
|
-
parameters: args.parameters,
|
|
143
|
-
restProps: args.restProps,
|
|
144
|
-
hasIndexSignature: propType ? hasIndexSignature(propType, args.checker) : false,
|
|
145
|
-
supportsSxProp: explicitPropNames.includes("sx") || supportsResolvedSxProp || args.bodySupportsSxProp === true,
|
|
146
|
-
...args.bodySxTarget ? { sxTarget: args.bodySxTarget } : {},
|
|
147
|
-
sxExcludedProperties,
|
|
148
|
-
...sxAllowedProperties !== void 0 ? { sxAllowedProperties } : {}
|
|
149
|
-
};
|
|
24
|
+
function isIntrinsicReactPropReference(typeNode) {
|
|
25
|
+
const typeName = typeNode.typeName.getText();
|
|
26
|
+
return /^(?:React\.)?(?:ComponentProps|ComponentPropsWithRef|ComponentPropsWithoutRef|HTMLAttributes|ButtonHTMLAttributes|AnchorHTMLAttributes|InputHTMLAttributes|SVGProps)$/.test(typeName);
|
|
150
27
|
}
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const optional = (symbol.flags & ts.SymbolFlags.Optional) !== 0;
|
|
155
|
-
return {
|
|
156
|
-
name: symbol.getName(),
|
|
157
|
-
optional,
|
|
158
|
-
readonly: isReadonlyProperty(symbol),
|
|
159
|
-
type: withOptionalUndefined(readPropTypeString(symbol, declaration, checker, location), optional)
|
|
160
|
-
};
|
|
161
|
-
}).sort(byName);
|
|
28
|
+
function isIntrinsicReactHeritageReference(heritageType) {
|
|
29
|
+
const typeName = heritageType.expression.getText();
|
|
30
|
+
return /^(?:React\.)?(?:ComponentProps|ComponentPropsWithRef|ComponentPropsWithoutRef|HTMLAttributes|ButtonHTMLAttributes|AnchorHTMLAttributes|InputHTMLAttributes|SVGProps)$/.test(typeName);
|
|
162
31
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
* `type === number`, not `number | undefined`. Downstream consumers
|
|
167
|
-
* (lower-rules/types.ts) rely on the `| undefined` suffix to gate certain
|
|
168
|
-
* emit decisions (e.g. wrapping a possibly-undefined value in a template
|
|
169
|
-
* string). Reconstruct it here so the syntactic fast path stays
|
|
170
|
-
* behaviorally equivalent to the typeToString path it replaced.
|
|
171
|
-
*/
|
|
172
|
-
function withOptionalUndefined(typeText, optional) {
|
|
173
|
-
if (!optional || !strictNullChecksOnForCurrentRun) return typeText;
|
|
174
|
-
if (/\bundefined\b/.test(typeText)) return typeText;
|
|
175
|
-
return `${typeText} | undefined`;
|
|
32
|
+
function propertyNameText(name) {
|
|
33
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
|
|
34
|
+
return null;
|
|
176
35
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
* any per-file work runs; read by `withOptionalUndefined` to decide whether to
|
|
180
|
-
* append `| undefined` to optional props. Module-scoped to avoid threading the
|
|
181
|
-
* boolean through ~6 helper signatures for a single read site.
|
|
182
|
-
*/
|
|
183
|
-
let strictNullChecksOnForCurrentRun = false;
|
|
184
|
-
/**
|
|
185
|
-
* Returns the prop's TS type as a string. Prefers the syntactic type annotation
|
|
186
|
-
* from the declaration AST (cheap, no checker call) and only falls back to
|
|
187
|
-
* `checker.typeToString` when the declaration has no usable type node — typically
|
|
188
|
-
* synthesized properties (mapped/intersection/spread-derived) where the checker
|
|
189
|
-
* is the only source of truth.
|
|
190
|
-
*
|
|
191
|
-
* Why: typeToString with NoTruncation dominated the prepass at 39s / 723K calls.
|
|
192
|
-
* For the consumers downstream (lower-rules/types.ts parseTypeText), the
|
|
193
|
-
* syntactic representation is what they want anyway — they only handle
|
|
194
|
-
* TSTypeReference / TSUnionType / TSLiteralType shapes.
|
|
195
|
-
*/
|
|
196
|
-
function readPropTypeString(symbol, declaration, _checker, _location) {
|
|
197
|
-
const typeNode = getDeclarationTypeNode(declaration);
|
|
198
|
-
if (typeNode) return typeNode.getText();
|
|
199
|
-
return "";
|
|
36
|
+
function bindingPatternHasName(pattern, name) {
|
|
37
|
+
return pattern.elements.some((element) => element.name.getText() === name);
|
|
200
38
|
}
|
|
201
|
-
function
|
|
202
|
-
if (
|
|
39
|
+
function bindingElementPropertyNameText(element) {
|
|
40
|
+
if (element.propertyName) return ts.isIdentifier(element.propertyName) || ts.isStringLiteral(element.propertyName) ? element.propertyName.text : null;
|
|
41
|
+
return ts.isIdentifier(element.name) ? element.name.text : null;
|
|
203
42
|
}
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
rest: Boolean(parameter.dotDotDotToken),
|
|
209
|
-
type: parameter.type ? parameter.type.getText() : checker.typeToString(checker.getTypeAtLocation(parameter), parameter)
|
|
210
|
-
}));
|
|
43
|
+
function unwrapExpression(expression) {
|
|
44
|
+
let current = expression;
|
|
45
|
+
while (ts.isAsExpression(current) || ts.isTypeAssertionExpression(current) || ts.isSatisfiesExpression(current) || ts.isParenthesizedExpression(current)) current = current.expression;
|
|
46
|
+
return current;
|
|
211
47
|
}
|
|
212
|
-
function
|
|
213
|
-
return
|
|
48
|
+
function isIdentifierNamed(expression, name) {
|
|
49
|
+
return ts.isIdentifier(expression) && expression.text === name;
|
|
214
50
|
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/internal/prepass/prop-name-collection.ts
|
|
215
53
|
function collectExplicitPropNames(typeNode, checker, visited = /* @__PURE__ */ new Set()) {
|
|
216
54
|
const names = /* @__PURE__ */ new Set();
|
|
217
55
|
collectExplicitPropNamesInto(names, typeNode, checker, visited);
|
|
218
56
|
return [...names].sort();
|
|
219
57
|
}
|
|
58
|
+
function typeNodeHasResolvableSxSurface(typeNode, checker, visited) {
|
|
59
|
+
if (ts.isTypeLiteralNode(typeNode)) return typeNode.members.some((member) => ts.isPropertySignature(member) && propertyNameText(member.name) === "sx");
|
|
60
|
+
if (ts.isIntersectionTypeNode(typeNode)) return typeNode.types.some((part) => typeNodeHasResolvableSxSurface(part, checker, visited));
|
|
61
|
+
if (ts.isUnionTypeNode(typeNode)) return typeNode.types.every((part) => typeNodeHasResolvableSxSurface(part, checker, visited));
|
|
62
|
+
if (!ts.isTypeReferenceNode(typeNode) || isIntrinsicReactPropReference(typeNode)) return false;
|
|
63
|
+
const utilityType = readUtilityTypeReference(typeNode);
|
|
64
|
+
if (utilityType.name === "Pick") return utilityType.typeArgs.length >= 2 && typeNodeKeyIncludes(utilityType.typeArgs[1], "sx");
|
|
65
|
+
if (utilityType.name === "Omit") {
|
|
66
|
+
const baseType = utilityType.typeArgs[0];
|
|
67
|
+
return baseType !== void 0 && utilityType.typeArgs.length >= 2 && !typeNodeKeyIncludes(utilityType.typeArgs[1], "sx") && typeNodeHasResolvableSxSurface(baseType, checker, visited);
|
|
68
|
+
}
|
|
69
|
+
if (isTransparentUtilityTypeName(utilityType.name)) {
|
|
70
|
+
const baseType = utilityType.typeArgs[0];
|
|
71
|
+
return baseType !== void 0 && typeNodeHasResolvableSxSurface(baseType, checker, visited);
|
|
72
|
+
}
|
|
73
|
+
return (resolveAliasedSymbol(checker.getSymbolAtLocation(typeNode.typeName), checker)?.declarations ?? []).some((declaration) => declarationHasResolvableSxSurface(declaration, checker, visited));
|
|
74
|
+
}
|
|
75
|
+
function collectSxExcludedProperties(typeNode, checker, visited) {
|
|
76
|
+
return collectSxSurfaceProperties(typeNode, checker, visited, collectStyleXStylesWithoutKeys).properties;
|
|
77
|
+
}
|
|
78
|
+
function collectSxAllowedProperties(typeNode, checker, visited) {
|
|
79
|
+
const collection = collectSxSurfaceProperties(typeNode, checker, visited, collectStyleXStylesKeys);
|
|
80
|
+
return collection.found ? collection.properties : void 0;
|
|
81
|
+
}
|
|
220
82
|
function collectExplicitPropNamesInto(names, typeNode, checker, visited) {
|
|
221
83
|
if (ts.isTypeLiteralNode(typeNode)) {
|
|
222
84
|
for (const member of typeNode.members) if (ts.isPropertySignature(member)) {
|
|
@@ -265,39 +127,6 @@ function collectExplicitPropNamesInto(names, typeNode, checker, visited) {
|
|
|
265
127
|
const symbol = resolveAliasedSymbol(checker.getSymbolAtLocation(typeNode.typeName), checker);
|
|
266
128
|
for (const declaration of symbol?.declarations ?? []) collectExplicitPropNamesFromDeclaration(names, declaration, checker, visited);
|
|
267
129
|
}
|
|
268
|
-
function typeNodeHasResolvableSxSurface(typeNode, checker, visited) {
|
|
269
|
-
if (ts.isTypeLiteralNode(typeNode)) return typeNode.members.some((member) => ts.isPropertySignature(member) && propertyNameText(member.name) === "sx");
|
|
270
|
-
if (ts.isIntersectionTypeNode(typeNode)) return typeNode.types.some((part) => typeNodeHasResolvableSxSurface(part, checker, visited));
|
|
271
|
-
if (ts.isUnionTypeNode(typeNode)) return typeNode.types.every((part) => typeNodeHasResolvableSxSurface(part, checker, visited));
|
|
272
|
-
if (!ts.isTypeReferenceNode(typeNode) || isIntrinsicReactPropReference(typeNode)) return false;
|
|
273
|
-
const utilityType = readUtilityTypeReference(typeNode);
|
|
274
|
-
if (utilityType.name === "Pick") return utilityType.typeArgs.length >= 2 && typeNodeKeyIncludes(utilityType.typeArgs[1], "sx");
|
|
275
|
-
if (utilityType.name === "Omit") {
|
|
276
|
-
const baseType = utilityType.typeArgs[0];
|
|
277
|
-
return baseType !== void 0 && utilityType.typeArgs.length >= 2 && !typeNodeKeyIncludes(utilityType.typeArgs[1], "sx") && typeNodeHasResolvableSxSurface(baseType, checker, visited);
|
|
278
|
-
}
|
|
279
|
-
if (isTransparentUtilityTypeName(utilityType.name)) {
|
|
280
|
-
const baseType = utilityType.typeArgs[0];
|
|
281
|
-
return baseType !== void 0 && typeNodeHasResolvableSxSurface(baseType, checker, visited);
|
|
282
|
-
}
|
|
283
|
-
return (resolveAliasedSymbol(checker.getSymbolAtLocation(typeNode.typeName), checker)?.declarations ?? []).some((declaration) => declarationHasResolvableSxSurface(declaration, checker, visited));
|
|
284
|
-
}
|
|
285
|
-
function readUtilityTypeReference(typeNode) {
|
|
286
|
-
return {
|
|
287
|
-
name: typeNode.typeName.getText(),
|
|
288
|
-
typeArgs: typeNode.typeArguments ?? []
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
function isTransparentUtilityTypeName(typeName) {
|
|
292
|
-
return typeName === "Partial" || typeName === "Required" || typeName === "Readonly";
|
|
293
|
-
}
|
|
294
|
-
function collectSxExcludedProperties(typeNode, checker, visited) {
|
|
295
|
-
return collectSxSurfaceProperties(typeNode, checker, visited, collectStyleXStylesWithoutKeys).properties;
|
|
296
|
-
}
|
|
297
|
-
function collectSxAllowedProperties(typeNode, checker, visited) {
|
|
298
|
-
const collection = collectSxSurfaceProperties(typeNode, checker, visited, collectStyleXStylesKeys);
|
|
299
|
-
return collection.found ? collection.properties : void 0;
|
|
300
|
-
}
|
|
301
130
|
function collectSxSurfaceProperties(typeNode, checker, visited, collectFromSxType) {
|
|
302
131
|
const names = /* @__PURE__ */ new Set();
|
|
303
132
|
const found = collectSxSurfacePropertiesInto(names, typeNode, checker, visited, collectFromSxType);
|
|
@@ -507,16 +336,6 @@ function declarationHasResolvableSxSurface(declaration, checker, visited) {
|
|
|
507
336
|
function declarationHeritageHasResolvableSxSurface(heritageType, checker, visited) {
|
|
508
337
|
return (resolveAliasedSymbol(checker.getSymbolAtLocation(heritageType.expression), checker)?.declarations ?? []).some((declaration) => declarationHasResolvableSxSurface(declaration, checker, visited));
|
|
509
338
|
}
|
|
510
|
-
function typeNodeKeyIncludes(typeNode, key) {
|
|
511
|
-
if (!typeNode) return false;
|
|
512
|
-
if (ts.isLiteralTypeNode(typeNode) && ts.isStringLiteral(typeNode.literal)) return typeNode.literal.text === key;
|
|
513
|
-
if (ts.isUnionTypeNode(typeNode)) return typeNode.types.some((part) => typeNodeKeyIncludes(part, key));
|
|
514
|
-
return false;
|
|
515
|
-
}
|
|
516
|
-
function resolveAliasedSymbol(symbol, checker) {
|
|
517
|
-
if (!symbol || (symbol.flags & ts.SymbolFlags.Alias) === 0) return symbol;
|
|
518
|
-
return checker.getAliasedSymbol(symbol);
|
|
519
|
-
}
|
|
520
339
|
function collectExplicitPropNamesFromDeclaration(names, declaration, checker, visited) {
|
|
521
340
|
if (visited.has(declaration)) return;
|
|
522
341
|
visited.add(declaration);
|
|
@@ -536,17 +355,423 @@ function collectExplicitPropNamesFromHeritage(names, heritageType, checker, visi
|
|
|
536
355
|
const symbol = resolveAliasedSymbol(checker.getSymbolAtLocation(heritageType.expression), checker);
|
|
537
356
|
for (const declaration of symbol?.declarations ?? []) collectExplicitPropNamesFromDeclaration(names, declaration, checker, visited);
|
|
538
357
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
358
|
+
//#endregion
|
|
359
|
+
//#region src/internal/prepass/sx-target-detection.ts
|
|
360
|
+
function readsSxProp(parameter, body) {
|
|
361
|
+
if (parameter?.name && ts.isObjectBindingPattern(parameter.name)) {
|
|
362
|
+
if (bindingPatternHasName(parameter.name, "sx")) return true;
|
|
363
|
+
}
|
|
364
|
+
if (!body || !parameter?.name || !ts.isIdentifier(parameter.name)) return false;
|
|
365
|
+
const propsName = parameter.name.text;
|
|
366
|
+
let found = false;
|
|
367
|
+
const visit = (node) => {
|
|
368
|
+
if (found) return;
|
|
369
|
+
if (isFunctionWithParameterNamed(node, propsName) || isFunctionWithParameterDestructuringName(node, "sx")) return;
|
|
370
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === propsName && node.name.text === "sx") {
|
|
371
|
+
found = true;
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && isIdentifierNamed(unwrapExpression(node.initializer), propsName) && bindingPatternHasName(node.name, "sx")) {
|
|
375
|
+
found = true;
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
ts.forEachChild(node, visit);
|
|
379
|
+
};
|
|
380
|
+
ts.forEachChild(body, visit);
|
|
381
|
+
return found;
|
|
382
|
+
}
|
|
383
|
+
function detectSxTarget(parameter, body) {
|
|
384
|
+
if (!body) return;
|
|
385
|
+
const sxNames = collectSxBindingNames(parameter, body);
|
|
386
|
+
if (sxNames.size === 0) return;
|
|
387
|
+
const sxPropContainerNames = collectSxPropContainerNames(parameter);
|
|
388
|
+
const sxPropsNames = collectStylexPropsBindingNames(body, sxNames, sxPropContainerNames);
|
|
389
|
+
const root = returnedJsxRoot(body);
|
|
390
|
+
if (!root) return;
|
|
391
|
+
if (jsxOpeningUsesSx(jsxRootOpening(root), sxNames, sxPropsNames, sxPropContainerNames)) return "root";
|
|
392
|
+
return jsxChildrenUseSx(root, sxNames, sxPropsNames, sxPropContainerNames) ? "inner" : void 0;
|
|
393
|
+
}
|
|
394
|
+
function collectSxBindingNames(parameter, body) {
|
|
395
|
+
const names = /* @__PURE__ */ new Set();
|
|
396
|
+
if (parameter?.name && ts.isObjectBindingPattern(parameter.name)) collectBindingElementLocalNames(parameter.name, "sx", names);
|
|
397
|
+
else names.add("sx");
|
|
398
|
+
if (parameter?.name && ts.isIdentifier(parameter.name)) {
|
|
399
|
+
const propsName = parameter.name.text;
|
|
400
|
+
const visit = (node) => {
|
|
401
|
+
if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && isIdentifierNamed(unwrapExpression(node.initializer), propsName)) collectBindingElementLocalNames(node.name, "sx", names);
|
|
402
|
+
ts.forEachChild(node, visit);
|
|
403
|
+
};
|
|
404
|
+
ts.forEachChild(body, visit);
|
|
405
|
+
}
|
|
406
|
+
return names;
|
|
407
|
+
}
|
|
408
|
+
function collectBindingElementLocalNames(pattern, propertyName, names) {
|
|
409
|
+
for (const element of pattern.elements) if (bindingElementPropertyNameText(element) === propertyName && ts.isIdentifier(element.name)) names.add(element.name.text);
|
|
410
|
+
}
|
|
411
|
+
function collectSxPropContainerNames(parameter) {
|
|
412
|
+
const names = /* @__PURE__ */ new Set();
|
|
413
|
+
if (parameter?.name && ts.isIdentifier(parameter.name)) names.add(parameter.name.text);
|
|
414
|
+
return names;
|
|
415
|
+
}
|
|
416
|
+
function collectStylexPropsBindingNames(body, sxNames, sxPropContainerNames) {
|
|
417
|
+
const names = /* @__PURE__ */ new Set();
|
|
418
|
+
const visit = (node) => {
|
|
419
|
+
if (ts.isVariableDeclaration(node) && node.initializer && isStylexPropsCallWithSx(node.initializer, sxNames, sxPropContainerNames)) {
|
|
420
|
+
if (ts.isIdentifier(node.name)) names.add(node.name.text);
|
|
421
|
+
else if (ts.isObjectBindingPattern(node.name)) collectBindingPatternIdentifierNames(node.name, names);
|
|
422
|
+
}
|
|
423
|
+
ts.forEachChild(node, visit);
|
|
424
|
+
};
|
|
425
|
+
ts.forEachChild(body, visit);
|
|
426
|
+
return names;
|
|
427
|
+
}
|
|
428
|
+
function collectBindingPatternIdentifierNames(pattern, names) {
|
|
429
|
+
for (const element of pattern.elements) if (ts.isIdentifier(element.name)) names.add(element.name.text);
|
|
430
|
+
}
|
|
431
|
+
function isStylexPropsCallWithSx(expr, sxNames, sxPropContainerNames) {
|
|
432
|
+
const unwrapped = unwrapExpression(expr);
|
|
433
|
+
const noSxPropsNames = /* @__PURE__ */ new Set();
|
|
434
|
+
return ts.isCallExpression(unwrapped) && isStylexPropsCallee(unwrapped.expression) && unwrapped.arguments.some((arg) => expressionReferencesNames(arg, sxNames, noSxPropsNames, sxPropContainerNames));
|
|
435
|
+
}
|
|
436
|
+
function isStylexPropsCallee(expr) {
|
|
437
|
+
return ts.isPropertyAccessExpression(expr) && expr.name.text === "props" && ts.isIdentifier(expr.expression) && expr.expression.text === "stylex";
|
|
438
|
+
}
|
|
439
|
+
function returnedJsxRoot(body) {
|
|
440
|
+
if (ts.isJsxElement(body) || ts.isJsxSelfClosingElement(body)) return body;
|
|
441
|
+
if (!ts.isBlock(body)) return null;
|
|
442
|
+
for (const statement of body.statements) {
|
|
443
|
+
if (!ts.isReturnStatement(statement) || !statement.expression) continue;
|
|
444
|
+
const expr = unwrapExpression(statement.expression);
|
|
445
|
+
if (ts.isJsxElement(expr) || ts.isJsxSelfClosingElement(expr)) return expr;
|
|
446
|
+
}
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
function jsxChildrenUseSx(root, sxNames, sxPropsNames, sxPropContainerNames) {
|
|
450
|
+
if (!ts.isJsxElement(root)) return false;
|
|
451
|
+
let found = false;
|
|
452
|
+
const visit = (node) => {
|
|
453
|
+
if (found) return;
|
|
454
|
+
if (functionShadowsSxReference(node, sxNames, sxPropContainerNames)) return;
|
|
455
|
+
if (ts.isJsxElement(node) && jsxOpeningUsesSx(node.openingElement, sxNames, sxPropsNames, sxPropContainerNames) || ts.isJsxSelfClosingElement(node) && jsxOpeningUsesSx(node, sxNames, sxPropsNames, sxPropContainerNames)) {
|
|
456
|
+
found = true;
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
ts.forEachChild(node, visit);
|
|
460
|
+
};
|
|
461
|
+
for (const child of root.children) visit(child);
|
|
462
|
+
return found;
|
|
463
|
+
}
|
|
464
|
+
function jsxRootOpening(root) {
|
|
465
|
+
return ts.isJsxElement(root) ? root.openingElement : root;
|
|
466
|
+
}
|
|
467
|
+
function jsxOpeningUsesSx(opening, sxNames, sxPropsNames, sxPropContainerNames) {
|
|
468
|
+
return opening.attributes.properties.some((attribute) => {
|
|
469
|
+
if (ts.isJsxSpreadAttribute(attribute)) return expressionReferencesNames(attribute.expression, sxNames, sxPropsNames, sxPropContainerNames);
|
|
470
|
+
if (!ts.isIdentifier(attribute.name) || !attribute.initializer) return false;
|
|
471
|
+
if (!ts.isJsxExpression(attribute.initializer) || !attribute.initializer.expression) return false;
|
|
472
|
+
if (attribute.name.text === "className" || attribute.name.text === "style") return expressionReferencesStylexPropsBinding(attribute.initializer.expression, sxPropsNames);
|
|
473
|
+
if (attribute.name.text !== "sx") return false;
|
|
474
|
+
return expressionReferencesNames(attribute.initializer.expression, sxNames, sxPropsNames, sxPropContainerNames);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
function expressionReferencesStylexPropsBinding(expr, sxPropsNames) {
|
|
478
|
+
const unwrapped = unwrapExpression(expr);
|
|
479
|
+
return ts.isIdentifier(unwrapped) && sxPropsNames.has(unwrapped.text);
|
|
480
|
+
}
|
|
481
|
+
function expressionReferencesNames(expr, sxNames, sxPropsNames, sxPropContainerNames) {
|
|
482
|
+
const unwrapped = unwrapExpression(expr);
|
|
483
|
+
if (ts.isIdentifier(unwrapped)) return sxNames.has(unwrapped.text) || sxPropsNames.has(unwrapped.text);
|
|
484
|
+
if (ts.isPropertyAccessExpression(unwrapped) && unwrapped.name.text === "sx" && ts.isIdentifier(unwrapped.expression)) return sxPropContainerNames.has(unwrapped.expression.text);
|
|
485
|
+
return isStylexPropsCallWithSx(unwrapped, sxNames, sxPropContainerNames);
|
|
486
|
+
}
|
|
487
|
+
function functionShadowsSxReference(node, sxNames, sxPropContainerNames) {
|
|
488
|
+
if (!isFunctionWithParameters(node)) return false;
|
|
489
|
+
for (const name of sxPropContainerNames) if (node.parameters.some((parameter) => isBindingNameNamed(parameter.name, name))) return true;
|
|
490
|
+
for (const name of sxNames) if (node.parameters.some((parameter) => isBindingNameNamed(parameter.name, name))) return true;
|
|
491
|
+
return node.parameters.some((parameter) => ts.isObjectBindingPattern(parameter.name) && bindingPatternHasName(parameter.name, "sx"));
|
|
492
|
+
}
|
|
493
|
+
function isFunctionWithParameterNamed(node, name) {
|
|
494
|
+
return isFunctionWithParameters(node) ? node.parameters.some((parameter) => isBindingNameNamed(parameter.name, name)) : false;
|
|
495
|
+
}
|
|
496
|
+
function isFunctionWithParameterDestructuringName(node, name) {
|
|
497
|
+
return isFunctionWithParameters(node) ? node.parameters.some((parameter) => ts.isObjectBindingPattern(parameter.name) && bindingPatternHasName(parameter.name, name)) : false;
|
|
498
|
+
}
|
|
499
|
+
function isFunctionWithParameters(node) {
|
|
500
|
+
return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node);
|
|
501
|
+
}
|
|
502
|
+
function isBindingNameNamed(name, expected) {
|
|
503
|
+
return ts.isIdentifier(name) && name.text === expected;
|
|
504
|
+
}
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region src/internal/prepass/ts-program-setup.ts
|
|
507
|
+
function createProgram(rootNames, cwd) {
|
|
508
|
+
const configPath = findTsConfig(rootNames, cwd);
|
|
509
|
+
const options = configPath ? readCompilerOptions(configPath) : defaultCompilerOptions();
|
|
510
|
+
return ts.createProgram({
|
|
511
|
+
rootNames: [...rootNames],
|
|
512
|
+
options: {
|
|
513
|
+
...options,
|
|
514
|
+
allowJs: true,
|
|
515
|
+
checkJs: false,
|
|
516
|
+
noEmit: true,
|
|
517
|
+
skipLibCheck: true,
|
|
518
|
+
skipDefaultLibCheck: true,
|
|
519
|
+
types: []
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
function getExportedNames(sourceFile, checker) {
|
|
524
|
+
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
525
|
+
if (!moduleSymbol) return /* @__PURE__ */ new Set();
|
|
526
|
+
return new Set(checker.getExportsOfModule(moduleSymbol).map((symbol) => symbol.getName()));
|
|
527
|
+
}
|
|
528
|
+
function getDefaultExportedLocalNames(sourceFile) {
|
|
529
|
+
const names = /* @__PURE__ */ new Set();
|
|
530
|
+
for (const statement of sourceFile.statements) {
|
|
531
|
+
if (!ts.isExportAssignment(statement) || !ts.isIdentifier(statement.expression)) continue;
|
|
532
|
+
names.add(statement.expression.text);
|
|
533
|
+
}
|
|
534
|
+
return names;
|
|
535
|
+
}
|
|
536
|
+
function normalizeFilePaths(files) {
|
|
537
|
+
return [...new Set(files.map(resolveExistingFilePath))].sort();
|
|
538
|
+
}
|
|
539
|
+
function normalizeFilePath(filePath) {
|
|
540
|
+
return resolveExistingFilePath(filePath);
|
|
541
|
+
}
|
|
542
|
+
function isTypeScriptLikeFile(filePath) {
|
|
543
|
+
return /\.(tsx?|jsx?)$/.test(filePath);
|
|
544
|
+
}
|
|
545
|
+
function readCompilerOptions(configPath) {
|
|
546
|
+
const config = ts.readConfigFile(configPath, (filePath) => ts.sys.readFile(filePath));
|
|
547
|
+
if (config.error) return defaultCompilerOptions();
|
|
548
|
+
return ts.parseJsonConfigFileContent(config.config, ts.sys, path.dirname(configPath)).options;
|
|
549
|
+
}
|
|
550
|
+
function defaultCompilerOptions() {
|
|
551
|
+
return {
|
|
552
|
+
target: ts.ScriptTarget.ES2022,
|
|
553
|
+
module: ts.ModuleKind.ESNext,
|
|
554
|
+
moduleResolution: ts.ModuleResolutionKind.Node10,
|
|
555
|
+
jsx: ts.JsxEmit.ReactJSX,
|
|
556
|
+
esModuleInterop: true,
|
|
557
|
+
skipLibCheck: true
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function findTsConfig(rootNames, cwd) {
|
|
561
|
+
const start = rootNames.length > 0 ? path.dirname(rootNames[0]) : cwd;
|
|
562
|
+
return ts.findConfigFile(start, (filePath) => ts.sys.fileExists(filePath), "tsconfig.json") ?? void 0;
|
|
563
|
+
}
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/internal/prepass/typescript-analysis.ts
|
|
566
|
+
function analyzeTypeScriptProgram(options) {
|
|
567
|
+
const rootNames = normalizeFilePaths(options.files).filter(isTypeScriptLikeFile);
|
|
568
|
+
if (rootNames.length === 0) return {
|
|
569
|
+
version: 1,
|
|
570
|
+
files: []
|
|
571
|
+
};
|
|
572
|
+
const program = createProgram(rootNames, options.cwd ?? process.cwd());
|
|
573
|
+
const checker = program.getTypeChecker();
|
|
574
|
+
const rootNameSet = new Set(rootNames.map((filePath) => path.resolve(filePath)));
|
|
575
|
+
const compilerOptions = program.getCompilerOptions();
|
|
576
|
+
strictNullChecksOnForCurrentRun = Boolean(compilerOptions.strictNullChecks ?? compilerOptions.strict);
|
|
577
|
+
return {
|
|
578
|
+
version: 1,
|
|
579
|
+
files: program.getSourceFiles().filter((sourceFile) => rootNameSet.has(path.resolve(sourceFile.fileName))).map((sourceFile) => analyzeSourceFile(sourceFile, checker)).filter((file) => file.components.length > 0 || file.functions.length > 0).sort((a, b) => a.filePath.localeCompare(b.filePath))
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
function analyzeSourceFile(sourceFile, checker) {
|
|
583
|
+
const exportedNames = getExportedNames(sourceFile, checker);
|
|
584
|
+
const defaultExportedLocalNames = getDefaultExportedLocalNames(sourceFile);
|
|
585
|
+
const localFunctionInitializers = collectLocalFunctionInitializers(sourceFile);
|
|
586
|
+
const components = [];
|
|
587
|
+
const functions = [];
|
|
588
|
+
const visit = (node) => {
|
|
589
|
+
if (ts.isFunctionDeclaration(node) && (node.name || isDefaultExport(node))) {
|
|
590
|
+
const fn = readFunctionDeclaration(node, checker, exportedNames);
|
|
591
|
+
functions.push(fn);
|
|
592
|
+
if (isReactComponentFunction(node, checker)) components.push(readReactComponentFromFunction(node, checker, exportedNames, defaultExportedLocalNames));
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (ts.isVariableStatement(node)) {
|
|
596
|
+
for (const declaration of node.declarationList.declarations) {
|
|
597
|
+
if (!ts.isIdentifier(declaration.name)) continue;
|
|
598
|
+
if (declaration.initializer && isStyledComponentInitializer(declaration.initializer)) {
|
|
599
|
+
components.push(readStyledComponent(declaration, node, checker, exportedNames));
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
const componentInitializer = declaration.initializer ? getComponentFunctionInitializerInfo(declaration.initializer, localFunctionInitializers) : void 0;
|
|
603
|
+
if (componentInitializer) {
|
|
604
|
+
functions.push(readVariableFunction(declaration.name.text, componentInitializer.fn, node, checker));
|
|
605
|
+
if (isReactComponentName(declaration.name.text) || returnsJsx(componentInitializer.fn)) components.push(readReactComponentFromVariable(declaration.name.text, componentInitializer.fn, componentInitializer.propTypeNode, node, checker, exportedNames, defaultExportedLocalNames));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
ts.forEachChild(node, visit);
|
|
611
|
+
};
|
|
612
|
+
ts.forEachChild(sourceFile, visit);
|
|
613
|
+
return {
|
|
614
|
+
filePath: normalizeFilePath(sourceFile.fileName),
|
|
615
|
+
components: components.sort(byName),
|
|
616
|
+
functions: functions.sort(byName)
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
function readFunctionDeclaration(node, checker, exportedNames) {
|
|
620
|
+
const name = node.name?.text ?? "default";
|
|
621
|
+
return {
|
|
622
|
+
name,
|
|
623
|
+
exported: exportedNames.has(name),
|
|
624
|
+
defaultExport: isDefaultExport(node),
|
|
625
|
+
typeParameters: readTypeParameters(node.typeParameters),
|
|
626
|
+
parameters: readParameters(node.parameters, checker)
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
function readVariableFunction(name, node, statement, checker) {
|
|
630
|
+
return {
|
|
631
|
+
name,
|
|
632
|
+
exported: isExported(statement),
|
|
633
|
+
defaultExport: false,
|
|
634
|
+
typeParameters: readTypeParameters(node.typeParameters),
|
|
635
|
+
parameters: readParameters(node.parameters, checker)
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
function readStyledComponent(declaration, statement, checker, exportedNames) {
|
|
639
|
+
const name = declaration.name.getText();
|
|
640
|
+
const typeNode = declaration.initializer ? findStyledPropsTypeNode(declaration.initializer) : void 0;
|
|
641
|
+
return buildComponentMetadata({
|
|
642
|
+
name,
|
|
643
|
+
kind: "styled",
|
|
644
|
+
exported: exportedNames.has(name) || isExported(statement),
|
|
645
|
+
defaultExport: false,
|
|
646
|
+
typeParameters: [],
|
|
647
|
+
propTypeNode: typeNode,
|
|
648
|
+
parameters: [],
|
|
649
|
+
restProps: [],
|
|
650
|
+
checker,
|
|
651
|
+
location: declaration
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
function readReactComponentFromFunction(node, checker, exportedNames, defaultExportedLocalNames) {
|
|
655
|
+
const name = node.name?.text ?? "default";
|
|
656
|
+
return buildComponentMetadata({
|
|
657
|
+
name,
|
|
658
|
+
kind: "react",
|
|
659
|
+
exported: exportedNames.has(name),
|
|
660
|
+
defaultExport: isDefaultExport(node) || defaultExportedLocalNames.has(name),
|
|
661
|
+
typeParameters: readTypeParameters(node.typeParameters),
|
|
662
|
+
propTypeNode: node.parameters[0]?.type,
|
|
663
|
+
parameters: readParameters(node.parameters, checker),
|
|
664
|
+
restProps: readRestProps(node.parameters[0], node.body),
|
|
665
|
+
bodySupportsSxProp: readsSxProp(node.parameters[0], node.body),
|
|
666
|
+
bodySxTarget: detectSxTarget(node.parameters[0], node.body),
|
|
667
|
+
checker,
|
|
668
|
+
location: node
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
function readReactComponentFromVariable(name, node, propTypeNode, statement, checker, exportedNames, defaultExportedLocalNames) {
|
|
672
|
+
return buildComponentMetadata({
|
|
673
|
+
name,
|
|
674
|
+
kind: "react",
|
|
675
|
+
exported: exportedNames.has(name) || isExported(statement),
|
|
676
|
+
defaultExport: defaultExportedLocalNames.has(name),
|
|
677
|
+
typeParameters: readTypeParameters(node.typeParameters),
|
|
678
|
+
propTypeNode: propTypeNode ?? node.parameters[0]?.type,
|
|
679
|
+
parameters: readParameters(node.parameters, checker),
|
|
680
|
+
restProps: readRestProps(node.parameters[0], node.body),
|
|
681
|
+
bodySupportsSxProp: readsSxProp(node.parameters[0], node.body),
|
|
682
|
+
bodySxTarget: detectSxTarget(node.parameters[0], node.body),
|
|
683
|
+
checker,
|
|
684
|
+
location: node
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
function buildComponentMetadata(args) {
|
|
688
|
+
const propType = args.propTypeNode ? args.checker.getTypeFromTypeNode(args.propTypeNode) : null;
|
|
689
|
+
const props = propType ? readPropsFromType(propType, args.checker, args.location) : [];
|
|
690
|
+
const explicitPropNames = args.propTypeNode ? collectExplicitPropNames(args.propTypeNode, args.checker) : [];
|
|
691
|
+
const supportsResolvedSxProp = props.some((prop) => prop.name === "sx") && args.propTypeNode !== void 0 && typeNodeHasResolvableSxSurface(args.propTypeNode, args.checker, /* @__PURE__ */ new Set());
|
|
692
|
+
const sxExcludedProperties = args.propTypeNode !== void 0 ? collectSxExcludedProperties(args.propTypeNode, args.checker, /* @__PURE__ */ new Set()) : [];
|
|
693
|
+
const sxAllowedProperties = args.propTypeNode !== void 0 ? collectSxAllowedProperties(args.propTypeNode, args.checker, /* @__PURE__ */ new Set()) : void 0;
|
|
694
|
+
return {
|
|
695
|
+
name: args.name,
|
|
696
|
+
kind: args.kind,
|
|
697
|
+
exported: args.exported,
|
|
698
|
+
defaultExport: args.defaultExport,
|
|
699
|
+
typeParameters: args.typeParameters,
|
|
700
|
+
propType: args.propTypeNode ? describeTypeNode(args.propTypeNode, args.checker) : null,
|
|
701
|
+
props,
|
|
702
|
+
explicitPropNames,
|
|
703
|
+
parameters: args.parameters,
|
|
704
|
+
restProps: args.restProps,
|
|
705
|
+
hasIndexSignature: propType ? hasIndexSignature(propType, args.checker) : false,
|
|
706
|
+
supportsSxProp: explicitPropNames.includes("sx") || supportsResolvedSxProp || args.bodySupportsSxProp === true,
|
|
707
|
+
...args.bodySxTarget ? { sxTarget: args.bodySxTarget } : {},
|
|
708
|
+
sxExcludedProperties,
|
|
709
|
+
...sxAllowedProperties !== void 0 ? { sxAllowedProperties } : {}
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
function readPropsFromType(type, checker, location) {
|
|
713
|
+
return checker.getPropertiesOfType(type).map((symbol) => {
|
|
714
|
+
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0] ?? location;
|
|
715
|
+
const optional = (symbol.flags & ts.SymbolFlags.Optional) !== 0;
|
|
716
|
+
return {
|
|
717
|
+
name: symbol.getName(),
|
|
718
|
+
optional,
|
|
719
|
+
readonly: isReadonlyProperty(symbol),
|
|
720
|
+
type: withOptionalUndefined(readPropTypeString(symbol, declaration, checker, location), optional)
|
|
721
|
+
};
|
|
722
|
+
}).sort(byName);
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* TS's resolved type for an optional property includes `| undefined` (because
|
|
726
|
+
* the `?` modifier widens it). Syntactic type nodes don't — `?: number` has
|
|
727
|
+
* `type === number`, not `number | undefined`. Downstream consumers
|
|
728
|
+
* (lower-rules/types.ts) rely on the `| undefined` suffix to gate certain
|
|
729
|
+
* emit decisions (e.g. wrapping a possibly-undefined value in a template
|
|
730
|
+
* string). Reconstruct it here so the syntactic fast path stays
|
|
731
|
+
* behaviorally equivalent to the typeToString path it replaced.
|
|
732
|
+
*/
|
|
733
|
+
function withOptionalUndefined(typeText, optional) {
|
|
734
|
+
if (!optional || !strictNullChecksOnForCurrentRun) return typeText;
|
|
735
|
+
if (/\bundefined\b/.test(typeText)) return typeText;
|
|
736
|
+
return `${typeText} | undefined`;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Per-run capture of strictNullChecks. Set by `analyzeTypeScriptProgram` before
|
|
740
|
+
* any per-file work runs; read by `withOptionalUndefined` to decide whether to
|
|
741
|
+
* append `| undefined` to optional props. Module-scoped to avoid threading the
|
|
742
|
+
* boolean through ~6 helper signatures for a single read site.
|
|
743
|
+
*/
|
|
744
|
+
let strictNullChecksOnForCurrentRun = false;
|
|
745
|
+
/**
|
|
746
|
+
* Returns the prop's TS type as a string. Prefers the syntactic type annotation
|
|
747
|
+
* from the declaration AST (cheap, no checker call) and only falls back to
|
|
748
|
+
* `checker.typeToString` when the declaration has no usable type node — typically
|
|
749
|
+
* synthesized properties (mapped/intersection/spread-derived) where the checker
|
|
750
|
+
* is the only source of truth.
|
|
751
|
+
*
|
|
752
|
+
* Why: typeToString with NoTruncation dominated the prepass at 39s / 723K calls.
|
|
753
|
+
* For the consumers downstream (lower-rules/types.ts parseTypeText), the
|
|
754
|
+
* syntactic representation is what they want anyway — they only handle
|
|
755
|
+
* TSTypeReference / TSUnionType / TSLiteralType shapes.
|
|
756
|
+
*/
|
|
757
|
+
function readPropTypeString(symbol, declaration, _checker, _location) {
|
|
758
|
+
const typeNode = getDeclarationTypeNode(declaration);
|
|
759
|
+
if (typeNode) return typeNode.getText();
|
|
760
|
+
return "";
|
|
761
|
+
}
|
|
762
|
+
function getDeclarationTypeNode(declaration) {
|
|
763
|
+
if (ts.isPropertySignature(declaration) || ts.isPropertyDeclaration(declaration) || ts.isParameter(declaration)) return declaration.type;
|
|
542
764
|
}
|
|
543
|
-
function
|
|
544
|
-
|
|
545
|
-
|
|
765
|
+
function readParameters(parameters, checker) {
|
|
766
|
+
return parameters.map((parameter) => ({
|
|
767
|
+
name: readParameterName(parameter.name),
|
|
768
|
+
optional: Boolean(parameter.questionToken || parameter.initializer),
|
|
769
|
+
rest: Boolean(parameter.dotDotDotToken),
|
|
770
|
+
type: parameter.type ? parameter.type.getText() : checker.typeToString(checker.getTypeAtLocation(parameter), parameter)
|
|
771
|
+
}));
|
|
546
772
|
}
|
|
547
|
-
function
|
|
548
|
-
|
|
549
|
-
return null;
|
|
773
|
+
function hasIndexSignature(type, checker) {
|
|
774
|
+
return checker.getIndexTypeOfType(type, ts.IndexKind.String) !== void 0 || checker.getIndexTypeOfType(type, ts.IndexKind.Number) !== void 0;
|
|
550
775
|
}
|
|
551
776
|
function readRestProps(parameter, body) {
|
|
552
777
|
const restProps = [];
|
|
@@ -571,166 +796,6 @@ function readRestProps(parameter, body) {
|
|
|
571
796
|
ts.forEachChild(body, visit);
|
|
572
797
|
return restProps.sort(byName);
|
|
573
798
|
}
|
|
574
|
-
function readsSxProp(parameter, body) {
|
|
575
|
-
if (parameter?.name && ts.isObjectBindingPattern(parameter.name)) {
|
|
576
|
-
if (bindingPatternHasName(parameter.name, "sx")) return true;
|
|
577
|
-
}
|
|
578
|
-
if (!body || !parameter?.name || !ts.isIdentifier(parameter.name)) return false;
|
|
579
|
-
const propsName = parameter.name.text;
|
|
580
|
-
let found = false;
|
|
581
|
-
const visit = (node) => {
|
|
582
|
-
if (found) return;
|
|
583
|
-
if (isFunctionWithParameterNamed(node, propsName) || isFunctionWithParameterDestructuringName(node, "sx")) return;
|
|
584
|
-
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === propsName && node.name.text === "sx") {
|
|
585
|
-
found = true;
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && isIdentifierNamed(unwrapExpression(node.initializer), propsName) && bindingPatternHasName(node.name, "sx")) {
|
|
589
|
-
found = true;
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
ts.forEachChild(node, visit);
|
|
593
|
-
};
|
|
594
|
-
ts.forEachChild(body, visit);
|
|
595
|
-
return found;
|
|
596
|
-
}
|
|
597
|
-
function detectSxTarget(parameter, body) {
|
|
598
|
-
if (!body) return;
|
|
599
|
-
const sxNames = collectSxBindingNames(parameter, body);
|
|
600
|
-
if (sxNames.size === 0) return;
|
|
601
|
-
const sxPropContainerNames = collectSxPropContainerNames(parameter);
|
|
602
|
-
const sxPropsNames = collectStylexPropsBindingNames(body, sxNames, sxPropContainerNames);
|
|
603
|
-
const root = returnedJsxRoot(body);
|
|
604
|
-
if (!root) return;
|
|
605
|
-
if (jsxOpeningUsesSx(jsxRootOpening(root), sxNames, sxPropsNames, sxPropContainerNames)) return "root";
|
|
606
|
-
return jsxChildrenUseSx(root, sxNames, sxPropsNames, sxPropContainerNames) ? "inner" : void 0;
|
|
607
|
-
}
|
|
608
|
-
function collectSxBindingNames(parameter, body) {
|
|
609
|
-
const names = /* @__PURE__ */ new Set();
|
|
610
|
-
if (parameter?.name && ts.isObjectBindingPattern(parameter.name)) collectBindingElementLocalNames(parameter.name, "sx", names);
|
|
611
|
-
else names.add("sx");
|
|
612
|
-
if (parameter?.name && ts.isIdentifier(parameter.name)) {
|
|
613
|
-
const propsName = parameter.name.text;
|
|
614
|
-
const visit = (node) => {
|
|
615
|
-
if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && isIdentifierNamed(unwrapExpression(node.initializer), propsName)) collectBindingElementLocalNames(node.name, "sx", names);
|
|
616
|
-
ts.forEachChild(node, visit);
|
|
617
|
-
};
|
|
618
|
-
ts.forEachChild(body, visit);
|
|
619
|
-
}
|
|
620
|
-
return names;
|
|
621
|
-
}
|
|
622
|
-
function collectBindingElementLocalNames(pattern, propertyName, names) {
|
|
623
|
-
for (const element of pattern.elements) if (bindingElementPropertyNameText(element) === propertyName && ts.isIdentifier(element.name)) names.add(element.name.text);
|
|
624
|
-
}
|
|
625
|
-
function collectSxPropContainerNames(parameter) {
|
|
626
|
-
const names = /* @__PURE__ */ new Set();
|
|
627
|
-
if (parameter?.name && ts.isIdentifier(parameter.name)) names.add(parameter.name.text);
|
|
628
|
-
return names;
|
|
629
|
-
}
|
|
630
|
-
function bindingElementPropertyNameText(element) {
|
|
631
|
-
if (element.propertyName) return ts.isIdentifier(element.propertyName) || ts.isStringLiteral(element.propertyName) ? element.propertyName.text : null;
|
|
632
|
-
return ts.isIdentifier(element.name) ? element.name.text : null;
|
|
633
|
-
}
|
|
634
|
-
function collectStylexPropsBindingNames(body, sxNames, sxPropContainerNames) {
|
|
635
|
-
const names = /* @__PURE__ */ new Set();
|
|
636
|
-
const visit = (node) => {
|
|
637
|
-
if (ts.isVariableDeclaration(node) && node.initializer && isStylexPropsCallWithSx(node.initializer, sxNames, sxPropContainerNames)) {
|
|
638
|
-
if (ts.isIdentifier(node.name)) names.add(node.name.text);
|
|
639
|
-
else if (ts.isObjectBindingPattern(node.name)) collectBindingPatternIdentifierNames(node.name, names);
|
|
640
|
-
}
|
|
641
|
-
ts.forEachChild(node, visit);
|
|
642
|
-
};
|
|
643
|
-
ts.forEachChild(body, visit);
|
|
644
|
-
return names;
|
|
645
|
-
}
|
|
646
|
-
function collectBindingPatternIdentifierNames(pattern, names) {
|
|
647
|
-
for (const element of pattern.elements) if (ts.isIdentifier(element.name)) names.add(element.name.text);
|
|
648
|
-
}
|
|
649
|
-
function isStylexPropsCallWithSx(expr, sxNames, sxPropContainerNames) {
|
|
650
|
-
const unwrapped = unwrapExpression(expr);
|
|
651
|
-
const noSxPropsNames = /* @__PURE__ */ new Set();
|
|
652
|
-
return ts.isCallExpression(unwrapped) && isStylexPropsCallee(unwrapped.expression) && unwrapped.arguments.some((arg) => expressionReferencesNames(arg, sxNames, noSxPropsNames, sxPropContainerNames));
|
|
653
|
-
}
|
|
654
|
-
function isStylexPropsCallee(expr) {
|
|
655
|
-
return ts.isPropertyAccessExpression(expr) && expr.name.text === "props" && ts.isIdentifier(expr.expression) && expr.expression.text === "stylex";
|
|
656
|
-
}
|
|
657
|
-
function returnedJsxRoot(body) {
|
|
658
|
-
if (ts.isJsxElement(body) || ts.isJsxSelfClosingElement(body)) return body;
|
|
659
|
-
if (!ts.isBlock(body)) return null;
|
|
660
|
-
for (const statement of body.statements) {
|
|
661
|
-
if (!ts.isReturnStatement(statement) || !statement.expression) continue;
|
|
662
|
-
const expr = unwrapExpression(statement.expression);
|
|
663
|
-
if (ts.isJsxElement(expr) || ts.isJsxSelfClosingElement(expr)) return expr;
|
|
664
|
-
}
|
|
665
|
-
return null;
|
|
666
|
-
}
|
|
667
|
-
function jsxChildrenUseSx(root, sxNames, sxPropsNames, sxPropContainerNames) {
|
|
668
|
-
if (!ts.isJsxElement(root)) return false;
|
|
669
|
-
let found = false;
|
|
670
|
-
const visit = (node) => {
|
|
671
|
-
if (found) return;
|
|
672
|
-
if (functionShadowsSxReference(node, sxNames, sxPropContainerNames)) return;
|
|
673
|
-
if (ts.isJsxElement(node) && jsxOpeningUsesSx(node.openingElement, sxNames, sxPropsNames, sxPropContainerNames) || ts.isJsxSelfClosingElement(node) && jsxOpeningUsesSx(node, sxNames, sxPropsNames, sxPropContainerNames)) {
|
|
674
|
-
found = true;
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
ts.forEachChild(node, visit);
|
|
678
|
-
};
|
|
679
|
-
for (const child of root.children) visit(child);
|
|
680
|
-
return found;
|
|
681
|
-
}
|
|
682
|
-
function jsxRootOpening(root) {
|
|
683
|
-
return ts.isJsxElement(root) ? root.openingElement : root;
|
|
684
|
-
}
|
|
685
|
-
function jsxOpeningUsesSx(opening, sxNames, sxPropsNames, sxPropContainerNames) {
|
|
686
|
-
return opening.attributes.properties.some((attribute) => {
|
|
687
|
-
if (ts.isJsxSpreadAttribute(attribute)) return expressionReferencesNames(attribute.expression, sxNames, sxPropsNames, sxPropContainerNames);
|
|
688
|
-
if (!ts.isIdentifier(attribute.name) || !attribute.initializer) return false;
|
|
689
|
-
if (!ts.isJsxExpression(attribute.initializer) || !attribute.initializer.expression) return false;
|
|
690
|
-
if (attribute.name.text === "className" || attribute.name.text === "style") return expressionReferencesStylexPropsBinding(attribute.initializer.expression, sxPropsNames);
|
|
691
|
-
if (attribute.name.text !== "sx") return false;
|
|
692
|
-
return expressionReferencesNames(attribute.initializer.expression, sxNames, sxPropsNames, sxPropContainerNames);
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
function expressionReferencesStylexPropsBinding(expr, sxPropsNames) {
|
|
696
|
-
const unwrapped = unwrapExpression(expr);
|
|
697
|
-
return ts.isIdentifier(unwrapped) && sxPropsNames.has(unwrapped.text);
|
|
698
|
-
}
|
|
699
|
-
function expressionReferencesNames(expr, sxNames, sxPropsNames, sxPropContainerNames) {
|
|
700
|
-
const unwrapped = unwrapExpression(expr);
|
|
701
|
-
if (ts.isIdentifier(unwrapped)) return sxNames.has(unwrapped.text) || sxPropsNames.has(unwrapped.text);
|
|
702
|
-
if (ts.isPropertyAccessExpression(unwrapped) && unwrapped.name.text === "sx" && ts.isIdentifier(unwrapped.expression)) return sxPropContainerNames.has(unwrapped.expression.text);
|
|
703
|
-
return isStylexPropsCallWithSx(unwrapped, sxNames, sxPropContainerNames);
|
|
704
|
-
}
|
|
705
|
-
function functionShadowsSxReference(node, sxNames, sxPropContainerNames) {
|
|
706
|
-
if (!isFunctionWithParameters(node)) return false;
|
|
707
|
-
for (const name of sxPropContainerNames) if (node.parameters.some((parameter) => isBindingNameNamed(parameter.name, name))) return true;
|
|
708
|
-
for (const name of sxNames) if (node.parameters.some((parameter) => isBindingNameNamed(parameter.name, name))) return true;
|
|
709
|
-
return node.parameters.some((parameter) => ts.isObjectBindingPattern(parameter.name) && bindingPatternHasName(parameter.name, "sx"));
|
|
710
|
-
}
|
|
711
|
-
function isFunctionWithParameterNamed(node, name) {
|
|
712
|
-
return isFunctionWithParameters(node) ? node.parameters.some((parameter) => isBindingNameNamed(parameter.name, name)) : false;
|
|
713
|
-
}
|
|
714
|
-
function isFunctionWithParameterDestructuringName(node, name) {
|
|
715
|
-
return isFunctionWithParameters(node) ? node.parameters.some((parameter) => ts.isObjectBindingPattern(parameter.name) && bindingPatternHasName(parameter.name, name)) : false;
|
|
716
|
-
}
|
|
717
|
-
function isFunctionWithParameters(node) {
|
|
718
|
-
return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node);
|
|
719
|
-
}
|
|
720
|
-
function isBindingNameNamed(name, expected) {
|
|
721
|
-
return ts.isIdentifier(name) && name.text === expected;
|
|
722
|
-
}
|
|
723
|
-
function bindingPatternHasName(pattern, name) {
|
|
724
|
-
return pattern.elements.some((element) => element.name.getText() === name);
|
|
725
|
-
}
|
|
726
|
-
function unwrapExpression(expression) {
|
|
727
|
-
let current = expression;
|
|
728
|
-
while (ts.isAsExpression(current) || ts.isTypeAssertionExpression(current) || ts.isSatisfiesExpression(current) || ts.isParenthesizedExpression(current)) current = current.expression;
|
|
729
|
-
return current;
|
|
730
|
-
}
|
|
731
|
-
function isIdentifierNamed(expression, name) {
|
|
732
|
-
return ts.isIdentifier(expression) && expression.text === name;
|
|
733
|
-
}
|
|
734
799
|
function describeTypeNode(typeNode, checker) {
|
|
735
800
|
const declaration = resolveTypeDeclaration(typeNode, checker);
|
|
736
801
|
return {
|
|
@@ -871,19 +936,6 @@ function readParameterName(name) {
|
|
|
871
936
|
function isReadonlyProperty(symbol) {
|
|
872
937
|
return Boolean(symbol.declarations?.some((declaration) => (ts.isPropertySignature(declaration) || ts.isPropertyDeclaration(declaration)) && declaration.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ReadonlyKeyword)));
|
|
873
938
|
}
|
|
874
|
-
function getExportedNames(sourceFile, checker) {
|
|
875
|
-
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
876
|
-
if (!moduleSymbol) return /* @__PURE__ */ new Set();
|
|
877
|
-
return new Set(checker.getExportsOfModule(moduleSymbol).map((symbol) => symbol.getName()));
|
|
878
|
-
}
|
|
879
|
-
function getDefaultExportedLocalNames(sourceFile) {
|
|
880
|
-
const names = /* @__PURE__ */ new Set();
|
|
881
|
-
for (const statement of sourceFile.statements) {
|
|
882
|
-
if (!ts.isExportAssignment(statement) || !ts.isIdentifier(statement.expression)) continue;
|
|
883
|
-
names.add(statement.expression.text);
|
|
884
|
-
}
|
|
885
|
-
return names;
|
|
886
|
-
}
|
|
887
939
|
function isExported(node) {
|
|
888
940
|
return Boolean(ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
|
|
889
941
|
}
|
|
@@ -893,50 +945,6 @@ function isDefaultExport(node) {
|
|
|
893
945
|
function isReactComponentName(name) {
|
|
894
946
|
return /^[A-Z]/.test(name);
|
|
895
947
|
}
|
|
896
|
-
function createProgram(rootNames, cwd) {
|
|
897
|
-
const configPath = findTsConfig(rootNames, cwd);
|
|
898
|
-
const options = configPath ? readCompilerOptions(configPath) : defaultCompilerOptions();
|
|
899
|
-
return ts.createProgram({
|
|
900
|
-
rootNames: [...rootNames],
|
|
901
|
-
options: {
|
|
902
|
-
...options,
|
|
903
|
-
allowJs: true,
|
|
904
|
-
checkJs: false,
|
|
905
|
-
noEmit: true,
|
|
906
|
-
skipLibCheck: true,
|
|
907
|
-
skipDefaultLibCheck: true,
|
|
908
|
-
types: []
|
|
909
|
-
}
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
function readCompilerOptions(configPath) {
|
|
913
|
-
const config = ts.readConfigFile(configPath, (filePath) => ts.sys.readFile(filePath));
|
|
914
|
-
if (config.error) return defaultCompilerOptions();
|
|
915
|
-
return ts.parseJsonConfigFileContent(config.config, ts.sys, path.dirname(configPath)).options;
|
|
916
|
-
}
|
|
917
|
-
function defaultCompilerOptions() {
|
|
918
|
-
return {
|
|
919
|
-
target: ts.ScriptTarget.ES2022,
|
|
920
|
-
module: ts.ModuleKind.ESNext,
|
|
921
|
-
moduleResolution: ts.ModuleResolutionKind.Node10,
|
|
922
|
-
jsx: ts.JsxEmit.ReactJSX,
|
|
923
|
-
esModuleInterop: true,
|
|
924
|
-
skipLibCheck: true
|
|
925
|
-
};
|
|
926
|
-
}
|
|
927
|
-
function findTsConfig(rootNames, cwd) {
|
|
928
|
-
const start = rootNames.length > 0 ? path.dirname(rootNames[0]) : cwd;
|
|
929
|
-
return ts.findConfigFile(start, (filePath) => ts.sys.fileExists(filePath), "tsconfig.json") ?? void 0;
|
|
930
|
-
}
|
|
931
|
-
function normalizeFilePaths(files) {
|
|
932
|
-
return [...new Set(files.map(resolveExistingFilePath))].sort();
|
|
933
|
-
}
|
|
934
|
-
function normalizeFilePath(filePath) {
|
|
935
|
-
return resolveExistingFilePath(filePath);
|
|
936
|
-
}
|
|
937
|
-
function isTypeScriptLikeFile(filePath) {
|
|
938
|
-
return /\.(tsx?|jsx?)$/.test(filePath);
|
|
939
|
-
}
|
|
940
948
|
function byName(a, b) {
|
|
941
949
|
return a.name.localeCompare(b.name);
|
|
942
950
|
}
|