@jesscss/less-parser 2.0.0-alpha.1 → 2.0.0-alpha.11

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/lib/index.cjs ADDED
@@ -0,0 +1,72 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_grammar = require("./grammar2.cjs");
3
+ let parseman = require("parseman");
4
+ let _jesscss_core = require("@jesscss/core");
5
+ let _jesscss_core_ast = require("@jesscss/core/ast");
6
+ //#region src/index.ts
7
+ function isStylesheet(value) {
8
+ return typeof value === "object" && value !== null && "type" in value && value.type === "Stylesheet" && "children" in value && Array.isArray(value.children);
9
+ }
10
+ /** Parse Less directly into the canonical AST v2 document. */
11
+ function parse(input) {
12
+ const entry = require_grammar.lessAstGrammar.Stylesheet;
13
+ const trivia = require_grammar.lessAstGrammar.whitespace;
14
+ if (entry === void 0 || trivia === void 0) throw new TypeError("Less AST grammar is missing its public document entry.");
15
+ const result = (0, parseman.run)(entry, input, {
16
+ trivia,
17
+ state: { source: input }
18
+ });
19
+ if (!result.ok) throw new require_grammar.LessParseError(result.span.start, result.expected);
20
+ if (result.unconsumedFrom !== null) {
21
+ if (result.unconsumedFrom > result.span.start) throw new require_grammar.LessParseError(result.unconsumedFrom, [], {
22
+ message: "Unexpected Less input after a complete stylesheet.",
23
+ reason: "The parser consumed a complete Less stylesheet before this token, so the remaining text is not part of any rule, declaration, or at-rule.",
24
+ fix: "Remove the extra input or wrap it in valid Less syntax."
25
+ });
26
+ throw new require_grammar.LessParseError(result.unconsumedFrom, [], {
27
+ message: "Unexpected Less syntax.",
28
+ reason: "The parser could not match this token as the start of a Less rule, declaration, or at-rule.",
29
+ fix: "Remove the token or rewrite it as valid Less syntax."
30
+ });
31
+ }
32
+ if (!isStylesheet(result.value)) throw new require_grammar.LessParseError(result.span.end, [], {
33
+ message: "Less parser did not produce a stylesheet.",
34
+ reason: "The Less parser matched the input but returned a value that is not a stylesheet document.",
35
+ fix: "Report this as a parser bug with the source that triggered it."
36
+ });
37
+ return (0, _jesscss_core_ast.withTriviaMap)((0, _jesscss_core_ast.withSourceSpan)(result.value, result.span), (0, _jesscss_core_ast.createTriviaMapFromParseman)(input, result.triviaMap));
38
+ }
39
+ /**
40
+ * Parse Less for the product plugin path. Parser packages own recognition facts;
41
+ * this boundary attaches file/source context once and returns normalized
42
+ * diagnostics for compiler and CLI consumers to render.
43
+ */
44
+ function safeParse(filePath, input) {
45
+ try {
46
+ return {
47
+ document: parse(input),
48
+ errors: [],
49
+ warnings: []
50
+ };
51
+ } catch (error) {
52
+ return {
53
+ errors: [(0, _jesscss_core.parserDiagnostic)({
54
+ dialect: "Less",
55
+ error,
56
+ filePath,
57
+ source: input
58
+ })],
59
+ warnings: []
60
+ };
61
+ }
62
+ }
63
+ //#endregion
64
+ exports.LessBareVariableInterpolationError = require_grammar.LessBareVariableInterpolationError;
65
+ exports.LessDynamicCharsetError = require_grammar.LessDynamicCharsetError;
66
+ exports.LessInlineJavaScriptError = require_grammar.LessInlineJavaScriptError;
67
+ exports.LessParseError = require_grammar.LessParseError;
68
+ exports.LessUnparenthesizedMixinGuardError = require_grammar.LessUnparenthesizedMixinGuardError;
69
+ exports.LessUnsupportedMixinNameError = require_grammar.LessUnsupportedMixinNameError;
70
+ exports.LessUnsupportedVariableNameError = require_grammar.LessUnsupportedVariableNameError;
71
+ exports.parse = parse;
72
+ exports.safeParse = safeParse;
package/lib/index.d.ts CHANGED
@@ -1,33 +1,12 @@
1
- import { type CstNode, Lexer } from 'chevrotain';
2
- import { LessActionsParser, type LessParserConfig } from './lessActionsParser.js';
3
- import type { ConditionalPick } from 'type-fest';
4
- import type { Rules, IParseResult } from '@jesscss/core';
5
- export * from './lessActionsParser.js';
6
- export * from './lessTokens.js';
7
- export type LessRules = keyof ConditionalPick<LessActionsParser, () => CstNode>;
8
- export type SyntacticContentAssistSuggestion = {
9
- nextTokenType: string;
10
- nextTokenLabel?: string;
11
- ruleStack: string[];
12
- occurrenceStack: number[];
13
- };
14
- export declare class Parser {
15
- lexer: Lexer;
16
- /** @todo - return Jess AST as parser */
17
- parser: LessActionsParser;
18
- constructor(config?: LessParserConfig);
19
- parse(text: string): IParseResult<Rules>;
20
- parse(text: string, rule: 'stylesheet', ...args: Parameters<LessActionsParser['stylesheet']>): IParseResult<Rules>;
21
- parse<T extends LessRules = LessRules>(text: string, rule?: T, ...args: Parameters<LessActionsParser[T]>): IParseResult;
22
- /**
23
- * IDE helper: suggest next possible token types at `offset` using Chevrotain's
24
- * syntactic content assist. This is syntactic-only (not semantic completion).
25
- *
26
- * Note: content assist is significantly slower than normal parsing, so it
27
- * should be called on-demand (e.g. near the cursor).
28
- */
29
- suggest(text: string, init: {
30
- offset: number;
31
- rule?: LessRules;
32
- }): SyntacticContentAssistSuggestion[];
33
- }
1
+ import { type ISafeParseResult } from '@jesscss/core';
2
+ import { type Stylesheet } from '@jesscss/core/ast';
3
+ export { LessBareVariableInterpolationError, LessDynamicCharsetError, LessInlineJavaScriptError, LessParseError, LessUnparenthesizedMixinGuardError, LessUnsupportedMixinNameError, LessUnsupportedVariableNameError } from './parse-error.js';
4
+ /** Parse Less directly into the canonical AST v2 document. */
5
+ export declare function parse(input: string): Stylesheet;
6
+ /**
7
+ * Parse Less for the product plugin path. Parser packages own recognition facts;
8
+ * this boundary attaches file/source context once and returns normalized
9
+ * diagnostics for compiler and CLI consumers to render.
10
+ */
11
+ export declare function safeParse(filePath: string, input: string): ISafeParseResult;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EACL,kCAAkC,EAClC,uBAAuB,EACvB,yBAAyB,EACzB,cAAc,EACd,kCAAkC,EAClC,6BAA6B,EAC7B,gCAAgC,EACjC,MAAM,kBAAkB,CAAC;AAa1B,8DAA8D;AAC9D,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAwC/C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAW3E"}
package/lib/index.js CHANGED
@@ -1,75 +1,63 @@
1
- import { Lexer } from 'chevrotain';
2
- import { lessTokens, lessFragments } from './lessTokens.js';
3
- import { createLexerDefinition } from '@jesscss/css-parser';
4
- import { LessActionsParser } from './lessActionsParser.js';
5
- import { LessErrorMessageProvider } from './lessErrorMessageProvider.js';
6
- export * from './lessActionsParser.js';
7
- export * from './lessTokens.js';
8
- const errorMessageProvider = new LessErrorMessageProvider();
9
- export class Parser {
10
- lexer;
11
- /** @todo - return Jess AST as parser */
12
- parser;
13
- constructor(config = {}) {
14
- config = {
15
- errorMessageProvider,
16
- /**
17
- * Override this if you want a stricter Less/CSS parser.
18
- * @todo - Allow overriding when parsing a single rule.
19
- */
20
- looseMode: true,
21
- skipValidations: process.env.TEST !== 'true',
22
- ...config
23
- };
24
- const { lexer, T } = createLexerDefinition(lessFragments(), lessTokens());
25
- this.lexer = new Lexer(lexer, {
26
- ensureOptimizations: true,
27
- skipValidations: process.env.TEST !== 'true'
28
- });
29
- this.parser = new LessActionsParser(lexer, T, config);
30
- /** Not sure why this is necessary, but Less tests were a problem */
31
- this.parse = this.parse.bind(this);
32
- }
33
- parse(text, rule = 'stylesheet', ...args) {
34
- const parser = this.parser;
35
- const lexerResult = this.lexer.tokenize(text);
36
- const lexedTokens = lexerResult.tokens;
37
- // Reset warnings BEFORE setting input, in case input setter does something that affects warnings
38
- parser.warnings = [];
39
- parser.input = lexedTokens;
40
- const tree = parser[rule](...args);
41
- // Capture warnings immediately after parsing to ensure they're not lost
42
- const warnings = [...parser.warnings];
43
- if (parser.errors.length > 0) {
44
- const firstError = parser.errors[0];
45
- const firstToken = firstError?.token;
46
- }
47
- return { tree, lexerResult, errors: parser.errors, warnings };
48
- }
49
- /**
50
- * IDE helper: suggest next possible token types at `offset` using Chevrotain's
51
- * syntactic content assist. This is syntactic-only (not semantic completion).
52
- *
53
- * Note: content assist is significantly slower than normal parsing, so it
54
- * should be called on-demand (e.g. near the cursor).
55
- */
56
- suggest(text, init) {
57
- const { offset, rule = 'stylesheet' } = init;
58
- const prefix = text.slice(0, Math.max(0, offset));
59
- const lexerResult = this.lexer.tokenize(prefix);
60
- const tokens = lexerResult.tokens;
61
- try {
62
- const paths = this.parser.computeContentAssist(rule, tokens);
63
- return paths.map(p => ({
64
- nextTokenType: p.nextTokenType.name,
65
- nextTokenLabel: p.nextTokenType.LABEL,
66
- ruleStack: p.ruleStack,
67
- occurrenceStack: p.occurrenceStack
68
- }));
69
- }
70
- catch {
71
- return [];
72
- }
73
- }
1
+ import { a as LessDynamicCharsetError, c as LessUnparenthesizedMixinGuardError, i as LessBareVariableInterpolationError, l as LessUnsupportedMixinNameError, o as LessInlineJavaScriptError, s as LessParseError, t as lessAstGrammar, u as LessUnsupportedVariableNameError } from "./grammar2.js";
2
+ import { run } from "parseman";
3
+ import { parserDiagnostic } from "@jesscss/core";
4
+ import { createTriviaMapFromParseman, withSourceSpan, withTriviaMap } from "@jesscss/core/ast";
5
+ //#region src/index.ts
6
+ function isStylesheet(value) {
7
+ return typeof value === "object" && value !== null && "type" in value && value.type === "Stylesheet" && "children" in value && Array.isArray(value.children);
74
8
  }
75
- //# sourceMappingURL=index.js.map
9
+ /** Parse Less directly into the canonical AST v2 document. */
10
+ function parse(input) {
11
+ const entry = lessAstGrammar.Stylesheet;
12
+ const trivia = lessAstGrammar.whitespace;
13
+ if (entry === void 0 || trivia === void 0) throw new TypeError("Less AST grammar is missing its public document entry.");
14
+ const result = run(entry, input, {
15
+ trivia,
16
+ state: { source: input }
17
+ });
18
+ if (!result.ok) throw new LessParseError(result.span.start, result.expected);
19
+ if (result.unconsumedFrom !== null) {
20
+ if (result.unconsumedFrom > result.span.start) throw new LessParseError(result.unconsumedFrom, [], {
21
+ message: "Unexpected Less input after a complete stylesheet.",
22
+ reason: "The parser consumed a complete Less stylesheet before this token, so the remaining text is not part of any rule, declaration, or at-rule.",
23
+ fix: "Remove the extra input or wrap it in valid Less syntax."
24
+ });
25
+ throw new LessParseError(result.unconsumedFrom, [], {
26
+ message: "Unexpected Less syntax.",
27
+ reason: "The parser could not match this token as the start of a Less rule, declaration, or at-rule.",
28
+ fix: "Remove the token or rewrite it as valid Less syntax."
29
+ });
30
+ }
31
+ if (!isStylesheet(result.value)) throw new LessParseError(result.span.end, [], {
32
+ message: "Less parser did not produce a stylesheet.",
33
+ reason: "The Less parser matched the input but returned a value that is not a stylesheet document.",
34
+ fix: "Report this as a parser bug with the source that triggered it."
35
+ });
36
+ return withTriviaMap(withSourceSpan(result.value, result.span), createTriviaMapFromParseman(input, result.triviaMap));
37
+ }
38
+ /**
39
+ * Parse Less for the product plugin path. Parser packages own recognition facts;
40
+ * this boundary attaches file/source context once and returns normalized
41
+ * diagnostics for compiler and CLI consumers to render.
42
+ */
43
+ function safeParse(filePath, input) {
44
+ try {
45
+ return {
46
+ document: parse(input),
47
+ errors: [],
48
+ warnings: []
49
+ };
50
+ } catch (error) {
51
+ return {
52
+ errors: [parserDiagnostic({
53
+ dialect: "Less",
54
+ error,
55
+ filePath,
56
+ source: input
57
+ })],
58
+ warnings: []
59
+ };
60
+ }
61
+ }
62
+ //#endregion
63
+ export { LessBareVariableInterpolationError, LessDynamicCharsetError, LessInlineJavaScriptError, LessParseError, LessUnparenthesizedMixinGuardError, LessUnsupportedMixinNameError, LessUnsupportedVariableNameError, parse, safeParse };
@@ -0,0 +1,68 @@
1
+ /** Structured failure from the public direct Less parser. */
2
+ export declare class LessParseError extends SyntaxError {
3
+ readonly code: 'parse/syntax-error';
4
+ readonly offset: number;
5
+ readonly expected: readonly string[];
6
+ readonly reason?: string;
7
+ readonly fix?: string;
8
+ constructor(offset: number, expected: readonly string[], options?: {
9
+ message?: string;
10
+ reason?: string;
11
+ fix?: string;
12
+ });
13
+ }
14
+ /** Interpolation is rejected inside the CSS @charset token. */
15
+ export declare class LessDynamicCharsetError extends SyntaxError {
16
+ readonly code: 'parse/dynamic-charset';
17
+ readonly offset: number;
18
+ readonly endOffset: number;
19
+ readonly reason = "Interpolation is not valid inside the CSS @charset token.";
20
+ readonly fix = "Use a static declaration such as @charset \"UTF-8\";";
21
+ constructor(offset: number, endOffset: number);
22
+ }
23
+ /** Executable inline backtick JavaScript is recognized so diagnostics can be precise. */
24
+ export declare class LessInlineJavaScriptError extends SyntaxError {
25
+ readonly code: 'parse/unsupported-inline-javascript';
26
+ readonly offset: number;
27
+ readonly endOffset: number;
28
+ readonly reason = "Backtick JavaScript expressions are not evaluated.";
29
+ readonly fix = "Move the expression into an explicit @from/@-from script import or a plugin function.";
30
+ constructor(offset: number, endOffset: number);
31
+ }
32
+ /** Syntax/prelude slots require explicit @{name} interpolation. */
33
+ export declare class LessBareVariableInterpolationError extends SyntaxError {
34
+ readonly code: 'parse/unsupported-bare-variable-interpolation';
35
+ readonly offset: number;
36
+ readonly endOffset: number;
37
+ readonly reason: string;
38
+ readonly fix: string;
39
+ constructor(offset: number, endOffset: number, name: string);
40
+ }
41
+ /** Legacy Less variable names are recognized so diagnostics can be precise. */
42
+ export declare class LessUnsupportedVariableNameError extends SyntaxError {
43
+ readonly code: 'parse/unsupported-variable-name';
44
+ readonly offset: number;
45
+ readonly endOffset: number;
46
+ readonly reason = "Less variable names must not be numeric-leading or dash-only.";
47
+ readonly fix: string;
48
+ constructor(offset: number, endOffset: number, name: string);
49
+ }
50
+ /** Legacy dash-only mixin names are recognized so diagnostics can be precise. */
51
+ export declare class LessUnsupportedMixinNameError extends SyntaxError {
52
+ readonly code: 'parse/unsupported-mixin-name';
53
+ readonly offset: number;
54
+ readonly endOffset: number;
55
+ readonly reason = "Dash-only Less mixin names are not supported.";
56
+ readonly fix = "Rename the mixin to a descriptive selector-like name, for example .mixin().";
57
+ constructor(offset: number, endOffset: number);
58
+ }
59
+ /** Ungrouped Less mixin guards are recognized so diagnostics can point at the guard. */
60
+ export declare class LessUnparenthesizedMixinGuardError extends SyntaxError {
61
+ readonly code: 'parse/unparenthesized-mixin-guard';
62
+ readonly offset: number;
63
+ readonly endOffset: number;
64
+ readonly reason = "Top-level Less mixin guards require each condition after when to be wrapped in parentheses.";
65
+ readonly fix = "Wrap the guard condition, for example: when (default()).";
66
+ constructor(offset: number, endOffset: number);
67
+ }
68
+ //# sourceMappingURL=parse-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-error.d.ts","sourceRoot":"","sources":["../src/parse-error.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,22 +1,31 @@
1
1
  {
2
2
  "name": "@jesscss/less-parser",
3
+ "type": "module",
3
4
  "publishConfig": {
4
5
  "access": "public"
5
6
  },
6
- "version": "2.0.0-alpha.1",
7
+ "version": "2.0.0-alpha.11",
8
+ "engines": {
9
+ "node": "^20.19.0 || >=22.12.0"
10
+ },
7
11
  "description": "Jess LESS parser",
8
- "main": "lib/index.js",
12
+ "main": "lib/index.cjs",
9
13
  "types": "lib/index.d.ts",
10
14
  "exports": {
11
15
  ".": {
12
- "import": "./lib/index.js",
13
16
  "types": "./lib/index.d.ts",
14
- "source": "./src/index.ts"
17
+ "import": "./lib/index.js",
18
+ "require": "./lib/index.cjs"
15
19
  },
16
- "./*": {
17
- "types": "./lib/*.d.ts",
18
- "import": "./lib/*.js",
19
- "source": "./src/*.ts"
20
+ "./cst": {
21
+ "types": "./lib/cst.d.ts",
22
+ "import": "./lib/cst.js",
23
+ "require": "./lib/cst.cjs"
24
+ },
25
+ "./grammar": {
26
+ "types": "./lib/grammar.d.ts",
27
+ "import": "./lib/grammar.js",
28
+ "require": "./lib/grammar.cjs"
20
29
  },
21
30
  "./package.json": "./package.json"
22
31
  },
@@ -24,15 +33,27 @@
24
33
  "lib"
25
34
  ],
26
35
  "dependencies": {
27
- "chevrotain": "^11.0.3",
28
- "chevrotain-allstar": "~0.3.0",
29
36
  "known-css-properties": "~0.37.0",
30
- "@jesscss/css-parser": "2.0.0-alpha.1",
31
- "@jesscss/core": "2.0.0-alpha.1"
37
+ "@jesscss/css-parser": "2.0.0-alpha.11"
38
+ },
39
+ "peerDependencies": {
40
+ "parseman": "^0.41.0",
41
+ "@jesscss/core": "2.0.0-alpha.11"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "@jesscss/core": {
45
+ "optional": true
46
+ }
32
47
  },
33
48
  "devDependencies": {
34
49
  "@types/node": "^18.19.31",
35
- "@jesscss/shared": "2.0.0-alpha.1"
50
+ "less": "^4.6.3",
51
+ "parseman": "^0.41.0",
52
+ "postcss-less": "~6.0.0",
53
+ "tsx": "~4.21.0",
54
+ "@jesscss/core": "2.0.0-alpha.11",
55
+ "@jesscss/shared": "2.0.0-alpha.1",
56
+ "@jesscss/parser-shared": "0.0.0"
36
57
  },
37
58
  "author": "Matthew Dean <matthew-dean@users.noreply.github.com>",
38
59
  "license": "MIT",
@@ -40,14 +61,17 @@
40
61
  "url": "https://github.com/jesscss/jess/issues"
41
62
  },
42
63
  "homepage": "https://github.com/jesscss/jess#readme",
64
+ "module": "lib/index.js",
43
65
  "scripts": {
44
66
  "ci": "pnpm build && pnpm test",
45
- "build": "pnpm compile",
46
- "compile": "tsc -p tsconfig.build.json",
47
- "dev": "tsc -p tsconfig.build.json -w",
67
+ "build": "pnpm --filter @jesscss/parser-shared build && pnpm compile",
68
+ "compile": "tsdown --tsconfig tsconfig.build.json --no-dts && tsc -p tsconfig.build.json --emitDeclarationOnly --noCheck",
69
+ "dev": "tsdown --tsconfig tsconfig.build.json --watch",
48
70
  "test": "cross-env TEST=true vitest --watch=false",
49
71
  "test:coverage": "cross-env TEST=true vitest --coverage",
50
72
  "lint:fix": "eslint --fix '**/*.{js,ts}'",
51
- "lint": "eslint '**/*.{js,ts}'"
73
+ "lint": "eslint '**/*.{js,ts}'",
74
+ "oracle:postcss-less": "node test/postcss-less-oracle.mjs",
75
+ "bench:postcss-less": "node test/postcss-less-oracle.mjs --bench"
52
76
  }
53
77
  }
