@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 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
+ [![npm version](https://badge.fury.io/js/%40markuplint%2Falpine-parser.svg)](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';
@@ -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
@@ -0,0 +1,3 @@
1
+ import type { ExtendedSpec } from '@markuplint/ml-spec';
2
+ declare const spec: ExtendedSpec;
3
+ export default spec;
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
+ }