@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 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
- ## [4.6.22](https://github.com/markuplint/markuplint/compare/@markuplint/alpine-parser@4.6.21...@markuplint/alpine-parser@4.6.22) (2025-11-05)
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
- **Note:** Version bump only for package @markuplint/alpine-parser
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 `spec` option to your [configuration](https://markuplint.dev/configuration/#properties/parser).
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-parser/spec"
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 { Token } from '@markuplint/parser-utils';
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
- visitAttr(token: Token, options: Parameters<HtmlParser['visitAttr']>[1]): (import("packages/@markuplint/ml-ast/lib/types.js").MLASTHTMLAttr & {
5
- __rightText?: string;
6
- }) | (import("packages/@markuplint/ml-ast/lib/types.js").MLASTSpreadAttr & {
7
- __rightText?: string;
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
- visitAttr(token, options) {
4
- const attr = super.visitAttr(token, options);
5
- if (attr.type === 'spread') {
6
- return attr;
7
- }
8
- const name = attr.name.raw;
9
- switch (name) {
10
- /**
11
- * @see https://alpinejs.dev/directives/data
12
- */
13
- case 'x-data': {
14
- return {
15
- ...attr,
16
- isDirective: true,
17
- };
18
- }
19
- /**
20
- * @see https://alpinejs.dev/directives/init
21
- */
22
- case 'x-init': {
23
- return {
24
- ...attr,
25
- isDirective: true,
26
- };
27
- }
28
- /**
29
- * @see https://alpinejs.dev/directives/show
30
- */
31
- case 'x-show': {
32
- return {
33
- ...attr,
34
- isDirective: true,
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
- return attr;
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": "4.6.22",
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": "4.6.22"
27
+ "@markuplint/html-parser": "5.0.0-alpha.0"
29
28
  },
30
29
  "devDependencies": {
31
- "@markuplint/ml-spec": "4.10.1",
32
- "@markuplint/parser-utils": "4.8.10"
30
+ "@markuplint/parser-utils": "5.0.0-alpha.0"
33
31
  },
34
- "gitHead": "6213ea30269ef404f030e67bbcc7fc7443ec1060"
32
+ "gitHead": "13dcfc84ec83d87360c720e253383b60767e1b56"
35
33
  }