less 4.9.0 → 5.0.0-alpha.1

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 (131) hide show
  1. package/README.md +19 -5
  2. package/bin/lessc +190 -630
  3. package/dist/less-node.cjs +399 -14570
  4. package/index.cjs +5 -2
  5. package/lib/index.js +164 -0
  6. package/lib/lessc-helper.js +52 -0
  7. package/lib/logger.js +76 -0
  8. package/lib/options.d.ts +46 -0
  9. package/lib/options.js +145 -0
  10. package/lib/types.js +20 -0
  11. package/lib/version.js +19 -0
  12. package/package.json +34 -40
  13. package/dist/less.cjs +0 -15215
  14. package/dist/less.js +0 -15215
  15. package/dist/less.min.js +0 -11
  16. package/dist/less.min.js.map +0 -1
  17. package/lib/less/constants.js +0 -13
  18. package/lib/less/contexts.js +0 -165
  19. package/lib/less/data/colors.js +0 -150
  20. package/lib/less/data/index.js +0 -4
  21. package/lib/less/data/unit-conversions.js +0 -21
  22. package/lib/less/default-options.js +0 -89
  23. package/lib/less/deprecation.js +0 -82
  24. package/lib/less/environment/abstract-file-manager.js +0 -140
  25. package/lib/less/environment/abstract-plugin-loader.js +0 -185
  26. package/lib/less/environment/environment-api.ts +0 -21
  27. package/lib/less/environment/environment.js +0 -59
  28. package/lib/less/environment/file-manager-api.ts +0 -77
  29. package/lib/less/functions/boolean.js +0 -29
  30. package/lib/less/functions/color-blending.js +0 -85
  31. package/lib/less/functions/color.js +0 -452
  32. package/lib/less/functions/data-uri.js +0 -74
  33. package/lib/less/functions/default.js +0 -26
  34. package/lib/less/functions/function-caller.js +0 -55
  35. package/lib/less/functions/function-registry.js +0 -36
  36. package/lib/less/functions/index.js +0 -35
  37. package/lib/less/functions/list.js +0 -158
  38. package/lib/less/functions/math-helper.js +0 -22
  39. package/lib/less/functions/math.js +0 -30
  40. package/lib/less/functions/number.js +0 -95
  41. package/lib/less/functions/string.js +0 -39
  42. package/lib/less/functions/style.js +0 -29
  43. package/lib/less/functions/svg.js +0 -87
  44. package/lib/less/functions/types.js +0 -70
  45. package/lib/less/import-manager.js +0 -183
  46. package/lib/less/index.js +0 -95
  47. package/lib/less/less-error.js +0 -166
  48. package/lib/less/logger.js +0 -34
  49. package/lib/less/parse-tree.js +0 -124
  50. package/lib/less/parse.js +0 -87
  51. package/lib/less/parser/lookup-pattern.js +0 -26
  52. package/lib/less/parser/parser-input.js +0 -400
  53. package/lib/less/parser/parser.js +0 -2998
  54. package/lib/less/plugin-manager.js +0 -168
  55. package/lib/less/render.js +0 -41
  56. package/lib/less/source-map-builder.js +0 -82
  57. package/lib/less/source-map-output.js +0 -151
  58. package/lib/less/transform-tree.js +0 -102
  59. package/lib/less/tree/anonymous.js +0 -61
  60. package/lib/less/tree/assignment.js +0 -48
  61. package/lib/less/tree/atrule-syntax.js +0 -8
  62. package/lib/less/tree/atrule.js +0 -340
  63. package/lib/less/tree/attribute.js +0 -63
  64. package/lib/less/tree/call.js +0 -132
  65. package/lib/less/tree/color.js +0 -285
  66. package/lib/less/tree/combinator.js +0 -38
  67. package/lib/less/tree/comment.js +0 -48
  68. package/lib/less/tree/condition.js +0 -65
  69. package/lib/less/tree/container.js +0 -104
  70. package/lib/less/tree/debug-info.js +0 -80
  71. package/lib/less/tree/declaration.js +0 -139
  72. package/lib/less/tree/detached-ruleset.js +0 -45
  73. package/lib/less/tree/dimension.js +0 -215
  74. package/lib/less/tree/element.js +0 -93
  75. package/lib/less/tree/expression.js +0 -100
  76. package/lib/less/tree/extend.js +0 -88
  77. package/lib/less/tree/import.js +0 -299
  78. package/lib/less/tree/index.js +0 -56
  79. package/lib/less/tree/interpolated-variable.js +0 -106
  80. package/lib/less/tree/javascript.js +0 -45
  81. package/lib/less/tree/js-eval-node.js +0 -80
  82. package/lib/less/tree/keyword.js +0 -28
  83. package/lib/less/tree/media.js +0 -90
  84. package/lib/less/tree/merge-rules.js +0 -47
  85. package/lib/less/tree/mixin-call.js +0 -283
  86. package/lib/less/tree/mixin-definition.js +0 -319
  87. package/lib/less/tree/namespace-value.js +0 -95
  88. package/lib/less/tree/negative.js +0 -37
  89. package/lib/less/tree/nested-at-rule.js +0 -239
  90. package/lib/less/tree/node.js +0 -310
  91. package/lib/less/tree/operation.js +0 -81
  92. package/lib/less/tree/paren.js +0 -41
  93. package/lib/less/tree/property.js +0 -96
  94. package/lib/less/tree/query-in-parens.js +0 -64
  95. package/lib/less/tree/quoted.js +0 -131
  96. package/lib/less/tree/ruleset.js +0 -1068
  97. package/lib/less/tree/selector.js +0 -201
  98. package/lib/less/tree/unicode-descriptor.js +0 -14
  99. package/lib/less/tree/unit.js +0 -170
  100. package/lib/less/tree/url.js +0 -83
  101. package/lib/less/tree/value.js +0 -60
  102. package/lib/less/tree/variable-call.js +0 -60
  103. package/lib/less/tree/variable.js +0 -85
  104. package/lib/less/utils.js +0 -126
  105. package/lib/less/visitors/extend-visitor.js +0 -505
  106. package/lib/less/visitors/import-sequencer.js +0 -56
  107. package/lib/less/visitors/import-visitor.js +0 -203
  108. package/lib/less/visitors/index.js +0 -15
  109. package/lib/less/visitors/join-selector-visitor.js +0 -65
  110. package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
  111. package/lib/less/visitors/to-css-visitor.js +0 -332
  112. package/lib/less/visitors/visitor.js +0 -165
  113. package/lib/less-browser/add-default-options.js +0 -53
  114. package/lib/less-browser/bootstrap.js +0 -67
  115. package/lib/less-browser/browser.js +0 -65
  116. package/lib/less-browser/cache.js +0 -43
  117. package/lib/less-browser/error-reporting.js +0 -170
  118. package/lib/less-browser/file-manager.js +0 -112
  119. package/lib/less-browser/image-size.js +0 -28
  120. package/lib/less-browser/index.js +0 -284
  121. package/lib/less-browser/log-listener.js +0 -42
  122. package/lib/less-browser/plugin-loader.js +0 -24
  123. package/lib/less-browser/utils.js +0 -30
  124. package/lib/less-node/environment.js +0 -43
  125. package/lib/less-node/file-manager.js +0 -156
  126. package/lib/less-node/fs.js +0 -14
  127. package/lib/less-node/image-size.js +0 -78
  128. package/lib/less-node/index.js +0 -31
  129. package/lib/less-node/lessc-helper.js +0 -95
  130. package/lib/less-node/plugin-loader.js +0 -62
  131. package/lib/less-node/url-file-manager.js +0 -60
