Skip to content

Commit 4208ae8

Browse files
committed
update scripts
1 parent e0c04f2 commit 4208ae8

File tree

3 files changed

+147
-73
lines changed

3 files changed

+147
-73
lines changed

utils/checkSnippetFormatting.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { exit } from "process";
22

33
import { parseAllSnippets } from "./snippetParser.ts";
44

5-
const [errored] = parseAllSnippets();
5+
const { errored } = parseAllSnippets();
66

77
if (errored) {
88
exit(1);

utils/consolidateSnippets.ts

+36-16
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,56 @@
1-
import { copyFileSync, writeFileSync } from "fs";
1+
import { copyFileSync, mkdirSync, writeFileSync } from "fs";
22
import { join } from "path";
33
import { exit } from "process";
44

5-
import { parseAllSnippets } from "./snippetParser.ts";
6-
import { LanguageType } from "../src/types";
7-
import { reverseSlugify } from "../src/utils/slugify";
5+
import { parseAllSnippets } from "./snippetParser.js";
6+
import { LanguageType } from "../src/types/index.js";
7+
import { slugify } from "../src/utils/slugify.js";
88

99
const dataPath = "public/consolidated/";
1010
const indexPath = join(dataPath, "_index.json");
1111
const iconPath = "public/icons/";
12-
const snippetsPath = "snippets/";
1312

14-
const [errored, snippets] = parseAllSnippets();
13+
const { errored, languages } = parseAllSnippets();
1514

1615
if (errored) {
1716
exit(1);
1817
}
1918

20-
const languages: LanguageType[] = [];
21-
for (const [language, categories] of Object.entries(snippets)) {
22-
const languageIconPath = join(snippetsPath, language, "icon.svg");
19+
mkdirSync(dataPath, { recursive: true });
20+
mkdirSync(iconPath, { recursive: true });
2321

24-
copyFileSync(languageIconPath, join(iconPath, `${language}.svg`));
22+
const index: LanguageType[] = [];
23+
for (const language of languages) {
24+
copyFileSync(language.icon, join(iconPath, `${slugify(language.name)}.svg`));
2525

26-
languages.push({
27-
lang: reverseSlugify(language).toUpperCase(),
28-
icon: `/icons/${language}.svg`,
26+
const subIndexes: LanguageType["subIndexes"] = [];
27+
28+
for (const subLanguage of language.subLanguages) {
29+
const joinedName = `${slugify(language.name)}--${slugify(subLanguage.name)}`;
30+
const iconName = `${joinedName}.svg`;
31+
const subLanguageFilePath = join(dataPath, `${joinedName}.json`);
32+
33+
copyFileSync(subLanguage.icon, join(iconPath, iconName));
34+
subIndexes.push({
35+
name: subLanguage.name.toUpperCase(),
36+
icon: `/icons/${iconName}`,
37+
});
38+
39+
writeFileSync(
40+
subLanguageFilePath,
41+
JSON.stringify(subLanguage.categories, null, 4)
42+
);
43+
}
44+
45+
index.push({
46+
name: language.name.toUpperCase(),
47+
icon: `/icons/${slugify(language.name)}.svg`,
48+
subIndexes,
2949
});
3050

31-
const languageFilePath = join(dataPath, `${language}.json`);
51+
const languageFilePath = join(dataPath, `${slugify(language.name)}.json`);
3252

33-
writeFileSync(languageFilePath, JSON.stringify(categories, null, 4));
53+
writeFileSync(languageFilePath, JSON.stringify(language.categories, null, 4));
3454
}
3555

36-
writeFileSync(indexPath, JSON.stringify(languages, null, 4));
56+
writeFileSync(indexPath, JSON.stringify(index, null, 4));

utils/snippetParser.ts

+110-56
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,49 @@
11
import { existsSync, readdirSync, readFileSync } from "fs";
22
import { join } from "path";
33

4-
import { CategoryType, RawSnippetType, SnippetType } from "../src/types";
4+
import { RawSnippetType, SnippetType } from "../src/types";
55
import { isCorrectType } from "../src/utils/objectUtils";
66
import { raise } from "../src/utils/raise";
77
import { reverseSlugify, slugify } from "../src/utils/slugify";
88

9-
const crlfRegex = /\r\n/gm;
9+
interface ParseLanguageResponse {
10+
name: string;
11+
icon: string;
12+
categories: Array<{
13+
name: string;
14+
snippets: Array<SnippetType>;
15+
}>;
16+
subLanguages: ParseLanguageResponse[];
17+
}
18+
19+
interface ParseCategoryResponse {
20+
name: string;
21+
snippets: Array<SnippetType>;
22+
}
23+
1024
const propertyRegex = /^\s+([a-zA-Z]+):\s*(.+)/;
11-
const headerEndCodeStartRegex = /^\s*---\s*```.*\n/;
25+
const headerEndCodeStartRegex = /^\s*---\s*```.*\r?\n/;
1226
const codeRegex = /^(.+)```/s;
1327

14-
let errored = false;
28+
let errored: boolean = false;
1529

1630
function parseSnippet(
17-
snippetPath: string,
31+
path: string,
1832
name: string,
1933
text: string
2034
): SnippetType | null {
21-
if (crlfRegex.exec(text) !== null) {
22-
return raise(
23-
"Found CRLF line endings instead of LF line endings",
24-
snippetPath
25-
);
26-
}
27-
let cursor = 0;
35+
let cursor: number = 0;
2836

2937
const fromCursor = () => text.substring(cursor);
30-
3138
if (!fromCursor().trim().startsWith("---")) {
32-
return raise("Missing header start delimiter '---'", snippetPath);
39+
return raise("Missing header start delimiter '---'", path);
3340
}
41+
3442
cursor += 3;
3543

3644
const properties = {};
3745

38-
let match;
46+
let match: string[] | null;
3947
while ((match = propertyRegex.exec(fromCursor())) !== null) {
4048
cursor += match[0].length;
4149
properties[match[1].toLowerCase()] = match[2];
@@ -49,26 +57,28 @@ function parseSnippet(
4957
"tags",
5058
])
5159
) {
52-
return raise("Invalid properties", snippetPath);
60+
return raise("Invalid properties", path);
5361
}
5462

5563
if (slugify(properties.title) !== name) {
5664
return raise(
5765
`slugifyed 'title' property doesn't match snippet file name`,
58-
snippetPath
66+
path
5967
);
6068
}
6169

6270
match = headerEndCodeStartRegex.exec(fromCursor());
6371
if (match === null) {
64-
return raise("Missing header end '---' or code start '```'", snippetPath);
72+
return raise("Missing header end '---' or code start '```'", path);
6573
}
74+
6675
cursor += match[0].length;
6776

6877
match = codeRegex.exec(fromCursor());
6978
if (match === null) {
70-
return raise("Missing code block end '```'", snippetPath);
79+
return raise("Missing code block end '```'", path);
7180
}
81+
7282
const code: string = match[1];
7383

7484
return {
@@ -83,56 +93,100 @@ function parseSnippet(
8393
.split(",")
8494
.map((contributor) => contributor.trim())
8595
.filter((contributor) => contributor),
86-
code,
96+
code: code.replace(/\r\n/g, "\n"),
8797
};
8898
}
8999

90-
const snippetPath = "snippets/";
91-
export function parseAllSnippets() {
92-
const snippets = {};
100+
function parseCategory(path: string, name: string): ParseCategoryResponse {
101+
const snippets: SnippetType[] = [];
93102

94-
for (const language of readdirSync(snippetPath)) {
95-
const languagePath = join(snippetPath, language);
96-
const languageIconPath = join(languagePath, "icon.svg");
103+
for (const snippet of readdirSync(path)) {
104+
const snippetPath = join(path, snippet);
105+
const snippetContent = readFileSync(snippetPath).toString();
106+
const snippetFileName = snippet.slice(0, -3);
97107

98-
if (!existsSync(languageIconPath)) {
108+
const snippetData = parseSnippet(
109+
snippetPath,
110+
snippetFileName,
111+
snippetContent
112+
);
113+
if (!snippetData) {
99114
errored = true;
100-
raise(`icon for '${language}' is missing`);
101115
continue;
102116
}
117+
snippets.push(snippetData);
118+
}
119+
120+
return {
121+
name: reverseSlugify(name),
122+
snippets,
123+
};
124+
}
125+
126+
function parseLanguage(
127+
path: string,
128+
name: string,
129+
subLanguageOf: string | null = null
130+
): ParseLanguageResponse | null {
131+
const iconPath = join(path, "icon.svg");
103132

104-
const categories: CategoryType[] = [];
105-
106-
for (const category of readdirSync(languagePath)) {
107-
if (category === "icon.svg") continue;
108-
109-
const categoryPath = join(languagePath, category);
110-
const categorySnippets: SnippetType[] = [];
111-
112-
for (const snippet of readdirSync(categoryPath)) {
113-
const snippetPath = join(categoryPath, snippet);
114-
const snippetContent = readFileSync(snippetPath).toString();
115-
const snippetFileName = snippet.slice(0, -3);
116-
const snippetData = parseSnippet(
117-
snippetPath,
118-
snippetFileName,
119-
snippetContent
120-
);
121-
if (snippetData === null) {
122-
errored = true;
123-
continue;
124-
}
125-
categorySnippets.push(snippetData);
133+
if (!existsSync(iconPath)) {
134+
return raise(
135+
`icon for '${subLanguageOf ? `${subLanguageOf}/` : ""}${name}' is missing`
136+
);
137+
}
138+
139+
const subLanguages: Array<ParseLanguageResponse> = [];
140+
const categories: Array<ParseCategoryResponse> = [];
141+
142+
for (const category of readdirSync(path)) {
143+
if (category === "icon.svg") continue;
144+
const categoryPath = join(path, category);
145+
146+
if (category.startsWith("[") && category.endsWith("]")) {
147+
if (subLanguageOf !== null) {
148+
return raise("Cannot have more than two level of language nesting");
126149
}
127150

128-
categories.push({
129-
categoryName: reverseSlugify(category),
130-
snippets: categorySnippets,
131-
});
151+
const parsedLanguage = parseLanguage(
152+
categoryPath,
153+
category.slice(1, -1),
154+
name
155+
);
156+
if (!parsedLanguage) {
157+
errored = true;
158+
continue;
159+
}
160+
subLanguages.push(parsedLanguage);
161+
} else {
162+
categories.push(parseCategory(categoryPath, category));
132163
}
164+
}
133165

134-
snippets[language] = categories;
166+
return {
167+
name: reverseSlugify(name),
168+
icon: iconPath,
169+
categories,
170+
subLanguages,
171+
};
172+
}
173+
174+
export function parseAllSnippets() {
175+
const snippetPath = "snippets/";
176+
177+
const languages: ParseLanguageResponse[] = [];
178+
for (const language of readdirSync(snippetPath)) {
179+
const languagePath = join(snippetPath, language);
180+
const parsedLanguage = parseLanguage(languagePath, language);
181+
if (!parsedLanguage) {
182+
errored = true;
183+
continue;
184+
}
185+
languages.push(parsedLanguage);
135186
}
136187

137-
return [errored, snippets];
188+
return {
189+
errored,
190+
languages,
191+
};
138192
}

0 commit comments

Comments
 (0)