-
Notifications
You must be signed in to change notification settings - Fork 0
/
codesandbox.sync.ts
104 lines (96 loc) · 3.05 KB
/
codesandbox.sync.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
/* eslint-disable no-console */
import { readdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
function scanFiles(
path: string,
filePredicate: (path: string) => boolean,
fileCallback: (path: string) => void
) {
readdirSync(path, { withFileTypes: true }).forEach((dirent) => {
if (dirent.isDirectory()) {
scanFiles(join(path, dirent.name), filePredicate, fileCallback);
} else if (dirent.isFile()) {
if (filePredicate(dirent.name)) {
fileCallback(join(path, dirent.name));
}
}
});
}
function mdxFiles(path: string) {
return path.endsWith('.mdx');
}
function transformFile(
path: string,
lineTransformFn: (path: string, lines: string[]) => string[]
): void {
const lines = readFile(path);
const newLines = lineTransformFn(path, lines);
writeFileSync(path, newLines.join('\n'));
}
function readFile(path: string) {
try {
const file = readFileSync(path, 'utf-8');
return file.split('\n');
} catch (e) {
console.error('Error reading file: ' + path);
throw e;
}
}
function findCodeSandboxes(
codeSandboxTransformFn: (mdxPath: string, srcPath: string, lines: string[]) => string[],
mdxPath: string,
lines: string[]
): string[] {
const newLines = [];
for (let lineNo = 0; lineNo < lines.length; lineNo++) {
const line = lines[lineNo];
newLines.push(line);
const match = line.match(/(.*)<(CodeSandbox|CodeFile) src=["']([^"']*)["'][^/]*>$/);
if (match) {
const [, prefix, tag, srcPath] = match;
const content: string[] = [];
let contentEndLine: string = '';
do {
if (lineNo > lines.length) {
throw new Error(tag + ' not closed');
}
const contentLine = lines[++lineNo];
if (contentLine.match(new RegExp('</' + tag + '>$'))) {
contentEndLine = contentLine;
} else if (contentLine.startsWith(prefix)) {
content.push(contentLine.slice(prefix.length));
} else {
throw new Error(
'Expecting content of `<' +
tag +
'>` to be indented with: ' +
JSON.stringify(prefix) +
' Was: ' +
JSON.stringify(contentLine) +
' in ' +
mdxPath +
' at line ' +
lineNo
);
}
} while (!contentEndLine);
const newContent = codeSandboxTransformFn(mdxPath, srcPath, content);
newLines.push(...newContent.map((l) => prefix + l), contentEndLine);
}
}
return newLines;
}
function syncCodeSandboxes(path: string) {
transformFile(path, findCodeSandboxes.bind(null, syncCodeSandbox));
}
function syncCodeSandbox(mdxPath: string, srcPath: string, lines: string[]) {
console.log('SYNCING', mdxPath, srcPath);
const first = lines[0];
const newContent = readFile(join('.', srcPath));
while (newContent.length && newContent[newContent.length - 1] == '') {
newContent.pop();
}
const last = lines[lines.length - 1];
return [first, ...newContent, last];
}
scanFiles('src/routes', mdxFiles, syncCodeSandboxes);