@jesscss/plugin-less-compat 2.0.0-alpha.6 → 2.0.0-alpha.7

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.
Files changed (116) hide show
  1. package/README.md +3 -2
  2. package/lib/index.cjs +844 -0
  3. package/lib/index.d.ts +1 -0
  4. package/lib/index.js +800 -10
  5. package/lib/less-adapter.cjs +216 -0
  6. package/lib/less-adapter.js +181 -0
  7. package/lib/less-compat-structures.cjs +378 -0
  8. package/lib/less-compat-structures.d.ts +2 -2
  9. package/lib/less-compat-structures.js +367 -512
  10. package/lib/nodes/at-rule.d.ts +2 -2
  11. package/lib/nodes/attribute-selector.d.ts +2 -2
  12. package/lib/nodes/call.d.ts +2 -2
  13. package/lib/nodes/color.d.ts +2 -1
  14. package/lib/nodes/combinator.d.ts +2 -1
  15. package/lib/nodes/comment.d.ts +2 -1
  16. package/lib/nodes/condition.d.ts +2 -2
  17. package/lib/nodes/declaration.d.ts +2 -2
  18. package/lib/nodes/dimension.d.ts +2 -1
  19. package/lib/nodes/expression.d.ts +2 -2
  20. package/lib/nodes/extend.d.ts +2 -1
  21. package/lib/nodes/import.d.ts +2 -2
  22. package/lib/nodes/keyword.d.ts +2 -1
  23. package/lib/nodes/list.d.ts +3 -2
  24. package/lib/nodes/mixin.d.ts +2 -2
  25. package/lib/nodes/negative.d.ts +2 -2
  26. package/lib/nodes/operation.d.ts +2 -2
  27. package/lib/nodes/paren.d.ts +2 -2
  28. package/lib/nodes/quoted.d.ts +2 -1
  29. package/lib/nodes/reference.d.ts +2 -1
  30. package/lib/nodes/ruleset.d.ts +2 -2
  31. package/lib/nodes/selector.d.ts +2 -2
  32. package/lib/nodes/sequence.d.ts +2 -2
  33. package/lib/nodes/url.d.ts +2 -1
  34. package/lib/nodes/var-declaration.d.ts +2 -2
  35. package/lib/plugin.d.ts +44 -16
  36. package/lib/transform/adapter.d.ts +9 -11
  37. package/lib/transform/index.cjs +13 -0
  38. package/lib/transform/index.d.ts +1 -1
  39. package/lib/transform/index.js +3 -8
  40. package/lib/transform/less-adapter.d.ts +29 -0
  41. package/lib/transform.cjs +1045 -0
  42. package/lib/transform.js +1015 -0
  43. package/lib/types.d.ts +153 -28
  44. package/package.json +6 -9
  45. package/lib/index.js.map +0 -1
  46. package/lib/less-compat-structures.js.map +0 -1
  47. package/lib/nodes/at-rule.js +0 -21
  48. package/lib/nodes/at-rule.js.map +0 -1
  49. package/lib/nodes/attribute-selector.js +0 -18
  50. package/lib/nodes/attribute-selector.js.map +0 -1
  51. package/lib/nodes/call.js +0 -27
  52. package/lib/nodes/call.js.map +0 -1
  53. package/lib/nodes/color.js +0 -23
  54. package/lib/nodes/color.js.map +0 -1
  55. package/lib/nodes/combinator.js +0 -7
  56. package/lib/nodes/combinator.js.map +0 -1
  57. package/lib/nodes/comment.js +0 -9
  58. package/lib/nodes/comment.js.map +0 -1
  59. package/lib/nodes/condition.js +0 -19
  60. package/lib/nodes/condition.js.map +0 -1
  61. package/lib/nodes/declaration.js +0 -38
  62. package/lib/nodes/declaration.js.map +0 -1
  63. package/lib/nodes/dimension.js +0 -9
  64. package/lib/nodes/dimension.js.map +0 -1
  65. package/lib/nodes/expression.js +0 -16
  66. package/lib/nodes/expression.js.map +0 -1
  67. package/lib/nodes/extend.js +0 -18
  68. package/lib/nodes/extend.js.map +0 -1
  69. package/lib/nodes/import.js +0 -22
  70. package/lib/nodes/import.js.map +0 -1
  71. package/lib/nodes/index.js +0 -308
  72. package/lib/nodes/index.js.map +0 -1
  73. package/lib/nodes/keyword.js +0 -8
  74. package/lib/nodes/keyword.js.map +0 -1
  75. package/lib/nodes/list.js +0 -61
  76. package/lib/nodes/list.js.map +0 -1
  77. package/lib/nodes/mixin.js +0 -22
  78. package/lib/nodes/mixin.js.map +0 -1
  79. package/lib/nodes/negative.js +0 -13
  80. package/lib/nodes/negative.js.map +0 -1
  81. package/lib/nodes/operation.js +0 -22
  82. package/lib/nodes/operation.js.map +0 -1
  83. package/lib/nodes/paren.js +0 -13
  84. package/lib/nodes/paren.js.map +0 -1
  85. package/lib/nodes/quoted.js +0 -23
  86. package/lib/nodes/quoted.js.map +0 -1
  87. package/lib/nodes/reference.js +0 -44
  88. package/lib/nodes/reference.js.map +0 -1
  89. package/lib/nodes/ruleset.js +0 -67
  90. package/lib/nodes/ruleset.js.map +0 -1
  91. package/lib/nodes/selector.js +0 -158
  92. package/lib/nodes/selector.js.map +0 -1
  93. package/lib/nodes/sequence.js +0 -56
  94. package/lib/nodes/sequence.js.map +0 -1
  95. package/lib/nodes/url.js +0 -13
  96. package/lib/nodes/url.js.map +0 -1
  97. package/lib/nodes/var-declaration.js +0 -21
  98. package/lib/nodes/var-declaration.js.map +0 -1
  99. package/lib/plugin-utils.js +0 -100
  100. package/lib/plugin-utils.js.map +0 -1
  101. package/lib/plugin.js +0 -1026
  102. package/lib/plugin.js.map +0 -1
  103. package/lib/transform/adapter.js +0 -111
  104. package/lib/transform/adapter.js.map +0 -1
  105. package/lib/transform/from-less.js +0 -170
  106. package/lib/transform/from-less.js.map +0 -1
  107. package/lib/transform/index.js.map +0 -1
  108. package/lib/transform/proxy.d.ts +0 -32
  109. package/lib/transform/proxy.js +0 -138
  110. package/lib/transform/proxy.js.map +0 -1
  111. package/lib/transform/to-less.js +0 -130
  112. package/lib/transform/to-less.js.map +0 -1
  113. package/lib/transform/type-map.js +0 -105
  114. package/lib/transform/type-map.js.map +0 -1
  115. package/lib/types.js +0 -5
  116. package/lib/types.js.map +0 -1
