Skip to content

Commit

Permalink
Resolve issue #1652
Browse files Browse the repository at this point in the history
  • Loading branch information
ericmorand committed Dec 17, 2023
1 parent 33174f9 commit 42370bc
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 29 deletions.
64 changes: 43 additions & 21 deletions packages/typescript/src/index.ts
Expand Up @@ -2,7 +2,7 @@ import * as path from 'path';

import { createFilter } from '@rollup/pluginutils';

import type { Plugin, SourceDescription } from 'rollup';
import type { Plugin, PluginContext, SourceDescription } from 'rollup';
import type { Watch } from 'typescript';

import type { RollupTypescriptOptions } from '../types';
Expand Down Expand Up @@ -37,6 +37,31 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi
tslib,
typescript: ts
} = getPluginOptions(options);
const createProgram = (context: PluginContext) =>
createWatchProgram(ts, context, {
formatHost,
resolveModule,
parsedOptions,
writeFile(fileName, data, _writeByteOrderMark, _onError, sourceFiles) {
if (sourceFiles) {
for (const sourceFile of sourceFiles) {
if (!parsedOptions.fileNames.includes(sourceFile.fileName)) {
parsedOptions.fileNames.push(sourceFile.fileName);
}
}
}

if (parsedOptions.options.composite || parsedOptions.options.incremental) {
tsCache.cacheCode(fileName, data);
}
emittedFiles.set(fileName, data);
},
status(diagnostic) {
watchProgramHelper.handleStatus(diagnostic);
},
transformers
});

const tsCache = new TSCache(cacheDir);
const emittedFiles = new Map<string, string>();
const watchProgramHelper = new WatchProgramHelper();
Expand All @@ -56,6 +81,14 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi
name: 'typescript',

buildStart(rollupOptions) {
if (typeof rollupOptions.input === 'string') {
rollupOptions.input = [rollupOptions.input];
}

if (Array.isArray(rollupOptions.input)) {
parsedOptions.fileNames = rollupOptions.input.map((fileName) => path.resolve(fileName));
}

emitParsedOptionsErrors(ts, this, parsedOptions);

preflight({
Expand All @@ -74,21 +107,7 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi
program = null;
}
if (!program) {
program = createWatchProgram(ts, this, {
formatHost,
resolveModule,
parsedOptions,
writeFile(fileName, data) {
if (parsedOptions.options.composite || parsedOptions.options.incremental) {
tsCache.cacheCode(fileName, data);
}
emittedFiles.set(fileName, data);
},
status(diagnostic) {
watchProgramHelper.handleStatus(diagnostic);
},
transformers
});
program = createProgram(this);
}
},

Expand Down Expand Up @@ -139,7 +158,6 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi

if (resolved) {
if (/\.d\.[cm]?ts/.test(resolved.extension)) return null;
if (!filter(resolved.resolvedFileName)) return null;
return path.normalize(resolved.resolvedFileName);
}

Expand All @@ -149,16 +167,20 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi
async load(id) {
if (!filter(id)) return null;

this.addWatchFile(id);
const resolvedId = path.resolve(id);

this.addWatchFile(resolvedId);
await watchProgramHelper.wait();

const fileName = normalizePath(id);
const fileName = normalizePath(resolvedId);
if (!parsedOptions.fileNames.includes(fileName)) {
// Discovered new file that was not known when originally parsing the TypeScript config
parsedOptions.fileNames.push(fileName);
parsedOptions.fileNames.push(path.resolve(fileName));

createProgram(this).close();
}

const output = findTypescriptOutput(ts, parsedOptions, id, emittedFiles, tsCache);
const output = findTypescriptOutput(ts, parsedOptions, resolvedId, emittedFiles, tsCache);

return output.code != null ? (output as SourceDescription) : null;
},
Expand Down
@@ -0,0 +1,2 @@
// eslint-disable-next-line
foo
@@ -0,0 +1,3 @@
import {foo} from "./valid";

console.log(foo);
@@ -0,0 +1 @@
export const foo = 5;
18 changes: 17 additions & 1 deletion packages/typescript/test/test.js
Expand Up @@ -1074,7 +1074,8 @@ test.serial('does it support tsconfig.rootDir for filtering', async (t) => {
t.is(files.length, 1);
});

test.serial('does it fail for filtering with incorrect rootDir in nested projects', async (t) => {
// todo: why would want to deliberately forbid resolution from outside of CWD? What problem does it solve to add such a constraint?
test.skip('does it fail for filtering with incorrect rootDir in nested projects', async (t) => {
process.chdir('fixtures/root-dir/packages/test-2');
const error = await t.throwsAsync(
rollup({
Expand Down Expand Up @@ -1420,3 +1421,18 @@ test.serial('compiled external library', async (t) => {
});
t.pass();
});

test.serial(
'do not consider files that are not part of the entry point dependency graph',
async (t) => {
process.chdir('fixtures/with-invalid-sources-inside-cwd');
const input = 'main.ts';

const build = await rollup({
input,
plugins: [typescript()]
});

t.deepEqual(build.watchFiles, [path.resolve('main.ts'), path.resolve('valid.ts')]);
}
);
18 changes: 11 additions & 7 deletions packages/typescript/test/tslib.ts
@@ -1,5 +1,7 @@
import { platform } from 'os';

import { resolve } from 'path';

import test from 'ava';
import type { RollupError } from 'rollup';
import { rollup } from 'rollup';
Expand Down Expand Up @@ -62,13 +64,15 @@ test.serial('fails on bad tslib path', async (t) => {
return;
}

if (error.watchFiles) {
let [filePath] = error.watchFiles;
filePath = filePath.substring(filePath.indexOf('packages'));
error.watchFiles[0] = filePath;
}

t.snapshot(error);
t.deepEqual(
error.message,
`Could not load fixtures/joker/tslib.js (imported by fixtures/overriding-tslib/main.ts): ENOENT: no such file or directory, open 'fixtures/joker/tslib.js'`
);
t.deepEqual(error.watchFiles, [
resolve('fixtures/overriding-tslib/main.ts'),
'fixtures/joker/tslib.js'
]);
t.deepEqual(error.code, 'ENOENT');
});

test.serial('fails without tslib installed', async (t) => {
Expand Down

0 comments on commit 42370bc

Please sign in to comment.