@bamboocss/extractor 1.12.2 → 1.13.1
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/LICENSE.md +1 -0
- package/dist/index.cjs +48 -12
- package/dist/index.d.cts +312 -0
- package/dist/index.d.mts +312 -0
- package/dist/index.mjs +48 -13
- package/package.json +4 -4
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2023 Segun Adebayo
|
|
4
|
+
Copyright (c) 2026 Gajus Kuizinas
|
|
4
5
|
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
6
7
|
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
package/dist/index.cjs
CHANGED
|
@@ -336,12 +336,12 @@ function getDeclarationFor(node, stack, ctx) {
|
|
|
336
336
|
if ((ts_morph.Node.isVariableDeclaration(parent) || ts_morph.Node.isParameterDeclaration(parent) || ts_morph.Node.isFunctionDeclaration(parent) || ts_morph.Node.isEnumDeclaration(parent) || ts_morph.Node.isBindingElement(parent)) && parent.getNameNode() == node) {
|
|
337
337
|
declarationStack.push(parent);
|
|
338
338
|
declaration = parent;
|
|
339
|
-
} else if (ts_morph.Node.isImportSpecifier(parent) && parent.getNameNode() == node) {
|
|
339
|
+
} else if (ts_morph.Node.isImportSpecifier(parent) && (parent.getNameNode() == node || parent.getAliasNode() == node)) {
|
|
340
340
|
if (ctx.flags?.skipTraverseFiles) return;
|
|
341
341
|
const sourceFile = getModuleSpecifierSourceFile(parent.getImportDeclaration());
|
|
342
342
|
if (sourceFile) {
|
|
343
343
|
const exportStack = [parent, sourceFile];
|
|
344
|
-
const maybeVar = getExportedVarDeclarationWithName(
|
|
344
|
+
const maybeVar = getExportedVarDeclarationWithName(parent.getNameNode().getText(), sourceFile, exportStack, ctx);
|
|
345
345
|
if (maybeVar) {
|
|
346
346
|
declarationStack.push(...exportStack.concat(maybeVar));
|
|
347
347
|
declaration = maybeVar;
|
|
@@ -508,9 +508,23 @@ const getObjectLiteralExpressionPropPairs = (expression, expressionStack, ctx, m
|
|
|
508
508
|
};
|
|
509
509
|
//#endregion
|
|
510
510
|
//#region src/maybe-box-node.ts
|
|
511
|
-
|
|
511
|
+
let cacheMap$1 = /* @__PURE__ */ new WeakMap();
|
|
512
512
|
const isCached = (node) => cacheMap$1.has(node);
|
|
513
513
|
const getCached = (node) => cacheMap$1.get(node);
|
|
514
|
+
/**
|
|
515
|
+
* Drops every memoized resolution.
|
|
516
|
+
*
|
|
517
|
+
* The cache is keyed on AST nodes, and a node's resolved value can depend on
|
|
518
|
+
* another file: `css(button)` folds whatever `./styles` exports. Editing that file
|
|
519
|
+
* replaces only its own nodes, so an importer's nodes stay identical and would
|
|
520
|
+
* otherwise keep serving the value read before the edit.
|
|
521
|
+
*/
|
|
522
|
+
const clearBoxNodeCache = () => {
|
|
523
|
+
if (!hasCachedEntries) return;
|
|
524
|
+
cacheMap$1 = /* @__PURE__ */ new WeakMap();
|
|
525
|
+
hasCachedEntries = false;
|
|
526
|
+
};
|
|
527
|
+
let hasCachedEntries = false;
|
|
514
528
|
const isPlusSyntax = (op) => op === ts_morph.ts.SyntaxKind.PlusToken;
|
|
515
529
|
const isLogicalSyntax = (op) => op === ts_morph.ts.SyntaxKind.BarBarToken || op === ts_morph.ts.SyntaxKind.QuestionQuestionToken || op === ts_morph.ts.SyntaxKind.AmpersandAmpersandToken || op === ts_morph.ts.SyntaxKind.EqualsEqualsEqualsToken || op === ts_morph.ts.SyntaxKind.EqualsEqualsToken || op === ts_morph.ts.SyntaxKind.ExclamationEqualsEqualsToken || op === ts_morph.ts.SyntaxKind.ExclamationEqualsToken || op === ts_morph.ts.SyntaxKind.GreaterThanEqualsToken || op === ts_morph.ts.SyntaxKind.GreaterThanToken || op === ts_morph.ts.SyntaxKind.LessThanEqualsToken || op === ts_morph.ts.SyntaxKind.LessThanToken || op === ts_morph.ts.SyntaxKind.InstanceOfKeyword || op === ts_morph.ts.SyntaxKind.InKeyword;
|
|
516
530
|
const isOperationSyntax = (op) => op === ts_morph.ts.SyntaxKind.AsteriskToken || op === ts_morph.ts.SyntaxKind.SlashToken || op === ts_morph.ts.SyntaxKind.PercentToken || op === ts_morph.ts.SyntaxKind.AsteriskAsteriskToken || op === ts_morph.ts.SyntaxKind.MinusToken;
|
|
@@ -520,6 +534,7 @@ const canReturnWhenTrueInLogicalExpression = (op) => {
|
|
|
520
534
|
function maybeBoxNode(node, stack, ctx, matchProp) {
|
|
521
535
|
const cache = (value) => {
|
|
522
536
|
cacheMap$1.set(node, value);
|
|
537
|
+
hasCachedEntries = true;
|
|
523
538
|
return value;
|
|
524
539
|
};
|
|
525
540
|
if (isCached(node)) return getCached(node);
|
|
@@ -916,17 +931,29 @@ const maybeDefinitionValue = (def, stack, ctx) => {
|
|
|
916
931
|
if (maybeValue) return maybeValue;
|
|
917
932
|
}
|
|
918
933
|
};
|
|
919
|
-
const getExportedVarDeclarationWithName = (varName, sourceFile, stack, ctx) => {
|
|
934
|
+
const getExportedVarDeclarationWithName = (varName, sourceFile, stack, ctx, visited = /* @__PURE__ */ new Set()) => {
|
|
935
|
+
const key = `${sourceFile.getFilePath()}:${varName}`;
|
|
936
|
+
if (visited.has(key)) return;
|
|
937
|
+
visited.add(key);
|
|
920
938
|
const maybeVar = sourceFile.getVariableDeclaration(varName);
|
|
921
939
|
if (maybeVar) return maybeVar;
|
|
922
|
-
const exportDeclaration = resolveVarDeclarationFromExportWithName(varName, sourceFile, stack, ctx);
|
|
940
|
+
const exportDeclaration = resolveVarDeclarationFromExportWithName(varName, sourceFile, stack, ctx, visited);
|
|
923
941
|
if (!exportDeclaration) return;
|
|
924
942
|
return exportDeclaration;
|
|
925
943
|
};
|
|
926
|
-
|
|
944
|
+
/**
|
|
945
|
+
* Given the name a module exposes, the name to look for in the module it came from.
|
|
946
|
+
* Returns `undefined` when this declaration does not provide `name` at all.
|
|
947
|
+
*
|
|
948
|
+
* For `export { btn as button } from './styles'` the two differ: `getAliasNode()`
|
|
949
|
+
* is `button`, the name this module exports, and `getNameNode()` is `btn`, the name
|
|
950
|
+
* to search for in `./styles`. Matching on the wrong one both hides names the
|
|
951
|
+
* module does export and resolves names it does not.
|
|
952
|
+
*/
|
|
953
|
+
const resolveExportedName = (name, exportDeclaration) => {
|
|
927
954
|
const namedExports = exportDeclaration.getNamedExports();
|
|
928
|
-
if (namedExports.length === 0) return
|
|
929
|
-
for (const namedExport of namedExports) if (namedExport.getNameNode().getText() === name) return
|
|
955
|
+
if (namedExports.length === 0) return name;
|
|
956
|
+
for (const namedExport of namedExports) if ((namedExport.getAliasNode() ?? namedExport.getNameNode()).getText() === name) return namedExport.getNameNode().getText();
|
|
930
957
|
};
|
|
931
958
|
/**
|
|
932
959
|
* Faster than declaration.getModuleSpecifierSourceFile()
|
|
@@ -946,14 +973,22 @@ const getModuleSpecifierSourceFile = (declaration) => {
|
|
|
946
973
|
if (!resolved.resolvedModule) return;
|
|
947
974
|
return project.addSourceFileAtPath(resolved.resolvedModule.resolvedFileName);
|
|
948
975
|
};
|
|
949
|
-
function resolveVarDeclarationFromExportWithName(symbolName, sourceFile, stack, ctx) {
|
|
976
|
+
function resolveVarDeclarationFromExportWithName(symbolName, sourceFile, stack, ctx, visited) {
|
|
950
977
|
for (const exportDeclaration of sourceFile.getExportDeclarations()) {
|
|
951
978
|
const exportStack = [exportDeclaration];
|
|
952
|
-
|
|
979
|
+
const sourceName = resolveExportedName(symbolName, exportDeclaration);
|
|
980
|
+
if (sourceName === void 0) continue;
|
|
953
981
|
const maybeFile = getModuleSpecifierSourceFile(exportDeclaration);
|
|
954
|
-
if (!maybeFile)
|
|
982
|
+
if (!maybeFile) {
|
|
983
|
+
const localVar = sourceFile.getVariableDeclaration(sourceName);
|
|
984
|
+
if (localVar) {
|
|
985
|
+
stack.push(...exportStack.concat(localVar));
|
|
986
|
+
return localVar;
|
|
987
|
+
}
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
955
990
|
exportStack.push(maybeFile);
|
|
956
|
-
const maybeVar = getExportedVarDeclarationWithName(
|
|
991
|
+
const maybeVar = getExportedVarDeclarationWithName(sourceName, maybeFile, stack, ctx, visited);
|
|
957
992
|
if (maybeVar) {
|
|
958
993
|
stack.push(...exportStack.concat(maybeVar));
|
|
959
994
|
return maybeVar;
|
|
@@ -1820,6 +1855,7 @@ exports.BoxNodeMap = BoxNodeMap;
|
|
|
1820
1855
|
exports.BoxNodeObject = BoxNodeObject;
|
|
1821
1856
|
exports.BoxNodeUnresolvable = BoxNodeUnresolvable;
|
|
1822
1857
|
exports.box = box;
|
|
1858
|
+
exports.clearBoxNodeCache = clearBoxNodeCache;
|
|
1823
1859
|
exports.extract = extract;
|
|
1824
1860
|
exports.extractCallExpressionArguments = extractCallExpressionArguments;
|
|
1825
1861
|
exports.extractJsxAttribute = extractJsxAttribute;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { BindingElement, CallExpression, EnumDeclaration, Expression, FunctionDeclaration, GetAccessorDeclaration, Identifier, JsxAttribute, JsxOpeningElement, JsxSelfClosingElement, JsxSpreadAttribute, Node, ParameterDeclaration, PropertyAssignment, ShorthandPropertyAssignment, SourceFile, TaggedTemplateExpression, VariableDeclaration } from "ts-morph";
|
|
2
|
+
import { EvaluateOptions as EvaluateOptions$1 } from "ts-evaluator";
|
|
3
|
+
|
|
4
|
+
//#region src/box-factory.d.ts
|
|
5
|
+
interface WithNode {
|
|
6
|
+
node: Node;
|
|
7
|
+
stack: Node[];
|
|
8
|
+
}
|
|
9
|
+
interface ObjectType extends WithNode {
|
|
10
|
+
type: 'object';
|
|
11
|
+
value: EvaluatedObjectResult;
|
|
12
|
+
isEmpty?: boolean;
|
|
13
|
+
}
|
|
14
|
+
type LiteralKind = 'array' | 'string' | 'number' | 'boolean' | 'null' | 'undefined';
|
|
15
|
+
interface LiteralType extends WithNode {
|
|
16
|
+
type: 'literal';
|
|
17
|
+
value: PrimitiveType;
|
|
18
|
+
kind: LiteralKind;
|
|
19
|
+
}
|
|
20
|
+
interface MapType extends WithNode {
|
|
21
|
+
type: 'map';
|
|
22
|
+
value: MapTypeValue;
|
|
23
|
+
}
|
|
24
|
+
interface ArrayType extends WithNode {
|
|
25
|
+
type: 'array';
|
|
26
|
+
value: BoxNode[];
|
|
27
|
+
}
|
|
28
|
+
interface UnresolvableType extends WithNode {
|
|
29
|
+
type: 'unresolvable';
|
|
30
|
+
}
|
|
31
|
+
interface ConditionalType extends WithNode {
|
|
32
|
+
type: 'conditional';
|
|
33
|
+
whenTrue: BoxNode;
|
|
34
|
+
whenFalse: BoxNode;
|
|
35
|
+
}
|
|
36
|
+
/** -> Jsx boolean attribute <Box flex /> */
|
|
37
|
+
interface EmptyInitializerType extends WithNode {
|
|
38
|
+
type: 'empty-initializer';
|
|
39
|
+
}
|
|
40
|
+
type BoxNodeDefinition = ObjectType | LiteralType | MapType | ArrayType | UnresolvableType | ConditionalType | EmptyInitializerType;
|
|
41
|
+
type BoxNode = BoxNodeObject | BoxNodeLiteral | BoxNodeMap | BoxNodeArray | BoxNodeUnresolvable | BoxNodeConditional | BoxNodeEmptyInitializer;
|
|
42
|
+
type MapTypeValue = Map<string, BoxNode>;
|
|
43
|
+
declare abstract class BoxNodeType$1<Definition extends BoxNodeDefinition = BoxNodeDefinition> {
|
|
44
|
+
readonly type: Definition['type'];
|
|
45
|
+
private readonly stack;
|
|
46
|
+
private readonly node;
|
|
47
|
+
constructor(definition: Definition);
|
|
48
|
+
getNode(): Node;
|
|
49
|
+
getStack(): Node[];
|
|
50
|
+
getRange: () => {
|
|
51
|
+
startPosition: number;
|
|
52
|
+
startLineNumber: number;
|
|
53
|
+
startColumn: number;
|
|
54
|
+
endPosition: number;
|
|
55
|
+
endLineNumber: number;
|
|
56
|
+
endColumn: number;
|
|
57
|
+
};
|
|
58
|
+
toJSON(): {
|
|
59
|
+
type: Definition["type"];
|
|
60
|
+
value: any;
|
|
61
|
+
node: string;
|
|
62
|
+
line: number;
|
|
63
|
+
column: number;
|
|
64
|
+
endLineNumber: number;
|
|
65
|
+
endColumn: number;
|
|
66
|
+
};
|
|
67
|
+
toString(): string;
|
|
68
|
+
}
|
|
69
|
+
declare class BoxNodeObject extends BoxNodeType$1<ObjectType> {
|
|
70
|
+
value: ObjectType['value'];
|
|
71
|
+
isEmpty: ObjectType['isEmpty'];
|
|
72
|
+
constructor(definition: ObjectType);
|
|
73
|
+
}
|
|
74
|
+
declare class BoxNodeLiteral extends BoxNodeType$1<LiteralType> {
|
|
75
|
+
value: LiteralType['value'];
|
|
76
|
+
kind: LiteralType['kind'];
|
|
77
|
+
constructor(definition: LiteralType);
|
|
78
|
+
}
|
|
79
|
+
declare class BoxNodeMap extends BoxNodeType$1<MapType> {
|
|
80
|
+
value: MapType['value'];
|
|
81
|
+
spreadConditions?: BoxNodeConditional[];
|
|
82
|
+
constructor(definition: MapType);
|
|
83
|
+
isRecipe: () => boolean;
|
|
84
|
+
}
|
|
85
|
+
declare class BoxNodeArray extends BoxNodeType$1<ArrayType> {
|
|
86
|
+
value: ArrayType['value'];
|
|
87
|
+
constructor(definition: ArrayType);
|
|
88
|
+
}
|
|
89
|
+
declare class BoxNodeUnresolvable extends BoxNodeType$1<UnresolvableType> {}
|
|
90
|
+
declare class BoxNodeConditional extends BoxNodeType$1<ConditionalType> {
|
|
91
|
+
whenTrue: ConditionalType['whenTrue'];
|
|
92
|
+
whenFalse: ConditionalType['whenFalse'];
|
|
93
|
+
constructor(definition: ConditionalType);
|
|
94
|
+
}
|
|
95
|
+
declare class BoxNodeEmptyInitializer extends BoxNodeType$1<EmptyInitializerType> {}
|
|
96
|
+
declare const isBoxNode: (value: unknown) => value is BoxNode;
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/types.d.ts
|
|
99
|
+
type PrimitiveType = string | number | boolean | null | undefined;
|
|
100
|
+
interface LiteralObject {
|
|
101
|
+
[key: string]: any;
|
|
102
|
+
}
|
|
103
|
+
type SingleLiteralValue = PrimitiveType | LiteralObject;
|
|
104
|
+
type LiteralValue = SingleLiteralValue | SingleLiteralValue[];
|
|
105
|
+
interface EvaluatedObjectResult {
|
|
106
|
+
[key: string]: LiteralValue;
|
|
107
|
+
}
|
|
108
|
+
interface ExtractedFunctionInstance {
|
|
109
|
+
name: string;
|
|
110
|
+
kind: 'call-expression';
|
|
111
|
+
fromNode: () => CallExpression;
|
|
112
|
+
box: BoxNodeArray;
|
|
113
|
+
}
|
|
114
|
+
interface ExtractedTaggedTemplateInstance {
|
|
115
|
+
name: string;
|
|
116
|
+
kind: 'tagged-template';
|
|
117
|
+
fromNode: () => TaggedTemplateExpression;
|
|
118
|
+
box: BoxNodeLiteral;
|
|
119
|
+
}
|
|
120
|
+
interface ExtractedFunctionResult {
|
|
121
|
+
kind: 'function';
|
|
122
|
+
nodesByProp: Map<string, BoxNode[]>;
|
|
123
|
+
queryList: Array<ExtractedFunctionInstance | ExtractedTaggedTemplateInstance>;
|
|
124
|
+
}
|
|
125
|
+
interface ExtractedComponentInstance {
|
|
126
|
+
name: string;
|
|
127
|
+
fromNode: () => JsxOpeningElement | JsxSelfClosingElement | CallExpression;
|
|
128
|
+
box: BoxNodeMap;
|
|
129
|
+
}
|
|
130
|
+
interface ExtractedComponentResult {
|
|
131
|
+
kind: 'component';
|
|
132
|
+
nodesByProp: Map<string, BoxNode[]>;
|
|
133
|
+
queryList: ExtractedComponentInstance[];
|
|
134
|
+
}
|
|
135
|
+
type ExtractResultItem = ExtractedComponentResult | ExtractedFunctionResult;
|
|
136
|
+
type ExtractResultByName = Map<string, ExtractResultItem>;
|
|
137
|
+
interface MatchTagArgs {
|
|
138
|
+
tagName: string;
|
|
139
|
+
tagNode: JsxOpeningElement | JsxSelfClosingElement | CallExpression;
|
|
140
|
+
isFactory: boolean;
|
|
141
|
+
}
|
|
142
|
+
interface MatchPropArgs {
|
|
143
|
+
propName: string;
|
|
144
|
+
propNode: JsxAttribute | PropertyAssignment | ShorthandPropertyAssignment | GetAccessorDeclaration | undefined;
|
|
145
|
+
}
|
|
146
|
+
interface MatchFnArgs {
|
|
147
|
+
fnName: string;
|
|
148
|
+
fnNode: CallExpression;
|
|
149
|
+
}
|
|
150
|
+
interface MatchFnArguments {
|
|
151
|
+
argNode: Node;
|
|
152
|
+
index: number;
|
|
153
|
+
}
|
|
154
|
+
interface MatchFnPropArgs {
|
|
155
|
+
propName: string;
|
|
156
|
+
propNode: PropertyAssignment | ShorthandPropertyAssignment | GetAccessorDeclaration;
|
|
157
|
+
}
|
|
158
|
+
interface FunctionMatchers {
|
|
159
|
+
matchFn: (element: MatchFnArgs) => boolean;
|
|
160
|
+
matchArg: (arg: Pick<MatchFnArgs, 'fnName' | 'fnNode'> & MatchFnArguments) => boolean;
|
|
161
|
+
matchProp: (prop: Pick<MatchFnArgs, 'fnName' | 'fnNode'> & MatchFnPropArgs) => boolean;
|
|
162
|
+
}
|
|
163
|
+
interface ComponentMatchers {
|
|
164
|
+
matchTag: (element: MatchTagArgs) => boolean;
|
|
165
|
+
matchProp: (prop: Pick<MatchTagArgs, 'tagName' | 'tagNode'> & MatchPropArgs) => boolean;
|
|
166
|
+
}
|
|
167
|
+
interface MatchTaggedTemplateArgs {
|
|
168
|
+
fnName: string;
|
|
169
|
+
taggedTemplateNode: TaggedTemplateExpression;
|
|
170
|
+
}
|
|
171
|
+
type MatchTaggedTemplate = (tag: MatchTaggedTemplateArgs) => boolean;
|
|
172
|
+
interface BoxContext {
|
|
173
|
+
getEvaluateOptions?: (node: Expression, stack: Node[]) => Omit<EvaluateOptions, 'node' | 'policy'> | void;
|
|
174
|
+
canEval?: (node: Expression, stack: Node[]) => boolean;
|
|
175
|
+
tokens?: {
|
|
176
|
+
view: {
|
|
177
|
+
get: (path: string, fallback?: string | number) => string | undefined;
|
|
178
|
+
getVar: (path: string, fallback?: string | number) => string | undefined;
|
|
179
|
+
};
|
|
180
|
+
isTokenFn?: (fnName: string) => boolean;
|
|
181
|
+
};
|
|
182
|
+
flags?: {
|
|
183
|
+
skipEvaluate?: boolean;
|
|
184
|
+
skipTraverseFiles?: boolean;
|
|
185
|
+
skipConditions?: boolean;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
type EvaluateOptions = Omit<EvaluateOptions$1, 'node' | 'policy'>;
|
|
189
|
+
type ExtractOptions = BoxContext & {
|
|
190
|
+
ast: SourceFile;
|
|
191
|
+
components?: ComponentMatchers;
|
|
192
|
+
functions?: FunctionMatchers;
|
|
193
|
+
taggedTemplates?: {
|
|
194
|
+
matchTaggedTemplate: MatchTaggedTemplate;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/to-box-node.d.ts
|
|
199
|
+
declare function toBoxNode<Value extends PrimitiveType>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral;
|
|
200
|
+
declare function toBoxNode<Value extends EvaluatedObjectResult>(value: Value, node: Node, stack: Node[]): BoxNodeObject;
|
|
201
|
+
declare function toBoxNode<Value extends PrimitiveType[]>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral[];
|
|
202
|
+
declare function toBoxNode<Value extends BoxNode | BoxNode[]>(value: Value, node: Node, stack: Node[]): Value;
|
|
203
|
+
declare function toBoxNode<Value extends LiteralValue>(value: Value, node: Node, stack: Node[]): Value extends unknown[] ? BoxNodeLiteral : Value extends PrimitiveType ? BoxNodeLiteral : BoxNodeObject;
|
|
204
|
+
declare function toBoxNode<Value extends PrimitiveType | BoxNode>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral;
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/box.d.ts
|
|
207
|
+
declare const box: {
|
|
208
|
+
object(value: EvaluatedObjectResult, node: Node, stack: Node[]): BoxNodeObject;
|
|
209
|
+
literal(value: PrimitiveType, node: Node, stack: Node[]): BoxNodeLiteral;
|
|
210
|
+
map(value: MapTypeValue, node: Node, stack: Node[]): BoxNodeMap;
|
|
211
|
+
array(value: BoxNode[], node: Node, stack: Node[]): BoxNodeArray;
|
|
212
|
+
conditional(whenTrue: BoxNode, whenFalse: BoxNode, node: Node, stack: Node[]): BoxNodeConditional;
|
|
213
|
+
from: typeof toBoxNode;
|
|
214
|
+
objectToMap: (value: Record<string, unknown>, node: Node, stack: Node[]) => BoxNodeMap;
|
|
215
|
+
emptyObject: (node: Node, stack: Node[]) => BoxNodeObject;
|
|
216
|
+
emptyInitializer: (node: Node, stack: Node[]) => BoxNodeEmptyInitializer;
|
|
217
|
+
unresolvable: (node: Node, stack: Node[]) => BoxNodeUnresolvable;
|
|
218
|
+
fallback(node: BoxNode): BoxNode;
|
|
219
|
+
/**
|
|
220
|
+
* box.type === “object” -> object that was resolved using ts-evaluator, most likely from a
|
|
221
|
+
* complex condition OR a simple CallExpression eval result, we don’t have access to individual
|
|
222
|
+
* AST nodes here so we need the distinction
|
|
223
|
+
*/
|
|
224
|
+
isObject(value: BoxNode | undefined): value is BoxNodeObject;
|
|
225
|
+
isLiteral(value: BoxNode | undefined): value is BoxNodeLiteral;
|
|
226
|
+
/**
|
|
227
|
+
* box.type === “map” -> basically any object that was statically analyzable, we store each
|
|
228
|
+
* prop + value in a Map
|
|
229
|
+
*/
|
|
230
|
+
isMap(value: BoxNode | undefined): value is BoxNodeMap;
|
|
231
|
+
isRecipe(value: BoxNode | undefined): value is BoxNodeMap;
|
|
232
|
+
isArray(value: BoxNode | undefined): value is BoxNodeArray;
|
|
233
|
+
isUnresolvable(value: BoxNode | undefined): value is BoxNodeUnresolvable;
|
|
234
|
+
isConditional(value: BoxNode | undefined): value is BoxNodeConditional;
|
|
235
|
+
isEmptyInitializer(value: BoxNode | undefined): value is BoxNodeEmptyInitializer;
|
|
236
|
+
isNumberLiteral(node: BoxNode | undefined): node is BoxNodeLiteral;
|
|
237
|
+
hasValue: (node: BoxNode | undefined) => node is BoxNodeLiteral | BoxNodeObject | BoxNodeMap | BoxNodeArray;
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/call-expression.d.ts
|
|
241
|
+
type MatchProp$1 = (prop: MatchFnPropArgs) => boolean;
|
|
242
|
+
type MatchArg = (prop: MatchFnArgs & MatchFnArguments) => boolean;
|
|
243
|
+
declare const extractCallExpressionArguments: (node: CallExpression, ctx: BoxContext, matchProp?: MatchProp$1, matchArg?: MatchArg) => BoxNodeArray;
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/extract.d.ts
|
|
246
|
+
declare const extract: ({
|
|
247
|
+
ast,
|
|
248
|
+
...ctx
|
|
249
|
+
}: ExtractOptions) => ExtractResultByName;
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/find-identifier-value-declaration.d.ts
|
|
252
|
+
declare function getDeclarationFor(node: Identifier, stack: Node[], ctx: BoxContext): VariableDeclaration | ParameterDeclaration | FunctionDeclaration | EnumDeclaration | BindingElement | undefined;
|
|
253
|
+
declare function findIdentifierValueDeclaration(identifier: Identifier, stack: Node[], ctx: BoxContext, visitedsWithStack?: WeakMap<Node, Node[]>): ReturnType<typeof getDeclarationFor> | undefined;
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/get-node-range.d.ts
|
|
256
|
+
declare const getNodeRange: (node: Node) => {
|
|
257
|
+
startPosition: number;
|
|
258
|
+
startLineNumber: number;
|
|
259
|
+
startColumn: number;
|
|
260
|
+
endPosition: number;
|
|
261
|
+
endLineNumber: number;
|
|
262
|
+
endColumn: number;
|
|
263
|
+
};
|
|
264
|
+
type NodeRange = ReturnType<typeof getNodeRange>;
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/jsx-attribute.d.ts
|
|
267
|
+
declare const extractJsxAttribute: (jsxAttribute: JsxAttribute, ctx: BoxContext) => BoxNode | undefined;
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region src/jsx-element-props.d.ts
|
|
270
|
+
declare const extractJsxElementProps: (node: JsxOpeningElement | JsxSelfClosingElement, ctx: BoxContext) => {
|
|
271
|
+
name: string;
|
|
272
|
+
props: Map<string, BoxNode>;
|
|
273
|
+
};
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/maybe-box-node.d.ts
|
|
276
|
+
/**
|
|
277
|
+
* Drops every memoized resolution.
|
|
278
|
+
*
|
|
279
|
+
* The cache is keyed on AST nodes, and a node's resolved value can depend on
|
|
280
|
+
* another file: `css(button)` folds whatever `./styles` exports. Editing that file
|
|
281
|
+
* replaces only its own nodes, so an importer's nodes stay identical and would
|
|
282
|
+
* otherwise keep serving the value read before the edit.
|
|
283
|
+
*/
|
|
284
|
+
declare const clearBoxNodeCache: () => void;
|
|
285
|
+
type MaybeBoxNodeReturn = BoxNode | undefined;
|
|
286
|
+
declare function maybeBoxNode(node: Node, stack: Node[], ctx: BoxContext, matchProp?: (prop: MatchFnPropArgs) => boolean): MaybeBoxNodeReturn;
|
|
287
|
+
declare const maybeIdentifierValue: (identifier: Identifier, _stack: Node[], ctx: BoxContext) => BoxNode;
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/jsx-spread-attribute.d.ts
|
|
290
|
+
type MatchProp = (prop: MatchFnPropArgs | MatchPropArgs) => boolean;
|
|
291
|
+
declare const extractJsxSpreadAttributeValues: (node: JsxSpreadAttribute, ctx: BoxContext, matchProp: MatchProp) => MaybeBoxNodeReturn;
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/unbox.d.ts
|
|
294
|
+
type BoxNodeType = BoxNode | BoxNode[] | undefined;
|
|
295
|
+
type CacheMap = WeakMap<BoxNode, Unboxed>;
|
|
296
|
+
interface UnboxContext {
|
|
297
|
+
path: string[];
|
|
298
|
+
parent: BoxNode | undefined;
|
|
299
|
+
cache: CacheMap;
|
|
300
|
+
/** @example <ColorBox color={unresolvableIdentifier ? "light.100" : "dark.200" } /> */
|
|
301
|
+
conditions: LiteralObject[];
|
|
302
|
+
/** @example <ColorBox {...(someCondition && { color: "blue.100" })} /> */
|
|
303
|
+
spreadConditions: LiteralObject[];
|
|
304
|
+
}
|
|
305
|
+
interface Unboxed {
|
|
306
|
+
raw: LiteralObject;
|
|
307
|
+
conditions: LiteralObject[];
|
|
308
|
+
spreadConditions: LiteralObject[];
|
|
309
|
+
}
|
|
310
|
+
declare const unbox: (node: BoxNodeType, ctx?: Pick<UnboxContext, "cache">) => Unboxed;
|
|
311
|
+
//#endregion
|
|
312
|
+
export { type BoxContext, type BoxNode, BoxNodeArray, BoxNodeConditional, BoxNodeEmptyInitializer, BoxNodeLiteral, BoxNodeMap, BoxNodeObject, BoxNodeUnresolvable, type EvaluateOptions, type ExtractOptions, type ExtractResultByName, type ExtractResultItem, type ExtractedComponentInstance, type ExtractedComponentResult, type ExtractedFunctionInstance, type ExtractedFunctionResult, type NodeRange, type PrimitiveType, type Unboxed, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { BindingElement, CallExpression, EnumDeclaration, Expression, FunctionDeclaration, GetAccessorDeclaration, Identifier, JsxAttribute, JsxOpeningElement, JsxSelfClosingElement, JsxSpreadAttribute, Node, ParameterDeclaration, PropertyAssignment, ShorthandPropertyAssignment, SourceFile, TaggedTemplateExpression, VariableDeclaration } from "ts-morph";
|
|
2
|
+
import { EvaluateOptions as EvaluateOptions$1 } from "ts-evaluator";
|
|
3
|
+
|
|
4
|
+
//#region src/box-factory.d.ts
|
|
5
|
+
interface WithNode {
|
|
6
|
+
node: Node;
|
|
7
|
+
stack: Node[];
|
|
8
|
+
}
|
|
9
|
+
interface ObjectType extends WithNode {
|
|
10
|
+
type: 'object';
|
|
11
|
+
value: EvaluatedObjectResult;
|
|
12
|
+
isEmpty?: boolean;
|
|
13
|
+
}
|
|
14
|
+
type LiteralKind = 'array' | 'string' | 'number' | 'boolean' | 'null' | 'undefined';
|
|
15
|
+
interface LiteralType extends WithNode {
|
|
16
|
+
type: 'literal';
|
|
17
|
+
value: PrimitiveType;
|
|
18
|
+
kind: LiteralKind;
|
|
19
|
+
}
|
|
20
|
+
interface MapType extends WithNode {
|
|
21
|
+
type: 'map';
|
|
22
|
+
value: MapTypeValue;
|
|
23
|
+
}
|
|
24
|
+
interface ArrayType extends WithNode {
|
|
25
|
+
type: 'array';
|
|
26
|
+
value: BoxNode[];
|
|
27
|
+
}
|
|
28
|
+
interface UnresolvableType extends WithNode {
|
|
29
|
+
type: 'unresolvable';
|
|
30
|
+
}
|
|
31
|
+
interface ConditionalType extends WithNode {
|
|
32
|
+
type: 'conditional';
|
|
33
|
+
whenTrue: BoxNode;
|
|
34
|
+
whenFalse: BoxNode;
|
|
35
|
+
}
|
|
36
|
+
/** -> Jsx boolean attribute <Box flex /> */
|
|
37
|
+
interface EmptyInitializerType extends WithNode {
|
|
38
|
+
type: 'empty-initializer';
|
|
39
|
+
}
|
|
40
|
+
type BoxNodeDefinition = ObjectType | LiteralType | MapType | ArrayType | UnresolvableType | ConditionalType | EmptyInitializerType;
|
|
41
|
+
type BoxNode = BoxNodeObject | BoxNodeLiteral | BoxNodeMap | BoxNodeArray | BoxNodeUnresolvable | BoxNodeConditional | BoxNodeEmptyInitializer;
|
|
42
|
+
type MapTypeValue = Map<string, BoxNode>;
|
|
43
|
+
declare abstract class BoxNodeType$1<Definition extends BoxNodeDefinition = BoxNodeDefinition> {
|
|
44
|
+
readonly type: Definition['type'];
|
|
45
|
+
private readonly stack;
|
|
46
|
+
private readonly node;
|
|
47
|
+
constructor(definition: Definition);
|
|
48
|
+
getNode(): Node;
|
|
49
|
+
getStack(): Node[];
|
|
50
|
+
getRange: () => {
|
|
51
|
+
startPosition: number;
|
|
52
|
+
startLineNumber: number;
|
|
53
|
+
startColumn: number;
|
|
54
|
+
endPosition: number;
|
|
55
|
+
endLineNumber: number;
|
|
56
|
+
endColumn: number;
|
|
57
|
+
};
|
|
58
|
+
toJSON(): {
|
|
59
|
+
type: Definition["type"];
|
|
60
|
+
value: any;
|
|
61
|
+
node: string;
|
|
62
|
+
line: number;
|
|
63
|
+
column: number;
|
|
64
|
+
endLineNumber: number;
|
|
65
|
+
endColumn: number;
|
|
66
|
+
};
|
|
67
|
+
toString(): string;
|
|
68
|
+
}
|
|
69
|
+
declare class BoxNodeObject extends BoxNodeType$1<ObjectType> {
|
|
70
|
+
value: ObjectType['value'];
|
|
71
|
+
isEmpty: ObjectType['isEmpty'];
|
|
72
|
+
constructor(definition: ObjectType);
|
|
73
|
+
}
|
|
74
|
+
declare class BoxNodeLiteral extends BoxNodeType$1<LiteralType> {
|
|
75
|
+
value: LiteralType['value'];
|
|
76
|
+
kind: LiteralType['kind'];
|
|
77
|
+
constructor(definition: LiteralType);
|
|
78
|
+
}
|
|
79
|
+
declare class BoxNodeMap extends BoxNodeType$1<MapType> {
|
|
80
|
+
value: MapType['value'];
|
|
81
|
+
spreadConditions?: BoxNodeConditional[];
|
|
82
|
+
constructor(definition: MapType);
|
|
83
|
+
isRecipe: () => boolean;
|
|
84
|
+
}
|
|
85
|
+
declare class BoxNodeArray extends BoxNodeType$1<ArrayType> {
|
|
86
|
+
value: ArrayType['value'];
|
|
87
|
+
constructor(definition: ArrayType);
|
|
88
|
+
}
|
|
89
|
+
declare class BoxNodeUnresolvable extends BoxNodeType$1<UnresolvableType> {}
|
|
90
|
+
declare class BoxNodeConditional extends BoxNodeType$1<ConditionalType> {
|
|
91
|
+
whenTrue: ConditionalType['whenTrue'];
|
|
92
|
+
whenFalse: ConditionalType['whenFalse'];
|
|
93
|
+
constructor(definition: ConditionalType);
|
|
94
|
+
}
|
|
95
|
+
declare class BoxNodeEmptyInitializer extends BoxNodeType$1<EmptyInitializerType> {}
|
|
96
|
+
declare const isBoxNode: (value: unknown) => value is BoxNode;
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/types.d.ts
|
|
99
|
+
type PrimitiveType = string | number | boolean | null | undefined;
|
|
100
|
+
interface LiteralObject {
|
|
101
|
+
[key: string]: any;
|
|
102
|
+
}
|
|
103
|
+
type SingleLiteralValue = PrimitiveType | LiteralObject;
|
|
104
|
+
type LiteralValue = SingleLiteralValue | SingleLiteralValue[];
|
|
105
|
+
interface EvaluatedObjectResult {
|
|
106
|
+
[key: string]: LiteralValue;
|
|
107
|
+
}
|
|
108
|
+
interface ExtractedFunctionInstance {
|
|
109
|
+
name: string;
|
|
110
|
+
kind: 'call-expression';
|
|
111
|
+
fromNode: () => CallExpression;
|
|
112
|
+
box: BoxNodeArray;
|
|
113
|
+
}
|
|
114
|
+
interface ExtractedTaggedTemplateInstance {
|
|
115
|
+
name: string;
|
|
116
|
+
kind: 'tagged-template';
|
|
117
|
+
fromNode: () => TaggedTemplateExpression;
|
|
118
|
+
box: BoxNodeLiteral;
|
|
119
|
+
}
|
|
120
|
+
interface ExtractedFunctionResult {
|
|
121
|
+
kind: 'function';
|
|
122
|
+
nodesByProp: Map<string, BoxNode[]>;
|
|
123
|
+
queryList: Array<ExtractedFunctionInstance | ExtractedTaggedTemplateInstance>;
|
|
124
|
+
}
|
|
125
|
+
interface ExtractedComponentInstance {
|
|
126
|
+
name: string;
|
|
127
|
+
fromNode: () => JsxOpeningElement | JsxSelfClosingElement | CallExpression;
|
|
128
|
+
box: BoxNodeMap;
|
|
129
|
+
}
|
|
130
|
+
interface ExtractedComponentResult {
|
|
131
|
+
kind: 'component';
|
|
132
|
+
nodesByProp: Map<string, BoxNode[]>;
|
|
133
|
+
queryList: ExtractedComponentInstance[];
|
|
134
|
+
}
|
|
135
|
+
type ExtractResultItem = ExtractedComponentResult | ExtractedFunctionResult;
|
|
136
|
+
type ExtractResultByName = Map<string, ExtractResultItem>;
|
|
137
|
+
interface MatchTagArgs {
|
|
138
|
+
tagName: string;
|
|
139
|
+
tagNode: JsxOpeningElement | JsxSelfClosingElement | CallExpression;
|
|
140
|
+
isFactory: boolean;
|
|
141
|
+
}
|
|
142
|
+
interface MatchPropArgs {
|
|
143
|
+
propName: string;
|
|
144
|
+
propNode: JsxAttribute | PropertyAssignment | ShorthandPropertyAssignment | GetAccessorDeclaration | undefined;
|
|
145
|
+
}
|
|
146
|
+
interface MatchFnArgs {
|
|
147
|
+
fnName: string;
|
|
148
|
+
fnNode: CallExpression;
|
|
149
|
+
}
|
|
150
|
+
interface MatchFnArguments {
|
|
151
|
+
argNode: Node;
|
|
152
|
+
index: number;
|
|
153
|
+
}
|
|
154
|
+
interface MatchFnPropArgs {
|
|
155
|
+
propName: string;
|
|
156
|
+
propNode: PropertyAssignment | ShorthandPropertyAssignment | GetAccessorDeclaration;
|
|
157
|
+
}
|
|
158
|
+
interface FunctionMatchers {
|
|
159
|
+
matchFn: (element: MatchFnArgs) => boolean;
|
|
160
|
+
matchArg: (arg: Pick<MatchFnArgs, 'fnName' | 'fnNode'> & MatchFnArguments) => boolean;
|
|
161
|
+
matchProp: (prop: Pick<MatchFnArgs, 'fnName' | 'fnNode'> & MatchFnPropArgs) => boolean;
|
|
162
|
+
}
|
|
163
|
+
interface ComponentMatchers {
|
|
164
|
+
matchTag: (element: MatchTagArgs) => boolean;
|
|
165
|
+
matchProp: (prop: Pick<MatchTagArgs, 'tagName' | 'tagNode'> & MatchPropArgs) => boolean;
|
|
166
|
+
}
|
|
167
|
+
interface MatchTaggedTemplateArgs {
|
|
168
|
+
fnName: string;
|
|
169
|
+
taggedTemplateNode: TaggedTemplateExpression;
|
|
170
|
+
}
|
|
171
|
+
type MatchTaggedTemplate = (tag: MatchTaggedTemplateArgs) => boolean;
|
|
172
|
+
interface BoxContext {
|
|
173
|
+
getEvaluateOptions?: (node: Expression, stack: Node[]) => Omit<EvaluateOptions, 'node' | 'policy'> | void;
|
|
174
|
+
canEval?: (node: Expression, stack: Node[]) => boolean;
|
|
175
|
+
tokens?: {
|
|
176
|
+
view: {
|
|
177
|
+
get: (path: string, fallback?: string | number) => string | undefined;
|
|
178
|
+
getVar: (path: string, fallback?: string | number) => string | undefined;
|
|
179
|
+
};
|
|
180
|
+
isTokenFn?: (fnName: string) => boolean;
|
|
181
|
+
};
|
|
182
|
+
flags?: {
|
|
183
|
+
skipEvaluate?: boolean;
|
|
184
|
+
skipTraverseFiles?: boolean;
|
|
185
|
+
skipConditions?: boolean;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
type EvaluateOptions = Omit<EvaluateOptions$1, 'node' | 'policy'>;
|
|
189
|
+
type ExtractOptions = BoxContext & {
|
|
190
|
+
ast: SourceFile;
|
|
191
|
+
components?: ComponentMatchers;
|
|
192
|
+
functions?: FunctionMatchers;
|
|
193
|
+
taggedTemplates?: {
|
|
194
|
+
matchTaggedTemplate: MatchTaggedTemplate;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/to-box-node.d.ts
|
|
199
|
+
declare function toBoxNode<Value extends PrimitiveType>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral;
|
|
200
|
+
declare function toBoxNode<Value extends EvaluatedObjectResult>(value: Value, node: Node, stack: Node[]): BoxNodeObject;
|
|
201
|
+
declare function toBoxNode<Value extends PrimitiveType[]>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral[];
|
|
202
|
+
declare function toBoxNode<Value extends BoxNode | BoxNode[]>(value: Value, node: Node, stack: Node[]): Value;
|
|
203
|
+
declare function toBoxNode<Value extends LiteralValue>(value: Value, node: Node, stack: Node[]): Value extends unknown[] ? BoxNodeLiteral : Value extends PrimitiveType ? BoxNodeLiteral : BoxNodeObject;
|
|
204
|
+
declare function toBoxNode<Value extends PrimitiveType | BoxNode>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral;
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/box.d.ts
|
|
207
|
+
declare const box: {
|
|
208
|
+
object(value: EvaluatedObjectResult, node: Node, stack: Node[]): BoxNodeObject;
|
|
209
|
+
literal(value: PrimitiveType, node: Node, stack: Node[]): BoxNodeLiteral;
|
|
210
|
+
map(value: MapTypeValue, node: Node, stack: Node[]): BoxNodeMap;
|
|
211
|
+
array(value: BoxNode[], node: Node, stack: Node[]): BoxNodeArray;
|
|
212
|
+
conditional(whenTrue: BoxNode, whenFalse: BoxNode, node: Node, stack: Node[]): BoxNodeConditional;
|
|
213
|
+
from: typeof toBoxNode;
|
|
214
|
+
objectToMap: (value: Record<string, unknown>, node: Node, stack: Node[]) => BoxNodeMap;
|
|
215
|
+
emptyObject: (node: Node, stack: Node[]) => BoxNodeObject;
|
|
216
|
+
emptyInitializer: (node: Node, stack: Node[]) => BoxNodeEmptyInitializer;
|
|
217
|
+
unresolvable: (node: Node, stack: Node[]) => BoxNodeUnresolvable;
|
|
218
|
+
fallback(node: BoxNode): BoxNode;
|
|
219
|
+
/**
|
|
220
|
+
* box.type === “object” -> object that was resolved using ts-evaluator, most likely from a
|
|
221
|
+
* complex condition OR a simple CallExpression eval result, we don’t have access to individual
|
|
222
|
+
* AST nodes here so we need the distinction
|
|
223
|
+
*/
|
|
224
|
+
isObject(value: BoxNode | undefined): value is BoxNodeObject;
|
|
225
|
+
isLiteral(value: BoxNode | undefined): value is BoxNodeLiteral;
|
|
226
|
+
/**
|
|
227
|
+
* box.type === “map” -> basically any object that was statically analyzable, we store each
|
|
228
|
+
* prop + value in a Map
|
|
229
|
+
*/
|
|
230
|
+
isMap(value: BoxNode | undefined): value is BoxNodeMap;
|
|
231
|
+
isRecipe(value: BoxNode | undefined): value is BoxNodeMap;
|
|
232
|
+
isArray(value: BoxNode | undefined): value is BoxNodeArray;
|
|
233
|
+
isUnresolvable(value: BoxNode | undefined): value is BoxNodeUnresolvable;
|
|
234
|
+
isConditional(value: BoxNode | undefined): value is BoxNodeConditional;
|
|
235
|
+
isEmptyInitializer(value: BoxNode | undefined): value is BoxNodeEmptyInitializer;
|
|
236
|
+
isNumberLiteral(node: BoxNode | undefined): node is BoxNodeLiteral;
|
|
237
|
+
hasValue: (node: BoxNode | undefined) => node is BoxNodeLiteral | BoxNodeObject | BoxNodeMap | BoxNodeArray;
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/call-expression.d.ts
|
|
241
|
+
type MatchProp$1 = (prop: MatchFnPropArgs) => boolean;
|
|
242
|
+
type MatchArg = (prop: MatchFnArgs & MatchFnArguments) => boolean;
|
|
243
|
+
declare const extractCallExpressionArguments: (node: CallExpression, ctx: BoxContext, matchProp?: MatchProp$1, matchArg?: MatchArg) => BoxNodeArray;
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/extract.d.ts
|
|
246
|
+
declare const extract: ({
|
|
247
|
+
ast,
|
|
248
|
+
...ctx
|
|
249
|
+
}: ExtractOptions) => ExtractResultByName;
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/find-identifier-value-declaration.d.ts
|
|
252
|
+
declare function getDeclarationFor(node: Identifier, stack: Node[], ctx: BoxContext): VariableDeclaration | ParameterDeclaration | FunctionDeclaration | EnumDeclaration | BindingElement | undefined;
|
|
253
|
+
declare function findIdentifierValueDeclaration(identifier: Identifier, stack: Node[], ctx: BoxContext, visitedsWithStack?: WeakMap<Node, Node[]>): ReturnType<typeof getDeclarationFor> | undefined;
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/get-node-range.d.ts
|
|
256
|
+
declare const getNodeRange: (node: Node) => {
|
|
257
|
+
startPosition: number;
|
|
258
|
+
startLineNumber: number;
|
|
259
|
+
startColumn: number;
|
|
260
|
+
endPosition: number;
|
|
261
|
+
endLineNumber: number;
|
|
262
|
+
endColumn: number;
|
|
263
|
+
};
|
|
264
|
+
type NodeRange = ReturnType<typeof getNodeRange>;
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/jsx-attribute.d.ts
|
|
267
|
+
declare const extractJsxAttribute: (jsxAttribute: JsxAttribute, ctx: BoxContext) => BoxNode | undefined;
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region src/jsx-element-props.d.ts
|
|
270
|
+
declare const extractJsxElementProps: (node: JsxOpeningElement | JsxSelfClosingElement, ctx: BoxContext) => {
|
|
271
|
+
name: string;
|
|
272
|
+
props: Map<string, BoxNode>;
|
|
273
|
+
};
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/maybe-box-node.d.ts
|
|
276
|
+
/**
|
|
277
|
+
* Drops every memoized resolution.
|
|
278
|
+
*
|
|
279
|
+
* The cache is keyed on AST nodes, and a node's resolved value can depend on
|
|
280
|
+
* another file: `css(button)` folds whatever `./styles` exports. Editing that file
|
|
281
|
+
* replaces only its own nodes, so an importer's nodes stay identical and would
|
|
282
|
+
* otherwise keep serving the value read before the edit.
|
|
283
|
+
*/
|
|
284
|
+
declare const clearBoxNodeCache: () => void;
|
|
285
|
+
type MaybeBoxNodeReturn = BoxNode | undefined;
|
|
286
|
+
declare function maybeBoxNode(node: Node, stack: Node[], ctx: BoxContext, matchProp?: (prop: MatchFnPropArgs) => boolean): MaybeBoxNodeReturn;
|
|
287
|
+
declare const maybeIdentifierValue: (identifier: Identifier, _stack: Node[], ctx: BoxContext) => BoxNode;
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/jsx-spread-attribute.d.ts
|
|
290
|
+
type MatchProp = (prop: MatchFnPropArgs | MatchPropArgs) => boolean;
|
|
291
|
+
declare const extractJsxSpreadAttributeValues: (node: JsxSpreadAttribute, ctx: BoxContext, matchProp: MatchProp) => MaybeBoxNodeReturn;
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/unbox.d.ts
|
|
294
|
+
type BoxNodeType = BoxNode | BoxNode[] | undefined;
|
|
295
|
+
type CacheMap = WeakMap<BoxNode, Unboxed>;
|
|
296
|
+
interface UnboxContext {
|
|
297
|
+
path: string[];
|
|
298
|
+
parent: BoxNode | undefined;
|
|
299
|
+
cache: CacheMap;
|
|
300
|
+
/** @example <ColorBox color={unresolvableIdentifier ? "light.100" : "dark.200" } /> */
|
|
301
|
+
conditions: LiteralObject[];
|
|
302
|
+
/** @example <ColorBox {...(someCondition && { color: "blue.100" })} /> */
|
|
303
|
+
spreadConditions: LiteralObject[];
|
|
304
|
+
}
|
|
305
|
+
interface Unboxed {
|
|
306
|
+
raw: LiteralObject;
|
|
307
|
+
conditions: LiteralObject[];
|
|
308
|
+
spreadConditions: LiteralObject[];
|
|
309
|
+
}
|
|
310
|
+
declare const unbox: (node: BoxNodeType, ctx?: Pick<UnboxContext, "cache">) => Unboxed;
|
|
311
|
+
//#endregion
|
|
312
|
+
export { type BoxContext, type BoxNode, BoxNodeArray, BoxNodeConditional, BoxNodeEmptyInitializer, BoxNodeLiteral, BoxNodeMap, BoxNodeObject, BoxNodeUnresolvable, type EvaluateOptions, type ExtractOptions, type ExtractResultByName, type ExtractResultItem, type ExtractedComponentInstance, type ExtractedComponentResult, type ExtractedFunctionInstance, type ExtractedFunctionResult, type NodeRange, type PrimitiveType, type Unboxed, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox };
|
package/dist/index.mjs
CHANGED
|
@@ -335,12 +335,12 @@ function getDeclarationFor(node, stack, ctx) {
|
|
|
335
335
|
if ((Node.isVariableDeclaration(parent) || Node.isParameterDeclaration(parent) || Node.isFunctionDeclaration(parent) || Node.isEnumDeclaration(parent) || Node.isBindingElement(parent)) && parent.getNameNode() == node) {
|
|
336
336
|
declarationStack.push(parent);
|
|
337
337
|
declaration = parent;
|
|
338
|
-
} else if (Node.isImportSpecifier(parent) && parent.getNameNode() == node) {
|
|
338
|
+
} else if (Node.isImportSpecifier(parent) && (parent.getNameNode() == node || parent.getAliasNode() == node)) {
|
|
339
339
|
if (ctx.flags?.skipTraverseFiles) return;
|
|
340
340
|
const sourceFile = getModuleSpecifierSourceFile(parent.getImportDeclaration());
|
|
341
341
|
if (sourceFile) {
|
|
342
342
|
const exportStack = [parent, sourceFile];
|
|
343
|
-
const maybeVar = getExportedVarDeclarationWithName(
|
|
343
|
+
const maybeVar = getExportedVarDeclarationWithName(parent.getNameNode().getText(), sourceFile, exportStack, ctx);
|
|
344
344
|
if (maybeVar) {
|
|
345
345
|
declarationStack.push(...exportStack.concat(maybeVar));
|
|
346
346
|
declaration = maybeVar;
|
|
@@ -507,9 +507,23 @@ const getObjectLiteralExpressionPropPairs = (expression, expressionStack, ctx, m
|
|
|
507
507
|
};
|
|
508
508
|
//#endregion
|
|
509
509
|
//#region src/maybe-box-node.ts
|
|
510
|
-
|
|
510
|
+
let cacheMap$1 = /* @__PURE__ */ new WeakMap();
|
|
511
511
|
const isCached = (node) => cacheMap$1.has(node);
|
|
512
512
|
const getCached = (node) => cacheMap$1.get(node);
|
|
513
|
+
/**
|
|
514
|
+
* Drops every memoized resolution.
|
|
515
|
+
*
|
|
516
|
+
* The cache is keyed on AST nodes, and a node's resolved value can depend on
|
|
517
|
+
* another file: `css(button)` folds whatever `./styles` exports. Editing that file
|
|
518
|
+
* replaces only its own nodes, so an importer's nodes stay identical and would
|
|
519
|
+
* otherwise keep serving the value read before the edit.
|
|
520
|
+
*/
|
|
521
|
+
const clearBoxNodeCache = () => {
|
|
522
|
+
if (!hasCachedEntries) return;
|
|
523
|
+
cacheMap$1 = /* @__PURE__ */ new WeakMap();
|
|
524
|
+
hasCachedEntries = false;
|
|
525
|
+
};
|
|
526
|
+
let hasCachedEntries = false;
|
|
513
527
|
const isPlusSyntax = (op) => op === ts.SyntaxKind.PlusToken;
|
|
514
528
|
const isLogicalSyntax = (op) => op === ts.SyntaxKind.BarBarToken || op === ts.SyntaxKind.QuestionQuestionToken || op === ts.SyntaxKind.AmpersandAmpersandToken || op === ts.SyntaxKind.EqualsEqualsEqualsToken || op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsToken || op === ts.SyntaxKind.GreaterThanEqualsToken || op === ts.SyntaxKind.GreaterThanToken || op === ts.SyntaxKind.LessThanEqualsToken || op === ts.SyntaxKind.LessThanToken || op === ts.SyntaxKind.InstanceOfKeyword || op === ts.SyntaxKind.InKeyword;
|
|
515
529
|
const isOperationSyntax = (op) => op === ts.SyntaxKind.AsteriskToken || op === ts.SyntaxKind.SlashToken || op === ts.SyntaxKind.PercentToken || op === ts.SyntaxKind.AsteriskAsteriskToken || op === ts.SyntaxKind.MinusToken;
|
|
@@ -519,6 +533,7 @@ const canReturnWhenTrueInLogicalExpression = (op) => {
|
|
|
519
533
|
function maybeBoxNode(node, stack, ctx, matchProp) {
|
|
520
534
|
const cache = (value) => {
|
|
521
535
|
cacheMap$1.set(node, value);
|
|
536
|
+
hasCachedEntries = true;
|
|
522
537
|
return value;
|
|
523
538
|
};
|
|
524
539
|
if (isCached(node)) return getCached(node);
|
|
@@ -915,17 +930,29 @@ const maybeDefinitionValue = (def, stack, ctx) => {
|
|
|
915
930
|
if (maybeValue) return maybeValue;
|
|
916
931
|
}
|
|
917
932
|
};
|
|
918
|
-
const getExportedVarDeclarationWithName = (varName, sourceFile, stack, ctx) => {
|
|
933
|
+
const getExportedVarDeclarationWithName = (varName, sourceFile, stack, ctx, visited = /* @__PURE__ */ new Set()) => {
|
|
934
|
+
const key = `${sourceFile.getFilePath()}:${varName}`;
|
|
935
|
+
if (visited.has(key)) return;
|
|
936
|
+
visited.add(key);
|
|
919
937
|
const maybeVar = sourceFile.getVariableDeclaration(varName);
|
|
920
938
|
if (maybeVar) return maybeVar;
|
|
921
|
-
const exportDeclaration = resolveVarDeclarationFromExportWithName(varName, sourceFile, stack, ctx);
|
|
939
|
+
const exportDeclaration = resolveVarDeclarationFromExportWithName(varName, sourceFile, stack, ctx, visited);
|
|
922
940
|
if (!exportDeclaration) return;
|
|
923
941
|
return exportDeclaration;
|
|
924
942
|
};
|
|
925
|
-
|
|
943
|
+
/**
|
|
944
|
+
* Given the name a module exposes, the name to look for in the module it came from.
|
|
945
|
+
* Returns `undefined` when this declaration does not provide `name` at all.
|
|
946
|
+
*
|
|
947
|
+
* For `export { btn as button } from './styles'` the two differ: `getAliasNode()`
|
|
948
|
+
* is `button`, the name this module exports, and `getNameNode()` is `btn`, the name
|
|
949
|
+
* to search for in `./styles`. Matching on the wrong one both hides names the
|
|
950
|
+
* module does export and resolves names it does not.
|
|
951
|
+
*/
|
|
952
|
+
const resolveExportedName = (name, exportDeclaration) => {
|
|
926
953
|
const namedExports = exportDeclaration.getNamedExports();
|
|
927
|
-
if (namedExports.length === 0) return
|
|
928
|
-
for (const namedExport of namedExports) if (namedExport.getNameNode().getText() === name) return
|
|
954
|
+
if (namedExports.length === 0) return name;
|
|
955
|
+
for (const namedExport of namedExports) if ((namedExport.getAliasNode() ?? namedExport.getNameNode()).getText() === name) return namedExport.getNameNode().getText();
|
|
929
956
|
};
|
|
930
957
|
/**
|
|
931
958
|
* Faster than declaration.getModuleSpecifierSourceFile()
|
|
@@ -945,14 +972,22 @@ const getModuleSpecifierSourceFile = (declaration) => {
|
|
|
945
972
|
if (!resolved.resolvedModule) return;
|
|
946
973
|
return project.addSourceFileAtPath(resolved.resolvedModule.resolvedFileName);
|
|
947
974
|
};
|
|
948
|
-
function resolveVarDeclarationFromExportWithName(symbolName, sourceFile, stack, ctx) {
|
|
975
|
+
function resolveVarDeclarationFromExportWithName(symbolName, sourceFile, stack, ctx, visited) {
|
|
949
976
|
for (const exportDeclaration of sourceFile.getExportDeclarations()) {
|
|
950
977
|
const exportStack = [exportDeclaration];
|
|
951
|
-
|
|
978
|
+
const sourceName = resolveExportedName(symbolName, exportDeclaration);
|
|
979
|
+
if (sourceName === void 0) continue;
|
|
952
980
|
const maybeFile = getModuleSpecifierSourceFile(exportDeclaration);
|
|
953
|
-
if (!maybeFile)
|
|
981
|
+
if (!maybeFile) {
|
|
982
|
+
const localVar = sourceFile.getVariableDeclaration(sourceName);
|
|
983
|
+
if (localVar) {
|
|
984
|
+
stack.push(...exportStack.concat(localVar));
|
|
985
|
+
return localVar;
|
|
986
|
+
}
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
954
989
|
exportStack.push(maybeFile);
|
|
955
|
-
const maybeVar = getExportedVarDeclarationWithName(
|
|
990
|
+
const maybeVar = getExportedVarDeclarationWithName(sourceName, maybeFile, stack, ctx, visited);
|
|
956
991
|
if (maybeVar) {
|
|
957
992
|
stack.push(...exportStack.concat(maybeVar));
|
|
958
993
|
return maybeVar;
|
|
@@ -1811,4 +1846,4 @@ const unbox = (node, ctx) => {
|
|
|
1811
1846
|
return result;
|
|
1812
1847
|
};
|
|
1813
1848
|
//#endregion
|
|
1814
|
-
export { BoxNodeArray, BoxNodeConditional, BoxNodeEmptyInitializer, BoxNodeLiteral, BoxNodeMap, BoxNodeObject, BoxNodeUnresolvable, box, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox };
|
|
1849
|
+
export { BoxNodeArray, BoxNodeConditional, BoxNodeEmptyInitializer, BoxNodeLiteral, BoxNodeMap, BoxNodeObject, BoxNodeUnresolvable, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox };
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bamboocss/extractor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.1",
|
|
4
4
|
"description": "The css extractor for css bamboo",
|
|
5
|
-
"homepage": "https://
|
|
5
|
+
"homepage": "https://bamboocss.com",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"author": "
|
|
7
|
+
"author": "Gajus Kuizinas <gajus@gajus.com>",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/bamboocss/bamboo.git",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"ts-evaluator": "1.2.0",
|
|
37
37
|
"ts-morph": "28.0.0",
|
|
38
|
-
"@bamboocss/shared": "1.
|
|
38
|
+
"@bamboocss/shared": "1.13.1"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsdown src/index.ts --format=cjs,esm --shims --dts",
|