less 4.4.1 → 4.5.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.
- package/Gruntfile.js +16 -17
- package/bin/lessc +35 -40
- package/dist/less.js +125 -186
- package/dist/less.min.js +2 -2
- package/dist/less.min.js.map +1 -1
- package/lib/less/contexts.js +0 -1
- package/lib/less/contexts.js.map +1 -1
- package/lib/less/default-options.js +22 -3
- package/lib/less/default-options.js.map +1 -1
- package/lib/less/less-error.js +2 -1
- package/lib/less/less-error.js.map +1 -1
- package/lib/less/parse-tree.js +58 -1
- package/lib/less/parse-tree.js.map +1 -1
- package/lib/less/parser/parser-input.js +2 -19
- package/lib/less/parser/parser-input.js.map +1 -1
- package/lib/less/parser/parser.js +8 -14
- package/lib/less/parser/parser.js.map +1 -1
- package/lib/less/source-map-output.js +1 -1
- package/lib/less/source-map-output.js.map +1 -1
- package/lib/less/tree/debug-info.js +29 -0
- package/lib/less/tree/debug-info.js.map +1 -1
- package/lib/less/tree/nested-at-rule.js +1 -1
- package/lib/less/tree/nested-at-rule.js.map +1 -1
- package/lib/less-node/lessc-helper.js +8 -7
- package/lib/less-node/lessc-helper.js.map +1 -1
- package/package.json +10 -5
- package/scripts/coverage-lines.js +207 -0
- package/scripts/coverage-report.js +158 -0
- package/scripts/postinstall.js +61 -0
- package/test/browser/common.js +22 -1
- package/test/browser/generator/runner.config.js +20 -24
- package/test/browser/generator/template.js +14 -3
- package/test/browser/runner-browser-options.js +5 -5
- package/test/index.js +293 -98
- package/test/less-test.js +453 -94
- package/test/sourcemaps/comprehensive.json +1 -0
- package/test/sourcemaps/sourcemaps-basepath.json +1 -0
- package/test/sourcemaps/sourcemaps-include-source.json +1 -0
- package/test/sourcemaps/sourcemaps-rootpath.json +1 -0
- package/test/sourcemaps/sourcemaps-url.json +1 -0
- package/test.less +1 -0
- package/tsconfig.json +20 -20
- package/lib/less/parser/chunker.js +0 -148
- package/lib/less/parser/chunker.js.map +0 -1
- package/test/browser/runner-legacy-options.js +0 -6
- package/test/browser/runner-legacy-spec.js +0 -3
package/test/index.js
CHANGED
|
@@ -1,112 +1,307 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// Mock needle for HTTP requests BEFORE any other requires
|
|
2
|
+
const Module = require('module');
|
|
3
|
+
const originalRequire = Module.prototype.require;
|
|
4
|
+
Module.prototype.require = function(id) {
|
|
5
|
+
if (id === 'needle') {
|
|
6
|
+
return {
|
|
7
|
+
get: function(url, options, callback) {
|
|
8
|
+
|
|
9
|
+
// Handle CDN requests
|
|
10
|
+
if (url.includes('cdn.jsdelivr.net')) {
|
|
11
|
+
if (url.includes('selectors.less')) {
|
|
12
|
+
setTimeout(() => {
|
|
13
|
+
callback(null, { statusCode: 200 }, fs.readFileSync(path.join(__dirname, '../../test-data/tests-unit/selectors/selectors.less'), 'utf8'));
|
|
14
|
+
}, 10);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (url.includes('media.less')) {
|
|
18
|
+
setTimeout(() => {
|
|
19
|
+
callback(null, { statusCode: 200 }, fs.readFileSync(path.join(__dirname, '../../test-data/tests-unit/media/media.less'), 'utf8'));
|
|
20
|
+
}, 10);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (url.includes('empty.less')) {
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
callback(null, { statusCode: 200 }, fs.readFileSync(path.join(__dirname, '../../test-data/tests-unit/empty/empty.less'), 'utf8'));
|
|
26
|
+
}, 10);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle redirect test - simulate needle's automatic redirect handling
|
|
32
|
+
if (url.includes('example.com/redirect.less')) {
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
// Simulate the final response after needle automatically follows the redirect
|
|
35
|
+
callback(null, { statusCode: 200 }, 'h1 { color: blue; }');
|
|
36
|
+
}, 10);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (url.includes('example.com/target.less')) {
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
callback(null, { statusCode: 200 }, 'h1 { color: blue; }');
|
|
43
|
+
}, 10);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Default error for unmocked URLs
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
callback(new Error('Unmocked URL: ' + url), null, null);
|
|
50
|
+
}, 10);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return originalRequire.apply(this, arguments);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Now load other modules after mocking is set up
|
|
58
|
+
var path = require('path'),
|
|
59
|
+
fs = require('fs'),
|
|
60
|
+
lessTest = require('./less-test'),
|
|
61
|
+
stylize = require('../lib/less-node/lessc-helper').stylize;
|
|
62
|
+
|
|
63
|
+
// Parse command line arguments for test filtering
|
|
64
|
+
var args = process.argv.slice(2);
|
|
65
|
+
var testFilter = args.length > 0 ? args[0] : null;
|
|
66
|
+
|
|
67
|
+
// Create the test runner with the filter
|
|
68
|
+
var lessTester = lessTest(testFilter);
|
|
69
|
+
|
|
70
|
+
// HTTP mocking is now handled by needle mocking above
|
|
71
|
+
|
|
72
|
+
// Test HTTP redirect functionality
|
|
73
|
+
function testHttpRedirects() {
|
|
74
|
+
const less = require('../lib/less-node').default;
|
|
75
|
+
|
|
76
|
+
console.log('🧪 Testing HTTP redirect functionality...');
|
|
77
|
+
|
|
78
|
+
const redirectTest = `
|
|
79
|
+
@import "https://example.com/redirect.less";
|
|
80
|
+
|
|
81
|
+
h1 { color: red; }
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
return less.render(redirectTest, {
|
|
85
|
+
filename: 'test-redirect.less'
|
|
86
|
+
}).then(result => {
|
|
87
|
+
console.log('✅ HTTP redirect test SUCCESS:');
|
|
88
|
+
console.log(result.css);
|
|
89
|
+
|
|
90
|
+
// Check if both imported and local content are present
|
|
91
|
+
if (result.css.includes('color: blue') && result.css.includes('color: red')) {
|
|
92
|
+
console.log('🎉 HTTP redirect test PASSED - both imported and local content found');
|
|
93
|
+
return true;
|
|
94
|
+
} else {
|
|
95
|
+
console.log('❌ HTTP redirect test FAILED - missing expected content');
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}).catch(err => {
|
|
99
|
+
console.log('❌ HTTP redirect test ERROR:');
|
|
100
|
+
console.log(err.message);
|
|
101
|
+
return false;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Test import-remote functionality
|
|
106
|
+
function testImportRemote() {
|
|
107
|
+
const less = require('../lib/less-node').default;
|
|
108
|
+
const fs = require('fs');
|
|
109
|
+
const path = require('path');
|
|
110
|
+
|
|
111
|
+
console.log('🧪 Testing import-remote functionality...');
|
|
112
|
+
|
|
113
|
+
const testFile = path.join(__dirname, '../../test-data/tests-unit/import/import-remote.less');
|
|
114
|
+
const expectedFile = path.join(__dirname, '../../test-data/tests-unit/import/import-remote.css');
|
|
115
|
+
|
|
116
|
+
const content = fs.readFileSync(testFile, 'utf8');
|
|
117
|
+
const expected = fs.readFileSync(expectedFile, 'utf8');
|
|
118
|
+
|
|
119
|
+
return less.render(content, {
|
|
120
|
+
filename: testFile
|
|
121
|
+
}).then(result => {
|
|
122
|
+
console.log('✅ Import-remote test SUCCESS:');
|
|
123
|
+
console.log('Expected:', expected.trim());
|
|
124
|
+
console.log('Actual:', result.css.trim());
|
|
125
|
+
|
|
126
|
+
if (result.css.trim() === expected.trim()) {
|
|
127
|
+
console.log('🎉 Import-remote test PASSED - CDN imports and variable resolution working');
|
|
128
|
+
return true;
|
|
129
|
+
} else {
|
|
130
|
+
console.log('❌ Import-remote test FAILED - output mismatch');
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}).catch(err => {
|
|
134
|
+
console.log('❌ Import-remote test ERROR:');
|
|
135
|
+
console.log(err.message);
|
|
136
|
+
return false;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
6
139
|
|
|
7
140
|
console.log('\n' + stylize('Less', 'underline') + '\n');
|
|
8
141
|
|
|
142
|
+
if (testFilter) {
|
|
143
|
+
console.log('Running tests matching: ' + testFilter + '\n');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Glob patterns for main test runs (excluding problematic tests that will run separately)
|
|
147
|
+
var globPatterns = [
|
|
148
|
+
'tests-config/*/*.less',
|
|
149
|
+
'tests-unit/*/*.less',
|
|
150
|
+
// Debug tests have nested subdirectories (comments/, mediaquery/, all/)
|
|
151
|
+
'tests-config/debug/*/linenumbers-*.less',
|
|
152
|
+
'!tests-config/sourcemaps/**/*.less', // Exclude sourcemaps (need special handling)
|
|
153
|
+
'!tests-config/sourcemaps-empty/*', // Exclude sourcemaps-empty (need special handling)
|
|
154
|
+
'!tests-config/sourcemaps-disable-annotation/*', // Exclude sourcemaps-disable-annotation (need special handling)
|
|
155
|
+
'!tests-config/sourcemaps-variable-selector/*', // Exclude sourcemaps-variable-selector (need special handling)
|
|
156
|
+
'!tests-config/globalVars/*', // Exclude globalVars (need JSON config handling)
|
|
157
|
+
'!tests-config/modifyVars/*', // Exclude modifyVars (need JSON config handling)
|
|
158
|
+
'!tests-config/js-type-errors/*', // Exclude js-type-errors (need special test function)
|
|
159
|
+
'!tests-config/no-js-errors/*', // Exclude no-js-errors (need special test function)
|
|
160
|
+
'!tests-unit/import/import-remote.less', // Exclude import-remote (tested separately in isolation)
|
|
161
|
+
|
|
162
|
+
// HTTP import tests are now included since we have needle mocking
|
|
163
|
+
];
|
|
164
|
+
|
|
9
165
|
var testMap = [
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
lessTester.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
lessTester.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
[{math: 0, strictUnits: false}, 'units/no-strict/'],
|
|
47
|
-
|
|
48
|
-
[{math: 'strict', strictUnits: true, sourceMap: true, globalVars: true }, 'sourcemaps/',
|
|
49
|
-
lessTester.testSourcemap, null, null,
|
|
50
|
-
function(filename, type, baseFolder) {
|
|
166
|
+
// Main test runs using glob patterns (cosmiconfig handles configs)
|
|
167
|
+
{
|
|
168
|
+
patterns: globPatterns
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Error tests
|
|
172
|
+
{
|
|
173
|
+
patterns: ['tests-error/eval/*.less'],
|
|
174
|
+
verifyFunction: lessTester.testErrors
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
patterns: ['tests-error/parse/*.less'],
|
|
178
|
+
verifyFunction: lessTester.testErrors
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
// Special test cases with specific handling
|
|
182
|
+
{
|
|
183
|
+
patterns: ['tests-config/js-type-errors/*.less'],
|
|
184
|
+
verifyFunction: lessTester.testTypeErrors
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
patterns: ['tests-config/no-js-errors/*.less'],
|
|
188
|
+
verifyFunction: lessTester.testErrors
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
// Sourcemap tests with special handling
|
|
192
|
+
{
|
|
193
|
+
patterns: [
|
|
194
|
+
'tests-config/sourcemaps/**/*.less',
|
|
195
|
+
'tests-config/sourcemaps-url/**/*.less',
|
|
196
|
+
'tests-config/sourcemaps-rootpath/**/*.less',
|
|
197
|
+
'tests-config/sourcemaps-basepath/**/*.less',
|
|
198
|
+
'tests-config/sourcemaps-include-source/**/*.less'
|
|
199
|
+
],
|
|
200
|
+
verifyFunction: lessTester.testSourcemap,
|
|
201
|
+
getFilename: function(filename, type, baseFolder) {
|
|
51
202
|
if (type === 'vars') {
|
|
52
203
|
return path.join(baseFolder, filename) + '.json';
|
|
53
204
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return path.join(
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
205
|
+
// Extract just the filename (without directory) for the JSON file
|
|
206
|
+
var jsonFilename = path.basename(filename);
|
|
207
|
+
// For sourcemap type, return path relative to test directory
|
|
208
|
+
if (type === 'sourcemap') {
|
|
209
|
+
return path.join('test/sourcemaps', jsonFilename) + '.json';
|
|
210
|
+
}
|
|
211
|
+
return path.join('test/sourcemaps', jsonFilename) + '.json';
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
patterns: ['tests-config/sourcemaps-empty/*.less'],
|
|
216
|
+
verifyFunction: lessTester.testEmptySourcemap
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
patterns: ['tests-config/sourcemaps-disable-annotation/*.less'],
|
|
220
|
+
verifyFunction: lessTester.testSourcemapWithoutUrlAnnotation
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
patterns: ['tests-config/sourcemaps-variable-selector/*.less'],
|
|
224
|
+
verifyFunction: lessTester.testSourcemapWithVariableInSelector
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
// Import tests with JSON configs
|
|
228
|
+
{
|
|
229
|
+
patterns: ['tests-config/globalVars/*.less'],
|
|
230
|
+
lessOptions: {
|
|
231
|
+
globalVars: function(file) {
|
|
232
|
+
const fs = require('fs');
|
|
233
|
+
const path = require('path');
|
|
234
|
+
const basename = path.basename(file, '.less');
|
|
235
|
+
const jsonPath = path.join(path.dirname(file), basename + '.json');
|
|
236
|
+
try {
|
|
237
|
+
return JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
238
|
+
} catch (e) {
|
|
239
|
+
return {};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
patterns: ['tests-config/modifyVars/*.less'],
|
|
246
|
+
lessOptions: {
|
|
247
|
+
modifyVars: function(file) {
|
|
248
|
+
const fs = require('fs');
|
|
249
|
+
const path = require('path');
|
|
250
|
+
const basename = path.basename(file, '.less');
|
|
251
|
+
const jsonPath = path.join(path.dirname(file), basename + '.json');
|
|
252
|
+
try {
|
|
253
|
+
return JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
254
|
+
} catch (e) {
|
|
255
|
+
return {};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
85
260
|
];
|
|
86
|
-
|
|
87
|
-
|
|
261
|
+
|
|
262
|
+
// Note: needle mocking is set up globally at the top of the file
|
|
263
|
+
|
|
264
|
+
testMap.forEach(function(testConfig) {
|
|
265
|
+
// For glob patterns, pass lessOptions as the first parameter and patterns as the second
|
|
266
|
+
if (testConfig.patterns) {
|
|
267
|
+
lessTester.runTestSet(
|
|
268
|
+
testConfig.lessOptions || {}, // First param: options (including lessOptions)
|
|
269
|
+
testConfig.patterns, // Second param: patterns
|
|
270
|
+
testConfig.verifyFunction || null, // Third param: verifyFunction
|
|
271
|
+
testConfig.nameModifier || null, // Fourth param: nameModifier
|
|
272
|
+
testConfig.doReplacements || null, // Fifth param: doReplacements
|
|
273
|
+
testConfig.getFilename || null // Sixth param: getFilename
|
|
274
|
+
);
|
|
275
|
+
} else {
|
|
276
|
+
// Legacy format for non-glob tests
|
|
277
|
+
var args = [
|
|
278
|
+
testConfig.options || {}, // First param: options
|
|
279
|
+
testConfig.foldername, // Second param: foldername
|
|
280
|
+
testConfig.verifyFunction || null, // Third param: verifyFunction
|
|
281
|
+
testConfig.nameModifier || null, // Fourth param: nameModifier
|
|
282
|
+
testConfig.doReplacements || null, // Fifth param: doReplacements
|
|
283
|
+
testConfig.getFilename || null // Sixth param: getFilename
|
|
284
|
+
];
|
|
285
|
+
lessTester.runTestSet.apply(lessTester, args);
|
|
286
|
+
}
|
|
88
287
|
});
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
lessTester.testSyncronous({syncImport: true}, '
|
|
288
|
+
|
|
289
|
+
// Special synchronous tests
|
|
290
|
+
lessTester.testSyncronous({syncImport: true}, 'tests-unit/import/import');
|
|
291
|
+
lessTester.testSyncronous({syncImport: true}, 'tests-config/math-strict/css');
|
|
292
|
+
|
|
92
293
|
lessTester.testNoOptions();
|
|
93
294
|
lessTester.testDisablePluginRule();
|
|
94
295
|
lessTester.testJSImport();
|
|
95
296
|
lessTester.finished();
|
|
96
297
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{},
|
|
108
|
-
'import-redirect/',
|
|
109
|
-
lessTester.testImportRedirect(scope)
|
|
110
|
-
);
|
|
111
|
-
lessTester.finished();
|
|
112
|
-
})();
|
|
298
|
+
|
|
299
|
+
// Test HTTP redirect functionality
|
|
300
|
+
console.log('\nTesting HTTP redirect functionality...');
|
|
301
|
+
testHttpRedirects();
|
|
302
|
+
console.log('HTTP redirect test completed');
|
|
303
|
+
|
|
304
|
+
// Test import-remote functionality in isolation
|
|
305
|
+
console.log('\nTesting import-remote functionality...');
|
|
306
|
+
testImportRemote();
|
|
307
|
+
console.log('Import-remote test completed');
|