From d6f988c8db286e5a4218fb78aee0c76c21f56c57 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Mon, 2 Dec 2019 15:59:35 -0800 Subject: [PATCH] chore: migrate rollup-plugin-typescript (#59) * chore: migrate rollup-plugin-typescript * feat: add support for tsconfig with extendsCo-authored-by: Tobias Lundin * chore: Update README for typescript plugin --- .../test/fixtures/yarn-bare/package.json | 1 + .../test/fixtures/yarn/package.json | 1 + packages/typescript/CHANGELOG.md | 111 +++++ packages/typescript/README.md | 145 +++++++ packages/typescript/index.d.ts | 45 ++ packages/typescript/package.json | 74 ++++ packages/typescript/rollup.config.js | 21 + packages/typescript/src/index.js | 177 ++++++++ packages/typescript/src/options.js | 71 ++++ packages/typescript/src/resolveHost.js | 18 + packages/typescript/src/string.js | 3 + .../typescript/test/fixtures/assign/main.ts | 7 + .../typescript/test/fixtures/async/main.ts | 9 + .../typescript/test/fixtures/basic/main.ts | 2 + .../test/fixtures/commonjs-imports/cjs.js | 1 + .../test/fixtures/commonjs-imports/main.ts | 3 + .../test/fixtures/dedup-helpers/A.ts | 2 + .../test/fixtures/dedup-helpers/B.ts | 2 + .../test/fixtures/dedup-helpers/Base.ts | 1 + .../test/fixtures/dedup-helpers/main.ts | 2 + packages/typescript/test/fixtures/dts/main.ts | 3 + .../test/fixtures/dynamic-imports/dynamic.ts | 2 + .../test/fixtures/dynamic-imports/main.ts | 1 + .../fixtures/export-abstract-class/main.ts | 1 + .../test/fixtures/export-class-fix/default.ts | 3 + .../test/fixtures/export-class-fix/main.ts | 4 + .../test/fixtures/export-class-fix/named.ts | 2 + .../test/fixtures/export-class/Foo.ts | 3 + .../test/fixtures/export-class/main.ts | 3 + .../test/fixtures/export-fodule/main.ts | 6 + .../export-namespace-export-class/test.ts | 7 + .../test/fixtures/import-class/A.ts | 9 + .../test/fixtures/import-class/main.ts | 3 + .../typescript/test/fixtures/jsx/main.tsx | 1 + .../test/fixtures/overriding-tslib/main.ts | 7 + .../fixtures/overriding-typescript/main.ts | 1 + .../fixtures/syntax-error/missing-type.ts | 1 + .../test/fixtures/tsconfig-extends/main.tsx | 1 + .../tsconfig-extends/tsconfig.base.json | 5 + .../fixtures/tsconfig-extends/tsconfig.json | 6 + .../test/fixtures/tsconfig-jsx/main.tsx | 1 + .../test/fixtures/tsconfig-jsx/tsconfig.json | 5 + packages/typescript/test/test.js | 393 ++++++++++++++++++ packages/typescript/tsconfig.json | 16 + packages/typescript/typings-test.js | 21 + pnpm-lock.yaml | 36 ++ util/test.js | 9 + 47 files changed, 1246 insertions(+) create mode 100644 packages/auto-install/test/fixtures/yarn-bare/package.json create mode 100644 packages/auto-install/test/fixtures/yarn/package.json create mode 100644 packages/typescript/CHANGELOG.md create mode 100644 packages/typescript/README.md create mode 100644 packages/typescript/index.d.ts create mode 100644 packages/typescript/package.json create mode 100644 packages/typescript/rollup.config.js create mode 100644 packages/typescript/src/index.js create mode 100644 packages/typescript/src/options.js create mode 100644 packages/typescript/src/resolveHost.js create mode 100644 packages/typescript/src/string.js create mode 100644 packages/typescript/test/fixtures/assign/main.ts create mode 100644 packages/typescript/test/fixtures/async/main.ts create mode 100644 packages/typescript/test/fixtures/basic/main.ts create mode 100644 packages/typescript/test/fixtures/commonjs-imports/cjs.js create mode 100644 packages/typescript/test/fixtures/commonjs-imports/main.ts create mode 100644 packages/typescript/test/fixtures/dedup-helpers/A.ts create mode 100644 packages/typescript/test/fixtures/dedup-helpers/B.ts create mode 100644 packages/typescript/test/fixtures/dedup-helpers/Base.ts create mode 100644 packages/typescript/test/fixtures/dedup-helpers/main.ts create mode 100644 packages/typescript/test/fixtures/dts/main.ts create mode 100644 packages/typescript/test/fixtures/dynamic-imports/dynamic.ts create mode 100644 packages/typescript/test/fixtures/dynamic-imports/main.ts create mode 100644 packages/typescript/test/fixtures/export-abstract-class/main.ts create mode 100644 packages/typescript/test/fixtures/export-class-fix/default.ts create mode 100644 packages/typescript/test/fixtures/export-class-fix/main.ts create mode 100644 packages/typescript/test/fixtures/export-class-fix/named.ts create mode 100644 packages/typescript/test/fixtures/export-class/Foo.ts create mode 100644 packages/typescript/test/fixtures/export-class/main.ts create mode 100644 packages/typescript/test/fixtures/export-fodule/main.ts create mode 100644 packages/typescript/test/fixtures/export-namespace-export-class/test.ts create mode 100644 packages/typescript/test/fixtures/import-class/A.ts create mode 100644 packages/typescript/test/fixtures/import-class/main.ts create mode 100644 packages/typescript/test/fixtures/jsx/main.tsx create mode 100644 packages/typescript/test/fixtures/overriding-tslib/main.ts create mode 100644 packages/typescript/test/fixtures/overriding-typescript/main.ts create mode 100644 packages/typescript/test/fixtures/syntax-error/missing-type.ts create mode 100644 packages/typescript/test/fixtures/tsconfig-extends/main.tsx create mode 100644 packages/typescript/test/fixtures/tsconfig-extends/tsconfig.base.json create mode 100644 packages/typescript/test/fixtures/tsconfig-extends/tsconfig.json create mode 100644 packages/typescript/test/fixtures/tsconfig-jsx/main.tsx create mode 100644 packages/typescript/test/fixtures/tsconfig-jsx/tsconfig.json create mode 100644 packages/typescript/test/test.js create mode 100644 packages/typescript/tsconfig.json create mode 100644 packages/typescript/typings-test.js diff --git a/packages/auto-install/test/fixtures/yarn-bare/package.json b/packages/auto-install/test/fixtures/yarn-bare/package.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/packages/auto-install/test/fixtures/yarn-bare/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/auto-install/test/fixtures/yarn/package.json b/packages/auto-install/test/fixtures/yarn/package.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/packages/auto-install/test/fixtures/yarn/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/typescript/CHANGELOG.md b/packages/typescript/CHANGELOG.md new file mode 100644 index 000000000..e94103a82 --- /dev/null +++ b/packages/typescript/CHANGELOG.md @@ -0,0 +1,111 @@ +# @rollup/plugin-typescript changelog + +## 2.0.0 + +_2019-11-25_ + +- **Breaking:** Minimum compatible Rollup version is 1.2.0 +- **Breaking:** Minimum supported Node version is 8.0.0 +- Published as @rollup/plugin-typescript + +## 1.0.1 + +_2019-03-24_ + +- Update dependencies ([#136](https://github.com/rollup/rollup-plugin-typescript/issues/136)) + +## 1.0.0 + +_2018-09-16_ + +- Major update for TypeScript 2/3, Rollup 1 compatibility, lots of fixes ([#124](https://github.com/rollup/rollup-plugin-typescript/issues/124)) +- Require TypeScript as peer dependency ([#121](https://github.com/rollup/rollup-plugin-typescript/issues/121)) +- Also test on Node 10 ([#119](https://github.com/rollup/rollup-plugin-typescript/issues/119)) +- Fix example in readme ([#98](https://github.com/rollup/rollup-plugin-typescript/issues/98)) + +## 0.8.1 + +- Ignore typescript-helpers in source maps ([#61](https://github.com/rollup/rollup-plugin-typescript/issues/61)) + +## 0.8.0 + +- Fix the rollup breaking change with paths ([#52](https://github.com/rollup/rollup-plugin-typescript/issues/52)) +- Don't fail without source maps ([#57](https://github.com/rollup/rollup-plugin-typescript/pull/57)) + +## 0.7.7 + +- Add missing `__assign` helper ([#49](https://github.com/rollup/rollup-plugin-typescript/issues/49)) + +## 0.7.6 + +- Ignore the `declaration` option ([#45](https://github.com/rollup/rollup-plugin-typescript/issues/45)) +- Disable `strictNullChecks` with a warning for TypeScript versions that don't support it ([#46](https://github.com/rollup/rollup-plugin-typescript/issues/46)) + +## 0.7.5 + +- Ensure NPM doesn't ignore typescript-helpers + +## 0.7.4 + +- Resolve typescript-helpers to a file in the filesystem. + +## 0.7.3 + +- Update Tippex to ^2.1.1 + +## 0.7.2 + +- Don't error if both `sourceMap` and `inlineSourceMap` are specified + +## 0.7.1 + +- No plugin specific options should be forwarded to TypeScript + +## 0.7.0 + +- Use `compilerOptions` from `tsconfig.json` if found ([#39](https://github.com/rollup/rollup-plugin-typescript/pull/32)) + +## 0.6.1 + +- Upgrade Tippex to ^2.1.0 +- Upgrade TypeScript to ^1.8.9 + +## 0.6.0 + +- Upgrade to TypeScript ^1.8.7 +- Update `__awaiter` helper to support TypeScript 1.8.x ([#32](https://github.com/rollup/rollup-plugin-typescript/pull/32)) +- Update `ts.nodeModuleNameResolver` to support both 1.7.x and 1.8.x ([#31](https://github.com/rollup/rollup-plugin-typescript/issues/31)) + +## 0.5.0 + +- Do not duplicate TypeScript's helpers ([#24](https://github.com/rollup/rollup-plugin-typescript/issues/24)) +- Handle `export abstract class` ([#23](https://github.com/rollup/rollup-plugin-typescript/issues/23)) + +## 0.4.1 + +- Does not attempt resolve or transform `.d.ts` files ([#22](https://github.com/rollup/rollup-plugin-typescript/pull/22)) + +## 0.4.0 + +- Work around TypeScript 1.7.5's transpilation issues ([#9](https://github.com/rollup/rollup-plugin-typescript/issues/9)) +- Overridable TypeScript version when transpiling ([#4](https://github.com/rollup/rollup-plugin-typescript/issues/4)) +- Add `jsx` support ([#11](https://github.com/rollup/rollup-plugin-typescript/issues/11)) + +## 0.3.0 + +- Author plugin in TypeScript +- Report diagnostics +- Resolve identifiers using `ts.nodeModuleNameResolver` + +## 0.2.1 + +- Upgrade to TypeScript ^1.7.5 +- Enable source maps per default + +## 0.2.0 + +- Use (_prerelease version of_) TypeScript 1.7.0 to generate ES5 while preserving ES2015 imports for efficient bundling. + +## 0.1.0 + +- Initial release diff --git a/packages/typescript/README.md b/packages/typescript/README.md new file mode 100644 index 000000000..b77c86830 --- /dev/null +++ b/packages/typescript/README.md @@ -0,0 +1,145 @@ +[npm]: https://img.shields.io/npm/v/@rollup/plugin-typescript +[npm-url]: https://www.npmjs.com/package/@rollup/plugin-typescript +[size]: https://packagephobia.now.sh/badge?p=@rollup/plugin-typescript +[size-url]: https://packagephobia.now.sh/result?p=@rollup/plugin-typescript + +[![npm][npm]][npm-url] +[![size][size]][size-url] +[![libera manifesto](https://img.shields.io/badge/libera-manifesto-lightgrey.svg)](https://liberamanifesto.com) + +# @rollup/plugin-typescript + +🍣 A Rollup plugin for seamless integration between Rollup and Typescript. + +## Requirements + +This plugin requires an [LTS](https://github.com/nodejs/Release) Node version (v8.0.0+) and Rollup v1.20.0+. Due to the use of `tslib` to inject helpers, this plugin requires at least [TypeScript 2.1](https://github.com/Microsoft/TypeScript/wiki/Roadmap#21-december-2016). See also [here](https://blog.mariusschulz.com/2016/12/16/typescript-2-1-external-helpers-library#the-importhelpers-flag-and-tslib). + +## Install + +Using npm: + +```console +npm install @rollup/plugin-typescript --save-dev +``` + +Note that both `typescript` and `tslib` are peer dependencies of this plugin that need to be installed separately. + +## Why? + +See [rollup-plugin-babel](https://github.com/rollup/rollup-plugin-babel). + +## Usage + +Create a `rollup.config.js` [configuration file](https://www.rollupjs.org/guide/en/#configuration-files) and import the plugin: + +```js +// rollup.config.js +import typescript from '@rollup/plugin-typescript'; + +export default { + input: 'src/index.ts', + output: { + dir: 'output', + format: 'cjs' + }, + plugins: [typescript()] +}; +``` + +Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#command-line-reference) or the [API](https://www.rollupjs.org/guide/en/#javascript-api). + +## Options + +The plugin loads any [`compilerOptions`](http://www.typescriptlang.org/docs/handbook/compiler-options.html) from the `tsconfig.json` file by default. Passing options to the plugin directly overrides those options: + +```js +... +export default { + input: './main.ts', + plugins: [ + typescript({lib: ["es5", "es6", "dom"], target: "es5"}) + ] +} +``` + +The following options are unique to `rollup-plugin-typescript`: + +### `exclude` + +Type: `String` | `Array[...String]` +Default: `null` + +A [minimatch pattern](https://github.com/isaacs/minimatch), or array of patterns, which specifies the files in the build the plugin should _ignore_. By default no files are ignored. + +### `include` + +Type: `String` | `Array(String)` +Default: `null` + +A [minimatch pattern](https://github.com/isaacs/minimatch), or array of patterns, which specifies the files in the build the plugin should operate on. By default all `.ts` and `.tsx` files are targeted. + +### `tsconfig` + +Type: `String` | `Boolean` +Default: `true` + +When set to false, ignores any options specified in the config file. If set to a string that corresponds to a file path, the specified file will be used as config file. + +### `typescript` + +Type: `import('typescript')` +Default: _peer dependency_ + +Overrides the TypeScript module used for transpilation. + +```js +typescript({ + typescript: require('some-fork-of-typescript') +}); +``` + +### `tslib` + +Type: `import('tslib')` +Default: _peer dependency_ + +Overrides the injected TypeScript helpers with a custom version + +```js +typescript({ + tslib: require('some-fork-of-tslib') +}); +``` + +### Importing CommonJS + +Though it is not recommended, it is possible to configure this plugin to handle imports of CommonJS files from TypeScript. For this, you need to specify `CommonJS` as the module format and add `rollup-plugin-commonjs` to transpile the CommonJS output generated by TypeScript to ES Modules so that rollup can process it. + +```js +// rollup.config.js +import typescript from 'rollup-plugin-typescript'; +import commonjs from 'rollup-plugin-commonjs'; + +export default { + input: './main.ts', + plugins: [ + typescript({ module: 'CommonJS' }), + commonjs({ extensions: ['.js', '.ts'] }) // the ".ts" extension is required + ] +}; +``` + +Note that this will often result in less optimal output. + +## Issues + +This plugin will currently **not warn for any type violations**. This plugin relies on TypeScript's [transpileModule](https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#a-simple-transform-function) function which basically transpiles TypeScript to JavaScript by stripping any type information on a per-file basis. While this is faster than using the language service, no cross-file type checks are possible with this approach. + +This also causes issues with emit-less types, see [rollup/rollup-plugin-typescript#28](https://github.com/rollup/rollup-plugin-typescript/issues/28). + +## Meta + +[CONTRIBUTING](/.github/CONTRIBUTING.md) + +[LICENSE (MIT)](/LICENSE) diff --git a/packages/typescript/index.d.ts b/packages/typescript/index.d.ts new file mode 100644 index 000000000..90623a117 --- /dev/null +++ b/packages/typescript/index.d.ts @@ -0,0 +1,45 @@ +import { Plugin } from 'rollup'; +import { CompilerOptionsValue, TsConfigSourceFile } from 'typescript'; + +interface RollupTypescriptOptions { + /** + * Determine which files are transpiled by Typescript (all `.ts` and + * `.tsx` files by default). + */ + include?: string | RegExp | ReadonlyArray | null; + /** + * Determine which files are transpiled by Typescript (all `.ts` and + * `.tsx` files by default). + */ + exclude?: string | RegExp | ReadonlyArray | null; + /** + * When set to false, ignores any options specified in the config file. + * If set to a string that corresponds to a file path, the specified file + * will be used as config file. + */ + tsconfig?: string | false; + /** + * Overrides TypeScript used for transpilation + */ + typescript?: typeof import('typescript'); + /** + * Overrides the injected TypeScript helpers with a custom version + */ + tslib?: typeof import('tslib'); + + /** + * Other Typescript compiler options + */ + [option: string]: + | CompilerOptionsValue + | TsConfigSourceFile + | RollupTypescriptOptions['include'] + | RollupTypescriptOptions['typescript'] + | RollupTypescriptOptions['tslib'] + | undefined; +} + +/** + * Seamless integration between Rollup and Typescript. + */ +export default function typescript(options?: RollupTypescriptOptions): Plugin; diff --git a/packages/typescript/package.json b/packages/typescript/package.json new file mode 100644 index 000000000..7d3e451c2 --- /dev/null +++ b/packages/typescript/package.json @@ -0,0 +1,74 @@ +{ + "name": "@rollup/plugin-typescript", + "version": "2.0.0", + "publishConfig": { + "access": "public" + }, + "description": "Seamless integration between Rollup and TypeScript.", + "license": "MIT", + "repository": "rollup/plugins", + "author": "Oskar Segersvärd", + "homepage": "https://github.com/rollup/plugins/packages/typescript/#readme", + "bugs": "https://github.com/rollup/plugins/issues", + "main": "dist/index.js", + "engines": { + "node": ">=8.0.0" + }, + "scripts": { + "build": "rollup -c", + "ci:coverage": "nyc pnpm run test && nyc report --reporter=text-lcov > coverage.lcov", + "ci:lint": "pnpm run build && pnpm run lint && pnpm run security", + "ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}", + "ci:test": "pnpm run test -- --verbose", + "lint": "pnpm run lint:js && pnpm run lint:docs && pnpm run lint:package", + "lint:docs": "prettier --single-quote --write README.md", + "lint:js": "eslint --fix --cache src test", + "lint:package": "prettier --write package.json --plugin=prettier-plugin-package", + "prebuild": "del-cli dist", + "prepare": "pnpm run build", + "prepublishOnly": "pnpm run lint", + "pretest": "pnpm run build", + "security": "echo 'pnpm needs `npm audit` support'", + "test": "ava" + }, + "files": [ + "dist", + "index.d.ts", + "README.md", + "LICENSE" + ], + "keywords": [ + "rollup", + "plugin", + "typescript", + "es2015" + ], + "peerDependencies": { + "rollup": "^1.20.0", + "tslib": "*", + "typescript": ">=2.1.0" + }, + "dependencies": { + "@rollup/pluginutils": "^3.0.0", + "resolve": "^1.12.2" + }, + "devDependencies": { + "@rollup/plugin-buble": "^0.20.0", + "buble": "^0.19.8", + "rollup": "^1.27.5", + "rollup-plugin-commonjs": "^9.3.4", + "tslib": "^1.10.0", + "typescript": "^3.7.2" + }, + "ava": { + "files": [ + "!**/fixtures/**", + "!**/output/**", + "!**/helpers/**", + "!**/recipes/**", + "!**/types.ts" + ] + }, + "jsnext:main": "dist/index.es.js", + "module": "dist/index.es.js" +} diff --git a/packages/typescript/rollup.config.js b/packages/typescript/rollup.config.js new file mode 100644 index 000000000..4d5743535 --- /dev/null +++ b/packages/typescript/rollup.config.js @@ -0,0 +1,21 @@ +import buble from '@rollup/plugin-buble'; + +import pkg from './package.json'; + +const external = Object.keys(pkg.dependencies).concat(['path', 'fs', 'typescript']); + +export default { + input: "src/index.js", + plugins: [buble()], + external, + output: [ + { + format: "cjs", + file: pkg.main + }, + { + format: "es", + file: pkg.module + } + ] +}; diff --git a/packages/typescript/src/index.js b/packages/typescript/src/index.js new file mode 100644 index 000000000..26ea13816 --- /dev/null +++ b/packages/typescript/src/index.js @@ -0,0 +1,177 @@ +import * as fs from 'fs'; + +import * as ts from 'typescript'; +import { createFilter } from 'rollup-pluginutils'; +import resolveId from 'resolve'; + +import endsWith from './string'; +import { getDefaultOptions, readTsConfig, adjustCompilerOptions } from './options'; +import resolveHost from './resolveHost'; + +const TSLIB_ID = '\0tslib'; + +export default function typescript(options = {}) { + let opts = Object.assign({}, options); + + const filter = createFilter( + opts.include || ['*.ts+(|x)', '**/*.ts+(|x)'], + opts.exclude || ['*.d.ts', '**/*.d.ts'] + ); + + delete opts.include; + delete opts.exclude; + + // Allow users to override the TypeScript version used for transpilation and tslib version used for helpers. + const tsRuntime = opts.typescript || ts; + const tslib = + opts.tslib || + fs.readFileSync(resolveId.sync('tslib/tslib.es6.js', { basedir: __dirname }), 'utf-8'); + + delete opts.typescript; + delete opts.tslib; + + // Load options from `tsconfig.json` unless explicitly asked not to. + const tsConfig = + opts.tsconfig === false + ? { compilerOptions: {} } + : readTsConfig(tsRuntime, opts.tsconfig); + + delete opts.tsconfig; + + // Since the CompilerOptions aren't designed for the Rollup + // use case, we'll adjust them for use with Rollup. + tsConfig.compilerOptions = adjustCompilerOptions(tsRuntime, tsConfig.compilerOptions); + opts = adjustCompilerOptions(tsRuntime, opts); + + opts = Object.assign(tsConfig.compilerOptions, getDefaultOptions(), opts); + + // Verify that we're targeting ES2015 modules. + const moduleType = opts.module.toUpperCase(); + if ( + moduleType !== 'ES2015' && + moduleType !== 'ES6' && + moduleType !== 'ESNEXT' && + moduleType !== 'COMMONJS' + ) { + throw new Error( + `@rollup/plugin-typescript: The module kind should be 'ES2015' or 'ESNext, found: '${opts.module}'` + ); + } + + const parsed = tsRuntime.convertCompilerOptionsFromJson(opts, process.cwd()); + + if (parsed.errors.length) { + parsed.errors.forEach((error) => + // eslint-disable-next-line + console.error(`@rollup/plugin-typescript: ${error.messageText}`) + ); + + throw new Error(`@rollup/plugin-typescript: Couldn't process compiler options`); + } + + // let typescript load inheritance chain if there are base configs + const extendedConfig = tsConfig.extends + ? tsRuntime.parseJsonConfigFileContent(tsConfig, tsRuntime.sys, process.cwd(), parsed.options) + : null; + + if (extendedConfig && extendedConfig.errors.length) { + extendedConfig.errors.forEach((error) => + // eslint-disable-next-line + console.error(`@rollup/plugin-typescript: ${error.messageText}`) + ); + + throw new Error(`@rollup/plugin-typescript: Couldn't process compiler options`); + } + + const compilerOptions = extendedConfig ? extendedConfig.options : parsed.options; + + return { + name: 'typescript', + + resolveId(importee, importer) { + if (importee === 'tslib') { + return TSLIB_ID; + } + + if (!importer) return null; + const containingFile = importer.split('\\').join('/'); + + const result = tsRuntime.nodeModuleNameResolver( + importee, + containingFile, + compilerOptions, + resolveHost + ); + + if (result.resolvedModule && result.resolvedModule.resolvedFileName) { + if (endsWith(result.resolvedModule.resolvedFileName, '.d.ts')) { + return null; + } + + return result.resolvedModule.resolvedFileName; + } + + return null; + }, + + load(id) { + if (id === TSLIB_ID) { + return tslib; + } + return null; + }, + + transform(code, id) { + if (!filter(id)) return null; + + const transformed = tsRuntime.transpileModule(code, { + fileName: id, + reportDiagnostics: true, + compilerOptions + }); + + // All errors except `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` + const diagnostics = transformed.diagnostics + ? transformed.diagnostics.filter((diagnostic) => diagnostic.code !== 1204) + : []; + + let fatalError = false; + + diagnostics.forEach((diagnostic) => { + const message = tsRuntime.flattenDiagnosticMessageText( + diagnostic.messageText, + '\n' + ); + + if (diagnostic.file) { + const { line, character } = diagnostic.file.getLineAndCharacterOfPosition( + diagnostic.start + ); + + this.warn( + `${diagnostic.file.fileName}(${line + 1},${character + 1}): error TS${ + diagnostic.code + }: ${message}` + ); + } else { + this.warn(`Error: ${message}`); + } + + if (diagnostic.category === ts.DiagnosticCategory.Error) { + fatalError = true; + } + }); + + if (fatalError) { + throw new Error(`There were TypeScript errors transpiling`); + } + + return { + code: transformed.outputText, + + // Rollup expects `map` to be an object so we must parse the string + map: transformed.sourceMapText ? JSON.parse(transformed.sourceMapText) : null + }; + } + }; +} diff --git a/packages/typescript/src/options.js b/packages/typescript/src/options.js new file mode 100644 index 000000000..ca477aea2 --- /dev/null +++ b/packages/typescript/src/options.js @@ -0,0 +1,71 @@ +import { sep } from 'path'; +import { existsSync, readFileSync } from 'fs'; + +export function getDefaultOptions() { + return { + noEmitHelpers: true, + module: 'ESNext', + sourceMap: true, + importHelpers: true + }; +} + +// Gratefully lifted from 'look-up', due to problems using it directly: +// https://github.com/jonschlinkert/look-up/blob/master/index.js +// MIT Licenced +function findFile(cwd, filename) { + let fp = cwd ? `${cwd}/${filename}` : filename; + + if (existsSync(fp)) { + return fp; + } + + const segs = cwd.split(sep); + + for (let len = segs.length; len >= 0; len--) { + const workingDir = segs.slice(0, len).join('/'); + fp = `${workingDir}/${filename}`; + if (existsSync(fp)) { + return fp; + } + } + + return null; +} + +export function readTsConfig(typescript, tsconfigPath) { + if (tsconfigPath && !existsSync(tsconfigPath)) { + throw new Error(`Could not find specified tsconfig.json at ${tsconfigPath}`); + } + const existingTsConfig = tsconfigPath || findFile(process.cwd(), 'tsconfig.json'); + if (!existingTsConfig) { + return {}; + } + const tsconfig = typescript.readConfigFile(existingTsConfig, (path) => + readFileSync(path, 'utf8') + ); + + if (!tsconfig.config || !tsconfig.config.compilerOptions) return { compilerOptions: {} }; + return tsconfig.config; +} + +export function adjustCompilerOptions(typescript, options) { + const opts = Object.assign({}, options); + // Set `sourceMap` to `inlineSourceMap` if it's a boolean + // under the assumption that both are never specified simultaneously. + if (typeof opts.inlineSourceMap === 'boolean') { + opts.sourceMap = opts.inlineSourceMap; + delete opts.inlineSourceMap; + } + + // Delete some options to prevent compilation error. + // See: https://github.com/rollup/rollup-plugin-typescript/issues/45 + // See: https://github.com/rollup/rollup-plugin-typescript/issues/142 + delete opts.declaration; + // Delete the `declarationMap` option, as it will cause an error, because we have + // deleted the `declaration` option. + delete opts.declarationMap; + delete opts.incremental; + delete opts.tsBuildInfoFile; + return opts; +} diff --git a/packages/typescript/src/resolveHost.js b/packages/typescript/src/resolveHost.js new file mode 100644 index 000000000..9f5a84168 --- /dev/null +++ b/packages/typescript/src/resolveHost.js @@ -0,0 +1,18 @@ +import { statSync } from 'fs'; + +export default { + directoryExists(dirPath) { + try { + return statSync(dirPath).isDirectory(); + } catch (err) { + return false; + } + }, + fileExists(filePath) { + try { + return statSync(filePath).isFile(); + } catch (err) { + return false; + } + } +}; diff --git a/packages/typescript/src/string.js b/packages/typescript/src/string.js new file mode 100644 index 000000000..885ae92ac --- /dev/null +++ b/packages/typescript/src/string.js @@ -0,0 +1,3 @@ +export default function endsWith(str, tail) { + return !tail.length || str.slice(-tail.length) === tail; +} diff --git a/packages/typescript/test/fixtures/assign/main.ts b/packages/typescript/test/fixtures/assign/main.ts new file mode 100644 index 000000000..f290df3bf --- /dev/null +++ b/packages/typescript/test/fixtures/assign/main.ts @@ -0,0 +1,7 @@ +const others = { + b: 2, + c: 1, + d: 3 +}; + +export default { a: 5, ...others, c: 3 }; diff --git a/packages/typescript/test/fixtures/async/main.ts b/packages/typescript/test/fixtures/async/main.ts new file mode 100644 index 000000000..1ba33da5c --- /dev/null +++ b/packages/typescript/test/fixtures/async/main.ts @@ -0,0 +1,9 @@ +export default async function ( n: number ) { + while ( --n ) { + await delay( 10 ); + } +} + +function delay ( interval: number ) { + return new Promise( resolve => setTimeout( resolve, interval ) ); +} diff --git a/packages/typescript/test/fixtures/basic/main.ts b/packages/typescript/test/fixtures/basic/main.ts new file mode 100644 index 000000000..d0b587a92 --- /dev/null +++ b/packages/typescript/test/fixtures/basic/main.ts @@ -0,0 +1,2 @@ +const answer: number = 42; +console.log( `the answer is ${answer}` ); diff --git a/packages/typescript/test/fixtures/commonjs-imports/cjs.js b/packages/typescript/test/fixtures/commonjs-imports/cjs.js new file mode 100644 index 000000000..8b8bd2cb2 --- /dev/null +++ b/packages/typescript/test/fixtures/commonjs-imports/cjs.js @@ -0,0 +1 @@ +module.exports = 'exported from commonjs'; diff --git a/packages/typescript/test/fixtures/commonjs-imports/main.ts b/packages/typescript/test/fixtures/commonjs-imports/main.ts new file mode 100644 index 000000000..e4d103245 --- /dev/null +++ b/packages/typescript/test/fixtures/commonjs-imports/main.ts @@ -0,0 +1,3 @@ +import cjs = require('./cjs'); + +export default cjs; diff --git a/packages/typescript/test/fixtures/dedup-helpers/A.ts b/packages/typescript/test/fixtures/dedup-helpers/A.ts new file mode 100644 index 000000000..6a661594a --- /dev/null +++ b/packages/typescript/test/fixtures/dedup-helpers/A.ts @@ -0,0 +1,2 @@ +import Base from './Base'; +export class A extends Base {} diff --git a/packages/typescript/test/fixtures/dedup-helpers/B.ts b/packages/typescript/test/fixtures/dedup-helpers/B.ts new file mode 100644 index 000000000..d344abf40 --- /dev/null +++ b/packages/typescript/test/fixtures/dedup-helpers/B.ts @@ -0,0 +1,2 @@ +import Base from './Base'; +export class B extends Base {} diff --git a/packages/typescript/test/fixtures/dedup-helpers/Base.ts b/packages/typescript/test/fixtures/dedup-helpers/Base.ts new file mode 100644 index 000000000..762486819 --- /dev/null +++ b/packages/typescript/test/fixtures/dedup-helpers/Base.ts @@ -0,0 +1 @@ +export default class Base {} diff --git a/packages/typescript/test/fixtures/dedup-helpers/main.ts b/packages/typescript/test/fixtures/dedup-helpers/main.ts new file mode 100644 index 000000000..2a1098309 --- /dev/null +++ b/packages/typescript/test/fixtures/dedup-helpers/main.ts @@ -0,0 +1,2 @@ +export { A } from './A'; +export { B } from './B'; diff --git a/packages/typescript/test/fixtures/dts/main.ts b/packages/typescript/test/fixtures/dts/main.ts new file mode 100644 index 000000000..4d1c21fbc --- /dev/null +++ b/packages/typescript/test/fixtures/dts/main.ts @@ -0,0 +1,3 @@ +import { foo } from 'an-import'; + +foo(); diff --git a/packages/typescript/test/fixtures/dynamic-imports/dynamic.ts b/packages/typescript/test/fixtures/dynamic-imports/dynamic.ts new file mode 100644 index 000000000..e5ff7be21 --- /dev/null +++ b/packages/typescript/test/fixtures/dynamic-imports/dynamic.ts @@ -0,0 +1,2 @@ +console.log('dynamic'); +export default 42; diff --git a/packages/typescript/test/fixtures/dynamic-imports/main.ts b/packages/typescript/test/fixtures/dynamic-imports/main.ts new file mode 100644 index 000000000..045d7044c --- /dev/null +++ b/packages/typescript/test/fixtures/dynamic-imports/main.ts @@ -0,0 +1 @@ +export default import('./dynamic'); diff --git a/packages/typescript/test/fixtures/export-abstract-class/main.ts b/packages/typescript/test/fixtures/export-abstract-class/main.ts new file mode 100644 index 000000000..2a6005706 --- /dev/null +++ b/packages/typescript/test/fixtures/export-abstract-class/main.ts @@ -0,0 +1 @@ +export abstract class A {} diff --git a/packages/typescript/test/fixtures/export-class-fix/default.ts b/packages/typescript/test/fixtures/export-class-fix/default.ts new file mode 100644 index 000000000..5613277f1 --- /dev/null +++ b/packages/typescript/test/fixtures/export-class-fix/default.ts @@ -0,0 +1,3 @@ +// the odd spacing is intentional +export default + class A {} diff --git a/packages/typescript/test/fixtures/export-class-fix/main.ts b/packages/typescript/test/fixtures/export-class-fix/main.ts new file mode 100644 index 000000000..08941b81f --- /dev/null +++ b/packages/typescript/test/fixtures/export-class-fix/main.ts @@ -0,0 +1,4 @@ +import A from './default'; +import { B } from './named'; + +export { A, B }; diff --git a/packages/typescript/test/fixtures/export-class-fix/named.ts b/packages/typescript/test/fixtures/export-class-fix/named.ts new file mode 100644 index 000000000..d6ec0dcc0 --- /dev/null +++ b/packages/typescript/test/fixtures/export-class-fix/named.ts @@ -0,0 +1,2 @@ +// the odd spacing is intentional +export class B {} diff --git a/packages/typescript/test/fixtures/export-class/Foo.ts b/packages/typescript/test/fixtures/export-class/Foo.ts new file mode 100644 index 000000000..7460ea242 --- /dev/null +++ b/packages/typescript/test/fixtures/export-class/Foo.ts @@ -0,0 +1,3 @@ +export class Foo { + foo = 'bar'; +} \ No newline at end of file diff --git a/packages/typescript/test/fixtures/export-class/main.ts b/packages/typescript/test/fixtures/export-class/main.ts new file mode 100644 index 000000000..d0f11799a --- /dev/null +++ b/packages/typescript/test/fixtures/export-class/main.ts @@ -0,0 +1,3 @@ +import {Foo} from './Foo.ts'; + +export default new Foo(); diff --git a/packages/typescript/test/fixtures/export-fodule/main.ts b/packages/typescript/test/fixtures/export-fodule/main.ts new file mode 100644 index 000000000..6bc078f70 --- /dev/null +++ b/packages/typescript/test/fixtures/export-fodule/main.ts @@ -0,0 +1,6 @@ +export function test() { + return 0; +} +export namespace test { + export const foo = "2" +} \ No newline at end of file diff --git a/packages/typescript/test/fixtures/export-namespace-export-class/test.ts b/packages/typescript/test/fixtures/export-namespace-export-class/test.ts new file mode 100644 index 000000000..2aa39df87 --- /dev/null +++ b/packages/typescript/test/fixtures/export-namespace-export-class/test.ts @@ -0,0 +1,7 @@ +// https://github.com/rollup/rollup-plugin-typescript/issues/70#issuecomment-336216349 + +// test.ts +export namespace MODE { + export class MODE { + } +} \ No newline at end of file diff --git a/packages/typescript/test/fixtures/import-class/A.ts b/packages/typescript/test/fixtures/import-class/A.ts new file mode 100644 index 000000000..c7ce40f62 --- /dev/null +++ b/packages/typescript/test/fixtures/import-class/A.ts @@ -0,0 +1,9 @@ +class A { + getArgs: () => any[]; + + constructor(...args: any[]) { + this.getArgs = () => args; + } +} + +export default A; diff --git a/packages/typescript/test/fixtures/import-class/main.ts b/packages/typescript/test/fixtures/import-class/main.ts new file mode 100644 index 000000000..5ff1dc324 --- /dev/null +++ b/packages/typescript/test/fixtures/import-class/main.ts @@ -0,0 +1,3 @@ +import A from './A'; + +new A(); diff --git a/packages/typescript/test/fixtures/jsx/main.tsx b/packages/typescript/test/fixtures/jsx/main.tsx new file mode 100644 index 000000000..37ccc3ce8 --- /dev/null +++ b/packages/typescript/test/fixtures/jsx/main.tsx @@ -0,0 +1 @@ +export default Yo! diff --git a/packages/typescript/test/fixtures/overriding-tslib/main.ts b/packages/typescript/test/fixtures/overriding-tslib/main.ts new file mode 100644 index 000000000..52432ad01 --- /dev/null +++ b/packages/typescript/test/fixtures/overriding-tslib/main.ts @@ -0,0 +1,7 @@ +class Base { + static baseMethod() { + return 'base method'; + } +} + +export default class Main extends Base {} diff --git a/packages/typescript/test/fixtures/overriding-typescript/main.ts b/packages/typescript/test/fixtures/overriding-typescript/main.ts new file mode 100644 index 000000000..8b1a39374 --- /dev/null +++ b/packages/typescript/test/fixtures/overriding-typescript/main.ts @@ -0,0 +1 @@ +// empty diff --git a/packages/typescript/test/fixtures/syntax-error/missing-type.ts b/packages/typescript/test/fixtures/syntax-error/missing-type.ts new file mode 100644 index 000000000..49d803c65 --- /dev/null +++ b/packages/typescript/test/fixtures/syntax-error/missing-type.ts @@ -0,0 +1 @@ +var a: ; diff --git a/packages/typescript/test/fixtures/tsconfig-extends/main.tsx b/packages/typescript/test/fixtures/tsconfig-extends/main.tsx new file mode 100644 index 000000000..37ccc3ce8 --- /dev/null +++ b/packages/typescript/test/fixtures/tsconfig-extends/main.tsx @@ -0,0 +1 @@ +export default Yo! diff --git a/packages/typescript/test/fixtures/tsconfig-extends/tsconfig.base.json b/packages/typescript/test/fixtures/tsconfig-extends/tsconfig.base.json new file mode 100644 index 000000000..986627de2 --- /dev/null +++ b/packages/typescript/test/fixtures/tsconfig-extends/tsconfig.base.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "jsx": "react" + } +} diff --git a/packages/typescript/test/fixtures/tsconfig-extends/tsconfig.json b/packages/typescript/test/fixtures/tsconfig-extends/tsconfig.json new file mode 100644 index 000000000..de5b4ae7f --- /dev/null +++ b/packages/typescript/test/fixtures/tsconfig-extends/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.base", + "compilerOptions": { + "allowJs": true + } +} diff --git a/packages/typescript/test/fixtures/tsconfig-jsx/main.tsx b/packages/typescript/test/fixtures/tsconfig-jsx/main.tsx new file mode 100644 index 000000000..37ccc3ce8 --- /dev/null +++ b/packages/typescript/test/fixtures/tsconfig-jsx/main.tsx @@ -0,0 +1 @@ +export default Yo! diff --git a/packages/typescript/test/fixtures/tsconfig-jsx/tsconfig.json b/packages/typescript/test/fixtures/tsconfig-jsx/tsconfig.json new file mode 100644 index 000000000..986627de2 --- /dev/null +++ b/packages/typescript/test/fixtures/tsconfig-jsx/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "jsx": "react" + } +} diff --git a/packages/typescript/test/test.js b/packages/typescript/test/test.js new file mode 100644 index 000000000..94f945c62 --- /dev/null +++ b/packages/typescript/test/test.js @@ -0,0 +1,393 @@ +const path = require('path'); + +const test = require('ava'); +const { rollup } = require('rollup'); + +const commonjs = require('rollup-plugin-commonjs'); + +const { getCode, testBundle } = require('../../../util/test'); + +const typescript = require('..'); + +test.beforeEach(() => process.chdir(__dirname)); + +const outputOptions = { format: 'esm' }; + +async function evaluateBundle(bundle) { + const { module } = await testBundle(null, bundle); + return module.exports; +} + +test('runs code through typescript', async (t) => { + const bundle = await rollup({ + input: 'fixtures/basic/main.ts', + plugins: [typescript()] + }); + const code = await getCode(bundle, outputOptions); + + t.false(code.includes('number'), code); + t.false(code.includes('const'), code); +}); + +test('ignores the declaration option', async (t) => { + await t.notThrowsAsync( + rollup({ + input: 'fixtures/basic/main.ts', + plugins: [typescript({ declaration: true })] + }) + ); +}); + +test('throws for unsupported module types', async (t) => { + let caughtError = null; + try { + await rollup({ + input: 'fixtures/basic/main.ts', + plugins: [typescript({ module: 'ES5' })] + }); + } catch (error) { + caughtError = error; + } + + t.truthy(caughtError, 'Throws an error.'); + t.true( + caughtError.message.includes("The module kind should be 'ES2015' or 'ESNext, found: 'ES5'"), + `Unexpected error message: ${caughtError.message}` + ); +}); + +test('ignores case of module types', async (t) => { + await t.notThrowsAsync( + rollup({ + input: 'fixtures/basic/main.ts', + plugins: [typescript({ module: 'eSnExT' })] + }) + ); +}); + +test('handles async functions', async (t) => { + const bundle = await rollup({ + input: 'fixtures/async/main.ts', + plugins: [typescript()] + }); + const wait = await evaluateBundle(bundle); + await wait(3); + t.pass(); +}); + +test('does not duplicate helpers', async (t) => { + const bundle = await rollup({ + input: 'fixtures/dedup-helpers/main.ts', + plugins: [typescript()] + }); + const code = await getCode(bundle, outputOptions); + + // The `__extends` function is defined in the bundle. + t.true(code.includes('function __extends'), code); + + // No duplicate `__extends` helper is defined. + t.false(code.includes('__extends$1'), code); +}); + +test('transpiles `export class A` correctly', async (t) => { + const bundle = await rollup({ + input: 'fixtures/export-class-fix/main.ts', + plugins: [typescript()] + }); + + const code = await getCode(bundle, outputOptions); + t.true(code.includes('export { A, B };'), code); + + const { A, B } = await evaluateBundle(bundle); + const aInst = new A(); + const bInst = new B(); + t.true(aInst instanceof A); + t.true(bInst instanceof B); +}); + +test('transpiles ES6 features to ES5 with source maps', async (t) => { + const bundle = await rollup({ + input: 'fixtures/import-class/main.ts', + plugins: [typescript()] + }); + + const code = await getCode(bundle, outputOptions); + + t.is(code.indexOf('...'), -1, code); + t.is(code.indexOf('=>'), -1, code); +}); + +test('reports diagnostics and throws if errors occur during transpilation', async (t) => { + let caughtError = null; + try { + await rollup({ + input: 'fixtures/syntax-error/missing-type.ts', + plugins: [typescript()] + }); + } catch (error) { + caughtError = error; + } + + t.truthy(caughtError, 'throws an error'); + t.true( + caughtError.message.includes('There were TypeScript errors transpiling'), + `Unexpected error message: ${caughtError.message}` + ); +}); + +test('works with named exports for abstract classes', async (t) => { + const bundle = await rollup({ + input: 'fixtures/export-abstract-class/main.ts', + plugins: [typescript()] + }); + const code = await getCode(bundle, outputOptions); + t.true(code.length > 0, code); +}); + +test('should use named exports for classes', async (t) => { + const bundle = await rollup({ + input: 'fixtures/export-class/main.ts', + plugins: [typescript()] + }); + t.is((await evaluateBundle(bundle)).foo, 'bar'); +}); + +test('supports overriding the TypeScript version', async (t) => { + const bundle = await rollup({ + input: 'fixtures/overriding-typescript/main.ts', + plugins: [ + typescript({ + // Don't use `tsconfig.json` + tsconfig: false, + + // test with a mocked version of TypeScript + typescript: fakeTypescript({ + version: '1.8.0-fake', + + transpileModule: () => { + // Ignore the code to transpile. Always return the same thing. + return { + outputText: 'export default 1337;', + diagnostics: [], + sourceMapText: JSON.stringify({ mappings: '' }) + }; + } + }) + }) + ] + }); + const result = await evaluateBundle(bundle); + + t.is(result, 1337); +}); + +test('supports overriding tslib', async (t) => { + const bundle = await rollup({ + input: 'fixtures/overriding-tslib/main.ts', + plugins: [ + typescript({ tslib: 'export const __extends = (Main, Super) => Main.myParent = Super' }) + ] + }); + const code = await evaluateBundle(bundle); + + t.is(code.myParent.baseMethod(), 'base method'); +}); + +test('should not resolve .d.ts files', async (t) => { + const bundle = await rollup({ + input: 'fixtures/dts/main.ts', + plugins: [typescript()] + }); + const imports = bundle.cache.modules[0].dependencies; + t.deepEqual(imports, ['an-import']); +}); + +test('should transpile JSX if enabled', async (t) => { + const bundle = await rollup({ + input: 'fixtures/jsx/main.tsx', + plugins: [typescript({ jsx: 'react' })] + }); + const code = await getCode(bundle, outputOptions); + + t.not(code.indexOf('var __assign = '), -1, 'should contain __assign definition'); + + const usage = code.indexOf('React.createElement("span", __assign({}, props), "Yo!")'); + + t.not(usage, -1, 'should contain usage'); +}); + +test.serial('automatically loads tsconfig.json from the current directory', async (t) => { + process.chdir('fixtures/tsconfig-jsx'); + + const bundle = await rollup({ + input: 'main.tsx', + plugins: [typescript()] + }); + const code = await getCode(bundle, outputOptions); + + const usage = code.indexOf('React.createElement("span", __assign({}, props), "Yo!")'); + t.not(usage, -1, 'should contain usage'); +}); + +test.serial('should support extends property in tsconfig', async (t) => { + process.chdir('fixtures/tsconfig-extends'); + + const bundle = await rollup({ + input: 'main.tsx', + plugins: [typescript()] + }); + const code = await getCode(bundle, outputOptions); + + const usage = code.indexOf('React.createElement("span", __assign({}, props), "Yo!")'); + t.not(usage, -1, 'should contain usage'); +}); + +test('allows specifying a path for tsconfig.json', async (t) => { + const bundle = await rollup({ + input: 'fixtures/tsconfig-jsx/main.tsx', + plugins: [ + typescript({ tsconfig: path.resolve(__dirname, 'fixtures/tsconfig-jsx/tsconfig.json') }) + ] + }); + const code = await getCode(bundle, outputOptions); + + const usage = code.indexOf('React.createElement("span", __assign({}, props), "Yo!")'); + t.not(usage, -1, 'should contain usage'); +}); + +test('throws if tsconfig cannot be found', async (t) => { + let caughtError = null; + try { + await rollup({ + input: 'fixtures/tsconfig-jsx/main.tsx', + plugins: [typescript({ tsconfig: path.resolve(__dirname, 'does-not-exist.json') })] + }); + } catch (error) { + caughtError = error; + } + + t.truthy(caughtError, 'Throws an error.'); + t.true( + caughtError.message.includes('Could not find specified tsconfig.json'), + `Unexpected error message: ${caughtError.message}` + ); +}); + +test('should throw on bad options', (t) => { + t.throws( + () => + rollup({ + input: 'does-not-matter.ts', + plugins: [typescript({ foo: 'bar' })] + }), + "@rollup/plugin-typescript: Couldn't process compiler options" + ); +}); + +test('prevents errors due to conflicting `sourceMap`/`inlineSourceMap` options', async (t) => { + await t.notThrowsAsync( + rollup({ + input: 'fixtures/overriding-typescript/main.ts', + plugins: [typescript({ inlineSourceMap: true })] + }) + ); +}); + +test('should not fail if source maps are off', async (t) => { + await t.notThrowsAsync( + rollup({ + input: 'fixtures/overriding-typescript/main.ts', + plugins: [ + typescript({ + inlineSourceMap: false, + sourceMap: false + }) + ] + }) + ); +}); + +test('does not include helpers in source maps', async (t) => { + const bundle = await rollup({ + input: 'fixtures/dedup-helpers/main.ts', + plugins: [typescript({ sourceMap: true })] + }); + const { output } = await bundle.generate({ + format: 'es', + sourcemap: true + }); + const [{ map }] = output; + + t.true(map.sources.every((source) => !source.includes('tslib'))); +}); + +test('should allow a namespace containing a class', async (t) => { + const bundle = await rollup({ + input: 'fixtures/export-namespace-export-class/test.ts', + plugins: [typescript()] + }); + const { MODE } = (await evaluateBundle(bundle)).MODE; + const mode = new MODE(); + + t.true(mode instanceof MODE); +}); + +test('should allow merging an exported function and namespace', async (t) => { + const bundle = await rollup({ + input: 'fixtures/export-fodule/main.ts', + plugins: [typescript()] + }); + const f = (await evaluateBundle(bundle)).test; + + t.is(f(), 0); + t.is(f.foo, '2'); +}); + +test('supports dynamic imports', async (t) => { + const code = await getCode( + await rollup({ + input: 'fixtures/dynamic-imports/main.ts', + inlineDynamicImports: true, + plugins: [typescript()] + }), + outputOptions + ); + t.true(code.includes("console.log('dynamic')")); +}); + +test('supports CommonJS imports when the output format is CommonJS', async (t) => { + const bundle = await rollup({ + input: 'fixtures/commonjs-imports/main.ts', + plugins: [typescript({ module: 'CommonJS' }), commonjs({ extensions: ['.ts', '.js'] })] + }); + const output = await evaluateBundle(bundle); + t.is(output, 'exported from commonjs'); +}); + +function fakeTypescript(custom) { + return Object.assign( + { + transpileModule() { + return { + outputText: '', + diagnostics: [], + sourceMapText: JSON.stringify({ mappings: '' }) + }; + }, + + convertCompilerOptionsFromJson(options) { + ['include', 'exclude', 'typescript', 'tslib', 'tsconfig'].forEach((option) => { + if (option in options) { + throw new Error(`unrecognized compiler option "${option}"`); + } + }); + + return { + options, + errors: [] + }; + } + }, + custom + ); +} diff --git a/packages/typescript/tsconfig.json b/packages/typescript/tsconfig.json new file mode 100644 index 000000000..842f6deb5 --- /dev/null +++ b/packages/typescript/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strict": true, + "noEmit": true, + "allowJs": true + }, + "files": [ + "index.d.ts", + "typings-test.js" + ] +} diff --git a/packages/typescript/typings-test.js b/packages/typescript/typings-test.js new file mode 100644 index 000000000..698c433c4 --- /dev/null +++ b/packages/typescript/typings-test.js @@ -0,0 +1,21 @@ +// @ts-check +import typescript from '.'; + +/** @type {import("rollup").RollupOptions} */ +const config = { + input: 'main.js', + output: { + file: 'bundle.js', + format: 'iife' + }, + plugins: [ + typescript({ + lib: ["es5", "es6", "dom"], + target: "es5", + include: 'node_modules/**', + exclude: ['node_modules/foo/**', 'node_modules/bar/**', /node_modules/], + }) + ] +}; + +export default config; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 162fce423..136e45877 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,10 @@ importers: rollup-plugin-node-resolve: ^5.2.0 packages/auto-install/test/fixtures/npm: specifiers: {} + packages/auto-install/test/fixtures/yarn: + specifiers: {} + packages/auto-install/test/fixtures/yarn-bare: + specifiers: {} packages/beep: devDependencies: rollup: 1.27.8 @@ -270,6 +274,26 @@ importers: magic-string: ^0.25.1 rollup: ^1.20.0 rollup-pluginutils: ^2.8.1 + packages/typescript: + dependencies: + '@rollup/pluginutils': 3.0.0_rollup@1.27.8 + resolve: 1.13.1 + devDependencies: + '@rollup/plugin-buble': 0.20.0_rollup@1.27.8 + buble: 0.19.8 + rollup: 1.27.8 + rollup-plugin-commonjs: 9.3.4_rollup@1.27.8 + tslib: 1.10.0 + typescript: 3.7.2 + specifiers: + '@rollup/plugin-buble': ^0.20.0 + '@rollup/pluginutils': ^3.0.0 + buble: ^0.19.8 + resolve: ^1.12.2 + rollup: ^1.27.5 + rollup-plugin-commonjs: ^9.3.4 + tslib: ^1.10.0 + typescript: ^3.7.2 packages/url: dependencies: make-dir: 3.0.0 @@ -5997,6 +6021,18 @@ packages: rollup: '>=1.12.0' resolution: integrity: sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q== + /rollup-plugin-commonjs/9.3.4_rollup@1.27.8: + dependencies: + estree-walker: 0.6.1 + magic-string: 0.25.4 + resolve: 1.13.1 + rollup: 1.27.8 + rollup-pluginutils: 2.8.2 + dev: true + peerDependencies: + rollup: '>=0.56.0' + resolution: + integrity: sha512-DTZOvRoiVIHHLFBCL4pFxOaJt8pagxsVldEXBOn6wl3/V21wVaj17HFfyzTsQUuou3sZL3lEJZVWKPFblJfI6w== /rollup-plugin-node-resolve/5.2.0: dependencies: '@types/resolve': 0.0.8 diff --git a/util/test.js b/util/test.js index 564892374..5003d5725 100644 --- a/util/test.js +++ b/util/test.js @@ -1,3 +1,7 @@ +/** + * @param {import('rollup').RollupBuild} bundle + * @param {import('rollup').OutputOptions} outputOptions + */ const getCode = async (bundle, outputOptions, allFiles = false) => { const { output } = await bundle.generate(outputOptions || { format: 'cjs' }); @@ -19,6 +23,11 @@ const getImports = async (bundle) => { return imports; }; +/** + * @param {import('ava').Assertions} t + * @param {import('rollup').RollupBuild} bundle + * @param {object} args + */ const testBundle = async (t, bundle, args = {}) => { const { output } = await bundle.generate({ format: 'cjs' }); const [{ code }] = output;