From 634f4cd1a9c184f1567505772068caf9920e1dc2 Mon Sep 17 00:00:00 2001 From: Christopher Wallis Date: Tue, 18 Oct 2016 01:36:38 -0400 Subject: [PATCH 01/16] tsconfig path can be passed in the tsconfig option --- src/index.js | 7 +++++-- src/options.js | 4 ++-- test/sample/custom-tsconfig/main.ts | 2 ++ test/sample/custom-tsconfig/tsconfig.json | 5 +++++ test/test.js | 8 ++++++++ 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 test/sample/custom-tsconfig/main.ts create mode 100644 test/sample/custom-tsconfig/tsconfig.json diff --git a/src/index.js b/src/index.js index 425b3c2..c839599 100644 --- a/src/index.js +++ b/src/index.js @@ -40,8 +40,11 @@ export default function typescript ( options ) { delete options.typescript; // Load options from `tsconfig.json` unless explicitly asked not to. - const tsconfig = options.tsconfig === false ? {} : - compilerOptionsFromTsConfig( typescript ); + const tsconfig = options.tsconfig === false + ? {} + : typeof options.tsconfig === 'string' + ? compilerOptionsFromTsConfig(typescript, options.tsconfig) + : compilerOptionsFromTsConfig(typescript, 'tsconfig.json'); delete options.tsconfig; diff --git a/src/options.js b/src/options.js index 5502ba4..e1b6ac3 100644 --- a/src/options.js +++ b/src/options.js @@ -37,10 +37,10 @@ function findFile ( cwd, filename ) { return null; } -export function compilerOptionsFromTsConfig ( typescript ) { +export function compilerOptionsFromTsConfig ( typescript, filename) { const cwd = process.cwd(); - const tsconfig = typescript.readConfigFile( findFile( cwd, 'tsconfig.json' ), path => readFileSync( path, 'utf8' ) ); + const tsconfig = typescript.readConfigFile( findFile( cwd, filename ), path => readFileSync( path, 'utf8' ) ); if ( !tsconfig.config || !tsconfig.config.compilerOptions ) return {}; diff --git a/test/sample/custom-tsconfig/main.ts b/test/sample/custom-tsconfig/main.ts new file mode 100644 index 0000000..d0b587a --- /dev/null +++ b/test/sample/custom-tsconfig/main.ts @@ -0,0 +1,2 @@ +const answer: number = 42; +console.log( `the answer is ${answer}` ); diff --git a/test/sample/custom-tsconfig/tsconfig.json b/test/sample/custom-tsconfig/tsconfig.json new file mode 100644 index 0000000..ea71f94 --- /dev/null +++ b/test/sample/custom-tsconfig/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "target": "es6" + } +} \ No newline at end of file diff --git a/test/test.js b/test/test.js index 9bcd97c..2e8a98c 100644 --- a/test/test.js +++ b/test/test.js @@ -220,6 +220,14 @@ describe( 'rollup-plugin-typescript', function () { assert.ok( map.sources.every( source => source.indexOf( 'typescript-helpers' ) === -1) ); }); }); + + it( 'reads in custom tsconfig files', () => { + return bundle('sample/custom-tsconfig/main.ts', { + tsconfig: 'sample/custom-tsconfig/tsconfig.json' + }).then(bundle => { + assert.equal(bundle.modules[1].code.indexOf('const answer = 42'), 0); + }); + }); }); function fakeTypescript ( custom ) { From 27b78a06f5afb696e4fd607f48543993e6a7dbe2 Mon Sep 17 00:00:00 2001 From: Christopher Wallis Date: Thu, 12 Jan 2017 16:01:14 -0500 Subject: [PATCH 02/16] updated to 2.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d6b857..73f570e 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "object-assign": "^4.0.1", "rollup-pluginutils": "^1.3.1", "tippex": "^2.1.1", - "typescript": "^1.8.9" + "typescript": "^2.1.4" }, "devDependencies": { "buble": "^0.13.1", From 54f55c75231111b620d996a341aedb7f7985c160 Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Mon, 22 May 2017 23:06:55 -0500 Subject: [PATCH 03/16] Progress towards 2.0 support and tslib --- package.json | 3 +- rollup.config.js | 1 + src/index.js | 17 ++++++--- src/options.js | 4 +++ src/typescript-helpers.js | 50 +++++++++++++-------------- test/sample/tslib-helpers/main.ts | 11 ++++++ test/test.js | 57 ++++++++++++++++++------------- 7 files changed, 89 insertions(+), 54 deletions(-) create mode 100644 test/sample/tslib-helpers/main.ts diff --git a/package.json b/package.json index 0d6b857..7b39de0 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "object-assign": "^4.0.1", "rollup-pluginutils": "^1.3.1", "tippex": "^2.1.1", - "typescript": "^1.8.9" + "tslib": "^1.7.1", + "typescript": "^2.3.3" }, "devDependencies": { "buble": "^0.13.1", diff --git a/rollup.config.js b/rollup.config.js index 11b20a8..5c73b05 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -12,6 +12,7 @@ export default { 'object-assign', 'rollup-pluginutils', 'tippex', + 'tslib', 'typescript' ], diff --git a/src/index.js b/src/index.js index 425b3c2..4460789 100644 --- a/src/index.js +++ b/src/index.js @@ -68,10 +68,12 @@ export default function typescript ( options ) { const compilerOptions = parsed.options; + const isVersionOne = compareVersions( typescript.version, '2.0.0' ) >= 0; + return { resolveId ( importee, importer ) { // Handle the special `typescript-helpers` import itself. - if ( importee === helpersId ) { + if ( isVersionOne && importee === helpersId ) { return helpersId; } @@ -100,7 +102,7 @@ export default function typescript ( options ) { }, load ( id ) { - if ( id === helpersId ) { + if ( isVersionOne && id === helpersId ) { return helpersSource; } }, @@ -140,10 +142,15 @@ export default function typescript ( options ) { throw new Error( `There were TypeScript errors transpiling` ); } + let finalCode = transformed.outputText; + + if (isVersionOne) { + // Always append an import for the helpers (for versions < 2) + finalCode += `\nimport { __assign, __awaiter, __extends, __decorate, __metadata, __param } from '${helpersId}';`; + } + return { - // Always append an import for the helpers. - code: transformed.outputText + - `\nimport { __assign, __awaiter, __extends, __decorate, __metadata, __param } from '${helpersId}';`, + code: finalCode, // Rollup expects `map` to be an object so we must parse the string map: transformed.sourceMapText ? JSON.parse(transformed.sourceMapText) : null diff --git a/src/options.js b/src/options.js index 5502ba4..9e40f62 100644 --- a/src/options.js +++ b/src/options.js @@ -65,4 +65,8 @@ export function adjustCompilerOptions ( typescript, options ) { console.warn( `rollup-plugin-typescript: 'strictNullChecks' is not supported; disabling it` ); } + + if ( compareVersions( tsVersion, '2.0.0' ) >= 0) { + options.importHelpers = true; + } } diff --git a/src/typescript-helpers.js b/src/typescript-helpers.js index 092b99e..32df8c9 100644 --- a/src/typescript-helpers.js +++ b/src/typescript-helpers.js @@ -1,41 +1,41 @@ export const __assign = Object.assign || function (target) { - for (var source, i = 1; i < arguments.length; i++) { - source = arguments[i]; - for (var prop in source) { - if (Object.prototype.hasOwnProperty.call(source, prop)) { - target[prop] = source[prop]; - } - } - } - return target; -}; + for (var source, i = 1; i < arguments.length; i++) { + source = arguments[i]; + for (var prop in source) { + if (Object.prototype.hasOwnProperty.call(source, prop)) { + target[prop] = source[prop]; + } + } + } + return target; + }; export function __extends(d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } export function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } export function __metadata(k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); } export function __param(paramIndex, decorator) { - return function (target, key) { decorator(target, key, paramIndex); } + return function (target, key) { decorator(target, key, paramIndex); } } export function __awaiter(thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments)).next()); - }); + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); } diff --git a/test/sample/tslib-helpers/main.ts b/test/sample/tslib-helpers/main.ts new file mode 100644 index 0000000..908125e --- /dev/null +++ b/test/sample/tslib-helpers/main.ts @@ -0,0 +1,11 @@ +function* generateNumber() { + let index = 10; + while (index > 0) { + yield index--; + } +} + +const generator: IterableIterator = generateNumber(); +generator.next(); + +// todo add more changes between our hardcoded helpers and the official tslib diff --git a/test/test.js b/test/test.js index 9bcd97c..6ca1ee4 100644 --- a/test/test.js +++ b/test/test.js @@ -9,7 +9,7 @@ process.chdir( __dirname ); function evaluate ( bundle ) { const module = { exports: {} }; - new Function( 'module', 'exports', bundle.generate({ format: 'cjs' }).code )( module, module.exports ); + new Function( 'module', 'exports', 'require', bundle.generate({ format: 'cjs' }).code )( module, module.exports, require ); // pass require for tslib return module.exports; } @@ -47,17 +47,18 @@ describe( 'rollup-plugin-typescript', function () { }); }); - it( 'does not duplicate helpers', () => { - return bundle( 'sample/dedup-helpers/main.ts' ).then( bundle => { - const code = bundle.generate().code; - - // The `__extends` function is defined in the bundle. - assert.ok( code.indexOf( 'function __extends' ) > -1, code ); - - // No duplicate `__extends` helper is defined. - assert.equal( code.indexOf( '__extends$1' ), -1, code ); - }); - }); + //// test removed as switching to tslib means that helpers are always deduped + // it( 'does not duplicate helpers', () => { + // return bundle( 'sample/dedup-helpers/main.ts' ).then( bundle => { + // const code = bundle.generate().code; + // + // // The `__extends` function is defined in the bundle. + // assert.ok( code.indexOf( 'function __extends' ) > -1, code ); + // + // // No duplicate `__extends` helper is defined. + // assert.equal( code.indexOf( '__extends$1' ), -1, code ); + // }); + // }); it( 'transpiles `export class A` correctly', () => { return bundle( 'sample/export-class-fix/main.ts' ).then( bundle => { @@ -179,10 +180,11 @@ describe( 'rollup-plugin-typescript', function () { return bundle( 'sample/jsx/main.tsx', { jsx: 'react' }).then( bundle => { const code = bundle.generate().code; - assert.notEqual( code.indexOf( 'const __assign = ' ), -1, - 'should contain __assign definition' ); + //// assertion disabled since this is now handled by typescript + // assert.notEqual( code.indexOf( 'const __assign = ' ), -1, + // 'should contain __assign definition' ); - const usage = code.indexOf( 'React.createElement("span", __assign({}, props), "Yo!")' ); + const usage = code.indexOf( 'React.createElement("span", tslib_1.__assign({}, props), "Yo!")' ); assert.notEqual( usage, -1, 'should contain usage' ); }); @@ -209,15 +211,24 @@ describe( 'rollup-plugin-typescript', function () { }); }); - it( 'does not include helpers in source maps', () => { - return bundle( 'sample/dedup-helpers/main.ts', { - sourceMap: true - }).then( bundle => { - const { map } = bundle.generate({ - sourceMap: true - }); + //// test removed as typescript handles this + // it( 'does not include helpers in source maps', () => { + // return bundle( 'sample/dedup-helpers/main.ts', { + // sourceMap: true + // }).then( bundle => { + // const { map } = bundle.generate({ + // sourceMap: true + // }); + // + // assert.ok( map.sources.every( source => source.indexOf( 'typescript-helpers' ) === -1) ); + // }); + // }); + + it( 'supports tslib helpers', () => { + return bundle( 'sample/tslib-helpers/main.ts' ).then( bundle => { + const code = bundle.generate().code; - assert.ok( map.sources.every( source => source.indexOf( 'typescript-helpers' ) === -1) ); + assert.notEqual( code.indexOf( 'from \'tslib\'' ), -1, 'should import tslib' ); }); }); }); From cd3856e61c88d6306386b2a4397b17646854b661 Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Mon, 22 May 2017 23:16:01 -0500 Subject: [PATCH 04/16] Manually add PR #86 --- src/typescript-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typescript-helpers.js b/src/typescript-helpers.js index 32df8c9..660dfdc 100644 --- a/src/typescript-helpers.js +++ b/src/typescript-helpers.js @@ -1,4 +1,4 @@ -export const __assign = Object.assign || function (target) { +export var __assign = Object.assign || function (target) { for (var source, i = 1; i < arguments.length; i++) { source = arguments[i]; for (var prop in source) { From 1f48874ccf56b92a102c6c6f19df6ddf6416d8ee Mon Sep 17 00:00:00 2001 From: Christopher Wallis Date: Tue, 23 May 2017 02:38:36 -0400 Subject: [PATCH 05/16] reverse last commit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73f570e..0d6b857 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "object-assign": "^4.0.1", "rollup-pluginutils": "^1.3.1", "tippex": "^2.1.1", - "typescript": "^2.1.4" + "typescript": "^1.8.9" }, "devDependencies": { "buble": "^0.13.1", From 987402056c85005963760be0e805d063e9284287 Mon Sep 17 00:00:00 2001 From: Christopher Wallis Date: Tue, 23 May 2017 02:57:19 -0400 Subject: [PATCH 06/16] forcing a commit to kick off travis after PR target change --- test/sample/custom-tsconfig/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sample/custom-tsconfig/tsconfig.json b/test/sample/custom-tsconfig/tsconfig.json index ea71f94..02fe94c 100644 --- a/test/sample/custom-tsconfig/tsconfig.json +++ b/test/sample/custom-tsconfig/tsconfig.json @@ -1,5 +1,5 @@ { "compilerOptions": { - "target": "es6" + "target": "es6" } } \ No newline at end of file From 2e111fd4aac337ce2ec5b1aee00c32832a1a9369 Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 14:14:37 -0500 Subject: [PATCH 07/16] Check TS version --- src/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/index.js b/src/index.js index 4460789..482a912 100644 --- a/src/index.js +++ b/src/index.js @@ -37,6 +37,10 @@ export default function typescript ( options ) { // Allow users to override the TypeScript version used for transpilation. const typescript = options.typescript || ts; + if ( compareVersions( typescript.version, '1.6.0' ) < 0 ) { + throw new Error( `rollup-plugin-typescript: TypeScript version must be later than 1.6.0` ); + } + delete options.typescript; // Load options from `tsconfig.json` unless explicitly asked not to. From 8f52f9fd7e4549383301ca8cdccc57974908b83f Mon Sep 17 00:00:00 2001 From: Michael Strobel Date: Mon, 23 Jan 2017 11:14:21 +0800 Subject: [PATCH 08/16] Add useLanguageService option as a solution for emit-less types and semantic diagnostics --- src/compiler.js | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ src/index.js | 22 ++++++-- 2 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 src/compiler.js diff --git a/src/compiler.js b/src/compiler.js new file mode 100644 index 0000000..3b2e252 --- /dev/null +++ b/src/compiler.js @@ -0,0 +1,142 @@ +import * as fs from 'fs'; +import compareVersions from 'compare-versions'; + +const fileCache = new Map(); +const tsFiles = new Set(); + +let typescript = undefined; +let compilerOptions = undefined; +let entryFile = undefined; +let languageService = undefined; + + +function getFile(fileName) { + let file = fileCache.get(fileName); + + if(file === undefined) { + const version = Date.now().toString(); + + if (!fs.existsSync(fileName)) { + file = { + snapshot: undefined, + version: version + }; + } + else { + file = { + snapshot: typescript.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString()), + version: version + }; + } + + fileCache.set(fileName, file); + } + + return file; +} + +function setFileContent(fileName, content, override) { + if(!override && fileCache.get(fileName)) { + return; + } + + tsFiles.add(fileName); + + fileCache.set(fileName, { + snapshot: typescript.ScriptSnapshot.fromString(content), + version: Date.now().toString() + }); +} + +function initLanguageService() { + if(languageService) return; + + fixTypeLookup(); + + const languageServiceHost = { + getScriptFileNames: () => Array.from(tsFiles), + getScriptVersion: (fileName) => getFile(fileName).version, + getScriptSnapshot: (fileName) => getFile(fileName).snapshot, + getCurrentDirectory: () => process.cwd(), + getCompilationSettings: () => compilerOptions, + getDefaultLibFileName: (options) => typescript.getDefaultLibFilePath(options) + }; + + languageService = typescript.createLanguageService(languageServiceHost, typescript.createDocumentRegistry()); +} + +/** + * Workaround for the LanguageService not finding typings in node_modules/@types: + * Manually set the "types" option to the folder names in node_modules/@types + */ +function fixTypeLookup() { + if(compilerOptions.types || compilerOptions.typeRoots) return; + + if ( compareVersions( typescript.version, '2.0.0' ) < 0 ) { + return; + } + + if(fs.existsSync('./node_modules/@types')) { + compilerOptions.types = fs.readdirSync('./node_modules/@types'); + } +} + + +function compileUsingLanguageService(fileName, content, refreshFile) { + setFileContent(fileName, content, refreshFile); + + const result = { + outputText: undefined, + diagnostics: undefined, + sourceMapText: undefined + }; + + const compiled = languageService.getEmitOutput(fileName); + + result.diagnostics = languageService.getCompilerOptionsDiagnostics() + .concat(languageService.getSyntacticDiagnostics(fileName)) + .concat(languageService.getSemanticDiagnostics(fileName)); + + compiled.outputFiles.forEach(outputFile => { + if(outputFile.name.slice(-3) === '.js') { + result.outputText = outputFile.text; + } + else if(outputFile.name.slice(-4) === '.map') { + result.sourceMapText = outputFile.text; + } + }); + + return result; +} + +function compileUsingSimpleApi(fileName, content) { + return typescript.transpileModule(content, { + fileName, + reportDiagnostics: true, + compilerOptions + }); +} + +function init(ts, compilerOpts, entry, useLanguageService) { + typescript = ts; + compilerOptions = compilerOpts; + entryFile = entry; + + tsFiles.add(entryFile); + + if(useLanguageService) { + initLanguageService(); + } +} + +function compileFile(fileName, content, refreshFile) { + return languageService + ? compileUsingLanguageService(fileName, content, refreshFile) + : compileUsingSimpleApi(fileName, content); +} + + +export default { + init, + compileFile +}; diff --git a/src/index.js b/src/index.js index 482a912..8eaf273 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,7 @@ import { endsWith } from './string'; import { getDefaultOptions, compilerOptionsFromTsConfig, adjustCompilerOptions } from './options.js'; import fixExportClass from './fixExportClass'; import resolveHost from './resolveHost'; +import compiler from './compiler'; /* interface Options { @@ -49,6 +50,9 @@ export default function typescript ( options ) { delete options.tsconfig; + const useLanguageService = options.useLanguageService; + delete options.useLanguageService; + // Since the CompilerOptions aren't designed for the Rollup // use case, we'll adjust them for use with Rollup. adjustCompilerOptions( typescript, tsconfig ); @@ -73,8 +77,14 @@ export default function typescript ( options ) { const compilerOptions = parsed.options; const isVersionOne = compareVersions( typescript.version, '2.0.0' ) >= 0; + let isFirstRun = true; return { + options (opts) { + const entryFile = path.resolve(process.cwd(), opts.entry); + compiler.init(typescript, compilerOptions, entryFile, useLanguageService); + }, + resolveId ( importee, importer ) { // Handle the special `typescript-helpers` import itself. if ( isVersionOne && importee === helpersId ) { @@ -114,11 +124,7 @@ export default function typescript ( options ) { transform ( code, id ) { if ( !filter( id ) ) return null; - const transformed = typescript.transpileModule( fixExportClass( code, id ), { - fileName: id, - reportDiagnostics: true, - compilerOptions - }); + const transformed = compiler.compileFile(id, fixExportClass( code, id ), !isFirstRun); // All errors except `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` const diagnostics = transformed.diagnostics ? @@ -142,7 +148,7 @@ export default function typescript ( options ) { } }); - if ( fatalError ) { + if ( fatalError && isFirstRun ) { throw new Error( `There were TypeScript errors transpiling` ); } @@ -159,6 +165,10 @@ export default function typescript ( options ) { // Rollup expects `map` to be an object so we must parse the string map: transformed.sourceMapText ? JSON.parse(transformed.sourceMapText) : null }; + }, + + onwrite() { + isFirstRun = false; } }; } From f1eaf23d77cc840d227bfaaadca1eb3613304f3b Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 14:22:42 -0500 Subject: [PATCH 09/16] Integrate PR 84 with some changes --- src/compiler.js | 182 ++++++++++++++++++++++++------------------------ src/index.js | 6 +- 2 files changed, 93 insertions(+), 95 deletions(-) diff --git a/src/compiler.js b/src/compiler.js index 3b2e252..4ce5239 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -10,133 +10,131 @@ let entryFile = undefined; let languageService = undefined; -function getFile(fileName) { - let file = fileCache.get(fileName); - - if(file === undefined) { - const version = Date.now().toString(); - - if (!fs.existsSync(fileName)) { - file = { - snapshot: undefined, - version: version - }; - } - else { - file = { - snapshot: typescript.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString()), - version: version - }; - } - - fileCache.set(fileName, file); - } - - return file; +function getFile (fileName) { + let file = fileCache.get( fileName ); + + if ( file === undefined ) { + const version = Date.now().toString(); + + if ( !fs.existsSync( fileName ) ) { + file = { + snapshot: undefined, + version + }; + } else { + file = { + snapshot: typescript.ScriptSnapshot.fromString( fs.readFileSync( fileName ).toString() ), + version + }; + } + + fileCache.set( fileName, file ); + } + + return file; } -function setFileContent(fileName, content, override) { - if(!override && fileCache.get(fileName)) { - return; - } +function setFileContent ( fileName, content, override ) { + if (!override && fileCache.get( fileName )) { + return; + } - tsFiles.add(fileName); + tsFiles.add( fileName ); - fileCache.set(fileName, { - snapshot: typescript.ScriptSnapshot.fromString(content), - version: Date.now().toString() - }); + fileCache.set( fileName, { + snapshot: typescript.ScriptSnapshot.fromString( content ), + version: Date.now().toString() + }); } -function initLanguageService() { - if(languageService) return; +function initLanguageService () { + if (languageService) return; - fixTypeLookup(); + fixTypeLookup(); - const languageServiceHost = { - getScriptFileNames: () => Array.from(tsFiles), - getScriptVersion: (fileName) => getFile(fileName).version, - getScriptSnapshot: (fileName) => getFile(fileName).snapshot, - getCurrentDirectory: () => process.cwd(), - getCompilationSettings: () => compilerOptions, - getDefaultLibFileName: (options) => typescript.getDefaultLibFilePath(options) - }; + const languageServiceHost = { + getScriptFileNames: () => Array.from( tsFiles ), + getScriptVersion: ( fileName ) => getFile( fileName ).version, + getScriptSnapshot: (fileName) => getFile( fileName ).snapshot, + getCurrentDirectory: () => process.cwd(), + getCompilationSettings: () => compilerOptions, + getDefaultLibFileName: ( options ) => typescript.getDefaultLibFilePath( options ) + }; - languageService = typescript.createLanguageService(languageServiceHost, typescript.createDocumentRegistry()); + languageService = typescript.createLanguageService( languageServiceHost, typescript.createDocumentRegistry() ); } /** * Workaround for the LanguageService not finding typings in node_modules/@types: * Manually set the "types" option to the folder names in node_modules/@types */ -function fixTypeLookup() { - if(compilerOptions.types || compilerOptions.typeRoots) return; +function fixTypeLookup () { + if ( compilerOptions.types || compilerOptions.typeRoots ) return; - if ( compareVersions( typescript.version, '2.0.0' ) < 0 ) { - return; - } + if ( compareVersions( typescript.version, '2.0.0' ) < 0 ) { + return; + } - if(fs.existsSync('./node_modules/@types')) { - compilerOptions.types = fs.readdirSync('./node_modules/@types'); - } + if ( fs.existsSync( './node_modules/@types' ) ) { + compilerOptions.types = fs.readdirSync('./node_modules/@types'); + } } -function compileUsingLanguageService(fileName, content, refreshFile) { - setFileContent(fileName, content, refreshFile); +function compileUsingLanguageService ( fileName, content, refreshFile ) { + setFileContent( fileName, content, refreshFile ); - const result = { - outputText: undefined, - diagnostics: undefined, - sourceMapText: undefined - }; + const result = { + outputText: undefined, + diagnostics: undefined, + sourceMapText: undefined + }; - const compiled = languageService.getEmitOutput(fileName); + const compiled = languageService.getEmitOutput( fileName ); - result.diagnostics = languageService.getCompilerOptionsDiagnostics() - .concat(languageService.getSyntacticDiagnostics(fileName)) - .concat(languageService.getSemanticDiagnostics(fileName)); + result.diagnostics = languageService.getCompilerOptionsDiagnostics() + .concat( languageService.getSyntacticDiagnostics( fileName ) ) + .concat( languageService.getSemanticDiagnostics( fileName ) ); - compiled.outputFiles.forEach(outputFile => { - if(outputFile.name.slice(-3) === '.js') { - result.outputText = outputFile.text; - } - else if(outputFile.name.slice(-4) === '.map') { - result.sourceMapText = outputFile.text; - } - }); + compiled.outputFiles.forEach( outputFile => { + if ( outputFile.name.slice( -3 ) === '.js' ) { + result.outputText = outputFile.text; + } else if ( outputFile.name.slice( -4 ) === '.map' ) { + result.sourceMapText = outputFile.text; + } + }); - return result; + return result; } -function compileUsingSimpleApi(fileName, content) { - return typescript.transpileModule(content, { - fileName, - reportDiagnostics: true, - compilerOptions - }); +function compileUsingSimpleApi ( fileName, content ) { + return typescript.transpileModule( content, { + fileName, + reportDiagnostics: true, + compilerOptions + }); } -function init(ts, compilerOpts, entry, useLanguageService) { - typescript = ts; - compilerOptions = compilerOpts; - entryFile = entry; +function init ( ts, compilerOpts, entry, useLanguageService ) { + typescript = ts; + compilerOptions = compilerOpts; + entryFile = entry; - tsFiles.add(entryFile); + tsFiles.add( entryFile ); - if(useLanguageService) { - initLanguageService(); - } + if ( useLanguageService ) { + initLanguageService(); + } } -function compileFile(fileName, content, refreshFile) { - return languageService - ? compileUsingLanguageService(fileName, content, refreshFile) - : compileUsingSimpleApi(fileName, content); +function compileFile ( fileName, content, refreshFile ) { + return languageService + ? compileUsingLanguageService( fileName, content, refreshFile ) + : compileUsingSimpleApi( fileName, content ); } export default { - init, - compileFile + init, + compileFile }; diff --git a/src/index.js b/src/index.js index 8eaf273..f511a74 100644 --- a/src/index.js +++ b/src/index.js @@ -50,7 +50,7 @@ export default function typescript ( options ) { delete options.tsconfig; - const useLanguageService = options.useLanguageService; + const useLanguageService = options.useLanguageService !== false; delete options.useLanguageService; // Since the CompilerOptions aren't designed for the Rollup @@ -82,7 +82,7 @@ export default function typescript ( options ) { return { options (opts) { const entryFile = path.resolve(process.cwd(), opts.entry); - compiler.init(typescript, compilerOptions, entryFile, useLanguageService); + compiler.init(typescript, compilerOptions, entryFile, useLanguageService); }, resolveId ( importee, importer ) { @@ -167,7 +167,7 @@ export default function typescript ( options ) { }; }, - onwrite() { + onwrite () { isFirstRun = false; } }; From 47adadbbbcd68b39c49f93633cab00073bf48f9d Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 14:27:58 -0500 Subject: [PATCH 10/16] Major version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b39de0..6e33d92 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rollup-plugin-typescript", - "version": "0.8.1", + "version": "1.0.0", "description": "Seamless integration between Rollup and TypeScript.", "main": "dist/rollup-plugin-typescript.cjs.js", "module": "dist/rollup-plugin-typescript.es.js", From 84c57b8bfb75ab3b0297e2b46f3884b7c65e8202 Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 14:36:19 -0500 Subject: [PATCH 11/16] Integrate PR 58 with some changes --- src/index.js | 6 +++++- test/sample/export-class-no-fix/main.ts | 1 + test/test.js | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/sample/export-class-no-fix/main.ts diff --git a/src/index.js b/src/index.js index 184640a..46d7b3a 100644 --- a/src/index.js +++ b/src/index.js @@ -127,7 +127,11 @@ export default function typescript ( options ) { transform ( code, id ) { if ( !filter( id ) ) return null; - const transformed = compiler.compileFile(id, fixExportClass( code, id ), !isFirstRun); + if ( compilerOptions.target === undefined || compilerOptions.target < typescript.ScriptTarget.ES2015 && isVersionOne ) { + code = fixExportClass( code, id ); + } + + const transformed = compiler.compileFile( id, code, !isFirstRun ); // All errors except `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` const diagnostics = transformed.diagnostics ? diff --git a/test/sample/export-class-no-fix/main.ts b/test/sample/export-class-no-fix/main.ts new file mode 100644 index 0000000..458d122 --- /dev/null +++ b/test/sample/export-class-no-fix/main.ts @@ -0,0 +1 @@ +export default class {} \ No newline at end of file diff --git a/test/test.js b/test/test.js index e1e7d95..461d2fd 100644 --- a/test/test.js +++ b/test/test.js @@ -71,6 +71,16 @@ describe( 'rollup-plugin-typescript', function () { }); }); + it( 'does not fix export class when targeting ES6', function () { + return bundle( 'sample/export-class-no-fix/main.ts', { + target: 'ES6' + }).then( function ( bundle ) { + const code = bundle.generate().code; + + assert.ok( code.indexOf( 'export default main' ) !== -1, code ); + }); + }); + it( 'transpiles ES6 features to ES5 with source maps', () => { return bundle( 'sample/import-class/main.ts' ).then( bundle => { const code = bundle.generate().code; @@ -267,6 +277,14 @@ function fakeTypescript ( custom ) { options, errors: [] }; + }, + + ScriptTarget: { + ES3: 0, + ES5: 1, + ES6: 2, + ES2015: 2, + Latest: 2 } }, custom); } From d685be0f6677a28f666f6e3da023b429b2765c61 Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 15:15:09 -0500 Subject: [PATCH 12/16] Work on tests --- package.json | 1 + src/compiler.js | 4 +- src/index.js | 2 +- test/sample/custom-tsconfig/main.ts | 4 +- test/sample/export-class/main.ts | 2 +- test/sample/jsx/main.tsx | 4 ++ test/sample/tslib-helpers/main.ts | 9 ++++ test/test.js | 83 ++++++++++++++++------------- 8 files changed, 66 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 6e33d92..1bee1bb 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "typescript": "^2.3.3" }, "devDependencies": { + "@types/react": "^15.0.24", "buble": "^0.13.1", "eslint": "^2.13.1", "mocha": "^3.0.0", diff --git a/src/compiler.js b/src/compiler.js index 4ce5239..9c056de 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -127,8 +127,8 @@ function init ( ts, compilerOpts, entry, useLanguageService ) { } } -function compileFile ( fileName, content, refreshFile ) { - return languageService +function compileFile ( fileName, content, refreshFile, useLanguageService ) { + return useLanguageService ? compileUsingLanguageService( fileName, content, refreshFile ) : compileUsingSimpleApi( fileName, content ); } diff --git a/src/index.js b/src/index.js index 46d7b3a..1ca2d17 100644 --- a/src/index.js +++ b/src/index.js @@ -131,7 +131,7 @@ export default function typescript ( options ) { code = fixExportClass( code, id ); } - const transformed = compiler.compileFile( id, code, !isFirstRun ); + const transformed = compiler.compileFile( id, code, !isFirstRun, useLanguageService ); // All errors except `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` const diagnostics = transformed.diagnostics ? diff --git a/test/sample/custom-tsconfig/main.ts b/test/sample/custom-tsconfig/main.ts index d0b587a..fb09e67 100644 --- a/test/sample/custom-tsconfig/main.ts +++ b/test/sample/custom-tsconfig/main.ts @@ -1,2 +1,2 @@ -const answer: number = 42; -console.log( `the answer is ${answer}` ); +const val: number = 42; +console.log( `the answer is ${val}` ); diff --git a/test/sample/export-class/main.ts b/test/sample/export-class/main.ts index d0f1179..f2c2bb7 100644 --- a/test/sample/export-class/main.ts +++ b/test/sample/export-class/main.ts @@ -1,3 +1,3 @@ -import {Foo} from './Foo.ts'; +import {Foo} from './Foo'; export default new Foo(); diff --git a/test/sample/jsx/main.tsx b/test/sample/jsx/main.tsx index 37ccc3c..09fc4aa 100644 --- a/test/sample/jsx/main.tsx +++ b/test/sample/jsx/main.tsx @@ -1 +1,5 @@ +import * as React from 'react'; + +const props = {}; + export default Yo! diff --git a/test/sample/tslib-helpers/main.ts b/test/sample/tslib-helpers/main.ts index 908125e..7097cbe 100644 --- a/test/sample/tslib-helpers/main.ts +++ b/test/sample/tslib-helpers/main.ts @@ -8,4 +8,13 @@ function* generateNumber() { const generator: IterableIterator = generateNumber(); generator.next(); +async function wait( n: number ) { + while ( --n ) { + await delay( 10 ); + } +} + +function delay ( interval: number ) { + return new Promise( resolve => setTimeout( resolve, interval ) ); +} // todo add more changes between our hardcoded helpers and the official tslib diff --git a/test/test.js b/test/test.js index 461d2fd..7aec3d0 100644 --- a/test/test.js +++ b/test/test.js @@ -1,10 +1,9 @@ +const path = require('path'); const assert = require( 'assert' ); const rollup = require( 'rollup' ); const assign = require( 'object-assign' ); const typescript = require( '..' ); -process.chdir( __dirname ); - // Evaluate a bundle (as CommonJS) and return its exports. function evaluate ( bundle ) { const module = { exports: {} }; @@ -26,7 +25,7 @@ describe( 'rollup-plugin-typescript', function () { this.timeout( 5000 ); it( 'runs code through typescript', () => { - return bundle( 'sample/basic/main.ts' ).then( bundle => { + return bundle( path.join( __dirname, 'sample/basic/main.ts' ) ).then( bundle => { const code = bundle.generate().code; assert.ok( code.indexOf( 'number' ) === -1, code ); @@ -35,17 +34,20 @@ describe( 'rollup-plugin-typescript', function () { }); it( 'ignores the declaration option', () => { - return bundle( 'sample/basic/main.ts', { declaration: true }); + return bundle( path.join( __dirname, 'sample/basic/main.ts' ), { declaration: true }); }); - it( 'handles async functions', () => { - return bundle( 'sample/async/main.ts' ) - .then( bundle => { - const wait = evaluate( bundle ); - - return wait( 3 ); - }); - }); + //// test moved to tslib test + // it( 'handles async functions', () => { + // return bundle( path.join( __dirname, 'sample/async/main.ts' ), { + // lib: [ 'ES5', 'ES2015', 'dom' ] + // }) + // .then( bundle => { + // const wait = evaluate( bundle ); + // + // return wait( 3 ); + // }); + // }); //// test removed as switching to tslib means that helpers are always deduped // it( 'does not duplicate helpers', () => { @@ -61,7 +63,7 @@ describe( 'rollup-plugin-typescript', function () { // }); it( 'transpiles `export class A` correctly', () => { - return bundle( 'sample/export-class-fix/main.ts' ).then( bundle => { + return bundle( path.join( __dirname, 'sample/export-class-fix/main.ts' ) ).then( bundle => { const code = bundle.generate().code; assert.equal( code.indexOf( 'class' ), -1, code ); @@ -71,18 +73,18 @@ describe( 'rollup-plugin-typescript', function () { }); }); - it( 'does not fix export class when targeting ES6', function () { - return bundle( 'sample/export-class-no-fix/main.ts', { + it( 'does not fix export class when targeting ES6', () => { + return bundle( path.join( __dirname, 'sample/export-class-no-fix/main.ts' ), { target: 'ES6' - }).then( function ( bundle ) { + }).then( bundle => { const code = bundle.generate().code; - assert.ok( code.indexOf( 'export default main' ) !== -1, code ); + assert.ok( code.indexOf( 'export default main' ) !== -1, code ); }); }); it( 'transpiles ES6 features to ES5 with source maps', () => { - return bundle( 'sample/import-class/main.ts' ).then( bundle => { + return bundle( path.join( __dirname, 'sample/import-class/main.ts' ) ).then( bundle => { const code = bundle.generate().code; assert.equal( code.indexOf( 'class' ), -1, code ); @@ -92,28 +94,29 @@ describe( 'rollup-plugin-typescript', function () { }); it( 'reports diagnostics and throws if errors occur during transpilation', () => { - return bundle( 'sample/syntax-error/missing-type.ts' ).catch( error => { + return bundle( path.join( __dirname, 'sample/syntax-error/missing-type.ts' ) ).catch( error => { assert.ok( error.message.indexOf( 'There were TypeScript errors transpiling' ) !== -1, 'Should reject erroneous code.' ); }); }); it( 'works with named exports for abstract classes', () => { - return bundle( 'sample/export-abstract-class/main.ts' ).then(bundle => { + return bundle( path.join( __dirname, 'sample/export-abstract-class/main.ts' ) ).then(bundle => { const code = bundle.generate().code; assert.ok( code.length > 0, code ); }); }); it( 'should use named exports for classes', () => { - return bundle( 'sample/export-class/main.ts' ).then( bundle => { + return bundle( path.join( __dirname, 'sample/export-class/main.ts' ) ).then( bundle => { assert.equal( evaluate( bundle ).foo, 'bar' ); }); }); it( 'supports overriding the TypeScript version', () => { - return bundle('sample/overriding-typescript/main.ts', { + return bundle( path.join( __dirname, 'sample/overriding-typescript/main.ts' ), { // Don't use `tsconfig.json` tsconfig: false, + useLanguageService: false, // test with a mocked version of TypeScript typescript: fakeTypescript({ @@ -135,8 +138,9 @@ describe( 'rollup-plugin-typescript', function () { describe( 'strictNullChecks', () => { it( 'is enabled for versions >= 1.9.0', () => { - return bundle( 'sample/overriding-typescript/main.ts', { + return bundle( path.join( __dirname, 'sample/overriding-typescript/main.ts' ), { tsconfig: false, + useLanguageService: false, strictNullChecks: true, typescript: fakeTypescript({ @@ -163,10 +167,11 @@ describe( 'rollup-plugin-typescript', function () { }; return rollup.rollup({ - entry: 'sample/overriding-typescript/main.ts', + entry: path.join( __dirname, 'sample/overriding-typescript/main.ts' ), plugins: [ typescript({ tsconfig: false, + useLanguageService: false, strictNullChecks: true, typescript: fakeTypescript({ @@ -180,14 +185,15 @@ describe( 'rollup-plugin-typescript', function () { }); }); - it( 'should not resolve .d.ts files', () => { - return bundle( 'sample/dts/main.ts' ).then( bundle => { - assert.deepEqual( bundle.imports, [ 'an-import' ] ); - }); - }); + //// todo find a better way to test this + // it( 'should not resolve .d.ts files', () => { + // return bundle( path.join( __dirname, 'sample/dts/main.ts' ) ).then( bundle => { + // assert.deepEqual( bundle.imports, [ 'an-import' ] ); + // }); + // }); it( 'should transpile JSX if enabled', () => { - return bundle( 'sample/jsx/main.tsx', { jsx: 'react' }).then( bundle => { + return bundle( path.join( __dirname, 'sample/jsx/main.tsx' ), { jsx: 'react' }).then( bundle => { const code = bundle.generate().code; //// assertion disabled since this is now handled by typescript @@ -209,13 +215,13 @@ describe( 'rollup-plugin-typescript', function () { }); it( 'prevents errors due to conflicting `sourceMap`/`inlineSourceMap` options', () => { - return bundle( 'sample/overriding-typescript/main.ts', { + return bundle( path.join( __dirname, 'sample/overriding-typescript/main.ts' ), { inlineSourceMap: true }); }); it ( 'should not fail if source maps are off', () => { - return bundle( 'sample/overriding-typescript/main.ts', { + return bundle( path.join( __dirname, 'sample/overriding-typescript/main.ts' ), { inlineSourceMap: false, sourceMap: false }); @@ -235,18 +241,21 @@ describe( 'rollup-plugin-typescript', function () { // }); it( 'supports tslib helpers', () => { - return bundle( 'sample/tslib-helpers/main.ts' ).then( bundle => { + return bundle( path.join( __dirname, 'sample/tslib-helpers/main.ts' ), { + target: 'ES5', + lib: [ 'ES5', 'ES2015.iterable', 'es2015.promise', 'dom' ] + }).then( bundle => { const code = bundle.generate().code; - assert.notEqual( code.indexOf( 'from \'tslib\'' ), -1, 'should import tslib' ); + assert.notEqual( code.indexOf( 'return __generator' ), -1, 'should import tslib' ); }); }); it( 'reads in custom tsconfig files', () => { - return bundle('sample/custom-tsconfig/main.ts', { - tsconfig: 'sample/custom-tsconfig/tsconfig.json' + return bundle(path.join( __dirname, 'sample/custom-tsconfig/main.ts' ), { + tsconfig: path.join( __dirname, 'sample/custom-tsconfig/tsconfig.json' ) }).then(bundle => { - assert.equal(bundle.modules[1].code.indexOf('const answer = 42'), 0); + assert.equal(bundle.modules[1].code.indexOf('const val = 42'), 0); }); }); }); From 05cc214866bdf2092c5c54261c45189416cf340e Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 15:16:42 -0500 Subject: [PATCH 13/16] Switch to repo convention that other rollup plugins use --- package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 1bee1bb..3f9f995 100644 --- a/package.json +++ b/package.json @@ -43,10 +43,7 @@ "rollup": "^0.34.3", "rollup-plugin-buble": "^0.13.0" }, - "repository": { - "type": "git", - "url": "git+https://github.com/rollup/rollup-plugin-typescript.git" - }, + "repository": "rollup/rollup-plugin-typescript", "bugs": { "url": "https://github.com/rollup/rollup-plugin-typescript/issues" } From c4d354a827ee448393b99b0bb2d379c96de50aa6 Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 15:18:52 -0500 Subject: [PATCH 14/16] Remove node version 0.12, as it's rather outdated --- .travis.yml | 1 - appveyor.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2e7fd10..52ad81f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,3 @@ language: node_js node_js: - "6" - "4" - - "0.12" diff --git a/appveyor.yml b/appveyor.yml index ff42894..66a227b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,6 @@ environment: matrix: - nodejs_version: "6" - nodejs_version: "4" - - nodejs_version: "0.12" version: "{build}" build: off From 8e83614cfc6a9633d0857d69f7c9b37019eb8c46 Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 16:01:42 -0500 Subject: [PATCH 15/16] Include .d.ts files --- src/compiler.js | 208 +++++++++++++++++++++++------------------------- src/index.js | 10 ++- 2 files changed, 106 insertions(+), 112 deletions(-) diff --git a/src/compiler.js b/src/compiler.js index 9c056de..ac87c56 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -1,140 +1,132 @@ import * as fs from 'fs'; import compareVersions from 'compare-versions'; -const fileCache = new Map(); -const tsFiles = new Set(); - -let typescript = undefined; -let compilerOptions = undefined; -let entryFile = undefined; -let languageService = undefined; - - -function getFile (fileName) { - let file = fileCache.get( fileName ); - - if ( file === undefined ) { - const version = Date.now().toString(); - - if ( !fs.existsSync( fileName ) ) { - file = { - snapshot: undefined, - version - }; - } else { - file = { - snapshot: typescript.ScriptSnapshot.fromString( fs.readFileSync( fileName ).toString() ), - version - }; - } +export default function createCompiler ( ts, compilerOpts, entry, useLanguageService ) { + const typescript = ts; + const compilerOptions = compilerOpts; + const entryFile = entry; + let languageService = undefined; - fileCache.set( fileName, file ); - } + const fileCache = new Map(); + const tsFiles = new Set(); - return file; -} + tsFiles.add( entryFile ); -function setFileContent ( fileName, content, override ) { - if (!override && fileCache.get( fileName )) { - return; + if ( useLanguageService ) { + initLanguageService(); } - tsFiles.add( fileName ); + function getFile (fileName) { + let file = fileCache.get( fileName ); + + if ( file === undefined ) { + const version = Date.now().toString(); + + if ( !fs.existsSync( fileName ) ) { + file = { + snapshot: undefined, + version + }; + } else { + file = { + snapshot: typescript.ScriptSnapshot.fromString( fs.readFileSync( fileName ).toString() ), + version + }; + } + + fileCache.set( fileName, file ); + } - fileCache.set( fileName, { - snapshot: typescript.ScriptSnapshot.fromString( content ), - version: Date.now().toString() - }); -} + return file; + } -function initLanguageService () { - if (languageService) return; + function setFileContent ( fileName, content, override ) { + if (!override && fileCache.get( fileName )) { + return; + } - fixTypeLookup(); + tsFiles.add( fileName ); - const languageServiceHost = { - getScriptFileNames: () => Array.from( tsFiles ), - getScriptVersion: ( fileName ) => getFile( fileName ).version, - getScriptSnapshot: (fileName) => getFile( fileName ).snapshot, - getCurrentDirectory: () => process.cwd(), - getCompilationSettings: () => compilerOptions, - getDefaultLibFileName: ( options ) => typescript.getDefaultLibFilePath( options ) - }; + fileCache.set( fileName, { + snapshot: typescript.ScriptSnapshot.fromString( content ), + version: Date.now().toString() + }); + } - languageService = typescript.createLanguageService( languageServiceHost, typescript.createDocumentRegistry() ); -} + function initLanguageService () { + if (languageService) return; -/** - * Workaround for the LanguageService not finding typings in node_modules/@types: - * Manually set the "types" option to the folder names in node_modules/@types - */ -function fixTypeLookup () { - if ( compilerOptions.types || compilerOptions.typeRoots ) return; + fixTypeLookup(); - if ( compareVersions( typescript.version, '2.0.0' ) < 0 ) { - return; - } + const languageServiceHost = { + getScriptFileNames: () => Array.from( tsFiles ), + getScriptVersion: ( fileName ) => getFile( fileName ).version, + getScriptSnapshot: (fileName) => getFile( fileName ).snapshot, + getCurrentDirectory: () => process.cwd(), + getCompilationSettings: () => compilerOptions, + getDefaultLibFileName: ( options ) => typescript.getDefaultLibFilePath( options ) + }; - if ( fs.existsSync( './node_modules/@types' ) ) { - compilerOptions.types = fs.readdirSync('./node_modules/@types'); + languageService = typescript.createLanguageService( languageServiceHost, typescript.createDocumentRegistry() ); } -} + /** + * Workaround for the LanguageService not finding typings in node_modules/@types: + * Manually set the "types" option to the folder names in node_modules/@types + */ + function fixTypeLookup () { + if ( compilerOptions.types || compilerOptions.typeRoots ) return; -function compileUsingLanguageService ( fileName, content, refreshFile ) { - setFileContent( fileName, content, refreshFile ); + if ( compareVersions( typescript.version, '2.0.0' ) < 0 ) { + return; + } - const result = { - outputText: undefined, - diagnostics: undefined, - sourceMapText: undefined - }; + if ( fs.existsSync( './node_modules/@types' ) ) { + compilerOptions.types = fs.readdirSync('./node_modules/@types'); + } + } - const compiled = languageService.getEmitOutput( fileName ); - result.diagnostics = languageService.getCompilerOptionsDiagnostics() - .concat( languageService.getSyntacticDiagnostics( fileName ) ) - .concat( languageService.getSemanticDiagnostics( fileName ) ); + function compileUsingLanguageService ( fileName, content, refreshFile ) { + setFileContent( fileName, content, refreshFile ); - compiled.outputFiles.forEach( outputFile => { - if ( outputFile.name.slice( -3 ) === '.js' ) { - result.outputText = outputFile.text; - } else if ( outputFile.name.slice( -4 ) === '.map' ) { - result.sourceMapText = outputFile.text; - } - }); + const result = { + outputText: undefined, + diagnostics: undefined, + sourceMapText: undefined + }; - return result; -} + const compiled = languageService.getEmitOutput( fileName ); -function compileUsingSimpleApi ( fileName, content ) { - return typescript.transpileModule( content, { - fileName, - reportDiagnostics: true, - compilerOptions - }); -} + result.diagnostics = languageService.getCompilerOptionsDiagnostics() + .concat( languageService.getSyntacticDiagnostics( fileName ) ) + .concat( languageService.getSemanticDiagnostics( fileName ) ); -function init ( ts, compilerOpts, entry, useLanguageService ) { - typescript = ts; - compilerOptions = compilerOpts; - entryFile = entry; + compiled.outputFiles.forEach( outputFile => { + if ( outputFile.name.slice( -3 ) === '.js' ) { + result.outputText = outputFile.text; + } else if ( outputFile.name.slice( -4 ) === '.map' ) { + result.sourceMapText = outputFile.text; + } + }); - tsFiles.add( entryFile ); + return result; + } - if ( useLanguageService ) { - initLanguageService(); + function compileUsingSimpleApi ( fileName, content ) { + return typescript.transpileModule( content, { + fileName, + reportDiagnostics: true, + compilerOptions + }); } -} -function compileFile ( fileName, content, refreshFile, useLanguageService ) { - return useLanguageService - ? compileUsingLanguageService( fileName, content, refreshFile ) - : compileUsingSimpleApi( fileName, content ); -} + function compileFile ( fileName, content, refreshFile ) { + return languageService + ? compileUsingLanguageService( fileName, content, refreshFile ) + : compileUsingSimpleApi( fileName, content ); + } + return { compileFile }; +} -export default { - init, - compileFile -}; diff --git a/src/index.js b/src/index.js index 1ca2d17..6b2e9ae 100644 --- a/src/index.js +++ b/src/index.js @@ -9,7 +9,7 @@ import { endsWith } from './string'; import { getDefaultOptions, compilerOptionsFromTsConfig, adjustCompilerOptions } from './options.js'; import fixExportClass from './fixExportClass'; import resolveHost from './resolveHost'; -import compiler from './compiler'; +import createCompiler from './compiler'; /* interface Options { @@ -30,7 +30,7 @@ export default function typescript ( options ) { const filter = createFilter( options.include || [ '*.ts+(|x)', '**/*.ts+(|x)' ], - options.exclude || [ '*.d.ts', '**/*.d.ts' ] ); + options.exclude || [] ); //|| [ '*.d.ts', '**/*.d.ts' ] ); delete options.include; delete options.exclude; @@ -82,10 +82,12 @@ export default function typescript ( options ) { const isVersionOne = compareVersions( typescript.version, '2.0.0' ) >= 0; let isFirstRun = true; + let compiler; + return { options (opts) { const entryFile = path.resolve(process.cwd(), opts.entry); - compiler.init(typescript, compilerOptions, entryFile, useLanguageService); + compiler = createCompiler( typescript, compilerOptions, entryFile, useLanguageService ); }, resolveId ( importee, importer ) { @@ -131,7 +133,7 @@ export default function typescript ( options ) { code = fixExportClass( code, id ); } - const transformed = compiler.compileFile( id, code, !isFirstRun, useLanguageService ); + const transformed = compiler.compileFile( id, code, !isFirstRun ); // All errors except `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` const diagnostics = transformed.diagnostics ? From 6d6368a8a71dbf702b8516da066fcc9294659aad Mon Sep 17 00:00:00 2001 From: Paul Sauve Date: Tue, 23 May 2017 16:17:35 -0500 Subject: [PATCH 16/16] Automatically include .d.ts files found in the project --- .gitignore | 1 + src/index.js | 21 ++++++++++++++++++- test/sample/includes-definitions/main.ts | 1 + test/sample/includes-definitions/somedef.d.ts | 3 +++ test/test.js | 6 ++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/sample/includes-definitions/main.ts create mode 100644 test/sample/includes-definitions/somedef.d.ts diff --git a/.gitignore b/.gitignore index 514b40a..355d67e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /node_modules dist +npm-debug.log \ No newline at end of file diff --git a/src/index.js b/src/index.js index 6b2e9ae..f058a88 100644 --- a/src/index.js +++ b/src/index.js @@ -30,7 +30,7 @@ export default function typescript ( options ) { const filter = createFilter( options.include || [ '*.ts+(|x)', '**/*.ts+(|x)' ], - options.exclude || [] ); //|| [ '*.d.ts', '**/*.d.ts' ] ); + options.exclude || [ '*.d.ts', '**/*.d.ts' ] ); delete options.include; delete options.exclude; @@ -88,6 +88,25 @@ export default function typescript ( options ) { options (opts) { const entryFile = path.resolve(process.cwd(), opts.entry); compiler = createCompiler( typescript, compilerOptions, entryFile, useLanguageService ); + + const definitionsFilter = createFilter( + [ '*.d.ts', '**/*.d.ts' ], + [ 'node_modules/**' ] ); + + function read (dir, parent) { + dir.forEach(file => { + file = path.join(parent, file); + const stats = fs.statSync(file); + if (stats.isFile() && file.indexOf('.d.ts') > -1) { + if (definitionsFilter(file)) { + compiler.compileFile(file, fs.readFileSync(file, 'utf8'), false); + } + } else if (stats.isDirectory()) { + read(fs.readdirSync(file), file); + } + }); + } + read(fs.readdirSync(process.cwd()), process.cwd()); }, resolveId ( importee, importer ) { diff --git a/test/sample/includes-definitions/main.ts b/test/sample/includes-definitions/main.ts new file mode 100644 index 0000000..1be7d15 --- /dev/null +++ b/test/sample/includes-definitions/main.ts @@ -0,0 +1 @@ +new SomeClass(0); \ No newline at end of file diff --git a/test/sample/includes-definitions/somedef.d.ts b/test/sample/includes-definitions/somedef.d.ts new file mode 100644 index 0000000..97d6d78 --- /dev/null +++ b/test/sample/includes-definitions/somedef.d.ts @@ -0,0 +1,3 @@ +declare class SomeClass { + constructor(num: number); +} \ No newline at end of file diff --git a/test/test.js b/test/test.js index 7aec3d0..2d58bb1 100644 --- a/test/test.js +++ b/test/test.js @@ -258,6 +258,12 @@ describe( 'rollup-plugin-typescript', function () { assert.equal(bundle.modules[1].code.indexOf('const val = 42'), 0); }); }); + + it( 'automatically includes .d.ts files', () => { + return bundle( path.join( __dirname, 'sample/includes-definitions/main.ts' ) ).then(bundle => { + assert.ok(bundle.generate().code.length > 0, 'code is generated'); + }); + }); }); function fakeTypescript ( custom ) {