@@ -5,36 +5,33 @@ import {
55 FileSystem ,
66 Terminal ,
77 ConsoleTerminalProvider ,
8- Path
8+ Path ,
9+ NewlineKind
910} from '@microsoft/node-core-library' ;
1011import * as glob from 'glob' ;
1112import * as path from 'path' ;
1213import { EOL } from 'os' ;
1314import * as chokidar from 'chokidar' ;
1415
15- import { ILocalizationFile } from './interfaces' ;
16- import { ILoggerOptions } from './utilities/Logging' ;
17- import { LocFileParser } from './utilities/LocFileParser' ;
18-
1916/**
2017 * @public
2118 */
22- export interface ITypingsGeneratorOptions {
19+ export interface ITypingsGeneratorOptions < TTypingsResult = string > {
2320 srcFolder : string ;
21+ fileExtensions : string [ ] ;
2422 generatedTsFolder : string ;
23+ parseAndGenerateTypings : ( fileContents : string , filePath : string ) => TTypingsResult ;
2524 terminal ?: Terminal ;
26- exportAsDefault ?: boolean ;
2725 filesToIgnore ?: string [ ] ;
2826}
2927
3028/**
31- * This is a simple tool that generates .d.ts files for .loc.json and .resx files.
29+ * This is a simple tool that generates .d.ts files for non-TS files.
3230 *
3331 * @public
3432 */
3533export class TypingsGenerator {
36- private _options : ITypingsGeneratorOptions ;
37- private _loggingOptions : ILoggerOptions ;
34+ protected _options : ITypingsGeneratorOptions ;
3835
3936 public constructor ( options : ITypingsGeneratorOptions ) {
4037 this . _options = {
@@ -57,6 +54,10 @@ export class TypingsGenerator {
5754 throw new Error ( 'generatedTsFolder must not be under srcFolder' ) ;
5855 }
5956
57+ if ( ! this . _options . fileExtensions || this . _options . fileExtensions . length === 0 ) {
58+ throw new Error ( 'At least one file extension must be provided.' ) ;
59+ }
60+
6061 if ( ! this . _options . filesToIgnore ) {
6162 this . _options . filesToIgnore = [ ] ;
6263 }
@@ -65,10 +66,7 @@ export class TypingsGenerator {
6566 this . _options . terminal = new Terminal ( new ConsoleTerminalProvider ( { verboseEnabled : true } ) ) ;
6667 }
6768
68- this . _loggingOptions = {
69- writeError : this . _options . terminal . writeErrorLine . bind ( this . _options . terminal ) ,
70- writeWarning : this . _options . terminal . writeWarningLine . bind ( this . _options . terminal )
71- } ;
69+ this . _options . fileExtensions = this . _normalizeFileExtensions ( this . _options . fileExtensions ) ;
7270 }
7371
7472 public generateTypings ( ) : void {
@@ -78,8 +76,8 @@ export class TypingsGenerator {
7876 return path . resolve ( this . _options . srcFolder , fileToIgnore ) ;
7977 } ) ) ;
8078
81- const locFilePaths : string [ ] = glob . sync (
82- path . join ( '**' , ' *+(.resx|.loc.json)' ) ,
79+ const filePaths : string [ ] = glob . sync (
80+ path . join ( '**' , ` *+(${ this . _options . fileExtensions . join ( '|' ) } )` ) ,
8381 {
8482 cwd : this . _options . srcFolder ,
8583 absolute : true ,
@@ -88,14 +86,14 @@ export class TypingsGenerator {
8886 }
8987 ) ;
9088
91- for ( let locFilePath of locFilePaths ) {
92- locFilePath = path . resolve ( this . _options . srcFolder , locFilePath ) ;
89+ for ( let filePath of filePaths ) {
90+ filePath = path . resolve ( this . _options . srcFolder , filePath ) ;
9391
94- if ( filesToIgnore . has ( locFilePath ) ) {
92+ if ( filesToIgnore . has ( filePath ) ) {
9593 continue ;
9694 }
9795
98- this . _parseFileAndGenerateTypings ( locFilePath ) ;
96+ this . _parseFileAndGenerateTypings ( filePath ) ;
9997 }
10098 }
10199
@@ -105,76 +103,40 @@ export class TypingsGenerator {
105103 const globBase : string = path . resolve ( this . _options . srcFolder , '**' ) ;
106104
107105 const watcher : chokidar . FSWatcher = chokidar . watch (
108- [ path . join ( globBase , '*.loc.json' ) , path . join ( globBase , '*.resx' ) ]
106+ this . _options . fileExtensions . map ( ( fileExtension ) => path . join ( globBase , `* ${ fileExtension } ` ) )
109107 ) ;
110- const boundGenerateTypingsFunction : ( locFilePath : string ) => void = this . _parseFileAndGenerateTypings . bind ( this ) ;
108+ const boundGenerateTypingsFunction : ( filePath : string ) => void = this . _parseFileAndGenerateTypings . bind ( this ) ;
111109 watcher . on ( 'add' , boundGenerateTypingsFunction ) ;
112110 watcher . on ( 'change' , boundGenerateTypingsFunction ) ;
113- watcher . on ( 'unlink' , ( locFilePath ) => {
114- const generatedTsFilePath : string = this . _getTypingsFilePath ( locFilePath ) ;
111+ watcher . on ( 'unlink' , ( filePath ) => {
112+ const generatedTsFilePath : string = this . _getTypingsFilePath ( filePath ) ;
115113 FileSystem . deleteFile ( generatedTsFilePath ) ;
116114 } ) ;
117115 }
118116
119117 private _parseFileAndGenerateTypings ( locFilePath : string ) : void {
120- const locFileData : ILocalizationFile = LocFileParser . parseLocFile ( {
121- filePath : locFilePath ,
122- content : FileSystem . readFile ( locFilePath ) ,
123- loggerOptions : this . _loggingOptions
124- } ) ;
125- this . _generateTypingsForLocFile ( locFilePath , locFileData ) ;
126- }
118+ try {
119+ const fileContents : string = FileSystem . readFile ( locFilePath ) ;
120+ const typingsData : string = this . _options . parseAndGenerateTypings ( fileContents , locFilePath ) ;
121+ const generatedTsFilePath : string = this . _getTypingsFilePath ( locFilePath ) ;
127122
128- private _generateTypingsForLocFile ( locFilePath : string , locFileData : ILocalizationFile ) : void {
129- const outputLines : string [ ] = [
130- '// This file was generated by a tool. Modifying it will produce unexpected behavior ',
131- ''
132- ] ;
123+ const prefixedTypingsData : string = [
124+ '// This file was generated by a tool. Modifying it will produce unexpected behavior' ,
125+ ' ',
126+ typingsData
127+ ] . join ( EOL ) ;
133128
134- let indent : string = '' ;
135- if ( this . _options . exportAsDefault ) {
136- outputLines . push (
137- 'export interface IStrings {'
129+ FileSystem . writeFile (
130+ generatedTsFilePath ,
131+ prefixedTypingsData ,
132+ { ensureFolderExists : true , convertLineEndings : NewlineKind . OsDefault }
138133 ) ;
139134
140- indent = ' ' ;
141- }
142-
143- for ( const stringName in locFileData ) { // eslint-disable-line guard-for-in
144- const { comment } = locFileData [ stringName ] ;
145-
146- if ( comment && comment . trim ( ) !== '' ) {
147- outputLines . push (
148- `${ indent } /**` ,
149- `${ indent } * ${ comment . replace ( / \* \/ / g, '*\\/' ) } ` ,
150- `${ indent } */`
151- ) ;
152- }
153-
154- if ( this . _options . exportAsDefault ) {
155- outputLines . push (
156- `${ indent } ${ stringName } : string;` ,
157- ''
158- ) ;
159- } else {
160- outputLines . push (
161- `export declare const ${ stringName } : string;` ,
162- ''
163- ) ;
164- }
165- }
166-
167- if ( this . _options . exportAsDefault ) {
168- outputLines . push (
169- '}' ,
170- '' ,
171- 'declare const strings: IStrings;' ,
172- 'export default strings;'
135+ } catch ( e ) {
136+ this . _options . terminal ! . writeError (
137+ `Error occurred parsing and generating typings for file "${ locFilePath } ": ${ e } `
173138 ) ;
174139 }
175-
176- const generatedTsFilePath : string = this . _getTypingsFilePath ( locFilePath ) ;
177- FileSystem . writeFile ( generatedTsFilePath , outputLines . join ( EOL ) , { ensureFolderExists : true } ) ;
178140 }
179141
180142 private _getTypingsFilePath ( locFilePath : string ) : string {
@@ -183,4 +145,17 @@ export class TypingsGenerator {
183145 path . relative ( this . _options . srcFolder , `${ locFilePath } .d.ts` )
184146 ) ;
185147 }
148+
149+ private _normalizeFileExtensions ( fileExtensions : string [ ] ) : string [ ] {
150+ const result : string [ ] = [ ] ;
151+ for ( const fileExtension of fileExtensions ) {
152+ if ( ! fileExtension . startsWith ( '.' ) ) {
153+ result . push ( `.${ fileExtension } ` ) ;
154+ } else {
155+ result . push ( fileExtension ) ;
156+ }
157+ }
158+
159+ return result ;
160+ }
186161}
0 commit comments