@@ -3,6 +3,12 @@ import { load } from "js-yaml";
33import { obj } from "through2" ;
44import PluginError from "plugin-error" ;
55import type Vinyl from "vinyl" ;
6+ import type {
7+ ExtendedMatchType ,
8+ ExtendedTextmateGrammar ,
9+ Pattern ,
10+ TextmateGrammar ,
11+ } from "./textmate-grammar" ;
612
713/**
814 * Replaces all rule references with the match pattern of the referenced rule.
@@ -34,7 +40,9 @@ function replaceReferencesWithStrings(
3440 * @param yaml The root of the YAML document.
3541 * @returns A map from macro name to replacement text.
3642 */
37- function gatherMacros ( yaml : any ) : Map < string , string > {
43+ function gatherMacros < T > (
44+ yaml : ExtendedTextmateGrammar < T > ,
45+ ) : Map < string , string > {
3846 const macros = new Map < string , string > ( ) ;
3947 for ( const key in yaml . macros ) {
4048 macros . set ( key , yaml . macros [ key ] ) ;
@@ -51,7 +59,7 @@ function gatherMacros(yaml: any): Map<string, string> {
5159 * @returns The match text for the rule. This is either the value of the rule's `match` property,
5260 * or the disjunction of the match text of all of the other rules `include`d by this rule.
5361 */
54- function getNodeMatchText ( rule : any ) : string {
62+ function getNodeMatchText ( rule : Pattern ) : string {
5563 if ( rule . match !== undefined ) {
5664 // For a match string, just use that string as the replacement.
5765 return rule . match ;
@@ -78,7 +86,7 @@ function getNodeMatchText(rule: any): string {
7886 * @returns A map whose keys are the names of rules, and whose values are the corresponding match
7987 * text of each rule.
8088 */
81- function gatherMatchTextForRules ( yaml : any ) : Map < string , string > {
89+ function gatherMatchTextForRules ( yaml : TextmateGrammar ) : Map < string , string > {
8290 const replacements = new Map < string , string > ( ) ;
8391 for ( const key in yaml . repository ) {
8492 const node = yaml . repository [ key ] ;
@@ -94,9 +102,14 @@ function gatherMatchTextForRules(yaml: any): Map<string, string> {
94102 * @param yaml The root of the YAML document.
95103 * @param action Callback to invoke on each rule.
96104 */
97- function visitAllRulesInFile ( yaml : any , action : ( rule : any ) => void ) {
105+ function visitAllRulesInFile < T > (
106+ yaml : ExtendedTextmateGrammar < T > ,
107+ action : ( rule : Pattern < T > ) => void ,
108+ ) {
98109 visitAllRulesInRuleMap ( yaml . patterns , action ) ;
99- visitAllRulesInRuleMap ( yaml . repository , action ) ;
110+ if ( yaml . repository ) {
111+ visitAllRulesInRuleMap ( Object . values ( yaml . repository ) , action ) ;
112+ }
100113}
101114
102115/**
@@ -107,9 +120,11 @@ function visitAllRulesInFile(yaml: any, action: (rule: any) => void) {
107120 * @param ruleMap The map or array of rules to visit.
108121 * @param action Callback to invoke on each rule.
109122 */
110- function visitAllRulesInRuleMap ( ruleMap : any , action : ( rule : any ) => void ) {
111- for ( const key in ruleMap ) {
112- const rule = ruleMap [ key ] ;
123+ function visitAllRulesInRuleMap < T > (
124+ ruleMap : Array < Pattern < T > > ,
125+ action : ( rule : Pattern < T > ) => void ,
126+ ) {
127+ for ( const rule of ruleMap ) {
113128 if ( typeof rule === "object" ) {
114129 action ( rule ) ;
115130 if ( rule . patterns !== undefined ) {
@@ -125,16 +140,22 @@ function visitAllRulesInRuleMap(ruleMap: any, action: (rule: any) => void) {
125140 * @param rule The rule whose matches are to be transformed.
126141 * @param action The transformation to make on each match pattern.
127142 */
128- function visitAllMatchesInRule ( rule : any , action : ( match : any ) => any ) {
143+ function visitAllMatchesInRule < T > ( rule : Pattern < T > , action : ( match : T ) => T ) {
129144 for ( const key in rule ) {
130145 switch ( key ) {
131146 case "begin" :
132147 case "end" :
133148 case "match" :
134- case "while" :
135- rule [ key ] = action ( rule [ key ] ) ;
136- break ;
149+ case "while" : {
150+ const ruleElement = rule [ key ] ;
137151
152+ if ( ! ruleElement ) {
153+ continue ;
154+ }
155+
156+ rule [ key ] = action ( ruleElement ) ;
157+ break ;
158+ }
138159 default :
139160 break ;
140161 }
@@ -148,14 +169,17 @@ function visitAllMatchesInRule(rule: any, action: (match: any) => any) {
148169 * @param rule Rule to be transformed.
149170 * @param key Base key of the property to be transformed.
150171 */
151- function expandPatternMatchProperties ( rule : any , key : "begin" | "end" ) {
152- const patternKey = `${ key } Pattern` ;
153- const capturesKey = `${ key } Captures` ;
172+ function expandPatternMatchProperties < T > (
173+ rule : Pattern < T > ,
174+ key : "begin" | "end" ,
175+ ) {
176+ const patternKey = `${ key } Pattern` as const ;
177+ const capturesKey = `${ key } Captures` as const ;
154178 const pattern = rule [ patternKey ] ;
155179 if ( pattern !== undefined ) {
156180 const patterns : string [ ] = Array . isArray ( pattern ) ? pattern : [ pattern ] ;
157- rule [ key ] = patterns . map ( ( p ) => `((?${ p } ))` ) . join ( "|" ) ;
158- const captures : { [ index : string ] : any } = { } ;
181+ rule [ key ] = patterns . map ( ( p ) => `((?${ p } ))` ) . join ( "|" ) as T ;
182+ const captures : Pattern [ "captures" ] = { } ;
159183 for ( const patternIndex in patterns ) {
160184 captures [ ( Number ( patternIndex ) + 1 ) . toString ( ) ] = {
161185 patterns : [
@@ -175,7 +199,7 @@ function expandPatternMatchProperties(rule: any, key: "begin" | "end") {
175199 *
176200 * @param yaml The root of the YAML document.
177201 */
178- function transformFile ( yaml : any ) {
202+ function transformFile ( yaml : ExtendedTextmateGrammar < ExtendedMatchType > ) {
179203 const macros = gatherMacros ( yaml ) ;
180204 visitAllRulesInFile ( yaml , ( rule ) => {
181205 expandPatternMatchProperties ( rule , "begin" ) ;
@@ -198,24 +222,29 @@ function transformFile(yaml: any) {
198222
199223 yaml . macros = undefined ;
200224
201- const replacements = gatherMatchTextForRules ( yaml ) ;
225+ // We have removed all object match properties, so we don't have an extended match type anymore.
226+ const macrolessYaml = yaml as ExtendedTextmateGrammar ;
227+
228+ const replacements = gatherMatchTextForRules ( macrolessYaml ) ;
202229 // Expand references in matches.
203- visitAllRulesInFile ( yaml , ( rule ) => {
230+ visitAllRulesInFile ( macrolessYaml , ( rule ) => {
204231 visitAllMatchesInRule ( rule , ( match ) => {
205232 return replaceReferencesWithStrings ( match , replacements ) ;
206233 } ) ;
207234 } ) ;
208235
209- if ( yaml . regexOptions !== undefined ) {
210- const regexOptions = `(?${ yaml . regexOptions } )` ;
211- visitAllRulesInFile ( yaml , ( rule ) => {
236+ if ( macrolessYaml . regexOptions !== undefined ) {
237+ const regexOptions = `(?${ macrolessYaml . regexOptions } )` ;
238+ visitAllRulesInFile ( macrolessYaml , ( rule ) => {
212239 visitAllMatchesInRule ( rule , ( match ) => {
213240 return regexOptions + match ;
214241 } ) ;
215242 } ) ;
216243
217- yaml . regexOptions = undefined ;
244+ macrolessYaml . regexOptions = undefined ;
218245 }
246+
247+ return macrolessYaml ;
219248}
220249
221250export function transpileTextMateGrammar ( ) {
@@ -230,8 +259,8 @@ export function transpileTextMateGrammar() {
230259 } else if ( file . isBuffer ( ) ) {
231260 const buf : Buffer = file . contents ;
232261 const yamlText : string = buf . toString ( "utf8" ) ;
233- const jsonData : any = load ( yamlText ) ;
234- transformFile ( jsonData ) ;
262+ const yamlData = load ( yamlText ) as TextmateGrammar ;
263+ const jsonData = transformFile ( yamlData ) ;
235264
236265 file . contents = Buffer . from ( JSON . stringify ( jsonData , null , 2 ) , "utf8" ) ;
237266 file . extname = ".json" ;
0 commit comments