less 5.0.0-alpha.6 → 5.0.0-alpha.8

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Less - Leaner CSS v5.0.0-alpha.6
2
+ * Less - Leaner CSS v5.0.0-alpha.8
3
3
  * http://lesscss.org
4
4
  *
5
5
  * Copyright (c) 2009-2026, Alexis Sellier <self@cloudhead.net>
@@ -105,19 +105,9 @@ const logger = {
105
105
  */
106
106
 
107
107
  const unsupportedAlphaOptions = new Map([
108
- ['sourceMap', 'source maps are not supported'],
109
- ['sourceMapFilename', 'source maps are not supported'],
110
- ['sourceMapRootpath', 'source maps are not supported'],
111
- ['sourceMapBasepath', 'source maps are not supported'],
112
- ['sourceMapURL', 'source maps are not supported'],
113
- ['sourceMapFileInline', 'source maps are not supported'],
114
108
  ['globalVars', 'global variable injection is not supported'],
115
109
  ['modifyVars', 'modify-var injection is not supported'],
116
- ['rootpath', 'URL rootpath rewriting is not supported'],
117
- ['rewriteUrls', 'URL rewriting is not supported'],
118
- ['urlArgs', 'URL argument rewriting is not supported'],
119
110
  ['javascriptEnabled', 'JavaScript evaluation is not supported'],
120
- ['compress', 'compressed output is not supported'],
121
111
  ]);
122
112
 
123
113
  function validateAlphaOptions(options) {
@@ -161,6 +151,55 @@ function stableStringify(value, seen = new WeakSet()) {
161
151
  return `{${entries.join(',')}}`;
162
152
  }
163
153
 
154
+ /**
155
+ * `collapseNesting` accepts `false` (keep authored nesting — the v5 default),
156
+ * `'native'` (CSS Nesting desugaring: parent wrapped in `:is()`, child selector
157
+ * lists distributed, specificity-faithful), `'compact'` (like `'native'` but
158
+ * also folds same-combinator descendant runs into one `:is()`), or the
159
+ * deprecated boolean `true` (alias for `'native'`). Anything else is rejected.
160
+ * @param {unknown} value
161
+ * @returns {boolean|'native'|'compact'}
162
+ */
163
+ function resolveCollapseNesting(value) {
164
+ if (value === false || value === true || value === 'native' || value === 'compact') {
165
+ return value;
166
+ }
167
+ throw new Error(
168
+ `collapseNesting must be false, 'native', 'compact', or true `
169
+ + `(deprecated alias for 'native'); got ${JSON.stringify(value)}`
170
+ );
171
+ }
172
+
173
+ /**
174
+ * Build the compiler's `output.sourceMap` value from Less options. Source maps
175
+ * are enabled when `sourceMap` is truthy; the object form (or the flat legacy
176
+ * `sourceMap*` options) configures the details. Returns `undefined` when no
177
+ * source map is requested.
178
+ * @param {import('./options.js').LessRenderOptions} opts
179
+ * @returns {undefined | true | Record<string, unknown>}
180
+ */
181
+ function resolveSourceMap(opts) {
182
+ if (!opts.sourceMap) {
183
+ return undefined;
184
+ }
185
+ const config = (typeof opts.sourceMap === 'object' && opts.sourceMap !== null)
186
+ ? { ...opts.sourceMap }
187
+ : {};
188
+ // Fold the flat legacy `sourceMap*` options into the object form the compiler
189
+ // reads; an explicit object sub-option wins over its flat alias.
190
+ const flat = [
191
+ 'sourceMapURL', 'sourceMapFilename', 'sourceMapFullFilename',
192
+ 'sourceMapRootpath', 'sourceMapBasepath', 'sourceMapFileInline',
193
+ 'sourceMapOutputFilename', 'outputSourceFiles', 'disableSourcemapAnnotation'
194
+ ];
195
+ for (const key of flat) {
196
+ if (opts[key] !== undefined && config[key] === undefined) {
197
+ config[key] = opts[key];
198
+ }
199
+ }
200
+ return Object.keys(config).length > 0 ? config : true;
201
+ }
202
+
164
203
  /**
165
204
  * Map Less render options to Jess compiler config.
166
205
  * @param {import('./options.js').LessRenderOptions} [options] Less-style options
@@ -195,11 +234,37 @@ function createLessOptions(options) {
195
234
  );
196
235
  }
197
236
 
198
- const plugins = [lessPlugin__default["default"]()];
237
+ // URL rewriting lives on the Less plugin (it rewrites `url(...)` during
238
+ // serialization), not in `output`. Only forward keys the caller set so the
239
+ // plugin's own v5 defaults apply otherwise.
240
+ const lessPluginOptions = {};
241
+ if (opts.rootpath !== undefined) lessPluginOptions.rootpath = opts.rootpath;
242
+ if (opts.rewriteUrls !== undefined) lessPluginOptions.rewriteUrls = opts.rewriteUrls;
243
+ if (opts.urlArgs !== undefined) lessPluginOptions.urlArgs = opts.urlArgs;
244
+
245
+ const plugins = [lessPlugin__default["default"](lessPluginOptions)];
199
246
  if (!skipLessCompat) {
200
247
  plugins.push(pluginLessCompat.lessCompatPlugin({ plugins: lessPlugins }));
201
248
  }
202
249
 
250
+ // The projection/serialization options the compiler reads off `output`:
251
+ // `collapseNesting` (nesting flatten mode), `compress` (minified output), and
252
+ // `sourceMap`. Emitted as a single file-less array entry so an explicit render
253
+ // option overrides a file-local styles.config for every key (the config merge
254
+ // appends it as the override default); left `{}` when the caller set none.
255
+ const outputEntry = {};
256
+ if (opts.collapseNesting !== undefined) {
257
+ outputEntry.collapseNesting = resolveCollapseNesting(opts.collapseNesting);
258
+ }
259
+ if (opts.compress !== undefined) {
260
+ outputEntry.compress = opts.compress;
261
+ }
262
+ const sourceMap = resolveSourceMap(opts);
263
+ if (sourceMap !== undefined) {
264
+ outputEntry.sourceMap = sourceMap;
265
+ }
266
+ const output = Object.keys(outputEntry).length > 0 ? [outputEntry] : {};
267
+
203
268
  const configOptions = {
204
269
  compile: {
205
270
  searchPaths: opts.paths || [],
@@ -207,15 +272,7 @@ function createLessOptions(options) {
207
272
  ...(unitMode !== undefined && { unitMode }),
208
273
  plugins,
209
274
  },
210
- // Less v5 preserves authored nesting unless its explicit compatibility
211
- // switch requests flattened CSS. Keep that public Less option at the
212
- // wrapper boundary; Jess owns the one renderer and its output mode.
213
- // A file's styles.config may use an output array. A file-less output entry
214
- // is the compiler's documented per-render override for that shape, so an
215
- // explicit public Less option remains authoritative over fixture config.
216
- output: Object.prototype.hasOwnProperty.call(opts, 'collapseNesting')
217
- ? [{ collapseNesting: opts.collapseNesting === true }]
218
- : {},
275
+ output,
219
276
  language: {},
220
277
  };
221
278
 
@@ -243,6 +300,13 @@ function mapRenderResult(result, options) {
243
300
  css: result.css ?? '',
244
301
  };
245
302
 
303
+ // Less 4.x returns the source map as `result.map` (a JSON string) when one was
304
+ // requested; forward it so `less.render(src, { sourceMap: true })` behaves the
305
+ // same. The compiler writes the `sourceMappingURL` annotation into `css` itself.
306
+ if (result.map !== undefined) {
307
+ out.map = result.map;
308
+ }
309
+
246
310
  if (result.imports && Array.isArray(result.imports)) {
247
311
  out.imports = result.imports;
248
312
  }
@@ -261,7 +325,7 @@ function mapRenderResult(result, options) {
261
325
  * @module less/lib/version
262
326
  */
263
327
 
264
- const semver = "5.0.0-alpha.6";
328
+ const semver = "5.0.0-alpha.8";
265
329
  const parsed = parseNodeVersion__default["default"](`v${semver}`);
266
330
 
267
331
  const version = {
package/lib/options.d.ts CHANGED
@@ -13,10 +13,46 @@ export interface LessRenderOptions {
13
13
  plugins?: unknown[];
14
14
  math?: number | 'always' | 'parens-division' | 'parens' | 'strict';
15
15
  /**
16
- * Opt into Less 4-style flattened output. Less v5 preserves authored nesting
17
- * by default.
16
+ * How to flatten authored nesting. Less v5 preserves authored nesting by
17
+ * default (`false`). `'native'` applies the CSS Nesting desugaring (parent
18
+ * wrapped in `:is()`, child selector lists distributed — specificity-faithful,
19
+ * matching the browser and Less 4.x); `'compact'` additionally folds
20
+ * same-combinator descendant runs into a single `:is()`. `true` is a
21
+ * deprecated alias for `'native'`.
18
22
  */
19
- collapseNesting?: boolean;
23
+ collapseNesting?: boolean | 'native' | 'compact';
24
+ /** Minified output. */
25
+ compress?: boolean;
26
+ /** Prepend a path to every rewritten `url(...)` and imported reference. */
27
+ rootpath?: string;
28
+ /** Rewrite relative `url(...)` against the importing file: `'all'` | `'local'` | `'off'` (or boolean). */
29
+ rewriteUrls?: boolean | 'all' | 'local' | 'off';
30
+ /** Append a query string to every non-data `url(...)`. */
31
+ urlArgs?: string;
32
+ /**
33
+ * Emit a source map. `true` turns it on with defaults; the object form (or the
34
+ * flat legacy `sourceMap*` options) configures it. Returned as `result.map`.
35
+ */
36
+ sourceMap?: boolean | {
37
+ sourceMapURL?: string;
38
+ sourceMapFilename?: string;
39
+ sourceMapFullFilename?: string;
40
+ sourceMapRootpath?: string;
41
+ sourceMapBasepath?: string;
42
+ sourceMapFileInline?: boolean;
43
+ sourceMapOutputFilename?: string;
44
+ outputSourceFiles?: boolean;
45
+ disableSourcemapAnnotation?: boolean;
46
+ };
47
+ sourceMapURL?: string;
48
+ sourceMapFilename?: string;
49
+ sourceMapFullFilename?: string;
50
+ sourceMapRootpath?: string;
51
+ sourceMapBasepath?: string;
52
+ sourceMapFileInline?: boolean;
53
+ sourceMapOutputFilename?: string;
54
+ outputSourceFiles?: boolean;
55
+ disableSourcemapAnnotation?: boolean;
20
56
  /** @internal Jess alpha benchmark-only flag for source graphs already proven @plugin-free. */
21
57
  __jessSkipLessCompatWhenPluginFree?: boolean;
22
58
  }
package/lib/options.js CHANGED
@@ -8,19 +8,9 @@ import { lessCompatPlugin } from '@jesscss/plugin-less-compat';
8
8
  import { logger } from './logger.js';
9
9
 
10
10
  const unsupportedAlphaOptions = new Map([
11
- ['sourceMap', 'source maps are not supported'],
12
- ['sourceMapFilename', 'source maps are not supported'],
13
- ['sourceMapRootpath', 'source maps are not supported'],
14
- ['sourceMapBasepath', 'source maps are not supported'],
15
- ['sourceMapURL', 'source maps are not supported'],
16
- ['sourceMapFileInline', 'source maps are not supported'],
17
11
  ['globalVars', 'global variable injection is not supported'],
18
12
  ['modifyVars', 'modify-var injection is not supported'],
19
- ['rootpath', 'URL rootpath rewriting is not supported'],
20
- ['rewriteUrls', 'URL rewriting is not supported'],
21
- ['urlArgs', 'URL argument rewriting is not supported'],
22
13
  ['javascriptEnabled', 'JavaScript evaluation is not supported'],
23
- ['compress', 'compressed output is not supported'],
24
14
  ]);
25
15
 
26
16
  function validateAlphaOptions(options) {
@@ -64,6 +54,55 @@ function stableStringify(value, seen = new WeakSet()) {
64
54
  return `{${entries.join(',')}}`;
65
55
  }
66
56
 
57
+ /**
58
+ * `collapseNesting` accepts `false` (keep authored nesting — the v5 default),
59
+ * `'native'` (CSS Nesting desugaring: parent wrapped in `:is()`, child selector
60
+ * lists distributed, specificity-faithful), `'compact'` (like `'native'` but
61
+ * also folds same-combinator descendant runs into one `:is()`), or the
62
+ * deprecated boolean `true` (alias for `'native'`). Anything else is rejected.
63
+ * @param {unknown} value
64
+ * @returns {boolean|'native'|'compact'}
65
+ */
66
+ function resolveCollapseNesting(value) {
67
+ if (value === false || value === true || value === 'native' || value === 'compact') {
68
+ return value;
69
+ }
70
+ throw new Error(
71
+ `collapseNesting must be false, 'native', 'compact', or true `
72
+ + `(deprecated alias for 'native'); got ${JSON.stringify(value)}`
73
+ );
74
+ }
75
+
76
+ /**
77
+ * Build the compiler's `output.sourceMap` value from Less options. Source maps
78
+ * are enabled when `sourceMap` is truthy; the object form (or the flat legacy
79
+ * `sourceMap*` options) configures the details. Returns `undefined` when no
80
+ * source map is requested.
81
+ * @param {import('./options.js').LessRenderOptions} opts
82
+ * @returns {undefined | true | Record<string, unknown>}
83
+ */
84
+ function resolveSourceMap(opts) {
85
+ if (!opts.sourceMap) {
86
+ return undefined;
87
+ }
88
+ const config = (typeof opts.sourceMap === 'object' && opts.sourceMap !== null)
89
+ ? { ...opts.sourceMap }
90
+ : {};
91
+ // Fold the flat legacy `sourceMap*` options into the object form the compiler
92
+ // reads; an explicit object sub-option wins over its flat alias.
93
+ const flat = [
94
+ 'sourceMapURL', 'sourceMapFilename', 'sourceMapFullFilename',
95
+ 'sourceMapRootpath', 'sourceMapBasepath', 'sourceMapFileInline',
96
+ 'sourceMapOutputFilename', 'outputSourceFiles', 'disableSourcemapAnnotation'
97
+ ];
98
+ for (const key of flat) {
99
+ if (opts[key] !== undefined && config[key] === undefined) {
100
+ config[key] = opts[key];
101
+ }
102
+ }
103
+ return Object.keys(config).length > 0 ? config : true;
104
+ }
105
+
67
106
  /**
68
107
  * Map Less render options to Jess compiler config.
69
108
  * @param {import('./options.js').LessRenderOptions} [options] Less-style options
@@ -98,11 +137,37 @@ export function createLessOptions(options) {
98
137
  );
99
138
  }
100
139
 
101
- const plugins = [lessPlugin()];
140
+ // URL rewriting lives on the Less plugin (it rewrites `url(...)` during
141
+ // serialization), not in `output`. Only forward keys the caller set so the
142
+ // plugin's own v5 defaults apply otherwise.
143
+ const lessPluginOptions = {};
144
+ if (opts.rootpath !== undefined) lessPluginOptions.rootpath = opts.rootpath;
145
+ if (opts.rewriteUrls !== undefined) lessPluginOptions.rewriteUrls = opts.rewriteUrls;
146
+ if (opts.urlArgs !== undefined) lessPluginOptions.urlArgs = opts.urlArgs;
147
+
148
+ const plugins = [lessPlugin(lessPluginOptions)];
102
149
  if (!skipLessCompat) {
103
150
  plugins.push(lessCompatPlugin({ plugins: lessPlugins }));
104
151
  }
105
152
 
153
+ // The projection/serialization options the compiler reads off `output`:
154
+ // `collapseNesting` (nesting flatten mode), `compress` (minified output), and
155
+ // `sourceMap`. Emitted as a single file-less array entry so an explicit render
156
+ // option overrides a file-local styles.config for every key (the config merge
157
+ // appends it as the override default); left `{}` when the caller set none.
158
+ const outputEntry = {};
159
+ if (opts.collapseNesting !== undefined) {
160
+ outputEntry.collapseNesting = resolveCollapseNesting(opts.collapseNesting);
161
+ }
162
+ if (opts.compress !== undefined) {
163
+ outputEntry.compress = opts.compress;
164
+ }
165
+ const sourceMap = resolveSourceMap(opts);
166
+ if (sourceMap !== undefined) {
167
+ outputEntry.sourceMap = sourceMap;
168
+ }
169
+ const output = Object.keys(outputEntry).length > 0 ? [outputEntry] : {};
170
+
106
171
  const configOptions = {
107
172
  compile: {
108
173
  searchPaths: opts.paths || [],
@@ -110,15 +175,7 @@ export function createLessOptions(options) {
110
175
  ...(unitMode !== undefined && { unitMode }),
111
176
  plugins,
112
177
  },
113
- // Less v5 preserves authored nesting unless its explicit compatibility
114
- // switch requests flattened CSS. Keep that public Less option at the
115
- // wrapper boundary; Jess owns the one renderer and its output mode.
116
- // A file's styles.config may use an output array. A file-less output entry
117
- // is the compiler's documented per-render override for that shape, so an
118
- // explicit public Less option remains authoritative over fixture config.
119
- output: Object.prototype.hasOwnProperty.call(opts, 'collapseNesting')
120
- ? [{ collapseNesting: opts.collapseNesting === true }]
121
- : {},
178
+ output,
122
179
  language: {},
123
180
  };
124
181
 
@@ -147,6 +204,13 @@ export function mapRenderResult(result, options) {
147
204
  css: result.css ?? '',
148
205
  };
149
206
 
207
+ // Less 4.x returns the source map as `result.map` (a JSON string) when one was
208
+ // requested; forward it so `less.render(src, { sourceMap: true })` behaves the
209
+ // same. The compiler writes the `sourceMappingURL` annotation into `css` itself.
210
+ if (result.map !== undefined) {
211
+ out.map = result.map;
212
+ }
213
+
150
214
  if (result.imports && Array.isArray(result.imports)) {
151
215
  out.imports = result.imports;
152
216
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "less",
3
- "version": "5.0.0-alpha.6",
3
+ "version": "5.0.0-alpha.8",
4
4
  "description": "Leaner CSS",
5
5
  "homepage": "http://lesscss.org",
6
6
  "author": {
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "scripts": {
54
54
  "quicktest": "npm run test:legacy-node",
55
- "test:alpha": "npm run typecheck && npm run build && npm run test:lessc && node test/jess-alpha-fast-path.mjs && node test/alpha-support.mjs && node test/alpha-fixtures.mjs",
55
+ "test:alpha": "npm run typecheck && npm run build && npm run test:lessc && node test/jess-alpha-fast-path.mjs && node test/alpha-support.mjs && node test/alpha-sourcemaps.mjs && node test/alpha-fixtures.mjs",
56
56
  "test:lessc": "node test/lessc-alpha.mjs",
57
57
  "test": "npm run test:alpha",
58
58
  "test:module": "node test/test-es6.js && node test/test-cjs.cjs",
@@ -141,15 +141,15 @@
141
141
  "rawcurrent": "https://raw.github.com/less/less.js/v",
142
142
  "sourcearchive": "https://github.com/less/less.js/archive/v",
143
143
  "dependencies": {
144
- "@jesscss/compiler": "2.0.0-alpha.20",
145
- "@jesscss/core": "2.0.0-alpha.20",
146
- "@jesscss/plugin-less": "2.0.0-alpha.20",
147
- "@jesscss/plugin-less-compat": "2.0.0-alpha.20",
148
- "@jesscss/plugin-node-modules": "2.0.0-alpha.20",
144
+ "@jesscss/compiler": "2.0.0-alpha.21",
145
+ "@jesscss/core": "2.0.0-alpha.21",
146
+ "@jesscss/plugin-less": "2.0.0-alpha.21",
147
+ "@jesscss/plugin-less-compat": "2.0.0-alpha.21",
148
+ "@jesscss/plugin-node-modules": "2.0.0-alpha.21",
149
149
  "parse-node-version": "^1.0.1"
150
150
  },
151
151
  "peerDependencies": {
152
- "@jesscss/plugin-js": "2.0.0-alpha.20"
152
+ "@jesscss/plugin-js": "2.0.0-alpha.21"
153
153
  },
154
154
  "peerDependenciesMeta": {
155
155
  "@jesscss/plugin-js": {