@markuplint/alpine-parser 4.1.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/LICENSE +21 -0
- package/README.md +28 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/parser.d.ts +11 -0
- package/lib/parser.js +188 -0
- package/lib/spec.d.ts +3 -0
- package/lib/spec.js +76 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017-2024 Yusuke Hirao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @markuplint/alpine-parser
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@markuplint/alpine-parser)
|
|
4
|
+
|
|
5
|
+
Use **markuplint** with [**Alpine.js**](https://alpinejs.dev).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
$ npm install -D @markuplint/alpine-parser
|
|
11
|
+
|
|
12
|
+
$ yarn add -D @markuplint/alpine-parser
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Add `parser` and `spec` option to your [configuration](https://markuplint.dev/configuration/#properties/parser).
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"parser": {
|
|
22
|
+
"\\.html$": "@markuplint/alpine-parser"
|
|
23
|
+
},
|
|
24
|
+
"specs": {
|
|
25
|
+
"\\.html$": "@markuplint/alpine-parser/spec"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parser } from './parser.js';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parser } from './parser.js';
|
package/lib/parser.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Token } from '@markuplint/parser-utils';
|
|
2
|
+
import { HtmlParser } from '@markuplint/html-parser';
|
|
3
|
+
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 | undefined;
|
|
6
|
+
}) | (import("packages/@markuplint/ml-ast/lib/types.js").MLASTSpreadAttr & {
|
|
7
|
+
__rightText?: string | undefined;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export declare const parser: AlpineParser;
|
|
11
|
+
export {};
|
package/lib/parser.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { HtmlParser } from '@markuplint/html-parser';
|
|
2
|
+
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,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return attr;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export const parser = new AlpineParser();
|
package/lib/spec.d.ts
ADDED
package/lib/spec.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* > `x-model` works with the following input elements:
|
|
3
|
+
* > - `<input type="text">`
|
|
4
|
+
* > - `<textarea>`
|
|
5
|
+
* > - `<input type="checkbox">`
|
|
6
|
+
* > - `<input type="radio">`
|
|
7
|
+
* > - `<select>`
|
|
8
|
+
* > - `<input type="range">`
|
|
9
|
+
*
|
|
10
|
+
* @see https://alpinejs.dev/directives/model
|
|
11
|
+
*/
|
|
12
|
+
const xModel = {
|
|
13
|
+
type: 'NoEmptyAny',
|
|
14
|
+
description: 'The x-model directive is used to bind a variable to a form input.',
|
|
15
|
+
};
|
|
16
|
+
const spec = {
|
|
17
|
+
specs: [
|
|
18
|
+
{
|
|
19
|
+
name: 'template',
|
|
20
|
+
attributes: {
|
|
21
|
+
/**
|
|
22
|
+
* @see https://alpinejs.dev/directives/for
|
|
23
|
+
*/
|
|
24
|
+
'x-for': {
|
|
25
|
+
type: 'NoEmptyAny',
|
|
26
|
+
description: "Alpine's x-for directive allows you to create DOM elements by iterating through a list. Here's a simple example of using it to create a list of colors based on an array.",
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* @see https://alpinejs.dev/directives/for#keys
|
|
30
|
+
*/
|
|
31
|
+
key: {
|
|
32
|
+
type: 'NoEmptyAny',
|
|
33
|
+
description: 'It is important to specify unique keys for each x-for iteration if you are going to be re-ordering items. Without dynamic keys, Alpine may have a hard time keeping track of what re-orders and will cause odd side-effects.',
|
|
34
|
+
condition: '[x-for]',
|
|
35
|
+
},
|
|
36
|
+
/**
|
|
37
|
+
* @see https://alpinejs.dev/directives/teleport
|
|
38
|
+
*/
|
|
39
|
+
'x-teleport': {
|
|
40
|
+
type: 'NoEmptyAny',
|
|
41
|
+
description: 'The x-teleport directive allows you to transport part of your Alpine template to another part of the DOM on the page entirely.',
|
|
42
|
+
},
|
|
43
|
+
/**
|
|
44
|
+
* @see https://alpinejs.dev/directives/if
|
|
45
|
+
*/
|
|
46
|
+
'x-if': {
|
|
47
|
+
type: 'NoEmptyAny',
|
|
48
|
+
description: 'x-if is used for toggling elements on the page, similarly to x-show, however it completely adds and removes the element it\'s applied to rather than just changing its CSS display property to "none".',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'input',
|
|
54
|
+
attributes: {
|
|
55
|
+
'x-model': {
|
|
56
|
+
...xModel,
|
|
57
|
+
condition: '[type=text i], [type=checkbox i], [type=radio i], [type=range i]',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'select',
|
|
63
|
+
attributes: {
|
|
64
|
+
'x-model': xModel,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'textarea',
|
|
69
|
+
attributes: {
|
|
70
|
+
'x-model': xModel,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
// eslint-disable-next-line import/no-default-export
|
|
76
|
+
export default spec;
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@markuplint/alpine-parser",
|
|
3
|
+
"version": "4.1.0",
|
|
4
|
+
"description": "Alpine.js parser for markuplint",
|
|
5
|
+
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
|
+
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"private": false,
|
|
9
|
+
"type": "module",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./lib/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./spec": {
|
|
15
|
+
"import": "./lib/spec.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"types": "lib/index.d.ts",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"clean": "tsc --build --clean"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@markuplint/html-parser": "4.1.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@markuplint/ml-spec": "4.0.1",
|
|
31
|
+
"@markuplint/parser-utils": "4.1.0"
|
|
32
|
+
},
|
|
33
|
+
"gitHead": "b9817c30c2df71faa866e3b3fe286afa499deede"
|
|
34
|
+
}
|