@wyw-in-js/babel-preset 1.1.0 → 2.0.0-alpha.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/esm/globals.js +104 -0
- package/esm/globals.js.map +1 -0
- package/esm/index.js +191 -9
- package/esm/index.js.map +1 -1
- package/esm/sync-transform-runner.js +63 -0
- package/esm/sync-transform-runner.js.map +1 -0
- package/package.json +14 -8
- package/types/globals.d.ts +2 -0
- package/types/globals.js +123 -0
- package/types/index.d.ts +4 -3
- package/types/index.js +209 -6
- package/types/sync-transform-runner.d.ts +1 -0
- package/types/sync-transform-runner.js +66 -0
- package/lib/index.js +0 -19
- package/lib/index.js.map +0 -1
package/esm/globals.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const ENCODED_GLOBAL_ENVELOPE_KEY = "__wyw_eval_global";
|
|
2
|
+
const ENCODED_GLOBAL_SIGNATURE = "wyw-eval-global";
|
|
3
|
+
const ENCODED_GLOBAL_VERSION = 1;
|
|
4
|
+
const isPlainObject = (value) => {
|
|
5
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9
|
+
return prototype === null || prototype === Object.prototype;
|
|
10
|
+
};
|
|
11
|
+
const formatGlobalsPath = (path) => path.reduce((acc, segment) => {
|
|
12
|
+
if (typeof segment === "number") {
|
|
13
|
+
return `${acc}[${segment}]`;
|
|
14
|
+
}
|
|
15
|
+
return /^[A-Za-z_$][\w$]*$/u.test(segment) ? `${acc}.${segment}` : `${acc}[${JSON.stringify(segment)}]`;
|
|
16
|
+
}, "eval.globals");
|
|
17
|
+
const validateFunctionSource = (source, path) => {
|
|
18
|
+
try {
|
|
19
|
+
// eslint-disable-next-line no-eval
|
|
20
|
+
const restored = eval(`(${source})`);
|
|
21
|
+
if (typeof restored !== "function") {
|
|
22
|
+
throw new TypeError("decoded source is not a function");
|
|
23
|
+
}
|
|
24
|
+
} catch (error) {
|
|
25
|
+
throw new Error(`[wyw-in-js] eval.globals contains an unsupported function at ${formatGlobalsPath(path)}. ` + `Ensure the value is a user-defined function expression/arrow function. ` + `Native and bound functions are not supported. ` + `Original error: ${String(error)}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const encodeGlobalsAtPath = (value, path) => {
|
|
29
|
+
if (typeof value === "function") {
|
|
30
|
+
const source = value.toString();
|
|
31
|
+
validateFunctionSource(source, path);
|
|
32
|
+
return { [ENCODED_GLOBAL_ENVELOPE_KEY]: {
|
|
33
|
+
signature: ENCODED_GLOBAL_SIGNATURE,
|
|
34
|
+
version: ENCODED_GLOBAL_VERSION,
|
|
35
|
+
kind: "function",
|
|
36
|
+
source
|
|
37
|
+
} };
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === "symbol") {
|
|
40
|
+
return { [ENCODED_GLOBAL_ENVELOPE_KEY]: {
|
|
41
|
+
signature: ENCODED_GLOBAL_SIGNATURE,
|
|
42
|
+
version: ENCODED_GLOBAL_VERSION,
|
|
43
|
+
kind: "symbol",
|
|
44
|
+
description: value.description ?? ""
|
|
45
|
+
} };
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
return value.map((item, index) => encodeGlobalsAtPath(item, [...path, index]));
|
|
49
|
+
}
|
|
50
|
+
if (isPlainObject(value)) {
|
|
51
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, encodeGlobalsAtPath(item, [...path, key])]));
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === "object" && value !== null) {
|
|
54
|
+
throw new Error(`[wyw-in-js] eval.globals contains an unsupported non-plain object at ${formatGlobalsPath(path)}. Use JSON-like primitives, arrays, plain objects, functions, and symbols.`);
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
};
|
|
58
|
+
export const encodeGlobals = (value) => encodeGlobalsAtPath(value, []);
|
|
59
|
+
const isEncodedGlobalPayload = (value) => {
|
|
60
|
+
if (!isPlainObject(value)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (value.signature !== ENCODED_GLOBAL_SIGNATURE || value.version !== ENCODED_GLOBAL_VERSION) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (value.kind === "function") {
|
|
67
|
+
return typeof value.source === "string";
|
|
68
|
+
}
|
|
69
|
+
return value.kind === "symbol" && typeof value.description === "string";
|
|
70
|
+
};
|
|
71
|
+
const isEncodedGlobal = (value) => {
|
|
72
|
+
if (!isPlainObject(value)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const keys = Object.keys(value);
|
|
76
|
+
return keys.length === 1 && keys[0] === ENCODED_GLOBAL_ENVELOPE_KEY && isEncodedGlobalPayload(value[ENCODED_GLOBAL_ENVELOPE_KEY]);
|
|
77
|
+
};
|
|
78
|
+
const decodeGlobalsAtPath = (value, path) => {
|
|
79
|
+
if (Array.isArray(value)) {
|
|
80
|
+
return value.map((item, index) => decodeGlobalsAtPath(item, [...path, index]));
|
|
81
|
+
}
|
|
82
|
+
if (isEncodedGlobal(value)) {
|
|
83
|
+
const payload = value[ENCODED_GLOBAL_ENVELOPE_KEY];
|
|
84
|
+
if (payload.kind === "function") {
|
|
85
|
+
try {
|
|
86
|
+
// eslint-disable-next-line no-eval
|
|
87
|
+
const restored = eval(`(${payload.source})`);
|
|
88
|
+
if (typeof restored !== "function") {
|
|
89
|
+
throw new TypeError("decoded source is not a function");
|
|
90
|
+
}
|
|
91
|
+
return restored;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
throw new Error(`[wyw-in-js] Failed to restore eval.globals function at ${formatGlobalsPath(path)}. Original error: ${String(error)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return Symbol(payload.description);
|
|
97
|
+
}
|
|
98
|
+
if (isPlainObject(value)) {
|
|
99
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, decodeGlobalsAtPath(item, [...path, key])]));
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
102
|
+
};
|
|
103
|
+
export const decodeGlobals = (value) => decodeGlobalsAtPath(value, []);
|
|
104
|
+
//# sourceMappingURL=globals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"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","names":[],"sources":["../src/globals.ts"],"version":3,"sourcesContent":["const ENCODED_GLOBAL_ENVELOPE_KEY = '__wyw_eval_global';\nconst ENCODED_GLOBAL_SIGNATURE = 'wyw-eval-global';\nconst ENCODED_GLOBAL_VERSION = 1;\n\ntype EncodedFunctionPayload = {\n kind: 'function';\n signature: typeof ENCODED_GLOBAL_SIGNATURE;\n source: string;\n version: typeof ENCODED_GLOBAL_VERSION;\n};\n\ntype EncodedSymbolPayload = {\n description: string;\n kind: 'symbol';\n signature: typeof ENCODED_GLOBAL_SIGNATURE;\n version: typeof ENCODED_GLOBAL_VERSION;\n};\n\ntype EncodedGlobalPayload = EncodedFunctionPayload | EncodedSymbolPayload;\n\ntype EncodedGlobal = {\n [ENCODED_GLOBAL_ENVELOPE_KEY]: EncodedGlobalPayload;\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || prototype === Object.prototype;\n};\n\nconst formatGlobalsPath = (path: Array<string | number>): string =>\n path.reduce<string>((acc, segment) => {\n if (typeof segment === 'number') {\n return `${acc}[${segment}]`;\n }\n\n return /^[A-Za-z_$][\\w$]*$/u.test(segment)\n ? `${acc}.${segment}`\n : `${acc}[${JSON.stringify(segment)}]`;\n }, 'eval.globals');\n\nconst validateFunctionSource = (\n source: string,\n path: Array<string | number>\n) => {\n try {\n // eslint-disable-next-line no-eval\n const restored = eval(`(${source})`) as unknown;\n if (typeof restored !== 'function') {\n throw new TypeError('decoded source is not a function');\n }\n } catch (error) {\n throw new Error(\n `[wyw-in-js] eval.globals contains an unsupported function at ${formatGlobalsPath(\n path\n )}. ` +\n `Ensure the value is a user-defined function expression/arrow function. ` +\n `Native and bound functions are not supported. ` +\n `Original error: ${String(error)}`\n );\n }\n};\n\nconst encodeGlobalsAtPath = (\n value: unknown,\n path: Array<string | number>\n): unknown => {\n if (typeof value === 'function') {\n const source = value.toString();\n validateFunctionSource(source, path);\n\n return {\n [ENCODED_GLOBAL_ENVELOPE_KEY]: {\n signature: ENCODED_GLOBAL_SIGNATURE,\n version: ENCODED_GLOBAL_VERSION,\n kind: 'function',\n source,\n },\n } satisfies EncodedGlobal;\n }\n\n if (typeof value === 'symbol') {\n return {\n [ENCODED_GLOBAL_ENVELOPE_KEY]: {\n signature: ENCODED_GLOBAL_SIGNATURE,\n version: ENCODED_GLOBAL_VERSION,\n kind: 'symbol',\n description: value.description ?? '',\n },\n } satisfies EncodedGlobal;\n }\n\n if (Array.isArray(value)) {\n return value.map((item, index) =>\n encodeGlobalsAtPath(item, [...path, index])\n );\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n encodeGlobalsAtPath(item, [...path, key]),\n ])\n );\n }\n\n if (typeof value === 'object' && value !== null) {\n throw new Error(\n `[wyw-in-js] eval.globals contains an unsupported non-plain object at ${formatGlobalsPath(\n path\n )}. Use JSON-like primitives, arrays, plain objects, functions, and symbols.`\n );\n }\n\n return value;\n};\n\nexport const encodeGlobals = (value: unknown): unknown =>\n encodeGlobalsAtPath(value, []);\n\nconst isEncodedGlobalPayload = (\n value: unknown\n): value is EncodedGlobalPayload => {\n if (!isPlainObject(value)) {\n return false;\n }\n\n if (\n value.signature !== ENCODED_GLOBAL_SIGNATURE ||\n value.version !== ENCODED_GLOBAL_VERSION\n ) {\n return false;\n }\n\n if (value.kind === 'function') {\n return typeof value.source === 'string';\n }\n\n return value.kind === 'symbol' && typeof value.description === 'string';\n};\n\nconst isEncodedGlobal = (value: unknown): value is EncodedGlobal => {\n if (!isPlainObject(value)) {\n return false;\n }\n\n const keys = Object.keys(value);\n return (\n keys.length === 1 &&\n keys[0] === ENCODED_GLOBAL_ENVELOPE_KEY &&\n isEncodedGlobalPayload(value[ENCODED_GLOBAL_ENVELOPE_KEY])\n );\n};\n\nconst decodeGlobalsAtPath = (\n value: unknown,\n path: Array<string | number>\n): unknown => {\n if (Array.isArray(value)) {\n return value.map((item, index) =>\n decodeGlobalsAtPath(item, [...path, index])\n );\n }\n\n if (isEncodedGlobal(value)) {\n const payload = value[ENCODED_GLOBAL_ENVELOPE_KEY];\n if (payload.kind === 'function') {\n try {\n // eslint-disable-next-line no-eval\n const restored = eval(`(${payload.source})`) as unknown;\n if (typeof restored !== 'function') {\n throw new TypeError('decoded source is not a function');\n }\n\n return restored;\n } catch (error) {\n throw new Error(\n `[wyw-in-js] Failed to restore eval.globals function at ${formatGlobalsPath(\n path\n )}. Original error: ${String(error)}`\n );\n }\n }\n\n return Symbol(payload.description);\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n decodeGlobalsAtPath(item, [...path, key]),\n ])\n );\n }\n\n return value;\n};\n\nexport const decodeGlobals = (value: unknown): unknown =>\n decodeGlobalsAtPath(value, []);\n"],"file":"globals.js"}
|
package/esm/index.js
CHANGED
|
@@ -1,13 +1,195 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { spawnSync } from "child_process";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { parseSync } from "@babel/core";
|
|
5
|
+
import { encodeGlobals } from "./globals.js";
|
|
6
|
+
const buildRunnerPath = () => {
|
|
7
|
+
const jsPath = fileURLToPath(new URL("./sync-transform-runner.js", import.meta.url));
|
|
8
|
+
if (existsSync(jsPath)) {
|
|
9
|
+
return jsPath;
|
|
10
|
+
}
|
|
11
|
+
return fileURLToPath(new URL("./sync-transform-runner.ts", import.meta.url));
|
|
12
|
+
};
|
|
13
|
+
const runnerPath = buildRunnerPath();
|
|
14
|
+
const nodeBinary = runnerPath.endsWith(".ts") && process.execPath.includes("bun") ? process.execPath : process.env.WYW_NODE_BINARY || (process.execPath.includes("bun") ? "node" : process.execPath);
|
|
15
|
+
const compatibilityWarnings = new Set();
|
|
16
|
+
const emitCompatibilityWarning = (key, message) => {
|
|
17
|
+
if (compatibilityWarnings.has(key)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
compatibilityWarnings.add(key);
|
|
21
|
+
if (typeof process.emitWarning === "function") {
|
|
22
|
+
process.emitWarning(message, {
|
|
23
|
+
code: `WYW_${key}`,
|
|
24
|
+
type: "DeprecationWarning"
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// eslint-disable-next-line no-console
|
|
29
|
+
console.warn(message);
|
|
30
|
+
};
|
|
31
|
+
const warnBabelPresetDeprecation = () => {
|
|
32
|
+
emitCompatibilityWarning("BABEL_PRESET_COMPATIBILITY", "[wyw-in-js] @wyw-in-js/babel-preset is a deprecated compatibility wrapper around the Oxc-backed transform. Prefer bundler integrations or the transform() API for new setups.");
|
|
33
|
+
};
|
|
34
|
+
const warnSynchronousModuleConfig = (configFile) => {
|
|
35
|
+
if (typeof configFile !== "string" || !/\.(?:mjs|mts)$/iu.test(configFile)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
emitCompatibilityWarning("BABEL_PRESET_SYNC_CONFIG", "[wyw-in-js] @wyw-in-js/babel-preset loads .mjs/.mts WyW config files synchronously. Keep them synchronous and avoid top-level await.");
|
|
39
|
+
};
|
|
2
40
|
function isEnabled(caller) {
|
|
3
|
-
|
|
41
|
+
return caller?.name !== "wyw-in-js" || caller.evaluate === true;
|
|
42
|
+
}
|
|
43
|
+
const isPlainObject = (value) => {
|
|
44
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const proto = Object.getPrototypeOf(value);
|
|
48
|
+
return proto === Object.prototype || proto === null;
|
|
49
|
+
};
|
|
50
|
+
const getObjectTypeName = (value) => {
|
|
51
|
+
const { constructor } = value;
|
|
52
|
+
if (constructor && typeof constructor.name === "string" && constructor.name.length > 0) {
|
|
53
|
+
return constructor.name;
|
|
54
|
+
}
|
|
55
|
+
const tag = Object.prototype.toString.call(value);
|
|
56
|
+
return tag.slice(8, -1) || "Object";
|
|
57
|
+
};
|
|
58
|
+
const formatOptionPath = (path) => path.reduce((acc, segment) => {
|
|
59
|
+
if (typeof segment === "number") {
|
|
60
|
+
return `${acc}[${segment}]`;
|
|
61
|
+
}
|
|
62
|
+
if (/^[A-Za-z_$][\w$]*$/u.test(segment)) {
|
|
63
|
+
return `${acc}.${segment}`;
|
|
64
|
+
}
|
|
65
|
+
return `${acc}[${JSON.stringify(segment)}]`;
|
|
66
|
+
}, "options");
|
|
67
|
+
const throwNonSerializableOption = (path, reason) => {
|
|
68
|
+
throw new Error(`[wyw-in-js] Babel preset option ${formatOptionPath(path)} is not serializable (${reason}). ` + "@wyw-in-js/babel-preset forwards inline options through a separate sync runner. " + "Move it into a WyW config file or use the async transform() API.");
|
|
69
|
+
};
|
|
70
|
+
const validateSerializableValue = (value, path) => {
|
|
71
|
+
if (value === null || value === undefined || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (typeof value === "function") {
|
|
75
|
+
throwNonSerializableOption(path, "Function");
|
|
76
|
+
}
|
|
77
|
+
if (typeof value === "symbol") {
|
|
78
|
+
throwNonSerializableOption(path, "Symbol");
|
|
79
|
+
}
|
|
80
|
+
if (typeof value === "bigint") {
|
|
81
|
+
throwNonSerializableOption(path, "BigInt");
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(value)) {
|
|
84
|
+
value.forEach((item, index) => validateSerializableValue(item, [...path, index]));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (isPlainObject(value)) {
|
|
88
|
+
Object.entries(value).forEach(([key, item]) => validateSerializableValue(item, [...path, key]));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
throwNonSerializableOption(path, getObjectTypeName(value));
|
|
92
|
+
};
|
|
93
|
+
const stringifyPayload = (payload) => {
|
|
94
|
+
validateSerializableValue(payload.inputSourceMap, ["inputSourceMap"]);
|
|
95
|
+
validateSerializableValue(payload.pluginOptions, ["pluginOptions"]);
|
|
96
|
+
return JSON.stringify(payload);
|
|
97
|
+
};
|
|
98
|
+
const buildTransformPayload = (file, options) => {
|
|
99
|
+
const filename = file.opts.filename;
|
|
100
|
+
const evalOptions = options.eval ?? {};
|
|
101
|
+
const inlineEvalGlobals = evalOptions.globals === undefined ? undefined : encodeGlobals(evalOptions.globals);
|
|
102
|
+
const nextEvalOptions = "globals" in evalOptions ? Object.fromEntries(Object.entries(evalOptions).filter(([key]) => key !== "globals")) : evalOptions;
|
|
103
|
+
const pluginOptionsForChild = {
|
|
104
|
+
...options,
|
|
105
|
+
eval: nextEvalOptions,
|
|
106
|
+
outputMetadata: true
|
|
107
|
+
};
|
|
108
|
+
if (pluginOptionsForChild.eval && Object.keys(pluginOptionsForChild.eval).length === 0) {
|
|
109
|
+
delete pluginOptionsForChild.eval;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
filename,
|
|
113
|
+
root: file.opts.root ?? undefined,
|
|
114
|
+
code: file.code ?? "",
|
|
115
|
+
inputSourceMap: file.opts.inputSourceMap ?? undefined,
|
|
116
|
+
pluginOptions: pluginOptionsForChild,
|
|
117
|
+
inlineEvalGlobals
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
const runSyncTransform = (payload) => {
|
|
121
|
+
let input;
|
|
122
|
+
try {
|
|
123
|
+
input = stringifyPayload(payload);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
throw new Error(`[wyw-in-js] Failed to serialize babel preset options: ${String(error)}`);
|
|
126
|
+
}
|
|
127
|
+
const result = spawnSync(nodeBinary, [runnerPath], {
|
|
128
|
+
input,
|
|
129
|
+
encoding: "utf8",
|
|
130
|
+
cwd: payload.root ?? process.cwd(),
|
|
131
|
+
env: {
|
|
132
|
+
...process.env,
|
|
133
|
+
NODE_NO_WARNINGS: "1",
|
|
134
|
+
WYW_EVAL_OXC_SYNC: "1"
|
|
135
|
+
},
|
|
136
|
+
maxBuffer: 10 * 1024 * 1024
|
|
137
|
+
});
|
|
138
|
+
if (result.error) {
|
|
139
|
+
throw result.error;
|
|
140
|
+
}
|
|
141
|
+
if (result.status !== 0) {
|
|
142
|
+
throw new Error(`[wyw-in-js] Babel preset sync transform failed:\n${result.stderr ?? ""}`);
|
|
143
|
+
}
|
|
144
|
+
return result.stdout ? JSON.parse(result.stdout) : { code: payload.code };
|
|
145
|
+
};
|
|
146
|
+
const toBabelMetadata = (metadata) => ({
|
|
147
|
+
dependencies: metadata.dependencies,
|
|
148
|
+
processors: metadata.processors.map((processor) => ({
|
|
149
|
+
artifacts: processor.artifacts,
|
|
150
|
+
className: processor.className,
|
|
151
|
+
displayName: processor.displayName,
|
|
152
|
+
location: processor.start ? {
|
|
153
|
+
end: processor.start,
|
|
154
|
+
start: processor.start
|
|
155
|
+
} : null
|
|
156
|
+
})),
|
|
157
|
+
replacements: metadata.replacements,
|
|
158
|
+
rules: metadata.rules
|
|
159
|
+
});
|
|
160
|
+
function oxcCompatibilityPlugin(_babel, options) {
|
|
161
|
+
return {
|
|
162
|
+
name: "@wyw-in-js/babel-preset/oxc-compatibility",
|
|
163
|
+
pre(file) {
|
|
164
|
+
const payload = buildTransformPayload(file, options);
|
|
165
|
+
const result = runSyncTransform(payload);
|
|
166
|
+
if (result.code && result.code !== payload.code) {
|
|
167
|
+
const ast = parseSync(result.code, {
|
|
168
|
+
babelrc: false,
|
|
169
|
+
configFile: false,
|
|
170
|
+
filename: payload.filename,
|
|
171
|
+
sourceType: "module"
|
|
172
|
+
});
|
|
173
|
+
if (ast?.program) {
|
|
174
|
+
const programNode = file.path.node;
|
|
175
|
+
programNode.body = ast.program.body;
|
|
176
|
+
programNode.directives = ast.program.directives;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (result.metadata) {
|
|
180
|
+
const metadata = file.metadata;
|
|
181
|
+
metadata.wywInJS = toBabelMetadata(result.metadata);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
visitor: {}
|
|
185
|
+
};
|
|
4
186
|
}
|
|
5
187
|
export default function wywInJS(babel, options) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
188
|
+
if (!babel.caller(isEnabled)) {
|
|
189
|
+
return {};
|
|
190
|
+
}
|
|
191
|
+
warnBabelPresetDeprecation();
|
|
192
|
+
warnSynchronousModuleConfig(options.configFile);
|
|
193
|
+
return { plugins: [[oxcCompatibilityPlugin, options]] };
|
|
12
194
|
}
|
|
13
|
-
//# sourceMappingURL=index.js.map
|
|
195
|
+
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["babelTransformPlugin","isEnabled","caller","name","evaluate","wywInJS","babel","options","plugins"],"sources":["../src/index.ts"],"sourcesContent":["import type { ConfigAPI, TransformCaller } from '@babel/core';\nimport { babelTransformPlugin } from '@wyw-in-js/transform';\nimport type { PluginOptions } from '@wyw-in-js/transform';\n\nfunction isEnabled(caller?: TransformCaller & { evaluate?: true }) {\n return caller?.name !== 'wyw-in-js' || caller.evaluate === true;\n}\n\nexport default function wywInJS(babel: ConfigAPI, options: PluginOptions) {\n if (!babel.caller(isEnabled)) {\n return {};\n }\n\n return {\n plugins: [[babelTransformPlugin, options]],\n };\n}\n"],"mappings":"AACA,SAASA,oBAAoB,QAAQ,sBAAsB;AAG3D,SAASC,SAASA,CAACC,MAA8C,EAAE;EACjE,OAAOA,MAAM,EAAEC,IAAI,KAAK,WAAW,IAAID,MAAM,CAACE,QAAQ,KAAK,IAAI;AACjE;AAEA,eAAe,SAASC,OAAOA,CAACC,KAAgB,EAAEC,OAAsB,EAAE;EACxE,IAAI,CAACD,KAAK,CAACJ,MAAM,CAACD,SAAS,CAAC,EAAE;IAC5B,OAAO,CAAC,CAAC;EACX;EAEA,OAAO;IACLO,OAAO,EAAE,CAAC,CAACR,oBAAoB,EAAEO,OAAO,CAAC;EAC3C,CAAC;AACH","ignoreList":[]}
|
|
1
|
+
{"mappings":"AAAA,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAQ9B,SAAS,iBAAiB;AAO1B,SAAS,qBAAqB;AAiB9B,MAAM,wBAAwB;CAC5B,MAAM,SAAS,cACb,IAAI,IAAI,8BAA8B,OAAO,KAAK,IAAI,CACvD;AACD,KAAI,WAAW,OAAO,EAAE;AACtB,SAAO;;AAGT,QAAO,cAAc,IAAI,IAAI,8BAA8B,OAAO,KAAK,IAAI,CAAC;;AAG9E,MAAM,aAAa,iBAAiB;AACpC,MAAM,aACJ,WAAW,SAAS,MAAM,IAAI,QAAQ,SAAS,SAAS,MAAM,GAC1D,QAAQ,WACR,QAAQ,IAAI,oBACX,QAAQ,SAAS,SAAS,MAAM,GAAG,SAAS,QAAQ;AAE3D,MAAM,wBAAwB,IAAI,KAAa;AAE/C,MAAM,4BAA4B,KAAa,YAAoB;AACjE,KAAI,sBAAsB,IAAI,IAAI,EAAE;AAClC;;AAGF,uBAAsB,IAAI,IAAI;AAE9B,KAAI,OAAO,QAAQ,gBAAgB,YAAY;AAC7C,UAAQ,YAAY,SAAS;GAC3B,MAAM,OAAO;GACb,MAAM;GACP,CAAC;AACF;;;AAIF,SAAQ,KAAK,QAAQ;;AAGvB,MAAM,mCAAmC;AACvC,0BACE,8BACA,gLACD;;AAGH,MAAM,+BAA+B,eAAwB;AAC3D,KACE,OAAO,eAAe,YACtB,CAAC,mBAAmB,KAAK,WAAW,EACpC;AACA;;AAGF,0BACE,4BACA,uIACD;;AAGH,SAAS,UAAU,QAAgD;AACjE,QAAO,QAAQ,SAAS,eAAe,OAAO,aAAa;;AAG7D,MAAM,iBAAiB,UAAqD;AAC1E,KAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,MAAM,EAAE;AACvE,SAAO;;CAGT,MAAM,QAAQ,OAAO,eAAe,MAAM;AAC1C,QAAO,UAAU,OAAO,aAAa,UAAU;;AAGjD,MAAM,qBAAqB,UAA0B;CACnD,MAAM,EAAE,gBAAgB;AACxB,KACE,eACA,OAAO,YAAY,SAAS,YAC5B,YAAY,KAAK,SAAS,GAC1B;AACA,SAAO,YAAY;;CAGrB,MAAM,MAAM,OAAO,UAAU,SAAS,KAAK,MAAM;AACjD,QAAO,IAAI,MAAM,GAAG,CAAC,EAAE,IAAI;;AAG7B,MAAM,oBAAoB,SACxB,KAAK,QAAgB,KAAK,YAAY;AACpC,KAAI,OAAO,YAAY,UAAU;AAC/B,SAAO,GAAG,IAAI,GAAG,QAAQ;;AAG3B,KAAI,sBAAsB,KAAK,QAAQ,EAAE;AACvC,SAAO,GAAG,IAAI,GAAG;;AAGnB,QAAO,GAAG,IAAI,GAAG,KAAK,UAAU,QAAQ,CAAC;GACxC,UAAU;AAEf,MAAM,8BACJ,MACA,WACU;AACV,OAAM,IAAI,MACR,mCAAmC,iBACjC,KACD,CAAC,wBAAwB,OAAO,OAC/B,qFACA,mEACH;;AAGH,MAAM,6BACJ,OACA,SACS;AACT,KACE,UAAU,QACV,UAAU,aACV,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,WACjB;AACA;;AAGF,KAAI,OAAO,UAAU,YAAY;AAC/B,6BAA2B,MAAM,WAAW;;AAG9C,KAAI,OAAO,UAAU,UAAU;AAC7B,6BAA2B,MAAM,SAAS;;AAG5C,KAAI,OAAO,UAAU,UAAU;AAC7B,6BAA2B,MAAM,SAAS;;AAG5C,KAAI,MAAM,QAAQ,MAAM,EAAE;AACxB,QAAM,SAAS,MAAM,UACnB,0BAA0B,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAClD;AACD;;AAGF,KAAI,cAAc,MAAM,EAAE;AACxB,SAAO,QAAQ,MAAM,CAAC,SAAS,CAAC,KAAK,UACnC,0BAA0B,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,CAChD;AACD;;AAGF,4BAA2B,MAAM,kBAAkB,MAAM,CAAC;;AAG5D,MAAM,oBAAoB,YAAkC;AAC1D,2BAA0B,QAAQ,gBAAgB,CAAC,iBAAiB,CAAC;AACrE,2BAA0B,QAAQ,eAAe,CAAC,gBAAgB,CAAC;AACnE,QAAO,KAAK,UAAU,QAAQ;;AAGhC,MAAM,yBACJ,MACA,YACyB;CACzB,MAAM,WAAW,KAAK,KAAK;CAC3B,MAAM,cAAc,QAAQ,QAAQ,EAAE;CACtC,MAAM,oBACJ,YAAY,YAAY,YACpB,YACA,cAAc,YAAY,QAAQ;CACxC,MAAM,kBACJ,aAAa,cACT,OAAO,YACL,OAAO,QAAQ,YAAY,CAAC,QAAQ,CAAC,SAAS,QAAQ,UAAU,CACjE,GACD;CAEN,MAAM,wBAAgD;EACpD,GAAG;EACH,MAAM;EACN,gBAAgB;EACjB;AAED,KACE,sBAAsB,QACtB,OAAO,KAAK,sBAAsB,KAAK,CAAC,WAAW,GACnD;AACA,SAAO,sBAAsB;;AAG/B,QAAO;EACL;EACA,MAAM,KAAK,KAAK,QAAQ;EACxB,MAAM,KAAK,QAAQ;EACnB,gBAAgB,KAAK,KAAK,kBAAkB;EAC5C,eAAe;EACf;EACD;;AAGH,MAAM,oBACJ,YACwB;CACxB,IAAI;AACJ,KAAI;AACF,UAAQ,iBAAiB,QAAQ;UAC1B,OAAO;AACd,QAAM,IAAI,MACR,yDAAyD,OAAO,MAAM,GACvE;;CAGH,MAAM,SAAS,UAAU,YAAY,CAAC,WAAW,EAAE;EACjD;EACA,UAAU;EACV,KAAK,QAAQ,QAAQ,QAAQ,KAAK;EAClC,KAAK;GACH,GAAG,QAAQ;GACX,kBAAkB;GAClB,mBAAmB;GACpB;EACD,WAAW,KAAK,OAAO;EACxB,CAAC;AAEF,KAAI,OAAO,OAAO;AAChB,QAAM,OAAO;;AAGf,KAAI,OAAO,WAAW,GAAG;AACvB,QAAM,IAAI,MACR,oDAAoD,OAAO,UAAU,KACtE;;AAGH,QAAO,OAAO,SACT,KAAK,MAAM,OAAO,OAAO,GAC1B,EAAE,MAAM,QAAQ,MAAM;;AAG5B,MAAM,mBACJ,cAC0B;CAC1B,cAAc,SAAS;CACvB,YAAY,SAAS,WAAW,KAAK,eAAe;EAClD,WAAW,UAAU;EACrB,WAAW,UAAU;EACrB,aAAa,UAAU;EACvB,UAAU,UAAU,QAChB;GACE,KAAK,UAAU;GACf,OAAO,UAAU;GAClB,GACD;EACL,EAAE;CACH,cAAc,SAAS;CACvB,OAAO,SAAS;CACjB;AAED,SAAS,uBACP,QACA,SACW;AACX,QAAO;EACL,MAAM;EACN,IAAI,MAAiB;GACnB,MAAM,UAAU,sBAAsB,MAAM,QAAQ;GACpD,MAAM,SAAS,iBAAiB,QAAQ;AAExC,OAAI,OAAO,QAAQ,OAAO,SAAS,QAAQ,MAAM;IAC/C,MAAM,MAAM,UAAU,OAAO,MAAM;KACjC,SAAS;KACT,YAAY;KACZ,UAAU,QAAQ;KAClB,YAAY;KACb,CAAC;AAEF,QAAI,KAAK,SAAS;KAChB,MAAM,cAAc,KAAK,KAAK;AAC9B,iBAAY,OAAO,IAAI,QAAQ;AAC/B,iBAAY,aAAa,IAAI,QAAQ;;;AAIzC,OAAI,OAAO,UAAU;IACnB,MAAM,WAAW,KAAK;AACtB,aAAS,UAAU,gBAAgB,OAAO,SAAS;;;EAGvD,SAAS,EAAE;EACZ;;AAGH,eAAe,SAAS,QAAQ,OAAkB,SAAwB;AACxE,KAAI,CAAC,MAAM,OAAO,UAAU,EAAE;AAC5B,SAAO,EAAE;;AAGX,6BAA4B;AAC5B,6BAA4B,QAAQ,WAAW;AAE/C,QAAO,EACL,SAAS,CAAC,CAAC,wBAAwB,QAAQ,CAAC,EAC7C","names":[],"sources":["../src/index.ts"],"version":3,"sourcesContent":["import { existsSync } from 'fs';\nimport { spawnSync } from 'child_process';\nimport { fileURLToPath } from 'url';\n\nimport type {\n BabelFile,\n ConfigAPI,\n PluginObj,\n TransformCaller,\n} from '@babel/core';\nimport { parseSync } from '@babel/core';\nimport type {\n PluginOptions,\n WYWTransformMetadata,\n WYWTransformResultMetadata,\n} from '@wyw-in-js/transform';\n\nimport { encodeGlobals } from './globals';\n\ntype SyncTransformPayload = {\n code: string;\n filename: string;\n inlineEvalGlobals?: unknown;\n inputSourceMap?: unknown;\n pluginOptions: Partial<PluginOptions>;\n root?: string;\n};\n\ntype SyncTransformOutput = {\n code: string;\n metadata?: WYWTransformResultMetadata;\n sourceMap?: unknown;\n};\n\nconst buildRunnerPath = () => {\n const jsPath = fileURLToPath(\n new URL('./sync-transform-runner.js', import.meta.url)\n );\n if (existsSync(jsPath)) {\n return jsPath;\n }\n\n return fileURLToPath(new URL('./sync-transform-runner.ts', import.meta.url));\n};\n\nconst runnerPath = buildRunnerPath();\nconst nodeBinary =\n runnerPath.endsWith('.ts') && process.execPath.includes('bun')\n ? process.execPath\n : process.env.WYW_NODE_BINARY ||\n (process.execPath.includes('bun') ? 'node' : process.execPath);\n\nconst compatibilityWarnings = new Set<string>();\n\nconst emitCompatibilityWarning = (key: string, message: string) => {\n if (compatibilityWarnings.has(key)) {\n return;\n }\n\n compatibilityWarnings.add(key);\n\n if (typeof process.emitWarning === 'function') {\n process.emitWarning(message, {\n code: `WYW_${key}`,\n type: 'DeprecationWarning',\n });\n return;\n }\n\n // eslint-disable-next-line no-console\n console.warn(message);\n};\n\nconst warnBabelPresetDeprecation = () => {\n emitCompatibilityWarning(\n 'BABEL_PRESET_COMPATIBILITY',\n '[wyw-in-js] @wyw-in-js/babel-preset is a deprecated compatibility wrapper around the Oxc-backed transform. Prefer bundler integrations or the transform() API for new setups.'\n );\n};\n\nconst warnSynchronousModuleConfig = (configFile: unknown) => {\n if (\n typeof configFile !== 'string' ||\n !/\\.(?:mjs|mts)$/iu.test(configFile)\n ) {\n return;\n }\n\n emitCompatibilityWarning(\n 'BABEL_PRESET_SYNC_CONFIG',\n '[wyw-in-js] @wyw-in-js/babel-preset loads .mjs/.mts WyW config files synchronously. Keep them synchronous and avoid top-level await.'\n );\n};\n\nfunction isEnabled(caller?: TransformCaller & { evaluate?: true }) {\n return caller?.name !== 'wyw-in-js' || caller.evaluate === true;\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n};\n\nconst getObjectTypeName = (value: object): string => {\n const { constructor } = value as { constructor?: { name?: unknown } };\n if (\n constructor &&\n typeof constructor.name === 'string' &&\n constructor.name.length > 0\n ) {\n return constructor.name;\n }\n\n const tag = Object.prototype.toString.call(value);\n return tag.slice(8, -1) || 'Object';\n};\n\nconst formatOptionPath = (path: Array<string | number>): string =>\n path.reduce<string>((acc, segment) => {\n if (typeof segment === 'number') {\n return `${acc}[${segment}]`;\n }\n\n if (/^[A-Za-z_$][\\w$]*$/u.test(segment)) {\n return `${acc}.${segment}`;\n }\n\n return `${acc}[${JSON.stringify(segment)}]`;\n }, 'options');\n\nconst throwNonSerializableOption = (\n path: Array<string | number>,\n reason: string\n): never => {\n throw new Error(\n `[wyw-in-js] Babel preset option ${formatOptionPath(\n path\n )} is not serializable (${reason}). ` +\n '@wyw-in-js/babel-preset forwards inline options through a separate sync runner. ' +\n 'Move it into a WyW config file or use the async transform() API.'\n );\n};\n\nconst validateSerializableValue = (\n value: unknown,\n path: Array<string | number>\n): void => {\n if (\n value === null ||\n value === undefined ||\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return;\n }\n\n if (typeof value === 'function') {\n throwNonSerializableOption(path, 'Function');\n }\n\n if (typeof value === 'symbol') {\n throwNonSerializableOption(path, 'Symbol');\n }\n\n if (typeof value === 'bigint') {\n throwNonSerializableOption(path, 'BigInt');\n }\n\n if (Array.isArray(value)) {\n value.forEach((item, index) =>\n validateSerializableValue(item, [...path, index])\n );\n return;\n }\n\n if (isPlainObject(value)) {\n Object.entries(value).forEach(([key, item]) =>\n validateSerializableValue(item, [...path, key])\n );\n return;\n }\n\n throwNonSerializableOption(path, getObjectTypeName(value));\n};\n\nconst stringifyPayload = (payload: SyncTransformPayload) => {\n validateSerializableValue(payload.inputSourceMap, ['inputSourceMap']);\n validateSerializableValue(payload.pluginOptions, ['pluginOptions']);\n return JSON.stringify(payload);\n};\n\nconst buildTransformPayload = (\n file: BabelFile,\n options: Partial<PluginOptions>\n): SyncTransformPayload => {\n const filename = file.opts.filename!;\n const evalOptions = options.eval ?? {};\n const inlineEvalGlobals =\n evalOptions.globals === undefined\n ? undefined\n : encodeGlobals(evalOptions.globals);\n const nextEvalOptions =\n 'globals' in evalOptions\n ? Object.fromEntries(\n Object.entries(evalOptions).filter(([key]) => key !== 'globals')\n )\n : evalOptions;\n\n const pluginOptionsForChild: Partial<PluginOptions> = {\n ...options,\n eval: nextEvalOptions,\n outputMetadata: true,\n };\n\n if (\n pluginOptionsForChild.eval &&\n Object.keys(pluginOptionsForChild.eval).length === 0\n ) {\n delete pluginOptionsForChild.eval;\n }\n\n return {\n filename,\n root: file.opts.root ?? undefined,\n code: file.code ?? '',\n inputSourceMap: file.opts.inputSourceMap ?? undefined,\n pluginOptions: pluginOptionsForChild,\n inlineEvalGlobals,\n };\n};\n\nconst runSyncTransform = (\n payload: SyncTransformPayload\n): SyncTransformOutput => {\n let input: string;\n try {\n input = stringifyPayload(payload);\n } catch (error) {\n throw new Error(\n `[wyw-in-js] Failed to serialize babel preset options: ${String(error)}`\n );\n }\n\n const result = spawnSync(nodeBinary, [runnerPath], {\n input,\n encoding: 'utf8',\n cwd: payload.root ?? process.cwd(),\n env: {\n ...process.env,\n NODE_NO_WARNINGS: '1',\n WYW_EVAL_OXC_SYNC: '1',\n },\n maxBuffer: 10 * 1024 * 1024,\n });\n\n if (result.error) {\n throw result.error;\n }\n\n if (result.status !== 0) {\n throw new Error(\n `[wyw-in-js] Babel preset sync transform failed:\\n${result.stderr ?? ''}`\n );\n }\n\n return result.stdout\n ? (JSON.parse(result.stdout) as SyncTransformOutput)\n : { code: payload.code };\n};\n\nconst toBabelMetadata = (\n metadata: WYWTransformResultMetadata\n): WYWTransformMetadata => ({\n dependencies: metadata.dependencies,\n processors: metadata.processors.map((processor) => ({\n artifacts: processor.artifacts,\n className: processor.className,\n displayName: processor.displayName,\n location: processor.start\n ? {\n end: processor.start,\n start: processor.start,\n }\n : null,\n })),\n replacements: metadata.replacements,\n rules: metadata.rules,\n});\n\nfunction oxcCompatibilityPlugin(\n _babel: ConfigAPI,\n options: Partial<PluginOptions>\n): PluginObj {\n return {\n name: '@wyw-in-js/babel-preset/oxc-compatibility',\n pre(file: BabelFile) {\n const payload = buildTransformPayload(file, options);\n const result = runSyncTransform(payload);\n\n if (result.code && result.code !== payload.code) {\n const ast = parseSync(result.code, {\n babelrc: false,\n configFile: false,\n filename: payload.filename,\n sourceType: 'module',\n });\n\n if (ast?.program) {\n const programNode = file.path.node;\n programNode.body = ast.program.body;\n programNode.directives = ast.program.directives;\n }\n }\n\n if (result.metadata) {\n const metadata = file.metadata as { wywInJS?: WYWTransformMetadata };\n metadata.wywInJS = toBabelMetadata(result.metadata);\n }\n },\n visitor: {},\n };\n}\n\nexport default function wywInJS(babel: ConfigAPI, options: PluginOptions) {\n if (!babel.caller(isEnabled)) {\n return {};\n }\n\n warnBabelPresetDeprecation();\n warnSynchronousModuleConfig(options.configFile);\n\n return {\n plugins: [[oxcCompatibilityPlugin, options]],\n };\n}\n"],"file":"index.js"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { asyncResolveFallback } from "@wyw-in-js/shared";
|
|
3
|
+
import { disposeEvalBroker, transform, TransformCacheCollection } from "@wyw-in-js/transform";
|
|
4
|
+
import { decodeGlobals } from "./globals.js";
|
|
5
|
+
const readStdin = () => {
|
|
6
|
+
try {
|
|
7
|
+
return readFileSync(0, "utf8");
|
|
8
|
+
} catch {
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const fail = (message) => {
|
|
13
|
+
// eslint-disable-next-line no-console
|
|
14
|
+
console.error(message);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
};
|
|
17
|
+
const rawInput = readStdin();
|
|
18
|
+
if (!rawInput.trim()) {
|
|
19
|
+
fail("[wyw-in-js] babel preset sync runner: empty input");
|
|
20
|
+
}
|
|
21
|
+
let payload;
|
|
22
|
+
try {
|
|
23
|
+
payload = JSON.parse(rawInput);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
fail(`[wyw-in-js] babel preset sync runner: failed to parse input: ${String(error)}`);
|
|
26
|
+
}
|
|
27
|
+
const { filename, root, code, inputSourceMap, pluginOptions, inlineEvalGlobals } = payload;
|
|
28
|
+
const normalizedInputSourceMap = inputSourceMap;
|
|
29
|
+
const pluginOptionsForTransform = { ...pluginOptions };
|
|
30
|
+
if (inlineEvalGlobals !== undefined) {
|
|
31
|
+
pluginOptionsForTransform.eval = {
|
|
32
|
+
...pluginOptionsForTransform.eval ?? {},
|
|
33
|
+
globals: decodeGlobals(inlineEvalGlobals)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const cache = new TransformCacheCollection();
|
|
37
|
+
let output;
|
|
38
|
+
let transformError = null;
|
|
39
|
+
try {
|
|
40
|
+
const result = await transform({
|
|
41
|
+
cache,
|
|
42
|
+
options: {
|
|
43
|
+
filename,
|
|
44
|
+
root,
|
|
45
|
+
inputSourceMap: normalizedInputSourceMap,
|
|
46
|
+
pluginOptions: pluginOptionsForTransform
|
|
47
|
+
}
|
|
48
|
+
}, code, asyncResolveFallback);
|
|
49
|
+
output = {
|
|
50
|
+
code: result.code,
|
|
51
|
+
metadata: result.metadata,
|
|
52
|
+
sourceMap: result.sourceMap
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
transformError = error;
|
|
56
|
+
} finally {
|
|
57
|
+
disposeEvalBroker(cache);
|
|
58
|
+
}
|
|
59
|
+
if (transformError) {
|
|
60
|
+
fail(`[wyw-in-js] babel preset sync runner: transform failed for ${filename}\n${String(transformError)}`);
|
|
61
|
+
}
|
|
62
|
+
process.stdout.write(JSON.stringify(output));
|
|
63
|
+
//# sourceMappingURL=sync-transform-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"AAAA,SAAS,oBAAoB;AAE7B,SAAS,4BAA4B;AACrC,SACE,mBACA,WACA,gCACK;AAGP,SAAS,qBAAqB;AAgB9B,MAAM,kBAAkB;AACtB,KAAI;AACF,SAAO,aAAa,GAAG,OAAO;SACxB;AACN,SAAO;;;AAIX,MAAM,QAAQ,YAAoB;;AAEhC,SAAQ,MAAM,QAAQ;AACtB,SAAQ,KAAK,EAAE;;AAGjB,MAAM,WAAW,WAAW;AAC5B,IAAI,CAAC,SAAS,MAAM,EAAE;AACpB,MAAK,oDAAoD;;AAG3D,IAAI;AACJ,IAAI;AACF,WAAU,KAAK,MAAM,SAAS;SACvB,OAAO;AACd,MACE,gEAAgE,OAC9D,MACD,GACF;;AAGH,MAAM,EACJ,UACA,MACA,MACA,gBACA,eACA,sBACE;AACJ,MAAM,2BAA2B;AAGjC,MAAM,4BAAoD,EAAE,GAAG,eAAe;AAE9E,IAAI,sBAAsB,WAAW;AACnC,2BAA0B,OAAO;EAC/B,GAAI,0BAA0B,QAAQ,EAAE;EACxC,SAAS,cAAc,kBAAkB;EAC1C;;AAGH,MAAM,QAAQ,IAAI,0BAA0B;AAC5C,IAAI;AACJ,IAAI,iBAA0B;AAE9B,IAAI;CACF,MAAM,SAAS,MAAM,UACnB;EACE;EACA,SAAS;GACP;GACA;GACA,gBAAgB;GAChB,eAAe;GAChB;EACF,EACD,MACA,qBACD;AAED,UAAS;EACP,MAAM,OAAO;EACb,UAAU,OAAO;EACjB,WAAW,OAAO;EACnB;SACM,OAAO;AACd,kBAAiB;UACT;AACR,mBAAkB,MAAM;;AAG1B,IAAI,gBAAgB;AAClB,MACE,8DAA8D,SAAS,IAAI,OACzE,eACD,GACF;;AAGH,QAAQ,OAAO,MAAM,KAAK,UAAU,OAAO,CAAC","names":[],"sources":["../src/sync-transform-runner.ts"],"version":3,"sourcesContent":["import { readFileSync } from 'fs';\n\nimport { asyncResolveFallback } from '@wyw-in-js/shared';\nimport {\n disposeEvalBroker,\n transform,\n TransformCacheCollection,\n} from '@wyw-in-js/transform';\nimport type { PluginOptions, Result } from '@wyw-in-js/transform';\n\nimport { decodeGlobals } from './globals';\n\ntype SyncTransformPayload = {\n code: string;\n filename: string;\n inlineEvalGlobals?: unknown;\n inputSourceMap?: unknown;\n pluginOptions: Partial<PluginOptions>;\n root?: string;\n};\n\ntype SyncTransformOutput = Pick<Result, 'code' | 'metadata' | 'sourceMap'>;\ntype TransformInputSourceMap = Parameters<\n typeof transform\n>[0]['options']['inputSourceMap'];\n\nconst readStdin = () => {\n try {\n return readFileSync(0, 'utf8');\n } catch {\n return '';\n }\n};\n\nconst fail = (message: string) => {\n // eslint-disable-next-line no-console\n console.error(message);\n process.exit(1);\n};\n\nconst rawInput = readStdin();\nif (!rawInput.trim()) {\n fail('[wyw-in-js] babel preset sync runner: empty input');\n}\n\nlet payload!: SyncTransformPayload;\ntry {\n payload = JSON.parse(rawInput) as SyncTransformPayload;\n} catch (error) {\n fail(\n `[wyw-in-js] babel preset sync runner: failed to parse input: ${String(\n error\n )}`\n );\n}\n\nconst {\n filename,\n root,\n code,\n inputSourceMap,\n pluginOptions,\n inlineEvalGlobals,\n} = payload;\nconst normalizedInputSourceMap = inputSourceMap as\n | TransformInputSourceMap\n | undefined;\nconst pluginOptionsForTransform: Partial<PluginOptions> = { ...pluginOptions };\n\nif (inlineEvalGlobals !== undefined) {\n pluginOptionsForTransform.eval = {\n ...(pluginOptionsForTransform.eval ?? {}),\n globals: decodeGlobals(inlineEvalGlobals) as Record<string, unknown>,\n };\n}\n\nconst cache = new TransformCacheCollection();\nlet output!: SyncTransformOutput;\nlet transformError: unknown = null;\n\ntry {\n const result = await transform(\n {\n cache,\n options: {\n filename,\n root,\n inputSourceMap: normalizedInputSourceMap,\n pluginOptions: pluginOptionsForTransform,\n },\n },\n code,\n asyncResolveFallback\n );\n\n output = {\n code: result.code,\n metadata: result.metadata,\n sourceMap: result.sourceMap,\n };\n} catch (error) {\n transformError = error;\n} finally {\n disposeEvalBroker(cache);\n}\n\nif (transformError) {\n fail(\n `[wyw-in-js] babel preset sync runner: transform failed for ${filename}\\n${String(\n transformError\n )}`\n );\n}\n\nprocess.stdout.write(JSON.stringify(output));\n"],"file":"sync-transform-runner.js"}
|
package/package.json
CHANGED
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wyw-in-js/babel-preset",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.1",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"dependencies": {
|
|
5
6
|
"@babel/core": "^7.23.5",
|
|
6
|
-
"@wyw-in-js/
|
|
7
|
+
"@wyw-in-js/shared": "2.0.0-alpha.1",
|
|
8
|
+
"@wyw-in-js/transform": "2.0.0-alpha.1"
|
|
7
9
|
},
|
|
8
10
|
"devDependencies": {
|
|
9
11
|
"@types/babel__core": "^7.20.5",
|
|
10
|
-
"@
|
|
12
|
+
"@types/node": "^22.0.0",
|
|
11
13
|
"@wyw-in-js/eslint-config": "workspace:*",
|
|
12
14
|
"@wyw-in-js/ts-config": "workspace:*"
|
|
13
15
|
},
|
|
14
16
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
17
|
+
"node": ">=22.0.0"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./types/index.d.ts",
|
|
22
|
+
"default": "./esm/index.js"
|
|
23
|
+
}
|
|
16
24
|
},
|
|
17
25
|
"files": [
|
|
18
26
|
"esm/",
|
|
19
|
-
"lib/",
|
|
20
27
|
"types/"
|
|
21
28
|
],
|
|
22
29
|
"license": "MIT",
|
|
23
|
-
"main": "
|
|
30
|
+
"main": "esm/index.js",
|
|
24
31
|
"module": "esm/index.js",
|
|
25
32
|
"publishConfig": {
|
|
26
33
|
"access": "public"
|
|
27
34
|
},
|
|
28
35
|
"scripts": {
|
|
29
|
-
"build:esm": "
|
|
30
|
-
"build:lib": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start",
|
|
36
|
+
"build:esm": "node ../../scripts/build-esm-oxc.mjs",
|
|
31
37
|
"build:types": "tsc --project ./tsconfig.lib.json --baseUrl . --rootDir ./src",
|
|
32
38
|
"lint": "eslint --ext .js,.ts ."
|
|
33
39
|
},
|
package/types/globals.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const ENCODED_GLOBAL_ENVELOPE_KEY = '__wyw_eval_global';
|
|
2
|
+
const ENCODED_GLOBAL_SIGNATURE = 'wyw-eval-global';
|
|
3
|
+
const ENCODED_GLOBAL_VERSION = 1;
|
|
4
|
+
const isPlainObject = (value) => {
|
|
5
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9
|
+
return prototype === null || prototype === Object.prototype;
|
|
10
|
+
};
|
|
11
|
+
const formatGlobalsPath = (path) => path.reduce((acc, segment) => {
|
|
12
|
+
if (typeof segment === 'number') {
|
|
13
|
+
return `${acc}[${segment}]`;
|
|
14
|
+
}
|
|
15
|
+
return /^[A-Za-z_$][\w$]*$/u.test(segment)
|
|
16
|
+
? `${acc}.${segment}`
|
|
17
|
+
: `${acc}[${JSON.stringify(segment)}]`;
|
|
18
|
+
}, 'eval.globals');
|
|
19
|
+
const validateFunctionSource = (source, path) => {
|
|
20
|
+
try {
|
|
21
|
+
// eslint-disable-next-line no-eval
|
|
22
|
+
const restored = eval(`(${source})`);
|
|
23
|
+
if (typeof restored !== 'function') {
|
|
24
|
+
throw new TypeError('decoded source is not a function');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw new Error(`[wyw-in-js] eval.globals contains an unsupported function at ${formatGlobalsPath(path)}. ` +
|
|
29
|
+
`Ensure the value is a user-defined function expression/arrow function. ` +
|
|
30
|
+
`Native and bound functions are not supported. ` +
|
|
31
|
+
`Original error: ${String(error)}`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const encodeGlobalsAtPath = (value, path) => {
|
|
35
|
+
if (typeof value === 'function') {
|
|
36
|
+
const source = value.toString();
|
|
37
|
+
validateFunctionSource(source, path);
|
|
38
|
+
return {
|
|
39
|
+
[ENCODED_GLOBAL_ENVELOPE_KEY]: {
|
|
40
|
+
signature: ENCODED_GLOBAL_SIGNATURE,
|
|
41
|
+
version: ENCODED_GLOBAL_VERSION,
|
|
42
|
+
kind: 'function',
|
|
43
|
+
source,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === 'symbol') {
|
|
48
|
+
return {
|
|
49
|
+
[ENCODED_GLOBAL_ENVELOPE_KEY]: {
|
|
50
|
+
signature: ENCODED_GLOBAL_SIGNATURE,
|
|
51
|
+
version: ENCODED_GLOBAL_VERSION,
|
|
52
|
+
kind: 'symbol',
|
|
53
|
+
description: value.description ?? '',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(value)) {
|
|
58
|
+
return value.map((item, index) => encodeGlobalsAtPath(item, [...path, index]));
|
|
59
|
+
}
|
|
60
|
+
if (isPlainObject(value)) {
|
|
61
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
62
|
+
key,
|
|
63
|
+
encodeGlobalsAtPath(item, [...path, key]),
|
|
64
|
+
]));
|
|
65
|
+
}
|
|
66
|
+
if (typeof value === 'object' && value !== null) {
|
|
67
|
+
throw new Error(`[wyw-in-js] eval.globals contains an unsupported non-plain object at ${formatGlobalsPath(path)}. Use JSON-like primitives, arrays, plain objects, functions, and symbols.`);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
};
|
|
71
|
+
export const encodeGlobals = (value) => encodeGlobalsAtPath(value, []);
|
|
72
|
+
const isEncodedGlobalPayload = (value) => {
|
|
73
|
+
if (!isPlainObject(value)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if (value.signature !== ENCODED_GLOBAL_SIGNATURE ||
|
|
77
|
+
value.version !== ENCODED_GLOBAL_VERSION) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (value.kind === 'function') {
|
|
81
|
+
return typeof value.source === 'string';
|
|
82
|
+
}
|
|
83
|
+
return value.kind === 'symbol' && typeof value.description === 'string';
|
|
84
|
+
};
|
|
85
|
+
const isEncodedGlobal = (value) => {
|
|
86
|
+
if (!isPlainObject(value)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const keys = Object.keys(value);
|
|
90
|
+
return (keys.length === 1 &&
|
|
91
|
+
keys[0] === ENCODED_GLOBAL_ENVELOPE_KEY &&
|
|
92
|
+
isEncodedGlobalPayload(value[ENCODED_GLOBAL_ENVELOPE_KEY]));
|
|
93
|
+
};
|
|
94
|
+
const decodeGlobalsAtPath = (value, path) => {
|
|
95
|
+
if (Array.isArray(value)) {
|
|
96
|
+
return value.map((item, index) => decodeGlobalsAtPath(item, [...path, index]));
|
|
97
|
+
}
|
|
98
|
+
if (isEncodedGlobal(value)) {
|
|
99
|
+
const payload = value[ENCODED_GLOBAL_ENVELOPE_KEY];
|
|
100
|
+
if (payload.kind === 'function') {
|
|
101
|
+
try {
|
|
102
|
+
// eslint-disable-next-line no-eval
|
|
103
|
+
const restored = eval(`(${payload.source})`);
|
|
104
|
+
if (typeof restored !== 'function') {
|
|
105
|
+
throw new TypeError('decoded source is not a function');
|
|
106
|
+
}
|
|
107
|
+
return restored;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw new Error(`[wyw-in-js] Failed to restore eval.globals function at ${formatGlobalsPath(path)}. Original error: ${String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return Symbol(payload.description);
|
|
114
|
+
}
|
|
115
|
+
if (isPlainObject(value)) {
|
|
116
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
117
|
+
key,
|
|
118
|
+
decodeGlobalsAtPath(item, [...path, key]),
|
|
119
|
+
]));
|
|
120
|
+
}
|
|
121
|
+
return value;
|
|
122
|
+
};
|
|
123
|
+
export const decodeGlobals = (value) => decodeGlobalsAtPath(value, []);
|
package/types/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { ConfigAPI } from '@babel/core';
|
|
2
|
-
import { babelTransformPlugin } from '@wyw-in-js/transform';
|
|
1
|
+
import type { ConfigAPI, PluginObj } from '@babel/core';
|
|
3
2
|
import type { PluginOptions } from '@wyw-in-js/transform';
|
|
3
|
+
declare function oxcCompatibilityPlugin(_babel: ConfigAPI, options: Partial<PluginOptions>): PluginObj;
|
|
4
4
|
export default function wywInJS(babel: ConfigAPI, options: PluginOptions): {
|
|
5
5
|
plugins?: undefined;
|
|
6
6
|
} | {
|
|
7
|
-
plugins: (PluginOptions | typeof
|
|
7
|
+
plugins: (PluginOptions | typeof oxcCompatibilityPlugin)[][];
|
|
8
8
|
};
|
|
9
|
+
export {};
|
package/types/index.js
CHANGED
|
@@ -1,15 +1,218 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { parseSync } from '@babel/core';
|
|
5
|
+
import { encodeGlobals } from './globals';
|
|
6
|
+
const buildRunnerPath = () => {
|
|
7
|
+
const jsPath = fileURLToPath(new URL('./sync-transform-runner.js', import.meta.url));
|
|
8
|
+
if (existsSync(jsPath)) {
|
|
9
|
+
return jsPath;
|
|
10
|
+
}
|
|
11
|
+
return fileURLToPath(new URL('./sync-transform-runner.ts', import.meta.url));
|
|
12
|
+
};
|
|
13
|
+
const runnerPath = buildRunnerPath();
|
|
14
|
+
const nodeBinary = runnerPath.endsWith('.ts') && process.execPath.includes('bun')
|
|
15
|
+
? process.execPath
|
|
16
|
+
: process.env.WYW_NODE_BINARY ||
|
|
17
|
+
(process.execPath.includes('bun') ? 'node' : process.execPath);
|
|
18
|
+
const compatibilityWarnings = new Set();
|
|
19
|
+
const emitCompatibilityWarning = (key, message) => {
|
|
20
|
+
if (compatibilityWarnings.has(key)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
compatibilityWarnings.add(key);
|
|
24
|
+
if (typeof process.emitWarning === 'function') {
|
|
25
|
+
process.emitWarning(message, {
|
|
26
|
+
code: `WYW_${key}`,
|
|
27
|
+
type: 'DeprecationWarning',
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// eslint-disable-next-line no-console
|
|
32
|
+
console.warn(message);
|
|
33
|
+
};
|
|
34
|
+
const warnBabelPresetDeprecation = () => {
|
|
35
|
+
emitCompatibilityWarning('BABEL_PRESET_COMPATIBILITY', '[wyw-in-js] @wyw-in-js/babel-preset is a deprecated compatibility wrapper around the Oxc-backed transform. Prefer bundler integrations or the transform() API for new setups.');
|
|
36
|
+
};
|
|
37
|
+
const warnSynchronousModuleConfig = (configFile) => {
|
|
38
|
+
if (typeof configFile !== 'string' ||
|
|
39
|
+
!/\.(?:mjs|mts)$/iu.test(configFile)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
emitCompatibilityWarning('BABEL_PRESET_SYNC_CONFIG', '[wyw-in-js] @wyw-in-js/babel-preset loads .mjs/.mts WyW config files synchronously. Keep them synchronous and avoid top-level await.');
|
|
43
|
+
};
|
|
5
44
|
function isEnabled(caller) {
|
|
6
45
|
return caller?.name !== 'wyw-in-js' || caller.evaluate === true;
|
|
7
46
|
}
|
|
8
|
-
|
|
47
|
+
const isPlainObject = (value) => {
|
|
48
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const proto = Object.getPrototypeOf(value);
|
|
52
|
+
return proto === Object.prototype || proto === null;
|
|
53
|
+
};
|
|
54
|
+
const getObjectTypeName = (value) => {
|
|
55
|
+
const { constructor } = value;
|
|
56
|
+
if (constructor &&
|
|
57
|
+
typeof constructor.name === 'string' &&
|
|
58
|
+
constructor.name.length > 0) {
|
|
59
|
+
return constructor.name;
|
|
60
|
+
}
|
|
61
|
+
const tag = Object.prototype.toString.call(value);
|
|
62
|
+
return tag.slice(8, -1) || 'Object';
|
|
63
|
+
};
|
|
64
|
+
const formatOptionPath = (path) => path.reduce((acc, segment) => {
|
|
65
|
+
if (typeof segment === 'number') {
|
|
66
|
+
return `${acc}[${segment}]`;
|
|
67
|
+
}
|
|
68
|
+
if (/^[A-Za-z_$][\w$]*$/u.test(segment)) {
|
|
69
|
+
return `${acc}.${segment}`;
|
|
70
|
+
}
|
|
71
|
+
return `${acc}[${JSON.stringify(segment)}]`;
|
|
72
|
+
}, 'options');
|
|
73
|
+
const throwNonSerializableOption = (path, reason) => {
|
|
74
|
+
throw new Error(`[wyw-in-js] Babel preset option ${formatOptionPath(path)} is not serializable (${reason}). ` +
|
|
75
|
+
'@wyw-in-js/babel-preset forwards inline options through a separate sync runner. ' +
|
|
76
|
+
'Move it into a WyW config file or use the async transform() API.');
|
|
77
|
+
};
|
|
78
|
+
const validateSerializableValue = (value, path) => {
|
|
79
|
+
if (value === null ||
|
|
80
|
+
value === undefined ||
|
|
81
|
+
typeof value === 'string' ||
|
|
82
|
+
typeof value === 'number' ||
|
|
83
|
+
typeof value === 'boolean') {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (typeof value === 'function') {
|
|
87
|
+
throwNonSerializableOption(path, 'Function');
|
|
88
|
+
}
|
|
89
|
+
if (typeof value === 'symbol') {
|
|
90
|
+
throwNonSerializableOption(path, 'Symbol');
|
|
91
|
+
}
|
|
92
|
+
if (typeof value === 'bigint') {
|
|
93
|
+
throwNonSerializableOption(path, 'BigInt');
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(value)) {
|
|
96
|
+
value.forEach((item, index) => validateSerializableValue(item, [...path, index]));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (isPlainObject(value)) {
|
|
100
|
+
Object.entries(value).forEach(([key, item]) => validateSerializableValue(item, [...path, key]));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
throwNonSerializableOption(path, getObjectTypeName(value));
|
|
104
|
+
};
|
|
105
|
+
const stringifyPayload = (payload) => {
|
|
106
|
+
validateSerializableValue(payload.inputSourceMap, ['inputSourceMap']);
|
|
107
|
+
validateSerializableValue(payload.pluginOptions, ['pluginOptions']);
|
|
108
|
+
return JSON.stringify(payload);
|
|
109
|
+
};
|
|
110
|
+
const buildTransformPayload = (file, options) => {
|
|
111
|
+
const filename = file.opts.filename;
|
|
112
|
+
const evalOptions = options.eval ?? {};
|
|
113
|
+
const inlineEvalGlobals = evalOptions.globals === undefined
|
|
114
|
+
? undefined
|
|
115
|
+
: encodeGlobals(evalOptions.globals);
|
|
116
|
+
const nextEvalOptions = 'globals' in evalOptions
|
|
117
|
+
? Object.fromEntries(Object.entries(evalOptions).filter(([key]) => key !== 'globals'))
|
|
118
|
+
: evalOptions;
|
|
119
|
+
const pluginOptionsForChild = {
|
|
120
|
+
...options,
|
|
121
|
+
eval: nextEvalOptions,
|
|
122
|
+
outputMetadata: true,
|
|
123
|
+
};
|
|
124
|
+
if (pluginOptionsForChild.eval &&
|
|
125
|
+
Object.keys(pluginOptionsForChild.eval).length === 0) {
|
|
126
|
+
delete pluginOptionsForChild.eval;
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
filename,
|
|
130
|
+
root: file.opts.root ?? undefined,
|
|
131
|
+
code: file.code ?? '',
|
|
132
|
+
inputSourceMap: file.opts.inputSourceMap ?? undefined,
|
|
133
|
+
pluginOptions: pluginOptionsForChild,
|
|
134
|
+
inlineEvalGlobals,
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
const runSyncTransform = (payload) => {
|
|
138
|
+
let input;
|
|
139
|
+
try {
|
|
140
|
+
input = stringifyPayload(payload);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
throw new Error(`[wyw-in-js] Failed to serialize babel preset options: ${String(error)}`);
|
|
144
|
+
}
|
|
145
|
+
const result = spawnSync(nodeBinary, [runnerPath], {
|
|
146
|
+
input,
|
|
147
|
+
encoding: 'utf8',
|
|
148
|
+
cwd: payload.root ?? process.cwd(),
|
|
149
|
+
env: {
|
|
150
|
+
...process.env,
|
|
151
|
+
NODE_NO_WARNINGS: '1',
|
|
152
|
+
WYW_EVAL_OXC_SYNC: '1',
|
|
153
|
+
},
|
|
154
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
155
|
+
});
|
|
156
|
+
if (result.error) {
|
|
157
|
+
throw result.error;
|
|
158
|
+
}
|
|
159
|
+
if (result.status !== 0) {
|
|
160
|
+
throw new Error(`[wyw-in-js] Babel preset sync transform failed:\n${result.stderr ?? ''}`);
|
|
161
|
+
}
|
|
162
|
+
return result.stdout
|
|
163
|
+
? JSON.parse(result.stdout)
|
|
164
|
+
: { code: payload.code };
|
|
165
|
+
};
|
|
166
|
+
const toBabelMetadata = (metadata) => ({
|
|
167
|
+
dependencies: metadata.dependencies,
|
|
168
|
+
processors: metadata.processors.map((processor) => ({
|
|
169
|
+
artifacts: processor.artifacts,
|
|
170
|
+
className: processor.className,
|
|
171
|
+
displayName: processor.displayName,
|
|
172
|
+
location: processor.start
|
|
173
|
+
? {
|
|
174
|
+
end: processor.start,
|
|
175
|
+
start: processor.start,
|
|
176
|
+
}
|
|
177
|
+
: null,
|
|
178
|
+
})),
|
|
179
|
+
replacements: metadata.replacements,
|
|
180
|
+
rules: metadata.rules,
|
|
181
|
+
});
|
|
182
|
+
function oxcCompatibilityPlugin(_babel, options) {
|
|
183
|
+
return {
|
|
184
|
+
name: '@wyw-in-js/babel-preset/oxc-compatibility',
|
|
185
|
+
pre(file) {
|
|
186
|
+
const payload = buildTransformPayload(file, options);
|
|
187
|
+
const result = runSyncTransform(payload);
|
|
188
|
+
if (result.code && result.code !== payload.code) {
|
|
189
|
+
const ast = parseSync(result.code, {
|
|
190
|
+
babelrc: false,
|
|
191
|
+
configFile: false,
|
|
192
|
+
filename: payload.filename,
|
|
193
|
+
sourceType: 'module',
|
|
194
|
+
});
|
|
195
|
+
if (ast?.program) {
|
|
196
|
+
const programNode = file.path.node;
|
|
197
|
+
programNode.body = ast.program.body;
|
|
198
|
+
programNode.directives = ast.program.directives;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (result.metadata) {
|
|
202
|
+
const metadata = file.metadata;
|
|
203
|
+
metadata.wywInJS = toBabelMetadata(result.metadata);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
visitor: {},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
export default function wywInJS(babel, options) {
|
|
9
210
|
if (!babel.caller(isEnabled)) {
|
|
10
211
|
return {};
|
|
11
212
|
}
|
|
213
|
+
warnBabelPresetDeprecation();
|
|
214
|
+
warnSynchronousModuleConfig(options.configFile);
|
|
12
215
|
return {
|
|
13
|
-
plugins: [[
|
|
216
|
+
plugins: [[oxcCompatibilityPlugin, options]],
|
|
14
217
|
};
|
|
15
218
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { asyncResolveFallback } from '@wyw-in-js/shared';
|
|
3
|
+
import { disposeEvalBroker, transform, TransformCacheCollection, } from '@wyw-in-js/transform';
|
|
4
|
+
import { decodeGlobals } from './globals';
|
|
5
|
+
const readStdin = () => {
|
|
6
|
+
try {
|
|
7
|
+
return readFileSync(0, 'utf8');
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const fail = (message) => {
|
|
14
|
+
// eslint-disable-next-line no-console
|
|
15
|
+
console.error(message);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
};
|
|
18
|
+
const rawInput = readStdin();
|
|
19
|
+
if (!rawInput.trim()) {
|
|
20
|
+
fail('[wyw-in-js] babel preset sync runner: empty input');
|
|
21
|
+
}
|
|
22
|
+
let payload;
|
|
23
|
+
try {
|
|
24
|
+
payload = JSON.parse(rawInput);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
fail(`[wyw-in-js] babel preset sync runner: failed to parse input: ${String(error)}`);
|
|
28
|
+
}
|
|
29
|
+
const { filename, root, code, inputSourceMap, pluginOptions, inlineEvalGlobals, } = payload;
|
|
30
|
+
const normalizedInputSourceMap = inputSourceMap;
|
|
31
|
+
const pluginOptionsForTransform = { ...pluginOptions };
|
|
32
|
+
if (inlineEvalGlobals !== undefined) {
|
|
33
|
+
pluginOptionsForTransform.eval = {
|
|
34
|
+
...(pluginOptionsForTransform.eval ?? {}),
|
|
35
|
+
globals: decodeGlobals(inlineEvalGlobals),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const cache = new TransformCacheCollection();
|
|
39
|
+
let output;
|
|
40
|
+
let transformError = null;
|
|
41
|
+
try {
|
|
42
|
+
const result = await transform({
|
|
43
|
+
cache,
|
|
44
|
+
options: {
|
|
45
|
+
filename,
|
|
46
|
+
root,
|
|
47
|
+
inputSourceMap: normalizedInputSourceMap,
|
|
48
|
+
pluginOptions: pluginOptionsForTransform,
|
|
49
|
+
},
|
|
50
|
+
}, code, asyncResolveFallback);
|
|
51
|
+
output = {
|
|
52
|
+
code: result.code,
|
|
53
|
+
metadata: result.metadata,
|
|
54
|
+
sourceMap: result.sourceMap,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
transformError = error;
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
disposeEvalBroker(cache);
|
|
62
|
+
}
|
|
63
|
+
if (transformError) {
|
|
64
|
+
fail(`[wyw-in-js] babel preset sync runner: transform failed for ${filename}\n${String(transformError)}`);
|
|
65
|
+
}
|
|
66
|
+
process.stdout.write(JSON.stringify(output));
|
package/lib/index.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = wywInJS;
|
|
7
|
-
var _transform = require("@wyw-in-js/transform");
|
|
8
|
-
function isEnabled(caller) {
|
|
9
|
-
return (caller === null || caller === void 0 ? void 0 : caller.name) !== 'wyw-in-js' || caller.evaluate === true;
|
|
10
|
-
}
|
|
11
|
-
function wywInJS(babel, options) {
|
|
12
|
-
if (!babel.caller(isEnabled)) {
|
|
13
|
-
return {};
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
plugins: [[_transform.babelTransformPlugin, options]]
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_transform","require","isEnabled","caller","name","evaluate","wywInJS","babel","options","plugins","babelTransformPlugin"],"sources":["../src/index.ts"],"sourcesContent":["import type { ConfigAPI, TransformCaller } from '@babel/core';\nimport { babelTransformPlugin } from '@wyw-in-js/transform';\nimport type { PluginOptions } from '@wyw-in-js/transform';\n\nfunction isEnabled(caller?: TransformCaller & { evaluate?: true }) {\n return caller?.name !== 'wyw-in-js' || caller.evaluate === true;\n}\n\nexport default function wywInJS(babel: ConfigAPI, options: PluginOptions) {\n if (!babel.caller(isEnabled)) {\n return {};\n }\n\n return {\n plugins: [[babelTransformPlugin, options]],\n };\n}\n"],"mappings":";;;;;;AACA,IAAAA,UAAA,GAAAC,OAAA;AAGA,SAASC,SAASA,CAACC,MAA8C,EAAE;EACjE,OAAO,CAAAA,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEC,IAAI,MAAK,WAAW,IAAID,MAAM,CAACE,QAAQ,KAAK,IAAI;AACjE;AAEe,SAASC,OAAOA,CAACC,KAAgB,EAAEC,OAAsB,EAAE;EACxE,IAAI,CAACD,KAAK,CAACJ,MAAM,CAACD,SAAS,CAAC,EAAE;IAC5B,OAAO,CAAC,CAAC;EACX;EAEA,OAAO;IACLO,OAAO,EAAE,CAAC,CAACC,+BAAoB,EAAEF,OAAO,CAAC;EAC3C,CAAC;AACH","ignoreList":[]}
|