@clayroach/unplugin 0.1.0-source-trace.2
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 +21 -0
- package/README.md +93 -0
- package/dist/cjs/esbuild.js +34 -0
- package/dist/cjs/esbuild.js.map +1 -0
- package/dist/cjs/index.js +113 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/rollup.js +33 -0
- package/dist/cjs/rollup.js.map +1 -0
- package/dist/cjs/rspack.js +33 -0
- package/dist/cjs/rspack.js.map +1 -0
- package/dist/cjs/transformers/index.js +17 -0
- package/dist/cjs/transformers/index.js.map +1 -0
- package/dist/cjs/transformers/sourceTrace.js +57 -0
- package/dist/cjs/transformers/sourceTrace.js.map +1 -0
- package/dist/cjs/utils/effectDetection.js +58 -0
- package/dist/cjs/utils/effectDetection.js.map +1 -0
- package/dist/cjs/utils/hoisting.js +71 -0
- package/dist/cjs/utils/hoisting.js.map +1 -0
- package/dist/cjs/vite.js +33 -0
- package/dist/cjs/vite.js.map +1 -0
- package/dist/cjs/webpack.js +33 -0
- package/dist/cjs/webpack.js.map +1 -0
- package/dist/dts/esbuild.d.ts +30 -0
- package/dist/dts/esbuild.d.ts.map +1 -0
- package/dist/dts/index.d.ts +46 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/rollup.d.ts +29 -0
- package/dist/dts/rollup.d.ts.map +1 -0
- package/dist/dts/rspack.d.ts +29 -0
- package/dist/dts/rspack.d.ts.map +1 -0
- package/dist/dts/transformers/index.d.ts +7 -0
- package/dist/dts/transformers/index.d.ts.map +1 -0
- package/dist/dts/transformers/sourceTrace.d.ts +41 -0
- package/dist/dts/transformers/sourceTrace.d.ts.map +1 -0
- package/dist/dts/utils/effectDetection.d.ts +35 -0
- package/dist/dts/utils/effectDetection.d.ts.map +1 -0
- package/dist/dts/utils/hoisting.d.ts +41 -0
- package/dist/dts/utils/hoisting.d.ts.map +1 -0
- package/dist/dts/vite.d.ts +29 -0
- package/dist/dts/vite.d.ts.map +1 -0
- package/dist/dts/webpack.d.ts +29 -0
- package/dist/dts/webpack.d.ts.map +1 -0
- package/dist/esm/esbuild.js +28 -0
- package/dist/esm/esbuild.js.map +1 -0
- package/dist/esm/index.js +109 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/dist/esm/rollup.js +27 -0
- package/dist/esm/rollup.js.map +1 -0
- package/dist/esm/rspack.js +27 -0
- package/dist/esm/rspack.js.map +1 -0
- package/dist/esm/transformers/index.js +7 -0
- package/dist/esm/transformers/index.js.map +1 -0
- package/dist/esm/transformers/sourceTrace.js +50 -0
- package/dist/esm/transformers/sourceTrace.js.map +1 -0
- package/dist/esm/utils/effectDetection.js +59 -0
- package/dist/esm/utils/effectDetection.js.map +1 -0
- package/dist/esm/utils/hoisting.js +70 -0
- package/dist/esm/utils/hoisting.js.map +1 -0
- package/dist/esm/vite.js +27 -0
- package/dist/esm/vite.js.map +1 -0
- package/dist/esm/webpack.js +27 -0
- package/dist/esm/webpack.js.map +1 -0
- package/esbuild/package.json +6 -0
- package/package.json +81 -0
- package/rollup/package.json +6 -0
- package/rspack/package.json +6 -0
- package/src/esbuild.ts +30 -0
- package/src/index.ts +218 -0
- package/src/rollup.ts +29 -0
- package/src/rspack.ts +29 -0
- package/src/transformers/index.ts +6 -0
- package/src/transformers/sourceTrace.ts +102 -0
- package/src/utils/effectDetection.ts +81 -0
- package/src/utils/hoisting.ts +132 -0
- package/src/vite.ts +29 -0
- package/src/webpack.ts +29 -0
- package/vite/package.json +6 -0
- package/webpack/package.json +6 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a CallExpression is `Effect.gen(...)`.
|
|
3
|
+
*/
|
|
4
|
+
export function isEffectGenCall(node) {
|
|
5
|
+
if (node.type !== "CallExpression")
|
|
6
|
+
return false;
|
|
7
|
+
const callee = node.callee;
|
|
8
|
+
// Match Effect.gen(...)
|
|
9
|
+
if (callee.type === "MemberExpression" &&
|
|
10
|
+
callee.object.type === "Identifier" &&
|
|
11
|
+
callee.object.name === "Effect" &&
|
|
12
|
+
callee.property.type === "Identifier" &&
|
|
13
|
+
callee.property.name === "gen") {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
// Match _.gen(...) where _ is an alias for Effect
|
|
17
|
+
if (callee.type === "MemberExpression" &&
|
|
18
|
+
callee.property.type === "Identifier" &&
|
|
19
|
+
callee.property.name === "gen") {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Checks if a node is inside an Effect.gen generator function.
|
|
26
|
+
* This walks up the AST to find if there's an enclosing generator function
|
|
27
|
+
* that is an argument to Effect.gen.
|
|
28
|
+
*/
|
|
29
|
+
export function isInsideEffectGen(path) {
|
|
30
|
+
let current = path.parentPath;
|
|
31
|
+
while (current) {
|
|
32
|
+
const node = current.parent;
|
|
33
|
+
if (node && isEffectGenCall(node)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
current = current.parentPath;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Checks if a CallExpression is a call to the adapter function `_()`.
|
|
42
|
+
* The adapter is the first argument passed to the generator function.
|
|
43
|
+
*/
|
|
44
|
+
export function isAdapterCall(node) {
|
|
45
|
+
return node.callee.type === "Identifier" && node.callee.name === "_";
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Checks if a YieldExpression is a `yield* _(effect)` pattern.
|
|
49
|
+
*/
|
|
50
|
+
export function isYieldAdapterCall(node) {
|
|
51
|
+
if (!node.delegate)
|
|
52
|
+
return false; // Must be yield*, not yield
|
|
53
|
+
if (!node.argument)
|
|
54
|
+
return false;
|
|
55
|
+
if (node.argument.type !== "CallExpression")
|
|
56
|
+
return false;
|
|
57
|
+
return isAdapterCall(node.argument);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=effectDetection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effectDetection.js","sourceRoot":"","sources":["../../../src/utils/effectDetection.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,KAAK,CAAA;IAEhD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAE1B,wBAAwB;IACxB,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;QAClC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;QACnC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;QACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,KAAK,EAC9B,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,kDAAkD;IAClD,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;QAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;QACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,KAAK,EAC9B,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAWD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAc;IAC9C,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,CAAA;IAC7B,OAAO,OAAO,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,OAAO,CAAC,MAA4B,CAAA;QACjD,IAAI,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,UAAU,CAAA;IAC9B,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAsB;IAClD,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAA;AACtE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAuB;IACxD,IAAI,CAAC,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA,CAAC,4BAA4B;IAC7D,IAAI,CAAC,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,KAAK,CAAA;IACzD,OAAO,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;AACrC,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for hoisting trace metadata to module scope.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.1.0
|
|
5
|
+
*/
|
|
6
|
+
import * as t from "@babel/types";
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new hoisting state.
|
|
9
|
+
*/
|
|
10
|
+
export function createHoistingState() {
|
|
11
|
+
return {
|
|
12
|
+
hoistedTraces: new Map(),
|
|
13
|
+
counter: 0,
|
|
14
|
+
statements: []
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates a unique deduplication key for a source location.
|
|
19
|
+
* Uses line:column to disambiguate multiple yields on the same line.
|
|
20
|
+
*/
|
|
21
|
+
export function createDedupKey(filename, line, column) {
|
|
22
|
+
return `${filename}:${line}:${column}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Gets or creates a hoisted trace identifier for the given source location.
|
|
26
|
+
*/
|
|
27
|
+
export function getOrCreateTraceIdentifier(state, filename, line, column, label) {
|
|
28
|
+
const key = createDedupKey(filename, line, column);
|
|
29
|
+
let identifier = state.hoistedTraces.get(key);
|
|
30
|
+
if (identifier) {
|
|
31
|
+
return identifier;
|
|
32
|
+
}
|
|
33
|
+
// Create new identifier
|
|
34
|
+
identifier = t.identifier(`_trace${state.counter++}`);
|
|
35
|
+
state.hoistedTraces.set(key, identifier);
|
|
36
|
+
// Create the SourceLocation object literal
|
|
37
|
+
const properties = [
|
|
38
|
+
t.objectProperty(t.identifier("_tag"), t.stringLiteral("SourceLocation")),
|
|
39
|
+
t.objectProperty(t.identifier("path"), t.stringLiteral(filename)),
|
|
40
|
+
t.objectProperty(t.identifier("line"), t.numericLiteral(line)),
|
|
41
|
+
t.objectProperty(t.identifier("column"), t.numericLiteral(column))
|
|
42
|
+
];
|
|
43
|
+
if (label) {
|
|
44
|
+
properties.push(t.objectProperty(t.identifier("label"), t.stringLiteral(label)));
|
|
45
|
+
}
|
|
46
|
+
// Wrap in Symbol.for call to add the type tag
|
|
47
|
+
const traceObject = t.objectExpression([
|
|
48
|
+
t.objectProperty(t.callExpression(t.memberExpression(t.identifier("Symbol"), t.identifier("for")), [t.stringLiteral("effect/SourceLocation")]), t.callExpression(t.memberExpression(t.identifier("Symbol"), t.identifier("for")), [t.stringLiteral("effect/SourceLocation")]), true // computed property
|
|
49
|
+
),
|
|
50
|
+
...properties
|
|
51
|
+
]);
|
|
52
|
+
// Create variable declaration
|
|
53
|
+
const declaration = t.variableDeclaration("const", [
|
|
54
|
+
t.variableDeclarator(identifier, traceObject)
|
|
55
|
+
]);
|
|
56
|
+
state.statements.push(declaration);
|
|
57
|
+
return identifier;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Extracts a label from a VariableDeclarator if the yield is part of an assignment.
|
|
61
|
+
* For example: `const user = yield* _(fetchUser(id))` extracts "user"
|
|
62
|
+
*/
|
|
63
|
+
export function extractLabelFromParent(path) {
|
|
64
|
+
const parent = path.parent;
|
|
65
|
+
if (parent?.type === "VariableDeclarator" && parent.id.type === "Identifier") {
|
|
66
|
+
return parent.id.name;
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=hoisting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hoisting.js","sourceRoot":"","sources":["../../../src/utils/hoisting.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/vite.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin export for @effect/unplugin.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* // vite.config.ts
|
|
7
|
+
* import effectPlugin from "@effect/unplugin/vite"
|
|
8
|
+
*
|
|
9
|
+
* export default {
|
|
10
|
+
* plugins: [
|
|
11
|
+
* effectPlugin({
|
|
12
|
+
* sourceTrace: true
|
|
13
|
+
* })
|
|
14
|
+
* ]
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @since 0.1.0
|
|
19
|
+
*/
|
|
20
|
+
import { unplugin } from "./index.js";
|
|
21
|
+
/**
|
|
22
|
+
* Vite plugin for Effect transformations.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
*/
|
|
26
|
+
export default unplugin.vite;
|
|
27
|
+
//# sourceMappingURL=vite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","sourceRoot":"","sources":["../../src/vite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAA4B,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE/D;;;;GAIG;AACH,eAAe,QAAQ,CAAC,IAAI,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webpack plugin export for @effect/unplugin.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* // webpack.config.js
|
|
7
|
+
* const effectPlugin = require("@effect/unplugin/webpack").default
|
|
8
|
+
*
|
|
9
|
+
* module.exports = {
|
|
10
|
+
* plugins: [
|
|
11
|
+
* effectPlugin({
|
|
12
|
+
* sourceTrace: true
|
|
13
|
+
* })
|
|
14
|
+
* ]
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @since 0.1.0
|
|
19
|
+
*/
|
|
20
|
+
import { unplugin } from "./index.js";
|
|
21
|
+
/**
|
|
22
|
+
* Webpack plugin for Effect transformations.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
*/
|
|
26
|
+
export default unplugin.webpack;
|
|
27
|
+
//# sourceMappingURL=webpack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webpack.js","sourceRoot":"","sources":["../../src/webpack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAA4B,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE/D;;;;GAIG;AACH,eAAe,QAAQ,CAAC,OAAO,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clayroach/unplugin",
|
|
3
|
+
"version": "0.1.0-source-trace.2",
|
|
4
|
+
"description": "Universal bundler plugin for Effect transformations",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Effect-TS/effect.git",
|
|
9
|
+
"directory": "packages/unplugin"
|
|
10
|
+
},
|
|
11
|
+
"sideEffects": [],
|
|
12
|
+
"homepage": "https://effect.website",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"unplugin": "^2.3.2",
|
|
15
|
+
"@babel/types": "^7.26.0",
|
|
16
|
+
"@babel/parser": "^7.26.0",
|
|
17
|
+
"@babel/traverse": "^7.26.0",
|
|
18
|
+
"@babel/generator": "^7.26.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@clayroach/effect": "^3.19.14-source-trace.2"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"provenance": true
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/cjs/index.js",
|
|
27
|
+
"module": "./dist/esm/index.js",
|
|
28
|
+
"types": "./dist/dts/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
"./package.json": "./package.json",
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/dts/index.d.ts",
|
|
33
|
+
"import": "./dist/esm/index.js",
|
|
34
|
+
"default": "./dist/cjs/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./vite": {
|
|
37
|
+
"types": "./dist/dts/vite.d.ts",
|
|
38
|
+
"import": "./dist/esm/vite.js",
|
|
39
|
+
"default": "./dist/cjs/vite.js"
|
|
40
|
+
},
|
|
41
|
+
"./rollup": {
|
|
42
|
+
"types": "./dist/dts/rollup.d.ts",
|
|
43
|
+
"import": "./dist/esm/rollup.js",
|
|
44
|
+
"default": "./dist/cjs/rollup.js"
|
|
45
|
+
},
|
|
46
|
+
"./webpack": {
|
|
47
|
+
"types": "./dist/dts/webpack.d.ts",
|
|
48
|
+
"import": "./dist/esm/webpack.js",
|
|
49
|
+
"default": "./dist/cjs/webpack.js"
|
|
50
|
+
},
|
|
51
|
+
"./esbuild": {
|
|
52
|
+
"types": "./dist/dts/esbuild.d.ts",
|
|
53
|
+
"import": "./dist/esm/esbuild.js",
|
|
54
|
+
"default": "./dist/cjs/esbuild.js"
|
|
55
|
+
},
|
|
56
|
+
"./rspack": {
|
|
57
|
+
"types": "./dist/dts/rspack.d.ts",
|
|
58
|
+
"import": "./dist/esm/rspack.js",
|
|
59
|
+
"default": "./dist/cjs/rspack.js"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"typesVersions": {
|
|
63
|
+
"*": {
|
|
64
|
+
"vite": [
|
|
65
|
+
"./dist/dts/vite.d.ts"
|
|
66
|
+
],
|
|
67
|
+
"rollup": [
|
|
68
|
+
"./dist/dts/rollup.d.ts"
|
|
69
|
+
],
|
|
70
|
+
"webpack": [
|
|
71
|
+
"./dist/dts/webpack.d.ts"
|
|
72
|
+
],
|
|
73
|
+
"esbuild": [
|
|
74
|
+
"./dist/dts/esbuild.d.ts"
|
|
75
|
+
],
|
|
76
|
+
"rspack": [
|
|
77
|
+
"./dist/dts/rspack.d.ts"
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/esbuild.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* esbuild plugin export for @effect/unplugin.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* // build.js
|
|
7
|
+
* import * as esbuild from "esbuild"
|
|
8
|
+
* import effectPlugin from "@effect/unplugin/esbuild"
|
|
9
|
+
*
|
|
10
|
+
* await esbuild.build({
|
|
11
|
+
* plugins: [
|
|
12
|
+
* effectPlugin({
|
|
13
|
+
* sourceTrace: true
|
|
14
|
+
* })
|
|
15
|
+
* ]
|
|
16
|
+
* })
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @since 0.1.0
|
|
20
|
+
*/
|
|
21
|
+
import { type EffectPluginOptions, unplugin } from "./index.js"
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* esbuild plugin for Effect transformations.
|
|
25
|
+
*
|
|
26
|
+
* @since 0.1.0
|
|
27
|
+
*/
|
|
28
|
+
export default unplugin.esbuild
|
|
29
|
+
|
|
30
|
+
export type { EffectPluginOptions }
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @effect/unplugin - Universal bundler plugin for Effect transformations.
|
|
3
|
+
*
|
|
4
|
+
* This plugin provides build-time transformations for Effect code:
|
|
5
|
+
* - Source trace injection for automatic log prefixing and debugging
|
|
6
|
+
* - Pure call annotations for tree-shaking optimization
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* // vite.config.ts
|
|
11
|
+
* import effectPlugin from "@effect/unplugin/vite"
|
|
12
|
+
*
|
|
13
|
+
* export default {
|
|
14
|
+
* plugins: [
|
|
15
|
+
* effectPlugin({
|
|
16
|
+
* sourceTrace: true
|
|
17
|
+
* })
|
|
18
|
+
* ]
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @since 0.1.0
|
|
23
|
+
*/
|
|
24
|
+
import type { GeneratorResult } from "@babel/generator"
|
|
25
|
+
import _generate from "@babel/generator"
|
|
26
|
+
import { parse } from "@babel/parser"
|
|
27
|
+
import type { Scope, TraverseOptions, Visitor } from "@babel/traverse"
|
|
28
|
+
import _traverse from "@babel/traverse"
|
|
29
|
+
import type { Node } from "@babel/types"
|
|
30
|
+
import { createUnplugin, type UnpluginFactory, type UnpluginInstance } from "unplugin"
|
|
31
|
+
import { createSourceTraceVisitor } from "./transformers/sourceTrace.js"
|
|
32
|
+
import type { HoistingState } from "./utils/hoisting.js"
|
|
33
|
+
|
|
34
|
+
// Define function types for Babel packages (they export differently in ESM vs CJS)
|
|
35
|
+
type TraverseFn = <S>(
|
|
36
|
+
parent: Node,
|
|
37
|
+
opts: TraverseOptions<S>,
|
|
38
|
+
scope: Scope | undefined,
|
|
39
|
+
state: S
|
|
40
|
+
) => void
|
|
41
|
+
|
|
42
|
+
type GenerateFn = (
|
|
43
|
+
ast: Node,
|
|
44
|
+
opts?: { sourceMaps?: boolean; sourceFileName?: string },
|
|
45
|
+
code?: string
|
|
46
|
+
) => GeneratorResult
|
|
47
|
+
|
|
48
|
+
// Handle both ESM and CJS module exports for Babel packages
|
|
49
|
+
const traverse: TraverseFn = typeof _traverse === "function"
|
|
50
|
+
? _traverse as TraverseFn
|
|
51
|
+
: (_traverse as unknown as { default: TraverseFn }).default
|
|
52
|
+
|
|
53
|
+
const generate: GenerateFn = typeof _generate === "function"
|
|
54
|
+
? _generate as GenerateFn
|
|
55
|
+
: (_generate as unknown as { default: GenerateFn }).default
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Internal state used by transformers during AST traversal.
|
|
59
|
+
*/
|
|
60
|
+
interface TransformState {
|
|
61
|
+
filename: string
|
|
62
|
+
hoisting: HoistingState
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Configuration options for the Effect plugin.
|
|
67
|
+
*
|
|
68
|
+
* @since 0.1.0
|
|
69
|
+
*/
|
|
70
|
+
export interface EffectPluginOptions {
|
|
71
|
+
/**
|
|
72
|
+
* Enable source trace injection into Effect.gen yields.
|
|
73
|
+
* When enabled, logs will automatically include source locations.
|
|
74
|
+
*
|
|
75
|
+
* @default true
|
|
76
|
+
*/
|
|
77
|
+
readonly sourceTrace?: boolean
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Enable @__PURE__ annotations for tree-shaking.
|
|
81
|
+
*
|
|
82
|
+
* @default false
|
|
83
|
+
*/
|
|
84
|
+
readonly annotateEffects?: boolean
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Glob patterns to include in transformation.
|
|
88
|
+
*
|
|
89
|
+
* @default ["**\/*.ts", "**\/*.tsx"]
|
|
90
|
+
*/
|
|
91
|
+
readonly include?: ReadonlyArray<string>
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Glob patterns to exclude from transformation.
|
|
95
|
+
*
|
|
96
|
+
* @default ["**\/node_modules/**", "**\/*.d.ts"]
|
|
97
|
+
*/
|
|
98
|
+
readonly exclude?: ReadonlyArray<string>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Default file patterns to include.
|
|
103
|
+
*/
|
|
104
|
+
const DEFAULT_INCLUDE = [/\.[jt]sx?$/]
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Default file patterns to exclude.
|
|
108
|
+
*/
|
|
109
|
+
const DEFAULT_EXCLUDE = [/node_modules/, /\.d\.ts$/]
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Checks if a file should be transformed based on include/exclude patterns.
|
|
113
|
+
*/
|
|
114
|
+
function shouldTransform(
|
|
115
|
+
id: string,
|
|
116
|
+
include: ReadonlyArray<string | RegExp>,
|
|
117
|
+
exclude: ReadonlyArray<string | RegExp>
|
|
118
|
+
): boolean {
|
|
119
|
+
// Check excludes first
|
|
120
|
+
for (const pattern of exclude) {
|
|
121
|
+
if (typeof pattern === "string") {
|
|
122
|
+
if (id.includes(pattern)) return false
|
|
123
|
+
} else if (pattern.test(id)) {
|
|
124
|
+
return false
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check includes
|
|
129
|
+
for (const pattern of include) {
|
|
130
|
+
if (typeof pattern === "string") {
|
|
131
|
+
if (id.includes(pattern)) return true
|
|
132
|
+
} else if (pattern.test(id)) {
|
|
133
|
+
return true
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Creates the unplugin factory.
|
|
142
|
+
*/
|
|
143
|
+
const unpluginFactory: UnpluginFactory<EffectPluginOptions | undefined> = (options = {}) => {
|
|
144
|
+
const {
|
|
145
|
+
annotateEffects: _annotateEffects = false,
|
|
146
|
+
exclude = DEFAULT_EXCLUDE,
|
|
147
|
+
include = DEFAULT_INCLUDE,
|
|
148
|
+
sourceTrace = true
|
|
149
|
+
} = options
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
name: "@effect/unplugin",
|
|
153
|
+
|
|
154
|
+
transformInclude(id) {
|
|
155
|
+
return shouldTransform(id, include as Array<string | RegExp>, exclude as Array<string | RegExp>)
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
transform(code, id) {
|
|
159
|
+
// Parse the source code
|
|
160
|
+
const ast = parse(code, {
|
|
161
|
+
sourceType: "module",
|
|
162
|
+
plugins: ["typescript", "jsx"]
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// Collect visitors
|
|
166
|
+
const visitors: Array<Visitor<TransformState>> = []
|
|
167
|
+
|
|
168
|
+
if (sourceTrace) {
|
|
169
|
+
visitors.push(createSourceTraceVisitor(id))
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Combine visitors
|
|
173
|
+
if (visitors.length === 0) {
|
|
174
|
+
return null
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Initialize state for each visitor
|
|
178
|
+
const states = visitors.map(() => ({
|
|
179
|
+
filename: id,
|
|
180
|
+
hoisting: {
|
|
181
|
+
hoistedTraces: new Map(),
|
|
182
|
+
counter: 0,
|
|
183
|
+
statements: []
|
|
184
|
+
}
|
|
185
|
+
}))
|
|
186
|
+
|
|
187
|
+
// Run each visitor
|
|
188
|
+
for (let i = 0; i < visitors.length; i++) {
|
|
189
|
+
traverse(ast, visitors[i], undefined, states[i])
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Generate output
|
|
193
|
+
const output = generate(ast, {
|
|
194
|
+
sourceMaps: true,
|
|
195
|
+
sourceFileName: id
|
|
196
|
+
}, code)
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
code: output.code,
|
|
200
|
+
map: output.map
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The unplugin instance.
|
|
208
|
+
*
|
|
209
|
+
* @since 0.1.0
|
|
210
|
+
*/
|
|
211
|
+
export const unplugin: UnpluginInstance<EffectPluginOptions | undefined, boolean> = createUnplugin(unpluginFactory)
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Default export for convenience.
|
|
215
|
+
*
|
|
216
|
+
* @since 0.1.0
|
|
217
|
+
*/
|
|
218
|
+
export default unplugin
|
package/src/rollup.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rollup plugin export for @effect/unplugin.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* // rollup.config.js
|
|
7
|
+
* import effectPlugin from "@effect/unplugin/rollup"
|
|
8
|
+
*
|
|
9
|
+
* export default {
|
|
10
|
+
* plugins: [
|
|
11
|
+
* effectPlugin({
|
|
12
|
+
* sourceTrace: true
|
|
13
|
+
* })
|
|
14
|
+
* ]
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @since 0.1.0
|
|
19
|
+
*/
|
|
20
|
+
import { type EffectPluginOptions, unplugin } from "./index.js"
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Rollup plugin for Effect transformations.
|
|
24
|
+
*
|
|
25
|
+
* @since 0.1.0
|
|
26
|
+
*/
|
|
27
|
+
export default unplugin.rollup
|
|
28
|
+
|
|
29
|
+
export type { EffectPluginOptions }
|
package/src/rspack.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rspack plugin export for @effect/unplugin.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* // rspack.config.js
|
|
7
|
+
* const effectPlugin = require("@effect/unplugin/rspack").default
|
|
8
|
+
*
|
|
9
|
+
* module.exports = {
|
|
10
|
+
* plugins: [
|
|
11
|
+
* effectPlugin({
|
|
12
|
+
* sourceTrace: true
|
|
13
|
+
* })
|
|
14
|
+
* ]
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @since 0.1.0
|
|
19
|
+
*/
|
|
20
|
+
import { type EffectPluginOptions, unplugin } from "./index.js"
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Rspack plugin for Effect transformations.
|
|
24
|
+
*
|
|
25
|
+
* @since 0.1.0
|
|
26
|
+
*/
|
|
27
|
+
export default unplugin.rspack
|
|
28
|
+
|
|
29
|
+
export type { EffectPluginOptions }
|