Skip to content

Commit 73907f8

Browse files
Updating snippet parsing and consolidation to support sub languages
1 parent 862ae12 commit 73907f8

File tree

2 files changed

+87
-49
lines changed

2 files changed

+87
-49
lines changed

utils/consolidateSnippets.js

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { exit } from 'process';
2-
import { parseAllSnippets, reverseSlugify } from './snippetParser.js';
2+
import { parseAllSnippets, reverseSlugify, slugify } from './snippetParser.js';
33
import { join } from 'path';
44
import { copyFileSync, writeFileSync } from 'fs';
55

@@ -8,21 +8,39 @@ const indexPath = join(dataPath, '_index.json');
88
const iconPath = 'public/icons/';
99
const snippetsPath = 'snippets/';
1010

11-
const [ errored, snippets ] = parseAllSnippets();
11+
const [ errored, languages ] = parseAllSnippets();
1212

1313
if(errored) exit(1);
1414

1515
const index = [];
16-
for(const [language, categories] of Object.entries(snippets)) {
17-
const languageIconPath = join(snippetsPath, language, 'icon.svg');
16+
for(const language of languages) {
17+
copyFileSync(language.icon, join(iconPath, `${slugify(language.name)}.svg`));
1818

19-
copyFileSync(languageIconPath, join(iconPath, `${language}.svg`));
19+
const subIndexes = [];
2020

21-
index.push({ lang: reverseSlugify(language).toUpperCase(), icon: `/icons/${language}.svg` });
21+
for(const subLanguage of language.subLanguages) {
22+
const joinedName = `${slugify(language.name)}--${slugify(subLanguage.name)}`;
23+
const iconName = `${joinedName}.svg`;
24+
const subLanguageFilePath = join(dataPath, `${joinedName}.json`);
25+
26+
copyFileSync(subLanguage.icon, join(iconPath, iconName));
27+
subIndexes.push({
28+
name: subLanguage.name.toUpperCase(),
29+
icon: `/icons/${iconName}`,
30+
});
31+
32+
writeFileSync(subLanguageFilePath, JSON.stringify(subLanguage.categories, null, 4));
33+
}
34+
35+
index.push({
36+
name: language.name.toUpperCase(),
37+
icon: `/icons/${slugify(language.name)}.svg`,
38+
subLanguages: subIndexes,
39+
});
2240

23-
const languageFilePath = join(dataPath, `${language}.json`);
41+
const languageFilePath = join(dataPath, `${slugify(language.name)}.json`);
2442

25-
writeFileSync(languageFilePath, JSON.stringify(categories, null, 4));
43+
writeFileSync(languageFilePath, JSON.stringify(language.categories, null, 4));
2644
}
2745

2846
writeFileSync(indexPath, JSON.stringify(index, null, 4));

utils/snippetParser.js

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ const crlfRegex = /\r\n/gm;
3131
const propertyRegex = /^\s+([a-zA-Z]+):\s*(.+)/;
3232
const headerEndCodeStartRegex = /^\s*---\s*```.*\n/;
3333
const codeRegex = /^(.+)```/s
34-
function parseSnippet(snippetPath, name, text) {
35-
if(crlfRegex.exec(text) !== null) return raise('Found CRLF line endings instead of LF line endings', snippetPath);
34+
function parseSnippet(path, name, text) {
35+
if(crlfRegex.exec(text) !== null) return raise('Found CRLF line endings instead of LF line endings', path);
3636
let cursor = 0;
3737

3838
const fromCursor = () => text.substring(cursor);
3939

40-
if(!fromCursor().trim().startsWith('---')) return raise('Missing header start delimiter \'---\'', snippetPath);
40+
if(!fromCursor().trim().startsWith('---')) return raise('Missing header start delimiter \'---\'', path);
4141
cursor += 3;
4242

4343
const properties = {};
@@ -47,19 +47,19 @@ function parseSnippet(snippetPath, name, text) {
4747
properties[match[1].toLowerCase()] = match[2];
4848
}
4949

50-
if(!('title' in properties)) return raise(`Missing 'title' property`, snippetPath);
51-
if(!('description' in properties)) return raise(`Missing 'description' property`, snippetPath);
52-
if(!('author' in properties)) return raise(`Missing 'author' property`, snippetPath);
53-
if(!('tags' in properties)) return raise(`Missing 'tags' property`, snippetPath);
50+
if(!('title' in properties)) return raise(`Missing 'title' property`, path);
51+
if(!('description' in properties)) return raise(`Missing 'description' property`, path);
52+
if(!('author' in properties)) return raise(`Missing 'author' property`, path);
53+
if(!('tags' in properties)) return raise(`Missing 'tags' property`, path);
5454

55-
if(slugify(properties.title) !== name) return raise(`slugifyed 'title' property doesn't match snippet file name`, snippetPath);
55+
if(slugify(properties.title) !== name) return raise(`slugifyed 'title' property doesn't match snippet file name`, path);
5656

5757
match = headerEndCodeStartRegex.exec(fromCursor());
58-
if(match === null) return raise('Missing header end \'---\' or code start \'```\'', snippetPath);
58+
if(match === null) return raise('Missing header end \'---\' or code start \'```\'', path);
5959
cursor += match[0].length;
6060

6161
match = codeRegex.exec(fromCursor());
62-
if(match === null) return raise('Missing code block end \'```\'', snippetPath);
62+
if(match === null) return raise('Missing code block end \'```\'', path);
6363
const code = match[1];
6464

6565
return {
@@ -72,43 +72,63 @@ function parseSnippet(snippetPath, name, text) {
7272
}
7373
}
7474

75+
function parseCategory(path, name) {
76+
const snippets = [];
77+
78+
for(const snippet of readdirSync(path)) {
79+
const snippetPath = join(path, snippet);
80+
const snippetContent = readFileSync(snippetPath).toString();
81+
const snippetFileName = snippet.slice(0, -3);
82+
83+
const snippetData = parseSnippet(snippetPath, snippetFileName, snippetContent);
84+
if(!snippetData) continue;
85+
snippets.push(snippetData);
86+
}
87+
88+
return {
89+
name: reverseSlugify(name),
90+
snippets,
91+
};
92+
}
93+
94+
function parseLanguage(path, name, subLanguageOf = null) {
95+
const iconPath = join(path, 'icon.svg');
96+
97+
if(!existsSync(iconPath)) return raise(`icon for '${subLanguageOf ? `${subLanguageOf}/` : '' }${name}' is missing`);
98+
99+
const categories = [];
100+
const subLanguages = [];
101+
102+
for(const category of readdirSync(path)) {
103+
if(category === 'icon.svg') continue;
104+
const categoryPath = join(path, category);
105+
106+
if(category.startsWith('[') && category.endsWith(']')) {
107+
if(subLanguageOf !== null) {
108+
return raise('Cannot have more than two level of language nesting');
109+
}
110+
subLanguages.push(parseLanguage(categoryPath, category.slice(1, -1), name));
111+
}else {
112+
categories.push(parseCategory(categoryPath, category));
113+
}
114+
}
115+
116+
return {
117+
name: reverseSlugify(name),
118+
icon: iconPath,
119+
categories, subLanguages,
120+
}
121+
}
122+
75123
const snippetPath = "snippets/";
76124
export function parseAllSnippets() {
77-
const snippets = {};
125+
const languages = [];
78126

79127
for(const language of readdirSync(snippetPath)) {
80128
const languagePath = join(snippetPath, language);
81-
82-
const languageIconPath = join(languagePath, 'icon.svg');
83-
84-
if(!existsSync(languageIconPath)) {
85-
raise(`icon for '${language}' is missing`);
86-
continue;
87-
}
88-
89-
const categories = [];
90-
for(const category of readdirSync(languagePath)) {
91-
if(category === 'icon.svg') continue;
92-
const categoryPath = join(languagePath, category);
93-
94-
const categorySnippets = [];
95-
for(const snippet of readdirSync(categoryPath)) {
96-
const snippetPath = join(categoryPath, snippet);
97-
const snippetContent = readFileSync(snippetPath).toString();
98-
const snippetFileName = snippet.slice(0, -3);
99-
100-
const snippetData = parseSnippet(snippetPath, snippetFileName, snippetContent);
101-
if(!snippetData) continue;
102-
categorySnippets.push(snippetData);
103-
}
104-
categories.push({
105-
categoryName: reverseSlugify(category),
106-
snippets: categorySnippets,
107-
});
108-
}
109129

110-
snippets[language] = categories;
130+
languages.push(parseLanguage(languagePath, language));
111131
}
112132

113-
return [ errored, snippets ];
133+
return [ errored, languages ];
114134
}

0 commit comments

Comments
 (0)