@markuplint/pug-parser 4.6.22 → 4.18.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/ARCHITECTURE.ja.md +436 -0
- package/ARCHITECTURE.md +436 -0
- package/CHANGELOG.md +9 -1
- package/SKILL.md +118 -0
- package/docs/maintenance.ja.md +188 -0
- package/docs/maintenance.md +188 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/parser.d.ts +38 -0
- package/lib/parser.js +43 -0
- package/lib/pug-parser/index.d.ts +9 -0
- package/lib/pug-parser/index.js +99 -3
- package/lib/types.d.ts +29 -0
- package/lib/utils/get-offset-from-line-and-col.d.ts +10 -0
- package/lib/utils/get-offset-from-line-and-col.js +10 -0
- package/package.json +5 -5
package/lib/pug-parser/index.js
CHANGED
|
@@ -3,6 +3,15 @@ import lexer from 'pug-lexer';
|
|
|
3
3
|
import parser from 'pug-parser';
|
|
4
4
|
import { getOffsetFromLineAndCol } from '../utils/get-offset-from-line-and-col.js';
|
|
5
5
|
import { getOffsetsFromCode } from '@markuplint/parser-utils/location';
|
|
6
|
+
/**
|
|
7
|
+
* Parses a Pug template string into an optimized AST with computed offsets
|
|
8
|
+
* and location data by lexing with pug-lexer, parsing with pug-parser,
|
|
9
|
+
* and then enriching each node with raw source, offsets, and end positions.
|
|
10
|
+
*
|
|
11
|
+
* @param pug - The raw Pug template source code
|
|
12
|
+
* @param useOffset - Whether to strip indent/outdent tokens (used when parsing at a non-zero offset)
|
|
13
|
+
* @returns The optimized Pug AST block containing enriched nodes
|
|
14
|
+
*/
|
|
6
15
|
export function pugParse(pug, useOffset = false) {
|
|
7
16
|
let lexOrigin = lexer(pug);
|
|
8
17
|
/**
|
|
@@ -23,6 +32,13 @@ export function pugParse(pug, useOffset = false) {
|
|
|
23
32
|
const ast = optimizeAST(originAst, lex, pug);
|
|
24
33
|
return ast;
|
|
25
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Computes the cumulative character offset at the end of each line
|
|
37
|
+
* in the given source string.
|
|
38
|
+
*
|
|
39
|
+
* @param pug - The raw Pug template source code
|
|
40
|
+
* @returns An array where each index corresponds to a line and the value is the cumulative offset
|
|
41
|
+
*/
|
|
26
42
|
function getOffsetsFromLines(pug) {
|
|
27
43
|
const lines = pug.split(/\n/);
|
|
28
44
|
let chars = 0;
|
|
@@ -32,6 +48,14 @@ function getOffsetsFromLines(pug) {
|
|
|
32
48
|
});
|
|
33
49
|
return result;
|
|
34
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Merges consecutive Text nodes into a single Text node, combining
|
|
53
|
+
* their raw source and extending the end location of the first node.
|
|
54
|
+
*
|
|
55
|
+
* @param nodes - The array of AST nodes to process
|
|
56
|
+
* @param pug - The raw Pug template source code
|
|
57
|
+
* @returns A new array with adjacent Text nodes merged together
|
|
58
|
+
*/
|
|
35
59
|
function mergeTextNode(
|
|
36
60
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
37
61
|
nodes, pug) {
|
|
@@ -50,10 +74,14 @@ nodes, pug) {
|
|
|
50
74
|
return baseNodes;
|
|
51
75
|
}
|
|
52
76
|
/**
|
|
77
|
+
* Transforms the raw pug-parser AST into an optimized AST by computing
|
|
78
|
+
* accurate source offsets, raw text slices, and end positions for each node.
|
|
79
|
+
* Recursively processes child blocks and merges adjacent text nodes.
|
|
53
80
|
*
|
|
54
|
-
* @param originalAST
|
|
55
|
-
* @param tokens
|
|
56
|
-
* @param pug
|
|
81
|
+
* @param originalAST - The raw AST block from pug-parser, or null
|
|
82
|
+
* @param tokens - The lexed token list from pug-lexer
|
|
83
|
+
* @param pug - The raw Pug template source code
|
|
84
|
+
* @returns The optimized AST block with enriched location data
|
|
57
85
|
*/
|
|
58
86
|
function optimizeAST(
|
|
59
87
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
@@ -471,6 +499,17 @@ tokens, pug) {
|
|
|
471
499
|
line: originalAST.line,
|
|
472
500
|
};
|
|
473
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* Recursively processes conditional node chains (`else if` / `else`) in the Pug AST,
|
|
504
|
+
* computing location data for each alternate branch.
|
|
505
|
+
*
|
|
506
|
+
* @param node - The Pug conditional AST node with potential alternate branches
|
|
507
|
+
* @param tokens - The lexed token list from pug-lexer
|
|
508
|
+
* @param pug - The raw Pug template source code
|
|
509
|
+
* @param offsets - Precomputed line offset array
|
|
510
|
+
* @param depth - The current recursion depth for tracking nested conditionals
|
|
511
|
+
* @returns An array of optimized conditional nodes for the alternate branches
|
|
512
|
+
*/
|
|
474
513
|
function optimizeASTOfConditionalNode(
|
|
475
514
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
476
515
|
node,
|
|
@@ -548,6 +587,17 @@ tokens, pug, offsets, depth) {
|
|
|
548
587
|
}
|
|
549
588
|
return altNodes;
|
|
550
589
|
}
|
|
590
|
+
/**
|
|
591
|
+
* Finds the matching lexer token for a node at the given position and returns
|
|
592
|
+
* its end location and length.
|
|
593
|
+
*
|
|
594
|
+
* @param offset - The character offset of the node's start
|
|
595
|
+
* @param line - The 1-based line number of the node
|
|
596
|
+
* @param column - The 1-based column number of the node
|
|
597
|
+
* @param tokens - The lexed token list from pug-lexer
|
|
598
|
+
* @param tokenType - Optional token type(s) to filter by
|
|
599
|
+
* @returns An object with endLine, endColumn, endOffset, and length
|
|
600
|
+
*/
|
|
551
601
|
function getLocationFromToken(offset, line, column,
|
|
552
602
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
553
603
|
tokens, tokenType) {
|
|
@@ -572,6 +622,17 @@ tokens, tokenType) {
|
|
|
572
622
|
length,
|
|
573
623
|
};
|
|
574
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* Extracts and enriches attribute data from the original Pug AST attributes
|
|
627
|
+
* by correlating each attribute with its corresponding lexer token to compute
|
|
628
|
+
* accurate offsets and raw source slices.
|
|
629
|
+
*
|
|
630
|
+
* @param originalAttrs - The original attribute list from the Pug AST
|
|
631
|
+
* @param tokens - The lexed token list from pug-lexer
|
|
632
|
+
* @param offsets - Precomputed line offset array
|
|
633
|
+
* @param pug - The raw Pug template source code
|
|
634
|
+
* @returns An array of enriched attribute objects with computed location data
|
|
635
|
+
*/
|
|
575
636
|
function getAttrs(
|
|
576
637
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
577
638
|
originalAttrs,
|
|
@@ -609,6 +670,19 @@ tokens, offsets, pug) {
|
|
|
609
670
|
}
|
|
610
671
|
return attrs;
|
|
611
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Determines the end position of a tag node including its attributes
|
|
675
|
+
* by scanning lexer tokens that follow the tag's position and precede
|
|
676
|
+
* non-attribute tokens.
|
|
677
|
+
*
|
|
678
|
+
* @param nodeName - The tag name of the element
|
|
679
|
+
* @param offset - The character offset of the tag's start
|
|
680
|
+
* @param line - The 1-based line number of the tag
|
|
681
|
+
* @param column - The 1-based column number of the tag
|
|
682
|
+
* @param tokens - The lexed token list from pug-lexer
|
|
683
|
+
* @param offsets - Precomputed line offset array
|
|
684
|
+
* @returns An object with endOffset, endLine, and endColumn
|
|
685
|
+
*/
|
|
612
686
|
function getEndAttributeLocation(nodeName, offset, line, column,
|
|
613
687
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
614
688
|
tokens, offsets) {
|
|
@@ -638,6 +712,15 @@ tokens, offsets) {
|
|
|
638
712
|
endColumn: column + nodeName.length,
|
|
639
713
|
};
|
|
640
714
|
}
|
|
715
|
+
/**
|
|
716
|
+
* Detects whether a Text node is part of a pipeless text block (indented
|
|
717
|
+
* text content below a tag) and returns its full span if so.
|
|
718
|
+
*
|
|
719
|
+
* @param node - The Pug Text AST node to check
|
|
720
|
+
* @param pug - The raw Pug template source code
|
|
721
|
+
* @param tokens - The lexed token list from pug-lexer
|
|
722
|
+
* @returns Location data for the pipeless text span, or null if not pipeless text
|
|
723
|
+
*/
|
|
641
724
|
function getPipelessText(
|
|
642
725
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
643
726
|
node, pug,
|
|
@@ -674,6 +757,19 @@ tokens) {
|
|
|
674
757
|
}
|
|
675
758
|
return null;
|
|
676
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Extracts raw text content and computes accurate end locations for a Text node
|
|
762
|
+
* by walking through lexer tokens from the node's start position. Handles
|
|
763
|
+
* multi-line text, piped text detection, and indentation tracking.
|
|
764
|
+
*
|
|
765
|
+
* @param val - The text value from the Pug AST node
|
|
766
|
+
* @param offset - The character offset where the text starts
|
|
767
|
+
* @param line - The 1-based start line number
|
|
768
|
+
* @param column - The 1-based start column number
|
|
769
|
+
* @param tokens - The lexed token list from pug-lexer
|
|
770
|
+
* @param pug - The raw Pug template source code
|
|
771
|
+
* @returns An array of ASTText nodes with computed location data
|
|
772
|
+
*/
|
|
677
773
|
function getRawTextAndLocationEnd(val, offset, line, column,
|
|
678
774
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
679
775
|
tokens, pug) {
|
package/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Additional location and raw source data that is computed during AST optimization
|
|
3
|
+
* and appended to the original Pug AST node types.
|
|
4
|
+
*/
|
|
1
5
|
export type AdditionalASTData = {
|
|
2
6
|
raw: string;
|
|
3
7
|
offset: number;
|
|
@@ -5,59 +9,84 @@ export type AdditionalASTData = {
|
|
|
5
9
|
endLine: number;
|
|
6
10
|
endColumn: number;
|
|
7
11
|
};
|
|
12
|
+
/** Union of all optimized Pug AST node types that the parser can produce. */
|
|
8
13
|
export type ASTNode = ASTDoctype | ASTComment | ASTBlockComment | ASTText | ASTTag | ASTInterpolatedTag | ASTCode | ASTConditional | ASTCase | ASTWhen | ASTWhile | ASTEach | ASTMixin | ASTMixinBlock | ASTYieldBlock | ASTFileReference | ASTInclude | ASTRawInclude | ASTIncludeFilter | ASTExtends | ASTNamedBlock | ASTFilter;
|
|
14
|
+
/** Represents a Pug block containing an ordered list of child nodes. */
|
|
9
15
|
export type ASTBlock = {
|
|
10
16
|
type: 'Block';
|
|
11
17
|
nodes: readonly ASTNode[];
|
|
12
18
|
line: number;
|
|
13
19
|
};
|
|
20
|
+
/** An optimized Pug doctype node with computed location data. */
|
|
14
21
|
export type ASTDoctype = PugAST.Doctype & AdditionalASTData;
|
|
22
|
+
/** An optimized Pug single-line comment node with computed location data. */
|
|
15
23
|
export type ASTComment = PugAST.Comments.Comment & AdditionalASTData;
|
|
24
|
+
/** An optimized Pug block comment node with computed location data and an optimized child block. */
|
|
16
25
|
export type ASTBlockComment = Omit<PugAST.Comments.BlockComment, 'block'> & {
|
|
17
26
|
block: ASTBlock | null;
|
|
18
27
|
} & AdditionalASTData;
|
|
28
|
+
/** An optimized Pug text node with computed location data. */
|
|
19
29
|
export type ASTText = PugAST.Text & AdditionalASTData;
|
|
30
|
+
/** An optimized Pug tag node with computed attributes and child block. */
|
|
20
31
|
export type ASTTag = Omit<PugAST.Tag, 'attrs' | 'block'> & {
|
|
21
32
|
attrs: readonly ASTAttr[];
|
|
22
33
|
block: ASTBlock | null;
|
|
23
34
|
} & AdditionalASTData;
|
|
35
|
+
/** An optimized Pug interpolated tag node with computed child block. */
|
|
24
36
|
export type ASTInterpolatedTag = Omit<PugAST.InterpolatedTag, 'block'> & {
|
|
25
37
|
block: ASTBlock | null;
|
|
26
38
|
} & AdditionalASTData;
|
|
39
|
+
/** An optimized Pug code node (unbuffered/buffered JavaScript) with computed child block. */
|
|
27
40
|
export type ASTCode = Omit<PugAST.Code, 'block'> & {
|
|
28
41
|
block: ASTBlock | null;
|
|
29
42
|
} & AdditionalASTData;
|
|
43
|
+
/** An optimized Pug conditional (`if`/`else if`/`else`) node with computed child block. */
|
|
30
44
|
export type ASTConditional = Omit<PugAST.CodeHelpers.Conditional, 'consequent' | 'alternate'> & {
|
|
31
45
|
block: ASTBlock | null;
|
|
32
46
|
} & AdditionalASTData;
|
|
47
|
+
/** An optimized Pug `case` node with computed child block. */
|
|
33
48
|
export type ASTCase = Omit<PugAST.CodeHelpers.CaseWhen.Case, 'block'> & {
|
|
34
49
|
block: ASTBlock | null;
|
|
35
50
|
} & AdditionalASTData;
|
|
51
|
+
/** An optimized Pug `when` node with computed child block. */
|
|
36
52
|
export type ASTWhen = Omit<PugAST.CodeHelpers.CaseWhen.When, 'block'> & {
|
|
37
53
|
block: ASTBlock | null;
|
|
38
54
|
} & AdditionalASTData;
|
|
55
|
+
/** An optimized Pug `while` loop node with computed location data. */
|
|
39
56
|
export type ASTWhile = PugAST.While & AdditionalASTData;
|
|
57
|
+
/** An optimized Pug `each` iteration node with computed child block. */
|
|
40
58
|
export type ASTEach = Omit<PugAST.Each, 'block' | 'alternate'> & {
|
|
41
59
|
block: ASTBlock | null;
|
|
42
60
|
} & AdditionalASTData;
|
|
61
|
+
/** An optimized Pug mixin (definition or call) node with computed child block. */
|
|
43
62
|
export type ASTMixin = Omit<PugAST.Mixin, 'block'> & {
|
|
44
63
|
block: ASTBlock | null;
|
|
45
64
|
} & AdditionalASTData;
|
|
65
|
+
/** An optimized Pug `block` placeholder inside a mixin definition. */
|
|
46
66
|
export type ASTMixinBlock = PugAST.MixinBlock & AdditionalASTData;
|
|
67
|
+
/** An optimized Pug `yield` block placeholder. */
|
|
47
68
|
export type ASTYieldBlock = PugAST.YieldBlock & AdditionalASTData;
|
|
69
|
+
/** An optimized Pug file reference node with computed location data. */
|
|
48
70
|
export type ASTFileReference = PugAST.FileOperations.FileReference & AdditionalASTData;
|
|
71
|
+
/** An optimized Pug `include` node with computed child block. */
|
|
49
72
|
export type ASTInclude = Omit<PugAST.FileOperations.Include, 'block'> & {
|
|
50
73
|
block: ASTBlock | null;
|
|
51
74
|
} & AdditionalASTData;
|
|
75
|
+
/** An optimized Pug raw `include` node with computed location data. */
|
|
52
76
|
export type ASTRawInclude = PugAST.FileOperations.RawInclude & AdditionalASTData;
|
|
77
|
+
/** An optimized Pug include filter node with computed location data. */
|
|
53
78
|
export type ASTIncludeFilter = PugAST.FileOperations.IncludeFilter & AdditionalASTData;
|
|
79
|
+
/** An optimized Pug `extends` node with computed location data. */
|
|
54
80
|
export type ASTExtends = PugAST.FileOperations.Extends & AdditionalASTData;
|
|
81
|
+
/** An optimized Pug named block node with computed child nodes. */
|
|
55
82
|
export type ASTNamedBlock = Omit<PugAST.FileOperations.NamedBlock, 'nodes'> & {
|
|
56
83
|
nodes: readonly ASTNode[];
|
|
57
84
|
} & AdditionalASTData;
|
|
85
|
+
/** An optimized Pug filter node with computed child block. */
|
|
58
86
|
export type ASTFilter = Omit<PugAST.Filter, 'block'> & {
|
|
59
87
|
block: ASTBlock | null;
|
|
60
88
|
} & AdditionalASTData;
|
|
89
|
+
/** An optimized Pug attribute with computed location and raw source data. */
|
|
61
90
|
export type ASTAttr = PugAST.AbstractNodeTypes.Attribute & AdditionalASTData;
|
|
62
91
|
export declare namespace PugAST {
|
|
63
92
|
/**
|
|
@@ -1 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the character offset in a string from a 1-based line number
|
|
3
|
+
* and 1-based column number. Handles multi-byte characters correctly
|
|
4
|
+
* by splitting lines into individual characters.
|
|
5
|
+
*
|
|
6
|
+
* @param str - The source string to compute the offset within
|
|
7
|
+
* @param line - The 1-based line number
|
|
8
|
+
* @param col - The 1-based column number
|
|
9
|
+
* @returns The 0-based character offset corresponding to the given line and column
|
|
10
|
+
*/
|
|
1
11
|
export declare function getOffsetFromLineAndCol(str: string, line: number, col: number): number;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the character offset in a string from a 1-based line number
|
|
3
|
+
* and 1-based column number. Handles multi-byte characters correctly
|
|
4
|
+
* by splitting lines into individual characters.
|
|
5
|
+
*
|
|
6
|
+
* @param str - The source string to compute the offset within
|
|
7
|
+
* @param line - The 1-based line number
|
|
8
|
+
* @param col - The 1-based column number
|
|
9
|
+
* @returns The 0-based character offset corresponding to the given line and column
|
|
10
|
+
*/
|
|
1
11
|
export function getOffsetFromLineAndCol(str, line, col) {
|
|
2
12
|
const lines = str.split('\n').slice(0, line);
|
|
3
13
|
const lastLine = lines.pop();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/pug-parser",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.18.0",
|
|
4
4
|
"description": "Pug parser for markuplint",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@markuplint/html-parser": "4.
|
|
25
|
-
"@markuplint/ml-ast": "4.
|
|
26
|
-
"@markuplint/parser-utils": "4.
|
|
24
|
+
"@markuplint/html-parser": "4.18.0",
|
|
25
|
+
"@markuplint/ml-ast": "4.18.0",
|
|
26
|
+
"@markuplint/parser-utils": "4.18.0",
|
|
27
27
|
"pug-lexer": "5.0.1",
|
|
28
28
|
"pug-parser": "6.0.0"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "1885af6349def3f19df975b9e9c399dd47361de1"
|
|
31
31
|
}
|