Skip to content

Commit

Permalink
feat: support parse interpolation in WXAttribute (#25)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored Mar 24, 2022
1 parent b55f7a1 commit f43fb98
Show file tree
Hide file tree
Showing 11 changed files with 516 additions and 80 deletions.
4 changes: 3 additions & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# @wxml/parser is Lei Chen's personal project
# Owner
* @iChenLei
* @iChenLei
# Collaborator
src/ @dhlolo
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ lib
dist
.DS_store
.idea
src/vscodedebug/test.ts
src/vscodedebug/test.ts
3 changes: 0 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
Expand Down
140 changes: 124 additions & 16 deletions src/ast/build-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
convertLexerErrorToNode,
convertParseErrorToNode,
sortTokenChildren,
sortASTNode,
} from "./util";

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

if (ctx.SLASH_OPEN?.[0] && ctx.END?.[0]) {
if (ctx.WXS_SLASH_CLOSE?.[0]) {
astNode.endTag = {
type: "WXEndTag",
name: get(ctx, "END_NAME[0].image"),
};
const endTagLocation = {
...pick(ctx.SLASH_OPEN[0], ["startOffset", "startLine", "startColumn"]),
...pick(ctx.END[0], ["endOffset", "endLine", "endColumn"]),
name: "wxs",
};
const endTagLocation = pick(ctx.WXS_SLASH_CLOSE[0], [
"startOffset",
"startLine",
"startColumn",
"endOffset",
"endLine",
"endColumn",
]);
mergeLocation(astNode.endTag, endTagLocation);
}

Expand All @@ -118,8 +123,8 @@ class CstToAstVisitor extends BaseWxmlCstVisitor {
if (ctx.SEA_WS !== undefined) {
allTokens = allTokens.concat(ctx.SEA_WS);
}
if (ctx.WXS_TEXT !== undefined) {
allTokens = allTokens.concat(ctx.WXS_TEXT);
if (ctx.INLINE_WXS_TEXT !== undefined) {
allTokens = allTokens.concat(ctx.INLINE_WXS_TEXT);
}
const sortedTokens = sortBy(allTokens, ["startOffset"]);
const fullText = map(sortedTokens, "image").join("");
Expand All @@ -130,19 +135,122 @@ class CstToAstVisitor extends BaseWxmlCstVisitor {
* AST - WXAttribute
*/
attribute(ctx, { location }) {
const rawValue = get(ctx, "STRING[0].image") || null;
const value = rawValue
? rawValue
.split("")
.slice(1, rawValue.length - 1)
.join("")
const attributeValue = ctx.attributeValue
? this.visit(ctx.attributeValue[0])
: null;

const astNode = {
type: "WXAttribute",
key: ctx.NAME[0].image,
quote: null,
value: null,
rawValue: null,
...(attributeValue || {}),
};
mergeLocation(astNode, location);
return astNode;
}

/**
* AST - WXAttributeValue
*/
attributeValue(ctx, { location }) {
if (ctx.PURE_STRING !== undefined) {
const raw = ctx.PURE_STRING[0].image;
const astNode = {
value: raw
.split("")
.slice(1, raw.length - 1)
.join(""),
rawValue: ctx.PURE_STRING[0].image,
children: [],
interpolations: [],
quote: raw?.length ? raw.slice(0, 1) : null,
};
mergeLocation(astNode, location);
return astNode;
} else if (ctx.doubleQuoteAttributeVal !== undefined) {
return this.visit(ctx.doubleQuoteAttributeVal[0]);
} else if (ctx.singleQuoteAttributeVal !== undefined) {
return this.visit(ctx.singleQuoteAttributeVal[0]);
}
}

doubleQuoteAttributeVal(ctx, { location }) {
const interpolationASTS = map(
ctx.attributeValInterpolation,
this.visit.bind(this)
);
const quote = '"';
let strASTs = map(ctx.PURE_STRING_IN_DOUBLE_QUOTE, (item) => {
const astNode = {
value: item.image,
type: "WXText",
};
mergeLocation(astNode, item);
return astNode;
});
const sortedValue = sortASTNode(interpolationASTS.concat(strASTs));
// @ts-expect-error
const value = sortedValue.map((v) => v.rawValue || v.value).join("");

const astNode = {
value,
rawValue: quote + value + quote,
children: sortedValue,
interpolations: interpolationASTS.map((intp) => {
return {
...intp,
type: "WXInterpolation",
};
}),
quote: quote,
};
mergeLocation(astNode, location);
return astNode;
}

attributeValInterpolation(ctx, { location }) {
const child = sortTokenChildren(ctx);
// @ts-expect-error
const value = (child || []).map((token) => token.image).join("");
const astNode = {
type: "WXAttributeInterpolation",
rawValue: value,
value: value.replace(/^{{/, "").replace(/}}$/, ""),
};
mergeLocation(astNode, location);
return astNode;
}

singleQuoteAttributeVal(ctx, { location }) {
const interpolationASTS = map(
ctx.attributeValInterpolation,
this.visit.bind(this)
);
const quote = "'";
let strASTs = map(ctx.PURE_STRING_IN_SINGLE_QUOTE, (item) => {
const astNode = {
value: item.image,
type: "WXText",
};
mergeLocation(astNode, item);
return astNode;
});
const sortedValue = sortASTNode(interpolationASTS.concat(strASTs));
// @ts-expect-error
const value = sortedValue.map((v) => v.rawValue || v.value).join("");
const astNode = {
value,
rawValue,
quote: rawValue?.length ? rawValue.slice(0, 1) : null,
rawValue: quote + value + quote,
children: sortedValue,
interpolations: interpolationASTS.map((intp) => {
return {
...intp,
type: "WXInterpolation",
};
}),
quote: quote,
};
mergeLocation(astNode, location);
return astNode;
Expand Down
29 changes: 29 additions & 0 deletions src/ast/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,35 @@ interface IEspreeError {
stack: string;
}

interface ASTNode {
loc: {
start: {
line: number;
column: number;
};
};
}

export function sortASTNode(nodes: Array<ASTNode>): Array<ASTNode> {
let nodeASTs = [];
nodes.forEach((node) => {
nodeASTs.push(node);
});
let sortedNodes = [];
sortedNodes = nodes.sort((nodeA, nodeB) => {
if (
nodeA.loc.start.line > nodeB.loc.start.line ||
(nodeA.loc.start.line === nodeB.loc.start.line &&
nodeA.loc.start.column > nodeB.loc.start.column)
) {
return 1;
} else {
return -1;
}
});
return sortedNodes;
}

/**
* sort token children
*/
Expand Down
Loading

0 comments on commit f43fb98

Please sign in to comment.