@clayroach/unplugin 0.1.0-source-trace.3 → 0.1.0-source-trace.4
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/cjs/index.js +10 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/transformers/annotateEffects.js +141 -0
- package/dist/cjs/transformers/annotateEffects.js.map +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/transformers/annotateEffects.d.ts +41 -0
- package/dist/dts/transformers/annotateEffects.d.ts.map +1 -0
- package/dist/esm/index.js +8 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/transformers/annotateEffects.js +140 -0
- package/dist/esm/transformers/annotateEffects.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +9 -2
- package/src/transformers/annotateEffects.ts +197 -0
package/dist/cjs/index.js
CHANGED
|
@@ -8,6 +8,7 @@ var _generator = _interopRequireDefault(require("@babel/generator"));
|
|
|
8
8
|
var _parser = require("@babel/parser");
|
|
9
9
|
var _traverse2 = _interopRequireDefault(require("@babel/traverse"));
|
|
10
10
|
var _unplugin = require("unplugin");
|
|
11
|
+
var _annotateEffects = require("./transformers/annotateEffects.js");
|
|
11
12
|
var _sourceTrace = require("./transformers/sourceTrace.js");
|
|
12
13
|
var _withSpanTrace = require("./transformers/withSpanTrace.js");
|
|
13
14
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -49,7 +50,7 @@ function shouldTransform(id, include, exclude) {
|
|
|
49
50
|
*/
|
|
50
51
|
const unpluginFactory = (options = {}) => {
|
|
51
52
|
const {
|
|
52
|
-
annotateEffects
|
|
53
|
+
annotateEffects = false,
|
|
53
54
|
exclude = DEFAULT_EXCLUDE,
|
|
54
55
|
include = DEFAULT_INCLUDE,
|
|
55
56
|
sourceTrace = true,
|
|
@@ -74,8 +75,15 @@ const unpluginFactory = (options = {}) => {
|
|
|
74
75
|
if (spanTrace) {
|
|
75
76
|
visitors.push((0, _withSpanTrace.createWithSpanTraceVisitor)(id));
|
|
76
77
|
}
|
|
78
|
+
// Run annotateEffects separately (it has a simpler state)
|
|
79
|
+
if (annotateEffects) {
|
|
80
|
+
const annotateState = {
|
|
81
|
+
filename: id
|
|
82
|
+
};
|
|
83
|
+
traverse(ast, (0, _annotateEffects.createAnnotateEffectsVisitor)(id), undefined, annotateState);
|
|
84
|
+
}
|
|
77
85
|
// Combine visitors
|
|
78
|
-
if (visitors.length === 0) {
|
|
86
|
+
if (visitors.length === 0 && !annotateEffects) {
|
|
79
87
|
return null;
|
|
80
88
|
}
|
|
81
89
|
// Initialize state for each visitor
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_generator","_interopRequireDefault","require","_parser","_traverse2","_unplugin","_sourceTrace","_withSpanTrace","e","__esModule","default","traverse","_traverse","generate","_generate","DEFAULT_INCLUDE","DEFAULT_EXCLUDE","shouldTransform","id","include","exclude","pattern","includes","test","unpluginFactory","options","annotateEffects","
|
|
1
|
+
{"version":3,"file":"index.js","names":["_generator","_interopRequireDefault","require","_parser","_traverse2","_unplugin","_annotateEffects","_sourceTrace","_withSpanTrace","e","__esModule","default","traverse","_traverse","generate","_generate","DEFAULT_INCLUDE","DEFAULT_EXCLUDE","shouldTransform","id","include","exclude","pattern","includes","test","unpluginFactory","options","annotateEffects","sourceTrace","spanTrace","name","transformInclude","transform","code","ast","parse","sourceType","plugins","visitors","push","createSourceTraceVisitor","createWithSpanTraceVisitor","annotateState","filename","createAnnotateEffectsVisitor","undefined","length","states","map","hoisting","hoistedTraces","Map","counter","statements","i","output","sourceMaps","sourceFileName","unplugin","exports","createUnplugin","_default"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.annotateEffectsTransformer = annotateEffectsTransformer;
|
|
7
|
+
exports.createAnnotateEffectsVisitor = createAnnotateEffectsVisitor;
|
|
8
|
+
const PURE_ANNOTATION = "#__PURE__";
|
|
9
|
+
/**
|
|
10
|
+
* Checks if a node already has a PURE annotation.
|
|
11
|
+
*/
|
|
12
|
+
function isPureAnnotated(node) {
|
|
13
|
+
const leadingComments = node.leadingComments;
|
|
14
|
+
if (!leadingComments) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return leadingComments.some(comment => /[@#]__PURE__/.test(comment.value));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Adds a PURE annotation comment to a node.
|
|
21
|
+
*/
|
|
22
|
+
function annotateAsPure(path) {
|
|
23
|
+
if (isPureAnnotated(path.node)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
path.addComment("leading", PURE_ANNOTATION);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Checks if the parent is a CallExpression or NewExpression.
|
|
30
|
+
*/
|
|
31
|
+
function hasCallableParent(path) {
|
|
32
|
+
const parentPath = path.parentPath;
|
|
33
|
+
if (!parentPath) return false;
|
|
34
|
+
return parentPath.isCallExpression() || parentPath.isNewExpression();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Checks if this node is used as a callee (e.g., `foo()` where foo is the callee).
|
|
38
|
+
*/
|
|
39
|
+
function isUsedAsCallee(path) {
|
|
40
|
+
if (!hasCallableParent(path)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const parentPath = path.parentPath;
|
|
44
|
+
return parentPath.get("callee") === path;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Checks if this node is inside a callee chain (e.g., `foo()()` or `foo.bar()`).
|
|
48
|
+
*/
|
|
49
|
+
function isInCallee(path) {
|
|
50
|
+
let current = path;
|
|
51
|
+
do {
|
|
52
|
+
current = current.parentPath;
|
|
53
|
+
if (!current) return false;
|
|
54
|
+
if (isUsedAsCallee(current)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
} while (!current.isStatement() && !current.isFunction());
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Checks if this expression is executed during module initialization
|
|
62
|
+
* (not inside a function that isn't immediately invoked).
|
|
63
|
+
*/
|
|
64
|
+
function isExecutedDuringInitialization(path) {
|
|
65
|
+
let functionParent = path.getFunctionParent();
|
|
66
|
+
while (functionParent) {
|
|
67
|
+
if (!isUsedAsCallee(functionParent)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
functionParent = functionParent.getFunctionParent();
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Checks if this expression is in an assignment context
|
|
76
|
+
* (variable declaration, assignment expression, or class).
|
|
77
|
+
*/
|
|
78
|
+
function isInAssignmentContext(path) {
|
|
79
|
+
const statement = path.getStatementParent();
|
|
80
|
+
if (!statement) return false;
|
|
81
|
+
let currentPath = path;
|
|
82
|
+
do {
|
|
83
|
+
currentPath = currentPath.parentPath;
|
|
84
|
+
if (!currentPath) return false;
|
|
85
|
+
if (currentPath.isVariableDeclaration() || currentPath.isAssignmentExpression() || currentPath.isClass()) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
} while (currentPath !== statement);
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Visitor function for CallExpression and NewExpression nodes.
|
|
93
|
+
*/
|
|
94
|
+
function callableExpressionVisitor(path, _state) {
|
|
95
|
+
// Skip if this is used as a callee (e.g., foo()())
|
|
96
|
+
if (isUsedAsCallee(path)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Skip if this is inside a callee chain
|
|
100
|
+
if (isInCallee(path)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Skip if not executed during initialization
|
|
104
|
+
if (!isExecutedDuringInitialization(path)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Must be in assignment context or export default
|
|
108
|
+
const statement = path.getStatementParent();
|
|
109
|
+
if (!isInAssignmentContext(path) && !statement?.isExportDefaultDeclaration()) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
annotateAsPure(path);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Creates a Babel visitor that adds PURE annotations to call expressions.
|
|
116
|
+
*/
|
|
117
|
+
function createAnnotateEffectsVisitor(filename, _options) {
|
|
118
|
+
return {
|
|
119
|
+
Program: {
|
|
120
|
+
enter(_path, state) {
|
|
121
|
+
state.filename = filename;
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
CallExpression(path, state) {
|
|
125
|
+
callableExpressionVisitor(path, state);
|
|
126
|
+
},
|
|
127
|
+
NewExpression(path, state) {
|
|
128
|
+
callableExpressionVisitor(path, state);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Creates the annotate effects transformer plugin.
|
|
134
|
+
*/
|
|
135
|
+
function annotateEffectsTransformer(options) {
|
|
136
|
+
return {
|
|
137
|
+
name: "effect-annotate-pure-calls",
|
|
138
|
+
visitor: createAnnotateEffectsVisitor("", options)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=annotateEffects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotateEffects.js","names":["PURE_ANNOTATION","isPureAnnotated","node","leadingComments","some","comment","test","value","annotateAsPure","path","addComment","hasCallableParent","parentPath","isCallExpression","isNewExpression","isUsedAsCallee","get","isInCallee","current","isStatement","isFunction","isExecutedDuringInitialization","functionParent","getFunctionParent","isInAssignmentContext","statement","getStatementParent","currentPath","isVariableDeclaration","isAssignmentExpression","isClass","callableExpressionVisitor","_state","isExportDefaultDeclaration","createAnnotateEffectsVisitor","filename","_options","Program","enter","_path","state","CallExpression","NewExpression","annotateEffectsTransformer","options","name","visitor"],"sources":["../../../src/transformers/annotateEffects.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/dist/dts/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAwC,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAwC,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAqCtF;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;IAE9B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;IAElC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAExC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACzC;AAsHD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,gBAAgB,CAAC,mBAAmB,GAAG,SAAS,EAAE,OAAO,CAAmC,CAAA;AAEnH;;;;GAIG;AACH,eAAe,QAAQ,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure call annotation transformer.
|
|
3
|
+
*
|
|
4
|
+
* This transformer adds `#__PURE__` comments to call expressions for better tree-shaking.
|
|
5
|
+
* It replicates the behavior of `babel-plugin-annotate-pure-calls` but integrated into
|
|
6
|
+
* the Effect unplugin.
|
|
7
|
+
*
|
|
8
|
+
* The `#__PURE__` annotation tells bundlers (Webpack, Rollup, esbuild) that a function call
|
|
9
|
+
* has no side effects and can be safely removed if the result is unused.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
*/
|
|
13
|
+
import type { Visitor } from "@babel/traverse";
|
|
14
|
+
/**
|
|
15
|
+
* Options for the annotate effects transformer.
|
|
16
|
+
*/
|
|
17
|
+
export interface AnnotateEffectsOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Filter function to determine if a file should be transformed.
|
|
20
|
+
*/
|
|
21
|
+
readonly filter?: (filename: string) => boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* State passed through the transformer.
|
|
25
|
+
*/
|
|
26
|
+
interface TransformState {
|
|
27
|
+
filename: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a Babel visitor that adds PURE annotations to call expressions.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createAnnotateEffectsVisitor(filename: string, _options?: AnnotateEffectsOptions): Visitor<TransformState>;
|
|
33
|
+
/**
|
|
34
|
+
* Creates the annotate effects transformer plugin.
|
|
35
|
+
*/
|
|
36
|
+
export declare function annotateEffectsTransformer(options?: AnnotateEffectsOptions): {
|
|
37
|
+
visitor: Visitor<TransformState>;
|
|
38
|
+
name: string;
|
|
39
|
+
};
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=annotateEffects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotateEffects.d.ts","sourceRoot":"","sources":["../../../src/transformers/annotateEffects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAY,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAGxD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;CAChD;AAED;;GAEG;AACH,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAmID;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,sBAAsB,GAChC,OAAO,CAAC,cAAc,CAAC,CAgBzB;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG;IAC5E,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAChC,IAAI,EAAE,MAAM,CAAA;CACb,CAKA"}
|
package/dist/esm/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import _generate from "@babel/generator";
|
|
|
2
2
|
import { parse } from "@babel/parser";
|
|
3
3
|
import _traverse from "@babel/traverse";
|
|
4
4
|
import { createUnplugin } from "unplugin";
|
|
5
|
+
import { createAnnotateEffectsVisitor } from "./transformers/annotateEffects.js";
|
|
5
6
|
import { createSourceTraceVisitor } from "./transformers/sourceTrace.js";
|
|
6
7
|
import { createWithSpanTraceVisitor } from "./transformers/withSpanTrace.js";
|
|
7
8
|
// Handle both ESM and CJS module exports for Babel packages
|
|
@@ -49,7 +50,7 @@ function shouldTransform(id, include, exclude) {
|
|
|
49
50
|
* Creates the unplugin factory.
|
|
50
51
|
*/
|
|
51
52
|
const unpluginFactory = (options = {}) => {
|
|
52
|
-
const { annotateEffects
|
|
53
|
+
const { annotateEffects = false, exclude = DEFAULT_EXCLUDE, include = DEFAULT_INCLUDE, sourceTrace = true, spanTrace = true } = options;
|
|
53
54
|
return {
|
|
54
55
|
name: "@effect/unplugin",
|
|
55
56
|
transformInclude(id) {
|
|
@@ -69,8 +70,13 @@ const unpluginFactory = (options = {}) => {
|
|
|
69
70
|
if (spanTrace) {
|
|
70
71
|
visitors.push(createWithSpanTraceVisitor(id));
|
|
71
72
|
}
|
|
73
|
+
// Run annotateEffects separately (it has a simpler state)
|
|
74
|
+
if (annotateEffects) {
|
|
75
|
+
const annotateState = { filename: id };
|
|
76
|
+
traverse(ast, createAnnotateEffectsVisitor(id), undefined, annotateState);
|
|
77
|
+
}
|
|
72
78
|
// Combine visitors
|
|
73
|
-
if (visitors.length === 0) {
|
|
79
|
+
if (visitors.length === 0 && !annotateEffects) {
|
|
74
80
|
return null;
|
|
75
81
|
}
|
|
76
82
|
// Initialize state for each visitor
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAwBA,OAAO,SAAS,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAErC,OAAO,SAAS,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EAAE,cAAc,EAA+C,MAAM,UAAU,CAAA;AACtF,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAA;AAiB5E,4DAA4D;AAC5D,MAAM,QAAQ,GAAe,OAAO,SAAS,KAAK,UAAU;IAC1D,CAAC,CAAC,SAAuB;IACzB,CAAC,CAAE,SAAgD,CAAC,OAAO,CAAA;AAE7D,MAAM,QAAQ,GAAe,OAAO,SAAS,KAAK,UAAU;IAC1D,CAAC,CAAC,SAAuB;IACzB,CAAC,CAAE,SAAgD,CAAC,OAAO,CAAA;AAsD7D;;GAEG;AACH,MAAM,eAAe,GAAG,CAAC,YAAY,CAAC,CAAA;AAEtC;;GAEG;AACH,MAAM,eAAe,GAAG,CAAC,cAAc,EAAE,UAAU,CAAC,CAAA;AAEpD;;GAEG;AACH,SAAS,eAAe,CACtB,EAAU,EACV,OAAuC,EACvC,OAAuC;IAEvC,uBAAuB;IACvB,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;QAC9B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,OAAO,KAAK,CAAA;QACxC,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,iBAAiB;IACjB,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;QAC9B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,OAAO,IAAI,CAAA;QACvC,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;GAEG;AACH,MAAM,eAAe,GAAqD,CAAC,OAAO,GAAG,EAAE,EAAE,EAAE;IACzF,MAAM,EACJ,eAAe,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
const PURE_ANNOTATION = "#__PURE__";
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a node already has a PURE annotation.
|
|
4
|
+
*/
|
|
5
|
+
function isPureAnnotated(node) {
|
|
6
|
+
const leadingComments = node.leadingComments;
|
|
7
|
+
if (!leadingComments) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
return leadingComments.some((comment) => /[@#]__PURE__/.test(comment.value));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Adds a PURE annotation comment to a node.
|
|
14
|
+
*/
|
|
15
|
+
function annotateAsPure(path) {
|
|
16
|
+
if (isPureAnnotated(path.node)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
path.addComment("leading", PURE_ANNOTATION);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Checks if the parent is a CallExpression or NewExpression.
|
|
23
|
+
*/
|
|
24
|
+
function hasCallableParent(path) {
|
|
25
|
+
const parentPath = path.parentPath;
|
|
26
|
+
if (!parentPath)
|
|
27
|
+
return false;
|
|
28
|
+
return parentPath.isCallExpression() || parentPath.isNewExpression();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Checks if this node is used as a callee (e.g., `foo()` where foo is the callee).
|
|
32
|
+
*/
|
|
33
|
+
function isUsedAsCallee(path) {
|
|
34
|
+
if (!hasCallableParent(path)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
const parentPath = path.parentPath;
|
|
38
|
+
return parentPath.get("callee") === path;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Checks if this node is inside a callee chain (e.g., `foo()()` or `foo.bar()`).
|
|
42
|
+
*/
|
|
43
|
+
function isInCallee(path) {
|
|
44
|
+
let current = path;
|
|
45
|
+
do {
|
|
46
|
+
current = current.parentPath;
|
|
47
|
+
if (!current)
|
|
48
|
+
return false;
|
|
49
|
+
if (isUsedAsCallee(current)) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
} while (!current.isStatement() && !current.isFunction());
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Checks if this expression is executed during module initialization
|
|
57
|
+
* (not inside a function that isn't immediately invoked).
|
|
58
|
+
*/
|
|
59
|
+
function isExecutedDuringInitialization(path) {
|
|
60
|
+
let functionParent = path.getFunctionParent();
|
|
61
|
+
while (functionParent) {
|
|
62
|
+
if (!isUsedAsCallee(functionParent)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
functionParent = functionParent.getFunctionParent();
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks if this expression is in an assignment context
|
|
71
|
+
* (variable declaration, assignment expression, or class).
|
|
72
|
+
*/
|
|
73
|
+
function isInAssignmentContext(path) {
|
|
74
|
+
const statement = path.getStatementParent();
|
|
75
|
+
if (!statement)
|
|
76
|
+
return false;
|
|
77
|
+
let currentPath = path;
|
|
78
|
+
do {
|
|
79
|
+
currentPath = currentPath.parentPath;
|
|
80
|
+
if (!currentPath)
|
|
81
|
+
return false;
|
|
82
|
+
if (currentPath.isVariableDeclaration() ||
|
|
83
|
+
currentPath.isAssignmentExpression() ||
|
|
84
|
+
currentPath.isClass()) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
} while (currentPath !== statement);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Visitor function for CallExpression and NewExpression nodes.
|
|
92
|
+
*/
|
|
93
|
+
function callableExpressionVisitor(path, _state) {
|
|
94
|
+
// Skip if this is used as a callee (e.g., foo()())
|
|
95
|
+
if (isUsedAsCallee(path)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Skip if this is inside a callee chain
|
|
99
|
+
if (isInCallee(path)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Skip if not executed during initialization
|
|
103
|
+
if (!isExecutedDuringInitialization(path)) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Must be in assignment context or export default
|
|
107
|
+
const statement = path.getStatementParent();
|
|
108
|
+
if (!isInAssignmentContext(path) && !statement?.isExportDefaultDeclaration()) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
annotateAsPure(path);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Creates a Babel visitor that adds PURE annotations to call expressions.
|
|
115
|
+
*/
|
|
116
|
+
export function createAnnotateEffectsVisitor(filename, _options) {
|
|
117
|
+
return {
|
|
118
|
+
Program: {
|
|
119
|
+
enter(_path, state) {
|
|
120
|
+
state.filename = filename;
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
CallExpression(path, state) {
|
|
124
|
+
callableExpressionVisitor(path, state);
|
|
125
|
+
},
|
|
126
|
+
NewExpression(path, state) {
|
|
127
|
+
callableExpressionVisitor(path, state);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Creates the annotate effects transformer plugin.
|
|
133
|
+
*/
|
|
134
|
+
export function annotateEffectsTransformer(options) {
|
|
135
|
+
return {
|
|
136
|
+
name: "effect-annotate-pure-calls",
|
|
137
|
+
visitor: createAnnotateEffectsVisitor("", options)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=annotateEffects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotateEffects.js","sourceRoot":"","sources":["../../../src/transformers/annotateEffects.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ import type { Scope, TraverseOptions, Visitor } from "@babel/traverse"
|
|
|
28
28
|
import _traverse from "@babel/traverse"
|
|
29
29
|
import type { Node } from "@babel/types"
|
|
30
30
|
import { createUnplugin, type UnpluginFactory, type UnpluginInstance } from "unplugin"
|
|
31
|
+
import { createAnnotateEffectsVisitor } from "./transformers/annotateEffects.js"
|
|
31
32
|
import { createSourceTraceVisitor } from "./transformers/sourceTrace.js"
|
|
32
33
|
import { createWithSpanTraceVisitor } from "./transformers/withSpanTrace.js"
|
|
33
34
|
import type { HoistingState } from "./utils/hoisting.js"
|
|
@@ -151,7 +152,7 @@ function shouldTransform(
|
|
|
151
152
|
*/
|
|
152
153
|
const unpluginFactory: UnpluginFactory<EffectPluginOptions | undefined> = (options = {}) => {
|
|
153
154
|
const {
|
|
154
|
-
annotateEffects
|
|
155
|
+
annotateEffects = false,
|
|
155
156
|
exclude = DEFAULT_EXCLUDE,
|
|
156
157
|
include = DEFAULT_INCLUDE,
|
|
157
158
|
sourceTrace = true,
|
|
@@ -183,8 +184,14 @@ const unpluginFactory: UnpluginFactory<EffectPluginOptions | undefined> = (optio
|
|
|
183
184
|
visitors.push(createWithSpanTraceVisitor(id))
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
// Run annotateEffects separately (it has a simpler state)
|
|
188
|
+
if (annotateEffects) {
|
|
189
|
+
const annotateState = { filename: id }
|
|
190
|
+
traverse(ast, createAnnotateEffectsVisitor(id), undefined, annotateState)
|
|
191
|
+
}
|
|
192
|
+
|
|
186
193
|
// Combine visitors
|
|
187
|
-
if (visitors.length === 0) {
|
|
194
|
+
if (visitors.length === 0 && !annotateEffects) {
|
|
188
195
|
return null
|
|
189
196
|
}
|
|
190
197
|
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure call annotation transformer.
|
|
3
|
+
*
|
|
4
|
+
* This transformer adds `#__PURE__` comments to call expressions for better tree-shaking.
|
|
5
|
+
* It replicates the behavior of `babel-plugin-annotate-pure-calls` but integrated into
|
|
6
|
+
* the Effect unplugin.
|
|
7
|
+
*
|
|
8
|
+
* The `#__PURE__` annotation tells bundlers (Webpack, Rollup, esbuild) that a function call
|
|
9
|
+
* has no side effects and can be safely removed if the result is unused.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
*/
|
|
13
|
+
import type { NodePath, Visitor } from "@babel/traverse"
|
|
14
|
+
import * as t from "@babel/types"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Options for the annotate effects transformer.
|
|
18
|
+
*/
|
|
19
|
+
export interface AnnotateEffectsOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Filter function to determine if a file should be transformed.
|
|
22
|
+
*/
|
|
23
|
+
readonly filter?: (filename: string) => boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* State passed through the transformer.
|
|
28
|
+
*/
|
|
29
|
+
interface TransformState {
|
|
30
|
+
filename: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const PURE_ANNOTATION = "#__PURE__"
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Checks if a node already has a PURE annotation.
|
|
37
|
+
*/
|
|
38
|
+
function isPureAnnotated(node: t.Node): boolean {
|
|
39
|
+
const leadingComments = node.leadingComments
|
|
40
|
+
if (!leadingComments) {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
return leadingComments.some((comment) => /[@#]__PURE__/.test(comment.value))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Adds a PURE annotation comment to a node.
|
|
48
|
+
*/
|
|
49
|
+
function annotateAsPure(path: NodePath<t.CallExpression | t.NewExpression>): void {
|
|
50
|
+
if (isPureAnnotated(path.node)) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
path.addComment("leading", PURE_ANNOTATION)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Checks if the parent is a CallExpression or NewExpression.
|
|
58
|
+
*/
|
|
59
|
+
function hasCallableParent(path: NodePath): boolean {
|
|
60
|
+
const parentPath = path.parentPath
|
|
61
|
+
if (!parentPath) return false
|
|
62
|
+
return parentPath.isCallExpression() || parentPath.isNewExpression()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Checks if this node is used as a callee (e.g., `foo()` where foo is the callee).
|
|
67
|
+
*/
|
|
68
|
+
function isUsedAsCallee(path: NodePath): boolean {
|
|
69
|
+
if (!hasCallableParent(path)) {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
const parentPath = path.parentPath as NodePath<t.CallExpression | t.NewExpression>
|
|
73
|
+
return parentPath.get("callee") === path
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Checks if this node is inside a callee chain (e.g., `foo()()` or `foo.bar()`).
|
|
78
|
+
*/
|
|
79
|
+
function isInCallee(path: NodePath): boolean {
|
|
80
|
+
let current: NodePath | null = path
|
|
81
|
+
do {
|
|
82
|
+
current = current.parentPath
|
|
83
|
+
if (!current) return false
|
|
84
|
+
if (isUsedAsCallee(current)) {
|
|
85
|
+
return true
|
|
86
|
+
}
|
|
87
|
+
} while (!current.isStatement() && !current.isFunction())
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Checks if this expression is executed during module initialization
|
|
93
|
+
* (not inside a function that isn't immediately invoked).
|
|
94
|
+
*/
|
|
95
|
+
function isExecutedDuringInitialization(path: NodePath): boolean {
|
|
96
|
+
let functionParent = path.getFunctionParent()
|
|
97
|
+
while (functionParent) {
|
|
98
|
+
if (!isUsedAsCallee(functionParent)) {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
functionParent = functionParent.getFunctionParent()
|
|
102
|
+
}
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Checks if this expression is in an assignment context
|
|
108
|
+
* (variable declaration, assignment expression, or class).
|
|
109
|
+
*/
|
|
110
|
+
function isInAssignmentContext(path: NodePath): boolean {
|
|
111
|
+
const statement = path.getStatementParent()
|
|
112
|
+
if (!statement) return false
|
|
113
|
+
|
|
114
|
+
let currentPath: NodePath | null = path
|
|
115
|
+
do {
|
|
116
|
+
currentPath = currentPath.parentPath
|
|
117
|
+
if (!currentPath) return false
|
|
118
|
+
|
|
119
|
+
if (
|
|
120
|
+
currentPath.isVariableDeclaration() ||
|
|
121
|
+
currentPath.isAssignmentExpression() ||
|
|
122
|
+
currentPath.isClass()
|
|
123
|
+
) {
|
|
124
|
+
return true
|
|
125
|
+
}
|
|
126
|
+
} while (currentPath !== statement)
|
|
127
|
+
|
|
128
|
+
return false
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Visitor function for CallExpression and NewExpression nodes.
|
|
133
|
+
*/
|
|
134
|
+
function callableExpressionVisitor(
|
|
135
|
+
path: NodePath<t.CallExpression | t.NewExpression>,
|
|
136
|
+
_state: TransformState
|
|
137
|
+
): void {
|
|
138
|
+
// Skip if this is used as a callee (e.g., foo()())
|
|
139
|
+
if (isUsedAsCallee(path)) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Skip if this is inside a callee chain
|
|
144
|
+
if (isInCallee(path)) {
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Skip if not executed during initialization
|
|
149
|
+
if (!isExecutedDuringInitialization(path)) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Must be in assignment context or export default
|
|
154
|
+
const statement = path.getStatementParent()
|
|
155
|
+
if (!isInAssignmentContext(path) && !statement?.isExportDefaultDeclaration()) {
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
annotateAsPure(path)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Creates a Babel visitor that adds PURE annotations to call expressions.
|
|
164
|
+
*/
|
|
165
|
+
export function createAnnotateEffectsVisitor(
|
|
166
|
+
filename: string,
|
|
167
|
+
_options?: AnnotateEffectsOptions
|
|
168
|
+
): Visitor<TransformState> {
|
|
169
|
+
return {
|
|
170
|
+
Program: {
|
|
171
|
+
enter(_path, state) {
|
|
172
|
+
state.filename = filename
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
CallExpression(path: NodePath<t.CallExpression>, state) {
|
|
177
|
+
callableExpressionVisitor(path, state)
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
NewExpression(path: NodePath<t.NewExpression>, state) {
|
|
181
|
+
callableExpressionVisitor(path, state)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Creates the annotate effects transformer plugin.
|
|
188
|
+
*/
|
|
189
|
+
export function annotateEffectsTransformer(options?: AnnotateEffectsOptions): {
|
|
190
|
+
visitor: Visitor<TransformState>
|
|
191
|
+
name: string
|
|
192
|
+
} {
|
|
193
|
+
return {
|
|
194
|
+
name: "effect-annotate-pure-calls",
|
|
195
|
+
visitor: createAnnotateEffectsVisitor("", options)
|
|
196
|
+
}
|
|
197
|
+
}
|