@jesscss/plugin-js 2.0.0-alpha.8 → 2.0.0-alpha.9
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 +4 -5
- package/lib/bridge.d.ts +4 -9
- package/lib/bridge.d.ts.map +1 -1
- package/lib/index.cjs +178 -74
- package/lib/index.d.ts +5 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +179 -75
- package/lib/runtime-worker.cjs +47 -25
- package/lib/runtime-worker.js +47 -25
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -39,11 +39,10 @@ favor of `@-from` / `@-use`.
|
|
|
39
39
|
|
|
40
40
|
## Status
|
|
41
41
|
|
|
42
|
-
**Alpha.** Part of Jess
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
for the API once it settles.
|
|
42
|
+
**Alpha.** Part of Jess. Requires a Deno runtime for script execution. The
|
|
43
|
+
programmatic plugin/compiler API is **not yet stabilized** — the `jess` CLI is
|
|
44
|
+
the documented public surface for the alpha. Watch the
|
|
45
|
+
[docs site](https://jesscss.github.io/) for the API once it settles.
|
|
47
46
|
|
|
48
47
|
- Project overview & positioning: <https://github.com/jesscss/jess#readme>
|
|
49
48
|
- Docs: <https://jesscss.github.io/> (currently pre-alpha content)
|
package/lib/bridge.d.ts
CHANGED
|
@@ -16,17 +16,12 @@ export type JsBridgeValue = {
|
|
|
16
16
|
kind: 'color';
|
|
17
17
|
rgb: [number, number, number];
|
|
18
18
|
alpha?: number;
|
|
19
|
-
format?: string;
|
|
20
19
|
} | {
|
|
21
20
|
__jessBridge: true;
|
|
22
21
|
kind: 'quoted';
|
|
23
22
|
value: string;
|
|
24
23
|
quote?: '"' | '\'';
|
|
25
24
|
escaped?: boolean;
|
|
26
|
-
} | {
|
|
27
|
-
__jessBridge: true;
|
|
28
|
-
kind: 'keyword';
|
|
29
|
-
value: string;
|
|
30
25
|
} | {
|
|
31
26
|
__jessBridge: true;
|
|
32
27
|
kind: 'anonymous';
|
|
@@ -35,17 +30,17 @@ export type JsBridgeValue = {
|
|
|
35
30
|
__jessBridge: true;
|
|
36
31
|
kind: 'list';
|
|
37
32
|
items: JsBridgeValue[];
|
|
38
|
-
separator
|
|
33
|
+
separator: ',' | '/' | ';';
|
|
39
34
|
} | {
|
|
40
35
|
__jessBridge: true;
|
|
41
|
-
kind: '
|
|
36
|
+
kind: 'expression';
|
|
42
37
|
items: JsBridgeValue[];
|
|
43
38
|
} | {
|
|
44
39
|
__jessBridge: true;
|
|
45
|
-
kind: '
|
|
40
|
+
kind: 'mixin';
|
|
46
41
|
rules: JsBridgeDeclaration[];
|
|
47
42
|
};
|
|
48
43
|
export declare function encodeBridgeValue(value: unknown): unknown;
|
|
49
44
|
export declare function decodeBridgeValue(value: unknown): unknown;
|
|
50
|
-
export declare function encodeBridgeArgs(args: unknown[]): unknown[];
|
|
45
|
+
export declare function encodeBridgeArgs(args: readonly unknown[]): unknown[];
|
|
51
46
|
//# sourceMappingURL=bridge.d.ts.map
|
package/lib/bridge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,mBAAmB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,aAAa,GACrB;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,GACxE;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpF;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5F;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAC;IAAC,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;CAAE,GACxF;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,GAClE;IAAE,YAAY,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,mBAAmB,EAAE,CAAA;CAAE,CAAC;AAiGxE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA8BzD;AAqCD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKzD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,CAEpE"}
|
package/lib/index.cjs
CHANGED
|
@@ -33,100 +33,198 @@ let node_path = require("node:path");
|
|
|
33
33
|
node_path = __toESM(node_path);
|
|
34
34
|
let node_url = require("node:url");
|
|
35
35
|
let node_child_process = require("node:child_process");
|
|
36
|
+
let _jesscss_core_value = require("@jesscss/core/value");
|
|
36
37
|
//#region src/bridge.ts
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (Object.values(_jesscss_core.ColorFormat).includes(value)) return value;
|
|
42
|
-
};
|
|
38
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
39
|
+
const isBridgeValue = (value) => isRecord(value) && value.__jessBridge === true && typeof value.kind === "string";
|
|
40
|
+
const isValueObj = (value) => isRecord(value) && typeof value.type === "string" && typeof value.bytes === "string";
|
|
41
|
+
const isDetached = (value) => isRecord(value) && value.type === "DetachedRuleset" && Array.isArray(value.rules);
|
|
43
42
|
function encodeBridgeChildValue(value) {
|
|
44
43
|
const encoded = encodeBridgeValue(value);
|
|
45
44
|
if (isBridgeValue(encoded)) return encoded;
|
|
46
45
|
return {
|
|
47
46
|
__jessBridge: true,
|
|
48
47
|
kind: "scalar",
|
|
49
|
-
value:
|
|
48
|
+
value: String(encoded)
|
|
50
49
|
};
|
|
51
50
|
}
|
|
51
|
+
function encodeFacadeValue(value) {
|
|
52
|
+
switch (value.type) {
|
|
53
|
+
case "Dimension": return typeof value.value === "number" ? {
|
|
54
|
+
__jessBridge: true,
|
|
55
|
+
kind: "dimension",
|
|
56
|
+
value: value.value,
|
|
57
|
+
unit: typeof value.unit === "string" ? value.unit : void 0
|
|
58
|
+
} : void 0;
|
|
59
|
+
case "Color": return Array.isArray(value.rgb) && value.rgb.length === 3 ? {
|
|
60
|
+
__jessBridge: true,
|
|
61
|
+
kind: "color",
|
|
62
|
+
rgb: [
|
|
63
|
+
value.rgb[0],
|
|
64
|
+
value.rgb[1],
|
|
65
|
+
value.rgb[2]
|
|
66
|
+
],
|
|
67
|
+
alpha: typeof value.alpha === "number" ? value.alpha : void 0
|
|
68
|
+
} : void 0;
|
|
69
|
+
case "Quoted": return typeof value.value === "string" ? {
|
|
70
|
+
__jessBridge: true,
|
|
71
|
+
kind: "quoted",
|
|
72
|
+
value: value.value,
|
|
73
|
+
quote: value.quote === "'" ? "'" : "\"",
|
|
74
|
+
escaped: value.escaped === true
|
|
75
|
+
} : void 0;
|
|
76
|
+
case "Anonymous":
|
|
77
|
+
case "Keyword": return typeof value.value === "string" ? {
|
|
78
|
+
__jessBridge: true,
|
|
79
|
+
kind: "anonymous",
|
|
80
|
+
value: value.value
|
|
81
|
+
} : void 0;
|
|
82
|
+
case "Expression": return Array.isArray(value.value) ? {
|
|
83
|
+
__jessBridge: true,
|
|
84
|
+
kind: "expression",
|
|
85
|
+
items: value.value.map(encodeBridgeChildValue)
|
|
86
|
+
} : void 0;
|
|
87
|
+
case "Value": return Array.isArray(value.value) ? {
|
|
88
|
+
__jessBridge: true,
|
|
89
|
+
kind: "list",
|
|
90
|
+
items: value.value.map(encodeBridgeChildValue),
|
|
91
|
+
separator: value.separator === "/" || value.separator === ";" ? value.separator : ","
|
|
92
|
+
} : void 0;
|
|
93
|
+
case "Mixin": {
|
|
94
|
+
const ruleset = value.ruleset;
|
|
95
|
+
if (!isRecord(ruleset) || !Array.isArray(ruleset.rules)) return;
|
|
96
|
+
const rules = [];
|
|
97
|
+
for (const rule of ruleset.rules) {
|
|
98
|
+
if (!isRecord(rule)) continue;
|
|
99
|
+
if (rule.type === "Declaration" && typeof rule.name === "string") rules.push({
|
|
100
|
+
name: rule.name,
|
|
101
|
+
value: encodeBridgeChildValue(rule.value)
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
__jessBridge: true,
|
|
106
|
+
kind: "mixin",
|
|
107
|
+
rules
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
default: return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
52
113
|
function encodeBridgeValue(value) {
|
|
53
|
-
if (value
|
|
54
|
-
__jessBridge: true,
|
|
55
|
-
kind: "dimension",
|
|
56
|
-
value: value.number,
|
|
57
|
-
unit: value.unit
|
|
58
|
-
};
|
|
59
|
-
if (value instanceof _jesscss_core.Color) return {
|
|
114
|
+
if (Array.isArray(value)) return {
|
|
60
115
|
__jessBridge: true,
|
|
61
|
-
kind: "
|
|
62
|
-
|
|
63
|
-
alpha: value.alpha,
|
|
64
|
-
format: value.options.format === void 0 ? void 0 : _jesscss_core.ColorFormat[value.options.format]
|
|
116
|
+
kind: "expression",
|
|
117
|
+
items: value.map(encodeBridgeChildValue)
|
|
65
118
|
};
|
|
66
|
-
if (value
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
if (isValueObj(value)) switch (value.type) {
|
|
120
|
+
case "Dimension": return {
|
|
121
|
+
__jessBridge: true,
|
|
122
|
+
kind: "dimension",
|
|
123
|
+
value: value.number,
|
|
124
|
+
unit: value.unit
|
|
125
|
+
};
|
|
126
|
+
case "Color": return {
|
|
127
|
+
__jessBridge: true,
|
|
128
|
+
kind: "color",
|
|
129
|
+
rgb: [
|
|
130
|
+
value.rgb[0],
|
|
131
|
+
value.rgb[1],
|
|
132
|
+
value.rgb[2]
|
|
133
|
+
],
|
|
134
|
+
alpha: value.alpha
|
|
135
|
+
};
|
|
136
|
+
case "Quoted": return {
|
|
137
|
+
__jessBridge: true,
|
|
138
|
+
kind: "quoted",
|
|
139
|
+
value: value.value,
|
|
140
|
+
quote: value.quote === "'" ? "'" : "\"",
|
|
141
|
+
escaped: value.escaped
|
|
142
|
+
};
|
|
143
|
+
case "List": return value.sep === "," || value.sep === "/" ? {
|
|
144
|
+
__jessBridge: true,
|
|
145
|
+
kind: "list",
|
|
146
|
+
items: value.value.map(encodeBridgeChildValue),
|
|
147
|
+
separator: value.sep
|
|
148
|
+
} : {
|
|
149
|
+
__jessBridge: true,
|
|
150
|
+
kind: "anonymous",
|
|
151
|
+
value: value.bytes
|
|
152
|
+
};
|
|
153
|
+
case "Block": return {
|
|
154
|
+
__jessBridge: true,
|
|
155
|
+
kind: "anonymous",
|
|
156
|
+
value: value.bytes
|
|
157
|
+
};
|
|
158
|
+
default: return {
|
|
96
159
|
__jessBridge: true,
|
|
97
|
-
kind: "
|
|
98
|
-
|
|
160
|
+
kind: "anonymous",
|
|
161
|
+
value: value.bytes
|
|
99
162
|
};
|
|
100
163
|
}
|
|
164
|
+
if (isDetached(value)) return {
|
|
165
|
+
__jessBridge: true,
|
|
166
|
+
kind: "mixin",
|
|
167
|
+
rules: value.rules.map((rule) => ({
|
|
168
|
+
name: rule.name,
|
|
169
|
+
value: encodeBridgeChildValue(rule.value)
|
|
170
|
+
}))
|
|
171
|
+
};
|
|
172
|
+
if (isRecord(value)) return encodeFacadeValue(value) ?? value;
|
|
101
173
|
return value;
|
|
102
174
|
}
|
|
103
|
-
function
|
|
104
|
-
if (!isBridgeValue(value)) return value;
|
|
175
|
+
function decodeValue(value) {
|
|
105
176
|
switch (value.kind) {
|
|
106
|
-
case "scalar": return
|
|
107
|
-
case "dimension": return
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
case "
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}, { format: colorFormatFromString(value.format) });
|
|
115
|
-
case "quoted": return new _jesscss_core.Quoted(value.value, {
|
|
116
|
-
quote: value.quote,
|
|
117
|
-
escaped: value.escaped
|
|
118
|
-
});
|
|
119
|
-
case "keyword": return new _jesscss_core.Any(value.value, { role: "keyword" });
|
|
120
|
-
case "anonymous": return new _jesscss_core.Any(value.value);
|
|
121
|
-
case "list": return new _jesscss_core.List(value.items.map((item) => decodeBridgeValue(item)), { sep: value.separator });
|
|
122
|
-
case "sequence": return new _jesscss_core.Sequence(value.items.map((item) => decodeBridgeValue(item)));
|
|
177
|
+
case "scalar": return (0, _jesscss_core_value.makeKeyword)(String(value.value));
|
|
178
|
+
case "dimension": return (0, _jesscss_core_value.makeDimension)(value.value, value.unit ?? "");
|
|
179
|
+
case "color": return (0, _jesscss_core_value.makeColorRgb)(value.rgb, value.alpha ?? 1, _jesscss_core_value.RGB);
|
|
180
|
+
case "quoted": return (0, _jesscss_core_value.makeQuoted)(value.value, value.quote ?? "\"", value.escaped === true);
|
|
181
|
+
case "anonymous": return (0, _jesscss_core_value.makeKeyword)(value.value);
|
|
182
|
+
case "expression": return value.items.map(decodeValue);
|
|
183
|
+
case "list": return (0, _jesscss_core_value.makeList)(value.items.map(decodeValue), value.separator === ";" ? "," : value.separator);
|
|
184
|
+
case "mixin": return (0, _jesscss_core_value.makeKeyword)("");
|
|
123
185
|
}
|
|
124
186
|
}
|
|
187
|
+
function decodeMixin(value) {
|
|
188
|
+
const nil = {
|
|
189
|
+
type: "Nil",
|
|
190
|
+
value: ""
|
|
191
|
+
};
|
|
192
|
+
const mixin = {
|
|
193
|
+
type: "Mixin",
|
|
194
|
+
name: nil,
|
|
195
|
+
args: nil,
|
|
196
|
+
ruleset: { rules: value.rules.map((rule) => ({
|
|
197
|
+
type: "Declaration",
|
|
198
|
+
name: rule.name,
|
|
199
|
+
value: decodeValue(rule.value),
|
|
200
|
+
eval() {
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
})) },
|
|
204
|
+
eval() {
|
|
205
|
+
return mixin;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
return mixin;
|
|
209
|
+
}
|
|
210
|
+
function decodeBridgeValue(value) {
|
|
211
|
+
if (!isBridgeValue(value)) return value;
|
|
212
|
+
return value.kind === "mixin" ? decodeMixin(value) : decodeValue(value);
|
|
213
|
+
}
|
|
125
214
|
function encodeBridgeArgs(args) {
|
|
126
215
|
return args.map(encodeBridgeValue);
|
|
127
216
|
}
|
|
128
217
|
//#endregion
|
|
129
218
|
//#region src/index.ts
|
|
219
|
+
/**
|
|
220
|
+
* Child-process stdio streams are typed as bare `Writable`/`Readable`, which do
|
|
221
|
+
* not declare `unref`, but the underlying pipe sockets expose it at runtime.
|
|
222
|
+
* The optional structural member lets any stream be passed without an unsafe
|
|
223
|
+
* cast; the runtime `?.` guard covers streams that genuinely lack the method.
|
|
224
|
+
*/
|
|
225
|
+
const unrefStream = (stream) => {
|
|
226
|
+
if (typeof stream === "object" && stream !== null && "unref" in stream && typeof stream.unref === "function") stream.unref();
|
|
227
|
+
};
|
|
130
228
|
const SCRIPT_EXTENSIONS = new Set([
|
|
131
229
|
".js",
|
|
132
230
|
".mjs",
|
|
@@ -390,9 +488,9 @@ var JsPlugin = class JsPlugin extends _jesscss_core.AbstractPlugin {
|
|
|
390
488
|
});
|
|
391
489
|
this.worker = child;
|
|
392
490
|
child.unref();
|
|
393
|
-
child.stdin
|
|
394
|
-
child.stdout
|
|
395
|
-
child.stderr
|
|
491
|
+
unrefStream(child.stdin);
|
|
492
|
+
unrefStream(child.stdout);
|
|
493
|
+
unrefStream(child.stderr);
|
|
396
494
|
child.stdout.setEncoding("utf8");
|
|
397
495
|
child.stderr.setEncoding("utf8");
|
|
398
496
|
child.stdout.on("data", (chunk) => this.onWorkerStdout(chunk));
|
|
@@ -578,7 +676,7 @@ var JsPlugin = class JsPlugin extends _jesscss_core.AbstractPlugin {
|
|
|
578
676
|
* @deprecated Less `@plugin` is deprecated. Prefer `@-from` for
|
|
579
677
|
* ESM-style script imports or `@-use` for Sass-module-style namespace imports.
|
|
580
678
|
*/
|
|
581
|
-
async importLessPlugin(absoluteFilePath) {
|
|
679
|
+
async importLessPlugin(absoluteFilePath, options = null) {
|
|
582
680
|
const ext = node_path.extname(absoluteFilePath);
|
|
583
681
|
if (!SCRIPT_EXTENSIONS.has(ext)) throw new Error(`Plugin "${this.name}" cannot import Less plugin "${absoluteFilePath}"`);
|
|
584
682
|
this.assertAllowedPath(absoluteFilePath);
|
|
@@ -586,7 +684,8 @@ var JsPlugin = class JsPlugin extends _jesscss_core.AbstractPlugin {
|
|
|
586
684
|
const modulePath = node_path.resolve(absoluteFilePath);
|
|
587
685
|
const loadResult = await this.callWorker({
|
|
588
686
|
type: "loadLessPlugin",
|
|
589
|
-
modulePath
|
|
687
|
+
modulePath,
|
|
688
|
+
options
|
|
590
689
|
});
|
|
591
690
|
if (!loadResult.ok) throw new Error(loadResult.error);
|
|
592
691
|
const functions = {};
|
|
@@ -594,6 +693,7 @@ var JsPlugin = class JsPlugin extends _jesscss_core.AbstractPlugin {
|
|
|
594
693
|
const invokeResult = await this.callWorker({
|
|
595
694
|
type: "invokeLessPluginFunction",
|
|
596
695
|
modulePath,
|
|
696
|
+
options,
|
|
597
697
|
functionName,
|
|
598
698
|
args: encodeBridgeArgs(args)
|
|
599
699
|
});
|
|
@@ -602,6 +702,10 @@ var JsPlugin = class JsPlugin extends _jesscss_core.AbstractPlugin {
|
|
|
602
702
|
};
|
|
603
703
|
return { functions };
|
|
604
704
|
}
|
|
705
|
+
/** Context-facing executable-plugin capability used by the direct AST path. */
|
|
706
|
+
async importPlugin(absoluteFilePath, options = null) {
|
|
707
|
+
return this.importLessPlugin(absoluteFilePath, options);
|
|
708
|
+
}
|
|
605
709
|
};
|
|
606
710
|
/**
|
|
607
711
|
* Global flag set when @jesscss/plugin-js is loaded.
|
package/lib/index.d.ts
CHANGED
|
@@ -63,7 +63,11 @@ export declare class JsPlugin extends AbstractPlugin {
|
|
|
63
63
|
* @deprecated Less `@plugin` is deprecated. Prefer `@-from` for
|
|
64
64
|
* ESM-style script imports or `@-use` for Sass-module-style namespace imports.
|
|
65
65
|
*/
|
|
66
|
-
importLessPlugin(absoluteFilePath: string): Promise<{
|
|
66
|
+
importLessPlugin(absoluteFilePath: string, options?: string | null): Promise<{
|
|
67
|
+
functions: Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
68
|
+
}>;
|
|
69
|
+
/** Context-facing executable-plugin capability used by the direct AST path. */
|
|
70
|
+
importPlugin(absoluteFilePath: string, options?: string | null): Promise<{
|
|
67
71
|
functions: Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
68
72
|
}>;
|
|
69
73
|
}
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACf,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACf,MAAM,eAAe,CAAC;AAyBvB,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,eAAgB,SAAQ,uBAAuB;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAChC;AAmCD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAK,MAAM,CAAC,UAAwB,KACnC,MAAM,CAAC,UAYT,CAAC;AA0FF,qBAAa,QAAS,SAAQ,cAAc;IAoBvB,IAAI,EAAE,eAAe;IAnBxC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAS;IACzC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAuB;IACnD,IAAI,SAAQ;IACZ,mBAAmB,WAAiC;IACpD,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,OAAO,CAIV;IAEL,OAAO,CAAC,SAAS,CAA6B;gBAE3B,IAAI,GAAE,eAAoB;IAM7C,OAAO;IAIP,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAkBrC,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,aAAa;IA4BrB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,mBAAmB;YA0Bb,WAAW;IA8CzB,OAAO,CAAC,WAAW;YAwFL,YAAY;IAW1B,OAAO,CAAC,cAAc;IAiCtB,OAAO,CAAC,gBAAgB;YAQV,UAAU;IAwBxB,OAAO,CAAC,QAAQ;IA0BhB,OAAO;IAMP,OAAO,CAAC,iBAAiB;IAgBnB,MAAM,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IA+CpE;;;;;OAKG;IACG,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,GAAG,IAAW,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;KAAE,CAAC;IA+BjK,+EAA+E;IACzE,YAAY,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,GAAG,IAAW,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;KAAE,CAAC;CAG9J;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AAOpE,QAAA,MAAM,QAAQ,UAAY,eAAe,aAEtB,CAAC;AAEpB,eAAe,QAAQ,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -1,103 +1,201 @@
|
|
|
1
|
-
import { AbstractPlugin
|
|
1
|
+
import { AbstractPlugin } from "@jesscss/core";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as net from "node:net";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
import { spawn, spawnSync } from "node:child_process";
|
|
7
|
+
import { RGB, makeColorRgb, makeDimension, makeKeyword, makeList, makeQuoted } from "@jesscss/core/value";
|
|
7
8
|
//#region src/bridge.ts
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (Object.values(ColorFormat).includes(value)) return value;
|
|
13
|
-
};
|
|
9
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
10
|
+
const isBridgeValue = (value) => isRecord(value) && value.__jessBridge === true && typeof value.kind === "string";
|
|
11
|
+
const isValueObj = (value) => isRecord(value) && typeof value.type === "string" && typeof value.bytes === "string";
|
|
12
|
+
const isDetached = (value) => isRecord(value) && value.type === "DetachedRuleset" && Array.isArray(value.rules);
|
|
14
13
|
function encodeBridgeChildValue(value) {
|
|
15
14
|
const encoded = encodeBridgeValue(value);
|
|
16
15
|
if (isBridgeValue(encoded)) return encoded;
|
|
17
16
|
return {
|
|
18
17
|
__jessBridge: true,
|
|
19
18
|
kind: "scalar",
|
|
20
|
-
value:
|
|
19
|
+
value: String(encoded)
|
|
21
20
|
};
|
|
22
21
|
}
|
|
22
|
+
function encodeFacadeValue(value) {
|
|
23
|
+
switch (value.type) {
|
|
24
|
+
case "Dimension": return typeof value.value === "number" ? {
|
|
25
|
+
__jessBridge: true,
|
|
26
|
+
kind: "dimension",
|
|
27
|
+
value: value.value,
|
|
28
|
+
unit: typeof value.unit === "string" ? value.unit : void 0
|
|
29
|
+
} : void 0;
|
|
30
|
+
case "Color": return Array.isArray(value.rgb) && value.rgb.length === 3 ? {
|
|
31
|
+
__jessBridge: true,
|
|
32
|
+
kind: "color",
|
|
33
|
+
rgb: [
|
|
34
|
+
value.rgb[0],
|
|
35
|
+
value.rgb[1],
|
|
36
|
+
value.rgb[2]
|
|
37
|
+
],
|
|
38
|
+
alpha: typeof value.alpha === "number" ? value.alpha : void 0
|
|
39
|
+
} : void 0;
|
|
40
|
+
case "Quoted": return typeof value.value === "string" ? {
|
|
41
|
+
__jessBridge: true,
|
|
42
|
+
kind: "quoted",
|
|
43
|
+
value: value.value,
|
|
44
|
+
quote: value.quote === "'" ? "'" : "\"",
|
|
45
|
+
escaped: value.escaped === true
|
|
46
|
+
} : void 0;
|
|
47
|
+
case "Anonymous":
|
|
48
|
+
case "Keyword": return typeof value.value === "string" ? {
|
|
49
|
+
__jessBridge: true,
|
|
50
|
+
kind: "anonymous",
|
|
51
|
+
value: value.value
|
|
52
|
+
} : void 0;
|
|
53
|
+
case "Expression": return Array.isArray(value.value) ? {
|
|
54
|
+
__jessBridge: true,
|
|
55
|
+
kind: "expression",
|
|
56
|
+
items: value.value.map(encodeBridgeChildValue)
|
|
57
|
+
} : void 0;
|
|
58
|
+
case "Value": return Array.isArray(value.value) ? {
|
|
59
|
+
__jessBridge: true,
|
|
60
|
+
kind: "list",
|
|
61
|
+
items: value.value.map(encodeBridgeChildValue),
|
|
62
|
+
separator: value.separator === "/" || value.separator === ";" ? value.separator : ","
|
|
63
|
+
} : void 0;
|
|
64
|
+
case "Mixin": {
|
|
65
|
+
const ruleset = value.ruleset;
|
|
66
|
+
if (!isRecord(ruleset) || !Array.isArray(ruleset.rules)) return;
|
|
67
|
+
const rules = [];
|
|
68
|
+
for (const rule of ruleset.rules) {
|
|
69
|
+
if (!isRecord(rule)) continue;
|
|
70
|
+
if (rule.type === "Declaration" && typeof rule.name === "string") rules.push({
|
|
71
|
+
name: rule.name,
|
|
72
|
+
value: encodeBridgeChildValue(rule.value)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
__jessBridge: true,
|
|
77
|
+
kind: "mixin",
|
|
78
|
+
rules
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
default: return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
23
84
|
function encodeBridgeValue(value) {
|
|
24
|
-
if (value
|
|
25
|
-
__jessBridge: true,
|
|
26
|
-
kind: "dimension",
|
|
27
|
-
value: value.number,
|
|
28
|
-
unit: value.unit
|
|
29
|
-
};
|
|
30
|
-
if (value instanceof Color) return {
|
|
85
|
+
if (Array.isArray(value)) return {
|
|
31
86
|
__jessBridge: true,
|
|
32
|
-
kind: "
|
|
33
|
-
|
|
34
|
-
alpha: value.alpha,
|
|
35
|
-
format: value.options.format === void 0 ? void 0 : ColorFormat[value.options.format]
|
|
87
|
+
kind: "expression",
|
|
88
|
+
items: value.map(encodeBridgeChildValue)
|
|
36
89
|
};
|
|
37
|
-
if (value
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
90
|
+
if (isValueObj(value)) switch (value.type) {
|
|
91
|
+
case "Dimension": return {
|
|
92
|
+
__jessBridge: true,
|
|
93
|
+
kind: "dimension",
|
|
94
|
+
value: value.number,
|
|
95
|
+
unit: value.unit
|
|
96
|
+
};
|
|
97
|
+
case "Color": return {
|
|
98
|
+
__jessBridge: true,
|
|
99
|
+
kind: "color",
|
|
100
|
+
rgb: [
|
|
101
|
+
value.rgb[0],
|
|
102
|
+
value.rgb[1],
|
|
103
|
+
value.rgb[2]
|
|
104
|
+
],
|
|
105
|
+
alpha: value.alpha
|
|
106
|
+
};
|
|
107
|
+
case "Quoted": return {
|
|
108
|
+
__jessBridge: true,
|
|
109
|
+
kind: "quoted",
|
|
110
|
+
value: value.value,
|
|
111
|
+
quote: value.quote === "'" ? "'" : "\"",
|
|
112
|
+
escaped: value.escaped
|
|
113
|
+
};
|
|
114
|
+
case "List": return value.sep === "," || value.sep === "/" ? {
|
|
115
|
+
__jessBridge: true,
|
|
116
|
+
kind: "list",
|
|
117
|
+
items: value.value.map(encodeBridgeChildValue),
|
|
118
|
+
separator: value.sep
|
|
119
|
+
} : {
|
|
120
|
+
__jessBridge: true,
|
|
121
|
+
kind: "anonymous",
|
|
122
|
+
value: value.bytes
|
|
123
|
+
};
|
|
124
|
+
case "Block": return {
|
|
125
|
+
__jessBridge: true,
|
|
126
|
+
kind: "anonymous",
|
|
127
|
+
value: value.bytes
|
|
128
|
+
};
|
|
129
|
+
default: return {
|
|
67
130
|
__jessBridge: true,
|
|
68
|
-
kind: "
|
|
69
|
-
|
|
131
|
+
kind: "anonymous",
|
|
132
|
+
value: value.bytes
|
|
70
133
|
};
|
|
71
134
|
}
|
|
135
|
+
if (isDetached(value)) return {
|
|
136
|
+
__jessBridge: true,
|
|
137
|
+
kind: "mixin",
|
|
138
|
+
rules: value.rules.map((rule) => ({
|
|
139
|
+
name: rule.name,
|
|
140
|
+
value: encodeBridgeChildValue(rule.value)
|
|
141
|
+
}))
|
|
142
|
+
};
|
|
143
|
+
if (isRecord(value)) return encodeFacadeValue(value) ?? value;
|
|
72
144
|
return value;
|
|
73
145
|
}
|
|
74
|
-
function
|
|
75
|
-
if (!isBridgeValue(value)) return value;
|
|
146
|
+
function decodeValue(value) {
|
|
76
147
|
switch (value.kind) {
|
|
77
|
-
case "scalar": return
|
|
78
|
-
case "dimension": return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
case "
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}, { format: colorFormatFromString(value.format) });
|
|
86
|
-
case "quoted": return new Quoted(value.value, {
|
|
87
|
-
quote: value.quote,
|
|
88
|
-
escaped: value.escaped
|
|
89
|
-
});
|
|
90
|
-
case "keyword": return new Any(value.value, { role: "keyword" });
|
|
91
|
-
case "anonymous": return new Any(value.value);
|
|
92
|
-
case "list": return new List(value.items.map((item) => decodeBridgeValue(item)), { sep: value.separator });
|
|
93
|
-
case "sequence": return new Sequence(value.items.map((item) => decodeBridgeValue(item)));
|
|
148
|
+
case "scalar": return makeKeyword(String(value.value));
|
|
149
|
+
case "dimension": return makeDimension(value.value, value.unit ?? "");
|
|
150
|
+
case "color": return makeColorRgb(value.rgb, value.alpha ?? 1, RGB);
|
|
151
|
+
case "quoted": return makeQuoted(value.value, value.quote ?? "\"", value.escaped === true);
|
|
152
|
+
case "anonymous": return makeKeyword(value.value);
|
|
153
|
+
case "expression": return value.items.map(decodeValue);
|
|
154
|
+
case "list": return makeList(value.items.map(decodeValue), value.separator === ";" ? "," : value.separator);
|
|
155
|
+
case "mixin": return makeKeyword("");
|
|
94
156
|
}
|
|
95
157
|
}
|
|
158
|
+
function decodeMixin(value) {
|
|
159
|
+
const nil = {
|
|
160
|
+
type: "Nil",
|
|
161
|
+
value: ""
|
|
162
|
+
};
|
|
163
|
+
const mixin = {
|
|
164
|
+
type: "Mixin",
|
|
165
|
+
name: nil,
|
|
166
|
+
args: nil,
|
|
167
|
+
ruleset: { rules: value.rules.map((rule) => ({
|
|
168
|
+
type: "Declaration",
|
|
169
|
+
name: rule.name,
|
|
170
|
+
value: decodeValue(rule.value),
|
|
171
|
+
eval() {
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
})) },
|
|
175
|
+
eval() {
|
|
176
|
+
return mixin;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return mixin;
|
|
180
|
+
}
|
|
181
|
+
function decodeBridgeValue(value) {
|
|
182
|
+
if (!isBridgeValue(value)) return value;
|
|
183
|
+
return value.kind === "mixin" ? decodeMixin(value) : decodeValue(value);
|
|
184
|
+
}
|
|
96
185
|
function encodeBridgeArgs(args) {
|
|
97
186
|
return args.map(encodeBridgeValue);
|
|
98
187
|
}
|
|
99
188
|
//#endregion
|
|
100
189
|
//#region src/index.ts
|
|
190
|
+
/**
|
|
191
|
+
* Child-process stdio streams are typed as bare `Writable`/`Readable`, which do
|
|
192
|
+
* not declare `unref`, but the underlying pipe sockets expose it at runtime.
|
|
193
|
+
* The optional structural member lets any stream be passed without an unsafe
|
|
194
|
+
* cast; the runtime `?.` guard covers streams that genuinely lack the method.
|
|
195
|
+
*/
|
|
196
|
+
const unrefStream = (stream) => {
|
|
197
|
+
if (typeof stream === "object" && stream !== null && "unref" in stream && typeof stream.unref === "function") stream.unref();
|
|
198
|
+
};
|
|
101
199
|
const SCRIPT_EXTENSIONS = new Set([
|
|
102
200
|
".js",
|
|
103
201
|
".mjs",
|
|
@@ -361,9 +459,9 @@ var JsPlugin = class JsPlugin extends AbstractPlugin {
|
|
|
361
459
|
});
|
|
362
460
|
this.worker = child;
|
|
363
461
|
child.unref();
|
|
364
|
-
child.stdin
|
|
365
|
-
child.stdout
|
|
366
|
-
child.stderr
|
|
462
|
+
unrefStream(child.stdin);
|
|
463
|
+
unrefStream(child.stdout);
|
|
464
|
+
unrefStream(child.stderr);
|
|
367
465
|
child.stdout.setEncoding("utf8");
|
|
368
466
|
child.stderr.setEncoding("utf8");
|
|
369
467
|
child.stdout.on("data", (chunk) => this.onWorkerStdout(chunk));
|
|
@@ -549,7 +647,7 @@ var JsPlugin = class JsPlugin extends AbstractPlugin {
|
|
|
549
647
|
* @deprecated Less `@plugin` is deprecated. Prefer `@-from` for
|
|
550
648
|
* ESM-style script imports or `@-use` for Sass-module-style namespace imports.
|
|
551
649
|
*/
|
|
552
|
-
async importLessPlugin(absoluteFilePath) {
|
|
650
|
+
async importLessPlugin(absoluteFilePath, options = null) {
|
|
553
651
|
const ext = path.extname(absoluteFilePath);
|
|
554
652
|
if (!SCRIPT_EXTENSIONS.has(ext)) throw new Error(`Plugin "${this.name}" cannot import Less plugin "${absoluteFilePath}"`);
|
|
555
653
|
this.assertAllowedPath(absoluteFilePath);
|
|
@@ -557,7 +655,8 @@ var JsPlugin = class JsPlugin extends AbstractPlugin {
|
|
|
557
655
|
const modulePath = path.resolve(absoluteFilePath);
|
|
558
656
|
const loadResult = await this.callWorker({
|
|
559
657
|
type: "loadLessPlugin",
|
|
560
|
-
modulePath
|
|
658
|
+
modulePath,
|
|
659
|
+
options
|
|
561
660
|
});
|
|
562
661
|
if (!loadResult.ok) throw new Error(loadResult.error);
|
|
563
662
|
const functions = {};
|
|
@@ -565,6 +664,7 @@ var JsPlugin = class JsPlugin extends AbstractPlugin {
|
|
|
565
664
|
const invokeResult = await this.callWorker({
|
|
566
665
|
type: "invokeLessPluginFunction",
|
|
567
666
|
modulePath,
|
|
667
|
+
options,
|
|
568
668
|
functionName,
|
|
569
669
|
args: encodeBridgeArgs(args)
|
|
570
670
|
});
|
|
@@ -573,6 +673,10 @@ var JsPlugin = class JsPlugin extends AbstractPlugin {
|
|
|
573
673
|
};
|
|
574
674
|
return { functions };
|
|
575
675
|
}
|
|
676
|
+
/** Context-facing executable-plugin capability used by the direct AST path. */
|
|
677
|
+
async importPlugin(absoluteFilePath, options = null) {
|
|
678
|
+
return this.importLessPlugin(absoluteFilePath, options);
|
|
679
|
+
}
|
|
576
680
|
};
|
|
577
681
|
/**
|
|
578
682
|
* Global flag set when @jesscss/plugin-js is loaded.
|
package/lib/runtime-worker.cjs
CHANGED
|
@@ -78,8 +78,17 @@ var Declaration = class {
|
|
|
78
78
|
return `${this.name}: ${v}`;
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
|
-
var
|
|
82
|
-
type = "
|
|
81
|
+
var Nil = class {
|
|
82
|
+
type = "Nil";
|
|
83
|
+
value = "";
|
|
84
|
+
eval() {
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var Mixin = class {
|
|
89
|
+
type = "Mixin";
|
|
90
|
+
name = new Nil();
|
|
91
|
+
args = new Nil();
|
|
83
92
|
ruleset;
|
|
84
93
|
constructor(rules) {
|
|
85
94
|
this.ruleset = { rules };
|
|
@@ -115,10 +124,11 @@ const lessFacade = {
|
|
|
115
124
|
Anonymous,
|
|
116
125
|
Color,
|
|
117
126
|
Declaration,
|
|
118
|
-
DetachedRuleset,
|
|
119
127
|
Dimension,
|
|
120
128
|
Expression,
|
|
121
129
|
Keyword,
|
|
130
|
+
Mixin,
|
|
131
|
+
Nil,
|
|
122
132
|
Quoted,
|
|
123
133
|
Value
|
|
124
134
|
},
|
|
@@ -150,11 +160,10 @@ const decodeBridgeValue = (value) => {
|
|
|
150
160
|
case "dimension": return new Dimension(value.value, value.unit ?? "");
|
|
151
161
|
case "color": return new Color(value.rgb, value.alpha ?? 1);
|
|
152
162
|
case "quoted": return new Quoted(value.quote ?? "\"", value.value, value.escaped === true);
|
|
153
|
-
case "keyword": return new Keyword(value.value);
|
|
154
163
|
case "anonymous": return new Anonymous(value.value);
|
|
155
164
|
case "list": return new Value((value.items ?? []).map(decodeBridgeValue), value.separator ?? ",");
|
|
156
|
-
case "
|
|
157
|
-
case "
|
|
165
|
+
case "expression": return new Expression((value.items ?? []).map(decodeBridgeValue));
|
|
166
|
+
case "mixin": return new Mixin((value.rules ?? []).map((decl) => {
|
|
158
167
|
const decoded = decodeBridgeValue(decl.value);
|
|
159
168
|
const cssText = decoded?.toCSS ? decoded.toCSS() : String(decoded);
|
|
160
169
|
return new Declaration(decl.name, new Anonymous(cssText));
|
|
@@ -191,21 +200,29 @@ const encodeBridgeValue = (value) => {
|
|
|
191
200
|
quote: value.quote,
|
|
192
201
|
escaped: value.escaped
|
|
193
202
|
};
|
|
194
|
-
if (value instanceof Keyword) return {
|
|
203
|
+
if (value instanceof Keyword || value instanceof Anonymous) return {
|
|
195
204
|
__jessBridge: true,
|
|
196
|
-
kind: "
|
|
205
|
+
kind: "anonymous",
|
|
197
206
|
value: String(value.value)
|
|
198
207
|
};
|
|
199
|
-
if (value instanceof
|
|
208
|
+
if (value instanceof Expression) return {
|
|
200
209
|
__jessBridge: true,
|
|
201
|
-
kind: "
|
|
202
|
-
|
|
210
|
+
kind: "expression",
|
|
211
|
+
items: value.value.map(encodeBridgeChildValue)
|
|
203
212
|
};
|
|
204
|
-
if (value instanceof Value
|
|
213
|
+
if (value instanceof Value) return {
|
|
205
214
|
__jessBridge: true,
|
|
206
|
-
kind:
|
|
215
|
+
kind: "list",
|
|
207
216
|
items: value.value.map(encodeBridgeChildValue),
|
|
208
|
-
separator: value
|
|
217
|
+
separator: value.separator === "/" || value.separator === ";" ? value.separator : ","
|
|
218
|
+
};
|
|
219
|
+
if (value instanceof Mixin) return {
|
|
220
|
+
__jessBridge: true,
|
|
221
|
+
kind: "mixin",
|
|
222
|
+
rules: value.ruleset.rules.filter((rule) => rule instanceof Declaration && typeof rule.name === "string").map((rule) => ({
|
|
223
|
+
name: rule.name,
|
|
224
|
+
value: encodeBridgeChildValue(rule.value)
|
|
225
|
+
}))
|
|
209
226
|
};
|
|
210
227
|
return value;
|
|
211
228
|
};
|
|
@@ -243,7 +260,7 @@ const loadModule = async (modulePath) => {
|
|
|
243
260
|
}
|
|
244
261
|
return exports;
|
|
245
262
|
};
|
|
246
|
-
const createLegacyLessPluginRuntime = (modulePath) => {
|
|
263
|
+
const createLegacyLessPluginRuntime = (modulePath, options) => {
|
|
247
264
|
const localFunctions = /* @__PURE__ */ new Map();
|
|
248
265
|
const functions = {
|
|
249
266
|
add(name, fn) {
|
|
@@ -280,7 +297,9 @@ const createLegacyLessPluginRuntime = (modulePath) => {
|
|
|
280
297
|
return plugin;
|
|
281
298
|
}
|
|
282
299
|
})() : plugin;
|
|
300
|
+
if (candidate && options != null && typeof candidate.setOptions === "function") candidate.setOptions(options);
|
|
283
301
|
if (candidate && typeof candidate.install === "function") candidate.install(less, manager, functions);
|
|
302
|
+
if (candidate && options != null && typeof candidate.setOptions === "function") candidate.setOptions(options);
|
|
284
303
|
};
|
|
285
304
|
const require = (specifier) => {
|
|
286
305
|
throw new Error(`Less @plugin require("${specifier}") is not supported in the Deno sandbox yet.`);
|
|
@@ -298,11 +317,13 @@ const createLegacyLessPluginRuntime = (modulePath) => {
|
|
|
298
317
|
fileInfo: { filename: modulePath }
|
|
299
318
|
};
|
|
300
319
|
};
|
|
301
|
-
const
|
|
302
|
-
|
|
320
|
+
const lessPluginCacheKey = (modulePath, options) => `${modulePath}\u0000${options ?? ""}`;
|
|
321
|
+
const loadLessPlugin = async (modulePath, options = null) => {
|
|
322
|
+
const cacheKey = lessPluginCacheKey(modulePath, options);
|
|
323
|
+
let functions = lessPluginFunctionCache.get(cacheKey);
|
|
303
324
|
if (functions) return Array.from(functions.keys());
|
|
304
325
|
const source = await Deno.readTextFile(modulePath);
|
|
305
|
-
const runtime = createLegacyLessPluginRuntime(modulePath);
|
|
326
|
+
const runtime = createLegacyLessPluginRuntime(modulePath, options);
|
|
306
327
|
const module = { exports: runtime.exports };
|
|
307
328
|
new Function("module", "exports", "require", "registerPlugin", "functions", "tree", "less", "fileInfo", "process", source)(module, module.exports, runtime.require, runtime.registerPlugin, runtime.functions, lessFacade.tree, {
|
|
308
329
|
...lessFacade,
|
|
@@ -311,14 +332,15 @@ const loadLessPlugin = async (modulePath) => {
|
|
|
311
332
|
const exported = module.exports?.default ?? module.exports;
|
|
312
333
|
if (typeof exported === "function" || exported && typeof exported.install === "function") runtime.registerPlugin(exported);
|
|
313
334
|
functions = runtime.localFunctions;
|
|
314
|
-
lessPluginFunctionCache.set(
|
|
335
|
+
lessPluginFunctionCache.set(cacheKey, functions);
|
|
315
336
|
return Array.from(functions.keys());
|
|
316
337
|
};
|
|
317
|
-
const invokeLessPluginFunction = async (modulePath, functionName, args) => {
|
|
318
|
-
|
|
338
|
+
const invokeLessPluginFunction = async (modulePath, functionName, args, options = null) => {
|
|
339
|
+
const cacheKey = lessPluginCacheKey(modulePath, options);
|
|
340
|
+
let functions = lessPluginFunctionCache.get(cacheKey);
|
|
319
341
|
if (!functions) {
|
|
320
|
-
await loadLessPlugin(modulePath);
|
|
321
|
-
functions = lessPluginFunctionCache.get(
|
|
342
|
+
await loadLessPlugin(modulePath, options);
|
|
343
|
+
functions = lessPluginFunctionCache.get(cacheKey);
|
|
322
344
|
}
|
|
323
345
|
const fn = functions?.get(String(functionName).toLowerCase());
|
|
324
346
|
if (typeof fn !== "function") throw new Error(`Less @plugin function "${functionName}" is not registered.`);
|
|
@@ -357,7 +379,7 @@ const handleRequest = async (req) => {
|
|
|
357
379
|
return;
|
|
358
380
|
}
|
|
359
381
|
if (req.type === "loadLessPlugin") {
|
|
360
|
-
const functions = await loadLessPlugin(req.modulePath);
|
|
382
|
+
const functions = await loadLessPlugin(req.modulePath, req.options ?? null);
|
|
361
383
|
send({
|
|
362
384
|
id: req.id,
|
|
363
385
|
ok: true,
|
|
@@ -366,7 +388,7 @@ const handleRequest = async (req) => {
|
|
|
366
388
|
return;
|
|
367
389
|
}
|
|
368
390
|
if (req.type === "invokeLessPluginFunction") {
|
|
369
|
-
const value = await invokeLessPluginFunction(req.modulePath, req.functionName, req.args ?? []);
|
|
391
|
+
const value = await invokeLessPluginFunction(req.modulePath, req.functionName, req.args ?? [], req.options ?? null);
|
|
370
392
|
send({
|
|
371
393
|
id: req.id,
|
|
372
394
|
ok: true,
|
package/lib/runtime-worker.js
CHANGED
|
@@ -76,8 +76,17 @@ var Declaration = class {
|
|
|
76
76
|
return `${this.name}: ${v}`;
|
|
77
77
|
}
|
|
78
78
|
};
|
|
79
|
-
var
|
|
80
|
-
type = "
|
|
79
|
+
var Nil = class {
|
|
80
|
+
type = "Nil";
|
|
81
|
+
value = "";
|
|
82
|
+
eval() {
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var Mixin = class {
|
|
87
|
+
type = "Mixin";
|
|
88
|
+
name = new Nil();
|
|
89
|
+
args = new Nil();
|
|
81
90
|
ruleset;
|
|
82
91
|
constructor(rules) {
|
|
83
92
|
this.ruleset = { rules };
|
|
@@ -113,10 +122,11 @@ const lessFacade = {
|
|
|
113
122
|
Anonymous,
|
|
114
123
|
Color,
|
|
115
124
|
Declaration,
|
|
116
|
-
DetachedRuleset,
|
|
117
125
|
Dimension,
|
|
118
126
|
Expression,
|
|
119
127
|
Keyword,
|
|
128
|
+
Mixin,
|
|
129
|
+
Nil,
|
|
120
130
|
Quoted,
|
|
121
131
|
Value
|
|
122
132
|
},
|
|
@@ -148,11 +158,10 @@ const decodeBridgeValue = (value) => {
|
|
|
148
158
|
case "dimension": return new Dimension(value.value, value.unit ?? "");
|
|
149
159
|
case "color": return new Color(value.rgb, value.alpha ?? 1);
|
|
150
160
|
case "quoted": return new Quoted(value.quote ?? "\"", value.value, value.escaped === true);
|
|
151
|
-
case "keyword": return new Keyword(value.value);
|
|
152
161
|
case "anonymous": return new Anonymous(value.value);
|
|
153
162
|
case "list": return new Value((value.items ?? []).map(decodeBridgeValue), value.separator ?? ",");
|
|
154
|
-
case "
|
|
155
|
-
case "
|
|
163
|
+
case "expression": return new Expression((value.items ?? []).map(decodeBridgeValue));
|
|
164
|
+
case "mixin": return new Mixin((value.rules ?? []).map((decl) => {
|
|
156
165
|
const decoded = decodeBridgeValue(decl.value);
|
|
157
166
|
const cssText = decoded?.toCSS ? decoded.toCSS() : String(decoded);
|
|
158
167
|
return new Declaration(decl.name, new Anonymous(cssText));
|
|
@@ -189,21 +198,29 @@ const encodeBridgeValue = (value) => {
|
|
|
189
198
|
quote: value.quote,
|
|
190
199
|
escaped: value.escaped
|
|
191
200
|
};
|
|
192
|
-
if (value instanceof Keyword) return {
|
|
201
|
+
if (value instanceof Keyword || value instanceof Anonymous) return {
|
|
193
202
|
__jessBridge: true,
|
|
194
|
-
kind: "
|
|
203
|
+
kind: "anonymous",
|
|
195
204
|
value: String(value.value)
|
|
196
205
|
};
|
|
197
|
-
if (value instanceof
|
|
206
|
+
if (value instanceof Expression) return {
|
|
198
207
|
__jessBridge: true,
|
|
199
|
-
kind: "
|
|
200
|
-
|
|
208
|
+
kind: "expression",
|
|
209
|
+
items: value.value.map(encodeBridgeChildValue)
|
|
201
210
|
};
|
|
202
|
-
if (value instanceof Value
|
|
211
|
+
if (value instanceof Value) return {
|
|
203
212
|
__jessBridge: true,
|
|
204
|
-
kind:
|
|
213
|
+
kind: "list",
|
|
205
214
|
items: value.value.map(encodeBridgeChildValue),
|
|
206
|
-
separator: value
|
|
215
|
+
separator: value.separator === "/" || value.separator === ";" ? value.separator : ","
|
|
216
|
+
};
|
|
217
|
+
if (value instanceof Mixin) return {
|
|
218
|
+
__jessBridge: true,
|
|
219
|
+
kind: "mixin",
|
|
220
|
+
rules: value.ruleset.rules.filter((rule) => rule instanceof Declaration && typeof rule.name === "string").map((rule) => ({
|
|
221
|
+
name: rule.name,
|
|
222
|
+
value: encodeBridgeChildValue(rule.value)
|
|
223
|
+
}))
|
|
207
224
|
};
|
|
208
225
|
return value;
|
|
209
226
|
};
|
|
@@ -241,7 +258,7 @@ const loadModule = async (modulePath) => {
|
|
|
241
258
|
}
|
|
242
259
|
return exports;
|
|
243
260
|
};
|
|
244
|
-
const createLegacyLessPluginRuntime = (modulePath) => {
|
|
261
|
+
const createLegacyLessPluginRuntime = (modulePath, options) => {
|
|
245
262
|
const localFunctions = /* @__PURE__ */ new Map();
|
|
246
263
|
const functions = {
|
|
247
264
|
add(name, fn) {
|
|
@@ -278,7 +295,9 @@ const createLegacyLessPluginRuntime = (modulePath) => {
|
|
|
278
295
|
return plugin;
|
|
279
296
|
}
|
|
280
297
|
})() : plugin;
|
|
298
|
+
if (candidate && options != null && typeof candidate.setOptions === "function") candidate.setOptions(options);
|
|
281
299
|
if (candidate && typeof candidate.install === "function") candidate.install(less, manager, functions);
|
|
300
|
+
if (candidate && options != null && typeof candidate.setOptions === "function") candidate.setOptions(options);
|
|
282
301
|
};
|
|
283
302
|
const require = (specifier) => {
|
|
284
303
|
throw new Error(`Less @plugin require("${specifier}") is not supported in the Deno sandbox yet.`);
|
|
@@ -296,11 +315,13 @@ const createLegacyLessPluginRuntime = (modulePath) => {
|
|
|
296
315
|
fileInfo: { filename: modulePath }
|
|
297
316
|
};
|
|
298
317
|
};
|
|
299
|
-
const
|
|
300
|
-
|
|
318
|
+
const lessPluginCacheKey = (modulePath, options) => `${modulePath}\u0000${options ?? ""}`;
|
|
319
|
+
const loadLessPlugin = async (modulePath, options = null) => {
|
|
320
|
+
const cacheKey = lessPluginCacheKey(modulePath, options);
|
|
321
|
+
let functions = lessPluginFunctionCache.get(cacheKey);
|
|
301
322
|
if (functions) return Array.from(functions.keys());
|
|
302
323
|
const source = await Deno.readTextFile(modulePath);
|
|
303
|
-
const runtime = createLegacyLessPluginRuntime(modulePath);
|
|
324
|
+
const runtime = createLegacyLessPluginRuntime(modulePath, options);
|
|
304
325
|
const module = { exports: runtime.exports };
|
|
305
326
|
new Function("module", "exports", "require", "registerPlugin", "functions", "tree", "less", "fileInfo", "process", source)(module, module.exports, runtime.require, runtime.registerPlugin, runtime.functions, lessFacade.tree, {
|
|
306
327
|
...lessFacade,
|
|
@@ -309,14 +330,15 @@ const loadLessPlugin = async (modulePath) => {
|
|
|
309
330
|
const exported = module.exports?.default ?? module.exports;
|
|
310
331
|
if (typeof exported === "function" || exported && typeof exported.install === "function") runtime.registerPlugin(exported);
|
|
311
332
|
functions = runtime.localFunctions;
|
|
312
|
-
lessPluginFunctionCache.set(
|
|
333
|
+
lessPluginFunctionCache.set(cacheKey, functions);
|
|
313
334
|
return Array.from(functions.keys());
|
|
314
335
|
};
|
|
315
|
-
const invokeLessPluginFunction = async (modulePath, functionName, args) => {
|
|
316
|
-
|
|
336
|
+
const invokeLessPluginFunction = async (modulePath, functionName, args, options = null) => {
|
|
337
|
+
const cacheKey = lessPluginCacheKey(modulePath, options);
|
|
338
|
+
let functions = lessPluginFunctionCache.get(cacheKey);
|
|
317
339
|
if (!functions) {
|
|
318
|
-
await loadLessPlugin(modulePath);
|
|
319
|
-
functions = lessPluginFunctionCache.get(
|
|
340
|
+
await loadLessPlugin(modulePath, options);
|
|
341
|
+
functions = lessPluginFunctionCache.get(cacheKey);
|
|
320
342
|
}
|
|
321
343
|
const fn = functions?.get(String(functionName).toLowerCase());
|
|
322
344
|
if (typeof fn !== "function") throw new Error(`Less @plugin function "${functionName}" is not registered.`);
|
|
@@ -355,7 +377,7 @@ const handleRequest = async (req) => {
|
|
|
355
377
|
return;
|
|
356
378
|
}
|
|
357
379
|
if (req.type === "loadLessPlugin") {
|
|
358
|
-
const functions = await loadLessPlugin(req.modulePath);
|
|
380
|
+
const functions = await loadLessPlugin(req.modulePath, req.options ?? null);
|
|
359
381
|
send({
|
|
360
382
|
id: req.id,
|
|
361
383
|
ok: true,
|
|
@@ -364,7 +386,7 @@ const handleRequest = async (req) => {
|
|
|
364
386
|
return;
|
|
365
387
|
}
|
|
366
388
|
if (req.type === "invokeLessPluginFunction") {
|
|
367
|
-
const value = await invokeLessPluginFunction(req.modulePath, req.functionName, req.args ?? []);
|
|
389
|
+
const value = await invokeLessPluginFunction(req.modulePath, req.functionName, req.args ?? [], req.options ?? null);
|
|
368
390
|
send({
|
|
369
391
|
id: req.id,
|
|
370
392
|
ok: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jesscss/plugin-js",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.9",
|
|
4
4
|
"description": "Jess plugin for JavaScript/TypeScript module imports with Deno runtime checks",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"deno": "^2.6.8",
|
|
21
|
-
"@jesscss/core": "2.0.0-alpha.
|
|
21
|
+
"@jesscss/core": "2.0.0-alpha.9"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.0.0",
|