0
# postcss-less
1
2
postcss-less is a PostCSS syntax parser specifically designed for LESS stylesheets. It enables PostCSS transformations and plugins to work directly with LESS source code without compilation, serving as a bridge between LESS syntax and the PostCSS ecosystem.
3
4
## Package Information
5
6
- **Package Name**: postcss-less
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install postcss-less`
10
- **Node.js Version**: >=12
11
- **Peer Dependencies**: `postcss ^8.3.5`
12
13
## Core Imports
14
15
```javascript
16
const syntax = require('postcss-less');
17
```
18
19
For ES6 modules:
20
21
```javascript
22
import syntax from 'postcss-less';
23
```
24
25
Individual imports:
26
27
```javascript
28
const { parse, stringify, nodeToString } = require('postcss-less');
29
```
30
31
## Basic Usage
32
33
```javascript
34
const postcss = require('postcss');
35
const syntax = require('postcss-less');
36
37
// Parse LESS code with PostCSS
38
const lessCode = `
39
// This is an inline comment
40
@primary-color: #428bca;
41
@secondary-color: lighten(@primary-color, 20%);
42
43
.header {
44
color: @primary-color;
45
.nav {
46
background: @secondary-color;
47
}
48
}
49
50
.mixin-example() {
51
border-radius: 4px;
52
}
53
54
.button {
55
.mixin-example();
56
&:hover {
57
color: darken(@primary-color, 10%);
58
}
59
}
60
`;
61
62
// Process with PostCSS and postcss-less syntax
63
postcss([
64
// Add your PostCSS plugins here
65
])
66
.process(lessCode, { syntax })
67
.then(function (result) {
68
console.log(result.css); // Processed LESS code
69
});
70
```
71
72
## Architecture
73
74
postcss-less extends the PostCSS parser and stringifier to handle LESS-specific syntax:
75
76
- **LessParser**: Extends PostCSS Parser to recognize LESS constructs (variables, mixins, inline comments, imports with options)
77
- **LessStringifier**: Extends PostCSS Stringifier to output LESS syntax correctly
78
- **Node Handlers**: Specialized processors for different LESS node types (imports, variables, mixins, inline comments, interpolation)
79
- **AST Extensions**: Adds LESS-specific properties to PostCSS AST nodes for semantic information
80
81
## Capabilities
82
83
### LESS Parsing
84
85
Parse LESS source code into a PostCSS-compatible AST with LESS-specific node properties.
86
87
```javascript { .api }
88
/**
89
* Parse LESS source code into PostCSS AST
90
* @param {string} less - LESS source code to parse
91
* @param {Object} options - PostCSS Input options (from, map, etc.)
92
* @returns {Root} PostCSS Root AST node with LESS-specific extensions
93
*/
94
function parse(less, options);
95
```
96
97
**Usage Example:**
98
99
```javascript
100
const syntax = require('postcss-less');
101
102
const lessCode = '@color: red; .test { color: @color; }';
103
const root = syntax.parse(lessCode, { from: 'input.less' });
104
105
// Access LESS-specific node properties
106
root.walkAtRules((rule) => {
107
if (rule.variable) {
108
console.log(`Variable: ${rule.name} = ${rule.value}`);
109
}
110
});
111
```
112
113
### LESS Stringification
114
115
Convert PostCSS AST nodes back to LESS syntax strings.
116
117
```javascript { .api }
118
/**
119
* Convert PostCSS AST nodes to LESS syntax strings
120
* @param {Node} node - PostCSS AST node to stringify
121
* @param {Function} builder - String builder callback function
122
*/
123
function stringify(node, builder);
124
```
125
126
**Usage Example:**
127
128
```javascript
129
const syntax = require('postcss-less');
130
131
const lessCode = '.mixin() { color: red; }';
132
const root = syntax.parse(lessCode);
133
134
syntax.stringify(root, (str) => {
135
process.stdout.write(str);
136
});
137
```
138
139
### Node String Conversion
140
141
Convert individual AST nodes to their string representation.
142
143
```javascript { .api }
144
/**
145
* Convert a single AST node to its string representation
146
* @param {Node} node - PostCSS AST node to convert
147
* @returns {string} String representation of the node
148
*/
149
function nodeToString(node);
150
```
151
152
**Usage Example:**
153
154
```javascript
155
const syntax = require('postcss-less');
156
157
const lessCode = '@var: 10px; .test { margin: @var; }';
158
const root = syntax.parse(lessCode);
159
160
root.walkAtRules((rule) => {
161
if (rule.variable) {
162
const nodeStr = syntax.nodeToString(rule);
163
console.log(`Variable node: ${nodeStr}`);
164
}
165
});
166
```
167
168
## LESS-Specific Features
169
170
### Variable Support
171
172
LESS variables (`@variable-name: value;`) are parsed with special properties:
173
174
```javascript { .api }
175
// Variable AtRule node properties
176
interface VariableAtRule extends AtRule {
177
variable: true; // Marks node as LESS variable
178
name: string; // Variable name (without @)
179
value: string; // Variable value
180
}
181
```
182
183
### Import Support
184
185
LESS `@import` statements with options are supported:
186
187
```javascript { .api }
188
// Import AtRule node properties
189
interface ImportAtRule extends AtRule {
190
import: true; // Marks node as import
191
filename: string; // Imported filename
192
options?: string; // Import options (reference, inline, etc.)
193
}
194
```
195
196
**Example:**
197
```less
198
@import (reference) "variables.less";
199
@import "mixins.less";
200
```
201
202
### Mixin Support
203
204
LESS mixins (`.mixin()` and `#mixin`) are parsed with special properties:
205
206
```javascript { .api }
207
// Mixin AtRule node properties
208
interface MixinAtRule extends AtRule {
209
mixin: true; // Marks node as mixin call
210
important?: true; // Present if mixin uses !important
211
}
212
```
213
214
### Function Support
215
216
LESS `each` functions and other function calls are supported:
217
218
```javascript { .api }
219
// Function AtRule node properties
220
interface FunctionAtRule extends AtRule {
221
function: true; // Marks node as function call
222
params: string; // Function parameters
223
}
224
```
225
226
**Example:**
227
```less
228
each(@list, {
229
.column-@{value} {
230
width: 100% / @length;
231
}
232
});
233
```
234
235
### Interpolation Support
236
237
LESS variable interpolation (`@{variable}`) is processed during parsing to handle dynamic property names and values.
238
239
### Inline Comment Support
240
241
Double-slash comments (`//`) are supported with special properties:
242
243
```javascript { .api }
244
// Inline Comment node properties
245
interface InlineComment extends Comment {
246
inline: true; // Marks comment as inline
247
raws: {
248
begin: '//'; // Comment delimiter
249
left: string; // Whitespace before text
250
right: string; // Whitespace after text
251
};
252
}
253
```
254
255
### Extend Support
256
257
LESS `:extend()` syntax is recognized on both rules and declarations:
258
259
```javascript { .api }
260
// Extend Rule/Declaration properties
261
interface ExtendNode extends Rule | Declaration {
262
extend: true; // Marks node as using extend
263
}
264
```
265
266
## Error Handling
267
268
postcss-less follows PostCSS error handling patterns. Parse errors throw `CssSyntaxError`:
269
270
```javascript
271
const postcss = require('postcss');
272
const syntax = require('postcss-less');
273
const CssSyntaxError = require('postcss/lib/css-syntax-error');
274
275
try {
276
const result = await postcss().process('.@{]', { syntax });
277
} catch (error) {
278
if (error instanceof CssSyntaxError) {
279
console.log(`Parse error at line ${error.line}, column ${error.column}: ${error.message}`);
280
}
281
}
282
```
283
284
## PostCSS Integration
285
286
Use as a syntax plugin with PostCSS processors:
287
288
```javascript
289
const postcss = require('postcss');
290
const autoprefixer = require('autoprefixer');
291
const syntax = require('postcss-less');
292
293
// Apply autoprefixer to LESS code
294
postcss([autoprefixer])
295
.process(lessCode, {
296
syntax,
297
from: 'input.less',
298
to: 'output.less'
299
})
300
.then(result => {
301
console.log(result.css); // LESS code with vendor prefixes
302
});
303
```
304
305
## Types
306
307
```javascript { .api }
308
// Main syntax object
309
interface PostcssLessSyntax {
310
parse: (less: string, options?: ProcessOptions) => Root;
311
stringify: (node: Node, builder: (str: string) => void) => void;
312
nodeToString: (node: Node) => string;
313
}
314
315
// PostCSS types (from postcss package)
316
interface ProcessOptions {
317
from?: string;
318
to?: string;
319
map?: SourceMapOptions | boolean;
320
parser?: Parser;
321
stringifier?: Stringifier;
322
}
323
324
interface Root extends Container {
325
type: 'root';
326
walk(callback: (node: Node) => boolean | void): Root;
327
walkAtRules(callback: (atRule: AtRule) => boolean | void): Root;
328
walkComments(callback: (comment: Comment) => boolean | void): Root;
329
walkDecls(callback: (decl: Declaration) => boolean | void): Root;
330
walkRules(callback: (rule: Rule) => boolean | void): Root;
331
}
332
333
interface AtRule extends Container {
334
type: 'atrule';
335
name: string;
336
params: string;
337
// LESS extensions
338
import?: boolean;
339
filename?: string;
340
options?: string;
341
variable?: boolean;
342
value?: string;
343
mixin?: boolean;
344
function?: boolean;
345
important?: boolean;
346
}
347
348
interface Comment extends Node {
349
type: 'comment';
350
text: string;
351
// LESS extensions
352
inline?: boolean;
353
}
354
355
interface Rule extends Container {
356
type: 'rule';
357
selector: string;
358
// LESS extensions
359
extend?: boolean;
360
}
361
362
interface Declaration extends Node {
363
type: 'decl';
364
prop: string;
365
value: string;
366
// LESS extensions
367
extend?: boolean;
368
}
369
```