@jesscss/plugin-less 2.0.0-alpha.10 → 2.0.0-alpha.11

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/lib/index.cjs CHANGED
@@ -50,6 +50,107 @@ const lessPluginDefaults = {
50
50
  collapseNesting: false
51
51
  };
52
52
  const lessValueEvaluator = (0, _jesscss_core.buildEvaluator)((0, _jesscss_fns_less_registry.makeLessRegistry)());
53
+ function stableStringify(value) {
54
+ if (value == null || typeof value !== "object") return JSON.stringify(value);
55
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
56
+ if (!isObjectRecord(value)) return JSON.stringify(value);
57
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(",")}}`;
58
+ }
59
+ function isObjectRecord(value) {
60
+ return value != null && typeof value === "object" && !Array.isArray(value);
61
+ }
62
+ function isPluginInterface(value) {
63
+ return isObjectRecord(value) && typeof value.name === "string";
64
+ }
65
+ function normalizeVariableName(name) {
66
+ return name.startsWith("@") ? name : `@${name}`;
67
+ }
68
+ function renderVariableOverrides(vars) {
69
+ if (!vars) return "";
70
+ return Object.entries(vars).map(([name, value]) => `${normalizeVariableName(name)}: ${String(value)};`).join("\n");
71
+ }
72
+ function getVariableOverrides(value) {
73
+ return isObjectRecord(value) ? value : null;
74
+ }
75
+ function cloneConfiguredPlugin(plugin) {
76
+ if (plugin.name !== "less-compat" || typeof plugin.constructor !== "function") return plugin;
77
+ try {
78
+ const opts = isObjectRecord(plugin) ? plugin.opts : void 0;
79
+ const freshPlugin = Reflect.construct(plugin.constructor, [opts]);
80
+ return isPluginInterface(freshPlugin) ? freshPlugin : plugin;
81
+ } catch {
82
+ return plugin;
83
+ }
84
+ }
85
+ function prepareLessRootSource(source, context) {
86
+ if (context.language !== void 0 && context.language !== "less") return source;
87
+ return [
88
+ [typeof context.activeOptions.banner === "string" ? context.activeOptions.banner : void 0, renderVariableOverrides(getVariableOverrides(context.activeOptions.globalVars))].filter(Boolean).join("\n"),
89
+ source,
90
+ renderVariableOverrides(getVariableOverrides(context.activeOptions.modifyVars))
91
+ ].filter(Boolean).join("\n");
92
+ }
93
+ var LessPluginResolver = class {
94
+ pluginInstanceCache = /* @__PURE__ */ new Map();
95
+ nativePluginIds = /* @__PURE__ */ new Map();
96
+ nextNativePluginId = 0;
97
+ getCacheKey(lessOptions, nativePlugins = []) {
98
+ const optionsKey = stableStringify({
99
+ math: lessOptions.math,
100
+ mathMode: lessOptions.mathMode,
101
+ strictUnits: lessOptions.strictUnits,
102
+ unitMode: lessOptions.unitMode,
103
+ equalityMode: lessOptions.equalityMode,
104
+ allowExtendSelectors: lessOptions.allowExtendSelectors,
105
+ leakyScope: lessOptions.leakyScope,
106
+ bubbleRootAtRules: lessOptions.bubbleRootAtRules,
107
+ collapseNesting: lessOptions.collapseNesting,
108
+ rootpath: lessOptions.rootpath,
109
+ rewriteUrls: lessOptions.rewriteUrls,
110
+ urlArgs: lessOptions.urlArgs,
111
+ processImports: lessOptions.processImports
112
+ });
113
+ if (nativePlugins.length === 0) return optionsKey;
114
+ return `${optionsKey}|native-plugins:${nativePlugins.map((plugin) => {
115
+ let id = this.nativePluginIds.get(plugin);
116
+ if (id === void 0) {
117
+ id = ++this.nextNativePluginId;
118
+ this.nativePluginIds.set(plugin, id);
119
+ }
120
+ return id;
121
+ }).join(",")}`;
122
+ }
123
+ getOrCreate(lessOptions, nativePlugins = []) {
124
+ const key = this.getCacheKey(lessOptions, nativePlugins);
125
+ let plugin = this.pluginInstanceCache.get(key);
126
+ if (!plugin) {
127
+ plugin = lessPlugin({
128
+ ...lessOptions,
129
+ ...nativePlugins.length === 0 ? {} : { plugins: nativePlugins }
130
+ });
131
+ this.pluginInstanceCache.set(key, plugin);
132
+ }
133
+ return plugin;
134
+ }
135
+ normalizeConfiguredPlugin(plugin, context) {
136
+ if (plugin.name !== "less") return cloneConfiguredPlugin(plugin);
137
+ const pluginOptions = isObjectRecord(plugin) && isObjectRecord(plugin.opts) ? plugin.opts : {};
138
+ const resolvedLessOptions = Object.fromEntries(Object.entries(context.optionsFor("less")).filter(([, value]) => value !== void 0));
139
+ const nativePlugins = Array.isArray(pluginOptions.plugins) ? pluginOptions.plugins : [];
140
+ return this.getOrCreate({
141
+ ...pluginOptions,
142
+ ...resolvedLessOptions
143
+ }, nativePlugins);
144
+ }
145
+ dispose() {
146
+ for (const plugin of this.pluginInstanceCache.values()) try {
147
+ plugin.dispose?.();
148
+ } catch {}
149
+ this.pluginInstanceCache.clear();
150
+ this.nativePluginIds.clear();
151
+ this.nextNativePluginId = 0;
152
+ }
153
+ };
53
154
  /** Match Less's URL normalization without treating URL text as an import path. */
54
155
  function normalizeUrlPath(url) {
55
156
  const segments = url.split("/");
@@ -233,5 +334,7 @@ const lessPlugin = ((opts) => {
233
334
  });
234
335
  //#endregion
235
336
  exports.LessPlugin = LessPlugin;
337
+ exports.LessPluginResolver = LessPluginResolver;
236
338
  exports.default = lessPlugin;
237
339
  exports.lessPluginDefaults = lessPluginDefaults;
340
+ exports.prepareLessRootSource = prepareLessRootSource;
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AbstractPlugin, Context, type UrlTransformRequest, type ISafeParseResult, type SafeParseOptions } from '@jesscss/core';
1
+ import { AbstractPlugin, Context, type UrlTransformRequest, type ISafeParseResult, type SafeParseOptions, type PluginInterface } from '@jesscss/core';
2
2
  import type { EqualityMode, MathMode, UnitMode, LessOptions } from 'styles-config';
3
3
  export type LessPluginOptions = LessOptions;
4
4
  /**
@@ -17,6 +17,23 @@ export declare const lessPluginDefaults: {
17
17
  readonly processImports: true;
18
18
  readonly collapseNesting: false;
19
19
  };
20
+ export type LessSourcePreparationContext = {
21
+ language?: string;
22
+ activeOptions: Record<string, unknown>;
23
+ };
24
+ export type LessPluginResolverContext = {
25
+ optionsFor(language?: string): Record<string, unknown>;
26
+ };
27
+ export declare function prepareLessRootSource(source: string, context: LessSourcePreparationContext): string;
28
+ export declare class LessPluginResolver {
29
+ private pluginInstanceCache;
30
+ private nativePluginIds;
31
+ private nextNativePluginId;
32
+ private getCacheKey;
33
+ getOrCreate(lessOptions: Record<string, unknown>, nativePlugins?: readonly unknown[]): PluginInterface;
34
+ normalizeConfiguredPlugin(plugin: PluginInterface, context: LessPluginResolverContext): PluginInterface;
35
+ dispose(): void;
36
+ }
20
37
  export declare class LessPlugin extends AbstractPlugin {
21
38
  opts: LessPluginOptions;
22
39
  name: string;
package/lib/index.js CHANGED
@@ -23,6 +23,107 @@ const lessPluginDefaults = {
23
23
  collapseNesting: false
24
24
  };
25
25
  const lessValueEvaluator = buildEvaluator(makeLessRegistry());
26
+ function stableStringify(value) {
27
+ if (value == null || typeof value !== "object") return JSON.stringify(value);
28
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
29
+ if (!isObjectRecord(value)) return JSON.stringify(value);
30
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(",")}}`;
31
+ }
32
+ function isObjectRecord(value) {
33
+ return value != null && typeof value === "object" && !Array.isArray(value);
34
+ }
35
+ function isPluginInterface(value) {
36
+ return isObjectRecord(value) && typeof value.name === "string";
37
+ }
38
+ function normalizeVariableName(name) {
39
+ return name.startsWith("@") ? name : `@${name}`;
40
+ }
41
+ function renderVariableOverrides(vars) {
42
+ if (!vars) return "";
43
+ return Object.entries(vars).map(([name, value]) => `${normalizeVariableName(name)}: ${String(value)};`).join("\n");
44
+ }
45
+ function getVariableOverrides(value) {
46
+ return isObjectRecord(value) ? value : null;
47
+ }
48
+ function cloneConfiguredPlugin(plugin) {
49
+ if (plugin.name !== "less-compat" || typeof plugin.constructor !== "function") return plugin;
50
+ try {
51
+ const opts = isObjectRecord(plugin) ? plugin.opts : void 0;
52
+ const freshPlugin = Reflect.construct(plugin.constructor, [opts]);
53
+ return isPluginInterface(freshPlugin) ? freshPlugin : plugin;
54
+ } catch {
55
+ return plugin;
56
+ }
57
+ }
58
+ function prepareLessRootSource(source, context) {
59
+ if (context.language !== void 0 && context.language !== "less") return source;
60
+ return [
61
+ [typeof context.activeOptions.banner === "string" ? context.activeOptions.banner : void 0, renderVariableOverrides(getVariableOverrides(context.activeOptions.globalVars))].filter(Boolean).join("\n"),
62
+ source,
63
+ renderVariableOverrides(getVariableOverrides(context.activeOptions.modifyVars))
64
+ ].filter(Boolean).join("\n");
65
+ }
66
+ var LessPluginResolver = class {
67
+ pluginInstanceCache = /* @__PURE__ */ new Map();
68
+ nativePluginIds = /* @__PURE__ */ new Map();
69
+ nextNativePluginId = 0;
70
+ getCacheKey(lessOptions, nativePlugins = []) {
71
+ const optionsKey = stableStringify({
72
+ math: lessOptions.math,
73
+ mathMode: lessOptions.mathMode,
74
+ strictUnits: lessOptions.strictUnits,
75
+ unitMode: lessOptions.unitMode,
76
+ equalityMode: lessOptions.equalityMode,
77
+ allowExtendSelectors: lessOptions.allowExtendSelectors,
78
+ leakyScope: lessOptions.leakyScope,
79
+ bubbleRootAtRules: lessOptions.bubbleRootAtRules,
80
+ collapseNesting: lessOptions.collapseNesting,
81
+ rootpath: lessOptions.rootpath,
82
+ rewriteUrls: lessOptions.rewriteUrls,
83
+ urlArgs: lessOptions.urlArgs,
84
+ processImports: lessOptions.processImports
85
+ });
86
+ if (nativePlugins.length === 0) return optionsKey;
87
+ return `${optionsKey}|native-plugins:${nativePlugins.map((plugin) => {
88
+ let id = this.nativePluginIds.get(plugin);
89
+ if (id === void 0) {
90
+ id = ++this.nextNativePluginId;
91
+ this.nativePluginIds.set(plugin, id);
92
+ }
93
+ return id;
94
+ }).join(",")}`;
95
+ }
96
+ getOrCreate(lessOptions, nativePlugins = []) {
97
+ const key = this.getCacheKey(lessOptions, nativePlugins);
98
+ let plugin = this.pluginInstanceCache.get(key);
99
+ if (!plugin) {
100
+ plugin = lessPlugin({
101
+ ...lessOptions,
102
+ ...nativePlugins.length === 0 ? {} : { plugins: nativePlugins }
103
+ });
104
+ this.pluginInstanceCache.set(key, plugin);
105
+ }
106
+ return plugin;
107
+ }
108
+ normalizeConfiguredPlugin(plugin, context) {
109
+ if (plugin.name !== "less") return cloneConfiguredPlugin(plugin);
110
+ const pluginOptions = isObjectRecord(plugin) && isObjectRecord(plugin.opts) ? plugin.opts : {};
111
+ const resolvedLessOptions = Object.fromEntries(Object.entries(context.optionsFor("less")).filter(([, value]) => value !== void 0));
112
+ const nativePlugins = Array.isArray(pluginOptions.plugins) ? pluginOptions.plugins : [];
113
+ return this.getOrCreate({
114
+ ...pluginOptions,
115
+ ...resolvedLessOptions
116
+ }, nativePlugins);
117
+ }
118
+ dispose() {
119
+ for (const plugin of this.pluginInstanceCache.values()) try {
120
+ plugin.dispose?.();
121
+ } catch {}
122
+ this.pluginInstanceCache.clear();
123
+ this.nativePluginIds.clear();
124
+ this.nextNativePluginId = 0;
125
+ }
126
+ };
26
127
  /** Match Less's URL normalization without treating URL text as an import path. */
