less 4.6.6 → 4.7.0
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/dist/less-node.cjs +168 -32
- package/dist/less.cjs +143 -26
- package/dist/less.js +143 -26
- package/dist/less.min.js +2 -2
- package/dist/less.min.js.map +1 -1
- package/lib/less/deprecation.js +5 -2
- package/lib/less/parser/parser-input.js +21 -1
- package/lib/less/parser/parser.js +112 -15
- package/lib/less/tree/nested-at-rule.js +6 -6
- package/lib/less-node/environment.js +3 -3
- package/lib/less-node/image-size.js +25 -6
- package/package.json +2 -2
package/lib/less/deprecation.js
CHANGED
|
@@ -17,10 +17,13 @@ const deprecations = {
|
|
|
17
17
|
description: 'The ./ operator is deprecated.'
|
|
18
18
|
},
|
|
19
19
|
'variable-in-unknown-value': {
|
|
20
|
-
description: '@
|
|
20
|
+
description: '@variable in custom property values is treated as literal text.'
|
|
21
|
+
},
|
|
22
|
+
'variable-in-at-rule-prelude': {
|
|
23
|
+
description: 'A bare @variable in an at-rule prelude (e.g. @media @foo) is deprecated. Use @{variable} interpolation instead.'
|
|
21
24
|
},
|
|
22
25
|
'property-in-unknown-value': {
|
|
23
|
-
description: '$
|
|
26
|
+
description: '$property in custom property values is treated as literal text.'
|
|
24
27
|
},
|
|
25
28
|
'js-eval': {
|
|
26
29
|
description: 'Inline JavaScript evaluation (backtick expressions) is deprecated and will be removed in Less 5.x.'
|
|
@@ -204,12 +204,23 @@ export default () => {
|
|
|
204
204
|
/**
|
|
205
205
|
* Permissive parsing. Ignores everything except matching {} [] () and quotes
|
|
206
206
|
* until matching token (outside of blocks)
|
|
207
|
+
*
|
|
208
|
+
* @param {string|RegExp} tok - stop token
|
|
209
|
+
* @param {boolean} [detectBareVar] - when set, also record the position of the
|
|
210
|
+
* first bare `@variable` reference (not `@{interpolation}`) that appears at
|
|
211
|
+
* PAREN depth 0 — i.e. a structural reference, not a declaration value inside
|
|
212
|
+
* `(...)`. Reuses this single pass (which already skips strings/comments) so
|
|
213
|
+
* callers don't re-scan the text. Exposed as `.bareVarIndex` on the returned
|
|
214
|
+
* group array (or null). `[...]`/`{...}` do NOT shield a reference — only
|
|
215
|
+
* `(...)` (a declaration-value group) does.
|
|
207
216
|
*/
|
|
208
|
-
parserInput.$parseUntil = tok => {
|
|
217
|
+
parserInput.$parseUntil = (tok, detectBareVar) => {
|
|
209
218
|
let quote = '';
|
|
210
219
|
let returnVal = null;
|
|
211
220
|
let inComment = false;
|
|
212
221
|
let blockDepth = 0;
|
|
222
|
+
let parenDepth = 0;
|
|
223
|
+
let bareVarIndex = null;
|
|
213
224
|
const blockStack = [];
|
|
214
225
|
const parseGroups = [];
|
|
215
226
|
const length = input.length;
|
|
@@ -249,6 +260,12 @@ export default () => {
|
|
|
249
260
|
i++;
|
|
250
261
|
continue;
|
|
251
262
|
}
|
|
263
|
+
if (detectBareVar && bareVarIndex === null && nextChar === '@' && parenDepth === 0) {
|
|
264
|
+
// A bare `@ident` (not `@{interpolation}`) outside any `(...)` —
|
|
265
|
+
// a structural reference. Strings/comments are already skipped above.
|
|
266
|
+
const after = input.charAt(i + 1);
|
|
267
|
+
if (after && /[-\w]/.test(after)) { bareVarIndex = i; }
|
|
268
|
+
}
|
|
252
269
|
switch (nextChar) {
|
|
253
270
|
case '\\':
|
|
254
271
|
i++;
|
|
@@ -284,6 +301,7 @@ export default () => {
|
|
|
284
301
|
case '(':
|
|
285
302
|
blockStack.push(')');
|
|
286
303
|
blockDepth++;
|
|
304
|
+
parenDepth++;
|
|
287
305
|
break;
|
|
288
306
|
case '[':
|
|
289
307
|
blockStack.push(']');
|
|
@@ -295,6 +313,7 @@ export default () => {
|
|
|
295
313
|
const expected = blockStack.pop();
|
|
296
314
|
if (nextChar === expected) {
|
|
297
315
|
blockDepth--;
|
|
316
|
+
if (nextChar === ')' && parenDepth > 0) { parenDepth--; }
|
|
298
317
|
} else {
|
|
299
318
|
// move the parser to the error and return expected
|
|
300
319
|
skipWhitespace(i - startPos);
|
|
@@ -310,6 +329,7 @@ export default () => {
|
|
|
310
329
|
}
|
|
311
330
|
} while (loop);
|
|
312
331
|
|
|
332
|
+
if (Array.isArray(returnVal)) { returnVal.bareVarIndex = bareVarIndex; }
|
|
313
333
|
return returnVal ? returnVal : null;
|
|
314
334
|
}
|
|
315
335
|
|
|
@@ -62,6 +62,10 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
62
62
|
|
|
63
63
|
const deprecationHandler = new DeprecationHandler();
|
|
64
64
|
|
|
65
|
+
// Tracks `${deprecationId}@${index}` pairs already warned about, so a source
|
|
66
|
+
// position that gets re-parsed via parser backtracking only warns once.
|
|
67
|
+
const warnedDeprecations = new Set();
|
|
68
|
+
|
|
65
69
|
/**
|
|
66
70
|
* @param {string} msg
|
|
67
71
|
* @param {number} index
|
|
@@ -71,6 +75,11 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
71
75
|
function warn(msg, index, type, deprecationId) {
|
|
72
76
|
if (context.quiet) { return; }
|
|
73
77
|
if (deprecationId && context.quietDeprecations) { return; }
|
|
78
|
+
if (deprecationId) {
|
|
79
|
+
const key = `${deprecationId}@${index ?? parserInput.i}`;
|
|
80
|
+
if (warnedDeprecations.has(key)) { return; }
|
|
81
|
+
warnedDeprecations.add(key);
|
|
82
|
+
}
|
|
74
83
|
if (deprecationId && !deprecationHandler.shouldWarn(deprecationId)) { return; }
|
|
75
84
|
|
|
76
85
|
logger.warn(
|
|
@@ -86,6 +95,17 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
86
95
|
);
|
|
87
96
|
}
|
|
88
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Warn that a bare `@variable` reference is being used in a non-value
|
|
100
|
+
* position (an at-rule prelude, name, or identifier), where it still
|
|
101
|
+
* resolves today but is deprecated in favour of `@{variable}` interpolation.
|
|
102
|
+
*
|
|
103
|
+
* @param {number} index - source position of the bare reference
|
|
104
|
+
*/
|
|
105
|
+
function warnBareAtRuleVariable(index) {
|
|
106
|
+
warn('A bare @variable in an at-rule prelude is deprecated. Use @{variable} interpolation instead.', index, 'DEPRECATED', 'variable-in-at-rule-prelude');
|
|
107
|
+
}
|
|
108
|
+
|
|
89
109
|
function expect(arg, msg) {
|
|
90
110
|
// some older browsers return typeof 'function' for RegExp
|
|
91
111
|
const result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg);
|
|
@@ -1636,7 +1656,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1636
1656
|
if (parserInput.$char(';')) {
|
|
1637
1657
|
value = new Anonymous('');
|
|
1638
1658
|
} else {
|
|
1639
|
-
value = this.permissiveValue(/[;}]
|
|
1659
|
+
value = this.permissiveValue(/[;}]/);
|
|
1640
1660
|
}
|
|
1641
1661
|
}
|
|
1642
1662
|
// Try to store values as anonymous
|
|
@@ -1695,8 +1715,12 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1695
1715
|
* math is allowed.
|
|
1696
1716
|
*
|
|
1697
1717
|
* @param {RexExp} untilTokens - Characters to stop parsing at
|
|
1718
|
+
* @param {boolean} [deprecateVariables] - when set, this is an at-rule
|
|
1719
|
+
* prelude (non-value position); accept `@{var}` interpolation and warn
|
|
1720
|
+
* on a bare `@var` reference (which resolves today but is deprecated).
|
|
1698
1721
|
*/
|
|
1699
|
-
permissiveValue: function (untilTokens) {
|
|
1722
|
+
permissiveValue: function (untilTokens, deprecateVariables) {
|
|
1723
|
+
const entities = this.entities;
|
|
1700
1724
|
let i;
|
|
1701
1725
|
let e;
|
|
1702
1726
|
let done;
|
|
@@ -1723,7 +1747,20 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1723
1747
|
value.push(e);
|
|
1724
1748
|
continue;
|
|
1725
1749
|
}
|
|
1726
|
-
|
|
1750
|
+
if (deprecateVariables) {
|
|
1751
|
+
// In an at-rule prelude, `@{var}` interpolation is the supported
|
|
1752
|
+
// form; consume it here so its `{` is not mistaken for a block.
|
|
1753
|
+
e = entities.variableCurly();
|
|
1754
|
+
if (!e) {
|
|
1755
|
+
const varIndex = parserInput.i;
|
|
1756
|
+
e = this.entity();
|
|
1757
|
+
if (e && e.type === 'Variable') {
|
|
1758
|
+
warnBareAtRuleVariable(varIndex);
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
} else {
|
|
1762
|
+
e = this.entity();
|
|
1763
|
+
}
|
|
1727
1764
|
if (e) {
|
|
1728
1765
|
value.push(e);
|
|
1729
1766
|
}
|
|
@@ -1750,7 +1787,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1750
1787
|
}
|
|
1751
1788
|
parserInput.save();
|
|
1752
1789
|
|
|
1753
|
-
value = parserInput.$parseUntil(tok);
|
|
1790
|
+
value = parserInput.$parseUntil(tok, deprecateVariables);
|
|
1754
1791
|
|
|
1755
1792
|
if (value) {
|
|
1756
1793
|
if (typeof value === 'string') {
|
|
@@ -1760,6 +1797,14 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1760
1797
|
parserInput.forget();
|
|
1761
1798
|
return new tree.Anonymous('', index);
|
|
1762
1799
|
}
|
|
1800
|
+
// At-rule prelude: `$parseUntil` (deprecateVariables) records the
|
|
1801
|
+
// first bare `@var` it saw outside any `(...)` in its single pass —
|
|
1802
|
+
// a structural reference (`[...]`/`{...}` don't shield it, only a
|
|
1803
|
+
// declaration-value `(...)` does). Warn once here rather than
|
|
1804
|
+
// re-scanning the text.
|
|
1805
|
+
if (deprecateVariables && value.bareVarIndex !== null && value.bareVarIndex !== undefined) {
|
|
1806
|
+
warnBareAtRuleVariable(value.bareVarIndex);
|
|
1807
|
+
}
|
|
1763
1808
|
/** @type {string} */
|
|
1764
1809
|
let item;
|
|
1765
1810
|
for (i = 0; i < value.length; i++) {
|
|
@@ -1776,11 +1821,14 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1776
1821
|
const quote = new tree.Quoted('\'', item, true, index, fileInfo);
|
|
1777
1822
|
const variableRegex = /@([\w-]+)/g;
|
|
1778
1823
|
const propRegex = /\$([\w-]+)/g;
|
|
1779
|
-
|
|
1780
|
-
|
|
1824
|
+
// At-rule preludes are handled once above via
|
|
1825
|
+
// `value.bareVarIndex`; the `variable-in-unknown-value`
|
|
1826
|
+
// notice is for unknown declaration values only.
|
|
1827
|
+
if (!deprecateVariables && variableRegex.test(item)) {
|
|
1828
|
+
warn('@variable in unknown values will not be evaluated as variables in the future. Use @{variable}', index, 'DEPRECATED', 'variable-in-unknown-value');
|
|
1781
1829
|
}
|
|
1782
1830
|
if (propRegex.test(item)) {
|
|
1783
|
-
warn('$
|
|
1831
|
+
warn('$property in unknown values will not be evaluated as property references in the future. Use ${property}', index, 'DEPRECATED', 'property-in-unknown-value');
|
|
1784
1832
|
}
|
|
1785
1833
|
quote.variableRegex = /@([\w-]+)|@{([\w-]+)}/g;
|
|
1786
1834
|
quote.propRegex = /\$([\w-]+)|\${([\w-]+)}/g;
|
|
@@ -1889,7 +1937,17 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1889
1937
|
}
|
|
1890
1938
|
parserInput.restore();
|
|
1891
1939
|
|
|
1892
|
-
e = entities.declarationCall.bind(this)() || cssKeyword() || entities.keyword() || entities.
|
|
1940
|
+
e = entities.declarationCall.bind(this)() || cssKeyword() || entities.keyword() || entities.variableCurly();
|
|
1941
|
+
if (!e) {
|
|
1942
|
+
const varIndex = parserInput.i;
|
|
1943
|
+
const bareVariable = entities.variable();
|
|
1944
|
+
if (bareVariable) {
|
|
1945
|
+
warnBareAtRuleVariable(varIndex);
|
|
1946
|
+
e = bareVariable;
|
|
1947
|
+
} else {
|
|
1948
|
+
e = entities.mixinLookup();
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1893
1951
|
if (e) {
|
|
1894
1952
|
nodes.push(e);
|
|
1895
1953
|
if (e.type === 'Variable' ||
|
|
@@ -1900,7 +1958,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1900
1958
|
let closed = false;
|
|
1901
1959
|
p = this.property();
|
|
1902
1960
|
parserInput.save();
|
|
1903
|
-
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^[
|
|
1961
|
+
if (!p && syntaxOptions.queryInParens && parserInput.$re(/^(?:[^()]|\([^()]*\))*\s*([<>]=|<=|>=|[<>]|=)/)) {
|
|
1904
1962
|
parserInput.restore();
|
|
1905
1963
|
p = this.condition();
|
|
1906
1964
|
|
|
@@ -1980,7 +2038,17 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
1980
2038
|
features[features.length - 1].noSpacing = false;
|
|
1981
2039
|
}
|
|
1982
2040
|
} else {
|
|
1983
|
-
e = entities.
|
|
2041
|
+
e = entities.variableCurly();
|
|
2042
|
+
if (!e) {
|
|
2043
|
+
const varIndex = parserInput.i;
|
|
2044
|
+
const bareVariable = entities.variable();
|
|
2045
|
+
if (bareVariable) {
|
|
2046
|
+
warnBareAtRuleVariable(varIndex);
|
|
2047
|
+
e = bareVariable;
|
|
2048
|
+
} else {
|
|
2049
|
+
e = entities.mixinLookup();
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
1984
2052
|
if (e) {
|
|
1985
2053
|
features.push(e);
|
|
1986
2054
|
if (!parserInput.$char(',')) { break; }
|
|
@@ -2094,8 +2162,24 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2094
2162
|
return null;
|
|
2095
2163
|
}
|
|
2096
2164
|
},
|
|
2165
|
+
/**
|
|
2166
|
+
* An entity in a non-value at-rule position (an at-rule identifier,
|
|
2167
|
+
* name, or keyword-list item — e.g. the name in `@keyframes @foo`).
|
|
2168
|
+
* `@{foo}` interpolation is the supported form; a bare `@foo` still
|
|
2169
|
+
* resolves but is deprecated.
|
|
2170
|
+
*/
|
|
2171
|
+
atRuleEntity: function () {
|
|
2172
|
+
const curly = this.entities.variableCurly();
|
|
2173
|
+
if (curly) { return curly; }
|
|
2174
|
+
const index = parserInput.i;
|
|
2175
|
+
const e = this.entity();
|
|
2176
|
+
if (e && e.type === 'Variable') {
|
|
2177
|
+
warnBareAtRuleVariable(index);
|
|
2178
|
+
}
|
|
2179
|
+
return e;
|
|
2180
|
+
},
|
|
2097
2181
|
atruleUnknown: function (value, name, hasBlock) {
|
|
2098
|
-
value = this.permissiveValue(/^[{;]
|
|
2182
|
+
value = this.permissiveValue(/^[{;]/, true);
|
|
2099
2183
|
hasBlock = (parserInput.currentChar() === '{');
|
|
2100
2184
|
if (!value) {
|
|
2101
2185
|
if (!hasBlock && parserInput.currentChar() !== ';') {
|
|
@@ -2111,16 +2195,16 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2111
2195
|
rules = this.blockRuleset();
|
|
2112
2196
|
parserInput.save();
|
|
2113
2197
|
if (!rules && !isRooted) {
|
|
2114
|
-
value = this.
|
|
2198
|
+
value = this.atRuleEntity();
|
|
2115
2199
|
rules = this.blockRuleset();
|
|
2116
2200
|
}
|
|
2117
2201
|
if (!rules && !isRooted) {
|
|
2118
2202
|
parserInput.restore();
|
|
2119
2203
|
var e = [];
|
|
2120
|
-
value = this.
|
|
2204
|
+
value = this.atRuleEntity();
|
|
2121
2205
|
while (parserInput.$char(',')) {
|
|
2122
2206
|
e.push(value);
|
|
2123
|
-
value = this.
|
|
2207
|
+
value = this.atRuleEntity();
|
|
2124
2208
|
}
|
|
2125
2209
|
if (value && e.length > 0) {
|
|
2126
2210
|
e.push(value);
|
|
@@ -2205,12 +2289,25 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
|
|
|
2205
2289
|
parserInput.commentStore.length = 0;
|
|
2206
2290
|
|
|
2207
2291
|
if (hasIdentifier) {
|
|
2208
|
-
value = this.
|
|
2292
|
+
value = this.atRuleEntity();
|
|
2209
2293
|
if (!value) {
|
|
2210
2294
|
error(`expected ${name} identifier`);
|
|
2211
2295
|
}
|
|
2212
2296
|
} else if (hasExpression) {
|
|
2297
|
+
// `@namespace` may carry an interpolated `@{ns}` prefix (or a
|
|
2298
|
+
// deprecated bare `@ns`). Parse that prefix directly so `@{ns}`
|
|
2299
|
+
// is accepted here without treating value positions as
|
|
2300
|
+
// interpolation contexts, then read the namespace URL.
|
|
2301
|
+
let prefix = this.entities.variableCurly();
|
|
2302
|
+
if (!prefix && parserInput.peek(/^@@?[\w-]/)) {
|
|
2303
|
+
const prefixIndex = parserInput.i;
|
|
2304
|
+
prefix = this.entities.variable();
|
|
2305
|
+
if (prefix) { warnBareAtRuleVariable(prefixIndex); }
|
|
2306
|
+
}
|
|
2213
2307
|
value = this.expression();
|
|
2308
|
+
if (prefix) {
|
|
2309
|
+
value = value ? new(tree.Expression)([prefix, ...value.value]) : prefix;
|
|
2310
|
+
}
|
|
2214
2311
|
if (!value) {
|
|
2215
2312
|
error(`expected ${name} expression`);
|
|
2216
2313
|
}
|
|
@@ -145,16 +145,16 @@ const NestableAtRulePrototype = {
|
|
|
145
145
|
self.features = new Value(self.permute(/** @type {Node[][]} */ (/** @type {unknown} */ (path))).map(
|
|
146
146
|
/** @param {Node | Node[]} path */
|
|
147
147
|
path => {
|
|
148
|
-
|
|
148
|
+
path = /** @type {Node[]} */ (path).map(
|
|
149
149
|
/** @param {Node & { toCSS?: Function }} fragment */
|
|
150
|
-
|
|
150
|
+
fragment => fragment.toCSS ? fragment : new Anonymous(/** @type {string} */ (/** @type {unknown} */ (fragment))));
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
for (i = /** @type {Node[]} */ (path).length - 1; i > 0; i--) {
|
|
153
153
|
/** @type {Node[]} */ (path).splice(i, 0, new Anonymous('and'));
|
|
154
|
-
|
|
154
|
+
}
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
return new Expression(/** @type {Node[]} */ (path));
|
|
157
|
+
}));
|
|
158
158
|
self.setParent(self.features, self);
|
|
159
159
|
|
|
160
160
|
// Fake a tree-node that doesn't output anything.
|
|
@@ -8,7 +8,7 @@ class SourceMapGeneratorFallback {
|
|
|
8
8
|
toJSON(){
|
|
9
9
|
return null;
|
|
10
10
|
}
|
|
11
|
-
}
|
|
11
|
+
}
|
|
12
12
|
|
|
13
13
|
export default {
|
|
14
14
|
encodeBase64: function encodeBase64(str) {
|
|
@@ -19,9 +19,9 @@ export default {
|
|
|
19
19
|
mimeLookup: function (filename) {
|
|
20
20
|
try {
|
|
21
21
|
const mimeModule = require('mime');
|
|
22
|
-
return mimeModule ? mimeModule.lookup(filename) :
|
|
22
|
+
return mimeModule ? mimeModule.lookup(filename) : 'application/octet-stream';
|
|
23
23
|
} catch (e) {
|
|
24
|
-
return
|
|
24
|
+
return 'application/octet-stream';
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
charsetLookup: function (mime) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
1
2
|
import { createRequire } from 'module';
|
|
2
3
|
import Dimension from '../less/tree/dimension.js';
|
|
3
4
|
import Expression from '../less/tree/expression.js';
|
|
@@ -33,27 +34,45 @@ export default environment => {
|
|
|
33
34
|
throw fileSync.error;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
let probe;
|
|
38
|
+
try {
|
|
39
|
+
probe = require('probe-image-size/sync');
|
|
40
|
+
} catch (_) {
|
|
41
|
+
return { width: 0, height: 0 };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const size = probe(readFileSync(fileSync.filename));
|
|
45
|
+
|
|
46
|
+
if (!size) {
|
|
47
|
+
throw {
|
|
48
|
+
type: 'File',
|
|
49
|
+
message: `Unrecognised image format for '${filePath}'`
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
width: size.width,
|
|
55
|
+
height: size.height
|
|
56
|
+
};
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
const imageFunctions = {
|
|
41
|
-
'image-size': function(filePathNode) {
|
|
60
|
+
'image-size': function (filePathNode) {
|
|
42
61
|
const size = imageSize(this, filePathNode);
|
|
43
62
|
return new Expression([
|
|
44
63
|
new Dimension(size.width, 'px'),
|
|
45
64
|
new Dimension(size.height, 'px')
|
|
46
65
|
]);
|
|
47
66
|
},
|
|
48
|
-
'image-width': function(filePathNode) {
|
|
67
|
+
'image-width': function (filePathNode) {
|
|
49
68
|
const size = imageSize(this, filePathNode);
|
|
50
69
|
return new Dimension(size.width, 'px');
|
|
51
70
|
},
|
|
52
|
-
'image-height': function(filePathNode) {
|
|
71
|
+
'image-height': function (filePathNode) {
|
|
53
72
|
const size = imageSize(this, filePathNode);
|
|
54
73
|
return new Dimension(size.height, 'px');
|
|
55
74
|
}
|
|
56
75
|
};
|
|
57
76
|
|
|
58
77
|
functionRegistry.addMultiple(imageFunctions);
|
|
59
|
-
};
|
|
78
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "less",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"description": "Leaner CSS",
|
|
5
5
|
"homepage": "http://lesscss.org",
|
|
6
6
|
"author": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"optionalDependencies": {
|
|
71
71
|
"errno": "^0.1.1",
|
|
72
72
|
"graceful-fs": "^4.1.2",
|
|
73
|
-
"image-size": "
|
|
73
|
+
"probe-image-size": "^7.2.3",
|
|
74
74
|
"make-dir": "^5.1.0",
|
|
75
75
|
"mime": "^1.4.1",
|
|
76
76
|
"needle": "^3.1.0",
|