@markuplint/astro-parser 3.12.0 → 4.0.0-alpha.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2019 Yusuke Hirao
3
+ Copyright (c) 2017-2024 Yusuke Hirao
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,11 +1,3 @@
1
- import type { RootNode } from '@astrojs/compiler';
2
- export type {
3
- RootNode,
4
- ElementNode,
5
- CustomElementNode,
6
- ComponentNode,
7
- FragmentNode,
8
- AttributeNode,
9
- Node,
10
- } from '@astrojs/compiler';
1
+ import type { RootNode } from '@astrojs/compiler/types';
2
+ export type { RootNode, ElementNode, CustomElementNode, ComponentNode, FragmentNode, AttributeNode, Node, } from '@astrojs/compiler/types';
11
3
  export declare function astroParse(code: string): RootNode;
@@ -1,17 +1,13 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.astroParse = void 0;
4
- const parser_utils_1 = require("@markuplint/parser-utils");
5
- const astro_eslint_parser_1 = require("astro-eslint-parser");
6
- function astroParse(code) {
7
- const { result } = (0, astro_eslint_parser_1.parseTemplate)(code);
1
+ import { ParserError } from '@markuplint/parser-utils';
2
+ import { parseTemplate } from 'astro-eslint-parser';
3
+ export function astroParse(code) {
4
+ const { result } = parseTemplate(code);
8
5
  if (result.diagnostics[0]) {
9
6
  const error = result.diagnostics[0];
10
- throw new parser_utils_1.ParserError(error.text, {
7
+ throw new ParserError(error.text, {
11
8
  line: error.location.line,
12
9
  col: error.location.column,
13
10
  });
14
11
  }
15
12
  return result.ast;
16
13
  }
17
- exports.astroParse = astroParse;
package/lib/index.d.ts CHANGED
@@ -1,2 +1 @@
1
- export { parse } from './parse';
2
- export declare const endTag = 'xml';
1
+ export { parser } from './parser.js';
package/lib/index.js CHANGED
@@ -1,6 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.endTag = exports.parse = void 0;
4
- var parse_1 = require("./parse");
5
- Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return parse_1.parse; } });
6
- exports.endTag = 'xml';
1
+ export { parser } from './parser.js';
@@ -0,0 +1,51 @@
1
+ import type { Node } from './astro-parser.js';
2
+ import type { MLASTParentNode, MLASTNodeTreeItem } from '@markuplint/ml-ast';
3
+ import type { ChildToken, Token } from '@markuplint/parser-utils';
4
+ import { Parser } from '@markuplint/parser-utils';
5
+ type State = {
6
+ scopeNS: string;
7
+ };
8
+ declare class AstroParser extends Parser<Node, State> {
9
+ #private;
10
+ constructor();
11
+ tokenize(): {
12
+ ast: Node[];
13
+ isFragment: boolean;
14
+ };
15
+ nodeize(originNode: Node, parentNode: MLASTParentNode | null, depth: number): readonly MLASTNodeTreeItem[];
16
+ afterFlattenNodes(nodeList: readonly MLASTNodeTreeItem[]): readonly MLASTNodeTreeItem[];
17
+ visitElement(token: ChildToken, childNodes: readonly Node[]): readonly MLASTNodeTreeItem[];
18
+ visitChildren(children: readonly Node[], parentNode: MLASTParentNode | null): never[];
19
+ visitAttr(token: Token): (import("@markuplint/ml-ast").MLASTSpreadAttr & {
20
+ __rightText?: string | undefined;
21
+ }) | {
22
+ isDynamicValue: true | undefined;
23
+ isDirective: true | undefined;
24
+ potentialName: string | undefined;
25
+ type: "attr";
26
+ nodeName: string;
27
+ spacesBeforeName: import("@markuplint/ml-ast").MLASTToken;
28
+ name: import("@markuplint/ml-ast").MLASTToken;
29
+ spacesBeforeEqual: import("@markuplint/ml-ast").MLASTToken;
30
+ equal: import("@markuplint/ml-ast").MLASTToken;
31
+ spacesAfterEqual: import("@markuplint/ml-ast").MLASTToken;
32
+ startQuote: import("@markuplint/ml-ast").MLASTToken;
33
+ value: import("@markuplint/ml-ast").MLASTToken;
34
+ endQuote: import("@markuplint/ml-ast").MLASTToken;
35
+ potentialValue?: string | undefined;
36
+ valueType?: "string" | "number" | "boolean" | "code" | undefined;
37
+ candidate?: string | undefined;
38
+ isDuplicatable: boolean;
39
+ uuid: string;
40
+ raw: string;
41
+ startOffset: number;
42
+ endOffset: number;
43
+ startLine: number;
44
+ endLine: number;
45
+ startCol: number;
46
+ endCol: number;
47
+ __rightText?: string | undefined;
48
+ };
49
+ }
50
+ export declare const parser: AstroParser;
51
+ export {};
package/lib/parser.js ADDED
@@ -0,0 +1,214 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _AstroParser_instances, _AstroParser_updateScopeNS;
7
+ import { AttrState, Parser, ParserError } from '@markuplint/parser-utils';
8
+ import { astroParse } from './astro-parser.js';
9
+ class AstroParser extends Parser {
10
+ constructor() {
11
+ super({
12
+ endTagType: 'xml',
13
+ selfCloseType: 'html+xml',
14
+ }, {
15
+ scopeNS: 'http://www.w3.org/1999/xhtml',
16
+ });
17
+ _AstroParser_instances.add(this);
18
+ }
19
+ tokenize() {
20
+ return {
21
+ ast: astroParse(this.rawCode).children,
22
+ isFragment: true,
23
+ };
24
+ }
25
+ nodeize(
26
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
27
+ originNode, parentNode, depth) {
28
+ if (!originNode.position) {
29
+ throw new TypeError("Node doesn't have position");
30
+ }
31
+ const startOffset = originNode.position.start.offset;
32
+ const endOffset = originNode.position.end?.offset;
33
+ const token = this.sliceFragment(startOffset, endOffset);
34
+ __classPrivateFieldGet(this, _AstroParser_instances, "m", _AstroParser_updateScopeNS).call(this, originNode, parentNode);
35
+ switch (originNode.type) {
36
+ case 'doctype': {
37
+ return this.visitDoctype({
38
+ ...token,
39
+ depth,
40
+ parentNode,
41
+ name: originNode.value,
42
+ publicId: '',
43
+ systemId: '',
44
+ });
45
+ }
46
+ case 'text': {
47
+ if (parentNode?.type === 'psblock') {
48
+ return [];
49
+ }
50
+ return this.visitText({
51
+ ...token,
52
+ depth,
53
+ parentNode,
54
+ });
55
+ }
56
+ case 'comment': {
57
+ return this.visitComment({
58
+ ...token,
59
+ depth,
60
+ parentNode,
61
+ });
62
+ }
63
+ case 'component':
64
+ case 'custom-element':
65
+ case 'fragment':
66
+ case 'element': {
67
+ const tagToken = token.raw ? token : this.sliceFragment(0);
68
+ return this.visitElement({
69
+ ...tagToken,
70
+ depth,
71
+ parentNode,
72
+ }, originNode.children);
73
+ }
74
+ case 'expression': {
75
+ const firstChild = originNode.children.at(0);
76
+ const lastChild = originNode.children.at(-1);
77
+ let startExpressionRaw = token.raw;
78
+ let startExpressionStartLine = token.startLine;
79
+ let startExpressionStartCol = token.startCol;
80
+ const nodes = [];
81
+ if (firstChild && lastChild && firstChild !== lastChild) {
82
+ const startExpressionEndOffset = firstChild.position?.end?.offset ?? endOffset ?? startOffset;
83
+ const startExpressionLocation = this.sliceFragment(startOffset, startExpressionEndOffset);
84
+ startExpressionRaw = startExpressionLocation.raw;
85
+ startExpressionStartLine = startExpressionLocation.startLine;
86
+ startExpressionStartCol = startExpressionLocation.startCol;
87
+ const closeExpressionLocation = this.sliceFragment(lastChild.position?.start.offset ?? startOffset, endOffset);
88
+ nodes.push(...this.visitPsBlock({
89
+ ...closeExpressionLocation,
90
+ depth,
91
+ parentNode,
92
+ nodeName: 'MustacheTag',
93
+ }));
94
+ }
95
+ nodes.push(...this.visitPsBlock({
96
+ raw: startExpressionRaw,
97
+ startOffset,
98
+ startLine: startExpressionStartLine,
99
+ startCol: startExpressionStartCol,
100
+ depth,
101
+ parentNode,
102
+ nodeName: 'MustacheTag',
103
+ }, originNode.children));
104
+ return nodes;
105
+ }
106
+ default: {
107
+ return [];
108
+ }
109
+ }
110
+ }
111
+ afterFlattenNodes(nodeList) {
112
+ return super.afterFlattenNodes(nodeList, {
113
+ exposeInvalidNode: false,
114
+ });
115
+ }
116
+ visitElement(token,
117
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
118
+ childNodes) {
119
+ const parsedNodes = this.parseCodeFragment(token);
120
+ const startTagNode = parsedNodes.at(0);
121
+ if (!startTagNode || startTagNode.type !== 'starttag') {
122
+ throw new ParserError('Not found start tag', startTagNode ?? token);
123
+ }
124
+ return super.visitElement(startTagNode, childNodes, {
125
+ overwriteProps: {
126
+ namespace: this.state.scopeNS,
127
+ },
128
+ createEndTagToken: () => {
129
+ if (startTagNode.selfClosingSolidus?.raw === '/') {
130
+ return null;
131
+ }
132
+ const endTagNode = parsedNodes.at(-1);
133
+ if (endTagNode?.type !== 'endtag') {
134
+ return null;
135
+ }
136
+ return endTagNode ?? null;
137
+ },
138
+ });
139
+ }
140
+ visitChildren(
141
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
142
+ children, parentNode) {
143
+ const siblings = super.visitChildren(children, parentNode);
144
+ if (siblings.length > 0) {
145
+ throw new ParserError('Discovered child nodes with differing hierarchy levels', siblings[0]);
146
+ }
147
+ return [];
148
+ }
149
+ visitAttr(token) {
150
+ const attr = super.visitAttr(token, {
151
+ quoteSet: [
152
+ { start: '"', end: '"' },
153
+ { start: "'", end: "'" },
154
+ { start: '{', end: '}' },
155
+ ],
156
+ quoteInValueChars: [
157
+ { start: '"', end: '"' },
158
+ { start: "'", end: "'" },
159
+ { start: '`', end: '`' },
160
+ { start: '${', end: '}' },
161
+ ],
162
+ startState:
163
+ // is shorthand attribute
164
+ token.raw.trim().startsWith('{') ? AttrState.BeforeValue : AttrState.BeforeName,
165
+ });
166
+ if (attr.type === 'spread') {
167
+ return attr;
168
+ }
169
+ const isDynamicValue = attr.startQuote.raw === '{' || undefined;
170
+ let potentialName;
171
+ let isDirective;
172
+ if (isDynamicValue && attr.name.raw === '') {
173
+ potentialName = attr.value.raw;
174
+ }
175
+ /**
176
+ * Detects Template Directive
177
+ *
178
+ * @see https://docs.astro.build/en/reference/directives-reference/
179
+ */
180
+ const [, directive] = attr.name.raw.match(/^([^:]+):([^:]+)$/) ?? [];
181
+ if (directive) {
182
+ const lowerCaseDirectiveName = directive.toLowerCase();
183
+ switch (lowerCaseDirectiveName) {
184
+ case 'class': {
185
+ potentialName = lowerCaseDirectiveName;
186
+ break;
187
+ }
188
+ default: {
189
+ isDirective = true;
190
+ }
191
+ }
192
+ }
193
+ return {
194
+ ...attr,
195
+ isDynamicValue,
196
+ isDirective,
197
+ potentialName,
198
+ };
199
+ }
200
+ }
201
+ _AstroParser_instances = new WeakSet(), _AstroParser_updateScopeNS = function _AstroParser_updateScopeNS(
202
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
203
+ originNode, parentNode) {
204
+ const parentNS = this.state.scopeNS;
205
+ if (parentNS === 'http://www.w3.org/1999/xhtml' &&
206
+ originNode.type === 'element' &&
207
+ originNode.name?.toLowerCase() === 'svg') {
208
+ this.state.scopeNS = 'http://www.w3.org/2000/svg';
209
+ }
210
+ else if (parentNS === 'http://www.w3.org/2000/svg' && parentNode && parentNode.nodeName === 'foreignObject') {
211
+ this.state.scopeNS = 'http://www.w3.org/1999/xhtml';
212
+ }
213
+ };
214
+ export const parser = new AstroParser();
package/package.json CHANGED
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "name": "@markuplint/astro-parser",
3
- "version": "3.12.0",
3
+ "version": "4.0.0-alpha.10",
4
4
  "description": "astro 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