27
128
  function normalizeUrlPath(url) {
28
129
  const segments = url.split("/");
@@ -205,4 +306,4 @@ const lessPlugin = ((opts) => {
205
306
  return new LessPlugin(opts);
206
307
  });
207
308
  //#endregion
208
- export { LessPlugin, lessPlugin as default, lessPluginDefaults };
309
+ export { LessPlugin, LessPluginResolver, lessPlugin as default, lessPluginDefaults, prepareLessRootSource };
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "access": "public"
6
6
  },
7
7
  "description": "A Less stylesheet engine for Jess",
8
- "version": "2.0.0-alpha.10",
8
+ "version": "2.0.0-alpha.11",
9
9
  "engines": {
10
10
  "node": "^20.19.0 || >=22.12.0"
11
11
  },
@@ -23,12 +23,12 @@
23
23
  "lib"
24
24
  ],
25
25
  "dependencies": {
26
- "@jesscss/fns": "2.0.0-alpha.10",
27
- "@jesscss/less-parser": "2.0.0-alpha.10",
28
- "@jesscss/plugin-less-compat": "2.0.0-alpha.10",
29
- "@jesscss/core": "2.0.0-alpha.10",
30
- "@jesscss/style-resolver": "2.0.0-alpha.10",
31
- "styles-config": "2.0.0-alpha.10"
26
+ "@jesscss/fns": "2.0.0-alpha.11",
27
+ "@jesscss/core": "2.0.0-alpha.11",
28
+ "@jesscss/plugin-less-compat": "2.0.0-alpha.11",
29
+ "@jesscss/less-parser": "2.0.0-alpha.11",
30
+ "@jesscss/style-resolver": "2.0.0-alpha.11",
31
+ "styles-config": "2.0.0-alpha.11"
32
32
  },
33
33
  "devDependencies": {},
34
34
  "author": "Matthew Dean <matthew-dean@users.noreply.github.com>",