@@ -1 +0,0 @@
1
- export declare const syncLog: (data: object) => void;
@@ -1,34 +0,0 @@
1
- /**
2
- * Synchronous debug logging utility for tests.
3
- * This file is in __tests__ so it won't be included in the public API.
4
- */
5
- import { appendFileSync, existsSync, mkdirSync } from 'fs';
6
- import { join, dirname } from 'path';
7
- // Find monorepo root by looking for pnpm-workspace.yaml
8
- function findMonorepoRoot(start) {
9
- let dir = start;
10
- while (dir !== '/') {
11
- if (existsSync(join(dir, 'pnpm-workspace.yaml'))) {
12
- return dir;
13
- }
14
- dir = dirname(dir);
15
- }
16
- return process.cwd();
17
- }
18
- const ROOT = findMonorepoRoot(__dirname);
19
- const LOG_DIR = join(ROOT, '.cursor');
20
- const LOG_PATH = process.env.DEBUG_LOG_PATH || join(LOG_DIR, 'debug.log');
21
- // Ensure directory exists
22
- try {
23
- mkdirSync(LOG_DIR, { recursive: true });
24
- }
25
- catch { }
26
- export const syncLog = (data) => {
27
- try {
28
- appendFileSync(LOG_PATH, JSON.stringify(data) + '\n');
29
- }
30
- catch {
31
- // Ignore errors
32
- }
33
- };
34
- //# sourceMappingURL=debug-log.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"debug-log.js","sourceRoot":"","sources":["../../src/__tests__/debug-log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAErC,wDAAwD;AACxD,SAAS,gBAAgB,CAAC,KAAa;IACrC,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,OAAO,GAAG,KAAK,GAAG,EAAE,CAAC;QACnB,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,GAAG,CAAC;QACb,CAAC;QACD,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AAE1E,0BAA0B;AAC1B,IAAI,CAAC;IAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAAC,CAAC;AAAC,MAAM,CAAC,CAAA,CAAC;AAEzD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE;IACtC,IAAI,CAAC;QACH,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;AACH,CAAC,CAAC"}
package/lib/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,156 +0,0 @@
1
- import type { TokenVocabulary, TokenType, IToken } from 'chevrotain';
2
- import { type Rule, type RuleContext as CssRuleContext, type CssParserConfig, CssActionsParser, type CssTokenType, type TokenMap as CssTokenMap } from '@jesscss/css-parser';
3
- import { Reference, type MathMode, type Node, type Extend, type ComplexSelector, type Selector } from '@jesscss/core';
4
- import { type LessExtraTokenType } from './lessTokens.js';
5
- export type LessParserConfig = CssParserConfig & {
6
- /**
7
- * Is less strict with certain CSS rules and Less syntax
8
- * that the old Less parser allowed.
9
- *
10
- * @note This will also enable CSS legacyMode unless
11
- * legacyMode is explicitly false.
12
- */
13
- looseMode?: boolean;
14
- /**
15
- * Controls whether mixins and detached rulesets "leak" their inner rules.
16
- * When true (default):
17
- * - Mixins: Mixin and VarDeclaration nodes are 'public' and 'optional' respectively
18
- * - Detached rulesets: Mixin and VarDeclaration nodes are 'public' and 'private' respectively
19
- * When false:
20
- * - Both mixins and detached rulesets: Mixin and VarDeclaration nodes are 'private'
21
- */
22
- leakyRules?: boolean;
23
- /**
24
- * Less math evaluation mode. Used during parsing to decide whether a given
25
- * `Operation` should be represented as an `Expression` for Less→Jess conversion.
26
- *
27
- * Mirrors runtime behavior in `Context.shouldOperate()`.
28
- *
29
- * @default 'parens-division'
30
- */
31
- mathMode?: MathMode;
32
- /**
33
- * When enabled (default), the parser will wrap the *outermost* Less math/value
34
- * expressions (math operations, variable references, and chained mixin/variable
35
- * calls) in an `Expression({ parens: true })`.
36
- *
37
- * This is purely a parse-time AST shape choice to support Less→Jess conversion.
38
- *
39
- * @default true
40
- */
41
- wrapOuterExpressions?: boolean;
42
- };
43
- export type CombinedTokenMap = Record<CssTokenType, TokenType> & Record<LessExtraTokenType, TokenType>;
44
- export type TokenMap = CombinedTokenMap;
45
- export interface ExtendTarget {
46
- selector?: Selector;
47
- target: Selector;
48
- flag: IToken | undefined;
49
- }
50
- export type RuleContext = CssRuleContext & {
51
- selector?: Selector;
52
- hasDefault?: boolean;
53
- /** Selectors in a selector sequence are extended */
54
- allExtended?: boolean;
55
- /** Mixin definition */
56
- isDefinition?: boolean;
57
- allowAnonymousMixins?: boolean;
58
- requireAccessorsAfterMixinCall?: boolean;
59
- inValueList?: boolean;
60
- allowComma?: boolean;
61
- /** Allow passing in the currently constructed Node */
62
- node?: Node;
63
- ruleIsFinished?: boolean;
64
- sequences?: Array<ComplexSelector | Extend>;
65
- asReference?: boolean;
66
- /** For :extend(...) */
67
- extendTargets?: ExtendTarget[];
68
- extendNodes?: Extend[];
69
- /** Inside an extend production - prevents 'all' from being consumed as selector */
70
- inExtend?: boolean;
71
- /** Inside a custom property value - used for deprecation warnings */
72
- inCustomPropertyValue?: boolean;
73
- /**
74
- * When true, the current production should wrap the *outermost* parsed value
75
- * (if it is a Less expression) in `Expression({ parens: true })`.
76
- *
77
- * This flag should only be set by value-entry productions (e.g. `valueSequence`)
78
- * and must be cleared for nested parsing so Expressions never contain Expressions.
79
- */
80
- wrapInExpression?: boolean;
81
- /**
82
- * Parse-time equivalent of `Context.parenFrames`. This is a boolean stack
83
- * (not a depth counter) because some productions (notably `Call`) intentionally
84
- * push `false` to disable the ambient "in parens" math behavior.
85
- */
86
- parenFrames?: boolean[];
87
- /**
88
- * Parse-time equivalent of `Context.calcFrames`.
89
- */
90
- calcFrames?: number;
91
- /**
92
- * Tracks where a detached ruleset literal is parsed from so we can
93
- * disambiguate Collection vs anonymous mixin semantics.
94
- */
95
- detachedRulesetUsage?: 'function-arg' | 'mixin-arg' | 'default-param';
96
- };
97
- /**
98
- * Unlike the historical Less parser, this parser
99
- * avoids all backtracking
100
- */
101
- export declare class LessActionsParser extends CssActionsParser {
102
- T: CssTokenMap;
103
- looseMode: boolean;
104
- leakyRules: boolean;
105
- /** Warnings collected during parsing */
106
- warnings: Array<{
107
- message: string;
108
- token?: IToken;
109
- deprecation?: string;
110
- }>;
111
- expressionSum: Rule;
112
- expressionProduct: Rule;
113
- expressionValue: Rule;
114
- functionValueList: Rule;
115
- ifFunction: Rule;
116
- booleanFunction: Rule;
117
- wrappedDeclarationList: Rule;
118
- varDeclarationOrCall: Rule;
119
- varName: Rule;
120
- selectorCapture: Rule;
121
- valueReference: Rule;
122
- varReference: Rule;
123
- mixinReference: Rule;
124
- mixinName: Rule;
125
- mixinOrQualifiedRule: Rule;
126
- qualifiedRuleBody: Rule;
127
- mixinArgs: Rule;
128
- mixinArgList: Rule;
129
- mixinArg: Rule;
130
- anonymousMixinDefinition: Rule;
131
- callArgument: Rule;
132
- extend: Rule;
133
- ampersandExtend: Rule;
134
- lookupOrCall: Rule;
135
- comparison: Rule;
136
- guard: Rule;
137
- guardDefault: Rule;
138
- guardOr: Rule;
139
- guardAnd: Rule;
140
- guardInParens: Rule;
141
- guardInner: Rule;
142
- guardWithCondition: Rule;
143
- guardWithConditionValue: Rule;
144
- exportAtRule: Rule;
145
- /** See `LessParserConfig.mathMode` */
146
- mathMode: MathMode;
147
- /** See `LessParserConfig.wrapOuterExpressions` */
148
- wrapOuterExpressions: boolean;
149
- constructor(tokenVocabulary: TokenVocabulary, T: any, config?: LessParserConfig);
150
- protected processValueToken(token: IToken, ctx?: RuleContext): Reference | Node<unknown, import("core/lib/tree/node-base.js").NodeOptions>;
151
- /**
152
- * Emits a deprecation warning during parsing.
153
- * Only collects warnings during the non-recording phase.
154
- */
155
- protected warnDeprecation(message: string, token?: IToken, deprecationId?: string): void;
156
- }