8
  "private": false,
9
- "main": "lib/index.js",
10
- "types": "lib/index.d.ts",
9
+ "type": "module",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./lib/index.js"
13
+ }
14
+ },
15
+ "types": "./lib/index.d.ts",
11
16
  "publishConfig": {
12
17
  "access": "public"
13
18
  },
@@ -16,12 +21,12 @@
16
21
  "clean": "tsc --build --clean"
17
22
  },
18
23
  "dependencies": {
19
- "@astrojs/parser": "0.22.2",
20
- "@markuplint/html-parser": "3.13.0",
21
- "@markuplint/ml-ast": "3.2.0",
22
- "@markuplint/parser-utils": "3.13.0",
23
- "astro-eslint-parser": "^0.16.0",
24
- "tslib": "^2.6.2"
24
+ "@markuplint/ml-ast": "4.0.0-alpha.10",
25
+ "@markuplint/parser-utils": "4.0.0-alpha.10",
26
+ "astro-eslint-parser": "^0.16.2"
27
+ },
28
+ "devDependencies": {
29
+ "@astrojs/compiler": "^2.5.1"
25
30
  },
26
- "gitHead": "b37b749d7ac0f9e6cbd022ee7031bc020c6677d3"
31
+ "gitHead": "b41153ea665aa8f091daf6114a06047f4ccb8350"
27
32
  }