package/lib/index.js CHANGED
@@ -1,11 +1,801 @@
1
+ import { a as mapJessTypeToLessType, i as getLessTypeIndex, n as createLessAdapter, o as mapLessTypeToJessType, t as LessAdapterBase } from "./less-adapter.js";
2
+ import { a as fromLessTree, i as fromLessPluginReturnValue, n as toLessTree, r as fromLessNode, t as toLessNode } from "./transform.js";
3
+ import { LessPluginManager, LessTreeConstructors, LessVisitor, createLessMock } from "./less-compat-structures.js";
4
+ import { createRequire } from "node:module";
5
+ import * as fs from "node:fs";
6
+ import path from "node:path";
7
+ import { AbstractPlugin, Any, Declaration, Deprecation, Dimension, F_VISIBLE, JsFunction, Node, REMOVE, WARN, toDiagnostic } from "@jesscss/core";
8
+ //#region \0rolldown/runtime.js
9
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
10
+ //#endregion
11
+ //#region src/plugin-utils.ts
1
12
  /**
2
- * @jesscss/plugin-less-compat
3
- *
4
- * Less.js compatibility layer for Jess.
5
- * Enables Less.js plugins and visitors to work with Jess AST.
6
- */
7
- export { LessCompatPlugin, default as lessCompatPlugin } from './plugin.js';
8
- export { default } from './plugin.js';
9
- export * from './transform/index.js';
10
- export { isLessPlugin, isJessPlugin, filterPlugins } from './plugin-utils.js';
11
- //# sourceMappingURL=index.js.map
13
+ * Detect if a plugin is a Less.js plugin
14
+ */
15
+ function isLessPlugin(plugin) {
16
+ if (!plugin) return false;
17
+ if (typeof plugin.install === "function") return true;
18
+ if (typeof plugin === "function") {
19
+ if (typeof plugin.install === "function") return true;
20
+ if (plugin.prototype && typeof plugin.prototype.install === "function") return true;
21
+ try {
22
+ const instance = new plugin({});
23
+ if (instance && typeof instance.install === "function") return true;
24
+ } catch (e) {
25
+ try {
26
+ const instance = plugin({});
27
+ if (instance && typeof instance.install === "function") return true;
28
+ return true;
29
+ } catch (e2) {}
30
+ }
31
+ }
32
+ return false;
33
+ }
34
+ /**
35
+ * Detect if a plugin is a Jess plugin
36
+ */
37
+ function isJessPlugin(plugin) {
38
+ if (!plugin) return false;
39
+ if (typeof plugin === "object" && "name" in plugin && typeof plugin.name === "string") return true;
40
+ if (typeof plugin === "function") try {
41
+ const instance = plugin({});
42
+ if (instance && typeof instance === "object" && "name" in instance && typeof instance.name === "string") return true;
43
+ } catch (e) {}
44
+ return false;
45
+ }
46
+ /**
47
+ * Filter and separate Less plugins from Jess plugins
48
+ * This allows mixed plugin arrays to be handled correctly
49
+ */
50
+ function filterPlugins(plugins) {
51
+ const lessPlugins = [];
52
+ const jessPlugins = [];
53
+ for (const plugin of plugins) if (isLessPlugin(plugin)) lessPlugins.push(plugin);
54
+ else if (isJessPlugin(plugin)) jessPlugins.push(plugin);
55
+ else lessPlugins.push(plugin);
56
+ return {
57
+ lessPlugins,
58
+ jessPlugins
59
+ };
60
+ }
61
+ //#endregion
62
+ //#region src/plugin.ts
63
+ const isThenable = (v) => !!v && (typeof v === "object" || typeof v === "function") && typeof v.then === "function";
64
+ /**
65
+ * Structural guard for Less/Jess nodes that expose an `eval(context)` method.
66
+ * Used by the @plugin function wrappers to evaluate node arguments before
67
+ * handing them to legacy Less plugin functions.
68
+ */
69
+ const hasEvalMethod = (x) => !!x && (typeof x === "object" || typeof x === "function") && typeof x.eval === "function";
70
+ /** Structural guard for nodes that expose a `removeFlag` mutator. */
71
+ const hasRemoveFlag = (x) => !!x && typeof x.removeFlag === "function";
72
+ const LESS_PLUGIN_JS_RUNTIME_MESSAGE = "Feature not supported. Install @jesscss/plugin-js to enable Less @plugin script execution.";
73
+ const SCRIPT_MODULES_DISABLED_MESSAGE = "Less @plugin is disabled by disableScriptModules.";
74
+ /**
75
+ * Wrap a Less plugin function and add it to a Jess function registry.
76
+ * Used so that deprecated @plugin-loaded functions register into the Rules that
77
+ * contain the @plugin.
78
+ * Conversion of Less return values to Jess uses the shared fromLessPluginReturnValue.
79
+ *
80
+ * @deprecated Legacy Less @plugin support. Prefer @use / @-use for script integration in .less files.
81
+ */
82
+ function addToJessRegistry(jessRegistry, name, func) {
83
+ if (!jessRegistry || typeof jessRegistry.add !== "function") return;
84
+ try {
85
+ name = name.toLowerCase();
86
+ const wrapped = function(...args) {
87
+ const maybeEvaldArgs = args.map((arg) => {
88
+ if (arg instanceof Any || arg instanceof Declaration || arg instanceof Dimension) {}
89
+ if (hasEvalMethod(arg) && arg.evaluated !== true) try {
90
+ return arg.eval(this);
91
+ } catch {
92
+ return arg;
93
+ }
94
+ return arg;
95
+ });
96
+ const call = (finalArgs) => func.apply(this, finalArgs);
97
+ const result = maybeEvaldArgs.some(isThenable) ? Promise.all(maybeEvaldArgs.map((a) => isThenable(a) ? a : Promise.resolve(a))).then(call) : call(maybeEvaldArgs);
98
+ const statementContext = this?.caller?.parent?.type === "Rules";
99
+ const convertResult = (r) => fromLessPluginReturnValue(r, { statementContext });
100
+ return isThenable(result) ? result.then(convertResult) : convertResult(result);
101
+ };
102
+ Object.assign(wrapped, func);
103
+ jessRegistry.add(name, wrapped);
104
+ } catch (e) {}
105
+ }
106
+ /**
107
+ * Wrap a Less 4.x-style custom function (as registered through
108
+ * `less.functions.functionRegistry.add`) and add it to a Jess function registry.
109
+ *
110
+ * Unlike {@link addToJessRegistry}, the evaluated arguments are converted to
111
+ * Less-shaped nodes via `toLessNode` before the function runs. Less 4.x custom
112
+ * functions receive `less.tree.*` values (with `.value`, `.unit`, `.rgb`, …),
113
+ * not raw Jess nodes, so this conversion is required for parity.
114
+ */
115
+ function addRootFunctionToJessRegistry(jessRegistry, name, func) {
116
+ if (!jessRegistry || typeof jessRegistry.add !== "function") return;
117
+ name = name.toLowerCase();
118
+ const wrapped = function(...args) {
119
+ const evaldArgs = args.map((arg) => {
120
+ if (hasEvalMethod(arg) && arg.evaluated !== true) try {
121
+ return arg.eval(this);
122
+ } catch {
123
+ return arg;
124
+ }
125
+ return arg;
126
+ });
127
+ const call = (finalArgs) => {
128
+ const lessArgs = finalArgs.map((a) => a instanceof Node ? toLessNode(a) : a);
129
+ return func.apply(this, lessArgs);
130
+ };
131
+ const statementContext = this?.caller?.parent?.type === "Rules";
132
+ const convertResult = (r) => fromLessPluginReturnValue(r, { statementContext });
133
+ const result = evaldArgs.some(isThenable) ? Promise.all(evaldArgs.map((a) => isThenable(a) ? a : Promise.resolve(a))).then(call) : call(evaldArgs);
134
+ return isThenable(result) ? result.then(convertResult) : convertResult(result);
135
+ };
136
+ Object.assign(wrapped, func);
137
+ jessRegistry.add(name, wrapped);
138
+ }
139
+ /**
140
+ * Plugin that enables Less.js compatibility by transforming
141
+ * Jess nodes to Less-compatible format for visitor processing.
142
+ */
143
+ var LessCompatPlugin = class extends AbstractPlugin {
144
+ name = "less-compat";
145
+ _cachedVisitor;
146
+ _lessPluginManager;
147
+ _currentFilePath;
148
+ _jessFunctionRegistry;
149
+ _context;
150
+ /** Trees whose root scope already received the configured root functions. */
151
+ _fnRegisteredTrees = /* @__PURE__ */ new WeakSet();
152
+ constructor(opts = {}) {
153
+ super();
154
+ this.opts = opts;
155
+ }
156
+ /**
157
+ * Return the visitor through the early visitor hook so it runs before
158
+ * evaluation. This keeps Less plugin visitors and preprocessors early without
159
+ * bringing back a public node preparation pass.
160
+ *
161
+ * Less plugins can register visitors via:
162
+ * - addVisitor() - these run early by default
163
+ * - addPreProcessor() - these run early
164
+ * - addPostProcessor() - these run on serialized CSS after render
165
+ */
166
+ get beforeEvalVisitor() {
167
+ if (!this._cachedVisitor) this._cachedVisitor = this.visitor;
168
+ return this._cachedVisitor;
169
+ }
170
+ /**
171
+ * Less post-processors operate on final CSS, not on the preRenderVisitor tree hook.
172
+ */
173
+ get postEvalVisitor() {}
174
+ runPostProcessors(css, extra = {}) {
175
+ return (this._lessPluginManager?.getPostProcessors() || []).reduce((current, processor) => {
176
+ if (!processor || typeof processor.process !== "function") return current;
177
+ try {
178
+ const output = processor.process(current, extra);
179
+ return typeof output === "string" ? output : current;
180
+ } catch (error) {
181
+ throw error;
182
+ }
183
+ }, css);
184
+ }
185
+ setCurrentFilePath(filePath) {
186
+ this._currentFilePath = filePath;
187
+ }
188
+ setContext(context) {
189
+ this._context = context;
190
+ try {
191
+ const root = context?.root;
192
+ if (root && typeof root.setFunctionBinding === "function" && typeof root.findFunction === "function") this._jessFunctionRegistry = this.createJessFunctionBindingRegistry(root);
193
+ } catch {}
194
+ }
195
+ createJessFunctionBindingRegistry(root) {
196
+ return {
197
+ add(name, func) {
198
+ const lowerName = name.toLowerCase();
199
+ const jsFunc = func instanceof JsFunction ? func : new JsFunction({
200
+ name: lowerName,
201
+ fn: func
202
+ });
203
+ if (!jsFunc.name) jsFunc.name = lowerName;
204
+ root.setFunctionBinding(lowerName, jsFunc);
205
+ },
206
+ get(name) {
207
+ const fn = root.findFunction(name.toLowerCase());
208
+ return fn instanceof JsFunction ? fn : void 0;
209
+ }
210
+ };
211
+ }
212
+ hasConfiguredBeforeEvalWork() {
213
+ return !!this.opts.plugins?.length || !!this.opts.visitors?.length;
214
+ }
215
+ sourceMayContainPluginDirective(tree) {
216
+ if (!tree) return false;
217
+ const source = tree._treeContext?.file?.source;
218
+ if (typeof source === "string" && source.includes("@plugin")) return true;
219
+ return this.treeContainsPluginDirective(tree);
220
+ }
221
+ treeContainsPluginDirective(node, depth = 0) {
222
+ if (!node || typeof node !== "object" || depth > 32) return false;
223
+ const candidate = node;
224
+ const type = candidate.type;
225
+ if (type === "AtRule" || type === "AtRuleStatement" || type === "Directive") {
226
+ const name = candidate.name;
227
+ let nameValue;
228
+ if (typeof name === "string") nameValue = name;
229
+ else if (name && typeof name === "object") {
230
+ const inner = name.value;
231
+ if (typeof inner === "string") nameValue = inner;
232
+ }
233
+ if (nameValue === "@plugin" || nameValue === "plugin") return true;
234
+ }
235
+ const rules = candidate.rules;
236
+ if (Array.isArray(rules)) {
237
+ for (const child of rules) if (this.treeContainsPluginDirective(child, depth + 1)) return true;
238
+ }
239
+ return false;
240
+ }
241
+ warnForPluginDirective(node) {
242
+ const context = this._context;
243
+ if (!context || !Array.isArray(context.warnings)) return;
244
+ const deprecation = Deprecation.fromId("less-plugin") ?? Deprecation.userAuthored;
245
+ context.warnings.push(toDiagnostic(WARN.deprecated({
246
+ node,
247
+ filePath: this._currentFilePath,
248
+ meta: {
249
+ what: "@plugin",
250
+ use: "@use / @-use",
251
+ deprecation
252
+ },
253
+ note: "In .less files compiled through the Less CLI compatibility path, migrate script integration to @use / @-use."
254
+ })));
255
+ }
256
+ markPluginDirectiveInvisible(node) {
257
+ const jessNode = node instanceof LessAdapterBase ? node.jessNode : node;
258
+ if (hasRemoveFlag(jessNode)) jessNode.removeFlag(F_VISIBLE);
259
+ }
260
+ registerDenoLessPluginFunctions(jessRegistry, functions) {
261
+ if (!jessRegistry || typeof jessRegistry.add !== "function") return;
262
+ for (const [name, fn] of Object.entries(functions)) jessRegistry.add(name.toLowerCase(), async function(...args) {
263
+ const context = this;
264
+ return fn(...await Promise.all(args.map(async (arg) => {
265
+ if (hasEvalMethod(arg) && arg.evaluated !== true) {
266
+ const out = arg.eval(context);
267
+ return isThenable(out) ? await out : out;
268
+ }
269
+ return arg;
270
+ })));
271
+ });
272
+ }
273
+ loadLessPluginFileWithDeno(fullPath, targetJessRegistry) {
274
+ const finish = async (plugin) => {
275
+ if (!plugin || typeof plugin.importLessPlugin !== "function") return false;
276
+ if (this._context?.plugins && !this._context.plugins.includes(plugin)) this._context.plugins.push(plugin);
277
+ const loaded = await plugin.importLessPlugin(fullPath);
278
+ this.registerDenoLessPluginFunctions(targetJessRegistry ?? this._jessFunctionRegistry, loaded.functions ?? {});
279
+ return true;
280
+ };
281
+ const ext = path.extname(fullPath);
282
+ const existingPlugin = [...this._context?.plugins ?? [], ...this.opts.plugins ?? []].find((plugin) => plugin?.supportedExtensions?.includes(ext) && typeof plugin.importLessPlugin === "function");
283
+ if (existingPlugin) return finish(existingPlugin);
284
+ const loader = this._context?.opts?.loadPluginForExtension;
285
+ if (!loader) return false;
286
+ const load = loader(ext);
287
+ return isThenable(load) ? Promise.resolve(load).then(finish) : finish(load);
288
+ }
289
+ beforeEvalVisitorForTree(tree) {
290
+ this.registerRootFunctions(tree);
291
+ if (!this.hasConfiguredBeforeEvalWork() && !this.sourceMayContainPluginDirective(tree)) return;
292
+ return this.beforeEvalVisitor;
293
+ }
294
+ /**
295
+ * Register the configured Less 4.x root functions onto a parsed tree's root
296
+ * scope, using the same `setFunctionBinding` mechanism the Less plugin uses
297
+ * for built-ins. Idempotent per tree.
298
+ */
299
+ registerRootFunctions(tree) {
300
+ const fns = this.opts.functions;
301
+ if (!fns) return;
302
+ if (!tree || typeof tree.setFunctionBinding !== "function" || typeof tree.findFunction !== "function") return;
303
+ if (this._fnRegisteredTrees.has(tree)) return;
304
+ this._fnRegisteredTrees.add(tree);
305
+ const registry = this.createJessFunctionBindingRegistry(tree);
306
+ for (const [name, fn] of Object.entries(fns)) if (typeof fn === "function") addRootFunctionToJessRegistry(registry, name, fn);
307
+ }
308
+ /**
309
+ * Filter and separate Less plugins from Jess plugins
310
+ * This allows mixed plugin arrays to be handled correctly
311
+ *
312
+ * @deprecated Use filterPlugins from './plugin-utils.js' instead
313
+ */
314
+ static filterLessPlugins(plugins) {
315
+ return filterPlugins(plugins);
316
+ }
317
+ /**
318
+ * Return a visitor that wraps Less visitors
319
+ *
320
+ * This visitor intercepts each node, converts it to Less format,
321
+ * runs the Less visitors, and converts back if modified.
322
+ */
323
+ get visitor() {
324
+ const cacheMap = this.opts.cache !== false ? /* @__PURE__ */ new WeakMap() : void 0;
325
+ const LessVisitor$1 = LessVisitor;
326
+ const LessPluginManagerClass = LessPluginManager;
327
+ const lessVisitorInstances = [];
328
+ let pluginManagerRef = null;
329
+ let mockLessRef = null;
330
+ const createUnknownTreeConstructor = (type) => {
331
+ return function(...args) {
332
+ return {
333
+ value: null,
334
+ type,
335
+ name: args[0] || "",
336
+ args: args.slice(1) || [],
337
+ index: 0,
338
+ fileInfo: {},
339
+ accept: function(visitor) {
340
+ return visitor.visit(this);
341
+ }
342
+ };
343
+ };
344
+ };
345
+ const attachFunctionRegistrySurface = (registry) => {
346
+ for (const [name, ctor] of Object.entries(LessTreeConstructors)) Object.defineProperty(registry, name, {
347
+ value: ctor,
348
+ enumerable: false,
349
+ configurable: true,
350
+ writable: true
351
+ });
352
+ for (const name of [
353
+ "Alpha",
354
+ "Assignment",
355
+ "Condition",
356
+ "Expression",
357
+ "Value"
358
+ ]) if (!(name in registry)) Object.defineProperty(registry, name, {
359
+ value: createUnknownTreeConstructor(name),
360
+ enumerable: false,
361
+ configurable: true,
362
+ writable: true
363
+ });
364
+ return registry;
365
+ };
366
+ function* createVisitorIterator() {
367
+ let index = 0;
368
+ while (index < lessVisitorInstances.length) {
369
+ yield lessVisitorInstances[index];
370
+ index++;
371
+ }
372
+ }
373
+ let currentRealRegistry = this._jessFunctionRegistry;
374
+ const createFunctionRegistry = () => {
375
+ const data = {};
376
+ let base = null;
377
+ return attachFunctionRegistrySurface({
378
+ get _data() {
379
+ return data;
380
+ },
381
+ get _base() {
382
+ return base;
383
+ },
384
+ set _base(v) {
385
+ base = v;
386
+ },
387
+ add(name, func) {
388
+ name = name.toLowerCase();
389
+ data[name] = func;
390
+ if (currentRealRegistry) addToJessRegistry(currentRealRegistry, name, func);
391
+ },
392
+ addMultiple(functions) {
393
+ Object.keys(functions).forEach((name) => {
394
+ this.add(name, functions[name]);
395
+ });
396
+ },
397
+ get(name) {
398
+ name = name.toLowerCase();
399
+ if (data[name]) return data[name];
400
+ if (base) return base.get(name);
401
+ if (currentRealRegistry) try {
402
+ return currentRealRegistry.get(name);
403
+ } catch (_e) {}
404
+ },
405
+ getLocalFunctions() {
406
+ return { ...data };
407
+ },
408
+ inherit() {
409
+ const child = createFunctionRegistry();
410
+ child._base = this;
411
+ return child;
412
+ },
413
+ create(base) {
414
+ const newRegistry = createFunctionRegistry();
415
+ newRegistry._base = base;
416
+ return newRegistry;
417
+ }
418
+ });
419
+ };
420
+ /**
421
+ * Create a mock function registry that forwards add/addMultiple/get to the given
422
+ * Jess registry. Used when loading @plugin scripts so functions register into the
423
+ * Rules that contain the @plugin directive.
424
+ */
425
+ const createScopedFunctionRegistry = (jessRegistry) => {
426
+ const data = {};
427
+ return attachFunctionRegistrySurface({
428
+ add(name, func) {
429
+ name = name.toLowerCase();
430
+ data[name] = func;
431
+ addToJessRegistry(jessRegistry, name, func);
432
+ },
433
+ addMultiple(functions) {
434
+ Object.keys(functions).forEach((name) => {
435
+ this.add(name, functions[name]);
436
+ });
437
+ },
438
+ get(name) {
439
+ name = name.toLowerCase();
440
+ if (data[name]) return data[name];
441
+ try {
442
+ return jessRegistry?.get?.(name);
443
+ } catch {
444
+ return;
445
+ }
446
+ }
447
+ });
448
+ };
449
+ const functionRegistry = createFunctionRegistry();
450
+ const mockLess = createLessMock(functionRegistry);
451
+ const pluginManager = new LessPluginManagerClass(mockLess, true);
452
+ this._lessPluginManager = pluginManager;
453
+ const loadPluginSource = (fullPath, registerPlugin, targetJessRegistry) => {
454
+ const contents = fs.readFileSync(fullPath, "utf8");
455
+ const localModule = { exports: {} };
456
+ const functions = targetJessRegistry != null ? createScopedFunctionRegistry(targetJessRegistry) : functionRegistry;
457
+ new Function("module", "require", "registerPlugin", "functions", "tree", "less", "fileInfo", contents)(localModule, createRequire(fullPath), registerPlugin, functions, LessTreeConstructors, mockLess, { filename: fullPath });
458
+ return {
459
+ module: localModule.exports,
460
+ registered: null
461
+ };
462
+ };
463
+ const requirePluginFile = (fullPath, targetJessRegistry) => {
464
+ const registeredPlugins = [];
465
+ const registerPlugin = (plugin) => {
466
+ registeredPlugins.push(plugin);
467
+ };
468
+ const loaded = loadPluginSource(fullPath, registerPlugin, targetJessRegistry);
469
+ return {
470
+ module: loaded.module,
471
+ registered: registeredPlugins.length > 0 ? registeredPlugins[registeredPlugins.length - 1] : loaded.registered
472
+ };
473
+ };
474
+ pluginManagerRef = pluginManager;
475
+ mockLessRef = mockLess;
476
+ if (this.opts.plugins?.length) {
477
+ const { lessPlugins } = filterPlugins(this.opts.plugins);
478
+ if (lessPlugins.length > 0) {
479
+ const visitorsBefore = pluginManager.visitors ? [...pluginManager.visitors] : [];
480
+ const processedPlugins = [];
481
+ lessPlugins.forEach((plugin) => {
482
+ if (!plugin) return;
483
+ if (typeof plugin === "function") try {
484
+ const pluginInstance = new plugin({});
485
+ if (pluginInstance) processedPlugins.push(pluginInstance);
486
+ else try {
487
+ const pluginInstance2 = plugin({});
488
+ if (pluginInstance2) processedPlugins.push(pluginInstance2);
489
+ else processedPlugins.push(plugin);
490
+ } catch (_e2) {
491
+ processedPlugins.push(plugin);
492
+ }
493
+ } catch (_e) {
494
+ try {
495
+ const pluginInstance = plugin({});
496
+ if (pluginInstance) processedPlugins.push(pluginInstance);
497
+ else processedPlugins.push(plugin);
498
+ } catch (_e2) {
499
+ processedPlugins.push(plugin);
500
+ }
501
+ }
502
+ else processedPlugins.push(plugin);
503
+ });
504
+ processedPlugins.forEach((plugin) => {
505
+ if (!plugin) return;
506
+ try {
507
+ const wrappedVisitor = new LessVisitor$1(plugin);
508
+ lessVisitorInstances.push(wrappedVisitor);
509
+ } catch (e) {}
510
+ if (typeof plugin.install === "function") plugin.install(mockLess, pluginManager, mockLess.functions.functionRegistry);
511
+ else if (typeof plugin === "function") if (plugin.prototype && typeof plugin.prototype.install === "function") try {
512
+ const pluginInstance = new plugin({});
513
+ if (pluginInstance && typeof pluginInstance.install === "function") pluginInstance.install(mockLess, pluginManager, mockLess.functions.functionRegistry);
514
+ } catch (_e) {
515
+ try {
516
+ const pluginInstance = plugin({});
517
+ if (pluginInstance && typeof pluginInstance.install === "function") pluginInstance.install(mockLess, pluginManager, mockLess.functions.functionRegistry);
518
+ else if (pluginInstance) lessVisitorInstances.push(new LessVisitor$1(pluginInstance));
519
+ } catch (_e2) {
520
+ lessVisitorInstances.push(new LessVisitor$1(plugin));
521
+ }
522
+ }
523
+ else try {
524
+ const pluginInstance = plugin({});
525
+ if (pluginInstance && typeof pluginInstance.install === "function") pluginInstance.install(mockLess, pluginManager, mockLess.functions.functionRegistry);
526
+ else if (pluginInstance) lessVisitorInstances.push(new LessVisitor$1(pluginInstance));
527
+ } catch (_e2) {
528
+ lessVisitorInstances.push(new LessVisitor$1(plugin));
529
+ }
530
+ else lessVisitorInstances.push(new LessVisitor$1(plugin));
531
+ });
532
+ if (pluginManager.visitors && pluginManager.visitors.length > visitorsBefore.length) {
533
+ const newVisitors = pluginManager.visitors.slice(visitorsBefore.length);
534
+ lessVisitorInstances.push(...newVisitors.map((v) => {
535
+ if (v instanceof LessVisitor$1) return v;
536
+ return new LessVisitor$1(v);
537
+ }));
538
+ }
539
+ }
540
+ }
541
+ /** @deprecated Less.js Visitor API - Direct visitor support for Less.js compatibility */
542
+ if (this.opts.visitors?.length) this.opts.visitors.forEach((visitorImpl) => {
543
+ if (visitorImpl instanceof LessVisitor$1) lessVisitorInstances.push(visitorImpl);
544
+ else lessVisitorInstances.push(new LessVisitor$1(visitorImpl));
545
+ });
546
+ const processing = /* @__PURE__ */ new WeakSet();
547
+ let insideLessTraversal = false;
548
+ const processedPluginDirectives = /* @__PURE__ */ new WeakSet();
549
+ const visitor = {
550
+ atRule: (node, _ctx) => {
551
+ if (node && (node.type === "AtRule" || node.type === "AtRuleStatement" || node.type === "Directive")) {
552
+ const atRuleName = node.name ?? node.value?.name;
553
+ let nameValue;
554
+ if (typeof atRuleName === "string") nameValue = atRuleName;
555
+ else if (atRuleName?.value) nameValue = atRuleName.value;
556
+ else if (typeof atRuleName?.valueOf === "function") {
557
+ const value = atRuleName.valueOf();
558
+ if (typeof value === "string") nameValue = value;
559
+ }
560
+ if (nameValue === "plugin" || nameValue === "@plugin") {
561
+ const rawDirective = node instanceof LessAdapterBase ? node.jessNode : node;
562
+ const pluginDirectiveNode = typeof rawDirective === "object" && rawDirective !== null ? rawDirective : {};
563
+ if (processedPluginDirectives.has(pluginDirectiveNode)) return node;
564
+ processedPluginDirectives.add(pluginDirectiveNode);
565
+ this.warnForPluginDirective(rawDirective);
566
+ if (this._context?.opts?.disableScriptModules || this._context?.opts?.disablePluginRule) throw new Error(SCRIPT_MODULES_DISABLED_MESSAGE);
567
+ const baseDir = this._currentFilePath ? path.dirname(this._currentFilePath) : void 0;
568
+ const prelude = node.prelude ?? node.value?.prelude ?? node.value;
569
+ let pluginPath;
570
+ let pluginOptions;
571
+ if (prelude) {
572
+ const isObjectLike = (value) => typeof value === "object" && value !== null;
573
+ const hasValueOf = (value) => isObjectLike(value) && typeof value.valueOf === "function";
574
+ const valueOfString = (value, trim = false) => {
575
+ if (!hasValueOf(value)) return;
576
+ const output = value.valueOf();
577
+ return typeof output === "string" ? trim ? output.trim() : output : void 0;
578
+ };
579
+ const stringFromNodeValue = (value) => {
580
+ if (typeof value === "string") return value;
581
+ const valueResult = valueOfString(value);
582
+ if (valueResult !== void 0) return valueResult;
583
+ if (isObjectLike(value) && typeof value.value === "string") return value.value;
584
+ };
585
+ const extractStringValue = (node) => {
586
+ if (!node) return;
587
+ if (typeof node === "string") return node;
588
+ if (!isObjectLike(node)) return;
589
+ if (node.type === "Quoted" && node.value) {
590
+ const value = stringFromNodeValue(node.value);
591
+ if (value !== void 0) return value;
592
+ return valueOfString(node);
593
+ }
594
+ if (node.type === "Url" && node.value) {
595
+ const value = stringFromNodeValue(node.value);
596
+ if (value !== void 0) return value;
597
+ if (isObjectLike(node.value) && node.value.type === "Quoted") return extractStringValue(node.value);
598
+ return valueOfString(node);
599
+ }
600
+ return valueOfString(node, true);
601
+ };
602
+ if (typeof prelude === "string") pluginPath = prelude;
603
+ else if (prelude.type === "Quoted" || prelude.type === "Url") pluginPath = extractStringValue(prelude);
604
+ else if (prelude.type === "Sequence" && Array.isArray(prelude.value)) for (let i = 0; i < prelude.value.length; i++) {
605
+ const item = prelude.value[i];
606
+ const extracted = extractStringValue(item);
607
+ if (item && extracted !== void 0) {
608
+ pluginPath = extracted;
609
+ if (i > 0) {
610
+ const prevItem = prelude.value[i - 1];
611
+ if (prevItem && prevItem.type === "Paren" && prevItem.value) {
612
+ const optionsValue = prevItem.value.valueOf ? prevItem.value.valueOf() : prevItem.value.toString();
613
+ if (typeof optionsValue === "string") pluginOptions = optionsValue.trim();
614
+ } else if (prevItem && typeof prevItem.valueOf === "function") {
615
+ const optionsValue = prevItem.valueOf();
616
+ if (typeof optionsValue === "string" && optionsValue.includes("=")) pluginOptions = optionsValue.trim();
617
+ }
618
+ }
619
+ if (pluginPath) break;
620
+ }
621
+ }
622
+ else if (prelude.type === "Expression" && prelude.value) {
623
+ const values = Array.isArray(prelude.value) ? prelude.value : [prelude.value];
624
+ for (let i = 0; i < values.length; i++) {
625
+ const item = values[i];
626
+ const extracted = extractStringValue(item);
627
+ if (item && extracted !== void 0) {
628
+ pluginPath = extracted;
629
+ if (i > 0) {
630
+ const prevItem = values[i - 1];
631
+ if (prevItem && prevItem.type === "Paren" && prevItem.value) {
632
+ const optionsValue = prevItem.value.valueOf ? prevItem.value.valueOf() : prevItem.value.toString();
633
+ if (typeof optionsValue === "string") pluginOptions = optionsValue.trim();
634
+ }
635
+ }
636
+ if (pluginPath) break;
637
+ }
638
+ }
639
+ } else if (prelude.type === "List" && prelude.value) {
640
+ const items = Array.isArray(prelude.value) ? prelude.value : [prelude.value];
641
+ for (let i = 0; i < items.length; i++) {
642
+ const item = items[i];
643
+ const extracted = extractStringValue(item);
644
+ if (item && extracted !== void 0) {
645
+ pluginPath = extracted;
646
+ if (i > 0) {
647
+ const prevItem = items[i - 1];
648
+ if (prevItem && prevItem.type === "Paren" && prevItem.value) {
649
+ const optionsValue = prevItem.value.valueOf ? prevItem.value.valueOf() : prevItem.value.toString();
650
+ if (typeof optionsValue === "string") pluginOptions = optionsValue.trim();
651
+ }
652
+ }
653
+ if (pluginPath) break;
654
+ }
655
+ }
656
+ } else if (prelude.value && typeof prelude.value === "string") pluginPath = prelude.value;
657
+ if (!pluginPath && typeof prelude.valueOf === "function") {
658
+ const fallbackValue = prelude.valueOf();
659
+ if (typeof fallbackValue === "string") pluginPath = fallbackValue;
660
+ }
661
+ }
662
+ if (pluginPath) {
663
+ if (typeof pluginPath === "string") pluginPath = pluginPath.trim().replace(/^["']|["']$/g, "").trim();
664
+ else pluginPath = String(pluginPath).trim().replace(/^["']|["']$/g, "").trim();
665
+ const isExplicitLocalPath = pluginPath.startsWith(".") || pluginPath.startsWith("/") || pluginPath.includes("/") || pluginPath.includes(path.sep);
666
+ const localBasePath = baseDir && !path.isAbsolute(pluginPath) ? path.resolve(baseDir, pluginPath) : path.isAbsolute(pluginPath) ? pluginPath : void 0;
667
+ let resolvedLocalPluginFile;
668
+ if (localBasePath) resolvedLocalPluginFile = [
669
+ localBasePath,
670
+ `${localBasePath}.js`,
671
+ `${localBasePath}.cjs`,
672
+ `${localBasePath}.mjs`
673
+ ].find((p) => fs.existsSync(p));
674
+ const isLocalPath = isExplicitLocalPath || !!resolvedLocalPluginFile;
675
+ if (isLocalPath && (!pluginManagerRef || !mockLessRef)) throw new Error(LESS_PLUGIN_JS_RUNTIME_MESSAGE);
676
+ if (pluginManagerRef && mockLessRef) try {
677
+ let scopeRules = node instanceof LessAdapterBase ? node.jessNode : node;
678
+ while (scopeRules && scopeRules.type !== "Rules") scopeRules = scopeRules.parent;
679
+ if (scopeRules && typeof scopeRules.setFunctionBinding === "function" && typeof scopeRules.findFunction === "function") if (!scopeRules.parent) currentRealRegistry = this._jessFunctionRegistry;
680
+ else currentRealRegistry = this.createJessFunctionBindingRegistry(scopeRules);
681
+ else currentRealRegistry = this._jessFunctionRegistry;
682
+ let pluginInstance = null;
683
+ if (this.opts.pluginRegistry && this.opts.pluginRegistry[pluginPath]) {
684
+ const pluginFactory = this.opts.pluginRegistry[pluginPath];
685
+ pluginInstance = typeof pluginFactory === "function" ? pluginFactory() : pluginFactory;
686
+ } else if (isLocalPath && resolvedLocalPluginFile) {
687
+ const loadedWithDeno = this.loadLessPluginFileWithDeno(resolvedLocalPluginFile, currentRealRegistry);
688
+ if (isThenable(loadedWithDeno)) return loadedWithDeno.then((loaded) => {
689
+ if (!loaded) throw new Error(LESS_PLUGIN_JS_RUNTIME_MESSAGE);
690
+ this.markPluginDirectiveInvisible(node);
691
+ return node;
692
+ });
693
+ if (!loadedWithDeno) throw new Error(LESS_PLUGIN_JS_RUNTIME_MESSAGE);
694
+ } else if (isLocalPath) throw new Error(LESS_PLUGIN_JS_RUNTIME_MESSAGE);
695
+ else if (!isLocalPath && this.opts.autoLoadPlugins !== false) {
696
+ const packageNamesToTry = ["less-plugin-", ""].map((prefix) => prefix + pluginPath);
697
+ let loaded = false;
698
+ if (this.opts.nodeModulesPlugin) for (const packageName of packageNamesToTry) {
699
+ const resolvedPath = this.opts.nodeModulesPlugin.resolvePackage(packageName);
700
+ if (resolvedPath) try {
701
+ const { module: pluginModule, registered } = requirePluginFile(resolvedPath, currentRealRegistry);
702
+ let PluginClass = pluginModule.default || pluginModule;
703
+ pluginInstance = registered || PluginClass;
704
+ loaded = true;
705
+ break;
706
+ } catch {}
707
+ }
708
+ if (!loaded) for (const fullName of packageNamesToTry) try {
709
+ if (typeof __require !== "undefined") {
710
+ const { module: pluginModule, registered } = requirePluginFile(fullName, currentRealRegistry);
711
+ let PluginClass = pluginModule.default || pluginModule;
712
+ pluginInstance = registered || PluginClass;
713
+ loaded = true;
714
+ break;
715
+ }
716
+ } catch (e) {
717
+ if (e.code !== "MODULE_NOT_FOUND") {}
718
+ }
719
+ }
720
+ if (pluginInstance) {
721
+ if (typeof pluginInstance === "function") try {
722
+ pluginInstance = new pluginInstance();
723
+ } catch {}
724
+ if (pluginOptions && typeof pluginInstance.setOptions === "function") try {
725
+ pluginInstance.setOptions(pluginOptions);
726
+ } catch {}
727
+ const visitorsBefore = pluginManagerRef.visitors.length;
728
+ pluginManagerRef.registerPlugin(pluginInstance);
729
+ if (pluginOptions && typeof pluginInstance.setOptions === "function") try {
730
+ pluginInstance.setOptions(pluginOptions);
731
+ } catch {}
732
+ if (pluginManagerRef.visitors.length > visitorsBefore) {
733
+ const newVisitors = pluginManagerRef.visitors.slice(visitorsBefore);
734
+ lessVisitorInstances.push(...newVisitors.map((v) => {
735
+ if (v instanceof LessVisitor$1) return v;
736
+ return new LessVisitor$1(v);
737
+ }));
738
+ }
739
+ }
740
+ } catch (e) {
741
+ if (e instanceof Error && e.message === LESS_PLUGIN_JS_RUNTIME_MESSAGE) throw e;
742
+ }
743
+ }
744
+ this.markPluginDirectiveInvisible(node);
745
+ }
746
+ }
747
+ return node;
748
+ },
749
+ visit: (node) => {
750
+ if (!node) return node;
751
+ const jessNode = node instanceof LessAdapterBase ? node.jessNode : node;
752
+ if (typeof jessNode !== "object" || jessNode === null) return node;
753
+ if ((node.type === "AtRule" || node.type === "AtRuleStatement" || node.type === "Directive") && visitor.atRule) {
754
+ const atRuleResult = visitor.atRule(node, void 0);
755
+ if (atRuleResult && typeof atRuleResult !== "symbol" && atRuleResult !== node) {
756
+ node = atRuleResult;
757
+ if ((node instanceof LessAdapterBase ? node.jessNode : node) !== jessNode) {}
758
+ }
759
+ }
760
+ if (insideLessTraversal) return node;
761
+ if (processing.has(jessNode)) return node;
762
+ processing.add(jessNode);
763
+ try {
764
+ const lessNode = toLessNode(jessNode, { cache: cacheMap });
765
+ insideLessTraversal = true;
766
+ try {
767
+ let result = lessNode;
768
+ if (lessVisitorInstances.length > 0) {
769
+ const visitorIterator = createVisitorIterator();
770
+ let iteratorResult = visitorIterator.next();
771
+ let iterationCount = 0;
772
+ while (!iteratorResult.done) {
773
+ iterationCount++;
774
+ if (iterationCount > 100) break;
775
+ result = iteratorResult.value.visit(result);
776
+ if (result === void 0) return REMOVE;
777
+ iteratorResult = visitorIterator.next();
778
+ }
779
+ }
780
+ if (result !== lessNode) {
781
+ const converted = fromLessNode(result, { cache: cacheMap });
782
+ return converted !== jessNode ? converted : jessNode;
783
+ }
784
+ return jessNode;
785
+ } finally {
786
+ insideLessTraversal = false;
787
+ }
788
+ } finally {}
789
+ }
790
+ };
791
+ return visitor;
792
+ }
793
+ };
794
+ /**
795
+ * Create a Less.js compatibility plugin
796
+ */
797
+ const lessCompatPlugin = (opts) => {
798
+ return new LessCompatPlugin(opts);
799
+ };
800
+ //#endregion
801
+ export { LessAdapterBase, LessCompatPlugin, LessTreeConstructors, createLessAdapter, createLessMock, lessCompatPlugin as default, lessCompatPlugin, filterPlugins, fromLessNode, fromLessPluginReturnValue, fromLessTree, getLessTypeIndex, isJessPlugin, isLessPlugin, mapJessTypeToLessType, mapLessTypeToJessType, toLessNode, toLessTree };