@markuplint/astro-parser 4.6.15 → 4.6.17

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,6 +3,14 @@
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.17](https://github.com/markuplint/markuplint/compare/@markuplint/astro-parser@4.6.16...@markuplint/astro-parser@4.6.17) (2025-02-27)
7
+
8
+ **Note:** Version bump only for package @markuplint/astro-parser
9
+
10
+ ## [4.6.16](https://github.com/markuplint/markuplint/compare/@markuplint/astro-parser@4.6.15...@markuplint/astro-parser@4.6.16) (2025-02-11)
11
+
12
+ **Note:** Version bump only for package @markuplint/astro-parser
13
+
6
14
  ## [4.6.15](https://github.com/markuplint/markuplint/compare/@markuplint/astro-parser@4.6.14...@markuplint/astro-parser@4.6.15) (2025-02-04)
7
15
 
8
16
  **Note:** Version bump only for package @markuplint/astro-parser
@@ -0,0 +1,2 @@
1
+ import type { MLASTBlockBehavior } from '@markuplint/ml-ast';
2
+ export declare function detectBlockBehavior(raw: string): MLASTBlockBehavior | null;
@@ -0,0 +1,12 @@
1
+ export function detectBlockBehavior(raw) {
2
+ const re = /\.+\s*(?<type>map|filter)\s*\((?:function\s*\(.[^\n\r{\u2028\u2029]*\{.*return\s*$|.+=>\s*\(?\s*)/;
3
+ const match = raw.match(re);
4
+ if (!match) {
5
+ return null;
6
+ }
7
+ const type = match.groups?.type === 'map' ? 'each' : 'if';
8
+ return {
9
+ type,
10
+ expression: raw,
11
+ };
12
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,516 @@
1
+ // @ts-nocheck
2
+ import { describe, test, expect } from 'vitest';
3
+ import { astroParse } from './astro-parser.js';
4
+ test('Basic', () => {
5
+ const ast = astroParse(`---
6
+ const name = "World";
7
+ ---
8
+ <!-- Comment -->
9
+ <style>
10
+ div {
11
+ color: red;
12
+ }
13
+ </style>
14
+ <div data-attr="v">Hello {name}!</div>
15
+ `);
16
+ expect(ast).toStrictEqual(expect.objectContaining({
17
+ children: [
18
+ {
19
+ position: {
20
+ end: {
21
+ column: 4,
22
+ line: 3,
23
+ offset: 29,
24
+ },
25
+ start: {
26
+ column: 1,
27
+ line: 1,
28
+ offset: 0,
29
+ },
30
+ },
31
+ type: 'frontmatter',
32
+ value: '\nconst name = "World";\n',
33
+ },
34
+ {
35
+ position: {
36
+ end: {
37
+ column: 17,
38
+ line: 4,
39
+ offset: 46,
40
+ },
41
+ start: {
42
+ column: 5,
43
+ line: 4,
44
+ offset: 30,
45
+ },
46
+ },
47
+ type: 'comment',
48
+ value: ' Comment ',
49
+ },
50
+ {
51
+ attributes: [],
52
+ children: [
53
+ {
54
+ position: {
55
+ end: {
56
+ column: 1,
57
+ line: 9,
58
+ offset: 79,
59
+ },
60
+ start: {
61
+ column: 8,
62
+ line: 5,
63
+ offset: 54,
64
+ },
65
+ },
66
+ type: 'text',
67
+ value: '\ndiv {\n color: red;\n}\n',
68
+ },
69
+ ],
70
+ name: 'style',
71
+ position: {
72
+ end: {
73
+ column: 9,
74
+ line: 9,
75
+ offset: 87,
76
+ },
77
+ start: {
78
+ column: 1,
79
+ line: 5,
80
+ offset: 47,
81
+ },
82
+ },
83
+ type: 'element',
84
+ },
85
+ {
86
+ position: {
87
+ end: {
88
+ column: 1,
89
+ line: 10,
90
+ offset: 88,
91
+ },
92
+ start: {
93
+ column: 9,
94
+ line: 9,
95
+ offset: 87,
96
+ },
97
+ },
98
+ type: 'text',
99
+ value: '\n',
100
+ },
101
+ {
102
+ attributes: [
103
+ {
104
+ kind: 'quoted',
105
+ name: 'data-attr',
106
+ position: {
107
+ start: {
108
+ column: 6,
109
+ line: 10,
110
+ offset: 93,
111
+ },
112
+ },
113
+ raw: '"v"',
114
+ type: 'attribute',
115
+ value: 'v',
116
+ },
117
+ ],
118
+ children: [
119
+ {
120
+ position: {
121
+ end: {
122
+ column: 26,
123
+ line: 10,
124
+ offset: 113,
125
+ },
126
+ start: {
127
+ column: 20,
128
+ line: 10,
129
+ offset: 107,
130
+ },
131
+ },
132
+ type: 'text',
133
+ value: 'Hello ',
134
+ },
135
+ {
136
+ children: [
137
+ {
138
+ position: {
139
+ end: {
140
+ column: 31,
141
+ line: 10,
142
+ offset: 118,
143
+ },
144
+ start: {
145
+ column: 27,
146
+ line: 10,
147
+ offset: 114,
148
+ },
149
+ },
150
+ type: 'text',
151
+ value: 'name',
152
+ },
153
+ ],
154
+ position: {
155
+ end: {
156
+ column: 9,
157
+ line: 11,
158
+ offset: 119,
159
+ },
160
+ start: {
161
+ column: 25,
162
+ line: 10,
163
+ offset: 113,
164
+ },
165
+ },
166
+ type: 'expression',
167
+ },
168
+ {
169
+ position: {
170
+ end: {
171
+ column: 33,
172
+ line: 10,
173
+ offset: 120,
174
+ },
175
+ start: {
176
+ column: 32,
177
+ line: 10,
178
+ offset: 119,
179
+ },
180
+ },
181
+ type: 'text',
182
+ value: '!',
183
+ },
184
+ ],
185
+ name: 'div',
186
+ position: {
187
+ end: {
188
+ column: 39,
189
+ line: 10,
190
+ offset: 126,
191
+ },
192
+ start: {
193
+ column: 1,
194
+ line: 10,
195
+ offset: 88,
196
+ },
197
+ },
198
+ type: 'element',
199
+ },
200
+ {
201
+ position: {
202
+ end: {
203
+ column: 1,
204
+ line: 11,
205
+ offset: 127,
206
+ },
207
+ start: {
208
+ column: 39,
209
+ line: 10,
210
+ offset: 126,
211
+ },
212
+ },
213
+ type: 'text',
214
+ value: '\n',
215
+ },
216
+ ],
217
+ type: 'root',
218
+ }));
219
+ });
220
+ test('Attr and Template Directive', () => {
221
+ const ast = astroParse('<div a b=c d="e" f=`g` x:y prop={ prop }></div>');
222
+ expect(ast.children?.[0].attributes).toStrictEqual(expect.objectContaining([
223
+ {
224
+ type: 'attribute',
225
+ kind: 'empty',
226
+ name: 'a',
227
+ value: '',
228
+ raw: '',
229
+ position: { start: { column: 6, line: 1, offset: 5 } },
230
+ },
231
+ {
232
+ type: 'attribute',
233
+ kind: 'quoted',
234
+ name: 'b',
235
+ value: 'c',
236
+ raw: 'c',
237
+ position: { start: { column: 8, line: 1, offset: 7 } },
238
+ },
239
+ {
240
+ type: 'attribute',
241
+ kind: 'quoted',
242
+ name: 'd',
243
+ value: 'e',
244
+ raw: '"e"',
245
+ position: { start: { column: 12, line: 1, offset: 11 } },
246
+ },
247
+ {
248
+ type: 'attribute',
249
+ kind: 'template-literal',
250
+ name: 'f',
251
+ value: 'g',
252
+ raw: '`g`',
253
+ position: { start: { column: 18, line: 1, offset: 17 } },
254
+ },
255
+ {
256
+ type: 'attribute',
257
+ kind: 'empty',
258
+ name: 'x:y',
259
+ value: '',
260
+ raw: '',
261
+ position: { start: { column: 24, line: 1, offset: 23 } },
262
+ },
263
+ {
264
+ type: 'attribute',
265
+ kind: 'expression',
266
+ name: 'prop',
267
+ value: ' prop ',
268
+ raw: '',
269
+ position: { start: { column: 28, line: 1, offset: 27 } },
270
+ },
271
+ ]));
272
+ });
273
+ test('Greater-than sign in attribute value', () => {
274
+ const ast = astroParse('<div attr="a>b"></div>');
275
+ expect(ast.children?.[0].attributes).toStrictEqual(expect.objectContaining([
276
+ {
277
+ kind: 'quoted',
278
+ name: 'attr',
279
+ position: { start: { column: 6, line: 1, offset: 5 } },
280
+ type: 'attribute',
281
+ value: 'a>b',
282
+ raw: '"a>b"',
283
+ },
284
+ ]));
285
+ });
286
+ test('frontmatter', () => {
287
+ const ast = astroParse(`---
288
+ // Example: <SomeComponent greeting="(Optional) Hello" name="Required Name" />
289
+ const { greeting = 'Hello', name } = Astro.props;
290
+ ---
291
+ <div>
292
+ <h1>{greeting}, {name}!</h1>
293
+ </div>`);
294
+ expect(ast.children[0]).toStrictEqual(expect.objectContaining({
295
+ position: {
296
+ end: {
297
+ column: 4,
298
+ line: 4,
299
+ offset: 136,
300
+ },
301
+ start: {
302
+ column: 1,
303
+ line: 1,
304
+ offset: 0,
305
+ },
306
+ },
307
+ type: 'frontmatter',
308
+ value: `
309
+ // Example: <SomeComponent greeting="(Optional) Hello" name="Required Name" />
310
+ const { greeting = 'Hello', name } = Astro.props;
311
+ `,
312
+ }));
313
+ });
314
+ test('Missing end tag', () => {
315
+ const ast = astroParse('<div><span><span /></div>');
316
+ expect(ast).toStrictEqual(expect.objectContaining({
317
+ type: 'root',
318
+ children: [
319
+ {
320
+ type: 'element',
321
+ name: 'div',
322
+ position: {
323
+ start: { line: 1, column: 2, offset: 0 },
324
+ },
325
+ attributes: [],
326
+ children: [
327
+ {
328
+ type: 'element',
329
+ name: 'span',
330
+ position: {
331
+ start: { line: 1, column: 6, offset: 5 },
332
+ end: { line: 1, column: 27, offset: 19 },
333
+ },
334
+ attributes: [],
335
+ children: [
336
+ {
337
+ type: 'element',
338
+ name: 'span',
339
+ position: {
340
+ start: { line: 1, column: 12, offset: 11 },
341
+ end: { line: 1, column: 19, offset: 19 },
342
+ },
343
+ attributes: [],
344
+ children: [],
345
+ },
346
+ ],
347
+ },
348
+ ],
349
+ },
350
+ ],
351
+ }));
352
+ });
353
+ describe('Issues', () => {
354
+ test('#803', () => {
355
+ const code = `<html lang="en">
356
+ <head>
357
+ <meta charset="utf-8" />
358
+ <title>Title</title>
359
+ <meta name="viewport" content="width=device-width" />
360
+ </head>
361
+ </html>
362
+ `;
363
+ const ast = astroParse(code);
364
+ expect(ast).toStrictEqual(expect.objectContaining({
365
+ type: 'root',
366
+ children: [
367
+ {
368
+ type: 'element',
369
+ name: 'html',
370
+ position: {
371
+ start: { line: 1, column: 1, offset: 0 },
372
+ end: { line: 7, column: 8, offset: 147 },
373
+ },
374
+ attributes: [
375
+ {
376
+ type: 'attribute',
377
+ kind: 'quoted',
378
+ name: 'lang',
379
+ value: 'en',
380
+ raw: '"en"',
381
+ position: { start: { line: 1, column: 7, offset: 6 } },
382
+ },
383
+ ],
384
+ children: [
385
+ {
386
+ type: 'text',
387
+ value: '\n\t',
388
+ position: {
389
+ start: { line: 1, column: 17, offset: 16 },
390
+ end: { line: 2, column: 2, offset: 18 },
391
+ },
392
+ },
393
+ {
394
+ type: 'element',
395
+ name: 'head',
396
+ attributes: [],
397
+ position: {
398
+ start: { line: 2, column: 2, offset: 18 },
399
+ end: { line: 6, column: 9, offset: 139 },
400
+ },
401
+ children: [
402
+ {
403
+ type: 'text',
404
+ value: '\n\t\t',
405
+ position: {
406
+ start: { line: 2, column: 8, offset: 24 },
407
+ end: { line: 3, column: 3, offset: 27 },
408
+ },
409
+ },
410
+ {
411
+ type: 'element',
412
+ name: 'meta',
413
+ position: { start: { line: 3, column: 4, offset: 27 } },
414
+ attributes: [
415
+ {
416
+ type: 'attribute',
417
+ kind: 'quoted',
418
+ name: 'charset',
419
+ value: 'utf-8',
420
+ raw: '"utf-8"',
421
+ position: { start: { line: 3, column: 9, offset: 33 } },
422
+ },
423
+ ],
424
+ children: [],
425
+ },
426
+ {
427
+ type: 'text',
428
+ value: '\n\t\t',
429
+ position: {
430
+ start: { line: 3, column: 27, offset: 51 },
431
+ end: { line: 4, column: 3, offset: 54 },
432
+ },
433
+ },
434
+ {
435
+ type: 'element',
436
+ name: 'title',
437
+ position: {
438
+ start: { line: 4, column: 3, offset: 54 },
439
+ end: { line: 4, column: 23, offset: 74 },
440
+ },
441
+ attributes: [],
442
+ children: [
443
+ {
444
+ type: 'text',
445
+ value: 'Title',
446
+ position: {
447
+ start: { line: 4, column: 10, offset: 61 },
448
+ end: { line: 4, column: 15, offset: 66 },
449
+ },
450
+ },
451
+ ],
452
+ },
453
+ {
454
+ type: 'text',
455
+ value: '\n\t\t',
456
+ position: {
457
+ start: { line: 4, column: 23, offset: 74 },
458
+ end: { line: 5, column: 3, offset: 77 },
459
+ },
460
+ },
461
+ {
462
+ type: 'element',
463
+ name: 'meta',
464
+ attributes: [
465
+ {
466
+ type: 'attribute',
467
+ kind: 'quoted',
468
+ name: 'name',
469
+ value: 'viewport',
470
+ raw: '"viewport"',
471
+ position: { start: { line: 5, column: 9, offset: 83 } },
472
+ },
473
+ {
474
+ type: 'attribute',
475
+ kind: 'quoted',
476
+ name: 'content',
477
+ value: 'width=device-width',
478
+ raw: '"width=device-width"',
479
+ position: { start: { line: 5, column: 25, offset: 99 } },
480
+ },
481
+ ],
482
+ position: { start: { line: 5, column: 4, offset: 77 } },
483
+ children: [],
484
+ },
485
+ {
486
+ type: 'text',
487
+ value: '\n\t',
488
+ position: {
489
+ start: { line: 5, column: 56, offset: 130 },
490
+ end: { line: 6, column: 2, offset: 132 },
491
+ },
492
+ },
493
+ ],
494
+ },
495
+ {
496
+ type: 'text',
497
+ value: '\n',
498
+ position: {
499
+ start: { line: 6, column: 9, offset: 139 },
500
+ end: { line: 7, column: 1, offset: 140 },
501
+ },
502
+ },
503
+ ],
504
+ },
505
+ {
506
+ type: 'text',
507
+ value: '\n',
508
+ position: {
509
+ start: { line: 7, column: 8, offset: 147 },
510
+ end: { line: 8, column: 1, offset: 148 },
511
+ },
512
+ },
513
+ ],
514
+ }));
515
+ });
516
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/astro-parser",
3
- "version": "4.6.15",
3
+ "version": "4.6.17",
4
4
  "description": "astro parser for markuplint",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -23,11 +23,11 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@markuplint/ml-ast": "4.4.9",
26
- "@markuplint/parser-utils": "4.8.3",
26
+ "@markuplint/parser-utils": "4.8.5",
27
27
  "astro-eslint-parser": "1.2.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@astrojs/compiler": "2.10.3"
30
+ "@astrojs/compiler": "2.10.4"
31
31
  },
32
- "gitHead": "687a84e00546b8f1f2ed88125fe507239723c8d8"
32
+ "gitHead": "1b71e44a0a372662abca460ef77888053b66a78d"
33
33
  }