@@ -1,9 +0,0 @@
1
- import type { AttributeNode } from './astro-parser';
2
- import type { MLASTHTMLAttr } from '@markuplint/ml-ast';
3
- export declare function attrTokenizer(
4
- attr: AttributeNode,
5
- nextAttr: AttributeNode | null,
6
- rawHtml: string,
7
- startTag: string,
8
- startTagEndOffset: number,
9
- ): MLASTHTMLAttr;
@@ -1,62 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.attrTokenizer = void 0;
4
- const parser_utils_1 = require("@markuplint/parser-utils");
5
- const mustacheTag = {
6
- start: '{',
7
- end: '}',
8
- };
9
- function attrTokenizer(
10
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
11
- attr,
12
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
13
- nextAttr, rawHtml, startTag, startTagEndOffset) {
14
- var _a, _b, _c;
15
- if (!attr.position) {
16
- throw new TypeError("Attr doesn't have position");
17
- }
18
- if (attr.position.end) {
19
- throw new TypeError('Node may is an attribute because it has end position');
20
- }
21
- let nextAttrBeforeSpaceOffset;
22
- if (nextAttr) {
23
- if (!nextAttr.position) {
24
- throw new TypeError("NextAttr doesn't have position");
25
- }
26
- if (nextAttr.position.end) {
27
- throw new TypeError('NextAttr Node may is an attribute because it has end position');
28
- }
29
- nextAttrBeforeSpaceOffset = (0, parser_utils_1.getSpaceBefore)(nextAttr.position.start.offset, rawHtml).startOffset;
30
- }
31
- else {
32
- const close = (_b = (_a = /(\/?>)$/.exec(startTag)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : '';
33
- nextAttrBeforeSpaceOffset = startTagEndOffset - close.length;
34
- }
35
- const { raw, startOffset } = (0, parser_utils_1.sliceFragment)(rawHtml, attr.position.start.offset, nextAttrBeforeSpaceOffset);
36
- const result = (0, parser_utils_1.parseAttr)(raw, startOffset, rawHtml, {
37
- valueDelimiters: [...parser_utils_1.defaultValueDelimiters, mustacheTag],
38
- });
39
- if (result.startQuote.raw === mustacheTag.start) {
40
- result.isDynamicValue = true;
41
- }
42
- /**
43
- * Detects Template Directive
44
- *
45
- * @see https://docs.astro.build/en/reference/directives-reference/
46
- */
47
- const [, directive] = (_c = result.name.raw.match(/^([^:]+):([^:]+)$/)) !== null && _c !== void 0 ? _c : [];
48
- if (directive) {
49
- const lowerCaseDirectiveName = directive.toLowerCase();
50
- switch (lowerCaseDirectiveName) {
51
- case 'class': {
52
- result.potentialName = lowerCaseDirectiveName;
53
- break;
54
- }
55
- default: {
56
- result.isDirective = true;
57
- }
58
- }
59
- }
60
- return result;
61
- }
62
- exports.attrTokenizer = attrTokenizer;
package/lib/parse.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import type { Parse } from '@markuplint/ml-ast';
2
- export declare const parse: Parse;