@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.
- package/README.md +3 -2
- package/lib/index.cjs +844 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +800 -10
- package/lib/less-adapter.cjs +216 -0
- package/lib/less-adapter.js +181 -0
- package/lib/less-compat-structures.cjs +378 -0
- package/lib/less-compat-structures.d.ts +2 -2
- package/lib/less-compat-structures.js +367 -512
- package/lib/nodes/at-rule.d.ts +2 -2
- package/lib/nodes/attribute-selector.d.ts +2 -2
- package/lib/nodes/call.d.ts +2 -2
- package/lib/nodes/color.d.ts +2 -1
- package/lib/nodes/combinator.d.ts +2 -1
- package/lib/nodes/comment.d.ts +2 -1
- package/lib/nodes/condition.d.ts +2 -2
- package/lib/nodes/declaration.d.ts +2 -2
- package/lib/nodes/dimension.d.ts +2 -1
- package/lib/nodes/expression.d.ts +2 -2
- package/lib/nodes/extend.d.ts +2 -1
- package/lib/nodes/import.d.ts +2 -2
- package/lib/nodes/keyword.d.ts +2 -1
- package/lib/nodes/list.d.ts +3 -2
- package/lib/nodes/mixin.d.ts +2 -2
- package/lib/nodes/negative.d.ts +2 -2
- package/lib/nodes/operation.d.ts +2 -2
- package/lib/nodes/paren.d.ts +2 -2
- package/lib/nodes/quoted.d.ts +2 -1
- package/lib/nodes/reference.d.ts +2 -1
- package/lib/nodes/ruleset.d.ts +2 -2
- package/lib/nodes/selector.d.ts +2 -2
- package/lib/nodes/sequence.d.ts +2 -2
- package/lib/nodes/url.d.ts +2 -1
- package/lib/nodes/var-declaration.d.ts +2 -2
- package/lib/plugin.d.ts +44 -16
- package/lib/transform/adapter.d.ts +9 -11
- package/lib/transform/index.cjs +13 -0
- package/lib/transform/index.d.ts +1 -1
- package/lib/transform/index.js +3 -8
- package/lib/transform/less-adapter.d.ts +29 -0
- package/lib/transform.cjs +1045 -0
- package/lib/transform.js +1015 -0
- package/lib/types.d.ts +153 -28
- package/package.json +6 -9
- package/lib/index.js.map +0 -1
- package/lib/less-compat-structures.js.map +0 -1
- package/lib/nodes/at-rule.js +0 -21
- package/lib/nodes/at-rule.js.map +0 -1
- package/lib/nodes/attribute-selector.js +0 -18
- package/lib/nodes/attribute-selector.js.map +0 -1
- package/lib/nodes/call.js +0 -27
- package/lib/nodes/call.js.map +0 -1
- package/lib/nodes/color.js +0 -23
- package/lib/nodes/color.js.map +0 -1
- package/lib/nodes/combinator.js +0 -7
- package/lib/nodes/combinator.js.map +0 -1
- package/lib/nodes/comment.js +0 -9
- package/lib/nodes/comment.js.map +0 -1
- package/lib/nodes/condition.js +0 -19
- package/lib/nodes/condition.js.map +0 -1
- package/lib/nodes/declaration.js +0 -38
- package/lib/nodes/declaration.js.map +0 -1
- package/lib/nodes/dimension.js +0 -9
- package/lib/nodes/dimension.js.map +0 -1
- package/lib/nodes/expression.js +0 -16
- package/lib/nodes/expression.js.map +0 -1
- package/lib/nodes/extend.js +0 -18
- package/lib/nodes/extend.js.map +0 -1
- package/lib/nodes/import.js +0 -22
- package/lib/nodes/import.js.map +0 -1
- package/lib/nodes/index.js +0 -308
- package/lib/nodes/index.js.map +0 -1
- package/lib/nodes/keyword.js +0 -8
- package/lib/nodes/keyword.js.map +0 -1
- package/lib/nodes/list.js +0 -61
- package/lib/nodes/list.js.map +0 -1
- package/lib/nodes/mixin.js +0 -22
- package/lib/nodes/mixin.js.map +0 -1
- package/lib/nodes/negative.js +0 -13
- package/lib/nodes/negative.js.map +0 -1
- package/lib/nodes/operation.js +0 -22
- package/lib/nodes/operation.js.map +0 -1
- package/lib/nodes/paren.js +0 -13
- package/lib/nodes/paren.js.map +0 -1
- package/lib/nodes/quoted.js +0 -23
- package/lib/nodes/quoted.js.map +0 -1
- package/lib/nodes/reference.js +0 -44
- package/lib/nodes/reference.js.map +0 -1
- package/lib/nodes/ruleset.js +0 -67
- package/lib/nodes/ruleset.js.map +0 -1
- package/lib/nodes/selector.js +0 -158
- package/lib/nodes/selector.js.map +0 -1
- package/lib/nodes/sequence.js +0 -56
- package/lib/nodes/sequence.js.map +0 -1
- package/lib/nodes/url.js +0 -13
- package/lib/nodes/url.js.map +0 -1
- package/lib/nodes/var-declaration.js +0 -21
- package/lib/nodes/var-declaration.js.map +0 -1
- package/lib/plugin-utils.js +0 -100
- package/lib/plugin-utils.js.map +0 -1
- package/lib/plugin.js +0 -1026
- package/lib/plugin.js.map +0 -1
- package/lib/transform/adapter.js +0 -111
- package/lib/transform/adapter.js.map +0 -1
- package/lib/transform/from-less.js +0 -170
- package/lib/transform/from-less.js.map +0 -1
- package/lib/transform/index.js.map +0 -1
- package/lib/transform/proxy.d.ts +0 -32
- package/lib/transform/proxy.js +0 -138
- package/lib/transform/proxy.js.map +0 -1
- package/lib/transform/to-less.js +0 -130
- package/lib/transform/to-less.js.map +0 -1
- package/lib/transform/type-map.js +0 -105
- package/lib/transform/type-map.js.map +0 -1
- package/lib/types.js +0 -5
- package/lib/types.js.map +0 -1
package/lib/transform.js
ADDED
|
@@ -0,0 +1,1015 @@
|
|
|
1
|
+
import { a as mapJessTypeToLessType, n as createLessAdapter, r as isAdaptingNode, t as LessAdapterBase } from "./less-adapter.js";
|
|
2
|
+
import { Ampersand, Any, BasicSelector, Collection, Color, ColorFormat, Combinator, ComplexSelector, CompoundSelector, Declaration, Dimension, ExtendFlag, Interpolated, Nil, Node, Num, Quoted, Rules, Selector, SelectorList, isStringCombinator, sourceSpanOf } from "@jesscss/core";
|
|
3
|
+
//#region src/transform/adapter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create a NodeTransformer from a declarative adapter definition.
|
|
6
|
+
*
|
|
7
|
+
* - `type` and `typeIndex` are auto-mapped.
|
|
8
|
+
* - If no `accept` is provided, leaf behavior (return self) is used.
|
|
9
|
+
* - Field lookups are dispatched from the `fields` record.
|
|
10
|
+
*/
|
|
11
|
+
function createFromAdapter(adapter) {
|
|
12
|
+
return (jessNode, cache) => {
|
|
13
|
+
return createLessAdapter(jessNode, {
|
|
14
|
+
lessType: adapter.lessType ?? ((node) => mapJessTypeToLessType(node.type)),
|
|
15
|
+
fields: adapter.fields,
|
|
16
|
+
accept: adapter.accept
|
|
17
|
+
}, cache);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function selfVisitAccept() {
|
|
21
|
+
return (node) => {
|
|
22
|
+
return node;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accept helper: traverse child nodes via visitor.visitArray.
|
|
27
|
+
*/
|
|
28
|
+
function childrenAccept(getChildren) {
|
|
29
|
+
return (node, visitor, cache) => {
|
|
30
|
+
const children = getChildren(node, cache);
|
|
31
|
+
if (children.length > 0) {
|
|
32
|
+
const lessChildren = children.map((child) => toLessNode(child, { cache })).filter((child) => child != null);
|
|
33
|
+
if (lessChildren.length > 0) {
|
|
34
|
+
if (visitor.visitArray) visitor.visitArray(lessChildren);
|
|
35
|
+
else for (const child of lessChildren) if (child?.accept) child.accept(visitor);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return node;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Accept helper: traverse a single child node.
|
|
43
|
+
*/
|
|
44
|
+
function singleChildAccept(getChild) {
|
|
45
|
+
return (node, visitor, cache) => {
|
|
46
|
+
const child = getChild(node);
|
|
47
|
+
if (child instanceof Node) {
|
|
48
|
+
const lessChild = toLessNode(child, { cache });
|
|
49
|
+
if (lessChild?.accept) lessChild.accept(visitor);
|
|
50
|
+
else if (lessChild && visitor.visitArray) visitor.visitArray([lessChild]);
|
|
51
|
+
else if (lessChild && visitor.visit) visitor.visit(lessChild);
|
|
52
|
+
}
|
|
53
|
+
return node;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/nodes/selector.ts
|
|
58
|
+
/**
|
|
59
|
+
* Flatten a hierarchical Jess selector into Less's flat Element array.
|
|
60
|
+
* Less expects: Element[] where each Element has { combinator, value }
|
|
61
|
+
* Jess now models complex selectors as an interleaved stream of selector
|
|
62
|
+
* components and explicit combinators. Less still expects flat Elements with
|
|
63
|
+
* the combinator attached to the following selector component.
|
|
64
|
+
*/
|
|
65
|
+
function flattenSelectorToElements(selector, cache) {
|
|
66
|
+
const elements = [];
|
|
67
|
+
if (typeof selector === "string") {
|
|
68
|
+
elements.push(createElementAdapter(selector, createLessCombinator(""), cache));
|
|
69
|
+
return elements;
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(selector)) {
|
|
72
|
+
const first = selector[0];
|
|
73
|
+
return first !== void 0 ? flattenSelectorToElements(first, cache) : [];
|
|
74
|
+
}
|
|
75
|
+
if (selector instanceof SelectorList) {
|
|
76
|
+
const selectorListValue = selector.value;
|
|
77
|
+
if (selectorListValue.length > 0 && selectorListValue[0]) return flattenSelectorToElements(selectorListValue[0], cache);
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
if (selector instanceof ComplexSelector) {
|
|
81
|
+
const components = selector.value;
|
|
82
|
+
let nextCombinatorValue = "";
|
|
83
|
+
for (let i = 0; i < components.length; i++) {
|
|
84
|
+
const component = components[i];
|
|
85
|
+
if (!component) continue;
|
|
86
|
+
if (component instanceof Combinator) {
|
|
87
|
+
nextCombinatorValue = component.value;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (typeof component === "string" && isStringCombinator(component)) {
|
|
91
|
+
nextCombinatorValue = component;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (component instanceof CompoundSelector) {
|
|
95
|
+
const compoundValue = component.value;
|
|
96
|
+
for (let j = 0; j < compoundValue.length; j++) {
|
|
97
|
+
const simple = compoundValue[j];
|
|
98
|
+
if (!simple) continue;
|
|
99
|
+
const elementCombinator = createLessCombinator(j === 0 ? nextCombinatorValue : "");
|
|
100
|
+
elements.push(createElementAdapter(simple, elementCombinator, cache));
|
|
101
|
+
}
|
|
102
|
+
} else if (typeof component === "string") {
|
|
103
|
+
const elementCombinator = createLessCombinator(nextCombinatorValue);
|
|
104
|
+
elements.push(createElementAdapter(component, elementCombinator, cache));
|
|
105
|
+
} else if (component instanceof BasicSelector || component instanceof Ampersand) {
|
|
106
|
+
const elementCombinator = createLessCombinator(nextCombinatorValue);
|
|
107
|
+
elements.push(createElementAdapter(component, elementCombinator, cache));
|
|
108
|
+
} else if (component instanceof Node) {
|
|
109
|
+
const elementCombinator = createLessCombinator(nextCombinatorValue);
|
|
110
|
+
elements.push(createElementAdapter(component, elementCombinator, cache));
|
|
111
|
+
}
|
|
112
|
+
nextCombinatorValue = "";
|
|
113
|
+
}
|
|
114
|
+
} else if (selector instanceof CompoundSelector) {
|
|
115
|
+
const compoundSelValue = selector.value;
|
|
116
|
+
for (let i = 0; i < compoundSelValue.length; i++) {
|
|
117
|
+
const basic = compoundSelValue[i];
|
|
118
|
+
if (!basic) continue;
|
|
119
|
+
const combinator = createLessCombinator(i === 0 ? "" : "");
|
|
120
|
+
elements.push(createElementAdapter(basic, combinator, cache));
|
|
121
|
+
}
|
|
122
|
+
} else if (selector instanceof BasicSelector || selector instanceof Ampersand) elements.push(createElementAdapter(selector, createLessCombinator(""), cache));
|
|
123
|
+
return elements;
|
|
124
|
+
}
|
|
125
|
+
function createLessCombinator(value) {
|
|
126
|
+
return {
|
|
127
|
+
type: "Combinator",
|
|
128
|
+
typeIndex: void 0,
|
|
129
|
+
value,
|
|
130
|
+
emptyOrWhitespace: value === "" || value === " ",
|
|
131
|
+
accept() {
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function createElementAdapter(basic, combinator, cache) {
|
|
137
|
+
if (typeof basic === "string") return {
|
|
138
|
+
type: "Element",
|
|
139
|
+
typeIndex: void 0,
|
|
140
|
+
combinator,
|
|
141
|
+
value: basic,
|
|
142
|
+
isVariable: false,
|
|
143
|
+
accept(visitor) {
|
|
144
|
+
if (combinator && visitor.visit) visitor.visit(combinator);
|
|
145
|
+
return basic;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const adapter = createLessAdapter(basic, {
|
|
149
|
+
lessType: "Element",
|
|
150
|
+
fields: {
|
|
151
|
+
combinator: () => combinator,
|
|
152
|
+
value: (target) => "value" in target ? target.value : void 0,
|
|
153
|
+
isVariable: () => false
|
|
154
|
+
},
|
|
155
|
+
accept: (target, visitor) => {
|
|
156
|
+
if (combinator && visitor.visit) visitor.visit(combinator);
|
|
157
|
+
const value = "value" in target ? target.value : void 0;
|
|
158
|
+
if (value && typeof value === "object" && value instanceof Node) {
|
|
159
|
+
const lessValue = toLessNode(value, { cache });
|
|
160
|
+
if (lessValue && visitor.visit) visitor.visit(lessValue);
|
|
161
|
+
}
|
|
162
|
+
return target;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
if (cache) cache.set(basic, adapter);
|
|
166
|
+
return adapter;
|
|
167
|
+
}
|
|
168
|
+
function transformSelectorToLess(sel, cache) {
|
|
169
|
+
const elements = flattenSelectorToElements(sel, cache);
|
|
170
|
+
if (typeof sel === "string" || Array.isArray(sel)) return {
|
|
171
|
+
type: "Selector",
|
|
172
|
+
typeIndex: void 0,
|
|
173
|
+
elements,
|
|
174
|
+
length: elements.length,
|
|
175
|
+
accept(visitor) {
|
|
176
|
+
if (visitor.visitArray) visitor.visitArray(elements);
|
|
177
|
+
return sel;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const adapter = createLessAdapter(sel, {
|
|
181
|
+
lessType: "Selector",
|
|
182
|
+
fields: {
|
|
183
|
+
elements: () => elements,
|
|
184
|
+
length: () => elements.length
|
|
185
|
+
},
|
|
186
|
+
accept: (node, visitor) => {
|
|
187
|
+
if (visitor.visitArray) visitor.visitArray(elements);
|
|
188
|
+
else if (visitor.visit) for (const element of elements) visitor.visit(element);
|
|
189
|
+
else for (const element of elements) if (element?.accept) element.accept(visitor);
|
|
190
|
+
return node;
|
|
191
|
+
}
|
|
192
|
+
}, cache);
|
|
193
|
+
for (let i = 0; i < elements.length; i++) Object.defineProperty(adapter, String(i), {
|
|
194
|
+
enumerable: true,
|
|
195
|
+
configurable: true,
|
|
196
|
+
get: () => elements[i]
|
|
197
|
+
});
|
|
198
|
+
return adapter;
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/nodes/ruleset.ts
|
|
202
|
+
/**
|
|
203
|
+
* Return a Ruleset's child rules as a flat array.
|
|
204
|
+
*
|
|
205
|
+
* Core's `Ruleset.rules` is normally a plain `Node[]` (the parser delivers an
|
|
206
|
+
* array), but a caller may also construct a Ruleset with a `Rules` wrapper node
|
|
207
|
+
* as its body (`new Ruleset({ rules: new Rules([...]) })`). The wrapper is stored
|
|
208
|
+
* as-is now that the old factory-side unwrap was removed, so read its `.rules`.
|
|
209
|
+
*/
|
|
210
|
+
function ruleList(rs) {
|
|
211
|
+
const rules = rs.rules;
|
|
212
|
+
if (rules instanceof Rules) return rules.rules;
|
|
213
|
+
if (Array.isArray(rules)) return rules;
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
const transformRulesetToLess = createFromAdapter({
|
|
217
|
+
fields: {
|
|
218
|
+
selectors: (rs, cache) => {
|
|
219
|
+
const selector = rs.selector;
|
|
220
|
+
if (selector instanceof Nil) return [];
|
|
221
|
+
if (!selector) return [];
|
|
222
|
+
if (selector instanceof SelectorList) return selector.value.filter((s) => s instanceof Selector).map((s) => transformSelectorToLess(s, cache));
|
|
223
|
+
return [transformSelectorToLess(selector, cache)];
|
|
224
|
+
},
|
|
225
|
+
rules: (rs, cache) => {
|
|
226
|
+
return ruleList(rs).map((r) => toLessNode(r, { cache }));
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
accept: (ruleset, visitor, cache) => {
|
|
230
|
+
const selector = ruleset.selector;
|
|
231
|
+
const rules = ruleList(ruleset);
|
|
232
|
+
if (selector && !(selector instanceof Nil)) if (selector instanceof SelectorList) {
|
|
233
|
+
const lessSelectors = selector.value.filter((s) => s instanceof Selector).map((s) => toLessNode(s, { cache }));
|
|
234
|
+
if (visitor.visitArray) visitor.visitArray(lessSelectors);
|
|
235
|
+
else for (const ls of lessSelectors) if (ls?.accept) ls.accept(visitor);
|
|
236
|
+
} else {
|
|
237
|
+
const lessSelector = transformSelectorToLess(selector, cache);
|
|
238
|
+
if (lessSelector) {
|
|
239
|
+
if (visitor.visitArray) visitor.visitArray([lessSelector]);
|
|
240
|
+
else if (lessSelector.accept) lessSelector.accept(visitor);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (rules.length > 0) {
|
|
244
|
+
const lessRules = rules.map((r) => toLessNode(r, { cache }));
|
|
245
|
+
if (visitor.visitArray) visitor.visitArray(lessRules);
|
|
246
|
+
else for (const lr of lessRules) if (lr?.accept) lr.accept(visitor);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/transform/from-less.ts
|
|
252
|
+
/**
|
|
253
|
+
* Convert a Less node back to a Jess node
|
|
254
|
+
*
|
|
255
|
+
* @param lessNode - The Less node to convert
|
|
256
|
+
* @param options - Conversion options
|
|
257
|
+
* @returns A Jess node
|
|
258
|
+
*/
|
|
259
|
+
function fromLessNode(lessNode, options) {
|
|
260
|
+
if (!lessNode) return lessNode;
|
|
261
|
+
const cache = options?.cache || /* @__PURE__ */ new WeakMap();
|
|
262
|
+
if (cache.has(lessNode)) {
|
|
263
|
+
const cached = cache.get(lessNode);
|
|
264
|
+
if (cached) return cached;
|
|
265
|
+
}
|
|
266
|
+
if (lessNode instanceof LessAdapterBase) {
|
|
267
|
+
cache.set(lessNode, lessNode.jessNode);
|
|
268
|
+
return lessNode.jessNode;
|
|
269
|
+
}
|
|
270
|
+
if (lessNode && typeof lessNode === "object" && "__jessNode" in lessNode) return lessNode.__jessNode;
|
|
271
|
+
if (lessNode && typeof lessNode === "object" && typeof lessNode.type === "string") {
|
|
272
|
+
if (lessNode.type === "Quoted") {
|
|
273
|
+
const quote = lessNode.quote === "'" || lessNode.quote === "\"" ? lessNode.quote : "\"";
|
|
274
|
+
const out = new Quoted(typeof lessNode.value === "string" ? lessNode.value : String(lessNode.value), {
|
|
275
|
+
quote,
|
|
276
|
+
escaped: !!lessNode.escaped
|
|
277
|
+
});
|
|
278
|
+
cache.set(lessNode, out);
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
if (lessNode.type === "Anonymous") {
|
|
282
|
+
const out = new Any(typeof lessNode.value === "string" ? lessNode.value : String(lessNode.value));
|
|
283
|
+
cache.set(lessNode, out);
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
if (lessNode.type === "Dimension" || lessNode.type === "Num") {
|
|
287
|
+
const out = new Dimension({
|
|
288
|
+
number: typeof lessNode.value === "number" ? lessNode.value : Number(lessNode.value),
|
|
289
|
+
unit: (typeof lessNode.unit === "string" ? lessNode.unit : "") || void 0
|
|
290
|
+
});
|
|
291
|
+
cache.set(lessNode, out);
|
|
292
|
+
return out;
|
|
293
|
+
}
|
|
294
|
+
if (lessNode.type === "Color") {
|
|
295
|
+
const [r = 0, g = 0, b = 0] = Array.isArray(lessNode.rgb) ? lessNode.rgb : [
|
|
296
|
+
0,
|
|
297
|
+
0,
|
|
298
|
+
0
|
|
299
|
+
];
|
|
300
|
+
const alpha = typeof lessNode.alpha === "number" ? lessNode.alpha : 1;
|
|
301
|
+
const out = new Color({
|
|
302
|
+
rgb: [
|
|
303
|
+
r,
|
|
304
|
+
g,
|
|
305
|
+
b
|
|
306
|
+
],
|
|
307
|
+
alpha
|
|
308
|
+
}, { format: ColorFormat.HEX });
|
|
309
|
+
cache.set(lessNode, out);
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
if (lessNode.type === "Declaration" || lessNode.type === "Rule") {
|
|
313
|
+
const prop = String(lessNode.name ?? "");
|
|
314
|
+
const val = lessNode.value;
|
|
315
|
+
const decl = new Declaration({
|
|
316
|
+
name: prop,
|
|
317
|
+
value: new Any(val && typeof val === "object" && typeof val.value === "string" ? val.value : String(val ?? ""))
|
|
318
|
+
});
|
|
319
|
+
cache.set(lessNode, decl);
|
|
320
|
+
return decl;
|
|
321
|
+
}
|
|
322
|
+
if (lessNode.type === "DetachedRuleset") {
|
|
323
|
+
const ruleset = lessNode.ruleset;
|
|
324
|
+
const rules = ruleset && Array.isArray(ruleset.rules) ? ruleset.rules : [];
|
|
325
|
+
const nodes = [];
|
|
326
|
+
for (const rr of rules) if (rr && typeof rr === "object" && (rr.type === "Declaration" || rr.type === "Rule")) {
|
|
327
|
+
const prop = String(rr.name ?? "");
|
|
328
|
+
const val = rr.value;
|
|
329
|
+
const decl = new Declaration({
|
|
330
|
+
name: prop,
|
|
331
|
+
value: new Any(val && typeof val === "object" && typeof val.value === "string" ? val.value : String(val ?? ""))
|
|
332
|
+
});
|
|
333
|
+
nodes.push(decl);
|
|
334
|
+
}
|
|
335
|
+
const out = new Collection(nodes);
|
|
336
|
+
cache.set(lessNode, out);
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
if (lessNode.type === "AtRule") {
|
|
340
|
+
const n = String(lessNode.name ?? "");
|
|
341
|
+
const line = `${n} ${String(lessNode.value ?? "")};`;
|
|
342
|
+
const out = n === "@charset" ? new Any(line, { role: "charset" }) : new Any(line);
|
|
343
|
+
cache.set(lessNode, out);
|
|
344
|
+
return out;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
throw new Error(`Cannot convert Less node back to Jess: ${lessNode?.type || "unknown type"}. Less visitors should not create new nodes, only modify existing ones.`);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Convert a Less plugin function return value to a Jess node.
|
|
351
|
+
* Handles primitives (number, boolean), Less nodes (via fromLessNode), and toCSS() objects.
|
|
352
|
+
* Use this for @plugin-loaded function results so conversion is centralized here.
|
|
353
|
+
*/
|
|
354
|
+
function fromLessPluginReturnValue(value, options) {
|
|
355
|
+
if (value === null || value === void 0) return;
|
|
356
|
+
if (typeof value === "number") return new Any(String(value));
|
|
357
|
+
if (value === true || value === false) {
|
|
358
|
+
if (options?.statementContext) return;
|
|
359
|
+
return new Any(String(value));
|
|
360
|
+
}
|
|
361
|
+
if (typeof value === "object" && value !== null) {
|
|
362
|
+
if ("type" in value && typeof value.type === "string") return fromLessNode(value, options);
|
|
363
|
+
if ("toCSS" in value && typeof value.toCSS === "function") try {
|
|
364
|
+
const css = value.toCSS();
|
|
365
|
+
return new Any(typeof css === "string" ? css : String(css));
|
|
366
|
+
} catch {}
|
|
367
|
+
}
|
|
368
|
+
if (value instanceof Node) return value;
|
|
369
|
+
return new Any(String(value));
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Convert an entire Less tree back to Jess Rules
|
|
373
|
+
*
|
|
374
|
+
* @param lessTree - The Less tree to convert
|
|
375
|
+
* @param options - Conversion options
|
|
376
|
+
* @returns A Jess Rules tree
|
|
377
|
+
*/
|
|
378
|
+
function fromLessTree(lessTree, _options) {
|
|
379
|
+
if (lessTree instanceof LessAdapterBase && lessTree.jessNode instanceof Rules) return lessTree.jessNode;
|
|
380
|
+
throw new Error("Cannot convert Less tree back to Jess Rules");
|
|
381
|
+
}
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/nodes/declaration.ts
|
|
384
|
+
const transformDeclarationToLess = createFromAdapter({
|
|
385
|
+
fields: {
|
|
386
|
+
name: {
|
|
387
|
+
get: (d) => d.name,
|
|
388
|
+
set: (d, value) => {
|
|
389
|
+
d.name = value instanceof Interpolated ? value : String(value);
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
value: {
|
|
393
|
+
get: (d, cache) => {
|
|
394
|
+
const value = d.value;
|
|
395
|
+
return value instanceof Node ? toLessNode(value, { cache }) : value;
|
|
396
|
+
},
|
|
397
|
+
set: (d, value) => {
|
|
398
|
+
const node = value instanceof Node ? value : fromLessNode(value);
|
|
399
|
+
d.adopt(node);
|
|
400
|
+
d.value = node;
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
important: (d) => d.important || false,
|
|
404
|
+
variable: (d) => d.options?.assign !== void 0,
|
|
405
|
+
merge: () => false
|
|
406
|
+
},
|
|
407
|
+
accept: (decl, visitor, cache) => {
|
|
408
|
+
const value = decl.value;
|
|
409
|
+
if (value instanceof Node) {
|
|
410
|
+
const lessValue = toLessNode(value, { cache });
|
|
411
|
+
if (lessValue?.accept) lessValue.accept(visitor);
|
|
412
|
+
else if (lessValue && visitor.visitArray) visitor.visitArray([lessValue]);
|
|
413
|
+
else if (lessValue && visitor.visit) visitor.visit(lessValue);
|
|
414
|
+
}
|
|
415
|
+
return decl;
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
//#endregion
|
|
419
|
+
//#region src/nodes/mixin.ts
|
|
420
|
+
const transformMixinToLess = createFromAdapter({
|
|
421
|
+
fields: {
|
|
422
|
+
name: (m) => m.name,
|
|
423
|
+
params: (m, cache) => {
|
|
424
|
+
const params = m.params;
|
|
425
|
+
return params instanceof Node ? toLessNode(params, { cache }) : params;
|
|
426
|
+
},
|
|
427
|
+
rules: (m, cache) => {
|
|
428
|
+
return m.rules.map((r) => toLessNode(r, { cache }));
|
|
429
|
+
},
|
|
430
|
+
condition: (m, cache) => {
|
|
431
|
+
const guard = m.guard;
|
|
432
|
+
return guard instanceof Node ? toLessNode(guard, { cache }) : guard;
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
accept: selfVisitAccept()
|
|
436
|
+
});
|
|
437
|
+
//#endregion
|
|
438
|
+
//#region src/nodes/dimension.ts
|
|
439
|
+
const transformDimensionToLess = createFromAdapter({ fields: {
|
|
440
|
+
value: (d) => d.number,
|
|
441
|
+
unit: (d) => d instanceof Num ? "" : d.unit || ""
|
|
442
|
+
} });
|
|
443
|
+
//#endregion
|
|
444
|
+
//#region src/nodes/color.ts
|
|
445
|
+
const transformColorToLess = createFromAdapter({ fields: {
|
|
446
|
+
rgb: (c) => c.rgb || [
|
|
447
|
+
0,
|
|
448
|
+
0,
|
|
449
|
+
0
|
|
450
|
+
],
|
|
451
|
+
alpha: (c) => c._alpha,
|
|
452
|
+
value: (c) => {
|
|
453
|
+
const rgb = c.rgb;
|
|
454
|
+
const alpha = c._alpha;
|
|
455
|
+
if (rgb && alpha !== void 0 && alpha < 1) return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${alpha})`;
|
|
456
|
+
if (rgb) return `#${rgb.map((v) => {
|
|
457
|
+
const numericValue = Array.isArray(v) ? v[0] : v;
|
|
458
|
+
return Math.round(numericValue).toString(16).padStart(2, "0");
|
|
459
|
+
}).join("")}`;
|
|
460
|
+
return "";
|
|
461
|
+
}
|
|
462
|
+
} });
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/nodes/operation.ts
|
|
465
|
+
const transformOperationToLess = createFromAdapter({
|
|
466
|
+
fields: {
|
|
467
|
+
op: (o) => o.operator || "",
|
|
468
|
+
operands: (o, cache) => {
|
|
469
|
+
const operands = [];
|
|
470
|
+
const { left, right } = o;
|
|
471
|
+
if (left instanceof Node) operands.push(left);
|
|
472
|
+
if (right instanceof Node) operands.push(right);
|
|
473
|
+
return operands.map((n) => toLessNode(n, { cache }));
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
accept: selfVisitAccept()
|
|
477
|
+
});
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/nodes/expression.ts
|
|
480
|
+
const transformExpressionToLess = createFromAdapter({
|
|
481
|
+
fields: { value: (e, cache) => {
|
|
482
|
+
const value = e.value;
|
|
483
|
+
if (value instanceof Node) return [toLessNode(value, { cache })];
|
|
484
|
+
return [value];
|
|
485
|
+
} },
|
|
486
|
+
accept: selfVisitAccept()
|
|
487
|
+
});
|
|
488
|
+
//#endregion
|
|
489
|
+
//#region src/nodes/sequence.ts
|
|
490
|
+
const transformSequenceToLess = createFromAdapter({
|
|
491
|
+
fields: {
|
|
492
|
+
value: (seq, cache) => (seq.value ?? []).map((item) => item instanceof Node ? toLessNode(item, { cache }) : item).filter((item) => item != null),
|
|
493
|
+
length: (seq) => (seq.value ?? []).filter((v) => v != null).length
|
|
494
|
+
},
|
|
495
|
+
accept: (seq, visitor, cache) => {
|
|
496
|
+
const raw = seq.value ?? [];
|
|
497
|
+
if (!Array.isArray(raw) || raw.length === 0) return seq;
|
|
498
|
+
for (let i = 0; i < raw.length; i++) {
|
|
499
|
+
const item = raw[i];
|
|
500
|
+
if (item == null) continue;
|
|
501
|
+
const lessItem = item instanceof Node ? toLessNode(item, { cache }) : item;
|
|
502
|
+
if (!lessItem || typeof visitor?.visit !== "function") continue;
|
|
503
|
+
const visited = visitor.visit(lessItem);
|
|
504
|
+
if (visited && visited !== lessItem && typeof visited === "object" && "type" in visited) try {
|
|
505
|
+
const jessReplacement = fromLessNode(visited, { cache: /* @__PURE__ */ new WeakMap() });
|
|
506
|
+
if (item instanceof Node) jessReplacement.inherit(item);
|
|
507
|
+
seq.adopt(jessReplacement);
|
|
508
|
+
seq.value[i] = jessReplacement;
|
|
509
|
+
} catch {}
|
|
510
|
+
}
|
|
511
|
+
return seq;
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
//#endregion
|
|
515
|
+
//#region src/nodes/quoted.ts
|
|
516
|
+
const transformQuotedToLess = createFromAdapter({
|
|
517
|
+
fields: {
|
|
518
|
+
value: (q) => {
|
|
519
|
+
const value = q.value;
|
|
520
|
+
if (typeof value === "string") return value;
|
|
521
|
+
if (value instanceof Any) return value.value;
|
|
522
|
+
if (value instanceof Interpolated) return String(value.source);
|
|
523
|
+
return String(value);
|
|
524
|
+
},
|
|
525
|
+
quote: (q) => q.quote || "\"",
|
|
526
|
+
escaped: (q) => q.escaped === true
|
|
527
|
+
},
|
|
528
|
+
accept: selfVisitAccept()
|
|
529
|
+
});
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/nodes/url.ts
|
|
532
|
+
const transformUrlToLess = createFromAdapter({
|
|
533
|
+
fields: { value: (u, cache) => {
|
|
534
|
+
const value = u.value;
|
|
535
|
+
return value instanceof Quoted ? toLessNode(value, { cache }) : value;
|
|
536
|
+
} },
|
|
537
|
+
accept: selfVisitAccept()
|
|
538
|
+
});
|
|
539
|
+
//#endregion
|
|
540
|
+
//#region src/nodes/comment.ts
|
|
541
|
+
const transformCommentToLess = createFromAdapter({
|
|
542
|
+
fields: {
|
|
543
|
+
value: (c) => c.value,
|
|
544
|
+
silent: () => false
|
|
545
|
+
},
|
|
546
|
+
accept: selfVisitAccept()
|
|
547
|
+
});
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/nodes/at-rule.ts
|
|
550
|
+
const transformAtRuleToLess = createFromAdapter({
|
|
551
|
+
fields: {
|
|
552
|
+
name: (a) => a.name,
|
|
553
|
+
value: (a, cache) => {
|
|
554
|
+
const prelude = a.prelude;
|
|
555
|
+
return prelude instanceof Node ? toLessNode(prelude, { cache }) : prelude;
|
|
556
|
+
},
|
|
557
|
+
rules: (a, cache) => {
|
|
558
|
+
const rules = a.rules;
|
|
559
|
+
return rules ? rules.map((r) => toLessNode(r, { cache })) : [];
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
accept: childrenAccept((a) => {
|
|
563
|
+
const rules = a.rules;
|
|
564
|
+
return rules.length ? [...rules] : [];
|
|
565
|
+
})
|
|
566
|
+
});
|
|
567
|
+
//#endregion
|
|
568
|
+
//#region src/nodes/import.ts
|
|
569
|
+
const transformImportToLess = createFromAdapter({
|
|
570
|
+
fields: {
|
|
571
|
+
path: (imp, cache) => {
|
|
572
|
+
const path = imp.path;
|
|
573
|
+
return path instanceof Node ? toLessNode(path, { cache }) : path;
|
|
574
|
+
},
|
|
575
|
+
options: (imp) => imp.options?.importOptions || {},
|
|
576
|
+
currentFileInfo: () => ({}),
|
|
577
|
+
index: (imp) => sourceSpanOf(imp)?.start
|
|
578
|
+
},
|
|
579
|
+
accept: selfVisitAccept()
|
|
580
|
+
});
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/nodes/extend.ts
|
|
583
|
+
const transformExtendToLess = createFromAdapter({
|
|
584
|
+
fields: {
|
|
585
|
+
selector: (e, cache) => {
|
|
586
|
+
const selector = e.selector;
|
|
587
|
+
return selector instanceof Selector ? toLessNode(selector, { cache }) : selector;
|
|
588
|
+
},
|
|
589
|
+
option: (e) => e.flag === ExtendFlag.Exact ? "exact" : "all",
|
|
590
|
+
index: (e) => sourceSpanOf(e)?.start
|
|
591
|
+
},
|
|
592
|
+
accept: selfVisitAccept()
|
|
593
|
+
});
|
|
594
|
+
//#endregion
|
|
595
|
+
//#region src/nodes/condition.ts
|
|
596
|
+
const transformConditionToLess = createFromAdapter({
|
|
597
|
+
fields: {
|
|
598
|
+
op: (c) => c.operator || "",
|
|
599
|
+
lvalue: (c, cache) => {
|
|
600
|
+
const left = c.left;
|
|
601
|
+
return left instanceof Node ? toLessNode(left, { cache }) : left;
|
|
602
|
+
},
|
|
603
|
+
rvalue: (c, cache) => {
|
|
604
|
+
const right = c.right;
|
|
605
|
+
return right instanceof Node ? toLessNode(right, { cache }) : right;
|
|
606
|
+
},
|
|
607
|
+
negate: (c) => c.negate
|
|
608
|
+
},
|
|
609
|
+
accept: selfVisitAccept()
|
|
610
|
+
});
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region src/nodes/paren.ts
|
|
613
|
+
const transformParenToLess = createFromAdapter({
|
|
614
|
+
fields: { value: (p, cache) => {
|
|
615
|
+
const value = p.value;
|
|
616
|
+
return value instanceof Node ? toLessNode(value, { cache }) : value;
|
|
617
|
+
} },
|
|
618
|
+
accept: selfVisitAccept()
|
|
619
|
+
});
|
|
620
|
+
//#endregion
|
|
621
|
+
//#region src/nodes/negative.ts
|
|
622
|
+
const transformNegativeToLess = createFromAdapter({
|
|
623
|
+
fields: { value: (n, cache) => {
|
|
624
|
+
const value = n.value;
|
|
625
|
+
return value instanceof Node ? toLessNode(value, { cache }) : value;
|
|
626
|
+
} },
|
|
627
|
+
accept: selfVisitAccept()
|
|
628
|
+
});
|
|
629
|
+
//#endregion
|
|
630
|
+
//#region src/nodes/list.ts
|
|
631
|
+
function getFilteredValue(list, cache) {
|
|
632
|
+
const data = list.value;
|
|
633
|
+
if (Array.isArray(data)) return data.map((item) => {
|
|
634
|
+
if (!item) return null;
|
|
635
|
+
if (item instanceof Node) return toLessNode(item, { cache }) || null;
|
|
636
|
+
return item;
|
|
637
|
+
}).filter((item) => item != null);
|
|
638
|
+
if (data != null) {
|
|
639
|
+
if (data && typeof data === "object" && "type" in data) {
|
|
640
|
+
const lessValue = toLessNode(data, { cache });
|
|
641
|
+
return lessValue ? [lessValue] : [];
|
|
642
|
+
}
|
|
643
|
+
return [data];
|
|
644
|
+
}
|
|
645
|
+
return [];
|
|
646
|
+
}
|
|
647
|
+
const transformListToLess = createFromAdapter({
|
|
648
|
+
fields: {
|
|
649
|
+
value: (l, cache) => getFilteredValue(l, cache),
|
|
650
|
+
length: (l, cache) => getFilteredValue(l, cache).length
|
|
651
|
+
},
|
|
652
|
+
accept: (list, visitor, cache) => {
|
|
653
|
+
const value = list.value;
|
|
654
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
655
|
+
const lessItems = value.map((item) => item instanceof Node ? toLessNode(item, { cache }) : item).filter((item) => item != null);
|
|
656
|
+
if (lessItems.length > 0) {
|
|
657
|
+
if (visitor.visitArray) visitor.visitArray(lessItems);
|
|
658
|
+
else for (const li of lessItems) if (li?.accept) li.accept(visitor);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return list;
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region src/nodes/var-declaration.ts
|
|
666
|
+
const transformVarDeclarationToLess = createFromAdapter({
|
|
667
|
+
fields: {
|
|
668
|
+
name: {
|
|
669
|
+
get: (v) => v.name,
|
|
670
|
+
set: (v, value) => {
|
|
671
|
+
v.name = value instanceof Interpolated ? value : String(value);
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
value: {
|
|
675
|
+
get: (v, cache) => {
|
|
676
|
+
const value = v.value;
|
|
677
|
+
return value instanceof Node ? toLessNode(value, { cache }) : value;
|
|
678
|
+
},
|
|
679
|
+
set: (v, value) => {
|
|
680
|
+
const node = value instanceof Node ? value : fromLessNode(value);
|
|
681
|
+
v.adopt(node);
|
|
682
|
+
v.value = node;
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
index: (v) => sourceSpanOf(v)?.start
|
|
686
|
+
},
|
|
687
|
+
accept: singleChildAccept((v) => {
|
|
688
|
+
const value = v.value;
|
|
689
|
+
return value instanceof Node ? value : void 0;
|
|
690
|
+
})
|
|
691
|
+
});
|
|
692
|
+
//#endregion
|
|
693
|
+
//#region src/nodes/keyword.ts
|
|
694
|
+
const transformKeywordToLess = createFromAdapter({
|
|
695
|
+
fields: { value: (k) => k.value },
|
|
696
|
+
accept: selfVisitAccept()
|
|
697
|
+
});
|
|
698
|
+
//#endregion
|
|
699
|
+
//#region src/nodes/combinator.ts
|
|
700
|
+
const transformCombinatorToLess = createFromAdapter({ fields: { value: (c) => c.value } });
|
|
701
|
+
//#endregion
|
|
702
|
+
//#region src/nodes/attribute-selector.ts
|
|
703
|
+
const transformAttributeSelectorToLess = createFromAdapter({
|
|
704
|
+
fields: {
|
|
705
|
+
key: (a, cache) => {
|
|
706
|
+
const name = a.name;
|
|
707
|
+
return name instanceof Node ? toLessNode(name, { cache }) : name;
|
|
708
|
+
},
|
|
709
|
+
op: (a) => a.op || "",
|
|
710
|
+
value: (a, cache) => {
|
|
711
|
+
const value = a.attributeValue;
|
|
712
|
+
return value instanceof Node ? toLessNode(value, { cache }) : value;
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
accept: selfVisitAccept()
|
|
716
|
+
});
|
|
717
|
+
//#endregion
|
|
718
|
+
//#region src/nodes/call.ts
|
|
719
|
+
const transformCallToLess = createFromAdapter({
|
|
720
|
+
fields: {
|
|
721
|
+
name: (c) => c.name,
|
|
722
|
+
args: (c, cache) => {
|
|
723
|
+
const args = c.args;
|
|
724
|
+
if (!args) return [];
|
|
725
|
+
return args.value.map((arg) => arg instanceof Node ? toLessNode(arg, { cache }) : arg);
|
|
726
|
+
},
|
|
727
|
+
index: (c) => sourceSpanOf(c)?.start
|
|
728
|
+
},
|
|
729
|
+
accept: childrenAccept((c) => {
|
|
730
|
+
const argsValue = c.args?.value;
|
|
731
|
+
return argsValue?.length ? argsValue.filter((a) => a instanceof Node) : [];
|
|
732
|
+
})
|
|
733
|
+
});
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/nodes/reference.ts
|
|
736
|
+
const transformReferenceToLess = createFromAdapter({
|
|
737
|
+
lessType: (ref) => {
|
|
738
|
+
const refType = ref.options?.type || "variable";
|
|
739
|
+
if (refType === "property") return "Property";
|
|
740
|
+
if (refType === "function" || refType === "mixin") return "VariableCall";
|
|
741
|
+
return "Variable";
|
|
742
|
+
},
|
|
743
|
+
fields: {
|
|
744
|
+
name: (ref) => {
|
|
745
|
+
const refType = ref.options?.type || "variable";
|
|
746
|
+
const lessType = refType === "property" ? "Property" : refType === "function" || refType === "mixin" ? "VariableCall" : "Variable";
|
|
747
|
+
const key = ref.key;
|
|
748
|
+
if (typeof key === "string") {
|
|
749
|
+
if (lessType === "Variable" && !key.startsWith("@")) return `@${key}`;
|
|
750
|
+
return key;
|
|
751
|
+
}
|
|
752
|
+
return String(key);
|
|
753
|
+
},
|
|
754
|
+
value: (ref) => {
|
|
755
|
+
const refType = ref.options?.type || "variable";
|
|
756
|
+
if (refType === "function" || refType === "mixin") return ref;
|
|
757
|
+
},
|
|
758
|
+
index: (ref) => sourceSpanOf(ref)?.start,
|
|
759
|
+
currentFileInfo: () => ({})
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
//#endregion
|
|
763
|
+
//#region src/nodes/index.ts
|
|
764
|
+
function isRuleset(node) {
|
|
765
|
+
return node.type === "Ruleset";
|
|
766
|
+
}
|
|
767
|
+
function isDeclaration(node) {
|
|
768
|
+
return node.type === "Declaration";
|
|
769
|
+
}
|
|
770
|
+
function isMixin(node) {
|
|
771
|
+
return node.type === "Mixin";
|
|
772
|
+
}
|
|
773
|
+
function isDimension(node) {
|
|
774
|
+
return node.type === "Dimension";
|
|
775
|
+
}
|
|
776
|
+
function isNum(node) {
|
|
777
|
+
return node.type === "Num";
|
|
778
|
+
}
|
|
779
|
+
function isColor(node) {
|
|
780
|
+
return node.type === "Color";
|
|
781
|
+
}
|
|
782
|
+
function isOperation(node) {
|
|
783
|
+
return node.type === "Operation";
|
|
784
|
+
}
|
|
785
|
+
function isExpression(node) {
|
|
786
|
+
return node.type === "Expression";
|
|
787
|
+
}
|
|
788
|
+
function isSequence(node) {
|
|
789
|
+
return node.type === "Sequence";
|
|
790
|
+
}
|
|
791
|
+
function isQuoted(node) {
|
|
792
|
+
return node.type === "Quoted";
|
|
793
|
+
}
|
|
794
|
+
function isUrl(node) {
|
|
795
|
+
return node.type === "Url";
|
|
796
|
+
}
|
|
797
|
+
function isComment(node) {
|
|
798
|
+
return node.type === "Comment";
|
|
799
|
+
}
|
|
800
|
+
function isAtRule(node) {
|
|
801
|
+
return node.type === "AtRule";
|
|
802
|
+
}
|
|
803
|
+
function isStyleImport(node) {
|
|
804
|
+
return node.type === "StyleImport";
|
|
805
|
+
}
|
|
806
|
+
function isExtend(node) {
|
|
807
|
+
return node.type === "Extend";
|
|
808
|
+
}
|
|
809
|
+
function isCondition(node) {
|
|
810
|
+
return node.type === "Condition";
|
|
811
|
+
}
|
|
812
|
+
function isParen(node) {
|
|
813
|
+
return node.type === "Paren";
|
|
814
|
+
}
|
|
815
|
+
function isNegative(node) {
|
|
816
|
+
return node.type === "Negative";
|
|
817
|
+
}
|
|
818
|
+
function isList(node) {
|
|
819
|
+
return node.type === "List";
|
|
820
|
+
}
|
|
821
|
+
function isVarDeclaration(node) {
|
|
822
|
+
return node.type === "VarDeclaration";
|
|
823
|
+
}
|
|
824
|
+
function isKeyword(node) {
|
|
825
|
+
return node.type === "Keyword";
|
|
826
|
+
}
|
|
827
|
+
function isCombinator(node) {
|
|
828
|
+
return node.type === "Combinator";
|
|
829
|
+
}
|
|
830
|
+
function isAttributeSelector(node) {
|
|
831
|
+
return node.type === "AttributeSelector";
|
|
832
|
+
}
|
|
833
|
+
function isCall(node) {
|
|
834
|
+
return node.type === "Call";
|
|
835
|
+
}
|
|
836
|
+
function isSelector(node) {
|
|
837
|
+
return node.type === "SelectorList" || node.type === "ComplexSelector" || node.type === "CompoundSelector" || node.type === "BasicSelector";
|
|
838
|
+
}
|
|
839
|
+
function isReference(node) {
|
|
840
|
+
return node.type === "Reference";
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Registry of node transformers
|
|
844
|
+
*/
|
|
845
|
+
const transformers = /* @__PURE__ */ new Map();
|
|
846
|
+
transformers.set("Ruleset", (node, cache) => {
|
|
847
|
+
if (isRuleset(node)) return transformRulesetToLess(node, cache);
|
|
848
|
+
throw new Error(`Expected Ruleset node, got ${node.type}`);
|
|
849
|
+
});
|
|
850
|
+
transformers.set("Declaration", (node, cache) => {
|
|
851
|
+
if (isDeclaration(node)) return transformDeclarationToLess(node, cache);
|
|
852
|
+
throw new Error(`Expected Declaration node, got ${node.type}`);
|
|
853
|
+
});
|
|
854
|
+
transformers.set("Mixin", (node, cache) => {
|
|
855
|
+
if (isMixin(node)) return transformMixinToLess(node, cache);
|
|
856
|
+
throw new Error(`Expected Mixin node, got ${node.type}`);
|
|
857
|
+
});
|
|
858
|
+
transformers.set("Dimension", (node, cache) => {
|
|
859
|
+
if (isDimension(node)) return transformDimensionToLess(node, cache);
|
|
860
|
+
throw new Error(`Expected Dimension node, got ${node.type}`);
|
|
861
|
+
});
|
|
862
|
+
transformers.set("Num", (node, cache) => {
|
|
863
|
+
if (isNum(node)) return transformDimensionToLess(node, cache);
|
|
864
|
+
throw new Error(`Expected Num node, got ${node.type}`);
|
|
865
|
+
});
|
|
866
|
+
transformers.set("Color", (node, cache) => {
|
|
867
|
+
if (isColor(node)) return transformColorToLess(node, cache);
|
|
868
|
+
throw new Error(`Expected Color node, got ${node.type}`);
|
|
869
|
+
});
|
|
870
|
+
transformers.set("Operation", (node, cache) => {
|
|
871
|
+
if (isOperation(node)) return transformOperationToLess(node, cache);
|
|
872
|
+
throw new Error(`Expected Operation node, got ${node.type}`);
|
|
873
|
+
});
|
|
874
|
+
transformers.set("Expression", (node, cache) => {
|
|
875
|
+
if (isExpression(node)) return transformExpressionToLess(node, cache);
|
|
876
|
+
throw new Error(`Expected Expression node, got ${node.type}`);
|
|
877
|
+
});
|
|
878
|
+
transformers.set("Sequence", (node, cache) => {
|
|
879
|
+
if (isSequence(node)) return transformSequenceToLess(node, cache);
|
|
880
|
+
throw new Error(`Expected Sequence node, got ${node.type}`);
|
|
881
|
+
});
|
|
882
|
+
transformers.set("Quoted", (node, cache) => {
|
|
883
|
+
if (isQuoted(node)) return transformQuotedToLess(node, cache);
|
|
884
|
+
throw new Error(`Expected Quoted node, got ${node.type}`);
|
|
885
|
+
});
|
|
886
|
+
transformers.set("Url", (node, cache) => {
|
|
887
|
+
if (isUrl(node)) return transformUrlToLess(node, cache);
|
|
888
|
+
throw new Error(`Expected Url node, got ${node.type}`);
|
|
889
|
+
});
|
|
890
|
+
transformers.set("Comment", (node, cache) => {
|
|
891
|
+
if (isComment(node)) return transformCommentToLess(node, cache);
|
|
892
|
+
throw new Error(`Expected Comment node, got ${node.type}`);
|
|
893
|
+
});
|
|
894
|
+
transformers.set("AtRule", (node, cache) => {
|
|
895
|
+
if (isAtRule(node)) return transformAtRuleToLess(node, cache);
|
|
896
|
+
throw new Error(`Expected AtRule node, got ${node.type}`);
|
|
897
|
+
});
|
|
898
|
+
transformers.set("StyleImport", (node, cache) => {
|
|
899
|
+
if (isStyleImport(node)) return transformImportToLess(node, cache);
|
|
900
|
+
throw new Error(`Expected StyleImport node, got ${node.type}`);
|
|
901
|
+
});
|
|
902
|
+
transformers.set("Extend", (node, cache) => {
|
|
903
|
+
if (isExtend(node)) return transformExtendToLess(node, cache);
|
|
904
|
+
throw new Error(`Expected Extend node, got ${node.type}`);
|
|
905
|
+
});
|
|
906
|
+
transformers.set("Condition", (node, cache) => {
|
|
907
|
+
if (isCondition(node)) return transformConditionToLess(node, cache);
|
|
908
|
+
throw new Error(`Expected Condition node, got ${node.type}`);
|
|
909
|
+
});
|
|
910
|
+
transformers.set("Paren", (node, cache) => {
|
|
911
|
+
if (isParen(node)) return transformParenToLess(node, cache);
|
|
912
|
+
throw new Error(`Expected Paren node, got ${node.type}`);
|
|
913
|
+
});
|
|
914
|
+
transformers.set("Negative", (node, cache) => {
|
|
915
|
+
if (isNegative(node)) return transformNegativeToLess(node, cache);
|
|
916
|
+
throw new Error(`Expected Negative node, got ${node.type}`);
|
|
917
|
+
});
|
|
918
|
+
transformers.set("List", (node, cache) => {
|
|
919
|
+
if (isList(node)) return transformListToLess(node, cache);
|
|
920
|
+
throw new Error(`Expected List node, got ${node.type}`);
|
|
921
|
+
});
|
|
922
|
+
transformers.set("VarDeclaration", (node, cache) => {
|
|
923
|
+
if (isVarDeclaration(node)) return transformVarDeclarationToLess(node, cache);
|
|
924
|
+
throw new Error(`Expected VarDeclaration node, got ${node.type}`);
|
|
925
|
+
});
|
|
926
|
+
transformers.set("Keyword", (node, cache) => {
|
|
927
|
+
if (isKeyword(node)) return transformKeywordToLess(node, cache);
|
|
928
|
+
throw new Error(`Expected Keyword node, got ${node.type}`);
|
|
929
|
+
});
|
|
930
|
+
transformers.set("Combinator", (node, cache) => {
|
|
931
|
+
if (isCombinator(node)) return transformCombinatorToLess(node, cache);
|
|
932
|
+
throw new Error(`Expected Combinator node, got ${node.type}`);
|
|
933
|
+
});
|
|
934
|
+
transformers.set("AttributeSelector", (node, cache) => {
|
|
935
|
+
if (isAttributeSelector(node)) return transformAttributeSelectorToLess(node, cache);
|
|
936
|
+
throw new Error(`Expected AttributeSelector node, got ${node.type}`);
|
|
937
|
+
});
|
|
938
|
+
transformers.set("Call", (node, cache) => {
|
|
939
|
+
if (isCall(node)) return transformCallToLess(node, cache);
|
|
940
|
+
throw new Error(`Expected Call node, got ${node.type}`);
|
|
941
|
+
});
|
|
942
|
+
transformers.set("SelectorList", (node, cache) => {
|
|
943
|
+
if (isSelector(node)) return transformSelectorToLess(node, cache);
|
|
944
|
+
throw new Error(`Expected Selector node, got ${node.type}`);
|
|
945
|
+
});
|
|
946
|
+
transformers.set("ComplexSelector", (node, cache) => {
|
|
947
|
+
if (isSelector(node)) return transformSelectorToLess(node, cache);
|
|
948
|
+
throw new Error(`Expected Selector node, got ${node.type}`);
|
|
949
|
+
});
|
|
950
|
+
transformers.set("CompoundSelector", (node, cache) => {
|
|
951
|
+
if (isSelector(node)) return transformSelectorToLess(node, cache);
|
|
952
|
+
throw new Error(`Expected Selector node, got ${node.type}`);
|
|
953
|
+
});
|
|
954
|
+
transformers.set("BasicSelector", (node, cache) => {
|
|
955
|
+
if (isSelector(node)) return transformSelectorToLess(node, cache);
|
|
956
|
+
throw new Error(`Expected Selector node, got ${node.type}`);
|
|
957
|
+
});
|
|
958
|
+
transformers.set("Reference", (node, cache) => {
|
|
959
|
+
if (isReference(node)) return transformReferenceToLess(node, cache);
|
|
960
|
+
throw new Error(`Expected Reference node, got ${node.type}`);
|
|
961
|
+
});
|
|
962
|
+
/**
|
|
963
|
+
* Get the transformer for a Jess node type
|
|
964
|
+
*/
|
|
965
|
+
function getTransformer(nodeType) {
|
|
966
|
+
return transformers.get(nodeType);
|
|
967
|
+
}
|
|
968
|
+
//#endregion
|
|
969
|
+
//#region src/transform/to-less.ts
|
|
970
|
+
/**
|
|
971
|
+
* Convert a Jess node to a Less-compatible adapter
|
|
972
|
+
*
|
|
973
|
+
* @param jessNode - The Jess node to convert
|
|
974
|
+
* @param options - Conversion options
|
|
975
|
+
* @returns A Less-compatible adapter node
|
|
976
|
+
*/
|
|
977
|
+
function toLessNode(jessNode, options) {
|
|
978
|
+
if (!jessNode) return jessNode;
|
|
979
|
+
const cache = options?.cache || /* @__PURE__ */ new WeakMap();
|
|
980
|
+
if (cache.has(jessNode)) return cache.get(jessNode);
|
|
981
|
+
if (isAdaptingNode(jessNode)) return jessNode;
|
|
982
|
+
const transformer = getTransformer(jessNode.type);
|
|
983
|
+
if (transformer) return transformer(jessNode, cache);
|
|
984
|
+
return createLessAdapter(jessNode, {
|
|
985
|
+
lessType: mapJessTypeToLessType(jessNode.type),
|
|
986
|
+
fields: { value: (target) => {
|
|
987
|
+
if (!("value" in target) || target.value === void 0) return;
|
|
988
|
+
const nodeValue = target.value;
|
|
989
|
+
if (nodeValue instanceof Node) return toLessNode(nodeValue, options);
|
|
990
|
+
if (Array.isArray(nodeValue)) return nodeValue.map((item) => item instanceof Node ? toLessNode(item, options) : item);
|
|
991
|
+
if (typeof nodeValue === "object" && nodeValue !== null) {
|
|
992
|
+
const converted = {};
|
|
993
|
+
for (const [key, val] of Object.entries(nodeValue)) if (val instanceof Node) converted[key] = toLessNode(val, options);
|
|
994
|
+
else if (Array.isArray(val)) converted[key] = val.map((item) => item instanceof Node ? toLessNode(item, options) : item);
|
|
995
|
+
else converted[key] = val;
|
|
996
|
+
return converted;
|
|
997
|
+
}
|
|
998
|
+
return nodeValue;
|
|
999
|
+
} },
|
|
1000
|
+
accept: (target) => target
|
|
1001
|
+
}, cache);
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Convert an entire Jess Rules tree to Less-compatible format
|
|
1005
|
+
*
|
|
1006
|
+
* @param jessRules - The Jess Rules tree to convert
|
|
1007
|
+
* @param options - Conversion options
|
|
1008
|
+
* @returns A Less-compatible tree
|
|
1009
|
+
*/
|
|
1010
|
+
function toLessTree(jessRules, options) {
|
|
1011
|
+
if (jessRules instanceof Rules) return toLessNode(jessRules, options);
|
|
1012
|
+
return toLessNode(jessRules, options);
|
|
1013
|
+
}
|
|
1014
|
+
//#endregion
|
|
1015
|
+
export { fromLessTree as a, fromLessPluginReturnValue as i, toLessTree as n, fromLessNode as r, toLessNode as t };
|