package/index.cjs CHANGED
@@ -1,2 +1,5 @@
1
- // CJS entry requires the pre-built CJS bundle
2
- module.exports = require('./dist/less-node.cjs');
1
+ // CJS entry: unwrap the Rollup namespace so require('less') returns the Less API object.
2
+ const bundle = require('./dist/less-node.cjs');
3
+
4
+ module.exports = bundle.default || bundle;
5
+ Object.assign(module.exports, bundle);
package/lib/index.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Less.js v5 — powered by Jess
3
+ *
4
+ * This module provides a Less-compatible API backed by the Jess compiler.
5
+ * It supports the same `less.render()` interface that Less 4.x users expect,
6
+ * while delegating all parsing, evaluation, and output to Jess with the
7
+ * `@jesscss/plugin-less` and `@jesscss/plugin-less-compat` plugins.
8
+ *
9
+ * @module less
10
+ */
11
+
12
+ import { readFileSync } from 'node:fs';
13
+ import { readFile } from 'node:fs/promises';
14
+ import { Compiler } from '@jesscss/compiler';
15
+ import nodeModulesPlugin from '@jesscss/plugin-node-modules';
16
+ import { createLessOptions, getCompilerCacheKey, mapRenderResult } from './options.js';
17
+ import { version } from './version.js';
18
+ import { logger } from './logger.js';
19
+ import { lesscHelper } from './lessc-helper.js';
20
+
21
+ const compilerCache = new Map();
22
+ const lessVersion = version.array;
23
+
24
+ function normalizeDiagnosticLines(lines, lineNumber, filePath) {
25
+ if (Array.isArray(lines)) {
26
+ return lines.map((line) => typeof line === 'string' ? line : String(line));
27
+ }
28
+ if (lines && typeof lines === 'object') {
29
+ const current = Number(lineNumber) || 1;
30
+ return [current - 1, current, current + 1]
31
+ .filter((line) => line > 0 && Object.prototype.hasOwnProperty.call(lines, line))
32
+ .map((line) => {
33
+ const value = lines[line];
34
+ return typeof value === 'string' ? value : String(value);
35
+ });
36
+ }
37
+ if (typeof filePath === 'string') {
38
+ try {
39
+ const sourceLines = readFileSync(filePath, 'utf8').split(/\r?\n/);
40
+ const current = Number(lineNumber) || 1;
41
+ return [current - 1, current, current + 1]
42
+ .filter((line) => line > 0 && line <= sourceLines.length)
43
+ .map((line) => sourceLines[line - 1]);
44
+ } catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ return undefined;
49
+ }
50
+
51
+ function createRenderErrorFromJessDiagnostic(result, filePath) {
52
+ const errors = result?.errors || [];
53
+ const diagnostic = errors[0];
54
+ const error = new Error(diagnostic?.message || 'Less render failed');
55
+
56
+ error.type = diagnostic?.phase || 'Syntax';
57
+ error.filename = diagnostic?.filePath || filePath;
58
+ error.line = diagnostic?.line || 1;
59
+ error.column = diagnostic?.column || 1;
60
+ error.extract = normalizeDiagnosticLines(diagnostic?.lines, error.line, error.filename);
61
+ error.jessErrors = errors;
62
+ error.jessWarnings = result?.warnings || [];
63
+
64
+ return error;
65
+ }
66
+
67
+ /**
68
+ * @param {object} configOptions
69
+ */
70
+ function getCompiler(configOptions) {
71
+ const cacheKey = getCompilerCacheKey(configOptions);
72
+ let compiler = compilerCache.get(cacheKey);
73
+ if (!compiler) {
74
+ compiler = new Compiler(configOptions, {
75
+ defaultPlugins: context => [nodeModulesPlugin({ basePath: context.resolutionBaseDir })],
76
+ scriptPluginSpecifier: '@jesscss/plugin-js',
77
+ scriptPluginResolveFrom: import.meta.url
78
+ });
79
+ compilerCache.set(cacheKey, compiler);
80
+ }
81
+ return compiler;
82
+ }
83
+
84
+ /**
85
+ * Render Less source to CSS.
86
+ *
87
+ * @param {string} input - Less source string
88
+ * @param {import('./options.js').LessRenderOptions} [options={}]
89
+ * @param {Function} [callback] - Optional Node-style callback(err, result)
90
+ * @returns {Promise<import('./options.js').LessRenderResult>}
91
+ */
92
+ function render(input, options = {}, callback) {
93
+ if (typeof options === 'function') {
94
+ callback = options;
95
+ options = {};
96
+ }
97
+ const promise = (async () => {
98
+ const { configOptions, filePath } = createLessOptions(options, { source: input });
99
+ const compiler = getCompiler(configOptions);
100
+
101
+ const result = await compiler.renderToResult(
102
+ { source: input, filePath, language: 'less', extension: '.less' },
103
+ { ...configOptions, suppressWarnings: true }
104
+ );
105
+
106
+ if (result.errors?.length) {
107
+ throw createRenderErrorFromJessDiagnostic(result, filePath);
108
+ }
109
+
110
+ return mapRenderResult(result, options);
111
+ })();
112
+
113
+ if (callback) {
114
+ promise.then(
115
+ result => callback(null, result),
116
+ err => callback(err)
117
+ );
118
+ }
119
+ return promise;
120
+ }
121
+
122
+ /**
123
+ * Render a Less file to CSS.
124
+ *
125
+ * @param {string} filePath - Absolute or relative path to .less file
126
+ * @param {import('./options.js').LessRenderOptions} [options={}]
127
+ * @returns {Promise<import('./options.js').LessRenderResult>}
128
+ */
129
+ async function renderFile(filePath, options = {}) {
130
+ const source = await readFile(filePath, 'utf8');
131
+ const { configOptions } = createLessOptions(options, { source });
132
+ const compiler = getCompiler(configOptions);
133
+
134
+ const result = await compiler.renderToResult(filePath, { ...configOptions, suppressWarnings: true });
135
+ if (result.errors?.length) {
136
+ throw createRenderErrorFromJessDiagnostic(result, filePath);
137
+ }
138
+ return mapRenderResult(result, options);
139
+ }
140
+
141
+ /**
142
+ * COMPAT GAP (v5): the Less 4.x `less.functions` (custom-function registry via
143
+ * `less.functions.functionRegistry.add/addMultiple`) and `less.tree` (node
144
+ * constructors) are intentionally NOT present on the Jess-backed build. Jess
145
+ * registers custom functions with `defineFunction(name, fn, opts)` supplied
146
+ * through the compiler config/plugins, and its values are Jess nodes, not
147
+ * `less.tree.*`. Providing these as throwing stubs would break feature-detection
148
+ * (`if (less.functions)`), so they are left absent until a real compat surface
149
+ * (registry -> defineFunction bridge + tree-node shims) is built. Tracked for
150
+ * the broader Less-runner/API-parity work; see also test/less-test.js guards.
151
+ *
152
+ * @type {import('./types.js').LessStatic}
153
+ */
154
+ const less = {
155
+ version: lessVersion,
156
+ render,
157
+ renderFile,
158
+ logger,
159
+ lesscHelper,
160
+ Compiler,
161
+ };
162
+
163
+ export default less;
164
+ export { render, renderFile, logger, lesscHelper, Compiler, lessVersion as version };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Helper functions for lessc CLI.
3
+ * Adapted from lib.bak/less-node/lessc-helper.js.
4
+ * @module less/lib/lessc-helper
5
+ */
6
+
7
+ /** @type {Record<string, [number, number]>} */
8
+ const STYLES = {
9
+ reset: [0, 0],
10
+ bold: [1, 22],
11
+ inverse: [7, 27],
12
+ underline: [4, 24],
13
+ yellow: [33, 39],
14
+ green: [32, 39],
15
+ red: [31, 39],
16
+ grey: [90, 39],
17
+ };
18
+
19
+ const lesscHelper = {
20
+ /** @param {string} str @param {string} style */
21
+ stylize(str, style) {
22
+ const s = STYLES[style] ?? STYLES.reset;
23
+ return `\x1b[${s[0]}m${str}\x1b[${s[1]}m`;
24
+ },
25
+
26
+ printUsage() {
27
+ console.log('usage: lessc [option option=parameter ...] <source> [destination]');
28
+ console.log('');
29
+ console.log('If source is set to `-\' (dash or hyphen-minus), input is read from stdin.');
30
+ console.log('');
31
+ console.log('options:');
32
+ console.log(' -h, --help Prints help (this message) and exit.');
33
+ console.log(' -I PATH, -IPATH Adds an import search path.');
34
+ console.log(' --include-path=PATHS Sets include paths. Separated by `:\'. `;\' also supported on windows.');
35
+ console.log(' --no-color Disables colorized output.');
36
+ console.log(' -s, --silent Suppresses output of error messages.');
37
+ console.log(' --quiet Suppresses output of warnings.');
38
+ console.log(' -v, --version Prints version number and exit.');
39
+ console.log(' --verbose Be verbose.');
40
+ console.log(' --collapse-nesting Flatten nested rules after preserving source-order cascade.');
41
+ console.log('');
42
+ console.log('This release intentionally supports a smaller CLI surface.');
43
+ console.log('Source maps, browser compilation, legacy plugin flags, lint-only mode, and');
44
+ console.log('URL rewrite flags will be revisited in later alphas.');
45
+ console.log('');
46
+ console.log('Report bugs to: http://github.com/less/less.js/issues');
47
+ console.log('Home page: <http://lesscss.org/>');
48
+ },
49
+ };
50
+
51
+ export { lesscHelper };
52
+ export default lesscHelper;
package/lib/logger.js ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Less logger wired to Jess's logger singleton.
3
+ * Forwards to Jess and maintains Less-style addListener/removeListener for compatibility.
4
+ * @module less/lib/logger
5
+ */
6
+
7
+ import { logger as jessLogger } from '@jesscss/core';
8
+
9
+ /** @typedef {{ error?: (msg: string) => void, warn?: (msg: string) => void, info?: (msg: string) => void, debug?: (msg: string) => void }} LogListener */
10
+
11
+ /** @type {LogListener[]} */
12
+ const _listeners = [];
13
+
14
+ /** @param {'error'|'warn'|'info'|'debug'} type @param {string} msg */
15
+ function _fireEvent(type, msg) {
16
+ for (const listener of _listeners) {
17
+ const fn = listener[type];
18
+ if (fn) fn(msg);
19
+ }
20
+ }
21
+
22
+ // Wrap Jess's logger so Less listeners receive Jess's log output without
23
+ // writing directly to stderr/stdout. Library consumers should be able to catch
24
+ // `less.render()` rejections without surprise terminal output; the CLI owns
25
+ // deciding whether/how to print diagnostics.
26
+ jessLogger.configure?.({
27
+ log(...args) {
28
+ _fireEvent('debug', args.map(String).join(' '));
29
+ },
30
+ info(...args) {
31
+ _fireEvent('info', args.map(String).join(' '));
32
+ },
33
+ warn(...args) {
34
+ _fireEvent('warn', args.map(String).join(' '));
35
+ },
36
+ error(...args) {
37
+ _fireEvent('error', args.map(String).join(' '));
38
+ },
39
+ });
40
+
41
+ /** Less-compatible logger backed by Jess's singleton */
42
+ const logger = {
43
+ /** @param {string} msg */
44
+ error(msg) {
45
+ _fireEvent('error', msg);
46
+ },
47
+
48
+ /** @param {string} msg */
49
+ warn(msg) {
50
+ _fireEvent('warn', msg);
51
+ },
52
+
53
+ /** @param {string} msg */
54
+ info(msg) {
55
+ _fireEvent('info', msg);
56
+ },
57
+
58
+ /** @param {string} msg */
59
+ debug(msg) {
60
+ _fireEvent('debug', msg);
61
+ },
62
+
63
+ /** @param {LogListener} listener */
64
+ addListener(listener) {
65
+ _listeners.push(listener);
66
+ },
67
+
68
+ /** @param {LogListener} listener */
69
+ removeListener(listener) {
70
+ const i = _listeners.indexOf(listener);
71
+ if (i >= 0) _listeners.splice(i, 1);
72
+ },
73
+ };
74
+
75
+ export { logger };
76
+ export default logger;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Options mapping between Less render options and Jess compiler config.
3
+ */
4
+
5
+ export interface LessRenderOptions {
6
+ filename?: string;
7
+ paths?: string[];
8
+ /**
9
+ * Legacy Less render plugins are routed through the alpha compatibility
10
+ * layer. File-manager, pre/post-processor, and @plugin execution are not
11
+ * alpha.1-supported surfaces yet.
12
+ */
13
+ plugins?: unknown[];
14
+ math?: number | 'always' | 'parens-division' | 'parens' | 'strict';
15
+ /**
16
+ * Opt into Less 4-style flattened output. Less v5 preserves authored nesting
17
+ * by default.
18
+ */
19
+ collapseNesting?: boolean;
20
+ /** @internal Jess alpha benchmark-only flag for source graphs already proven @plugin-free. */
21
+ __jessSkipLessCompatWhenPluginFree?: boolean;
22
+ }
23
+
24
+ export interface LessRenderResult {
25
+ css: string;
26
+ map?: string;
27
+ imports?: string[];
28
+ }
29
+
30
+ export interface JessRenderResult {
31
+ css?: string;
32
+ map?: string | object;
33
+ imports?: string[];
34
+ }
35
+
36
+ export function createLessOptions(options?: LessRenderOptions): {
37
+ configOptions: object;
38
+ filePath?: string;
39
+ };
40
+
41
+ export function getCompilerCacheKey(configOptions: object): string;
42
+
43
+ export function mapRenderResult(
44
+ result: JessRenderResult,
45
+ options?: LessRenderOptions
46
+ ): LessRenderResult;
package/lib/options.js ADDED
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Options mapping between Less render options and Jess compiler config.
3
+ * @module less/lib/options
4
+ */
5
+
6
+ import lessPlugin from '@jesscss/plugin-less';
7
+ import { lessCompatPlugin } from '@jesscss/plugin-less-compat';
8
+
9
+ const unsupportedAlphaOptions = new Map([
10
+ ['sourceMap', 'source maps are not supported'],
11
+ ['sourceMapFilename', 'source maps are not supported'],
12
+ ['sourceMapRootpath', 'source maps are not supported'],
13
+ ['sourceMapBasepath', 'source maps are not supported'],
14
+ ['sourceMapURL', 'source maps are not supported'],
15
+ ['sourceMapFileInline', 'source maps are not supported'],
16
+ ['globalVars', 'global variable injection is not supported'],
17
+ ['modifyVars', 'modify-var injection is not supported'],
18
+ ['strictUnits', 'strict unit mode 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
+ ['javascriptEnabled', 'JavaScript evaluation is not supported'],
23
+ ['compress', 'compressed output is not supported'],
24
+ ]);
25
+
26
+ function validateAlphaOptions(options) {
27
+ for (const [name, reason] of unsupportedAlphaOptions) {
28
+ if (Object.prototype.hasOwnProperty.call(options, name)) {
29
+ throw new Error(`${name} is not supported: ${reason}`);
30
+ }
31
+ }
32
+ }
33
+
34
+ /**
35
+ * @param {any} value
36
+ * @param {WeakSet<object>} [seen]
37
+ * @returns {string}
38
+ */
39
+ function stableStringify(value, seen = new WeakSet()) {
40
+ if (value == null || typeof value !== 'object') {
41
+ if (typeof value === 'function') {
42
+ return JSON.stringify(`[function ${value.name || 'anonymous'}]`);
43
+ }
44
+ return JSON.stringify(value);
45
+ }
46
+ if (seen.has(value)) {
47
+ return '"[Circular]"';
48
+ }
49
+ seen.add(value);
50
+ if (Array.isArray(value)) {
51
+ return `[${value.map((item) => stableStringify(item, seen)).join(',')}]`;
52
+ }
53
+ if (value.name && typeof value.name === 'string' && ('install' in value || 'parser' in value || 'opts' in value)) {
54
+ return stableStringify({
55
+ plugin: value.name,
56
+ opts: value.opts || {},
57
+ }, seen);
58
+ }
59
+ const entries = Object.keys(value)
60
+ .sort()
61
+ .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key], seen)}`);
62
+ return `{${entries.join(',')}}`;
63
+ }
64
+
65
+ /**
66
+ * Map Less render options to Jess compiler config.
67
+ * @param {import('./options.js').LessRenderOptions} [options] Less-style options
68
+ * @returns {{ configOptions: object, filePath?: string }}
69
+ */
70
+ export function createLessOptions(options) {
71
+ const opts = options || {};
72
+ validateAlphaOptions(opts);
73
+ const filePath = opts.filename || undefined;
74
+ const lessPlugins = Array.isArray(opts.plugins) ? opts.plugins : [];
75
+ const skipLessCompat =
76
+ opts.__jessSkipLessCompatWhenPluginFree === true && lessPlugins.length === 0;
77
+
78
+ const math = /** @type {number|string|undefined} */ (opts.math);
79
+ const mathMode =
80
+ math === 0 || math === 'always' ? 'always' :
81
+ math === 2 || math === 'parens' || math === 'strict' ? 'parens' :
82
+ 'parens-division';
83
+
84
+ const plugins = [lessPlugin()];
85
+ if (!skipLessCompat) {
86
+ plugins.push(lessCompatPlugin({ plugins: lessPlugins }));
87
+ }
88
+
89
+ const configOptions = {
90
+ compile: {
91
+ searchPaths: opts.paths || [],
92
+ mathMode,
93
+ plugins,
94
+ },
95
+ // Less v5 preserves authored nesting unless its explicit compatibility
96
+ // switch requests flattened CSS. Keep that public Less option at the
97
+ // wrapper boundary; Jess owns the one renderer and its output mode.
98
+ // A file's styles.config may use an output array. A file-less output entry
99
+ // is the compiler's documented per-render override for that shape, so an
100
+ // explicit public Less option remains authoritative over fixture config.
101
+ output: Object.prototype.hasOwnProperty.call(opts, 'collapseNesting')
102
+ ? [{ collapseNesting: opts.collapseNesting === true }]
103
+ : {},
104
+ language: {},
105
+ };
106
+
107
+ return { configOptions, filePath };
108
+ }
109
+
110
+ /**
111
+ * Stable compiler cache key for a Jess compiler configured from Less options.
112
+ * @param {object} configOptions Jess compiler config
113
+ * @returns {string}
114
+ */
115
+ export function getCompilerCacheKey(configOptions) {
116
+ return stableStringify(configOptions);
117
+ }
118
+
119
+ /**
120
+ * Map Jess render result to Less-style result.
121
+ * @param {import('./options.js').JessRenderResult} result Jess compiler result
122
+ * @param {import('./options.js').LessRenderOptions} [options] Original Less options
123
+ * @returns {import('./options.js').LessRenderResult}
124
+ */
125
+ export function mapRenderResult(result, options) {
126
+ const opts = options || {};
127
+ /** @type {import('./options.js').LessRenderResult} */
128
+ const out = {
129
+ css: result.css ?? '',
130
+ };
131
+
132
+ if (result.imports && Array.isArray(result.imports)) {
133
+ out.imports = result.imports;
134
+ }
135
+
136
+ // Structured Jess warnings (e.g. selector/parentless-ampersand). Exposed so
137
+ // callers and tests can assert them, mirroring how errors surface.
138
+ if (result.warnings && Array.isArray(result.warnings)) {
139
+ out.warnings = result.warnings;
140
+ }
141
+
142
+ return out;
143
+ }
144
+
145
+ export default { createLessOptions, getCompilerCacheKey, mapRenderResult };
package/lib/types.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * JSDoc type definitions for Less.js v5 (Jess wrapper).
3
+ * @module less/lib/types
4
+ */
5
+
6
+ /**
7
+ * @typedef {import('./options.js').LessRenderResult} LessRenderResult
8
+ */
9
+
10
+ /**
11
+ * @typedef {Object} LessStatic
12
+ * @property {number[]} version Less-compatible version tuple
13
+ * @property {function(string, import('./options.js').LessRenderOptions?, function?): Promise<LessRenderResult>} render Render Less to CSS
14
+ * @property {function(string, import('./options.js').LessRenderOptions?): Promise<LessRenderResult>} renderFile Render Less file to CSS
15
+ * @property {import('./logger.js').default} logger Logger instance
16
+ * @property {import('./lessc-helper.js').default} lesscHelper CLI helper
17
+ * @property {object} Compiler Jess Compiler class
18
+ */
19
+
20
+ export {};
package/lib/version.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Version info for Less.js v5 (Jess wrapper).
3
+ * @module less/lib/version
4
+ */
5
+
6
+ import { createRequire } from 'module';
7
+ import parseNodeVersion from 'parse-node-version';
8
+
9
+ const require = createRequire(import.meta.url);
10
+ const pkg = require('../package.json');
11
+ const semver = pkg.version || '5.0.0-alpha.0';
12
+ const parsed = parseNodeVersion(`v${semver}`);
13
+
14
+ export const version = {
15
+ semver,
16
+ array: [parsed.major, parsed.minor, parsed.patch],
17
+ };
18
+
19
+ export default version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "less",
3
- "version": "4.9.0",
3
+ "version": "5.0.0-alpha.1",
4
4
  "description": "Leaner CSS",
5
5
  "homepage": "http://lesscss.org",
6
6
  "author": {
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "https://github.com/less/less.js.git"
18
+ "url": "git+https://github.com/less/less.js.git"
19
19
  },
20
20
  "master": {
21
21
  "url": "https://github.com/less/less.js/blob/master/",
@@ -24,21 +24,17 @@
24
24
  "license": "Apache-2.0",
25
25
  "type": "module",
26
26
  "bin": {
27
- "lessc": "./bin/lessc"
27
+ "lessc": "bin/lessc"
28
28
  },
29
29
  "main": "./dist/less-node.cjs",
30
30
  "exports": {
31
31
  ".": {
32
- "browser": "./dist/less.cjs",
33
- "import": "./lib/less-node/index.js",
32
+ "import": "./lib/index.js",
34
33
  "require": "./dist/less-node.cjs",
35
- "default": "./lib/less-node/index.js"
34
+ "default": "./lib/index.js"
36
35
  },
37
36
  "./lib/*": "./lib/*",
38
- "./dist/less-node.cjs": "./dist/less-node.cjs",
39
- "./dist/less.cjs": "./dist/less.cjs",
40
- "./dist/less.js": "./dist/less.js",
41
- "./dist/less.min.js": "./dist/less.min.js"
37
+ "./dist/less-node.cjs": "./dist/less-node.cjs"
42
38
  },
43
39
  "directories": {
44
40
  "test": "./test"
@@ -51,30 +47,25 @@
51
47
  "index.cjs",
52
48
  "README.md"
53
49
  ],
54
- "browser": "./dist/less.js",
55
50
  "engines": {
56
- "node": ">=18"
51
+ "node": "^20.19.0 || >=22.12.0"
57
52
  },
58
53
  "scripts": {
59
- "quicktest": "grunt quicktest",
60
- "test": "grunt test",
61
- "test:node": "grunt test:node",
62
- "test:coverage": "c8 -r lcov -r json-summary -r text-summary -r html --include=\"lib/**/*.js\" --include=\"bin/**/*.js\" --exclude=\"dist/**\" --exclude=\"**/*.test.js\" --exclude=\"**/*.spec.js\" --exclude=\"test/**\" --exclude=\"tmp/**\" --exclude=\"**/abstract-file-manager.js\" --exclude=\"**/abstract-plugin-loader.js\" grunt shell:test && node scripts/coverage-report.js && node scripts/coverage-lines.js",
63
- "grunt": "grunt",
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",
56
+ "test:lessc": "node test/lessc-alpha.mjs",
57
+ "test": "npm run test:alpha",
58
+ "test:module": "node test/test-es6.js && node test/test-cjs.cjs",
59
+ "test:legacy-node": "node test/index.js",
60
+ "test:node": "npm run test:module",
61
+ "test:coverage": "c8 -r lcov -r json-summary -r text-summary -r html --include=\"lib/**/*.js\" --include=\"bin/**/*.js\" --exclude=\"dist/**\" --exclude=\"**/*.test.js\" --exclude=\"**/*.spec.js\" --exclude=\"test/**\" --exclude=\"tmp/**\" --exclude=\"**/abstract-file-manager.js\" --exclude=\"**/abstract-plugin-loader.js\" npm run test:legacy-node && node scripts/coverage-report.js && node scripts/coverage-lines.js",
64
62
  "lint": "eslint '**/*.{ts,js}'",
65
63
  "lint:fix": "eslint '**/*.{ts,js}' --fix",
66
64
  "typecheck": "tsc --noEmit",
67
65
  "build": "node build/rollup.js --dist",
68
- "prepublishOnly": "npm run typecheck && grunt dist && grunt test:node"
69
- },
70
- "optionalDependencies": {
71
- "errno": "^0.1.1",
72
- "graceful-fs": "^4.1.2",
73
- "probe-image-size": "^7.2.3",
74
- "make-dir": "^5.1.0",
75
- "mime": "^1.4.1",
76
- "needle": "^3.1.0",
77
- "source-map": "~0.6.0"
66
+ "benchmark": "node benchmark/benchmark-runner.cjs",
67
+ "benchmark:all": "node benchmark/run-and-compare.mjs",
68
+ "prepublishOnly": "npm run typecheck && npm run build && npm run test:lessc"
78
69
  },
79
70
  "devDependencies": {
80
71
  "@less/test-data": "workspace:*",
@@ -94,19 +85,10 @@
94
85
  "cross-env": "^7.0.3",
95
86
  "eslint": "^7.29.0",
96
87
  "fs-extra": "^8.1.0",
97
- "git-rev": "^0.2.1",
98
88
  "glob": "~11.0.3",
99
89
  "globby": "^10.0.1",
100
- "grunt": "^1.5.0",
101
- "grunt-cli": "^1.3.2",
102
- "grunt-contrib-clean": "^1.0.0",
103
- "grunt-contrib-connect": "^1.0.2",
104
- "grunt-eslint": "^23.0.0",
105
- "grunt-saucelabs": "^9.0.1",
106
- "grunt-shell": "^1.3.0",
107
90
  "html-template-tag": "^3.2.0",
108
91
  "jest-diff": "~30.1.2",
109
- "jit-grunt": "^0.10.0",
110
92
  "less-plugin-autoprefix": "^1.5.1",
111
93
  "less-plugin-clean-css": "^1.6.0",
112
94
  "minimist": "^1.2.0",
@@ -114,15 +96,14 @@
114
96
  "mocha-teamcity-reporter": "^3.0.0",
115
97
  "npm-run-all": "^4.1.5",
116
98
  "performance-now": "^0.2.0",
117
- "phin": "^2.2.3",
118
99
  "playwright": "1.50.1",
119
100
  "promise": "^7.1.1",
120
101
  "read-glob": "^3.0.0",
121
102
  "resolve": "^1.17.0",
122
103
  "rollup": "^2.52.2",
123
104
  "rollup-plugin-terser": "^5.1.1",
105
+ "semver": "^6.3.0",
124
106
  "shx": "^0.3.2",
125
- "time-grunt": "^1.3.0",
126
107
  "typescript": "^5.7.0",
127
108
  "uikit": "2.27.4",
128
109
  "url": "^0.11.4",
@@ -158,8 +139,21 @@
158
139
  "rawcurrent": "https://raw.github.com/less/less.js/v",
159
140
  "sourcearchive": "https://github.com/less/less.js/archive/v",
160
141
  "dependencies": {
161
- "copy-anything": "^3.0.5",
162
- "parse-node-version": "^1.0.1"
142
+ "@jesscss/compiler": "2.0.0-alpha.11",
143
+ "@jesscss/core": "2.0.0-alpha.11",
144
+ "@jesscss/plugin-less": "2.0.0-alpha.11",
145
+ "@jesscss/plugin-less-compat": "2.0.0-alpha.11",
146
+ "@jesscss/plugin-node-modules": "2.0.0-alpha.11",
147
+ "parse-node-version": "^1.0.1",
148
+ "parseman": "^0.41.0"
149
+ },
150
+ "peerDependencies": {
151
+ "@jesscss/plugin-js": "2.0.0-alpha.11"
152
+ },
153
+ "peerDependenciesMeta": {
154
+ "@jesscss/plugin-js": {
155
+ "optional": true
156
+ }
163
157
  },
164
158
  "gitHead": "1df9072ee9ebdadc791bf35dfb1dbc3ef9f1948f"
165
159
  }