-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.ts
104 lines (94 loc) · 3.19 KB
/
parser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import * as fs from "fs";
import * as ts from "typescript";
// Define the file naming convention
const componentFileExtension = ".tsx";
const templateFileExtension = `.template.${componentFileExtension}`;
function parseImports(filePath: string): string[] {
const fileContents = fs.readFileSync(filePath, "utf-8");
const sourceFile = ts.createSourceFile(
filePath,
fileContents,
ts.ScriptTarget.Latest,
true
);
const imports: string[] = [];
function getImports(node: ts.Node): void {
if (ts.isImportDeclaration(node)) {
imports.push(fileContents.substring(node.pos, node.end));
}
ts.forEachChild(node, getImports);
}
getImports(sourceFile);
return imports;
}
function parseJsx(filePath: string): string | null {
const fileContents = fs.readFileSync(filePath, "utf-8");
const sourceFile = ts.createSourceFile(
filePath,
fileContents,
ts.ScriptTarget.Latest,
true
);
// TODO:: throw error if more than one root node is found
let jsxMarkup: string | null = null;
function getRootNode(node: ts.Node): string | void {
// parse until you find the first jsx element
if (
ts.isJsxElement(node) ||
ts.isJsxSelfClosingElement(node) ||
ts.isJsxFragment(node)
) {
// if found root then return and stop looping
jsxMarkup = fileContents
.substring(node.pos, node.end)
.replace(/^\s+/, "");
return;
}
ts.forEachChild(node, getRootNode);
}
getRootNode(sourceFile);
return jsxMarkup;
}
const isComponentFile = (file: string): boolean => {
return file.endsWith(".tsx") && !file.endsWith(templateFileExtension);
};
function parseDirectory(directoryPath: string): void {
const files = fs.readdirSync(directoryPath);
files.forEach((file) => {
const filePath = `${directoryPath}/${file}`;
const stats = fs.statSync(filePath);
if (stats.isDirectory()) {
parseDirectory(filePath);
} else if (stats.isFile()) {
if (isComponentFile(file)) {
const fileContents = fs.readFileSync(filePath, "utf-8");
const templateTag = fileContents.match(
/<Template\s*dir\s*=\s*.*\s*\/>/
);
if (templateTag) {
let dirValue = templateTag[0].split(/"|'.+"|'/)[1];
if (!dirValue.endsWith(templateFileExtension)) {
new Error(
`Template file ${dirValue} does not have the correct extension. Expected ${templateFileExtension}`
);
}
if (dirValue.startsWith("/")) {
dirValue = dirValue.substring(1);
}
const templateFilePath = `${directoryPath}/${dirValue}`;
const jsxMarkup = parseJsx(templateFilePath);
const imports = parseImports(templateFilePath);
if (jsxMarkup) {
const componentCode = fileContents.replace(
/<Template\s*dir\s*=\s*.*\s*\/>/,
jsxMarkup
);
fs.writeFileSync(filePath, componentCode);
const importStatements = imports.join("\n");
fs.appendFileSync(filePath, `\n${importStatements}`);
}
}
}
}
});
}