Skip to content

Commit db6f850

Browse files
authored
When TS returns emitSkipped, fallback to transpileOnly (#1629)
* When TS returns emitSkipped, fallback to transpileOnly * fix failing windows test
1 parent 01d7ecd commit db6f850

File tree

5 files changed

+51
-13
lines changed

5 files changed

+51
-13
lines changed

.prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ tests/throw error.ts
1111
tests/throw error react tsx.tsx
1212
tests/esm/throw error.ts
1313
tests/legacy-source-map-support-interop/index.ts
14+
tests/main-realpath/symlink/symlink.tsx

src/index.ts

+17-13
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ export function create(rawOptions: CreateOptions = {}): Service {
10161016
if (diagnosticList.length) reportTSError(diagnosticList);
10171017

10181018
if (output.emitSkipped) {
1019-
throw new TypeError(`${relative(cwd, fileName)}: Emit skipped`);
1019+
return [undefined, undefined, true];
10201020
}
10211021

10221022
// Throw an error when requiring `.d.ts` files.
@@ -1029,7 +1029,7 @@ export function create(rawOptions: CreateOptions = {}): Service {
10291029
);
10301030
}
10311031

1032-
return [output.outputFiles[1].text, output.outputFiles[0].text];
1032+
return [output.outputFiles[1].text, output.outputFiles[0].text, false];
10331033
};
10341034

10351035
getTypeInfo = (code: string, fileName: string, position: number) => {
@@ -1159,7 +1159,8 @@ export function create(rawOptions: CreateOptions = {}): Service {
11591159
};
11601160

11611161
getOutput = (code: string, fileName: string) => {
1162-
const output: [string, string] = ['', ''];
1162+
let outText = '';
1163+
let outMap = '';
11631164

11641165
updateMemoryCache(code, fileName);
11651166

@@ -1179,9 +1180,9 @@ export function create(rawOptions: CreateOptions = {}): Service {
11791180
sourceFile,
11801181
(path, file, writeByteOrderMark) => {
11811182
if (path.endsWith('.map')) {
1182-
output[1] = file;
1183+
outMap = file;
11831184
} else {
1184-
output[0] = file;
1185+
outText = file;
11851186
}
11861187

11871188
if (options.emit) sys.writeFile(path, file, writeByteOrderMark);
@@ -1192,11 +1193,11 @@ export function create(rawOptions: CreateOptions = {}): Service {
11921193
);
11931194

11941195
if (result.emitSkipped) {
1195-
throw new TypeError(`${relative(cwd, fileName)}: Emit skipped`);
1196+
return [undefined, undefined, true];
11961197
}
11971198

11981199
// Throw an error when requiring files that cannot be compiled.
1199-
if (output[0] === '') {
1200+
if (outText === '') {
12001201
if (program.isSourceFileFromExternalLibrary(sourceFile)) {
12011202
throw new TypeError(
12021203
`Unable to compile file from external library: ${relative(
@@ -1214,7 +1215,7 @@ export function create(rawOptions: CreateOptions = {}): Service {
12141215
);
12151216
}
12161217

1217-
return output;
1218+
return [outText, outMap, false];
12181219
};
12191220

12201221
getTypeInfo = (code: string, fileName: string, position: number) => {
@@ -1291,7 +1292,7 @@ export function create(rawOptions: CreateOptions = {}): Service {
12911292
);
12921293
if (diagnosticList.length) reportTSError(diagnosticList);
12931294

1294-
return [result.outputText, result.sourceMapText as string];
1295+
return [result.outputText, result.sourceMapText as string, false];
12951296
};
12961297
}
12971298

@@ -1308,24 +1309,27 @@ export function create(rawOptions: CreateOptions = {}): Service {
13081309
: createTranspileOnlyGetOutputFunction(
13091310
ts.ModuleKind.ES2020 || ts.ModuleKind.ES2015
13101311
);
1312+
const getOutputTranspileOnly = createTranspileOnlyGetOutputFunction();
13111313

13121314
// Create a simple TypeScript compiler proxy.
13131315
function compile(code: string, fileName: string, lineOffset = 0) {
13141316
const normalizedFileName = normalizeSlashes(fileName);
13151317
const classification =
13161318
moduleTypeClassifier.classifyModule(normalizedFileName);
13171319
// Must always call normal getOutput to throw typechecking errors
1318-
let [value, sourceMap] = getOutput(code, normalizedFileName);
1320+
let [value, sourceMap, emitSkipped] = getOutput(code, normalizedFileName);
13191321
// If module classification contradicts the above, call the relevant transpiler
13201322
if (classification.moduleType === 'cjs' && getOutputForceCommonJS) {
13211323
[value, sourceMap] = getOutputForceCommonJS(code, normalizedFileName);
13221324
} else if (classification.moduleType === 'esm' && getOutputForceESM) {
13231325
[value, sourceMap] = getOutputForceESM(code, normalizedFileName);
1326+
} else if (emitSkipped) {
1327+
[value, sourceMap] = getOutputTranspileOnly(code, normalizedFileName);
13241328
}
13251329
const output = updateOutput(
1326-
value,
1330+
value!,
13271331
normalizedFileName,
1328-
sourceMap,
1332+
sourceMap!,
13291333
getExtension
13301334
);
13311335
outputCache.set(normalizedFileName, { content: output });
@@ -1456,7 +1460,7 @@ function registerExtension(
14561460
/**
14571461
* Internal source output.
14581462
*/
1459-
type SourceOutput = [string, string];
1463+
type SourceOutput = [string, string, false] | [undefined, undefined, true];
14601464

14611465
/**
14621466
* Update the output remapping the source map.

src/test/index.spec.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1256,3 +1256,14 @@ test.suite('ts-node', (test) => {
12561256
}
12571257
});
12581258
});
1259+
1260+
test('Falls back to transpileOnly when ts compiler returns emitSkipped', async () => {
1261+
const { err, stdout } = await exec(
1262+
`${CMD_TS_NODE_WITHOUT_PROJECT_FLAG} --project tsconfig.json ./outside-rootDir/foo.js`,
1263+
{
1264+
cwd: join(TEST_DIR, 'emit-skipped-fallback'),
1265+
}
1266+
);
1267+
expect(err).toBe(null);
1268+
expect(stdout).toBe('foo\n');
1269+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// This file causes TS to return emitSkipped because it's outside of rootDir and
2+
// it's .js. I assume this happens because the emit path is the same as the
3+
// input path, and perhaps also because the file is classified "external"
4+
5+
const decorator = () => {};
6+
7+
class Foo {
8+
// Using a decorator to prove this .js file is getting compiled
9+
@decorator
10+
method() {
11+
return 'foo';
12+
}
13+
}
14+
15+
console.log(new Foo().method());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"allowJs": true,
4+
"experimentalDecorators": true,
5+
"rootDir": "rootDir"
6+
}
7+
}

0 commit comments

Comments
 (0)