@@ -2,6 +2,9 @@ import { readFile, readdir } from "node:fs/promises";
22
33const SPEC_DIR = new URL ( "../spec" , import . meta. url ) . pathname ;
44
5+ /** @see {@link https://spec-md.com/#sec-Value-Literals } */
6+ const valueLiteralsRegexp = / \{ ( (?: [ ^ { } ] | (?: \{ [ ^ { } ] * \} ) ) + ) \} / g;
7+
58process . exitCode = 0 ;
69const filenames = await readdir ( SPEC_DIR ) ;
710for ( const filename of filenames ) {
@@ -23,13 +26,16 @@ for (const filename of filenames) {
2326 {
2427 // Is it an algorithm definition?
2528 const matches = line . match ( / ^ ( [ a - z 0 - 9 A - Z ] + ) ( \s * ) \( ( [ ^ ) ] * ) \) ( \s * ) : ( \s * ) $ / ) ;
29+ const grammarMatches =
30+ filename === "Section 2 -- Language.md" &&
31+ line . match ( / ^ ( [ A - Z a - z 0 - 9 ] + ) : \s + ( ( \S ) .* ) $ / ) ;
2632 if ( matches ) {
2733 const [ , algorithmName , ns1 , _args , ns2 , ns3 ] = matches ;
2834 if ( ns1 || ns2 || ns3 ) {
2935 console . log (
3036 `Bad whitespace in definition of ${ algorithmName } in '${ filename } ':`
3137 ) ;
32- console . log ( line ) ;
38+ console . dir ( line ) ;
3339 console . log ( ) ;
3440 process . exitCode = 1 ;
3541 }
@@ -47,7 +53,7 @@ for (const filename of filenames) {
4753 console . log (
4854 `Bad algorithm ${ algorithmName } step in '${ filename } ':`
4955 ) ;
50- console . log ( step ) ;
56+ console . dir ( step ) ;
5157 console . log ( ) ;
5258 process . exitCode = 1 ;
5359 }
@@ -57,18 +63,45 @@ for (const filename of filenames) {
5763 console . log (
5864 `Bad formatting for '${ algorithmName } ' step (does not end in '.' or ':') in '${ filename } ':`
5965 ) ;
60- console . log ( step ) ;
66+ console . dir ( step ) ;
6167 console . log ( ) ;
6268 process . exitCode = 1 ;
6369 }
6470 if ( step . match ( / ^ \s * ( - | [ 0 - 9 ] \. ) \s + [ a - z ] / ) ) {
6571 console . log (
6672 `Bad formatting of '${ algorithmName } ' step (should start with a capital) in '${ filename } ':`
6773 ) ;
68- console . log ( step ) ;
74+ console . dir ( step ) ;
6975 console . log ( ) ;
7076 process . exitCode = 1 ;
7177 }
78+
79+ const stepWithoutValueLiterals = step . replace (
80+ valueLiteralsRegexp ,
81+ ""
82+ ) ;
83+ if ( stepWithoutValueLiterals . match ( / \b [ A - Z ] [ A - Z a - z 0 - 9 ] + \( / ) ) {
84+ console . log (
85+ `Bad formatting of '${ algorithmName } ' step (algorithm call should be wrapped in braces: \`{MyAlgorithm(a, b, c)}\`) in '${ filename } ':`
86+ ) ;
87+ console . dir ( step ) ;
88+ console . log ( ) ;
89+ process . exitCode = 1 ;
90+ }
91+
92+ const valueLiterals = step . matchAll ( valueLiteralsRegexp , "" ) ;
93+ for ( const lit of valueLiterals ) {
94+ const inner = lit [ 1 ] ;
95+ if ( inner . includes ( "{" ) ) {
96+ console . log (
97+ `Bad formatting of '${ algorithmName } ' step (algorithm call should not contain braces: \`${ lit } \`) in '${ filename } ':`
98+ ) ;
99+ console . dir ( step ) ;
100+ console . log ( ) ;
101+ process . exitCode = 1 ;
102+ }
103+ }
104+
72105 const trimmedInnerLine = step . replace ( / \s + / g, " " ) ;
73106 if (
74107 trimmedInnerLine . match (
@@ -79,7 +112,67 @@ for (const filename of filenames) {
79112 console . log (
80113 `Potential bad formatting of '${ algorithmName } ' step (true/false/null should be wrapped in curly braces, e.g. '{true}') in '${ filename } ':`
81114 ) ;
82- console . log ( step ) ;
115+ console . dir ( step ) ;
116+ console . log ( ) ;
117+ process . exitCode = 1 ;
118+ }
119+ }
120+ } else if ( grammarMatches ) {
121+ // This is super loosey-goosey
122+ const [ , grammarName , rest ] = grammarMatches ;
123+ if ( rest . trim ( ) === "one of" ) {
124+ // Still grammar, not algorithm
125+ continue ;
126+ }
127+ if ( rest . trim ( ) === "" && lines [ i + 1 ] !== "" ) {
128+ console . log (
129+ `No empty space after grammar ${ grammarName } header in '${ filename } '`
130+ ) ;
131+ console . log ( ) ;
132+ process . exitCode = 1 ;
133+ }
134+ if ( ! lines [ i + 2 ] . startsWith ( "- " ) ) {
135+ // Not an algorithm; probably more grammar
136+ continue ;
137+ }
138+ for ( let j = i + 2 ; j < l ; j ++ ) {
139+ const step = lines [ j ] ;
140+ if ( ! step . match ( / ^ \s * ( - | [ 0 - 9 ] + \. ) / ) ) {
141+ if ( step !== "" ) {
142+ console . log ( `Bad grammar ${ grammarName } step in '${ filename } ':` ) ;
143+ console . dir ( step ) ;
144+ console . log ( ) ;
145+ process . exitCode = 1 ;
146+ }
147+ break ;
148+ }
149+ if ( ! step . match ( / [ . : ] $ / ) ) {
150+ console . log (
151+ `Bad formatting for '${ grammarName } ' step (does not end in '.' or ':') in '${ filename } ':`
152+ ) ;
153+ console . dir ( step ) ;
154+ console . log ( ) ;
155+ process . exitCode = 1 ;
156+ }
157+ if ( step . match ( / ^ \s * ( - | [ 0 - 9 ] \. ) \s + [ a - z ] / ) ) {
158+ console . log (
159+ `Bad formatting of '${ grammarName } ' step (should start with a capital) in '${ filename } ':`
160+ ) ;
161+ console . dir ( step ) ;
162+ console . log ( ) ;
163+ process . exitCode = 1 ;
164+ }
165+ const trimmedInnerLine = step . replace ( / \s + / g, " " ) ;
166+ if (
167+ trimmedInnerLine . match (
168+ / (?: [ r R ] e t u r n | i s (?: n o t ) ? ) ( t r u e | f a l s e | n u l l ) \b /
169+ ) &&
170+ ! trimmedInnerLine . match ( / n u l l o r e m p t y / )
171+ ) {
172+ console . log (
173+ `Potential bad formatting of '${ grammarName } ' step (true/false/null should be wrapped in curly braces, e.g. '{true}') in '${ filename } ':`
174+ ) ;
175+ console . dir ( step ) ;
83176 console . log ( ) ;
84177 process . exitCode = 1 ;
85178 }
0 commit comments