@formatjs/cli-lib
Version:
Lib for CLI for formatjs.
69 lines (68 loc) • 2.11 kB
JavaScript
import { NodeTypes, } from '@vue/compiler-core';
import { parse } from 'vue/compiler-sfc';
function walk(node, visitor) {
if (typeof node !== 'object' || node == null) {
return;
}
if (node.type === NodeTypes.ROOT) {
node.children.forEach(n => walk(n, visitor));
return;
}
if (node.type !== NodeTypes.ELEMENT &&
node.type !== NodeTypes.COMPOUND_EXPRESSION &&
node.type !== NodeTypes.INTERPOLATION) {
return;
}
visitor(node);
if (node.type === NodeTypes.INTERPOLATION) {
visitor(node.content);
}
else if (node.type === NodeTypes.ELEMENT) {
node.children.forEach(n => walk(n, visitor));
node.props
.filter((prop) => prop.type === NodeTypes.DIRECTIVE)
.filter(prop => !!prop.exp)
.forEach(prop => visitor(prop.exp));
}
else {
node.children.forEach(n => walk(n, visitor));
}
}
function templateSimpleExpressionNodeVisitor(parseScriptFn) {
return (n) => {
if (typeof n !== 'object') {
return;
}
if (n.type !== NodeTypes.SIMPLE_EXPRESSION) {
return;
}
const { content } = n;
// Wrap this in () since a vue comp node attribute can just be
// an object literal which, by itself is invalid TS
// but with () it becomes an ExpressionStatement
try {
parseScriptFn(`(${content})`);
}
catch (e) {
console.warn(`Failed to parse "${content}". Ignore this if content has no extractable message`, e);
}
};
}
export function parseFile(source, filename, parseScriptFn) {
const { descriptor, errors } = parse(source, {
filename,
});
if (errors.length) {
throw errors[0];
}
const { script, scriptSetup, template } = descriptor;
if (template) {
walk(template.ast, templateSimpleExpressionNodeVisitor(parseScriptFn));
}
if (script) {
parseScriptFn(script.content);
}
if (scriptSetup) {
parseScriptFn(scriptSetup.content);
}
}