Skip to content

Commit f43fb98

Browse files
dhloloIntiChenLei
authored
feat: support parse interpolation in WXAttribute (#25)
* fix: #19 * fix: 修正測試用例 * fix: add new unit test * fix: mv incoordination raw to rawValue * fix: inline <wxs * fix: remove .vscode * feat: support WXAttributeInterpolation and improve code Co-authored-by: Int <[email protected]> Co-authored-by: iChenLei <[email protected]>
1 parent b55f7a1 commit f43fb98

File tree

11 files changed

+516
-80
lines changed

11 files changed

+516
-80
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# @wxml/parser is Lei Chen's personal project
22
# Owner
3-
* @iChenLei
3+
* @iChenLei
4+
# Collaborator
5+
src/ @dhlolo

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ lib
33
dist
44
.DS_store
55
.idea
6-
src/vscodedebug/test.ts
6+
src/vscodedebug/test.ts

.vscode/launch.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
{
2-
// Use IntelliSense to learn about possible attributes.
3-
// Hover to view descriptions of existing attributes.
4-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
52
"version": "0.2.0",
63
"configurations": [
74
{

src/ast/build-ast.ts

Lines changed: 124 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
convertLexerErrorToNode,
99
convertParseErrorToNode,
1010
sortTokenChildren,
11+
sortASTNode,
1112
} from "./util";
1213

1314
type ICtx = Record<string, CstNode[]>;
@@ -87,15 +88,19 @@ class CstToAstVisitor extends BaseWxmlCstVisitor {
8788
mergeLocation(astNode.startTag, startTagLocation);
8889
}
8990

90-
if (ctx.SLASH_OPEN?.[0] && ctx.END?.[0]) {
91+
if (ctx.WXS_SLASH_CLOSE?.[0]) {
9192
astNode.endTag = {
9293
type: "WXEndTag",
93-
name: get(ctx, "END_NAME[0].image"),
94-
};
95-
const endTagLocation = {
96-
...pick(ctx.SLASH_OPEN[0], ["startOffset", "startLine", "startColumn"]),
97-
...pick(ctx.END[0], ["endOffset", "endLine", "endColumn"]),
94+
name: "wxs",
9895
};
96+
const endTagLocation = pick(ctx.WXS_SLASH_CLOSE[0], [
97+
"startOffset",
98+
"startLine",
99+
"startColumn",
100+
"endOffset",
101+
"endLine",
102+
"endColumn",
103+
]);
99104
mergeLocation(astNode.endTag, endTagLocation);
100105
}
101106

@@ -118,8 +123,8 @@ class CstToAstVisitor extends BaseWxmlCstVisitor {
118123
if (ctx.SEA_WS !== undefined) {
119124
allTokens = allTokens.concat(ctx.SEA_WS);
120125
}
121-
if (ctx.WXS_TEXT !== undefined) {
122-
allTokens = allTokens.concat(ctx.WXS_TEXT);
126+
if (ctx.INLINE_WXS_TEXT !== undefined) {
127+
allTokens = allTokens.concat(ctx.INLINE_WXS_TEXT);
123128
}
124129
const sortedTokens = sortBy(allTokens, ["startOffset"]);
125130
const fullText = map(sortedTokens, "image").join("");
@@ -130,19 +135,122 @@ class CstToAstVisitor extends BaseWxmlCstVisitor {
130135
* AST - WXAttribute
131136
*/
132137
attribute(ctx, { location }) {
133-
const rawValue = get(ctx, "STRING[0].image") || null;
134-
const value = rawValue
135-
? rawValue
136-
.split("")
137-
.slice(1, rawValue.length - 1)
138-
.join("")
138+
const attributeValue = ctx.attributeValue
139+
? this.visit(ctx.attributeValue[0])
139140
: null;
141+
140142
const astNode = {
141143
type: "WXAttribute",
142144
key: ctx.NAME[0].image,
145+
quote: null,
146+
value: null,
147+
rawValue: null,
148+
...(attributeValue || {}),
149+
};
150+
mergeLocation(astNode, location);
151+
return astNode;
152+
}
153+
154+
/**
155+
* AST - WXAttributeValue
156+
*/
157+
attributeValue(ctx, { location }) {
158+
if (ctx.PURE_STRING !== undefined) {
159+
const raw = ctx.PURE_STRING[0].image;
160+
const astNode = {
161+
value: raw
162+
.split("")
163+
.slice(1, raw.length - 1)
164+
.join(""),
165+
rawValue: ctx.PURE_STRING[0].image,
166+
children: [],
167+
interpolations: [],
168+
quote: raw?.length ? raw.slice(0, 1) : null,
169+
};
170+
mergeLocation(astNode, location);
171+
return astNode;
172+
} else if (ctx.doubleQuoteAttributeVal !== undefined) {
173+
return this.visit(ctx.doubleQuoteAttributeVal[0]);
174+
} else if (ctx.singleQuoteAttributeVal !== undefined) {
175+
return this.visit(ctx.singleQuoteAttributeVal[0]);
176+
}
177+
}
178+
179+
doubleQuoteAttributeVal(ctx, { location }) {
180+
const interpolationASTS = map(
181+
ctx.attributeValInterpolation,
182+
this.visit.bind(this)
183+
);
184+
const quote = '"';
185+
let strASTs = map(ctx.PURE_STRING_IN_DOUBLE_QUOTE, (item) => {
186+
const astNode = {
187+
value: item.image,
188+
type: "WXText",
189+
};
190+
mergeLocation(astNode, item);
191+
return astNode;
192+
});
193+
const sortedValue = sortASTNode(interpolationASTS.concat(strASTs));
194+
// @ts-expect-error
195+
const value = sortedValue.map((v) => v.rawValue || v.value).join("");
196+
197+
const astNode = {
198+
value,
199+
rawValue: quote + value + quote,
200+
children: sortedValue,
201+
interpolations: interpolationASTS.map((intp) => {
202+
return {
203+
...intp,
204+
type: "WXInterpolation",
205+
};
206+
}),
207+
quote: quote,
208+
};
209+
mergeLocation(astNode, location);
210+
return astNode;
211+
}
212+
213+
attributeValInterpolation(ctx, { location }) {
214+
const child = sortTokenChildren(ctx);
215+
// @ts-expect-error
216+
const value = (child || []).map((token) => token.image).join("");
217+
const astNode = {
218+
type: "WXAttributeInterpolation",
219+
rawValue: value,
220+
value: value.replace(/^{{/, "").replace(/}}$/, ""),
221+
};
222+
mergeLocation(astNode, location);
223+
return astNode;
224+
}
225+
226+
singleQuoteAttributeVal(ctx, { location }) {
227+
const interpolationASTS = map(
228+
ctx.attributeValInterpolation,
229+
this.visit.bind(this)
230+
);
231+
const quote = "'";
232+
let strASTs = map(ctx.PURE_STRING_IN_SINGLE_QUOTE, (item) => {
233+
const astNode = {
234+
value: item.image,
235+
type: "WXText",
236+
};
237+
mergeLocation(astNode, item);
238+
return astNode;
239+
});
240+
const sortedValue = sortASTNode(interpolationASTS.concat(strASTs));
241+
// @ts-expect-error
242+
const value = sortedValue.map((v) => v.rawValue || v.value).join("");
243+
const astNode = {
143244
value,
144-
rawValue,
145-
quote: rawValue?.length ? rawValue.slice(0, 1) : null,
245+
rawValue: quote + value + quote,
246+
children: sortedValue,
247+
interpolations: interpolationASTS.map((intp) => {
248+
return {
249+
...intp,
250+
type: "WXInterpolation",
251+
};
252+
}),
253+
quote: quote,
146254
};
147255
mergeLocation(astNode, location);
148256
return astNode;

src/ast/util.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,35 @@ interface IEspreeError {
1313
stack: string;
1414
}
1515

16+
interface ASTNode {
17+
loc: {
18+
start: {
19+
line: number;
20+
column: number;
21+
};
22+
};
23+
}
24+
25+
export function sortASTNode(nodes: Array<ASTNode>): Array<ASTNode> {
26+
let nodeASTs = [];
27+
nodes.forEach((node) => {
28+
nodeASTs.push(node);
29+
});
30+
let sortedNodes = [];
31+
sortedNodes = nodes.sort((nodeA, nodeB) => {
32+
if (
33+
nodeA.loc.start.line > nodeB.loc.start.line ||
34+
(nodeA.loc.start.line === nodeB.loc.start.line &&
35+
nodeA.loc.start.column > nodeB.loc.start.column)
36+
) {
37+
return 1;
38+
} else {
39+
return -1;
40+
}
41+
});
42+
return sortedNodes;
43+
}
44+
1645
/**
1746
* sort token children
1847
*/

0 commit comments

Comments
 (0)