Skip to content

Commit acaa640

Browse files
committed
fix(extends): fixes & tests for tsconfig extends
1 parent 8241aaa commit acaa640

15 files changed

+211
-87
lines changed

lib/plugin.js

+38-17
Original file line numberDiff line numberDiff line change
@@ -140,27 +140,38 @@ System.register(["typescript"], function (exports_1, context_1) {
140140
}
141141
function loadTsconfigOptions(options, parentAddress, fetchJson) {
142142
return __awaiter(this, void 0, void 0, function () {
143-
var tsconfigName, tsconfigText, result, extendedTsconfig, _a;
143+
var tsconfigName;
144+
return __generator(this, function (_a) {
145+
tsconfigName = options && options.tsconfig;
146+
if (tsconfigName === true)
147+
tsconfigName = 'tsconfig.json';
148+
if (tsconfigName) {
149+
return [2, loadTsconfigFile(tsconfigName, parentAddress, fetchJson)];
150+
}
151+
else {
152+
return [2, undefined];
153+
}
154+
return [2];
155+
});
156+
});
157+
}
158+
function loadTsconfigFile(filename, parentAddress, fetchJson) {
159+
return __awaiter(this, void 0, void 0, function () {
160+
var tsconfigText, result, extendedTsconfig, _a;
144161
return __generator(this, function (_b) {
145162
switch (_b.label) {
146-
case 0:
147-
tsconfigName = options && options.tsconfig;
148-
if (tsconfigName === true)
149-
tsconfigName = 'tsconfig.json';
150-
if (!tsconfigName)
151-
return [3, 7];
152-
return [4, fetchJson(tsconfigName, parentAddress)];
163+
case 0: return [4, fetchJson(filename, parentAddress)];
153164
case 1:
154165
tsconfigText = _b.sent();
155-
result = typescript_1["default"].parseConfigFileTextToJson(tsconfigName, tsconfigText);
166+
result = typescript_1["default"].parseConfigFileTextToJson(filename, tsconfigText);
156167
if (!result.error)
157168
return [3, 2];
158169
formatErrors([result.error], logger$2);
159-
throw new Error("failed to load tsconfig from " + tsconfigName);
170+
throw new Error("failed to load tsconfig from " + filename);
160171
case 2:
161172
if (!result.config["extends"])
162173
return [3, 4];
163-
return [4, loadTsconfigOptions(options, result.config["extends"], fetchJson)];
174+
return [4, loadTsconfigFile(result.config["extends"], filename, fetchJson)];
164175
case 3:
165176
_a = _b.sent();
166177
return [3, 5];
@@ -170,9 +181,6 @@ System.register(["typescript"], function (exports_1, context_1) {
170181
case 5:
171182
extendedTsconfig = _a;
172183
return [2, __assign({}, extendedTsconfig, result.config.compilerOptions)];
173-
case 6: return [3, 8];
174-
case 7: return [2, undefined];
175-
case 8: return [2];
176184
}
177185
});
178186
});
@@ -237,6 +245,16 @@ System.register(["typescript"], function (exports_1, context_1) {
237245
function isJson(filename) {
238246
return jsonRegex.test(filename);
239247
}
248+
function stripDoubleExtension(normalized) {
249+
var parts = normalized.split('.');
250+
if (parts.length > 1) {
251+
var extensions = ["js", "jsx", "ts", "tsx", "json"];
252+
if (extensions.indexOf(parts[parts.length - 2]) >= 0) {
253+
return parts.slice(0, -1).join('.');
254+
}
255+
}
256+
return normalized;
257+
}
240258
function hasError(diags) {
241259
return diags.some(function (diag) { return (diag.category === typescript_1["default"].DiagnosticCategory.Error); });
242260
}
@@ -304,7 +322,7 @@ System.register(["typescript"], function (exports_1, context_1) {
304322
logger.debug("systemjs translating " + load.address);
305323
if (isJson(load.address))
306324
return [2, load.source];
307-
return [4, resolveOptions(load.metadata.typescriptOptions, SystemJS.typescriptOptions, load.address, _fetchJson)];
325+
return [4, resolveOptions(SystemJS.typescriptOptions, load.metadata.typescriptOptions, load.address, _fetchJson)];
308326
case 1:
309327
options = _a.sent();
310328
host.addFile(load.address, load.source, options.target);
@@ -344,11 +362,14 @@ System.register(["typescript"], function (exports_1, context_1) {
344362
exports_1("instantiate", instantiate);
345363
function _fetchJson(fileName, parentAddress) {
346364
return __awaiter(this, void 0, void 0, function () {
347-
var json;
365+
var address, json;
348366
return __generator(this, function (_a) {
349367
switch (_a.label) {
350-
case 0: return [4, SystemJS["import"](fileName + '!' + __moduleName, parentAddress)];
368+
case 0: return [4, SystemJS.normalize(fileName, parentAddress)];
351369
case 1:
370+
address = _a.sent();
371+
return [4, SystemJS["import"](stripDoubleExtension(address) + '!' + __moduleName, parentAddress)];
372+
case 2:
352373
json = _a.sent();
353374
logger.debug("fetched " + fileName);
354375
return [2, JSON.stringify(json)];

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "plugin-typescript",
3-
"version": "8.0.0",
3+
"version": "9.0.0",
44
"description": "TypeScript loader for SystemJS",
55
"main": "lib/plugin.js",
66
"homepage": "https://github.com/frankwallis/plugin-typescript",

src/plugin.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { convertErrors, outputErrors } from './format-errors'
55
import { CompilerHost } from './compiler-host'
66
import { resolveOptions } from './resolve-options'
77
import { transpile } from './transpiler'
8-
import { isTypescript, isTypescriptDeclaration, isJson } from './utils'
8+
import { isTypescript, isTypescriptDeclaration, isJson, stripDoubleExtension } from './utils'
99

1010
const logger = new Logger({ debug: false })
1111
const host = getHost()
@@ -35,8 +35,8 @@ export async function translate(load: Module): Promise<string> {
3535

3636
/* resolve the typescript options for this file, this may involve loading tsconfig.json */
3737
const options = await resolveOptions(
38-
load.metadata.typescriptOptions,
3938
SystemJS.typescriptOptions,
39+
load.metadata.typescriptOptions,
4040
load.address,
4141
_fetchJson)
4242

@@ -93,7 +93,8 @@ export function instantiate(load: Module, origInstantiate: any) {
9393
* called by resolveOptions when it needs to fetch tsconfig.json
9494
*/
9595
async function _fetchJson(fileName: string, parentAddress: string): Promise<string> {
96-
const json = await SystemJS.import(fileName + '!' + __moduleName, parentAddress)
96+
const address = await SystemJS.normalize(fileName, parentAddress);
97+
const json = await SystemJS.import(stripDoubleExtension(address) + '!' + __moduleName, parentAddress)
9798
logger.debug(`fetched ${fileName}`)
9899
return JSON.stringify(json)
99100
}

src/resolve-options.ts

+24-16
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,33 @@ async function loadTsconfigOptions(
3535
if (tsconfigName === true) tsconfigName = 'tsconfig.json'
3636

3737
if (tsconfigName) {
38-
const tsconfigText = await fetchJson(tsconfigName, parentAddress)
39-
const result = ts.parseConfigFileTextToJson(tsconfigName, tsconfigText)
38+
return loadTsconfigFile(tsconfigName, parentAddress, fetchJson);
39+
}
40+
else {
41+
return undefined;
42+
}
43+
}
4044

41-
if (result.error) {
42-
formatErrors([result.error], logger)
43-
throw new Error(`failed to load tsconfig from ${tsconfigName}`)
44-
}
45-
else {
46-
const extendedTsconfig = result.config.extends
47-
? await loadTsconfigOptions(options, result.config.extends, fetchJson)
48-
: undefined
49-
return {
50-
...extendedTsconfig,
51-
...result.config.compilerOptions
52-
}
53-
}
45+
async function loadTsconfigFile(
46+
filename: string,
47+
parentAddress: string,
48+
fetchJson: FetchFunction): Promise<ts.CompilerOptions> {
49+
50+
const tsconfigText = await fetchJson(filename, parentAddress)
51+
const result = ts.parseConfigFileTextToJson(filename, tsconfigText)
52+
53+
if (result.error) {
54+
formatErrors([result.error], logger)
55+
throw new Error(`failed to load tsconfig from ${filename}`)
5456
}
5557
else {
56-
return undefined
58+
const extendedTsconfig = result.config.extends
59+
? await loadTsconfigFile(result.config.extends, filename, fetchJson)
60+
: undefined
61+
return {
62+
...extendedTsconfig,
63+
...result.config.compilerOptions
64+
}
5765
}
5866
}
5967

test/builder-spec.ts

+49-23
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ describe('Builder', () => {
3333
"module": "system",
3434
"target": "es5",
3535
"jsx": "react",
36-
"noImplicitAny": false,
3736
"tsconfig": false
3837
},
3938
packages: {
@@ -46,9 +45,9 @@ describe('Builder', () => {
4645
"main": "plugin.js"
4746
},
4847
"typescript": {
49-
"main": "lib/typescript.js",
48+
"main": "typescript.js",
5049
"meta": {
51-
"lib/typescript.js": {
50+
"typescript.js": {
5251
"exports": "ts"
5352
}
5453
}
@@ -57,34 +56,66 @@ describe('Builder', () => {
5756
map: {
5857
"testsrc": "test/fixtures-es6/plugin/elisions",
5958
"plugin": "lib",
60-
"typescript": "node_modules/typescript"
59+
"typescript": "node_modules/typescript/lib",
60+
"extend1": "test/fixtures-es6/plugin/tsconfig/extend1",
61+
"extend2": "test/fixtures-es6/plugin/tsconfig/extend2"
6162
}
6263
}
6364
}
6465

6566
describe('tsconfig', () => {
66-
it('does not load tsconfig when not configured', () => {
67+
it('does not load tsconfig when not configured', async () => {
6768
const config = defaultConfig() as any
6869
config.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
70+
config.packages["testsrc"].main = "good"
6971
builder.config(config)
70-
return builder.bundle('testsrc')
72+
await builder.bundle('testsrc')
7173
.should.be.fulfilled
74+
75+
const config2 = defaultConfig() as any
76+
config2.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
77+
builder.config(config2)
78+
await builder.bundle('testsrc')
79+
.should.be.rejectedWith(/Octal literals are not allowed in strict mode/)
7280
})
7381

74-
it('supports global tsconfig config option', () => {
82+
xit('supports tsconfig config option true', async () => {
7583
const config = defaultConfig() as any
7684
config.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
77-
delete config.typescriptOptions.module
78-
config.typescriptOptions.tsconfig = "testsrc/tsconfig.json"
85+
config.typescriptOptions.tsconfig = true;
7986
builder.config(config)
80-
return builder.bundle('testsrc')
81-
.should.be.rejectedWith(/transpilation failed/)
87+
await builder.bundle('testsrc').should.be.fulfilled
8288
})
8389

84-
it('supports file tsconfig config option', () => {
90+
it('tsconfig file "extends" supports relative path', async () => {
91+
const config = defaultConfig() as any
92+
config.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
93+
config.typescriptOptions.tsconfig = "test/fixtures-es6/plugin/tsconfig/extends-relative.json"
94+
builder.config(config)
95+
await builder.bundle('testsrc').should.be.fulfilled
96+
})
97+
98+
it('tsconfig file "extends" supports package path', async () => {
99+
const config = defaultConfig() as any
100+
config.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
101+
config.typescriptOptions.tsconfig = "test/fixtures-es6/plugin/tsconfig/extends-package.json"
102+
builder.config(config)
103+
104+
await builder.bundle('testsrc').should.be.fulfilled
105+
})
106+
107+
it('tsconfig file extends supports transitive package path', async () => {
108+
const config = defaultConfig() as any
109+
config.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
110+
config.typescriptOptions.tsconfig = "test/fixtures-es6/plugin/tsconfig/extends-transitive.json"
111+
builder.config(config)
112+
113+
await builder.bundle('testsrc').should.be.fulfilled
114+
})
115+
116+
it('supports file meta tsconfig config option', async () => {
85117
const config = defaultConfig() as any
86118
config.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
87-
delete config.typescriptOptions.module
88119

89120
const meta = {
90121
"*.ts": {
@@ -94,30 +125,25 @@ describe('Builder', () => {
94125
}
95126
}
96127
config.packages.testsrc.meta = meta
97-
98128
builder.config(config)
99-
return builder.bundle('testsrc')
100-
.should.be.rejectedWith(/transpilation failed/)
129+
await builder.bundle('testsrc').should.be.fulfilled
101130
})
102131

103-
it('file option overrides file tsconfig option', () => {
132+
it('file meta option overrides global tsconfig option', async () => {
104133
const config = defaultConfig() as any
105134
config.map["testsrc"] = "test/fixtures-es6/plugin/tsconfig"
106-
delete config.typescriptOptions.module
135+
config.typescriptOptions.noImplicitUseStrict = false;
107136

108137
const meta = {
109138
"*.ts": {
110139
"typescriptOptions": {
111-
"tsconfig": "testsrc/tsconfig.json",
112-
"module": "system"
140+
"noImplicitUseStrict": true
113141
}
114142
}
115143
}
116144
config.packages.testsrc.meta = meta
117-
118145
builder.config(config)
119-
return builder.bundle('testsrc')
120-
.should.be.fulfilled
146+
await builder.bundle('testsrc').should.be.fulfilled
121147
})
122148
})
123149

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
declare module 'testsrc/commonjs' {
2+
export function double(num: number): number;
3+
}
4+
5+
declare module 'testsrc/esm' {
6+
export function triple(num: number): number;
7+
}
8+
9+
declare module 'testsrc/amd' {
10+
export function quadruple(num: number): number;
11+
}
12+
13+
import {double} from 'testsrc/commonjs';
14+
import {triple} from 'testsrc/esm';
15+
import {quadruple} from 'testsrc/amd';
16+
17+
export var total = double(triple(quadruple(2)));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "extend2/tsconfig.json"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"compilerOptions": {
3+
"noImplicitUseStrict": true
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "extend2/tsconfig.json"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "./extend2/tsconfig.json"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "extend1/tsconfig.json"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Should not fail with noImplicitUseStrict: false or undefined
2+
export function add(a: number, b: number): number {
3+
return a + b;
4+
}
5+
6+
console.log(add(1, 2));
+5-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
export var o = 123;
2-
console.log(o);
1+
// Should fail with noImplicitUseStrict: false or undefined
2+
export var x = 010;
3+
export function add(a, b) {
4+
return a + b;
5+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"compilerOptions": {
3-
"module": "none"
3+
"noImplicitUseStrict": true
44
}
55
}

0 commit comments

Comments
 (0)