tempile-core 1.0.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/dist/ast/base/Node.d.ts +9 -0
- package/dist/ast/base/Node.js +9 -0
- package/dist/ast/base/Pos.d.ts +10 -0
- package/dist/ast/base/Pos.js +1 -0
- package/dist/ast/base/Root.d.ts +13 -0
- package/dist/ast/base/Root.js +105 -0
- package/dist/ast/base/node-types.d.ts +18 -0
- package/dist/ast/base/node-types.js +19 -0
- package/dist/ast/base/parse5-type-guards.d.ts +4 -0
- package/dist/ast/base/parse5-type-guards.js +9 -0
- package/dist/ast/base/parse5-types.d.ts +5 -0
- package/dist/ast/base/parse5-types.js +1 -0
- package/dist/ast/base/parser-types.d.ts +3 -0
- package/dist/ast/base/parser-types.js +1 -0
- package/dist/ast/control/ElseIfNode.d.ts +13 -0
- package/dist/ast/control/ElseIfNode.js +41 -0
- package/dist/ast/control/ElseNode.d.ts +11 -0
- package/dist/ast/control/ElseNode.js +34 -0
- package/dist/ast/control/ForNode.d.ts +13 -0
- package/dist/ast/control/ForNode.js +37 -0
- package/dist/ast/control/IfNode.d.ts +17 -0
- package/dist/ast/control/IfNode.js +64 -0
- package/dist/ast/features/AttrExprNode.d.ts +1 -0
- package/dist/ast/features/AttrExprNode.js +13 -0
- package/dist/ast/features/ContentNode.d.ts +12 -0
- package/dist/ast/features/ContentNode.js +44 -0
- package/dist/ast/features/ImportNode.d.ts +12 -0
- package/dist/ast/features/ImportNode.js +51 -0
- package/dist/ast/features/IncludeNode.d.ts +14 -0
- package/dist/ast/features/IncludeNode.js +42 -0
- package/dist/ast/features/LogicNode.d.ts +11 -0
- package/dist/ast/features/LogicNode.js +48 -0
- package/dist/ast/features/OutNode.d.ts +11 -0
- package/dist/ast/features/OutNode.js +45 -0
- package/dist/ast/features/SlotNode.d.ts +12 -0
- package/dist/ast/features/SlotNode.js +39 -0
- package/dist/ast/features/TempileNode.d.ts +14 -0
- package/dist/ast/features/TempileNode.js +53 -0
- package/dist/ast/html/Attribute.d.ts +15 -0
- package/dist/ast/html/Attribute.js +1 -0
- package/dist/ast/html/CommentNode.d.ts +10 -0
- package/dist/ast/html/CommentNode.js +23 -0
- package/dist/ast/html/DoctypeNode.d.ts +8 -0
- package/dist/ast/html/DoctypeNode.js +13 -0
- package/dist/ast/html/ElementNode.d.ts +14 -0
- package/dist/ast/html/ElementNode.js +29 -0
- package/dist/ast/html/TextNode.d.ts +10 -0
- package/dist/ast/html/TextNode.js +23 -0
- package/dist/ast/nodes.d.ts +15 -0
- package/dist/ast/nodes.js +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/parser/parser.d.ts +6 -0
- package/dist/parser/parser.js +71 -0
- package/dist/utils/utils.d.ts +7 -0
- package/dist/utils/utils.js +74 -0
- package/package.json +37 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawElementNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { generateCtxId, getAtAttributes, getPos } from "../../utils/utils.js";
|
|
5
|
+
class IncludeNode extends Node {
|
|
6
|
+
ctxId;
|
|
7
|
+
path;
|
|
8
|
+
children;
|
|
9
|
+
constructor(ctxId, path, children, pos) {
|
|
10
|
+
super(NodeType.Include, pos);
|
|
11
|
+
this.ctxId = ctxId;
|
|
12
|
+
this.path = path;
|
|
13
|
+
this.children = children;
|
|
14
|
+
}
|
|
15
|
+
getChildren() {
|
|
16
|
+
return this.children;
|
|
17
|
+
}
|
|
18
|
+
static newFromRawNode(node, fileName, rawAstParserFn) {
|
|
19
|
+
if (!isRawElementNode(node)) {
|
|
20
|
+
throw new Error(`Expected an element node but found '${node.nodeName}'. ` +
|
|
21
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
22
|
+
}
|
|
23
|
+
if (node.tagName !== "include") {
|
|
24
|
+
throw new Error(`Expected element tag name 'include' but found '${node.tagName}'. ` +
|
|
25
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
26
|
+
}
|
|
27
|
+
const atAttrs = getAtAttributes(node, fileName);
|
|
28
|
+
if (atAttrs.length < 1) {
|
|
29
|
+
throw new Error(`Missing @[path] attribute on <include> tag. ` +
|
|
30
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
31
|
+
}
|
|
32
|
+
else if (atAttrs.length > 1) {
|
|
33
|
+
throw new Error(`Multiple @ attributes on <include> tag are not allowed: found [${atAttrs.map(a => a.name).join(", ")}]. ` +
|
|
34
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
35
|
+
}
|
|
36
|
+
const children = rawAstParserFn(node.childNodes, fileName);
|
|
37
|
+
const ctxId = generateCtxId();
|
|
38
|
+
const pos = getPos(node, fileName);
|
|
39
|
+
return new IncludeNode(ctxId, atAttrs[0], children, pos);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export default IncludeNode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import Pos from "../base/Pos.js";
|
|
3
|
+
import { RawChildNode } from "../base/parse5-types.js";
|
|
4
|
+
declare class LogicNode extends Node {
|
|
5
|
+
lang: string;
|
|
6
|
+
data: string;
|
|
7
|
+
constructor(lang: string, data: string, pos: Pos);
|
|
8
|
+
getChildren(): Node[];
|
|
9
|
+
static newFromRawNode(node: RawChildNode, fileName: string): Node | null;
|
|
10
|
+
}
|
|
11
|
+
export default LogicNode;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawElementNode, isRawTextNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { getAtAttributes, getPos } from "../../utils/utils.js";
|
|
5
|
+
class LogicNode extends Node {
|
|
6
|
+
lang;
|
|
7
|
+
data;
|
|
8
|
+
constructor(lang, data, pos) {
|
|
9
|
+
super(NodeType.Logic, pos);
|
|
10
|
+
this.lang = lang;
|
|
11
|
+
this.data = data;
|
|
12
|
+
}
|
|
13
|
+
getChildren() {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
static newFromRawNode(node, fileName) {
|
|
17
|
+
if (!isRawElementNode(node)) {
|
|
18
|
+
throw new Error(`Expected an element node but found '${node.nodeName}'. ` +
|
|
19
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
20
|
+
}
|
|
21
|
+
if (node.tagName !== "logic") {
|
|
22
|
+
throw new Error(`Expected element tag name 'logic' but found '${node.tagName}'. ` +
|
|
23
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
24
|
+
}
|
|
25
|
+
const atAttrs = getAtAttributes(node, fileName);
|
|
26
|
+
if (atAttrs.length < 1) {
|
|
27
|
+
throw new Error(`Missing @[lang] attribute on <logic> tag. ` +
|
|
28
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
29
|
+
}
|
|
30
|
+
else if (atAttrs.length > 1) {
|
|
31
|
+
throw new Error(`Multiple @ attributes on <logic> tag are not allowed: found [${atAttrs.map(a => a.name).join(", ")}]. ` +
|
|
32
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
33
|
+
}
|
|
34
|
+
if (node.childNodes.length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
let outData = "";
|
|
37
|
+
for (const child of node.childNodes) {
|
|
38
|
+
if (!isRawTextNode(child)) {
|
|
39
|
+
throw new Error(`Invalid child node inside <logic>: found '${child.nodeName}' but only text or comment nodes are allowed. ` +
|
|
40
|
+
`File: ${fileName}, Line: ${child.sourceCodeLocation?.startLine ?? "?"}, Col: ${child.sourceCodeLocation?.startCol ?? "?"}`);
|
|
41
|
+
}
|
|
42
|
+
outData += child.value;
|
|
43
|
+
}
|
|
44
|
+
const pos = getPos(node, fileName);
|
|
45
|
+
return new LogicNode(atAttrs[0].name, outData, pos);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export default LogicNode;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import Pos from "../base/Pos.js";
|
|
3
|
+
import { RawChildNode } from "../base/parse5-types.js";
|
|
4
|
+
declare class OutNode extends Node {
|
|
5
|
+
data: string;
|
|
6
|
+
isRaw: boolean;
|
|
7
|
+
constructor(data: string, isRaw: boolean, pos: Pos);
|
|
8
|
+
getChildren(): Node[];
|
|
9
|
+
static newFromRawNode(node: RawChildNode, fileName: string): Node | null;
|
|
10
|
+
}
|
|
11
|
+
export default OutNode;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawElementNode, isRawTextNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { getAtAttributes, getPos } from "../../utils/utils.js";
|
|
5
|
+
class OutNode extends Node {
|
|
6
|
+
data;
|
|
7
|
+
isRaw;
|
|
8
|
+
constructor(data, isRaw, pos) {
|
|
9
|
+
super(NodeType.Out, pos);
|
|
10
|
+
this.data = data;
|
|
11
|
+
this.isRaw = isRaw;
|
|
12
|
+
}
|
|
13
|
+
getChildren() {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
static newFromRawNode(node, fileName) {
|
|
17
|
+
if (!isRawElementNode(node)) {
|
|
18
|
+
throw new Error(`Expected an element node but found '${node.nodeName}'. ` +
|
|
19
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
20
|
+
}
|
|
21
|
+
if (node.tagName !== "out") {
|
|
22
|
+
throw new Error(`Expected element tag name 'content' but found '${node.tagName}'. ` +
|
|
23
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
24
|
+
}
|
|
25
|
+
const atAttrs = getAtAttributes(node, fileName);
|
|
26
|
+
if (atAttrs.length > 1) {
|
|
27
|
+
throw new Error(`Multiple @ attributes on <out> tag are not allowed: found [${atAttrs.map(a => a.name).join(", ")}]. ` +
|
|
28
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
29
|
+
}
|
|
30
|
+
if (node.childNodes.length === 0)
|
|
31
|
+
return null;
|
|
32
|
+
let outData = "";
|
|
33
|
+
for (const child of node.childNodes) {
|
|
34
|
+
if (!isRawTextNode(child)) {
|
|
35
|
+
throw new Error(`Invalid child node inside <out>: found '${child.nodeName}' but only text or comment nodes are allowed. ` +
|
|
36
|
+
`File: ${fileName}, Line: ${child.sourceCodeLocation?.startLine ?? "?"}, Col: ${child.sourceCodeLocation?.startCol ?? "?"}`);
|
|
37
|
+
}
|
|
38
|
+
outData += child.value;
|
|
39
|
+
}
|
|
40
|
+
const isRaw = atAttrs.length > 0 ? atAttrs[0].name === "raw" ? true : false : false;
|
|
41
|
+
const pos = getPos(node, fileName);
|
|
42
|
+
return new OutNode(outData, isRaw, pos);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export default OutNode;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import Pos from "../base/Pos.js";
|
|
3
|
+
import { RawChildNode } from "../base/parse5-types.js";
|
|
4
|
+
import { RawASTParserFunction } from "../base/parser-types.js";
|
|
5
|
+
declare class SlotNode extends Node {
|
|
6
|
+
name: string;
|
|
7
|
+
children: Node[];
|
|
8
|
+
constructor(name: string, children: Node[], pos: Pos);
|
|
9
|
+
getChildren(): Node[];
|
|
10
|
+
static newFromRawNode(node: RawChildNode, fileName: string, rawAstParserFn: RawASTParserFunction): Node;
|
|
11
|
+
}
|
|
12
|
+
export default SlotNode;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawElementNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { getAtAttributes, getPos } from "../../utils/utils.js";
|
|
5
|
+
class SlotNode extends Node {
|
|
6
|
+
name;
|
|
7
|
+
children;
|
|
8
|
+
constructor(name, children, pos) {
|
|
9
|
+
super(NodeType.Slot, pos);
|
|
10
|
+
this.name = name;
|
|
11
|
+
this.children = children;
|
|
12
|
+
}
|
|
13
|
+
getChildren() {
|
|
14
|
+
return this.children;
|
|
15
|
+
}
|
|
16
|
+
static newFromRawNode(node, fileName, rawAstParserFn) {
|
|
17
|
+
if (!isRawElementNode(node)) {
|
|
18
|
+
throw new Error(`Expected an element node but found '${node.nodeName}'. ` +
|
|
19
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
20
|
+
}
|
|
21
|
+
if (node.tagName !== "slot") {
|
|
22
|
+
throw new Error(`Expected element tag name 'slot' but found '${node.tagName}'. ` +
|
|
23
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
24
|
+
}
|
|
25
|
+
const atAttrs = getAtAttributes(node, fileName);
|
|
26
|
+
if (atAttrs.length < 1) {
|
|
27
|
+
throw new Error(`Missing @[name] attribute on <slot> tag. ` +
|
|
28
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
29
|
+
}
|
|
30
|
+
else if (atAttrs.length > 1) {
|
|
31
|
+
throw new Error(`Multiple @ attributes on <slot> tag are not allowed: found [${atAttrs.map(a => a.name).join(", ")}]. ` +
|
|
32
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
33
|
+
}
|
|
34
|
+
const children = rawAstParserFn(node.childNodes, fileName);
|
|
35
|
+
const pos = getPos(node, fileName);
|
|
36
|
+
return new SlotNode(atAttrs[0].value, children, pos);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export default SlotNode;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import Pos from "../base/Pos.js";
|
|
3
|
+
import { RawChildNode } from "../base/parse5-types.js";
|
|
4
|
+
import { RawASTParserFunction } from "../base/parser-types.js";
|
|
5
|
+
import { Attribute } from "../html/Attribute.js";
|
|
6
|
+
declare class TempileNode extends Node {
|
|
7
|
+
nodeTypeData: string;
|
|
8
|
+
attrs: Attribute[];
|
|
9
|
+
children: Node[];
|
|
10
|
+
constructor(nodeTypeData: string, attrs: Attribute[], children: Node[], pos: Pos);
|
|
11
|
+
getChildren(): Node[];
|
|
12
|
+
static newFromRawNode(node: RawChildNode, fileName: string, rawAstParserFn: RawASTParserFunction): Node;
|
|
13
|
+
}
|
|
14
|
+
export default TempileNode;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawElementNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { getAtAttributes, getNonAtAttributes, getPos } from "../../utils/utils.js";
|
|
5
|
+
import DoctypeNode from "../html/DoctypeNode.js";
|
|
6
|
+
import { ElementNode } from "../nodes.js";
|
|
7
|
+
class TempileNode extends Node {
|
|
8
|
+
nodeTypeData;
|
|
9
|
+
attrs;
|
|
10
|
+
children;
|
|
11
|
+
constructor(nodeTypeData, attrs, children, pos) {
|
|
12
|
+
super(NodeType.Tempile, pos);
|
|
13
|
+
this.nodeTypeData = nodeTypeData;
|
|
14
|
+
this.attrs = attrs;
|
|
15
|
+
this.children = children;
|
|
16
|
+
}
|
|
17
|
+
getChildren() {
|
|
18
|
+
return this.children;
|
|
19
|
+
}
|
|
20
|
+
static newFromRawNode(node, fileName, rawAstParserFn) {
|
|
21
|
+
if (!isRawElementNode(node)) {
|
|
22
|
+
throw new Error(`Expected an element node but found '${node.nodeName}'. ` +
|
|
23
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
24
|
+
}
|
|
25
|
+
if (node.tagName !== "tempile") {
|
|
26
|
+
throw new Error(`Expected element tag name 'tempile' but found '${node.tagName}'. ` +
|
|
27
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
28
|
+
}
|
|
29
|
+
const atAttrs = getAtAttributes(node, fileName);
|
|
30
|
+
if (atAttrs.length < 1) {
|
|
31
|
+
throw new Error(`Missing @[type] attribute on <tempile> tag. ` +
|
|
32
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
33
|
+
}
|
|
34
|
+
else if (atAttrs.length > 1) {
|
|
35
|
+
throw new Error(`Multiple @ attributes on <tempile> tag are not allowed: found [${atAttrs.map(a => a.name).join(", ")}]. ` +
|
|
36
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
37
|
+
}
|
|
38
|
+
const nodeTypeAttr = atAttrs[0].name;
|
|
39
|
+
const allowedAttrs = ["doctype", "html", "head", "body"];
|
|
40
|
+
if (!allowedAttrs.includes(nodeTypeAttr)) {
|
|
41
|
+
throw new Error(`Invalid @ attribute '${nodeTypeAttr}' on <tempile> tag. Expected one of: ${allowedAttrs.join(", ")}. ` +
|
|
42
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
43
|
+
}
|
|
44
|
+
const nonAtAttrs = getNonAtAttributes(node, fileName);
|
|
45
|
+
const children = rawAstParserFn(node.childNodes, fileName);
|
|
46
|
+
const pos = getPos(node, fileName);
|
|
47
|
+
if (nodeTypeAttr === "doctype") {
|
|
48
|
+
return new DoctypeNode("<!DOCTYPE html>", pos);
|
|
49
|
+
}
|
|
50
|
+
return new ElementNode(nodeTypeAttr, nonAtAttrs, children, pos);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export default TempileNode;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Pos from "../base/Pos.js";
|
|
2
|
+
type AttrValueNode = {
|
|
3
|
+
type: "text";
|
|
4
|
+
value: string;
|
|
5
|
+
} | {
|
|
6
|
+
type: "expr";
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
type Attribute = {
|
|
10
|
+
name: string;
|
|
11
|
+
value: string;
|
|
12
|
+
valueNodes?: AttrValueNode[];
|
|
13
|
+
pos: Pos;
|
|
14
|
+
};
|
|
15
|
+
export { Attribute, AttrValueNode };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import Pos from "../base/Pos.js";
|
|
3
|
+
import { RawChildNode } from "../base/parse5-types.js";
|
|
4
|
+
declare class CommentNode extends Node {
|
|
5
|
+
data: string;
|
|
6
|
+
constructor(data: string, pos: Pos);
|
|
7
|
+
getChildren(): Node[];
|
|
8
|
+
static newFromRawNode(node: RawChildNode, fileName: string): Node;
|
|
9
|
+
}
|
|
10
|
+
export default CommentNode;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawCommentNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { getPos } from "../../utils/utils.js";
|
|
5
|
+
class CommentNode extends Node {
|
|
6
|
+
data;
|
|
7
|
+
constructor(data, pos) {
|
|
8
|
+
super(NodeType.Comment, pos);
|
|
9
|
+
this.data = data;
|
|
10
|
+
}
|
|
11
|
+
getChildren() {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
static newFromRawNode(node, fileName) {
|
|
15
|
+
if (!isRawCommentNode(node)) {
|
|
16
|
+
throw new Error(`Expected an comment node but found '${node.nodeName}'. ` +
|
|
17
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
18
|
+
}
|
|
19
|
+
const pos = getPos(node, fileName);
|
|
20
|
+
return new CommentNode(node.data, pos);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export default CommentNode;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
class DoctypeNode extends Node {
|
|
4
|
+
data;
|
|
5
|
+
constructor(data, pos) {
|
|
6
|
+
super(NodeType.Doctype, pos);
|
|
7
|
+
this.data = data;
|
|
8
|
+
}
|
|
9
|
+
getChildren() {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export default DoctypeNode;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import Pos from "../base/Pos.js";
|
|
3
|
+
import { Attribute } from "./Attribute.js";
|
|
4
|
+
import { RawChildNode } from "../base/parse5-types.js";
|
|
5
|
+
import { RawASTParserFunction } from "../base/parser-types.js";
|
|
6
|
+
declare class ElementNode extends Node {
|
|
7
|
+
tag: string;
|
|
8
|
+
attrs: Attribute[];
|
|
9
|
+
children: Node[];
|
|
10
|
+
constructor(tag: string, attrs: Attribute[], children: Node[], pos: Pos);
|
|
11
|
+
getChildren(): Node[];
|
|
12
|
+
static newFromRawNode(node: RawChildNode, fileName: string, rawAstParserFn: RawASTParserFunction): Node;
|
|
13
|
+
}
|
|
14
|
+
export default ElementNode;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawElementNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { getNonAtAttributes, getPos } from "../../utils/utils.js";
|
|
5
|
+
class ElementNode extends Node {
|
|
6
|
+
tag;
|
|
7
|
+
attrs;
|
|
8
|
+
children;
|
|
9
|
+
constructor(tag, attrs, children, pos) {
|
|
10
|
+
super(NodeType.Element, pos);
|
|
11
|
+
this.tag = tag;
|
|
12
|
+
this.children = children;
|
|
13
|
+
this.attrs = attrs;
|
|
14
|
+
}
|
|
15
|
+
getChildren() {
|
|
16
|
+
return this.children;
|
|
17
|
+
}
|
|
18
|
+
static newFromRawNode(node, fileName, rawAstParserFn) {
|
|
19
|
+
if (!isRawElementNode(node)) {
|
|
20
|
+
throw new Error(`Expected an element node but found '${node.nodeName}'. ` +
|
|
21
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
22
|
+
}
|
|
23
|
+
const nonAtAttrs = getNonAtAttributes(node, fileName);
|
|
24
|
+
const children = rawAstParserFn(node.childNodes, fileName);
|
|
25
|
+
const pos = getPos(node, fileName);
|
|
26
|
+
return new ElementNode(node.tagName, nonAtAttrs, children, pos);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export default ElementNode;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import Pos from "../base/Pos.js";
|
|
3
|
+
import { RawChildNode } from "../base/parse5-types.js";
|
|
4
|
+
declare class TextNode extends Node {
|
|
5
|
+
data: string;
|
|
6
|
+
constructor(data: string, pos: Pos);
|
|
7
|
+
getChildren(): Node[];
|
|
8
|
+
static newFromRawNode(node: RawChildNode, fileName: string): Node;
|
|
9
|
+
}
|
|
10
|
+
export default TextNode;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Node from "../base/Node.js";
|
|
2
|
+
import NodeType from "../base/node-types.js";
|
|
3
|
+
import { isRawTextNode } from "../base/parse5-type-guards.js";
|
|
4
|
+
import { getPos } from "../../utils/utils.js";
|
|
5
|
+
class TextNode extends Node {
|
|
6
|
+
data;
|
|
7
|
+
constructor(data, pos) {
|
|
8
|
+
super(NodeType.Text, pos);
|
|
9
|
+
this.data = data;
|
|
10
|
+
}
|
|
11
|
+
getChildren() {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
static newFromRawNode(node, fileName) {
|
|
15
|
+
if (!isRawTextNode(node)) {
|
|
16
|
+
throw new Error(`Expected an text node but found '${node.nodeName}'. ` +
|
|
17
|
+
`File: ${fileName}, Line: ${node.sourceCodeLocation?.startLine ?? "?"}, Col: ${node.sourceCodeLocation?.startCol ?? "?"}`);
|
|
18
|
+
}
|
|
19
|
+
const pos = getPos(node, fileName);
|
|
20
|
+
return new TextNode(node.value, pos);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export default TextNode;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ImportNode from "./features/ImportNode.js";
|
|
2
|
+
import TempileNode from "./features/TempileNode.js";
|
|
3
|
+
import CommentNode from "./html/CommentNode.js";
|
|
4
|
+
import TextNode from "./html/TextNode.js";
|
|
5
|
+
import ElementNode from "./html/ElementNode.js";
|
|
6
|
+
import IfNode from "./control/IfNode.js";
|
|
7
|
+
import ElseIfNode from "./control/ElseIfNode.js";
|
|
8
|
+
import ElseNode from "./control/ElseNode.js";
|
|
9
|
+
import ForNode from "./control/ForNode.js";
|
|
10
|
+
import IncludeNode from "./features/IncludeNode.js";
|
|
11
|
+
import SlotNode from "./features/SlotNode.js";
|
|
12
|
+
import ContentNode from "./features/ContentNode.js";
|
|
13
|
+
import OutNode from "./features/OutNode.js";
|
|
14
|
+
import LogicNode from "./features/LogicNode.js";
|
|
15
|
+
export { ImportNode, TempileNode, CommentNode, TextNode, ElementNode, IfNode, ElseIfNode, ElseNode, ForNode, IncludeNode, SlotNode, ContentNode, OutNode, LogicNode };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ImportNode from "./features/ImportNode.js";
|
|
2
|
+
import TempileNode from "./features/TempileNode.js";
|
|
3
|
+
import CommentNode from "./html/CommentNode.js";
|
|
4
|
+
import TextNode from "./html/TextNode.js";
|
|
5
|
+
import ElementNode from "./html/ElementNode.js";
|
|
6
|
+
import IfNode from "./control/IfNode.js";
|
|
7
|
+
import ElseIfNode from "./control/ElseIfNode.js";
|
|
8
|
+
import ElseNode from "./control/ElseNode.js";
|
|
9
|
+
import ForNode from "./control/ForNode.js";
|
|
10
|
+
import IncludeNode from "./features/IncludeNode.js";
|
|
11
|
+
import SlotNode from "./features/SlotNode.js";
|
|
12
|
+
import ContentNode from "./features/ContentNode.js";
|
|
13
|
+
import OutNode from "./features/OutNode.js";
|
|
14
|
+
import LogicNode from "./features/LogicNode.js";
|
|
15
|
+
export { ImportNode, TempileNode, CommentNode, TextNode, ElementNode, IfNode, ElseIfNode, ElseNode, ForNode, IncludeNode, SlotNode, ContentNode, OutNode, LogicNode };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import Node from "../ast/base/Node.js";
|
|
2
|
+
import type { RawChildNode } from "../ast/base/parse5-types.js";
|
|
3
|
+
import Root from "../ast/base/Root.js";
|
|
4
|
+
declare function parse(source: string, fileName: string): Root;
|
|
5
|
+
declare function parseRawAST(raw: RawChildNode[], fileName: string): Node[];
|
|
6
|
+
export { parse, parseRawAST };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { parseFragment } from "parse5";
|
|
2
|
+
import * as Nodes from "../ast/nodes.js";
|
|
3
|
+
import Root from "../ast/base/Root.js";
|
|
4
|
+
function parse(source, fileName) {
|
|
5
|
+
const raw = parseFragment(source, { sourceCodeLocationInfo: true });
|
|
6
|
+
const nodes = parseRawAST(raw.childNodes, fileName);
|
|
7
|
+
return new Root(nodes, fileName);
|
|
8
|
+
}
|
|
9
|
+
function parseRawAST(raw, fileName) {
|
|
10
|
+
const nodes = [];
|
|
11
|
+
for (const node of raw) {
|
|
12
|
+
switch (node.nodeName) {
|
|
13
|
+
case "#text":
|
|
14
|
+
nodes.push(Nodes.TextNode.newFromRawNode(node, fileName));
|
|
15
|
+
break;
|
|
16
|
+
case "#comment":
|
|
17
|
+
nodes.push(Nodes.CommentNode.newFromRawNode(node, fileName));
|
|
18
|
+
break;
|
|
19
|
+
case "import":
|
|
20
|
+
nodes.push(Nodes.ImportNode.newFromRawNode(node, fileName, parseRawAST));
|
|
21
|
+
break;
|
|
22
|
+
case "tempile":
|
|
23
|
+
nodes.push(Nodes.TempileNode.newFromRawNode(node, fileName, parseRawAST));
|
|
24
|
+
break;
|
|
25
|
+
case "if":
|
|
26
|
+
const ifNode = Nodes.IfNode.newFromRawNode(node, fileName, parseRawAST);
|
|
27
|
+
if (ifNode)
|
|
28
|
+
nodes.push(ifNode);
|
|
29
|
+
break;
|
|
30
|
+
case "elseif":
|
|
31
|
+
const elseIfNode = Nodes.ElseIfNode.newFromRawNode(node, fileName, parseRawAST);
|
|
32
|
+
if (elseIfNode)
|
|
33
|
+
nodes.push(elseIfNode);
|
|
34
|
+
break;
|
|
35
|
+
case "else":
|
|
36
|
+
const elseNode = Nodes.ElseNode.newFromRawNode(node, fileName, parseRawAST);
|
|
37
|
+
if (elseNode)
|
|
38
|
+
nodes.push(elseNode);
|
|
39
|
+
break;
|
|
40
|
+
case "for":
|
|
41
|
+
const forNode = Nodes.ForNode.newFromRawNode(node, fileName, parseRawAST);
|
|
42
|
+
if (forNode)
|
|
43
|
+
nodes.push(forNode);
|
|
44
|
+
break;
|
|
45
|
+
case "include":
|
|
46
|
+
nodes.push(Nodes.IncludeNode.newFromRawNode(node, fileName, parseRawAST));
|
|
47
|
+
break;
|
|
48
|
+
case "slot":
|
|
49
|
+
nodes.push(Nodes.SlotNode.newFromRawNode(node, fileName, parseRawAST));
|
|
50
|
+
break;
|
|
51
|
+
case "content":
|
|
52
|
+
nodes.push(Nodes.ContentNode.newFromRawNode(node, fileName, parseRawAST));
|
|
53
|
+
break;
|
|
54
|
+
case "out":
|
|
55
|
+
const outNode = Nodes.OutNode.newFromRawNode(node, fileName);
|
|
56
|
+
if (outNode)
|
|
57
|
+
nodes.push(outNode);
|
|
58
|
+
break;
|
|
59
|
+
case "logic":
|
|
60
|
+
const logicNode = Nodes.LogicNode.newFromRawNode(node, fileName);
|
|
61
|
+
if (logicNode)
|
|
62
|
+
nodes.push(logicNode);
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
nodes.push(Nodes.ElementNode.newFromRawNode(node, fileName, parseRawAST));
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return nodes;
|
|
70
|
+
}
|
|
71
|
+
export { parse, parseRawAST };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RawChildNode, RawElementNode } from "../ast/base/parse5-types.js";
|
|
2
|
+
import Pos from "../ast/base/Pos.js";
|
|
3
|
+
import { Attribute } from "../ast/html/Attribute.js";
|
|
4
|
+
export declare function getAtAttributes(node: RawElementNode, fileName: string): Attribute[];
|
|
5
|
+
export declare function getNonAtAttributes(node: RawElementNode, fileName: string): Attribute[];
|
|
6
|
+
export declare function generateCtxId(): string;
|
|
7
|
+
export declare function getPos(node: RawChildNode, fileName: string): Pos;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export function getAtAttributes(node, fileName) {
|
|
2
|
+
return node.attrs
|
|
3
|
+
.filter(attr => attr.name.startsWith("@"))
|
|
4
|
+
.map(attr => ({
|
|
5
|
+
name: attr.name.slice(1),
|
|
6
|
+
value: attr.value,
|
|
7
|
+
pos: getAttrPos(node, attr.name, fileName),
|
|
8
|
+
valueNodes: []
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
export function getNonAtAttributes(node, fileName) {
|
|
12
|
+
return node.attrs
|
|
13
|
+
.filter(attr => !attr.name.startsWith("@"))
|
|
14
|
+
.map(attr => ({
|
|
15
|
+
name: attr.name,
|
|
16
|
+
value: attr.value,
|
|
17
|
+
pos: getAttrPos(node, attr.name, fileName),
|
|
18
|
+
valueNodes: parseAttrValue(attr.value)
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
function parseAttrValue(value) {
|
|
22
|
+
const regex = /{{(.*?)}}/g;
|
|
23
|
+
const nodes = [];
|
|
24
|
+
let lastIndex = 0;
|
|
25
|
+
let match;
|
|
26
|
+
while ((match = regex.exec(value)) !== null) {
|
|
27
|
+
if (match.index > lastIndex) {
|
|
28
|
+
nodes.push({
|
|
29
|
+
type: "text",
|
|
30
|
+
value: value.slice(lastIndex, match.index)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
nodes.push({
|
|
34
|
+
type: "expr",
|
|
35
|
+
value: match[1].trim()
|
|
36
|
+
});
|
|
37
|
+
lastIndex = match.index + match[0].length;
|
|
38
|
+
}
|
|
39
|
+
if (lastIndex < value.length) {
|
|
40
|
+
nodes.push({
|
|
41
|
+
type: "text",
|
|
42
|
+
value: value.slice(lastIndex)
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return nodes;
|
|
46
|
+
}
|
|
47
|
+
function getAttrPos(node, attrName, fileName) {
|
|
48
|
+
return {
|
|
49
|
+
fileName: fileName,
|
|
50
|
+
startLine: node.sourceCodeLocation?.attrs?.[attrName].startLine,
|
|
51
|
+
startCol: node.sourceCodeLocation?.attrs?.[attrName].startCol,
|
|
52
|
+
startOffset: node.sourceCodeLocation?.attrs?.[attrName].startOffset,
|
|
53
|
+
endLine: node.sourceCodeLocation?.attrs?.[attrName].endLine,
|
|
54
|
+
endCol: node.sourceCodeLocation?.attrs?.[attrName].endCol,
|
|
55
|
+
endOffset: node.sourceCodeLocation?.attrs?.[attrName].endOffset
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function generateCtxId() {
|
|
59
|
+
const bytes = new Uint8Array(16);
|
|
60
|
+
crypto.getRandomValues(bytes);
|
|
61
|
+
return Buffer.from(bytes).toString("base64");
|
|
62
|
+
}
|
|
63
|
+
export function getPos(node, fileName) {
|
|
64
|
+
const pos = {
|
|
65
|
+
fileName: fileName,
|
|
66
|
+
startLine: node.sourceCodeLocation?.startLine,
|
|
67
|
+
startCol: node.sourceCodeLocation?.startCol,
|
|
68
|
+
startOffset: node.sourceCodeLocation?.startOffset,
|
|
69
|
+
endLine: node.sourceCodeLocation?.endLine,
|
|
70
|
+
endCol: node.sourceCodeLocation?.endCol,
|
|
71
|
+
endOffset: node.sourceCodeLocation?.endOffset
|
|
72
|
+
};
|
|
73
|
+
return pos;
|
|
74
|
+
}
|