@bamboocss/extractor 1.46.1 → 1.46.3
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/index.cjs +39 -0
- package/dist/index.d.cts +21 -1
- package/dist/index.d.mts +21 -1
- package/dist/index.mjs +38 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -311,6 +311,37 @@ const EMPTY_DEPENDENCIES = [];
|
|
|
311
311
|
/** One synchronous extraction context owns one nested capture stack. */
|
|
312
312
|
const trackers = /* @__PURE__ */ new WeakMap();
|
|
313
313
|
/**
|
|
314
|
+
* Per-path staleness, so an edit invalidates exactly the entries that read the edited file.
|
|
315
|
+
*
|
|
316
|
+
* The caches these entries live in are `WeakMap`s keyed on AST nodes — deliberately, so a
|
|
317
|
+
* retired tree releases its memory — which means they cannot be swept. What they *can* do is
|
|
318
|
+
* refuse a hit: every entry already records the module paths its computation read, because
|
|
319
|
+
* that same record is what the watch system replays into fold dependencies. Stamping entries
|
|
320
|
+
* with a creation generation and bumping a per-path generation on each edit turns the
|
|
321
|
+
* recorded read-set into a validity check, evaluated lazily at lookup.
|
|
322
|
+
*
|
|
323
|
+
* The trust base is unchanged. If a cross-file read were missing from `dependencies`, the
|
|
324
|
+
* fold's watch edges would already be missing it, and editing that file would fail to
|
|
325
|
+
* re-transform its consumers today — the recorded read-set is load-bearing for invalidation
|
|
326
|
+
* breadth before it is for cache validity.
|
|
327
|
+
*
|
|
328
|
+
* An entry's *own* file needs no record: reloading or overwriting a file re-parses it, which
|
|
329
|
+
* retires every node previously taken from it, and a retired node can never be a lookup key
|
|
330
|
+
* again. Only cross-file reads can go stale while the key survives, and those are exactly
|
|
331
|
+
* what the capture records.
|
|
332
|
+
*
|
|
333
|
+
* File-tree changes are not handled here at all: a created or deleted file can change what a
|
|
334
|
+
* specifier *resolves to* without any recorded path's content moving, so those events keep
|
|
335
|
+
* clearing the caches outright, exactly as before.
|
|
336
|
+
*/
|
|
337
|
+
let dependencyGeneration = 1;
|
|
338
|
+
const invalidatedAt = /* @__PURE__ */ new Map();
|
|
339
|
+
/** Mark one edited file's content stale for every cache entry that recorded reading it. */
|
|
340
|
+
const invalidateDependencyPath = (filePath) => {
|
|
341
|
+
dependencyGeneration++;
|
|
342
|
+
invalidatedAt.set(filePath.replaceAll("\\", "/"), dependencyGeneration);
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
314
345
|
* Attribute one resolved local module to every cache computation currently enclosing it.
|
|
315
346
|
*
|
|
316
347
|
* Paths, rather than SourceFile objects, are the replay payload. A source replacement may
|
|
@@ -341,6 +372,7 @@ const beginDependencyCapture = (ctx) => {
|
|
|
341
372
|
return {
|
|
342
373
|
dependencies: frame.dependencies ? [...frame.dependencies].sort() : EMPTY_DEPENDENCIES,
|
|
343
374
|
resolveModule: ctx.resolveModule,
|
|
375
|
+
generation: dependencyGeneration,
|
|
344
376
|
value
|
|
345
377
|
};
|
|
346
378
|
},
|
|
@@ -358,6 +390,10 @@ const beginDependencyCapture = (ctx) => {
|
|
|
358
390
|
*/
|
|
359
391
|
const replayDependencyCache = (entry, ctx) => {
|
|
360
392
|
if (entry.resolveModule !== ctx.resolveModule) return { hit: false };
|
|
393
|
+
for (const dependency of entry.dependencies) {
|
|
394
|
+
const at = invalidatedAt.get(dependency);
|
|
395
|
+
if (at !== void 0 && at > entry.generation) return { hit: false };
|
|
396
|
+
}
|
|
361
397
|
for (const dependency of entry.dependencies) recordModuleDependency(ctx, dependency);
|
|
362
398
|
return {
|
|
363
399
|
hit: true,
|
|
@@ -1248,6 +1284,7 @@ const maybeDefinitionValue = (def, stack, ctx) => {
|
|
|
1248
1284
|
}
|
|
1249
1285
|
};
|
|
1250
1286
|
const getExportedVarDeclarationWithName = (varName, sourceFile, stack, ctx, visited = /* @__PURE__ */ new Set()) => {
|
|
1287
|
+
ctx.recordExportRead?.(sourceFile.getFilePath(), varName);
|
|
1251
1288
|
const key = `${sourceFile.getFilePath()}:${varName}`;
|
|
1252
1289
|
if (visited.has(key)) return;
|
|
1253
1290
|
visited.add(key);
|
|
@@ -2211,6 +2248,8 @@ exports.extractJsxAttribute = extractJsxAttribute;
|
|
|
2211
2248
|
exports.extractJsxElementProps = extractJsxElementProps;
|
|
2212
2249
|
exports.extractJsxSpreadAttributeValues = extractJsxSpreadAttributeValues;
|
|
2213
2250
|
exports.findIdentifierValueDeclaration = findIdentifierValueDeclaration;
|
|
2251
|
+
exports.getExportedVarDeclarationWithName = getExportedVarDeclarationWithName;
|
|
2252
|
+
exports.invalidateDependencyPath = invalidateDependencyPath;
|
|
2214
2253
|
exports.isBoxNode = isBoxNode;
|
|
2215
2254
|
exports.maybeBoxNode = maybeBoxNode;
|
|
2216
2255
|
exports.maybeIdentifierValue = maybeIdentifierValue;
|
package/dist/index.d.cts
CHANGED
|
@@ -196,6 +196,8 @@ interface BoxContext {
|
|
|
196
196
|
resolveModule?: ResolveModule;
|
|
197
197
|
/** @internal Receives local source paths crossed by this exact extraction context. */
|
|
198
198
|
recordDependency?: (filePath: string) => void;
|
|
199
|
+
/** @internal Receives every `(module, exportedName)` a cross-file value resolution visited. */
|
|
200
|
+
recordExportRead?: (filePath: string, exportedName: string) => void;
|
|
199
201
|
getEvaluateOptions?: (node: Expression, stack: Node[]) => Omit<EvaluateOptions, 'node' | 'policy'> | void;
|
|
200
202
|
canEval?: (node: Expression, stack: Node[]) => boolean;
|
|
201
203
|
tokens?: {
|
|
@@ -307,6 +309,20 @@ declare const extractJsxElementProps: (node: JsxOpeningElement | JsxSelfClosingE
|
|
|
307
309
|
declare const clearBoxNodeCache: () => void;
|
|
308
310
|
type MaybeBoxNodeReturn = BoxNode | undefined;
|
|
309
311
|
declare function maybeBoxNode(node: Node, stack: Node[], ctx: BoxContext, matchProp?: (prop: MatchFnPropArgs) => boolean): MaybeBoxNodeReturn;
|
|
312
|
+
declare const getExportedVarDeclarationWithName: (varName: string, sourceFile: SourceFile, stack: Node[], ctx: BoxContext,
|
|
313
|
+
/**
|
|
314
|
+
* The `(file, name)` pairs already searched, so a cycle of re-exporting files
|
|
315
|
+
* terminates. Re-exports can form one — including a barrel that re-exports
|
|
316
|
+
* itself — and a name that never resolves inside the cycle would otherwise walk
|
|
317
|
+
* it forever. `export *` is the worst case, since it forwards every name.
|
|
318
|
+
*
|
|
319
|
+
* Keyed on the pair, not the file: a renaming re-export changes the name being
|
|
320
|
+
* searched from one hop to the next, so the same file can legitimately be visited
|
|
321
|
+
* for two different names. Keying on the file alone would truncate the second
|
|
322
|
+
* search and lose a value that is genuinely reachable.
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
visited?: Set<string>) => VariableDeclaration | undefined;
|
|
310
326
|
declare const maybeIdentifierValue: (identifier: Identifier, _stack: Node[], ctx: BoxContext) => BoxNode;
|
|
311
327
|
//#endregion
|
|
312
328
|
//#region src/jsx-spread-attribute.d.ts
|
|
@@ -316,6 +332,10 @@ declare const extractJsxSpreadAttributeValues: (node: JsxSpreadAttribute, ctx: B
|
|
|
316
332
|
//#region src/utils.d.ts
|
|
317
333
|
declare const unwrapExpression: (node: Node) => Node;
|
|
318
334
|
//#endregion
|
|
335
|
+
//#region src/dependency-cache.d.ts
|
|
336
|
+
/** Mark one edited file's content stale for every cache entry that recorded reading it. */
|
|
337
|
+
declare const invalidateDependencyPath: (filePath: string) => void;
|
|
338
|
+
//#endregion
|
|
319
339
|
//#region src/unbox.d.ts
|
|
320
340
|
type BoxNodeType = BoxNode | BoxNode[] | undefined;
|
|
321
341
|
type CacheMap = WeakMap<BoxNode, Unboxed>;
|
|
@@ -335,4 +355,4 @@ interface Unboxed {
|
|
|
335
355
|
}
|
|
336
356
|
declare const unbox: (node: BoxNodeType, ctx?: Pick<UnboxContext, "cache">) => Unboxed;
|
|
337
357
|
//#endregion
|
|
338
|
-
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 ResolveModule, type Unboxed, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox, unwrapExpression };
|
|
358
|
+
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 ResolveModule, type Unboxed, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, getExportedVarDeclarationWithName, invalidateDependencyPath, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox, unwrapExpression };
|
package/dist/index.d.mts
CHANGED
|
@@ -196,6 +196,8 @@ interface BoxContext {
|
|
|
196
196
|
resolveModule?: ResolveModule;
|
|
197
197
|
/** @internal Receives local source paths crossed by this exact extraction context. */
|
|
198
198
|
recordDependency?: (filePath: string) => void;
|
|
199
|
+
/** @internal Receives every `(module, exportedName)` a cross-file value resolution visited. */
|
|
200
|
+
recordExportRead?: (filePath: string, exportedName: string) => void;
|
|
199
201
|
getEvaluateOptions?: (node: Expression, stack: Node[]) => Omit<EvaluateOptions, 'node' | 'policy'> | void;
|
|
200
202
|
canEval?: (node: Expression, stack: Node[]) => boolean;
|
|
201
203
|
tokens?: {
|
|
@@ -307,6 +309,20 @@ declare const extractJsxElementProps: (node: JsxOpeningElement | JsxSelfClosingE
|
|
|
307
309
|
declare const clearBoxNodeCache: () => void;
|
|
308
310
|
type MaybeBoxNodeReturn = BoxNode | undefined;
|
|
309
311
|
declare function maybeBoxNode(node: Node, stack: Node[], ctx: BoxContext, matchProp?: (prop: MatchFnPropArgs) => boolean): MaybeBoxNodeReturn;
|
|
312
|
+
declare const getExportedVarDeclarationWithName: (varName: string, sourceFile: SourceFile, stack: Node[], ctx: BoxContext,
|
|
313
|
+
/**
|
|
314
|
+
* The `(file, name)` pairs already searched, so a cycle of re-exporting files
|
|
315
|
+
* terminates. Re-exports can form one — including a barrel that re-exports
|
|
316
|
+
* itself — and a name that never resolves inside the cycle would otherwise walk
|
|
317
|
+
* it forever. `export *` is the worst case, since it forwards every name.
|
|
318
|
+
*
|
|
319
|
+
* Keyed on the pair, not the file: a renaming re-export changes the name being
|
|
320
|
+
* searched from one hop to the next, so the same file can legitimately be visited
|
|
321
|
+
* for two different names. Keying on the file alone would truncate the second
|
|
322
|
+
* search and lose a value that is genuinely reachable.
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
visited?: Set<string>) => VariableDeclaration | undefined;
|
|
310
326
|
declare const maybeIdentifierValue: (identifier: Identifier, _stack: Node[], ctx: BoxContext) => BoxNode;
|
|
311
327
|
//#endregion
|
|
312
328
|
//#region src/jsx-spread-attribute.d.ts
|
|
@@ -316,6 +332,10 @@ declare const extractJsxSpreadAttributeValues: (node: JsxSpreadAttribute, ctx: B
|
|
|
316
332
|
//#region src/utils.d.ts
|
|
317
333
|
declare const unwrapExpression: (node: Node) => Node;
|
|
318
334
|
//#endregion
|
|
335
|
+
//#region src/dependency-cache.d.ts
|
|
336
|
+
/** Mark one edited file's content stale for every cache entry that recorded reading it. */
|
|
337
|
+
declare const invalidateDependencyPath: (filePath: string) => void;
|
|
338
|
+
//#endregion
|
|
319
339
|
//#region src/unbox.d.ts
|
|
320
340
|
type BoxNodeType = BoxNode | BoxNode[] | undefined;
|
|
321
341
|
type CacheMap = WeakMap<BoxNode, Unboxed>;
|
|
@@ -335,4 +355,4 @@ interface Unboxed {
|
|
|
335
355
|
}
|
|
336
356
|
declare const unbox: (node: BoxNodeType, ctx?: Pick<UnboxContext, "cache">) => Unboxed;
|
|
337
357
|
//#endregion
|
|
338
|
-
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 ResolveModule, type Unboxed, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox, unwrapExpression };
|
|
358
|
+
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 ResolveModule, type Unboxed, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, getExportedVarDeclarationWithName, invalidateDependencyPath, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox, unwrapExpression };
|
package/dist/index.mjs
CHANGED
|
@@ -310,6 +310,37 @@ const EMPTY_DEPENDENCIES = [];
|
|
|
310
310
|
/** One synchronous extraction context owns one nested capture stack. */
|
|
311
311
|
const trackers = /* @__PURE__ */ new WeakMap();
|
|
312
312
|
/**
|
|
313
|
+
* Per-path staleness, so an edit invalidates exactly the entries that read the edited file.
|
|
314
|
+
*
|
|
315
|
+
* The caches these entries live in are `WeakMap`s keyed on AST nodes — deliberately, so a
|
|
316
|
+
* retired tree releases its memory — which means they cannot be swept. What they *can* do is
|
|
317
|
+
* refuse a hit: every entry already records the module paths its computation read, because
|
|
318
|
+
* that same record is what the watch system replays into fold dependencies. Stamping entries
|
|
319
|
+
* with a creation generation and bumping a per-path generation on each edit turns the
|
|
320
|
+
* recorded read-set into a validity check, evaluated lazily at lookup.
|
|
321
|
+
*
|
|
322
|
+
* The trust base is unchanged. If a cross-file read were missing from `dependencies`, the
|
|
323
|
+
* fold's watch edges would already be missing it, and editing that file would fail to
|
|
324
|
+
* re-transform its consumers today — the recorded read-set is load-bearing for invalidation
|
|
325
|
+
* breadth before it is for cache validity.
|
|
326
|
+
*
|
|
327
|
+
* An entry's *own* file needs no record: reloading or overwriting a file re-parses it, which
|
|
328
|
+
* retires every node previously taken from it, and a retired node can never be a lookup key
|
|
329
|
+
* again. Only cross-file reads can go stale while the key survives, and those are exactly
|
|
330
|
+
* what the capture records.
|
|
331
|
+
*
|
|
332
|
+
* File-tree changes are not handled here at all: a created or deleted file can change what a
|
|
333
|
+
* specifier *resolves to* without any recorded path's content moving, so those events keep
|
|
334
|
+
* clearing the caches outright, exactly as before.
|
|
335
|
+
*/
|
|
336
|
+
let dependencyGeneration = 1;
|
|
337
|
+
const invalidatedAt = /* @__PURE__ */ new Map();
|
|
338
|
+
/** Mark one edited file's content stale for every cache entry that recorded reading it. */
|
|
339
|
+
const invalidateDependencyPath = (filePath) => {
|
|
340
|
+
dependencyGeneration++;
|
|
341
|
+
invalidatedAt.set(filePath.replaceAll("\\", "/"), dependencyGeneration);
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
313
344
|
* Attribute one resolved local module to every cache computation currently enclosing it.
|
|
314
345
|
*
|
|
315
346
|
* Paths, rather than SourceFile objects, are the replay payload. A source replacement may
|
|
@@ -340,6 +371,7 @@ const beginDependencyCapture = (ctx) => {
|
|
|
340
371
|
return {
|
|
341
372
|
dependencies: frame.dependencies ? [...frame.dependencies].sort() : EMPTY_DEPENDENCIES,
|
|
342
373
|
resolveModule: ctx.resolveModule,
|
|
374
|
+
generation: dependencyGeneration,
|
|
343
375
|
value
|
|
344
376
|
};
|
|
345
377
|
},
|
|
@@ -357,6 +389,10 @@ const beginDependencyCapture = (ctx) => {
|
|
|
357
389
|
*/
|
|
358
390
|
const replayDependencyCache = (entry, ctx) => {
|
|
359
391
|
if (entry.resolveModule !== ctx.resolveModule) return { hit: false };
|
|
392
|
+
for (const dependency of entry.dependencies) {
|
|
393
|
+
const at = invalidatedAt.get(dependency);
|
|
394
|
+
if (at !== void 0 && at > entry.generation) return { hit: false };
|
|
395
|
+
}
|
|
360
396
|
for (const dependency of entry.dependencies) recordModuleDependency(ctx, dependency);
|
|
361
397
|
return {
|
|
362
398
|
hit: true,
|
|
@@ -1247,6 +1283,7 @@ const maybeDefinitionValue = (def, stack, ctx) => {
|
|
|
1247
1283
|
}
|
|
1248
1284
|
};
|
|
1249
1285
|
const getExportedVarDeclarationWithName = (varName, sourceFile, stack, ctx, visited = /* @__PURE__ */ new Set()) => {
|
|
1286
|
+
ctx.recordExportRead?.(sourceFile.getFilePath(), varName);
|
|
1250
1287
|
const key = `${sourceFile.getFilePath()}:${varName}`;
|
|
1251
1288
|
if (visited.has(key)) return;
|
|
1252
1289
|
visited.add(key);
|
|
@@ -2195,4 +2232,4 @@ const unbox = (node, ctx) => {
|
|
|
2195
2232
|
return result;
|
|
2196
2233
|
};
|
|
2197
2234
|
//#endregion
|
|
2198
|
-
export { BoxNodeArray, BoxNodeConditional, BoxNodeEmptyInitializer, BoxNodeLiteral, BoxNodeMap, BoxNodeObject, BoxNodeUnresolvable, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox, unwrapExpression };
|
|
2235
|
+
export { BoxNodeArray, BoxNodeConditional, BoxNodeEmptyInitializer, BoxNodeLiteral, BoxNodeMap, BoxNodeObject, BoxNodeUnresolvable, box, clearBoxNodeCache, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, getExportedVarDeclarationWithName, invalidateDependencyPath, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox, unwrapExpression };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bamboocss/extractor",
|
|
3
|
-
"version": "1.46.
|
|
3
|
+
"version": "1.46.3",
|
|
4
4
|
"description": "The css extractor for css bamboo",
|
|
5
5
|
"homepage": "https://bamboocss.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"ts-evaluator": "2.0.0",
|
|
37
37
|
"ts-morph": "28.0.0",
|
|
38
|
-
"@bamboocss/shared": "1.46.
|
|
38
|
+
"@bamboocss/shared": "1.46.3"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsdown src/index.ts --format=cjs,esm --shims --dts",
|