@@ -31,13 +31,13 @@ const crlfRegex = /\r\n/gm;
3131const propertyRegex = / ^ \s + ( [ a - z A - Z ] + ) : \s * ( .+ ) / ;
3232const headerEndCodeStartRegex = / ^ \s * - - - \s * ` ` ` .* \n / ;
3333const 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+
75123const snippetPath = "snippets/" ;
76124export 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