@clayroach/effect-unplugin 4.0.0-effect4-transformer.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/README.md ADDED
@@ -0,0 +1,384 @@
1
+ # @clayroach/effect-unplugin
2
+
3
+ Build-time AST transformer for Effect source location tracing and automatic span instrumentation.
4
+
5
+ ## Features
6
+
7
+ - **Source Tracing**: Transforms `yield*` expressions inside `Effect.gen()` to inject stack frame information
8
+ - **Span Instrumentation**: Auto-wraps Effect combinators with `Effect.withSpan()` for distributed tracing
9
+ - **OpenTelemetry Semantic Conventions**: Adds `code.filepath`, `code.lineno`, `code.column`, `code.function` attributes
10
+ - **Configurable Span Names**: Three formats - function-based, location-based, or full
11
+ - **Granular Control**: Depth-based or override-based filtering strategies
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pnpm add -D @clayroach/effect-unplugin
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ### Vite
22
+
23
+ ```typescript
24
+ // vite.config.ts
25
+ import { defineConfig } from 'vite'
26
+ import effectPlugin from '@clayroach/effect-unplugin/vite'
27
+
28
+ export default defineConfig({
29
+ plugins: [
30
+ effectPlugin({
31
+ sourceTrace: true,
32
+ spans: { enabled: true }
33
+ })
34
+ ]
35
+ })
36
+ ```
37
+
38
+ ### ESBuild
39
+
40
+ ```typescript
41
+ import effectPlugin from '@clayroach/effect-unplugin/esbuild'
42
+ import { build } from 'esbuild'
43
+
44
+ build({
45
+ plugins: [effectPlugin({ sourceTrace: true, spans: { enabled: true } })],
46
+ // ... other options
47
+ })
48
+ ```
49
+
50
+ ### Webpack / Rollup
51
+
52
+ ```typescript
53
+ import effectPlugin from '@clayroach/effect-unplugin/webpack'
54
+ // or
55
+ import effectPlugin from '@clayroach/effect-unplugin/rollup'
56
+ ```
57
+
58
+ ## Configuration
59
+
60
+ ### Basic Options
61
+
62
+ ```typescript
63
+ effectPlugin({
64
+ // Enable source tracing for yield* expressions (default: true)
65
+ sourceTrace: true,
66
+
67
+ // Extract function names from yield* arguments (default: true)
68
+ extractFunctionName: true,
69
+
70
+ // File patterns to include (default: .js, .ts, .jsx, .tsx)
71
+ include: /\.[jt]sx?$/,
72
+
73
+ // File patterns to exclude (default: node_modules)
74
+ exclude: /node_modules/,
75
+
76
+ // Span instrumentation options
77
+ spans: {
78
+ enabled: true,
79
+ include: ["gen", "fork", "all", "forEach"],
80
+ nameFormat: "function" // "function" | "location" | "full"
81
+ }
82
+ })
83
+ ```
84
+
85
+ ### Span Name Formats
86
+
87
+ Control how span names appear in traces:
88
+
89
+ **`"function"` (default)**: Use function/variable names
90
+ ```
91
+ effect.gen (fetchUser)
92
+ effect.all
93
+ effect.forEach (processItems)
94
+ ```
95
+
96
+ **`"location"`: Use file locations
97
+ ```
98
+ effect.gen (index.ts:23)
99
+ effect.all (index.ts:49)
100
+ effect.forEach (index.ts:59)
101
+ ```
102
+
103
+ **`"full"`: Include both
104
+ ```
105
+ effect.gen (fetchUser @ index.ts:23)
106
+ effect.all (index.ts:49)
107
+ effect.forEach (processItems @ index.ts:59)
108
+ ```
109
+
110
+ All formats include full source location in span attributes (`code.filepath`, `code.lineno`, etc.)
111
+
112
+ ## Instrumentation Strategies
113
+
114
+ Reduce overhead with fine-grained control over which Effect calls get instrumented.
115
+
116
+ ### Depth Strategy
117
+
118
+ Limit instrumentation by nesting depth:
119
+
120
+ ```typescript
121
+ spans: {
122
+ enabled: true,
123
+ strategy: {
124
+ type: "depth",
125
+ maxDepth: 2 // 0 = top-level only, 1 = one level deep, etc.
126
+ }
127
+ }
128
+ ```
129
+
130
+ **Per-combinator depth limits:**
131
+ ```typescript
132
+ spans: {
133
+ enabled: true,
134
+ strategy: {
135
+ type: "depth",
136
+ perCombinator: {
137
+ fork: 0, // Only top-level forks
138
+ gen: 1, // Gen + one level deep
139
+ all: Infinity // No limit on Effect.all
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ ### Override Strategy
146
+
147
+ Filter by file patterns and function names:
148
+
149
+ ```typescript
150
+ spans: {
151
+ enabled: true,
152
+ strategy: {
153
+ type: "overrides",
154
+ rules: {
155
+ // Only instrument forks in worker files
156
+ fork: {
157
+ files: "src/workers/**"
158
+ },
159
+ // Skip gen in tests and private functions
160
+ gen: {
161
+ excludeFiles: "**/*.test.ts",
162
+ excludeFunctions: "^_.*"
163
+ },
164
+ // Only instrument forEach in API handlers
165
+ forEach: {
166
+ files: ["src/api/**", "src/handlers/**"],
167
+ functions: "^handle.*"
168
+ }
169
+ }
170
+ }
171
+ }
172
+ ```
173
+
174
+ **Filter Options:**
175
+ - `files`: Glob patterns to include (single string or array)
176
+ - `excludeFiles`: Glob patterns to exclude
177
+ - `functions`: Regex patterns for function names to include
178
+ - `excludeFunctions`: Regex patterns for function names to exclude
179
+
180
+ ## Examples
181
+
182
+ ### Example 1: Reduce Fork Overhead
183
+
184
+ Only instrument top-level forks to avoid noisy background task traces:
185
+
186
+ ```typescript
187
+ spans: {
188
+ enabled: true,
189
+ strategy: {
190
+ type: "depth",
191
+ perCombinator: {
192
+ fork: 0,
193
+ forkDaemon: 0,
194
+ forkScoped: 0
195
+ }
196
+ }
197
+ }
198
+ ```
199
+
200
+ ### Example 2: Production-Only Instrumentation
201
+
202
+ Skip instrumentation in tests and development utilities:
203
+
204
+ ```typescript
205
+ spans: {
206
+ enabled: true,
207
+ strategy: {
208
+ type: "overrides",
209
+ rules: {
210
+ gen: {
211
+ excludeFiles: [
212
+ "**/*.test.ts",
213
+ "**/__tests__/**",
214
+ "src/dev/**"
215
+ ]
216
+ }
217
+ }
218
+ }
219
+ }
220
+ ```
221
+
222
+ ### Example 3: Selective High-Value Traces
223
+
224
+ Only instrument critical paths:
225
+
226
+ ```typescript
227
+ spans: {
228
+ enabled: true,
229
+ strategy: {
230
+ type: "overrides",
231
+ rules: {
232
+ gen: {
233
+ files: [
234
+ "src/api/**",
235
+ "src/workers/**",
236
+ "src/processors/**"
237
+ ]
238
+ },
239
+ fork: {
240
+ files: "src/workers/**",
241
+ functions: "^(background|worker).*"
242
+ }
243
+ }
244
+ }
245
+ }
246
+ ```
247
+
248
+ ## How It Works
249
+
250
+ ### Source Tracing
251
+
252
+ Transforms:
253
+ ```typescript
254
+ const fetchUser = (id: string) =>
255
+ Effect.gen(function* () {
256
+ yield* Console.log(`Fetching ${id}`)
257
+ return { id, name: `User ${id}` }
258
+ })
259
+ ```
260
+
261
+ Into:
262
+ ```typescript
263
+ const _sf0 = { name: "log", stack: () => "index.ts:3:4", parent: undefined }
264
+
265
+ const fetchUser = (id: string) =>
266
+ Effect.gen(function* () {
267
+ yield* Effect.updateService(
268
+ Console.log(`Fetching ${id}`),
269
+ References.CurrentStackFrame,
270
+ (parent) => ({ ..._sf0, parent })
271
+ )
272
+ return { id, name: `User ${id}` }
273
+ })
274
+ ```
275
+
276
+ ### Span Instrumentation
277
+
278
+ Transforms:
279
+ ```typescript
280
+ const program = Effect.gen(function* () {
281
+ const users = yield* Effect.all([
282
+ fetchUser('alice'),
283
+ fetchUser('bob')
284
+ ])
285
+ })
286
+ ```
287
+
288
+ Into:
289
+ ```typescript
290
+ const program = Effect.withSpan(
291
+ Effect.gen(function* () {
292
+ const users = yield* Effect.withSpan(
293
+ Effect.all([fetchUser('alice'), fetchUser('bob')]),
294
+ "effect.all",
295
+ {
296
+ attributes: {
297
+ "code.filepath": "src/index.ts",
298
+ "code.lineno": 5,
299
+ "code.column": 23,
300
+ "code.function": "effect.all"
301
+ }
302
+ }
303
+ )
304
+ }),
305
+ "effect.gen (program)",
306
+ {
307
+ attributes: {
308
+ "code.filepath": "src/index.ts",
309
+ "code.lineno": 3,
310
+ "code.column": 16,
311
+ "code.function": "program"
312
+ }
313
+ }
314
+ )
315
+ ```
316
+
317
+ ## Supported Combinators
318
+
319
+ - `gen` - Effect.gen()
320
+ - `fork` - Effect.fork()
321
+ - `forkDaemon` - Effect.forkDaemon()
322
+ - `forkScoped` - Effect.forkScoped()
323
+ - `all` - Effect.all()
324
+ - `forEach` - Effect.forEach()
325
+ - `filter` - Effect.filter()
326
+ - `reduce` - Effect.reduce()
327
+ - `iterate` - Effect.iterate()
328
+ - `loop` - Effect.loop()
329
+
330
+ ## API Reference
331
+
332
+ ### SourceTraceOptions
333
+
334
+ ```typescript
335
+ interface SourceTraceOptions {
336
+ include?: string | RegExp | Array<string | RegExp>
337
+ exclude?: string | RegExp | Array<string | RegExp>
338
+ sourceTrace?: boolean
339
+ extractFunctionName?: boolean
340
+ spans?: SpanInstrumentationOptions
341
+ }
342
+ ```
343
+
344
+ ### SpanInstrumentationOptions
345
+
346
+ ```typescript
347
+ interface SpanInstrumentationOptions {
348
+ enabled?: boolean
349
+ include?: Array<InstrumentableEffect>
350
+ exclude?: Array<InstrumentableEffect>
351
+ nameFormat?: "function" | "location" | "full"
352
+ strategy?: DepthInstrumentationStrategy | OverrideInstrumentationStrategy
353
+ }
354
+ ```
355
+
356
+ ### DepthInstrumentationStrategy
357
+
358
+ ```typescript
359
+ interface DepthInstrumentationStrategy {
360
+ type: "depth"
361
+ maxDepth?: number
362
+ perCombinator?: Partial<Record<InstrumentableEffect, number>>
363
+ }
364
+ ```
365
+
366
+ ### OverrideInstrumentationStrategy
367
+
368
+ ```typescript
369
+ interface OverrideInstrumentationStrategy {
370
+ type: "overrides"
371
+ rules: Partial<Record<InstrumentableEffect, CombinatorFilter>>
372
+ }
373
+
374
+ interface CombinatorFilter {
375
+ files?: string | Array<string>
376
+ excludeFiles?: string | Array<string>
377
+ functions?: string | Array<string> // Regex patterns
378
+ excludeFunctions?: string | Array<string> // Regex patterns
379
+ }
380
+ ```
381
+
382
+ ## License
383
+
384
+ MIT
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @since 0.0.1
3
+ * @category models
4
+ */
5
+ export interface AnnotateResult {
6
+ readonly code: string;
7
+ readonly map?: unknown;
8
+ readonly transformed: boolean;
9
+ }
10
+ /**
11
+ * Transforms source code to add pure annotations to Effect calls.
12
+ *
13
+ * @since 0.0.1
14
+ * @category transform
15
+ */
16
+ export declare function annotateEffects(code: string, id: string): AnnotateResult;
17
+ //# sourceMappingURL=annotateEffects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotateEffects.d.ts","sourceRoot":"","sources":["../src/annotateEffects.ts"],"names":[],"mappings":"AA2EA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;CAC9B;AA0ED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,CA8CxE"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Effect tree-shaking annotations transformer.
3
+ *
4
+ * Adds `\/* @__PURE__ *\/` comments to Effect calls for bundler tree-shaking.
5
+ *
6
+ * @since 0.0.1
7
+ */
8
+ import { parse } from "@babel/parser";
9
+ import * as _traverse from "@babel/traverse";
10
+ import * as _generate from "@babel/generator";
11
+ import * as t from "@babel/types";
12
+ // Handle CommonJS/ESM interop for babel packages
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ const traverseModule = _traverse;
15
+ const traverse = typeof traverseModule === "function" ? traverseModule : typeof traverseModule.default === "function" ? traverseModule.default : traverseModule.default?.default ?? traverseModule;
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ const generateModule = _generate;
18
+ const generate = typeof generateModule === "function" ? generateModule : typeof generateModule.default === "function" ? generateModule.default : generateModule.default?.default ?? generateModule;
19
+ /**
20
+ * Effect module names that should have pure annotations.
21
+ */
22
+ const EFFECT_MODULES = /*#__PURE__*/new Set(["Effect", "Option", "Either", "Data", "Schema", "Array", "Chunk", "HashMap", "HashSet", "List", "Queue", "Stream", "Layer", "Scope", "Ref", "SynchronizedRef", "SubscriptionRef", "Duration", "Schedule", "Cause", "Exit", "Match", "Boolean", "Number", "String", "Struct", "Tuple", "Function", "Predicate", "Order", "Equivalence", "Context", "Brand", "Types"]);
23
+ /**
24
+ * Checks if a call expression already has a pure annotation.
25
+ */
26
+ function hasPureAnnotation(node) {
27
+ const comments = node.leadingComments;
28
+ if (!comments) return false;
29
+ return comments.some(comment => comment.type === "CommentBlock" && (comment.value.includes("@__PURE__") || comment.value.includes("#__PURE__")));
30
+ }
31
+ /**
32
+ * Checks if a call is to an Effect module method.
33
+ */
34
+ function isEffectModuleCall(node) {
35
+ const callee = node.callee;
36
+ // Effect.succeed(...) or Option.some(...)
37
+ if (t.isMemberExpression(callee) && t.isIdentifier(callee.object) && EFFECT_MODULES.has(callee.object.name)) {
38
+ return true;
39
+ }
40
+ return false;
41
+ }
42
+ /**
43
+ * Checks if a CallExpression is in a context where pure annotation is useful.
44
+ * Only annotate calls in variable declarations or export declarations.
45
+ */
46
+ function isInAnnotatableContext(path) {
47
+ let parent = path.parentPath;
48
+ while (parent !== null) {
49
+ const node = parent.node;
50
+ // Variable declaration: const x = Effect.succeed(...)
51
+ if (t.isVariableDeclarator(node)) {
52
+ return true;
53
+ }
54
+ // Export: export const x = Effect.succeed(...)
55
+ if (t.isExportDefaultDeclaration(node) || t.isExportNamedDeclaration(node)) {
56
+ return true;
57
+ }
58
+ // Return statement: return Effect.succeed(...)
59
+ if (t.isReturnStatement(node)) {
60
+ return true;
61
+ }
62
+ // Arrow function body: () => Effect.succeed(...)
63
+ if (t.isArrowFunctionExpression(node)) {
64
+ return true;
65
+ }
66
+ // Stop at block statements
67
+ if (t.isBlockStatement(node) || t.isProgram(node)) {
68
+ break;
69
+ }
70
+ parent = parent.parentPath;
71
+ }
72
+ return false;
73
+ }
74
+ /**
75
+ * Transforms source code to add pure annotations to Effect calls.
76
+ *
77
+ * @since 0.0.1
78
+ * @category transform
79
+ */
80
+ export function annotateEffects(code, id) {
81
+ let ast;
82
+ try {
83
+ ast = parse(code, {
84
+ sourceType: "module",
85
+ plugins: ["typescript", "jsx"],
86
+ sourceFilename: id
87
+ });
88
+ } catch {
89
+ return {
90
+ code,
91
+ transformed: false
92
+ };
93
+ }
94
+ let hasTransformed = false;
95
+ traverse(ast, {
96
+ CallExpression(path) {
97
+ // Skip if already has pure annotation
98
+ if (hasPureAnnotation(path.node)) return;
99
+ // Only annotate Effect module calls
100
+ if (!isEffectModuleCall(path.node)) return;
101
+ // Only annotate in useful contexts
102
+ if (!isInAnnotatableContext(path)) return;
103
+ // Add @__PURE__ annotation
104
+ t.addComment(path.node, "leading", "#__PURE__", false);
105
+ hasTransformed = true;
106
+ }
107
+ });
108
+ if (!hasTransformed) {
109
+ return {
110
+ code,
111
+ transformed: false
112
+ };
113
+ }
114
+ const result = generate(ast, {
115
+ sourceMaps: true,
116
+ sourceFileName: id,
117
+ comments: true
118
+ }, code);
119
+ return {
120
+ code: result.code,
121
+ map: result.map,
122
+ transformed: true
123
+ };
124
+ }
125
+ //# sourceMappingURL=annotateEffects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotateEffects.js","names":["parse","_traverse","_generate","t","traverseModule","traverse","default","generateModule","generate","EFFECT_MODULES","Set","hasPureAnnotation","node","comments","leadingComments","some","comment","type","value","includes","isEffectModuleCall","callee","isMemberExpression","isIdentifier","object","has","name","isInAnnotatableContext","path","parent","parentPath","isVariableDeclarator","isExportDefaultDeclaration","isExportNamedDeclaration","isReturnStatement","isArrowFunctionExpression","isBlockStatement","isProgram","annotateEffects","code","id","ast","sourceType","plugins","sourceFilename","transformed","hasTransformed","CallExpression","addComment","result","sourceMaps","sourceFileName","map"],"sources":["../src/annotateEffects.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ declare const _default: (options?: import("./types.ts").SourceTraceOptions | undefined) => import("unplugin").EsbuildPlugin;
2
+ export default _default;
3
+ //# sourceMappingURL=esbuild.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"esbuild.d.ts","sourceRoot":"","sources":["../src/esbuild.ts"],"names":[],"mappings":";AAiBA,wBAA+B"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * esbuild plugin for Effect source location tracing.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import esbuild from "esbuild"
7
+ * import effectSourceTrace from "@effect/unplugin/esbuild"
8
+ *
9
+ * esbuild.build({
10
+ * plugins: [effectSourceTrace()]
11
+ * })
12
+ * ```
13
+ *
14
+ * @since 0.0.1
15
+ */
16
+ import unplugin from "./index.js";
17
+ export default unplugin.esbuild;
18
+ //# sourceMappingURL=esbuild.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"esbuild.js","names":["unplugin","esbuild"],"sources":["../src/esbuild.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;AAeA,OAAOA,QAAQ,MAAM,YAAY;AAEjC,eAAeA,QAAQ,CAACC,OAAO","ignoreList":[]}
@@ -0,0 +1,12 @@
1
+ import type { SourceTraceOptions } from "./types.ts";
2
+ export { type TransformResult } from "./sourceTrace.ts";
3
+ export type { FilterPattern, InstrumentableEffect, SourceTraceOptions, SpanInstrumentationOptions } from "./types.ts";
4
+ /**
5
+ * Creates the Effect source trace unplugin.
6
+ *
7
+ * @since 0.0.1
8
+ * @category unplugin
9
+ */
10
+ export declare const unplugin: import("unplugin").UnpluginInstance<SourceTraceOptions | undefined, boolean>;
11
+ export default unplugin;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAiB,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEnE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAA;AAiCrH;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,8EAmBnB,CAAA;AAEF,eAAe,QAAQ,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Build-time AST transformer for Effect source location tracing and auto-instrumentation.
3
+ *
4
+ * Provides two features:
5
+ * 1. **Source Tracing**: Transforms `yield*` expressions inside `Effect.gen()` to
6
+ * inject source location information via `CurrentStackFrame`.
7
+ * 2. **Span Instrumentation**: Wraps Effect combinators with `withSpan()` for
8
+ * automatic distributed tracing with OpenTelemetry semantic conventions.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * // vite.config.ts
13
+ * import { defineConfig } from "vite"
14
+ * import effectSourceTrace from "@effect/unplugin/vite"
15
+ *
16
+ * export default defineConfig({
17
+ * plugins: [effectSourceTrace({
18
+ * // Enable source tracing (default: true)
19
+ * sourceTrace: true,
20
+ * // Enable span instrumentation
21
+ * spans: {
22
+ * enabled: true,
23
+ * include: ["gen", "fork", "all", "forEach"],
24
+ * nameFormat: "function" // "function" | "location" | "full"
25
+ * }
26
+ * })]
27
+ * })
28
+ * ```
29
+ *
30
+ * @since 0.0.1
31
+ */
32
+ import { createUnplugin } from "unplugin";
33
+ import { transform } from "./sourceTrace.js";
34
+ export {} from "./sourceTrace.js";
35
+ const defaultInclude = [/\.[jt]sx?$/];
36
+ const defaultExclude = [/node_modules/];
37
+ function toArray(value) {
38
+ if (value === undefined) return [];
39
+ if (Array.isArray(value)) return value;
40
+ return [value];
41
+ }
42
+ function createFilter(include, exclude) {
43
+ const includePatterns = toArray(include ?? defaultInclude);
44
+ const excludePatterns = toArray(exclude ?? defaultExclude);
45
+ return id => {
46
+ for (const pattern of excludePatterns) {
47
+ if (typeof pattern === "string" ? id.includes(pattern) : pattern.test(id)) {
48
+ return false;
49
+ }
50
+ }
51
+ for (const pattern of includePatterns) {
52
+ if (typeof pattern === "string" ? id.includes(pattern) : pattern.test(id)) {
53
+ return true;
54
+ }
55
+ }
56
+ return false;
57
+ };
58
+ }
59
+ /**
60
+ * Creates the Effect source trace unplugin.
61
+ *
62
+ * @since 0.0.1
63
+ * @category unplugin
64
+ */
65
+ export const unplugin = /*#__PURE__*/createUnplugin((options = {}) => {
66
+ const filter = createFilter(options.include, options.exclude);
67
+ return {
68
+ name: "effect-source-trace",
69
+ enforce: "pre",
70
+ transformInclude(id) {
71
+ return filter(id);
72
+ },
73
+ transform(code, id) {
74
+ const result = transform(code, id, options);
75
+ if (!result.transformed) {
76
+ return null;
77
+ }
78
+ return {
79
+ code: result.code,
80
+ map: result.map
81
+ };
82
+ }
83
+ };
84
+ });
85
+ export default unplugin;
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["createUnplugin","transform","defaultInclude","defaultExclude","toArray","value","undefined","Array","isArray","createFilter","include","exclude","includePatterns","excludePatterns","id","pattern","includes","test","unplugin","options","filter","name","enforce","transformInclude","code","result","transformed","map"],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAASA,cAAc,QAAyD,UAAU;AAC1F,SAASC,SAAS,QAAQ,kBAAkB;AAG5C,eAAqC,kBAAkB;AAGvD,MAAMC,cAAc,GAAmC,CAAC,YAAY,CAAC;AACrE,MAAMC,cAAc,GAAmC,CAAC,cAAc,CAAC;AAEvE,SAASC,OAAOA,CAACC,KAAgC;EAC/C,IAAIA,KAAK,KAAKC,SAAS,EAAE,OAAO,EAAE;EAClC,IAAIC,KAAK,CAACC,OAAO,CAACH,KAAK,CAAC,EAAE,OAAOA,KAAK;EACtC,OAAO,CAACA,KAAwB,CAAC;AACnC;AAEA,SAASI,YAAYA,CACnBC,OAAkC,EAClCC,OAAkC;EAElC,MAAMC,eAAe,GAAGR,OAAO,CAACM,OAAO,IAAIR,cAAc,CAAC;EAC1D,MAAMW,eAAe,GAAGT,OAAO,CAACO,OAAO,IAAIR,cAAc,CAAC;EAE1D,OAAQW,EAAU,IAAa;IAC7B,KAAK,MAAMC,OAAO,IAAIF,eAAe,EAAE;MACrC,IAAI,OAAOE,OAAO,KAAK,QAAQ,GAAGD,EAAE,CAACE,QAAQ,CAACD,OAAO,CAAC,GAAGA,OAAO,CAACE,IAAI,CAACH,EAAE,CAAC,EAAE;QACzE,OAAO,KAAK;MACd;IACF;IACA,KAAK,MAAMC,OAAO,IAAIH,eAAe,EAAE;MACrC,IAAI,OAAOG,OAAO,KAAK,QAAQ,GAAGD,EAAE,CAACE,QAAQ,CAACD,OAAO,CAAC,GAAGA,OAAO,CAACE,IAAI,CAACH,EAAE,CAAC,EAAE;QACzE,OAAO,IAAI;MACb;IACF;IACA,OAAO,KAAK;EACd,CAAC;AACH;AAEA;;;;;;AAMA,OAAO,MAAMI,QAAQ,gBAAGlB,cAAc,CAAiC,CAACmB,OAAO,GAAG,EAAE,KAAI;EACtF,MAAMC,MAAM,GAAGX,YAAY,CAACU,OAAO,CAACT,OAAO,EAAES,OAAO,CAACR,OAAO,CAAC;EAE7D,OAAO;IACLU,IAAI,EAAE,qBAAqB;IAC3BC,OAAO,EAAE,KAAK;IAEdC,gBAAgBA,CAACT,EAAE;MACjB,OAAOM,MAAM,CAACN,EAAE,CAAC;IACnB,CAAC;IAEDb,SAASA,CAACuB,IAAI,EAAEV,EAAE;MAChB,MAAMW,MAAM,GAAGxB,SAAS,CAACuB,IAAI,EAAEV,EAAE,EAAEK,OAAO,CAAC;MAC3C,IAAI,CAACM,MAAM,CAACC,WAAW,EAAE;QACvB,OAAO,IAAI;MACb;MACA,OAAO;QAAEF,IAAI,EAAEC,MAAM,CAACD,IAAI;QAAEG,GAAG,EAAEF,MAAM,CAACE;MAAG,CAA6B;IAC1E;GACD;AACH,CAAC,CAAC;AAEF,eAAeT,QAAQ","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ declare const _default: (options?: import("./types.ts").SourceTraceOptions | undefined) => import("rollup").Plugin<any> | import("rollup").Plugin<any>[];
2
+ export default _default;
3
+ //# sourceMappingURL=rollup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../src/rollup.ts"],"names":[],"mappings":";AAiBA,wBAA8B"}