@markuplint/alpine-parser 4.6.22 → 5.0.0-alpha.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/CHANGELOG.md +9 -2
- package/README.md +2 -2
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/parser.d.ts +25 -6
- package/lib/parser.js +47 -182
- package/lib/spec.d.ts +8 -0
- package/lib/spec.js +10 -0
- package/package.json +7 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,13 +3,20 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
# [5.0.0-alpha.0](https://github.com/markuplint/markuplint/compare/v4.14.1...v5.0.0-alpha.0) (2026-02-20)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **alpine-parser:** support loop blocks ([d92c53c](https://github.com/markuplint/markuplint/commit/d92c53ce7337a2b39f78cbc43edbe1aba2232bae))
|
|
11
|
+
- delete htmx-parser, simplify alpine-parser, add migration guide and tests ([f8dbb09](https://github.com/markuplint/markuplint/commit/f8dbb090707d8cfbf3d859a9b868b2087064f89b))
|
|
9
12
|
|
|
13
|
+
## [4.6.23](https://github.com/markuplint/markuplint/compare/@markuplint/alpine-parser@4.6.22...@markuplint/alpine-parser@4.6.23) (2026-02-10)
|
|
10
14
|
|
|
15
|
+
**Note:** Version bump only for package @markuplint/alpine-parser
|
|
11
16
|
|
|
17
|
+
## [4.6.22](https://github.com/markuplint/markuplint/compare/@markuplint/alpine-parser@4.6.21...@markuplint/alpine-parser@4.6.22) (2025-11-05)
|
|
12
18
|
|
|
19
|
+
**Note:** Version bump only for package @markuplint/alpine-parser
|
|
13
20
|
|
|
14
21
|
## [4.6.21](https://github.com/markuplint/markuplint/compare/@markuplint/alpine-parser@4.6.20...@markuplint/alpine-parser@4.6.21) (2025-08-24)
|
|
15
22
|
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ $ yarn add -D @markuplint/alpine-parser
|
|
|
14
14
|
|
|
15
15
|
## Usage
|
|
16
16
|
|
|
17
|
-
Add `parser` and `
|
|
17
|
+
Add `parser` and `specs` option to your [configuration](https://markuplint.dev/configuration/#properties/parser).
|
|
18
18
|
|
|
19
19
|
```json
|
|
20
20
|
{
|
|
@@ -22,7 +22,7 @@ Add `parser` and `spec` option to your [configuration](https://markuplint.dev/co
|
|
|
22
22
|
"\\.html$": "@markuplint/alpine-parser"
|
|
23
23
|
},
|
|
24
24
|
"specs": {
|
|
25
|
-
"\\.html$": "@markuplint/alpine-
|
|
25
|
+
"\\.html$": "@markuplint/alpine-spec"
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
```
|
package/lib/index.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @markuplint/alpine-parser
|
|
3
|
+
* Markuplint parser plugin for Alpine.js templates. Extends the standard HTML parser
|
|
4
|
+
* to recognize Alpine.js directives (e.g., x-data, x-bind, x-on) and treat them
|
|
5
|
+
* appropriately during linting.
|
|
6
|
+
*/
|
|
1
7
|
export { parser } from './parser.js';
|
package/lib/index.js
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @markuplint/alpine-parser
|
|
3
|
+
* Markuplint parser plugin for Alpine.js templates. Extends the standard HTML parser
|
|
4
|
+
* to recognize Alpine.js directives (e.g., x-data, x-bind, x-on) and treat them
|
|
5
|
+
* appropriately during linting.
|
|
6
|
+
*/
|
|
1
7
|
export { parser } from './parser.js';
|
package/lib/parser.d.ts
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MLASTNodeTreeItem } from '@markuplint/ml-ast';
|
|
2
2
|
import { HtmlParser } from '@markuplint/html-parser';
|
|
3
|
+
/**
|
|
4
|
+
* Parser for Alpine.js templates that extends the standard HTML parser.
|
|
5
|
+
*
|
|
6
|
+
* Converts `<template x-for="...">` elements into preprocessor-specific
|
|
7
|
+
* blocks so that markuplint understands the iteration semantics.
|
|
8
|
+
*
|
|
9
|
+
* Attribute-level directive resolution (x-bind, x-on, @, :, etc.) is
|
|
10
|
+
* handled declaratively via `directivePatterns` in `@markuplint/alpine-spec`.
|
|
11
|
+
*/
|
|
3
12
|
declare class AlpineParser extends HtmlParser {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Overrides the base element visitor to convert `<template x-for="...">` elements
|
|
15
|
+
* into preprocessor-specific blocks with `blockBehavior: { type: 'each' }`.
|
|
16
|
+
* The matching closing tag receives `{ type: 'end' }`. Non-template elements
|
|
17
|
+
* and templates without `x-for` are passed through unchanged.
|
|
18
|
+
*
|
|
19
|
+
* @param token - The element token with tag metadata
|
|
20
|
+
* @param childNodes - The child AST nodes within the element
|
|
21
|
+
* @param options - Options forwarded to the base `visitElement`
|
|
22
|
+
* @returns An array of markuplint node tree items, with `x-for` templates replaced by psblock nodes
|
|
23
|
+
*/
|
|
24
|
+
visitElement(token: Parameters<HtmlParser['visitElement']>[0], childNodes: Parameters<HtmlParser['visitElement']>[1], options: Parameters<HtmlParser['visitElement']>[2]): readonly MLASTNodeTreeItem[];
|
|
9
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Singleton Alpine.js parser instance for use by the markuplint engine.
|
|
28
|
+
*/
|
|
10
29
|
export declare const parser: AlpineParser;
|
|
11
30
|
export {};
|
package/lib/parser.js
CHANGED
|
@@ -1,188 +1,53 @@
|
|
|
1
1
|
import { HtmlParser } from '@markuplint/html-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Alpine.js templates that extends the standard HTML parser.
|
|
4
|
+
*
|
|
5
|
+
* Converts `<template x-for="...">` elements into preprocessor-specific
|
|
6
|
+
* blocks so that markuplint understands the iteration semantics.
|
|
7
|
+
*
|
|
8
|
+
* Attribute-level directive resolution (x-bind, x-on, @, :, etc.) is
|
|
9
|
+
* handled declaratively via `directivePatterns` in `@markuplint/alpine-spec`.
|
|
10
|
+
*/
|
|
2
11
|
class AlpineParser extends HtmlParser {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* @see https://alpinejs.dev/directives/text
|
|
39
|
-
*/
|
|
40
|
-
case 'x-text': {
|
|
41
|
-
return {
|
|
42
|
-
...attr,
|
|
43
|
-
isDirective: true,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* @see https://alpinejs.dev/directives/html
|
|
48
|
-
*/
|
|
49
|
-
case 'x-html': {
|
|
50
|
-
return {
|
|
51
|
-
...attr,
|
|
52
|
-
isDirective: true,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* {@link ./spec.ts} Treat as a normal attribute and allow only in template elements as defined in `spec`.
|
|
57
|
-
*
|
|
58
|
-
* @see https://alpinejs.dev/directives/model
|
|
59
|
-
*/
|
|
60
|
-
case 'x-model': {
|
|
61
|
-
return attr;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* @see https://alpinejs.dev/directives/modelable
|
|
65
|
-
*/
|
|
66
|
-
case 'x-modelable': {
|
|
67
|
-
return {
|
|
68
|
-
...attr,
|
|
69
|
-
isDirective: true,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* {@link ./spec.ts} Treat as a normal attribute and allow only in template elements as defined in `spec`.
|
|
74
|
-
*
|
|
75
|
-
* @see https://alpinejs.dev/directives/for
|
|
76
|
-
*/
|
|
77
|
-
case 'x-for': {
|
|
78
|
-
return attr;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* @see https://alpinejs.dev/directives/effect
|
|
82
|
-
*/
|
|
83
|
-
case 'x-effect': {
|
|
84
|
-
return {
|
|
85
|
-
...attr,
|
|
86
|
-
isDirective: true,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* @see https://alpinejs.dev/directives/ignore
|
|
91
|
-
*/
|
|
92
|
-
case 'x-ignore': {
|
|
93
|
-
return {
|
|
94
|
-
...attr,
|
|
95
|
-
valueType: 'boolean',
|
|
96
|
-
isDirective: true,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* @see https://alpinejs.dev/directives/ref
|
|
101
|
-
*/
|
|
102
|
-
case 'x-ref': {
|
|
103
|
-
return {
|
|
104
|
-
...attr,
|
|
105
|
-
isDirective: true,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* @see https://alpinejs.dev/directives/cloak
|
|
110
|
-
*/
|
|
111
|
-
case 'x-cloak': {
|
|
112
|
-
return {
|
|
113
|
-
...attr,
|
|
114
|
-
valueType: 'boolean',
|
|
115
|
-
isDirective: true,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* {@link ./spec.ts} Treat as a normal attribute and allow only in template elements as defined in `spec`.
|
|
120
|
-
*
|
|
121
|
-
* @see https://alpinejs.dev/directives/teleport
|
|
122
|
-
*/
|
|
123
|
-
case 'x-teleport': {
|
|
124
|
-
return attr;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* {@link ./spec.ts} Treat as a normal attribute and allow only in template elements as defined in `spec`.
|
|
128
|
-
*
|
|
129
|
-
* @see https://alpinejs.dev/directives/if
|
|
130
|
-
*/
|
|
131
|
-
case 'x-if': {
|
|
132
|
-
return attr;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* @see https://alpinejs.dev/directives/id
|
|
136
|
-
*/
|
|
137
|
-
case 'x-id': {
|
|
138
|
-
return {
|
|
139
|
-
...attr,
|
|
140
|
-
isDirective: true,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* @see https://alpinejs.dev/directives/bind
|
|
146
|
-
*/
|
|
147
|
-
if (name.startsWith('x-bind:') || name.startsWith(':')) {
|
|
148
|
-
const potentialName = (attr.name.raw.match(/^(x-bind:|:)([^.]+)(?:\.([^.]+))?$/i) ?? [])[2];
|
|
149
|
-
if (!potentialName) {
|
|
150
|
-
return attr;
|
|
151
|
-
}
|
|
152
|
-
return {
|
|
153
|
-
...attr,
|
|
154
|
-
potentialName,
|
|
155
|
-
valueType: 'code',
|
|
156
|
-
isDuplicatable: ['class', 'style'].includes(potentialName),
|
|
157
|
-
isDynamicValue: true,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* @see https://alpinejs.dev/directives/on
|
|
162
|
-
*/
|
|
163
|
-
if (name.startsWith('x-on:') || name.startsWith('@')) {
|
|
164
|
-
const potentialName = (attr.name.raw.match(/^(x-on:|@)([^.]+)(\..+)?$/i) ?? [])[2];
|
|
165
|
-
if (!potentialName) {
|
|
166
|
-
return attr;
|
|
167
|
-
}
|
|
168
|
-
return {
|
|
169
|
-
...attr,
|
|
170
|
-
potentialName: `on${potentialName.toLowerCase()}`,
|
|
171
|
-
// TODO: Postpone due to inability to distinguish between custom and native events
|
|
172
|
-
isDirective: true,
|
|
173
|
-
isDynamicValue: true,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* @see https://alpinejs.dev/directives/transition
|
|
178
|
-
*/
|
|
179
|
-
if (/^x-transition(?:$|:|\.)/.test(name)) {
|
|
180
|
-
return {
|
|
181
|
-
...attr,
|
|
182
|
-
isDirective: true,
|
|
12
|
+
/**
|
|
13
|
+
* Overrides the base element visitor to convert `<template x-for="...">` elements
|
|
14
|
+
* into preprocessor-specific blocks with `blockBehavior: { type: 'each' }`.
|
|
15
|
+
* The matching closing tag receives `{ type: 'end' }`. Non-template elements
|
|
16
|
+
* and templates without `x-for` are passed through unchanged.
|
|
17
|
+
*
|
|
18
|
+
* @param token - The element token with tag metadata
|
|
19
|
+
* @param childNodes - The child AST nodes within the element
|
|
20
|
+
* @param options - Options forwarded to the base `visitElement`
|
|
21
|
+
* @returns An array of markuplint node tree items, with `x-for` templates replaced by psblock nodes
|
|
22
|
+
*/
|
|
23
|
+
visitElement(token, childNodes = [], options) {
|
|
24
|
+
return super.visitElement(token, childNodes, options).map(node => {
|
|
25
|
+
if (node.type !== 'starttag' && node.type !== 'endtag') {
|
|
26
|
+
return node;
|
|
27
|
+
}
|
|
28
|
+
if (node.nodeName.toLowerCase() !== 'template') {
|
|
29
|
+
return node;
|
|
30
|
+
}
|
|
31
|
+
const attrs = node.type === 'starttag' ? node.attributes : node.pairNode.attributes;
|
|
32
|
+
if (!attrs.some(attr => attr.nodeName.toLowerCase() === 'x-for')) {
|
|
33
|
+
return node;
|
|
34
|
+
}
|
|
35
|
+
const forBlock = {
|
|
36
|
+
isFragment: false,
|
|
37
|
+
childNodes: [],
|
|
38
|
+
...node,
|
|
39
|
+
type: 'psblock',
|
|
40
|
+
blockBehavior: {
|
|
41
|
+
type: node.type === 'starttag' ? 'each' : 'end',
|
|
42
|
+
expression: node.raw,
|
|
43
|
+
},
|
|
44
|
+
isBogus: false,
|
|
183
45
|
};
|
|
184
|
-
|
|
185
|
-
|
|
46
|
+
return forBlock;
|
|
47
|
+
});
|
|
186
48
|
}
|
|
187
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Singleton Alpine.js parser instance for use by the markuplint engine.
|
|
52
|
+
*/
|
|
188
53
|
export const parser = new AlpineParser();
|
package/lib/spec.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import type { ExtendedSpec } from '@markuplint/ml-spec';
|
|
2
|
+
/**
|
|
3
|
+
* Extended specification for Alpine.js directive attributes.
|
|
4
|
+
*
|
|
5
|
+
* Defines which Alpine.js-specific attributes are allowed on which HTML elements,
|
|
6
|
+
* their expected value types, and any element-level conditions. This enables
|
|
7
|
+
* markuplint to validate Alpine.js attributes as if they were part of the
|
|
8
|
+
* standard HTML spec.
|
|
9
|
+
*/
|
|
2
10
|
declare const spec: ExtendedSpec;
|
|
3
11
|
export default spec;
|
package/lib/spec.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Attribute specification for the Alpine.js `x-model` directive.
|
|
3
|
+
*
|
|
2
4
|
* > `x-model` works with the following input elements:
|
|
3
5
|
* > - `<input type="text">`
|
|
4
6
|
* > - `<textarea>`
|
|
@@ -13,6 +15,14 @@ const xModel = {
|
|
|
13
15
|
type: 'NoEmptyAny',
|
|
14
16
|
description: 'The x-model directive is used to bind a variable to a form input.',
|
|
15
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Extended specification for Alpine.js directive attributes.
|
|
20
|
+
*
|
|
21
|
+
* Defines which Alpine.js-specific attributes are allowed on which HTML elements,
|
|
22
|
+
* their expected value types, and any element-level conditions. This enables
|
|
23
|
+
* markuplint to validate Alpine.js attributes as if they were part of the
|
|
24
|
+
* standard HTML spec.
|
|
25
|
+
*/
|
|
16
26
|
const spec = {
|
|
17
27
|
specs: [
|
|
18
28
|
{
|
package/package.json
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/alpine-parser",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-alpha.0",
|
|
4
4
|
"description": "Alpine.js parser for markuplint",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22"
|
|
10
|
+
},
|
|
8
11
|
"type": "module",
|
|
9
12
|
"exports": {
|
|
10
13
|
".": {
|
|
11
14
|
"import": "./lib/index.js",
|
|
12
15
|
"types": "./lib/index.d.ts"
|
|
13
|
-
},
|
|
14
|
-
"./spec": {
|
|
15
|
-
"import": "./lib/spec.js",
|
|
16
|
-
"types": "./lib/spec.d.ts"
|
|
17
16
|
}
|
|
18
17
|
},
|
|
19
18
|
"publishConfig": {
|
|
@@ -25,11 +24,10 @@
|
|
|
25
24
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
26
25
|
},
|
|
27
26
|
"dependencies": {
|
|
28
|
-
"@markuplint/html-parser": "
|
|
27
|
+
"@markuplint/html-parser": "5.0.0-alpha.0"
|
|
29
28
|
},
|
|
30
29
|
"devDependencies": {
|
|
31
|
-
"@markuplint/
|
|
32
|
-
"@markuplint/parser-utils": "4.8.10"
|
|
30
|
+
"@markuplint/parser-utils": "5.0.0-alpha.0"
|
|
33
31
|
},
|
|
34
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "13dcfc84ec83d87360c720e253383b60767e1b56"
|
|
35
33
|
}
|