unplugin-react-fine-grained-signals 0.1.0

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/loader.js ADDED
@@ -0,0 +1,160 @@
1
+ import { Buffer } from "node:buffer";
2
+ //#region src/loader.ts
3
+ /**
4
+ * The webpack/rspack transform loader.
5
+ *
6
+ * unplugin ships its own loader for both compilers, and both copies of it hand
7
+ * the transform's source map on with
8
+ * `callback(null, res.code, map == null ? map : res.map || map)` -- so a plugin
9
+ * that runs with `enforce: "pre"`, and therefore sees no incoming map at all in
10
+ * a normal configuration, has its map discarded every single time. That matters
11
+ * here because Babel re-prints the whole file: every line number shifts, and a
12
+ * downstream loader then builds its map treating the already-transformed text
13
+ * as the original source, so breakpoints and stack traces land on lines that do
14
+ * not exist. Vite, Rollup and esbuild take the map straight off the `transform`
15
+ * hook's return value and are unaffected.
16
+ *
17
+ * This is that same loader with its map handling corrected, so
18
+ * `src/unplugin.ts` points the compiler's loader rule here instead:
19
+ *
20
+ * - with no incoming map -- the ordinary `enforce: "pre"` case -- the map the
21
+ * transform produced is passed on rather than dropped;
22
+ * - with an incoming map -- webpack lets several `pre` loaders chain, so
23
+ * `enforce: "pre"` does not actually guarantee this one runs first -- the two
24
+ * are composed, so neither the upstream loader's edits nor this transform's
25
+ * are lost from the positions a debugger ends up with.
26
+ */
27
+ function toError(thrown) {
28
+ return thrown instanceof Error ? thrown : new Error(String(thrown));
29
+ }
30
+ /** webpack hands the incoming map on as an object or as its JSON text. */
31
+ function toSourceMapObject(map) {
32
+ if (typeof map === "string") try {
33
+ const parsed = JSON.parse(map);
34
+ return parsed !== null && typeof parsed === "object" ? parsed : null;
35
+ } catch {
36
+ return null;
37
+ }
38
+ return map !== null && typeof map === "object" ? map : null;
39
+ }
40
+ /**
41
+ * A `sourceMappingURL` comment naming a map file rather than carrying one.
42
+ *
43
+ * Babel strips these itself, but only on the branch it takes when it found no
44
+ * input map -- so appending an input map below suppresses that stripping and
45
+ * would leave a stale `//# sourceMappingURL=App.tsx.map` line in the output.
46
+ * Rather than cut such a comment out of the source by hand (a text edit to the
47
+ * author's file, on a guess about what is comment and what is string), a file
48
+ * that carries one simply does not get an input map appended: it keeps exactly
49
+ * the behaviour it had before this loader forwarded incoming maps at all.
50
+ * Matching too eagerly therefore only costs composition for that one file,
51
+ * which is why this looks for the shape and not for a precise comment.
52
+ */
53
+ const EXTERNAL_SOURCE_MAP_COMMENT = /(?:\/\/|\/\*)[@#][ \t]+sourceMappingURL=(?!data:)/;
54
+ /**
55
+ * The incoming map re-attached to `source` as a trailing inline
56
+ * `sourceMappingURL` comment, or `null` when there is no map worth attaching.
57
+ *
58
+ * Composing has to happen inside the Babel run that re-prints the file: Babel
59
+ * is the only thing that knows how its output positions relate to its input,
60
+ * and it already merges an input map into the map it emits. Its `inputSourceMap`
61
+ * option defaults to reading that map out of exactly this comment, and it lifts
62
+ * the comment out of the AST as it reads it, so nothing of it reaches the
63
+ * printed output -- which makes this the transform's `inputSourceMap` channel
64
+ * without the transform needing an option for it.
65
+ *
66
+ * Forwarding the incoming map must never make the result worse than not
67
+ * forwarding it, so several shapes are left behind rather than passed on: a map
68
+ * with no `sources` array makes Babel throw outright, and one whose `sources`
69
+ * is present but empty composes into a map with no sources at all, throwing
70
+ * away the perfectly good file name the transform's own map would have had.
71
+ */
72
+ function inlineSourceMapComment(map, source) {
73
+ const candidate = toSourceMapObject(map);
74
+ if (candidate === null) return null;
75
+ if (Number(candidate.version) !== 3) return null;
76
+ if (typeof candidate.mappings !== "string") return null;
77
+ if (!Array.isArray(candidate.sources) || candidate.sources.length === 0) return null;
78
+ if (EXTERNAL_SOURCE_MAP_COMMENT.test(source)) return null;
79
+ let json;
80
+ try {
81
+ json = JSON.stringify(candidate);
82
+ } catch {
83
+ return null;
84
+ }
85
+ return `\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${Buffer.from(json, "utf8").toString("base64")}`;
86
+ }
87
+ /**
88
+ * Removes occurrences of the exact text appended above from a transform's
89
+ * result. Babel takes its own copy back out as it reads it, so this is for a
90
+ * `transform` hook that is not Babel and would print it straight back.
91
+ *
92
+ * The guarantee is only that: every byte-identical occurrence goes, whether or
93
+ * not this loader is what put it there. A file already containing a comment
94
+ * byte-identical to the one generated here -- which means already carrying this
95
+ * exact incoming map, inline -- would lose it, and is accepted as an edge case;
96
+ * on the Babel path it would not have survived anyway, since Babel filters out
97
+ * every inline map comment it sees rather than only the last. A comment naming
98
+ * a map *file* is a different matter and is handled before the fact, by
99
+ * `EXTERNAL_SOURCE_MAP_COMMENT` above.
100
+ */
101
+ function withoutInlineSourceMap(code, comment) {
102
+ return comment === null ? code : code.replaceAll(comment, "");
103
+ }
104
+ /**
105
+ * The `this` a `transform` hook is called with. This plugin's own transform is
106
+ * a pure `(code, id)` function that never touches it, so rather than rebuild
107
+ * unplugin's full build context out of compiler internals, this forwards the
108
+ * few context methods that have a direct loader equivalent and leaves it there.
109
+ */
110
+ function createHookContext(loaderContext) {
111
+ return {
112
+ addWatchFile(file) {
113
+ loaderContext.addDependency?.(file);
114
+ },
115
+ getWatchFiles() {
116
+ return loaderContext.getDependencies?.() ?? [];
117
+ },
118
+ error(message) {
119
+ throw toError(message);
120
+ },
121
+ warn(message) {
122
+ const warning = toError(message);
123
+ if (loaderContext.emitWarning !== void 0) loaderContext.emitWarning(warning);
124
+ else console.warn(warning.message);
125
+ }
126
+ };
127
+ }
128
+ function reactFineGrainedSignalsLoader(source, map) {
129
+ const callback = this.async();
130
+ const query = this.query;
131
+ const plugin = query !== null && typeof query === "object" ? query.plugin ?? void 0 : void 0;
132
+ const hook = plugin?.transform;
133
+ const handler = typeof hook === "function" ? hook : hook?.handler;
134
+ if (handler === void 0) {
135
+ callback(null, source, map);
136
+ return;
137
+ }
138
+ const id = this.resource;
139
+ if (plugin?.transformInclude !== void 0 && plugin.transformInclude(id) !== true) {
140
+ callback(null, source, map);
141
+ return;
142
+ }
143
+ const runTransform = (input) => {
144
+ try {
145
+ return Promise.resolve(handler.call(createHookContext(this), input, id));
146
+ } catch (thrown) {
147
+ return Promise.reject(toError(thrown));
148
+ }
149
+ };
150
+ const inlineMap = inlineSourceMapComment(map, source);
151
+ (inlineMap === null ? runTransform(source) : runTransform(source + inlineMap).catch(() => runTransform(source))).then((result) => {
152
+ if (result === null || result === void 0) callback(null, source, map);
153
+ else if (typeof result === "string") callback(null, withoutInlineSourceMap(result, inlineMap), map);
154
+ else callback(null, withoutInlineSourceMap(result.code, inlineMap), result.map ?? map);
155
+ }, (thrown) => {
156
+ callback(toError(thrown));
157
+ });
158
+ }
159
+ //#endregion
160
+ export { reactFineGrainedSignalsLoader as default };
@@ -0,0 +1,11 @@
1
+ import { a as createBundlerPlugin, c as resolveEsbuildLoader, d as ReactFineGrainedSignalsTransform, i as canTransform, l as ReactFineGrainedSignalsMode, n as EsbuildLoaderName, o as pluginName, r as ReactFineGrainedSignalsOptions, s as reactFineGrainedSignals, t as BundlerTransformOutput, u as ReactFineGrainedSignalsReactCompiler } from "./unplugin-CG9_mdcA.js";
2
+ //#region src/rollup.d.ts
3
+ /** A minimal Rollup-compatible plugin shape. */
4
+ interface RollupPlugin {
5
+ name: string;
6
+ enforce?: "pre" | "post";
7
+ transform?: (code: string, id: string) => BundlerTransformOutput;
8
+ }
9
+ declare const _default: (options?: ReactFineGrainedSignalsOptions) => RollupPlugin;
10
+ //#endregion
11
+ export { BundlerTransformOutput, EsbuildLoaderName, type ReactFineGrainedSignalsMode, ReactFineGrainedSignalsOptions, type ReactFineGrainedSignalsReactCompiler, type ReactFineGrainedSignalsTransform, RollupPlugin, canTransform, createBundlerPlugin, _default as default, pluginName, reactFineGrainedSignals, resolveEsbuildLoader };
package/dist/rollup.js ADDED
@@ -0,0 +1,5 @@
1
+ import { a as resolveEsbuildLoader, i as reactFineGrainedSignals, n as createBundlerPlugin, r as pluginName, t as canTransform } from "./unplugin-B2_q8KNi.js";
2
+ //#region src/rollup.ts
3
+ var rollup_default = createBundlerPlugin("rollup");
4
+ //#endregion
5
+ export { canTransform, createBundlerPlugin, rollup_default as default, pluginName, reactFineGrainedSignals, resolveEsbuildLoader };
@@ -0,0 +1,9 @@
1
+ import { a as createBundlerPlugin, c as resolveEsbuildLoader, d as ReactFineGrainedSignalsTransform, i as canTransform, l as ReactFineGrainedSignalsMode, n as EsbuildLoaderName, o as pluginName, r as ReactFineGrainedSignalsOptions, s as reactFineGrainedSignals, t as BundlerTransformOutput, u as ReactFineGrainedSignalsReactCompiler } from "./unplugin-CG9_mdcA.js";
2
+ //#region src/rspack.d.ts
3
+ /** The compiler-plugin contract used by Rspack. */
4
+ interface RspackPlugin {
5
+ apply(compiler: unknown): void;
6
+ }
7
+ declare const _default: (options?: ReactFineGrainedSignalsOptions) => RspackPlugin;
8
+ //#endregion
9
+ export { BundlerTransformOutput, EsbuildLoaderName, type ReactFineGrainedSignalsMode, ReactFineGrainedSignalsOptions, type ReactFineGrainedSignalsReactCompiler, type ReactFineGrainedSignalsTransform, RspackPlugin, canTransform, createBundlerPlugin, _default as default, pluginName, reactFineGrainedSignals, resolveEsbuildLoader };
package/dist/rspack.js ADDED
@@ -0,0 +1,5 @@
1
+ import { a as resolveEsbuildLoader, i as reactFineGrainedSignals, n as createBundlerPlugin, r as pluginName, t as canTransform } from "./unplugin-B2_q8KNi.js";
2
+ //#region src/rspack.ts
3
+ var rspack_default = createBundlerPlugin("rspack");
4
+ //#endregion
5
+ export { canTransform, createBundlerPlugin, rspack_default as default, pluginName, reactFineGrainedSignals, resolveEsbuildLoader };