@rollup/plugin-typescript
Advanced tools
Comparing version 3.0.0 to 3.1.0
# @rollup/plugin-typescript ChangeLog | ||
## v3.1.0 | ||
_2020-03-05_ | ||
### Bugfixes | ||
- fix: Use builtin extends resolution (#199) | ||
### Features | ||
- feat: Move to BuilderProgram API (#217) | ||
### Updates | ||
- test: Add preserveModules test (#234) | ||
- chore: refactor compiler host (#214) | ||
- test: Add test for optional chaining (#207) | ||
- chore: Use typechecking (4bb8753) | ||
## v3.0.0 | ||
@@ -4,0 +23,0 @@ |
@@ -1,87 +0,40 @@ | ||
import { resolve, win32, posix } from 'path'; | ||
import { readFile, readFileSync } from 'fs'; | ||
import { resolve, dirname, relative, win32, posix } from 'path'; | ||
import { createFilter } from '@rollup/pluginutils'; | ||
import * as defaultTs from 'typescript'; | ||
import resolveId from 'resolve'; | ||
import { readFileSync } from 'fs'; | ||
// `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` | ||
const CANNOT_COMPILE_ESM = 1204; | ||
/** | ||
* For each type error reported by Typescript, emit a Rollup warning or error. | ||
* Create a format diagnostics host to use with the Typescript type checking APIs. | ||
* Typescript hosts are used to represent the user's system, | ||
* with an API for checking case sensitivity etc. | ||
* @param compilerOptions Typescript compiler options. Affects functions such as `getNewLine`. | ||
* @see https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API | ||
*/ | ||
function emitDiagnostics(ts, context, host, diagnostics) { | ||
if (!diagnostics) | ||
return; | ||
const { noEmitOnError } = host.getCompilationSettings(); | ||
diagnostics | ||
.filter((diagnostic) => diagnostic.code !== CANNOT_COMPILE_ESM) | ||
.forEach((diagnostic) => { | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = diagnosticToWarning(ts, host, diagnostic); | ||
// Errors are fatal. Otherwise emit warnings. | ||
if (noEmitOnError && diagnostic.category === ts.DiagnosticCategory.Error) { | ||
context.error(warning); | ||
} | ||
else { | ||
context.warn(warning); | ||
} | ||
}); | ||
} | ||
/** | ||
* Converts a Typescript type error into an equivalent Rollup warning object. | ||
*/ | ||
function diagnosticToWarning(ts, host, diagnostic) { | ||
const pluginCode = `TS${diagnostic.code}`; | ||
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = { | ||
pluginCode, | ||
message: `@rollup/plugin-typescript ${pluginCode}: ${message}` | ||
function createFormattingHost(ts, compilerOptions) { | ||
return { | ||
/** Returns the compiler options for the project. */ | ||
getCompilationSettings: () => compilerOptions, | ||
/** Returns the current working directory. */ | ||
getCurrentDirectory: () => process.cwd(), | ||
/** Returns the string that corresponds with the selected `NewLineKind`. */ | ||
getNewLine() { | ||
switch (compilerOptions.newLine) { | ||
case ts.NewLineKind.CarriageReturnLineFeed: | ||
return '\r\n'; | ||
case ts.NewLineKind.LineFeed: | ||
return '\n'; | ||
default: | ||
return ts.sys.newLine; | ||
} | ||
}, | ||
/** Returns a lower case name on case insensitive systems, otherwise the original name. */ | ||
getCanonicalFileName: (fileName) => ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase() | ||
}; | ||
if (diagnostic.file) { | ||
// Add information about the file location | ||
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); | ||
warning.loc = { | ||
column: character + 1, | ||
line: line + 1, | ||
file: diagnostic.file.fileName | ||
}; | ||
if (host) { | ||
// Extract a code frame from Typescript | ||
const formatted = ts.formatDiagnosticsWithColorAndContext([diagnostic], host); | ||
// Typescript only exposes this formatter as a string prefixed with the flattened message. | ||
// We need to remove it here since Rollup treats the properties as separate parts. | ||
let frame = formatted.slice(formatted.indexOf(message) + message.length); | ||
const newLine = host.getNewLine(); | ||
if (frame.startsWith(newLine)) { | ||
frame = frame.slice(frame.indexOf(newLine) + newLine.length); | ||
} | ||
warning.frame = frame; | ||
} | ||
} | ||
return warning; | ||
} | ||
/** | ||
* Map of Typescript instances to paths to DocumentRegistries. | ||
*/ | ||
const globalRegistryCache = new Map(); | ||
/** | ||
* Return a `DocumentRegistry` instance that matches the given Typescript instance | ||
* and working directory. If there is no a pre-existing instance, one will be | ||
* created and set in the map. | ||
*/ | ||
function getDocumentRegistry(ts, cwd) { | ||
if (!globalRegistryCache.has(ts)) { | ||
globalRegistryCache.set(ts, new Map()); | ||
} | ||
const instanceRegistryCache = globalRegistryCache.get(ts); | ||
if (!instanceRegistryCache.has(cwd)) { | ||
instanceRegistryCache.set(cwd, ts.createDocumentRegistry(ts.sys.useCaseSensitiveFileNames, cwd)); | ||
} | ||
return instanceRegistryCache.get(cwd); | ||
} | ||
/** | ||
* Create a helper for resolving modules using Typescript. | ||
* @param host Typescript host that extends `ModuleResolutionHost` | ||
* with methods for sanitizing filenames and getting compiler options. | ||
*/ | ||
@@ -91,4 +44,5 @@ function createModuleResolver(ts, host) { | ||
const cache = ts.createModuleResolutionCache(process.cwd(), host.getCanonicalFileName, compilerOptions); | ||
const moduleHost = Object.assign(Object.assign({}, ts.sys), host); | ||
return (moduleName, containingFile) => { | ||
const resolved = ts.nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache); | ||
const resolved = ts.nodeModuleNameResolver(moduleName, containingFile, compilerOptions, moduleHost, cache); | ||
return resolved.resolvedModule; | ||
@@ -98,83 +52,2 @@ }; | ||
/** | ||
* Create a language service host to use with the Typescript compiler & type checking APIs. | ||
* @param parsedOptions Parsed options for Typescript. | ||
* @param parsedOptions.options Typescript compiler options. Affects functions such as `getNewLine`. | ||
* @param parsedOptions.fileNames Declaration files to include for typechecking. | ||
* @see https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API | ||
*/ | ||
function createHost(ts, parsedOptions) { | ||
const files = new Map(); | ||
/** Get the code stored in a File snapshot. */ | ||
function getCode({ file }) { | ||
return file.getText(0, file.getLength()); | ||
} | ||
/** @see TypescriptHost.addFile */ | ||
function addFile(id, code) { | ||
const existing = files.get(id); | ||
// Don't need to update if nothing changed | ||
if (existing && getCode(existing) === code) | ||
return; | ||
files.set(id, { | ||
file: ts.ScriptSnapshot.fromString(code), | ||
version: existing ? existing.version + 1 : 0 | ||
}); | ||
} | ||
/** Helper that tries to read the file if it hasn't been stored yet */ | ||
function getFile(id) { | ||
if (!files.has(id)) { | ||
const code = ts.sys.readFile(id); | ||
if (code == null) { | ||
throw new Error(`@rollup/plugin-typescript: Could not find ${id}`); | ||
} | ||
addFile(id, code); | ||
} | ||
return files.get(id); | ||
} | ||
parsedOptions.fileNames.forEach((id) => getFile(id)); | ||
let resolver; | ||
const host = { | ||
getCompilationSettings: () => parsedOptions.options, | ||
getCurrentDirectory: () => process.cwd(), | ||
getNewLine: () => getNewLine(ts, parsedOptions.options.newLine), | ||
getCanonicalFileName: (fileName) => ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(), | ||
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, | ||
getDefaultLibFileName: ts.getDefaultLibFilePath, | ||
getDirectories: ts.sys.getDirectories, | ||
directoryExists: ts.sys.directoryExists, | ||
realpath: ts.sys.realpath, | ||
readDirectory: ts.sys.readDirectory, | ||
readFile(fileName, encoding) { | ||
const file = files.get(fileName); | ||
if (file != null) | ||
return getCode(file); | ||
return ts.sys.readFile(fileName, encoding); | ||
}, | ||
fileExists: (fileName) => files.has(fileName) || ts.sys.fileExists(fileName), | ||
getScriptFileNames: () => Array.from(files.keys()), | ||
getScriptSnapshot: (fileName) => getFile(fileName).file, | ||
getScriptVersion: (fileName) => getFile(fileName).version.toString(), | ||
resolveModuleNames(moduleNames, containingFile) { | ||
return moduleNames.map((moduleName) => resolver(moduleName, containingFile)); | ||
}, | ||
addFile | ||
}; | ||
// Declared here because this has a circular reference | ||
resolver = createModuleResolver(ts, host); | ||
return host; | ||
} | ||
/** | ||
* Returns the string that corresponds with the selected `NewLineKind`. | ||
*/ | ||
function getNewLine(ts, kind) { | ||
switch (kind) { | ||
case ts.NewLineKind.CarriageReturnLineFeed: | ||
return '\r\n'; | ||
case ts.NewLineKind.LineFeed: | ||
return '\n'; | ||
default: | ||
return ts.sys.newLine; | ||
} | ||
} | ||
/*! ***************************************************************************** | ||
@@ -207,40 +80,10 @@ Copyright (c) Microsoft Corporation. All rights reserved. | ||
const TSLIB_ID = '\0tslib'; | ||
const readFileAsync = (file) => new Promise((fulfil, reject) => readFile(file, 'utf-8', (err, contents) => (err ? reject(err) : fulfil(contents)))); | ||
const resolveIdAsync = (file, opts) => new Promise((fulfil, reject) => resolveId(file, opts, (err, contents) => (err ? reject(err) : fulfil(contents)))); | ||
/** | ||
* Returns code asynchronously for the tslib helper library. | ||
* @param customHelperCode Overrides the injected helpers with a custom version. | ||
*/ | ||
async function getTsLibCode(customHelperCode) { | ||
if (customHelperCode) | ||
return customHelperCode; | ||
const defaultPath = await resolveIdAsync('tslib/tslib.es6.js', { basedir: __dirname }); | ||
return readFileAsync(defaultPath); | ||
function getTsLibPath() { | ||
return resolveIdAsync('tslib/tslib.es6.js', { basedir: __dirname }); | ||
} | ||
const DEFAULT_COMPILER_OPTIONS = { | ||
module: 'esnext', | ||
sourceMap: true, | ||
noEmitOnError: true | ||
}; | ||
const FORCED_COMPILER_OPTIONS = { | ||
// See: https://github.com/rollup/rollup-plugin-typescript/issues/45 | ||
// See: https://github.com/rollup/rollup-plugin-typescript/issues/142 | ||
declaration: false, | ||
// Delete the `declarationMap` option, as it will cause an error, because we have | ||
// deleted the `declaration` option. | ||
declarationMap: false, | ||
incremental: false, | ||
// eslint-disable-next-line no-undefined | ||
tsBuildInfoFile: undefined, | ||
// Always use tslib | ||
noEmitHelpers: true, | ||
importHelpers: true, | ||
// Typescript needs to emit the code for us to work with | ||
noEmit: false, | ||
emitDeclarationOnly: false, | ||
// Preventing Typescript from resolving code may break compilation | ||
noResolve: false | ||
}; | ||
/** | ||
@@ -254,7 +97,7 @@ * Separate the Rollup plugin options from the Typescript compiler options, | ||
* - `typescript`: Instance of Typescript library (possibly custom). | ||
* - `tslib`: ESM code from the tslib helper library (possibly) | ||
* - `tslib`: ESM code from the tslib helper library (possibly custom). | ||
*/ | ||
function getPluginOptions(options) { | ||
const { include, exclude, tsconfig, typescript, tslib } = options, compilerOptions = __rest(options, ["include", "exclude", "tsconfig", "typescript", "tslib"]); | ||
const filter = createFilter(include || ['*.ts+(|x)', '**/*.ts+(|x)'], exclude || ['*.d.ts', '**/*.d.ts']); | ||
const filter = createFilter(include || ['*.ts+(|x)', '**/*.ts+(|x)'], exclude); | ||
return { | ||
@@ -265,6 +108,113 @@ filter, | ||
typescript: typescript || defaultTs, | ||
tslib: getTsLibCode(tslib) | ||
tslib: tslib || getTsLibPath() | ||
}; | ||
} | ||
/** | ||
* Converts a Typescript type error into an equivalent Rollup warning object. | ||
*/ | ||
function diagnosticToWarning(ts, host, diagnostic) { | ||
const pluginCode = `TS${diagnostic.code}`; | ||
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = { | ||
pluginCode, | ||
message: `@rollup/plugin-typescript ${pluginCode}: ${message}` | ||
}; | ||
if (diagnostic.file) { | ||
// Add information about the file location | ||
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); | ||
warning.loc = { | ||
column: character + 1, | ||
line: line + 1, | ||
file: diagnostic.file.fileName | ||
}; | ||
if (host) { | ||
// Extract a code frame from Typescript | ||
const formatted = ts.formatDiagnosticsWithColorAndContext([diagnostic], host); | ||
// Typescript only exposes this formatter as a string prefixed with the flattened message. | ||
// We need to remove it here since Rollup treats the properties as separate parts. | ||
let frame = formatted.slice(formatted.indexOf(message) + message.length); | ||
const newLine = host.getNewLine(); | ||
if (frame.startsWith(newLine)) { | ||
frame = frame.slice(frame.indexOf(newLine) + newLine.length); | ||
} | ||
warning.frame = frame; | ||
} | ||
} | ||
return warning; | ||
} | ||
const DEFAULT_COMPILER_OPTIONS = { | ||
module: 'esnext', | ||
noEmitOnError: true, | ||
skipLibCheck: true | ||
}; | ||
const FORCED_COMPILER_OPTIONS = { | ||
// Always use tslib | ||
noEmitHelpers: true, | ||
importHelpers: true, | ||
// Typescript needs to emit the code for us to work with | ||
noEmit: false, | ||
emitDeclarationOnly: false, | ||
// Preventing Typescript from resolving code may break compilation | ||
noResolve: false | ||
}; | ||
/* eslint-disable no-param-reassign */ | ||
const DIRECTORY_PROPS = ['outDir', 'declarationDir']; | ||
/** | ||
* Mutates the compiler options to convert paths from relative to absolute. | ||
* This should be used with compiler options passed through the Rollup plugin options, | ||
* not those found from loading a tsconfig.json file. | ||
* @param compilerOptions Compiler options to _mutate_. | ||
* @param relativeTo Paths are resolved relative to this path. | ||
*/ | ||
function makePathsAbsolute(compilerOptions, relativeTo) { | ||
for (const pathProp of DIRECTORY_PROPS) { | ||
if (compilerOptions[pathProp]) { | ||
compilerOptions[pathProp] = resolve(relativeTo, compilerOptions[pathProp]); | ||
} | ||
} | ||
} | ||
/** | ||
* Mutates the compiler options to normalize some values for Rollup. | ||
* @param compilerOptions Compiler options to _mutate_. | ||
* @returns True if the source map compiler option was not initially set. | ||
*/ | ||
function normalizeCompilerOptions(ts, compilerOptions) { | ||
let autoSetSourceMap = false; | ||
if (compilerOptions.inlineSourceMap) { | ||
// Force separate source map files for Rollup to work with. | ||
compilerOptions.sourceMap = true; | ||
compilerOptions.inlineSourceMap = false; | ||
} | ||
else if (typeof compilerOptions.sourceMap !== 'boolean') { | ||
// Default to using source maps. | ||
// If the plugin user sets sourceMap to false we keep that option. | ||
compilerOptions.sourceMap = true; | ||
autoSetSourceMap = true; | ||
} | ||
switch (compilerOptions.module) { | ||
case ts.ModuleKind.ES2015: | ||
case ts.ModuleKind.ESNext: | ||
case ts.ModuleKind.CommonJS: | ||
// OK module type | ||
return autoSetSourceMap; | ||
case ts.ModuleKind.None: | ||
case ts.ModuleKind.AMD: | ||
case ts.ModuleKind.UMD: | ||
case ts.ModuleKind.System: { | ||
// Invalid module type | ||
const moduleType = ts.ModuleKind[compilerOptions.module]; | ||
throw new Error(`@rollup/plugin-typescript: The module kind should be 'ES2015' or 'ESNext, found: '${moduleType}'`); | ||
} | ||
default: | ||
// Unknown or unspecified module type, force ESNext | ||
compilerOptions.module = ts.ModuleKind.ESNext; | ||
} | ||
return autoSetSourceMap; | ||
} | ||
/** | ||
* Finds the path to the tsconfig file relative to the current working directory. | ||
@@ -298,3 +248,2 @@ * @param relativePath Relative tsconfig path given by the user. | ||
function readTsConfigFile(ts, tsConfigPath) { | ||
var _a; | ||
const { config, error } = ts.readConfigFile(tsConfigPath, (path) => readFileSync(path, 'utf8')); | ||
@@ -304,7 +253,2 @@ if (error) { | ||
} | ||
const extendedTsConfig = (_a = config) === null || _a === void 0 ? void 0 : _a.extends; | ||
if (extendedTsConfig) { | ||
// Get absolute path of `extends`, starting at basedir of the tsconfig file. | ||
config.extends = resolve(process.cwd(), tsConfigPath, '..', extendedTsConfig); | ||
} | ||
return config || {}; | ||
@@ -326,38 +270,4 @@ } | ||
} | ||
const configCache = new Map(); | ||
/** | ||
* Mutates the compiler options to normalize some values for Rollup. | ||
* @param compilerOptions Compiler options to _mutate_. | ||
*/ | ||
function normalizeCompilerOptions(ts, compilerOptions) { | ||
/* eslint-disable no-param-reassign */ | ||
if (compilerOptions.inlineSourceMap) { | ||
// Force separate source map files for Rollup to work with. | ||
compilerOptions.sourceMap = true; | ||
compilerOptions.inlineSourceMap = false; | ||
} | ||
else if (typeof compilerOptions.sourceMap !== 'boolean') { | ||
// Default to using source maps. | ||
// If the plugin user sets sourceMap to false we keep that option. | ||
compilerOptions.sourceMap = true; | ||
} | ||
switch (compilerOptions.module) { | ||
case ts.ModuleKind.ES2015: | ||
case ts.ModuleKind.ESNext: | ||
case ts.ModuleKind.CommonJS: | ||
// OK module type | ||
return; | ||
case ts.ModuleKind.None: | ||
case ts.ModuleKind.AMD: | ||
case ts.ModuleKind.UMD: | ||
case ts.ModuleKind.System: { | ||
// Invalid module type | ||
const moduleType = ts.ModuleKind[compilerOptions.module]; | ||
throw new Error(`@rollup/plugin-typescript: The module kind should be 'ES2015' or 'ESNext, found: '${moduleType}'`); | ||
} | ||
default: | ||
// Unknown or unspecified module type, force ESNext | ||
compilerOptions.module = ts.ModuleKind.ESNext; | ||
} | ||
} | ||
/** | ||
* Parse the Typescript config to use with the plugin. | ||
@@ -374,3 +284,5 @@ * @param ts Typescript library instance. | ||
function parseTypescriptConfig(ts, tsconfig, compilerOptions) { | ||
/* eslint-disable no-undefined */ | ||
const cwd = process.cwd(); | ||
makePathsAbsolute(compilerOptions, cwd); | ||
let parsedConfig; | ||
@@ -381,22 +293,89 @@ // Resolve path to file. If file is not found, pass undefined path to `parseJsonConfigFileContent`. | ||
const tsConfigFile = tsConfigPath ? readTsConfigFile(ts, tsConfigPath) : {}; | ||
const basePath = tsConfigPath ? dirname(tsConfigPath) : cwd; | ||
// If compilerOptions has enums, it represents an CompilerOptions object instead of parsed JSON. | ||
// This determines where the data is passed to the parser. | ||
if (containsEnumOptions(compilerOptions)) { | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions) }), ts.sys, cwd, Object.assign(Object.assign({}, compilerOptions), FORCED_COMPILER_OPTIONS), tsConfigPath); | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions) }), ts.sys, basePath, Object.assign(Object.assign({}, compilerOptions), FORCED_COMPILER_OPTIONS), tsConfigPath, undefined, undefined, configCache); | ||
} | ||
else { | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions), compilerOptions) }), ts.sys, cwd, FORCED_COMPILER_OPTIONS, tsConfigPath); | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions), compilerOptions) }), ts.sys, basePath, FORCED_COMPILER_OPTIONS, tsConfigPath, undefined, undefined, configCache); | ||
} | ||
// We only want to automatically add ambient declaration files. | ||
// Normal script files are handled by Rollup. | ||
parsedConfig.fileNames = parsedConfig.fileNames.filter((file) => file.endsWith('.d.ts')); | ||
normalizeCompilerOptions(ts, parsedConfig.options); | ||
return parsedConfig; | ||
const autoSetSourceMap = normalizeCompilerOptions(ts, parsedConfig.options); | ||
return Object.assign(Object.assign({}, parsedConfig), { autoSetSourceMap }); | ||
} | ||
/** | ||
* If errors are detected in the parsed options, | ||
* display all of them as warnings then emit an error. | ||
*/ | ||
function emitParsedOptionsErrors(ts, context, parsedOptions) { | ||
if (parsedOptions.errors.length > 0) { | ||
parsedOptions.errors.forEach((error) => context.warn(diagnosticToWarning(ts, null, error))); | ||
context.error(`@rollup/plugin-typescript: Couldn't process compiler options`); | ||
} | ||
} | ||
/** | ||
* Validate that the `compilerOptions.sourceMap` option matches `outputOptions.sourcemap`. | ||
* @param context Rollup plugin context used to emit warnings. | ||
* @param compilerOptions Typescript compiler options. | ||
* @param outputOptions Rollup output options. | ||
* @param autoSetSourceMap True if the `compilerOptions.sourceMap` property was set to `true` | ||
* by the plugin, not the user. | ||
*/ | ||
function validateSourceMap(context, compilerOptions, outputOptions, autoSetSourceMap) { | ||
if (compilerOptions.sourceMap && !outputOptions.sourcemap && !autoSetSourceMap) { | ||
context.warn(`@rollup/plugin-typescript: Rollup 'sourcemap' option must be set to generate source maps.`); | ||
} | ||
else if (!compilerOptions.sourceMap && outputOptions.sourcemap) { | ||
context.warn(`@rollup/plugin-typescript: Typescript 'sourceMap' compiler option must be set to generate source maps.`); | ||
} | ||
} | ||
/** | ||
* Validate that the out directory used by Typescript can be controlled by Rollup. | ||
* @param context Rollup plugin context used to emit errors. | ||
* @param compilerOptions Typescript compiler options. | ||
* @param outputOptions Rollup output options. | ||
*/ | ||
function validatePaths(ts, context, compilerOptions, outputOptions) { | ||
if (compilerOptions.out) { | ||
context.error(`@rollup/plugin-typescript: Deprecated 'out' option is not supported. Use 'outDir' instead.`); | ||
} | ||
else if (compilerOptions.outFile) { | ||
context.error(`@rollup/plugin-typescript: 'outFile' option is not supported. Use 'outDir' instead.`); | ||
} | ||
for (const dirProperty of DIRECTORY_PROPS) { | ||
if (compilerOptions[dirProperty]) { | ||
if (!outputOptions.dir) { | ||
context.error(`@rollup/plugin-typescript: 'dir' must be used when '${dirProperty}' is specified.`); | ||
} | ||
// Checks if the given path lies within Rollup output dir | ||
const fromRollupDirToTs = relative(outputOptions.dir, compilerOptions[dirProperty]); | ||
if (fromRollupDirToTs.startsWith('..')) { | ||
context.error(`@rollup/plugin-typescript: '${dirProperty}' must be located inside 'dir'.`); | ||
} | ||
} | ||
} | ||
const tsBuildInfoPath = ts.getTsBuildInfoEmitOutputFilePath(compilerOptions); | ||
if (tsBuildInfoPath && compilerOptions.incremental) { | ||
if (!outputOptions.dir) { | ||
context.error(`@rollup/plugin-typescript: 'dir' must be used when 'tsBuildInfoFile' or 'incremental' are specified.`); | ||
} | ||
// Checks if the given path lies within Rollup output dir | ||
const fromRollupDirToTs = relative(outputOptions.dir, tsBuildInfoPath); | ||
if (fromRollupDirToTs.startsWith('..')) { | ||
context.error(`@rollup/plugin-typescript: 'tsBuildInfoFile' must be located inside 'dir'.`); | ||
} | ||
} | ||
if (compilerOptions.declaration || compilerOptions.declarationMap) { | ||
if (DIRECTORY_PROPS.every((dirProperty) => !compilerOptions[dirProperty])) { | ||
context.error(`@rollup/plugin-typescript: 'outDir' or 'declarationDir' must be specified to generate declaration files.`); | ||
} | ||
} | ||
} | ||
/** | ||
* Checks if the given OutputFile represents some code | ||
*/ | ||
function isCodeOutputFile(file) { | ||
return !isMapOutputFile(file) && !file.name.endsWith('.d.ts'); | ||
function isCodeOutputFile(name) { | ||
return !isMapOutputFile(name) && !name.endsWith('.d.ts'); | ||
} | ||
@@ -406,37 +385,115 @@ /** | ||
*/ | ||
function isMapOutputFile({ name }) { | ||
function isMapOutputFile(name) { | ||
return name.endsWith('.map'); | ||
} | ||
/** | ||
* Transforms a Typescript EmitOutput into a Rollup SourceDescription. | ||
* Finds the corresponding emitted Javascript files for a given Typescript file. | ||
* @param id Path to the Typescript file. | ||
* @param emittedFiles Map of file names to source code, | ||
* containing files emitted by the Typescript compiler. | ||
*/ | ||
function typescriptOutputToRollupTransformation(outputFiles) { | ||
var _a; | ||
const code = outputFiles.find(isCodeOutputFile); | ||
if (code == null) | ||
return null; | ||
const map = outputFiles.find(isMapOutputFile); | ||
function findTypescriptOutput(ts, parsedOptions, id, emittedFiles) { | ||
const emittedFileNames = ts.getOutputFileNames(parsedOptions, id, !ts.sys.useCaseSensitiveFileNames); | ||
const codeFile = emittedFileNames.find(isCodeOutputFile); | ||
const mapFile = emittedFileNames.find(isMapOutputFile); | ||
return { | ||
code: code.text, | ||
map: (_a = map) === null || _a === void 0 ? void 0 : _a.text | ||
code: emittedFiles.get(codeFile), | ||
map: emittedFiles.get(mapFile), | ||
declarations: emittedFileNames.filter((name) => name !== codeFile && name !== mapFile) | ||
}; | ||
} | ||
// `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` | ||
const CANNOT_COMPILE_ESM = 1204; | ||
/** | ||
* Emit a Rollup warning or error for a Typescript type error. | ||
*/ | ||
function emitDiagnostic(ts, context, host, diagnostic) { | ||
if (diagnostic.code === CANNOT_COMPILE_ESM) | ||
return; | ||
const { noEmitOnError } = host.getCompilationSettings(); | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = diagnosticToWarning(ts, host, diagnostic); | ||
// Errors are fatal. Otherwise emit warnings. | ||
if (noEmitOnError && diagnostic.category === ts.DiagnosticCategory.Error) { | ||
context.error(warning); | ||
} | ||
else { | ||
context.warn(warning); | ||
} | ||
} | ||
function buildDiagnosticReporter(ts, context, host) { | ||
return function reportDiagnostics(diagnostic) { | ||
emitDiagnostic(ts, context, host, diagnostic); | ||
}; | ||
} | ||
/** | ||
* Create a language service host to use with the Typescript compiler & type checking APIs. | ||
* Typescript hosts are used to represent the user's system, | ||
* with an API for reading files, checking directories and case sensitivity etc. | ||
* @see https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API | ||
*/ | ||
function createWatchHost(ts, context, { formatHost, parsedOptions, writeFile, resolveModule }) { | ||
const createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram; | ||
const baseHost = ts.createWatchCompilerHost(parsedOptions.fileNames, parsedOptions.options, ts.sys, createProgram, buildDiagnosticReporter(ts, context, formatHost), | ||
// Ignore watch status changes | ||
() => { }, parsedOptions.projectReferences); | ||
return Object.assign(Object.assign({}, baseHost), { | ||
/** Override the created program so an in-memory emit is used */ | ||
afterProgramCreate(program) { | ||
const origEmit = program.emit; | ||
// eslint-disable-next-line no-param-reassign | ||
program.emit = (targetSourceFile, _, ...args) => origEmit(targetSourceFile, writeFile, ...args); | ||
return baseHost.afterProgramCreate(program); | ||
}, | ||
/** Add helper to deal with module resolution */ | ||
resolveModuleNames(moduleNames, containingFile) { | ||
return moduleNames.map((moduleName) => resolveModule(moduleName, containingFile)); | ||
} }); | ||
} | ||
function createWatchProgram(ts, context, options) { | ||
return ts.createWatchProgram(createWatchHost(ts, context, options)); | ||
} | ||
function typescript(options = {}) { | ||
const { filter, tsconfig, compilerOptions, tslib, typescript: ts } = getPluginOptions(options); | ||
const emittedFiles = new Map(); | ||
const declarationFiles = new Set(); | ||
const parsedOptions = parseTypescriptConfig(ts, tsconfig, compilerOptions); | ||
const host = createHost(ts, parsedOptions); | ||
const services = ts.createLanguageService(host, getDocumentRegistry(ts, process.cwd())); | ||
parsedOptions.fileNames = parsedOptions.fileNames.filter(filter); | ||
const formatHost = createFormattingHost(ts, parsedOptions.options); | ||
const resolveModule = createModuleResolver(ts, formatHost); | ||
let program = null; | ||
function normalizePath(fileName) { | ||
return fileName.split(win32.sep).join(posix.sep); | ||
} | ||
return { | ||
name: 'typescript', | ||
buildStart() { | ||
if (parsedOptions.errors.length > 0) { | ||
parsedOptions.errors.forEach((error) => this.warn(diagnosticToWarning(ts, host, error))); | ||
this.error(`@rollup/plugin-typescript: Couldn't process compiler options`); | ||
emitParsedOptionsErrors(ts, this, parsedOptions); | ||
program = createWatchProgram(ts, this, { | ||
formatHost, | ||
resolveModule, | ||
parsedOptions, | ||
writeFile(fileName, data) { | ||
emittedFiles.set(fileName, data); | ||
} | ||
}); | ||
}, | ||
buildEnd() { | ||
var _a; | ||
if (process.env.ROLLUP_WATCH !== 'true') { | ||
// ESLint doesn't understand optional chaining | ||
// eslint-disable-next-line | ||
(_a = program) === null || _a === void 0 ? void 0 : _a.close(); | ||
} | ||
}, | ||
renderStart(outputOptions) { | ||
validateSourceMap(this, parsedOptions.options, outputOptions, parsedOptions.autoSetSourceMap); | ||
validatePaths(ts, this, parsedOptions.options, outputOptions); | ||
}, | ||
resolveId(importee, importer) { | ||
var _a; | ||
if (importee === 'tslib') { | ||
return TSLIB_ID; | ||
return tslib; | ||
} | ||
@@ -446,9 +503,8 @@ if (!importer) | ||
// Convert path from windows separators to posix separators | ||
const containingFile = importer.split(win32.sep).join(posix.sep); | ||
const resolved = host.resolveModuleNames([importee], containingFile); | ||
const resolvedFile = (_a = resolved[0]) === null || _a === void 0 ? void 0 : _a.resolvedFileName; | ||
if (resolvedFile) { | ||
if (resolvedFile.endsWith('.d.ts')) | ||
const containingFile = normalizePath(importer); | ||
const resolved = resolveModule(importee, containingFile); | ||
if (resolved) { | ||
if (resolved.extension === '.d.ts') | ||
return null; | ||
return resolvedFile; | ||
return resolved.resolvedFileName; | ||
} | ||
@@ -458,27 +514,27 @@ return null; | ||
load(id) { | ||
if (id === TSLIB_ID) { | ||
return tslib; | ||
} | ||
return null; | ||
}, | ||
transform(code, id) { | ||
if (!filter(id)) | ||
return null; | ||
host.addFile(id, code); | ||
const output = services.getEmitOutput(id); | ||
if (output.emitSkipped) { | ||
// Emit failed, print all diagnostics for this file | ||
const allDiagnostics = [] | ||
.concat(services.getSyntacticDiagnostics(id)) | ||
.concat(services.getSemanticDiagnostics(id)); | ||
emitDiagnostics(ts, this, host, allDiagnostics); | ||
throw new Error(`Couldn't compile ${id}`); | ||
const output = findTypescriptOutput(ts, parsedOptions, id, emittedFiles); | ||
output.declarations.forEach((declaration) => declarationFiles.add(declaration)); | ||
return output.code ? output : null; | ||
}, | ||
generateBundle(outputOptions) { | ||
for (const id of declarationFiles) { | ||
const code = emittedFiles.get(id); | ||
if (code) { | ||
this.emitFile({ | ||
type: 'asset', | ||
fileName: normalizePath(relative(outputOptions.dir, id)), | ||
source: code | ||
}); | ||
} | ||
} | ||
return typescriptOutputToRollupTransformation(output.outputFiles); | ||
}, | ||
generateBundle() { | ||
const program = services.getProgram(); | ||
if (program == null) | ||
return; | ||
emitDiagnostics(ts, this, host, ts.getPreEmitDiagnostics(program)); | ||
const tsBuildInfoPath = ts.getTsBuildInfoEmitOutputFilePath(parsedOptions.options); | ||
if (tsBuildInfoPath) { | ||
this.emitFile({ | ||
type: 'asset', | ||
fileName: normalizePath(relative(outputOptions.dir, tsBuildInfoPath)), | ||
source: emittedFiles.get(tsBuildInfoPath) | ||
}); | ||
} | ||
} | ||
@@ -485,0 +541,0 @@ }; |
@@ -6,87 +6,40 @@ 'use strict'; | ||
var path = require('path'); | ||
var fs = require('fs'); | ||
var pluginutils = require('@rollup/pluginutils'); | ||
var defaultTs = require('typescript'); | ||
var resolveId = _interopDefault(require('resolve')); | ||
var fs = require('fs'); | ||
// `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` | ||
const CANNOT_COMPILE_ESM = 1204; | ||
/** | ||
* For each type error reported by Typescript, emit a Rollup warning or error. | ||
* Create a format diagnostics host to use with the Typescript type checking APIs. | ||
* Typescript hosts are used to represent the user's system, | ||
* with an API for checking case sensitivity etc. | ||
* @param compilerOptions Typescript compiler options. Affects functions such as `getNewLine`. | ||
* @see https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API | ||
*/ | ||
function emitDiagnostics(ts, context, host, diagnostics) { | ||
if (!diagnostics) | ||
return; | ||
const { noEmitOnError } = host.getCompilationSettings(); | ||
diagnostics | ||
.filter((diagnostic) => diagnostic.code !== CANNOT_COMPILE_ESM) | ||
.forEach((diagnostic) => { | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = diagnosticToWarning(ts, host, diagnostic); | ||
// Errors are fatal. Otherwise emit warnings. | ||
if (noEmitOnError && diagnostic.category === ts.DiagnosticCategory.Error) { | ||
context.error(warning); | ||
} | ||
else { | ||
context.warn(warning); | ||
} | ||
}); | ||
} | ||
/** | ||
* Converts a Typescript type error into an equivalent Rollup warning object. | ||
*/ | ||
function diagnosticToWarning(ts, host, diagnostic) { | ||
const pluginCode = `TS${diagnostic.code}`; | ||
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = { | ||
pluginCode, | ||
message: `@rollup/plugin-typescript ${pluginCode}: ${message}` | ||
function createFormattingHost(ts, compilerOptions) { | ||
return { | ||
/** Returns the compiler options for the project. */ | ||
getCompilationSettings: () => compilerOptions, | ||
/** Returns the current working directory. */ | ||
getCurrentDirectory: () => process.cwd(), | ||
/** Returns the string that corresponds with the selected `NewLineKind`. */ | ||
getNewLine() { | ||
switch (compilerOptions.newLine) { | ||
case ts.NewLineKind.CarriageReturnLineFeed: | ||
return '\r\n'; | ||
case ts.NewLineKind.LineFeed: | ||
return '\n'; | ||
default: | ||
return ts.sys.newLine; | ||
} | ||
}, | ||
/** Returns a lower case name on case insensitive systems, otherwise the original name. */ | ||
getCanonicalFileName: (fileName) => ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase() | ||
}; | ||
if (diagnostic.file) { | ||
// Add information about the file location | ||
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); | ||
warning.loc = { | ||
column: character + 1, | ||
line: line + 1, | ||
file: diagnostic.file.fileName | ||
}; | ||
if (host) { | ||
// Extract a code frame from Typescript | ||
const formatted = ts.formatDiagnosticsWithColorAndContext([diagnostic], host); | ||
// Typescript only exposes this formatter as a string prefixed with the flattened message. | ||
// We need to remove it here since Rollup treats the properties as separate parts. | ||
let frame = formatted.slice(formatted.indexOf(message) + message.length); | ||
const newLine = host.getNewLine(); | ||
if (frame.startsWith(newLine)) { | ||
frame = frame.slice(frame.indexOf(newLine) + newLine.length); | ||
} | ||
warning.frame = frame; | ||
} | ||
} | ||
return warning; | ||
} | ||
/** | ||
* Map of Typescript instances to paths to DocumentRegistries. | ||
*/ | ||
const globalRegistryCache = new Map(); | ||
/** | ||
* Return a `DocumentRegistry` instance that matches the given Typescript instance | ||
* and working directory. If there is no a pre-existing instance, one will be | ||
* created and set in the map. | ||
*/ | ||
function getDocumentRegistry(ts, cwd) { | ||
if (!globalRegistryCache.has(ts)) { | ||
globalRegistryCache.set(ts, new Map()); | ||
} | ||
const instanceRegistryCache = globalRegistryCache.get(ts); | ||
if (!instanceRegistryCache.has(cwd)) { | ||
instanceRegistryCache.set(cwd, ts.createDocumentRegistry(ts.sys.useCaseSensitiveFileNames, cwd)); | ||
} | ||
return instanceRegistryCache.get(cwd); | ||
} | ||
/** | ||
* Create a helper for resolving modules using Typescript. | ||
* @param host Typescript host that extends `ModuleResolutionHost` | ||
* with methods for sanitizing filenames and getting compiler options. | ||
*/ | ||
@@ -96,4 +49,5 @@ function createModuleResolver(ts, host) { | ||
const cache = ts.createModuleResolutionCache(process.cwd(), host.getCanonicalFileName, compilerOptions); | ||
const moduleHost = Object.assign(Object.assign({}, ts.sys), host); | ||
return (moduleName, containingFile) => { | ||
const resolved = ts.nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache); | ||
const resolved = ts.nodeModuleNameResolver(moduleName, containingFile, compilerOptions, moduleHost, cache); | ||
return resolved.resolvedModule; | ||
@@ -103,83 +57,2 @@ }; | ||
/** | ||
* Create a language service host to use with the Typescript compiler & type checking APIs. | ||
* @param parsedOptions Parsed options for Typescript. | ||
* @param parsedOptions.options Typescript compiler options. Affects functions such as `getNewLine`. | ||
* @param parsedOptions.fileNames Declaration files to include for typechecking. | ||
* @see https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API | ||
*/ | ||
function createHost(ts, parsedOptions) { | ||
const files = new Map(); | ||
/** Get the code stored in a File snapshot. */ | ||
function getCode({ file }) { | ||
return file.getText(0, file.getLength()); | ||
} | ||
/** @see TypescriptHost.addFile */ | ||
function addFile(id, code) { | ||
const existing = files.get(id); | ||
// Don't need to update if nothing changed | ||
if (existing && getCode(existing) === code) | ||
return; | ||
files.set(id, { | ||
file: ts.ScriptSnapshot.fromString(code), | ||
version: existing ? existing.version + 1 : 0 | ||
}); | ||
} | ||
/** Helper that tries to read the file if it hasn't been stored yet */ | ||
function getFile(id) { | ||
if (!files.has(id)) { | ||
const code = ts.sys.readFile(id); | ||
if (code == null) { | ||
throw new Error(`@rollup/plugin-typescript: Could not find ${id}`); | ||
} | ||
addFile(id, code); | ||
} | ||
return files.get(id); | ||
} | ||
parsedOptions.fileNames.forEach((id) => getFile(id)); | ||
let resolver; | ||
const host = { | ||
getCompilationSettings: () => parsedOptions.options, | ||
getCurrentDirectory: () => process.cwd(), | ||
getNewLine: () => getNewLine(ts, parsedOptions.options.newLine), | ||
getCanonicalFileName: (fileName) => ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(), | ||
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, | ||
getDefaultLibFileName: ts.getDefaultLibFilePath, | ||
getDirectories: ts.sys.getDirectories, | ||
directoryExists: ts.sys.directoryExists, | ||
realpath: ts.sys.realpath, | ||
readDirectory: ts.sys.readDirectory, | ||
readFile(fileName, encoding) { | ||
const file = files.get(fileName); | ||
if (file != null) | ||
return getCode(file); | ||
return ts.sys.readFile(fileName, encoding); | ||
}, | ||
fileExists: (fileName) => files.has(fileName) || ts.sys.fileExists(fileName), | ||
getScriptFileNames: () => Array.from(files.keys()), | ||
getScriptSnapshot: (fileName) => getFile(fileName).file, | ||
getScriptVersion: (fileName) => getFile(fileName).version.toString(), | ||
resolveModuleNames(moduleNames, containingFile) { | ||
return moduleNames.map((moduleName) => resolver(moduleName, containingFile)); | ||
}, | ||
addFile | ||
}; | ||
// Declared here because this has a circular reference | ||
resolver = createModuleResolver(ts, host); | ||
return host; | ||
} | ||
/** | ||
* Returns the string that corresponds with the selected `NewLineKind`. | ||
*/ | ||
function getNewLine(ts, kind) { | ||
switch (kind) { | ||
case ts.NewLineKind.CarriageReturnLineFeed: | ||
return '\r\n'; | ||
case ts.NewLineKind.LineFeed: | ||
return '\n'; | ||
default: | ||
return ts.sys.newLine; | ||
} | ||
} | ||
/*! ***************************************************************************** | ||
@@ -212,40 +85,10 @@ Copyright (c) Microsoft Corporation. All rights reserved. | ||
const TSLIB_ID = '\0tslib'; | ||
const readFileAsync = (file) => new Promise((fulfil, reject) => fs.readFile(file, 'utf-8', (err, contents) => (err ? reject(err) : fulfil(contents)))); | ||
const resolveIdAsync = (file, opts) => new Promise((fulfil, reject) => resolveId(file, opts, (err, contents) => (err ? reject(err) : fulfil(contents)))); | ||
/** | ||
* Returns code asynchronously for the tslib helper library. | ||
* @param customHelperCode Overrides the injected helpers with a custom version. | ||
*/ | ||
async function getTsLibCode(customHelperCode) { | ||
if (customHelperCode) | ||
return customHelperCode; | ||
const defaultPath = await resolveIdAsync('tslib/tslib.es6.js', { basedir: __dirname }); | ||
return readFileAsync(defaultPath); | ||
function getTsLibPath() { | ||
return resolveIdAsync('tslib/tslib.es6.js', { basedir: __dirname }); | ||
} | ||
const DEFAULT_COMPILER_OPTIONS = { | ||
module: 'esnext', | ||
sourceMap: true, | ||
noEmitOnError: true | ||
}; | ||
const FORCED_COMPILER_OPTIONS = { | ||
// See: https://github.com/rollup/rollup-plugin-typescript/issues/45 | ||
// See: https://github.com/rollup/rollup-plugin-typescript/issues/142 | ||
declaration: false, | ||
// Delete the `declarationMap` option, as it will cause an error, because we have | ||
// deleted the `declaration` option. | ||
declarationMap: false, | ||
incremental: false, | ||
// eslint-disable-next-line no-undefined | ||
tsBuildInfoFile: undefined, | ||
// Always use tslib | ||
noEmitHelpers: true, | ||
importHelpers: true, | ||
// Typescript needs to emit the code for us to work with | ||
noEmit: false, | ||
emitDeclarationOnly: false, | ||
// Preventing Typescript from resolving code may break compilation | ||
noResolve: false | ||
}; | ||
/** | ||
@@ -259,7 +102,7 @@ * Separate the Rollup plugin options from the Typescript compiler options, | ||
* - `typescript`: Instance of Typescript library (possibly custom). | ||
* - `tslib`: ESM code from the tslib helper library (possibly) | ||
* - `tslib`: ESM code from the tslib helper library (possibly custom). | ||
*/ | ||
function getPluginOptions(options) { | ||
const { include, exclude, tsconfig, typescript, tslib } = options, compilerOptions = __rest(options, ["include", "exclude", "tsconfig", "typescript", "tslib"]); | ||
const filter = pluginutils.createFilter(include || ['*.ts+(|x)', '**/*.ts+(|x)'], exclude || ['*.d.ts', '**/*.d.ts']); | ||
const filter = pluginutils.createFilter(include || ['*.ts+(|x)', '**/*.ts+(|x)'], exclude); | ||
return { | ||
@@ -270,6 +113,113 @@ filter, | ||
typescript: typescript || defaultTs, | ||
tslib: getTsLibCode(tslib) | ||
tslib: tslib || getTsLibPath() | ||
}; | ||
} | ||
/** | ||
* Converts a Typescript type error into an equivalent Rollup warning object. | ||
*/ | ||
function diagnosticToWarning(ts, host, diagnostic) { | ||
const pluginCode = `TS${diagnostic.code}`; | ||
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = { | ||
pluginCode, | ||
message: `@rollup/plugin-typescript ${pluginCode}: ${message}` | ||
}; | ||
if (diagnostic.file) { | ||
// Add information about the file location | ||
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); | ||
warning.loc = { | ||
column: character + 1, | ||
line: line + 1, | ||
file: diagnostic.file.fileName | ||
}; | ||
if (host) { | ||
// Extract a code frame from Typescript | ||
const formatted = ts.formatDiagnosticsWithColorAndContext([diagnostic], host); | ||
// Typescript only exposes this formatter as a string prefixed with the flattened message. | ||
// We need to remove it here since Rollup treats the properties as separate parts. | ||
let frame = formatted.slice(formatted.indexOf(message) + message.length); | ||
const newLine = host.getNewLine(); | ||
if (frame.startsWith(newLine)) { | ||
frame = frame.slice(frame.indexOf(newLine) + newLine.length); | ||
} | ||
warning.frame = frame; | ||
} | ||
} | ||
return warning; | ||
} | ||
const DEFAULT_COMPILER_OPTIONS = { | ||
module: 'esnext', | ||
noEmitOnError: true, | ||
skipLibCheck: true | ||
}; | ||
const FORCED_COMPILER_OPTIONS = { | ||
// Always use tslib | ||
noEmitHelpers: true, | ||
importHelpers: true, | ||
// Typescript needs to emit the code for us to work with | ||
noEmit: false, | ||
emitDeclarationOnly: false, | ||
// Preventing Typescript from resolving code may break compilation | ||
noResolve: false | ||
}; | ||
/* eslint-disable no-param-reassign */ | ||
const DIRECTORY_PROPS = ['outDir', 'declarationDir']; | ||
/** | ||
* Mutates the compiler options to convert paths from relative to absolute. | ||
* This should be used with compiler options passed through the Rollup plugin options, | ||
* not those found from loading a tsconfig.json file. | ||
* @param compilerOptions Compiler options to _mutate_. | ||
* @param relativeTo Paths are resolved relative to this path. | ||
*/ | ||
function makePathsAbsolute(compilerOptions, relativeTo) { | ||
for (const pathProp of DIRECTORY_PROPS) { | ||
if (compilerOptions[pathProp]) { | ||
compilerOptions[pathProp] = path.resolve(relativeTo, compilerOptions[pathProp]); | ||
} | ||
} | ||
} | ||
/** | ||
* Mutates the compiler options to normalize some values for Rollup. | ||
* @param compilerOptions Compiler options to _mutate_. | ||
* @returns True if the source map compiler option was not initially set. | ||
*/ | ||
function normalizeCompilerOptions(ts, compilerOptions) { | ||
let autoSetSourceMap = false; | ||
if (compilerOptions.inlineSourceMap) { | ||
// Force separate source map files for Rollup to work with. | ||
compilerOptions.sourceMap = true; | ||
compilerOptions.inlineSourceMap = false; | ||
} | ||
else if (typeof compilerOptions.sourceMap !== 'boolean') { | ||
// Default to using source maps. | ||
// If the plugin user sets sourceMap to false we keep that option. | ||
compilerOptions.sourceMap = true; | ||
autoSetSourceMap = true; | ||
} | ||
switch (compilerOptions.module) { | ||
case ts.ModuleKind.ES2015: | ||
case ts.ModuleKind.ESNext: | ||
case ts.ModuleKind.CommonJS: | ||
// OK module type | ||
return autoSetSourceMap; | ||
case ts.ModuleKind.None: | ||
case ts.ModuleKind.AMD: | ||
case ts.ModuleKind.UMD: | ||
case ts.ModuleKind.System: { | ||
// Invalid module type | ||
const moduleType = ts.ModuleKind[compilerOptions.module]; | ||
throw new Error(`@rollup/plugin-typescript: The module kind should be 'ES2015' or 'ESNext, found: '${moduleType}'`); | ||
} | ||
default: | ||
// Unknown or unspecified module type, force ESNext | ||
compilerOptions.module = ts.ModuleKind.ESNext; | ||
} | ||
return autoSetSourceMap; | ||
} | ||
/** | ||
* Finds the path to the tsconfig file relative to the current working directory. | ||
@@ -303,3 +253,2 @@ * @param relativePath Relative tsconfig path given by the user. | ||
function readTsConfigFile(ts, tsConfigPath) { | ||
var _a; | ||
const { config, error } = ts.readConfigFile(tsConfigPath, (path) => fs.readFileSync(path, 'utf8')); | ||
@@ -309,7 +258,2 @@ if (error) { | ||
} | ||
const extendedTsConfig = (_a = config) === null || _a === void 0 ? void 0 : _a.extends; | ||
if (extendedTsConfig) { | ||
// Get absolute path of `extends`, starting at basedir of the tsconfig file. | ||
config.extends = path.resolve(process.cwd(), tsConfigPath, '..', extendedTsConfig); | ||
} | ||
return config || {}; | ||
@@ -331,38 +275,4 @@ } | ||
} | ||
const configCache = new Map(); | ||
/** | ||
* Mutates the compiler options to normalize some values for Rollup. | ||
* @param compilerOptions Compiler options to _mutate_. | ||
*/ | ||
function normalizeCompilerOptions(ts, compilerOptions) { | ||
/* eslint-disable no-param-reassign */ | ||
if (compilerOptions.inlineSourceMap) { | ||
// Force separate source map files for Rollup to work with. | ||
compilerOptions.sourceMap = true; | ||
compilerOptions.inlineSourceMap = false; | ||
} | ||
else if (typeof compilerOptions.sourceMap !== 'boolean') { | ||
// Default to using source maps. | ||
// If the plugin user sets sourceMap to false we keep that option. | ||
compilerOptions.sourceMap = true; | ||
} | ||
switch (compilerOptions.module) { | ||
case ts.ModuleKind.ES2015: | ||
case ts.ModuleKind.ESNext: | ||
case ts.ModuleKind.CommonJS: | ||
// OK module type | ||
return; | ||
case ts.ModuleKind.None: | ||
case ts.ModuleKind.AMD: | ||
case ts.ModuleKind.UMD: | ||
case ts.ModuleKind.System: { | ||
// Invalid module type | ||
const moduleType = ts.ModuleKind[compilerOptions.module]; | ||
throw new Error(`@rollup/plugin-typescript: The module kind should be 'ES2015' or 'ESNext, found: '${moduleType}'`); | ||
} | ||
default: | ||
// Unknown or unspecified module type, force ESNext | ||
compilerOptions.module = ts.ModuleKind.ESNext; | ||
} | ||
} | ||
/** | ||
* Parse the Typescript config to use with the plugin. | ||
@@ -379,3 +289,5 @@ * @param ts Typescript library instance. | ||
function parseTypescriptConfig(ts, tsconfig, compilerOptions) { | ||
/* eslint-disable no-undefined */ | ||
const cwd = process.cwd(); | ||
makePathsAbsolute(compilerOptions, cwd); | ||
let parsedConfig; | ||
@@ -386,22 +298,89 @@ // Resolve path to file. If file is not found, pass undefined path to `parseJsonConfigFileContent`. | ||
const tsConfigFile = tsConfigPath ? readTsConfigFile(ts, tsConfigPath) : {}; | ||
const basePath = tsConfigPath ? path.dirname(tsConfigPath) : cwd; | ||
// If compilerOptions has enums, it represents an CompilerOptions object instead of parsed JSON. | ||
// This determines where the data is passed to the parser. | ||
if (containsEnumOptions(compilerOptions)) { | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions) }), ts.sys, cwd, Object.assign(Object.assign({}, compilerOptions), FORCED_COMPILER_OPTIONS), tsConfigPath); | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions) }), ts.sys, basePath, Object.assign(Object.assign({}, compilerOptions), FORCED_COMPILER_OPTIONS), tsConfigPath, undefined, undefined, configCache); | ||
} | ||
else { | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions), compilerOptions) }), ts.sys, cwd, FORCED_COMPILER_OPTIONS, tsConfigPath); | ||
parsedConfig = ts.parseJsonConfigFileContent(Object.assign(Object.assign({}, tsConfigFile), { compilerOptions: Object.assign(Object.assign(Object.assign({}, DEFAULT_COMPILER_OPTIONS), tsConfigFile.compilerOptions), compilerOptions) }), ts.sys, basePath, FORCED_COMPILER_OPTIONS, tsConfigPath, undefined, undefined, configCache); | ||
} | ||
// We only want to automatically add ambient declaration files. | ||
// Normal script files are handled by Rollup. | ||
parsedConfig.fileNames = parsedConfig.fileNames.filter((file) => file.endsWith('.d.ts')); | ||
normalizeCompilerOptions(ts, parsedConfig.options); | ||
return parsedConfig; | ||
const autoSetSourceMap = normalizeCompilerOptions(ts, parsedConfig.options); | ||
return Object.assign(Object.assign({}, parsedConfig), { autoSetSourceMap }); | ||
} | ||
/** | ||
* If errors are detected in the parsed options, | ||
* display all of them as warnings then emit an error. | ||
*/ | ||
function emitParsedOptionsErrors(ts, context, parsedOptions) { | ||
if (parsedOptions.errors.length > 0) { | ||
parsedOptions.errors.forEach((error) => context.warn(diagnosticToWarning(ts, null, error))); | ||
context.error(`@rollup/plugin-typescript: Couldn't process compiler options`); | ||
} | ||
} | ||
/** | ||
* Validate that the `compilerOptions.sourceMap` option matches `outputOptions.sourcemap`. | ||
* @param context Rollup plugin context used to emit warnings. | ||
* @param compilerOptions Typescript compiler options. | ||
* @param outputOptions Rollup output options. | ||
* @param autoSetSourceMap True if the `compilerOptions.sourceMap` property was set to `true` | ||
* by the plugin, not the user. | ||
*/ | ||
function validateSourceMap(context, compilerOptions, outputOptions, autoSetSourceMap) { | ||
if (compilerOptions.sourceMap && !outputOptions.sourcemap && !autoSetSourceMap) { | ||
context.warn(`@rollup/plugin-typescript: Rollup 'sourcemap' option must be set to generate source maps.`); | ||
} | ||
else if (!compilerOptions.sourceMap && outputOptions.sourcemap) { | ||
context.warn(`@rollup/plugin-typescript: Typescript 'sourceMap' compiler option must be set to generate source maps.`); | ||
} | ||
} | ||
/** | ||
* Validate that the out directory used by Typescript can be controlled by Rollup. | ||
* @param context Rollup plugin context used to emit errors. | ||
* @param compilerOptions Typescript compiler options. | ||
* @param outputOptions Rollup output options. | ||
*/ | ||
function validatePaths(ts, context, compilerOptions, outputOptions) { | ||
if (compilerOptions.out) { | ||
context.error(`@rollup/plugin-typescript: Deprecated 'out' option is not supported. Use 'outDir' instead.`); | ||
} | ||
else if (compilerOptions.outFile) { | ||
context.error(`@rollup/plugin-typescript: 'outFile' option is not supported. Use 'outDir' instead.`); | ||
} | ||
for (const dirProperty of DIRECTORY_PROPS) { | ||
if (compilerOptions[dirProperty]) { | ||
if (!outputOptions.dir) { | ||
context.error(`@rollup/plugin-typescript: 'dir' must be used when '${dirProperty}' is specified.`); | ||
} | ||
// Checks if the given path lies within Rollup output dir | ||
const fromRollupDirToTs = path.relative(outputOptions.dir, compilerOptions[dirProperty]); | ||
if (fromRollupDirToTs.startsWith('..')) { | ||
context.error(`@rollup/plugin-typescript: '${dirProperty}' must be located inside 'dir'.`); | ||
} | ||
} | ||
} | ||
const tsBuildInfoPath = ts.getTsBuildInfoEmitOutputFilePath(compilerOptions); | ||
if (tsBuildInfoPath && compilerOptions.incremental) { | ||
if (!outputOptions.dir) { | ||
context.error(`@rollup/plugin-typescript: 'dir' must be used when 'tsBuildInfoFile' or 'incremental' are specified.`); | ||
} | ||
// Checks if the given path lies within Rollup output dir | ||
const fromRollupDirToTs = path.relative(outputOptions.dir, tsBuildInfoPath); | ||
if (fromRollupDirToTs.startsWith('..')) { | ||
context.error(`@rollup/plugin-typescript: 'tsBuildInfoFile' must be located inside 'dir'.`); | ||
} | ||
} | ||
if (compilerOptions.declaration || compilerOptions.declarationMap) { | ||
if (DIRECTORY_PROPS.every((dirProperty) => !compilerOptions[dirProperty])) { | ||
context.error(`@rollup/plugin-typescript: 'outDir' or 'declarationDir' must be specified to generate declaration files.`); | ||
} | ||
} | ||
} | ||
/** | ||
* Checks if the given OutputFile represents some code | ||
*/ | ||
function isCodeOutputFile(file) { | ||
return !isMapOutputFile(file) && !file.name.endsWith('.d.ts'); | ||
function isCodeOutputFile(name) { | ||
return !isMapOutputFile(name) && !name.endsWith('.d.ts'); | ||
} | ||
@@ -411,37 +390,115 @@ /** | ||
*/ | ||
function isMapOutputFile({ name }) { | ||
function isMapOutputFile(name) { | ||
return name.endsWith('.map'); | ||
} | ||
/** | ||
* Transforms a Typescript EmitOutput into a Rollup SourceDescription. | ||
* Finds the corresponding emitted Javascript files for a given Typescript file. | ||
* @param id Path to the Typescript file. | ||
* @param emittedFiles Map of file names to source code, | ||
* containing files emitted by the Typescript compiler. | ||
*/ | ||
function typescriptOutputToRollupTransformation(outputFiles) { | ||
var _a; | ||
const code = outputFiles.find(isCodeOutputFile); | ||
if (code == null) | ||
return null; | ||
const map = outputFiles.find(isMapOutputFile); | ||
function findTypescriptOutput(ts, parsedOptions, id, emittedFiles) { | ||
const emittedFileNames = ts.getOutputFileNames(parsedOptions, id, !ts.sys.useCaseSensitiveFileNames); | ||
const codeFile = emittedFileNames.find(isCodeOutputFile); | ||
const mapFile = emittedFileNames.find(isMapOutputFile); | ||
return { | ||
code: code.text, | ||
map: (_a = map) === null || _a === void 0 ? void 0 : _a.text | ||
code: emittedFiles.get(codeFile), | ||
map: emittedFiles.get(mapFile), | ||
declarations: emittedFileNames.filter((name) => name !== codeFile && name !== mapFile) | ||
}; | ||
} | ||
// `Cannot compile modules into 'es6' when targeting 'ES5' or lower.` | ||
const CANNOT_COMPILE_ESM = 1204; | ||
/** | ||
* Emit a Rollup warning or error for a Typescript type error. | ||
*/ | ||
function emitDiagnostic(ts, context, host, diagnostic) { | ||
if (diagnostic.code === CANNOT_COMPILE_ESM) | ||
return; | ||
const { noEmitOnError } = host.getCompilationSettings(); | ||
// Build a Rollup warning object from the diagnostics object. | ||
const warning = diagnosticToWarning(ts, host, diagnostic); | ||
// Errors are fatal. Otherwise emit warnings. | ||
if (noEmitOnError && diagnostic.category === ts.DiagnosticCategory.Error) { | ||
context.error(warning); | ||
} | ||
else { | ||
context.warn(warning); | ||
} | ||
} | ||
function buildDiagnosticReporter(ts, context, host) { | ||
return function reportDiagnostics(diagnostic) { | ||
emitDiagnostic(ts, context, host, diagnostic); | ||
}; | ||
} | ||
/** | ||
* Create a language service host to use with the Typescript compiler & type checking APIs. | ||
* Typescript hosts are used to represent the user's system, | ||
* with an API for reading files, checking directories and case sensitivity etc. | ||
* @see https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API | ||
*/ | ||
function createWatchHost(ts, context, { formatHost, parsedOptions, writeFile, resolveModule }) { | ||
const createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram; | ||
const baseHost = ts.createWatchCompilerHost(parsedOptions.fileNames, parsedOptions.options, ts.sys, createProgram, buildDiagnosticReporter(ts, context, formatHost), | ||
// Ignore watch status changes | ||
() => { }, parsedOptions.projectReferences); | ||
return Object.assign(Object.assign({}, baseHost), { | ||
/** Override the created program so an in-memory emit is used */ | ||
afterProgramCreate(program) { | ||
const origEmit = program.emit; | ||
// eslint-disable-next-line no-param-reassign | ||
program.emit = (targetSourceFile, _, ...args) => origEmit(targetSourceFile, writeFile, ...args); | ||
return baseHost.afterProgramCreate(program); | ||
}, | ||
/** Add helper to deal with module resolution */ | ||
resolveModuleNames(moduleNames, containingFile) { | ||
return moduleNames.map((moduleName) => resolveModule(moduleName, containingFile)); | ||
} }); | ||
} | ||
function createWatchProgram(ts, context, options) { | ||
return ts.createWatchProgram(createWatchHost(ts, context, options)); | ||
} | ||
function typescript(options = {}) { | ||
const { filter, tsconfig, compilerOptions, tslib, typescript: ts } = getPluginOptions(options); | ||
const emittedFiles = new Map(); | ||
const declarationFiles = new Set(); | ||
const parsedOptions = parseTypescriptConfig(ts, tsconfig, compilerOptions); | ||
const host = createHost(ts, parsedOptions); | ||
const services = ts.createLanguageService(host, getDocumentRegistry(ts, process.cwd())); | ||
parsedOptions.fileNames = parsedOptions.fileNames.filter(filter); | ||
const formatHost = createFormattingHost(ts, parsedOptions.options); | ||
const resolveModule = createModuleResolver(ts, formatHost); | ||
let program = null; | ||
function normalizePath(fileName) { | ||
return fileName.split(path.win32.sep).join(path.posix.sep); | ||
} | ||
return { | ||
name: 'typescript', | ||
buildStart() { | ||
if (parsedOptions.errors.length > 0) { | ||
parsedOptions.errors.forEach((error) => this.warn(diagnosticToWarning(ts, host, error))); | ||
this.error(`@rollup/plugin-typescript: Couldn't process compiler options`); | ||
emitParsedOptionsErrors(ts, this, parsedOptions); | ||
program = createWatchProgram(ts, this, { | ||
formatHost, | ||
resolveModule, | ||
parsedOptions, | ||
writeFile(fileName, data) { | ||
emittedFiles.set(fileName, data); | ||
} | ||
}); | ||
}, | ||
buildEnd() { | ||
var _a; | ||
if (process.env.ROLLUP_WATCH !== 'true') { | ||
// ESLint doesn't understand optional chaining | ||
// eslint-disable-next-line | ||
(_a = program) === null || _a === void 0 ? void 0 : _a.close(); | ||
} | ||
}, | ||
renderStart(outputOptions) { | ||
validateSourceMap(this, parsedOptions.options, outputOptions, parsedOptions.autoSetSourceMap); | ||
validatePaths(ts, this, parsedOptions.options, outputOptions); | ||
}, | ||
resolveId(importee, importer) { | ||
var _a; | ||
if (importee === 'tslib') { | ||
return TSLIB_ID; | ||
return tslib; | ||
} | ||
@@ -451,9 +508,8 @@ if (!importer) | ||
// Convert path from windows separators to posix separators | ||
const containingFile = importer.split(path.win32.sep).join(path.posix.sep); | ||
const resolved = host.resolveModuleNames([importee], containingFile); | ||
const resolvedFile = (_a = resolved[0]) === null || _a === void 0 ? void 0 : _a.resolvedFileName; | ||
if (resolvedFile) { | ||
if (resolvedFile.endsWith('.d.ts')) | ||
const containingFile = normalizePath(importer); | ||
const resolved = resolveModule(importee, containingFile); | ||
if (resolved) { | ||
if (resolved.extension === '.d.ts') | ||
return null; | ||
return resolvedFile; | ||
return resolved.resolvedFileName; | ||
} | ||
@@ -463,27 +519,27 @@ return null; | ||
load(id) { | ||
if (id === TSLIB_ID) { | ||
return tslib; | ||
} | ||
return null; | ||
}, | ||
transform(code, id) { | ||
if (!filter(id)) | ||
return null; | ||
host.addFile(id, code); | ||
const output = services.getEmitOutput(id); | ||
if (output.emitSkipped) { | ||
// Emit failed, print all diagnostics for this file | ||
const allDiagnostics = [] | ||
.concat(services.getSyntacticDiagnostics(id)) | ||
.concat(services.getSemanticDiagnostics(id)); | ||
emitDiagnostics(ts, this, host, allDiagnostics); | ||
throw new Error(`Couldn't compile ${id}`); | ||
const output = findTypescriptOutput(ts, parsedOptions, id, emittedFiles); | ||
output.declarations.forEach((declaration) => declarationFiles.add(declaration)); | ||
return output.code ? output : null; | ||
}, | ||
generateBundle(outputOptions) { | ||
for (const id of declarationFiles) { | ||
const code = emittedFiles.get(id); | ||
if (code) { | ||
this.emitFile({ | ||
type: 'asset', | ||
fileName: normalizePath(path.relative(outputOptions.dir, id)), | ||
source: code | ||
}); | ||
} | ||
} | ||
return typescriptOutputToRollupTransformation(output.outputFiles); | ||
}, | ||
generateBundle() { | ||
const program = services.getProgram(); | ||
if (program == null) | ||
return; | ||
emitDiagnostics(ts, this, host, ts.getPreEmitDiagnostics(program)); | ||
const tsBuildInfoPath = ts.getTsBuildInfoEmitOutputFilePath(parsedOptions.options); | ||
if (tsBuildInfoPath) { | ||
this.emitFile({ | ||
type: 'asset', | ||
fileName: normalizePath(path.relative(outputOptions.dir, tsBuildInfoPath)), | ||
source: emittedFiles.get(tsBuildInfoPath) | ||
}); | ||
} | ||
} | ||
@@ -490,0 +546,0 @@ }; |
{ | ||
"name": "@rollup/plugin-typescript", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"publishConfig": { | ||
@@ -22,6 +22,7 @@ "access": "public" | ||
"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", | ||
"ci:test": "pnpm run test -- --verbose --serial", | ||
"lint": "pnpm run lint:js && pnpm run lint:docs && pnpm run lint:json && pnpm run lint:package", | ||
"lint:docs": "prettier --single-quote --write README.md", | ||
"lint:js": "eslint --fix --cache src test --ext .js,.ts", | ||
"lint:json": "prettier --write **/tsconfig.json", | ||
"lint:package": "prettier --write package.json --plugin=prettier-plugin-package", | ||
@@ -58,3 +59,3 @@ "prebuild": "del-cli dist", | ||
"@rollup/plugin-commonjs": "^11.0.1", | ||
"@rollup/plugin-typescript": "^2.0.1", | ||
"@rollup/plugin-typescript": "^3.0.0", | ||
"buble": "^0.19.8", | ||
@@ -61,0 +62,0 @@ "rollup": "^1.27.14", |
@@ -111,3 +111,3 @@ [npm]: https://img.shields.io/npm/v/@rollup/plugin-typescript | ||
typescript({ | ||
tslib: fs.readFileSync(require.resolve('some-fork-of-tslib')) | ||
tslib: require.resolve('some-fork-of-tslib') | ||
}); | ||
@@ -138,4 +138,2 @@ ``` | ||
- `declaration`, `declarationMap`: This plugin currently cannot emit declaration files. | ||
- `incremental`, `tsBuildInfoFile`: This plugin currently does not support incremental compilation using Typescript. | ||
- `noEmitHelpers`, `importHelpers`: The `tslib` helper module always must be used. | ||
@@ -142,0 +140,0 @@ - `noEmit`, `emitDeclarationOnly`: Typescript needs to emit code for the plugin to work with. |
@@ -0,5 +1,6 @@ | ||
import { FilterPattern } from '@rollup/pluginutils'; | ||
import { Plugin } from 'rollup'; | ||
import { CompilerOptionsValue, TsConfigSourceFile } from 'typescript'; | ||
interface RollupTypescriptOptions { | ||
export interface RollupTypescriptOptions { | ||
/** | ||
@@ -20,3 +21,3 @@ * Other Typescript compiler options. | ||
*/ | ||
include?: string | RegExp | Array<string | RegExp> | null; | ||
include?: FilterPattern; | ||
/** | ||
@@ -26,3 +27,3 @@ * Determine which files are transpiled by Typescript (all `.ts` and | ||
*/ | ||
exclude?: string | RegExp | Array<string | RegExp> | null; | ||
exclude?: FilterPattern; | ||
/** | ||
@@ -29,0 +30,0 @@ * When set to false, ignores any options specified in the config file. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
62598
1075
196
5