1 | import * as ts from 'typescript';
|
2 | import { createFilter } from 'rollup-pluginutils';
|
3 | import * as path from 'path';
|
4 | import {
|
5 | existsSync,
|
6 | readFileSync,
|
7 | statSync,
|
8 | } from 'fs';
|
9 | import assign from 'object-assign';
|
10 | import compareVersions from 'compare-versions';
|
11 |
|
12 | import { endsWith } from './string';
|
13 | import fixExportClass from './fixExportClass';
|
14 |
|
15 | interface Options {
|
16 | tsconfig?: boolean;
|
17 | include?: string | string[];
|
18 | exclude?: string | string[];
|
19 | typescript?: typeof ts;
|
20 | module?: string;
|
21 | }
|
22 |
|
23 | const resolveHost = {
|
24 | fileExists ( filePath: string ): boolean {
|
25 | try {
|
26 | return statSync( filePath ).isFile();
|
27 | } catch ( err ) {
|
28 | return false;
|
29 | }
|
30 | }
|
31 | };
|
32 |
|
33 | function goodErrors ( diagnostic: ts.Diagnostic ): boolean {
|
34 |
|
35 | return diagnostic.code !== 1204;
|
36 | }
|
37 |
|
38 | function getDefaultOptions(): any {
|
39 | return {
|
40 | noEmitHelpers: true,
|
41 | module: 'es2015',
|
42 | sourceMap: true
|
43 | };
|
44 | }
|
45 |
|
46 | // Gratefully lifted from 'look-up', due to problems using it directly:
|
47 | // https://github.com/jonschlinkert/look-up/blob/master/index.js
|
48 | // MIT Licenced
|
49 | function findFile( cwd: string, filename: string ): string {
|
50 | let fp = cwd ? ( cwd + '/' + filename ) : filename;
|
51 |
|
52 | if ( existsSync( fp ) ) {
|
53 | return fp;
|
54 | }
|
55 |
|
56 | const segs = cwd.split( path.sep );
|
57 | let len = segs.length;
|
58 |
|
59 | while ( len-- ) {
|
60 | cwd = segs.slice( 0, len ).join( '/' );
|
61 | fp = cwd + '/' + filename;
|
62 | if ( existsSync( fp ) ) {
|
63 | return fp;
|
64 | }
|
65 | }
|
66 | return null;
|
67 | }
|
68 |
|
69 | function compilerOptionsFromTsConfig( typescript: typeof ts ): ts.CompilerOptions {
|
70 | const cwd = process.cwd();
|
71 |
|
72 | const tsconfig = typescript.readConfigFile( findFile( cwd, 'tsconfig.json' ), path => readFileSync( path, 'utf8' ) );
|
73 |
|
74 | if ( !tsconfig.config || !tsconfig.config.compilerOptions ) return {};
|
75 |
|
76 | return tsconfig.config.compilerOptions;
|
77 | }
|
78 |
|
79 |
|
80 |
|
81 | function fixSourceMapOption( options: any ) {
|
82 | if ( typeof options.inlineSourceMap === 'boolean' ) {
|
83 | options.sourceMap = options.inlineSourceMap;
|
84 | delete options.inlineSourceMap;
|
85 | }
|
86 | }
|
87 |
|
88 | export default function typescript ( options: Options ) {
|
89 | options = assign( {}, options || {} );
|
90 |
|
91 | const filter = createFilter(
|
92 | options.include || [ '*.ts+(|x)', '**/*.ts+(|x)' ],
|
93 | options.exclude || [ '*.d.ts', '**/*.d.ts' ] );
|
94 |
|
95 | delete options.include;
|
96 | delete options.exclude;
|
97 |
|
98 |
|
99 | const typescript: typeof ts = options.typescript || ts;
|
100 |
|
101 | delete options.typescript;
|
102 |
|
103 |
|
104 | const tsconfig = options.tsconfig === false ? {} :
|
105 | compilerOptionsFromTsConfig( typescript );
|
106 |
|
107 | delete options.tsconfig;
|
108 |
|
109 |
|
110 |
|
111 | fixSourceMapOption( tsconfig );
|
112 | fixSourceMapOption( options );
|
113 |
|
114 |
|
115 | options = assign( tsconfig, getDefaultOptions(), options );
|
116 |
|
117 |
|
118 | if ( options.module !== 'es2015' && options.module !== 'es6' ) {
|
119 | throw new Error( `rollup-plugin-typescript: The module kind should be 'es2015', found: '${ options.module }'` );
|
120 | }
|
121 |
|
122 | const parsed = typescript.convertCompilerOptionsFromJson( options, process.cwd() );
|
123 |
|
124 | if ( parsed.errors.length ) {
|
125 | parsed.errors.forEach( error => console.error( `rollup-plugin-typescript: ${ error.messageText }` ) );
|
126 |
|
127 | throw new Error( `rollup-plugin-typescript: Couldn't process compiler options` );
|
128 | }
|
129 |
|
130 | const compilerOptions = parsed.options;
|
131 |
|
132 | return {
|
133 | resolveId ( importee: string, importer: string ): string {
|
134 |
|
135 | if ( importee === 'typescript-helpers' ) {
|
136 | return path.resolve( __dirname, '../src/typescript-helpers.js' );
|
137 | }
|
138 |
|
139 | if ( !importer ) return null;
|
140 |
|
141 | var result: ts.ResolvedModuleWithFailedLookupLocations;
|
142 |
|
143 | if ( compareVersions( typescript.version, '1.8.0' ) < 0 ) {
|
144 |
|
145 | result = (typescript as any).nodeModuleNameResolver( importee, importer, resolveHost );
|
146 | } else {
|
147 | result = typescript.nodeModuleNameResolver( importee, importer, compilerOptions, resolveHost );
|
148 | }
|
149 |
|
150 | if ( result.resolvedModule && result.resolvedModule.resolvedFileName ) {
|
151 | if ( endsWith( result.resolvedModule.resolvedFileName, '.d.ts' ) ) {
|
152 | return null;
|
153 | }
|
154 |
|
155 | return result.resolvedModule.resolvedFileName;
|
156 | }
|
157 |
|
158 | return null;
|
159 | },
|
160 |
|
161 | transform ( code: string, id: string ): { code: string, map: any } {
|
162 | if ( !filter( id ) ) return null;
|
163 |
|
164 | const transformed = typescript.transpileModule( fixExportClass( code, id ), {
|
165 | fileName: id,
|
166 | reportDiagnostics: true,
|
167 | compilerOptions
|
168 | });
|
169 |
|
170 | const diagnostics = transformed.diagnostics.filter( goodErrors );
|
171 | let fatalError = false;
|
172 |
|
173 | diagnostics.forEach( diagnostic => {
|
174 | var message = typescript.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
175 |
|
176 | if ( diagnostic.file ) {
|
177 | const { line, character } = diagnostic.file.getLineAndCharacterOfPosition( diagnostic.start );
|
178 |
|
179 | console.error( `${diagnostic.file.fileName}(${line + 1},${character + 1}): error TS${diagnostic.code}: ${message}` );
|
180 | } else {
|
181 | console.error( `Error: ${message}` );
|
182 | }
|
183 |
|
184 | if ( diagnostic.category === ts.DiagnosticCategory.Error ) {
|
185 | fatalError = true;
|
186 | }
|
187 | });
|
188 |
|
189 | if ( fatalError ) {
|
190 | throw new Error( `There were TypeScript errors transpiling "${id}"` );
|
191 | }
|
192 |
|
193 | return {
|
194 |
|
195 | code: transformed.outputText +
|
196 | `\nimport { __extends, __decorate, __metadata, __param, __awaiter } from 'typescript-helpers';`,
|
197 |
|
198 |
|
199 | map: JSON.parse(transformed.sourceMapText)
|
200 | };
|
201 | }
|
202 | };
|
203 | }
|