Skip to content

Commit 9ecd10c

Browse files
committed
Extension loading and management tools
1 parent 18fb33d commit 9ecd10c

35 files changed

+1016
-108
lines changed

Gulpfile.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
411411
completedDts.pipe(clone())
412412
.pipe(insert.transform((content, file) => {
413413
file.path = nodeStandaloneDefinitionsFile;
414-
return content.replace(/declare (namespace|module) ts/g, 'declare module "typescript"');
414+
return content.replace(/declare (namespace|module) ts {/g, 'declare module "typescript" {\n import * as ts from "typescript";');
415415
}))
416416
]).pipe(gulp.dest(builtLocalDirectory));
417417
});

Jakefile.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ var compilerSources = [
4646
"declarationEmitter.ts",
4747
"emitter.ts",
4848
"program.ts",
49+
"extensions.ts",
4950
"commandLineParser.ts",
5051
"tsc.ts",
5152
"diagnosticInformationMap.generated.ts"
@@ -67,6 +68,7 @@ var servicesSources = [
6768
"declarationEmitter.ts",
6869
"emitter.ts",
6970
"program.ts",
71+
"extensions.ts",
7072
"commandLineParser.ts",
7173
"diagnosticInformationMap.generated.ts"
7274
].map(function (f) {
@@ -131,6 +133,7 @@ var harnessCoreSources = [
131133
"typeWriter.ts",
132134
"fourslashRunner.ts",
133135
"projectsRunner.ts",
136+
"extensionRunner.ts",
134137
"loggedIO.ts",
135138
"rwcRunner.ts",
136139
"test262Runner.ts",
@@ -158,7 +161,7 @@ var harnessSources = harnessCoreSources.concat([
158161
"convertCompilerOptionsFromJson.ts",
159162
"convertTypingOptionsFromJson.ts",
160163
"tsserverProjectSystem.ts",
161-
"matchFiles.ts"
164+
"matchFiles.ts",
162165
].map(function (f) {
163166
return path.join(unittestsDirectory, f);
164167
})).concat([
@@ -524,7 +527,7 @@ compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].conca
524527

525528
// Node package definition file to be distributed without the package. Created by replacing
526529
// 'ts' namespace with '"typescript"' as a module.
527-
var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts/g, 'declare module "typescript"');
530+
var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts {/g, 'declare module "typescript" {\n import * as ts from "typescript";');
528531
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
529532
});
530533

src/compiler/commandLineParser.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ namespace ts {
282282
experimental: true,
283283
description: Diagnostics.Enables_experimental_support_for_emitting_type_metadata_for_decorators
284284
},
285+
{
286+
name: "extensions",
287+
type: "object",
288+
isTSConfigOnly: true,
289+
description: Diagnostics.List_of_compiler_extensions_to_require
290+
},
285291
{
286292
name: "moduleResolution",
287293
type: {
@@ -429,7 +435,7 @@ namespace ts {
429435
name: "strictNullChecks",
430436
type: "boolean",
431437
description: Diagnostics.Enable_strict_null_checks
432-
}
438+
},
433439
];
434440

435441
/* @internal */

src/compiler/core.ts

+78-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
/// <reference path="performance.ts" />
33

44

5+
namespace ts {
6+
export function startsWith(str: string, prefix: string): boolean {
7+
return str.lastIndexOf(prefix, 0) === 0;
8+
}
9+
10+
export function endsWith(str: string, suffix: string): boolean {
11+
const expectedPos = str.length - suffix.length;
12+
return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos;
13+
}
14+
}
15+
516
/* @internal */
617
namespace ts {
718
/**
@@ -178,6 +189,26 @@ namespace ts {
178189
return array1.concat(array2);
179190
}
180191

192+
export function flatten<T>(array1: T[][]): T[] {
193+
if (!array1 || !array1.length) return <any>array1;
194+
return [].concat(...array1);
195+
}
196+
197+
export function groupBy<T>(array: T[], classifier: (item: T) => string): {[index: string]: T[]};
198+
export function groupBy<T>(array: T[], classifier: (item: T) => number): {[index: number]: T[]};
199+
export function groupBy<T>(array: T[], classifier: (item: T) => (string | number)): {[index: string]: T[], [index: number]: T[]} {
200+
if (!array || !array.length) return undefined;
201+
const ret: {[index: string]: T[], [index: number]: T[]} = {};
202+
for (const elem of array) {
203+
const key = classifier(elem);
204+
if (!ret[key]) {
205+
ret[key] = [];
206+
}
207+
ret[key].push(elem);
208+
}
209+
return ret;
210+
}
211+
181212
export function deduplicate<T>(array: T[], areEqual?: (a: T, b: T) => boolean): T[] {
182213
let result: T[];
183214
if (array) {
@@ -908,17 +939,6 @@ namespace ts {
908939
return true;
909940
}
910941

911-
/* @internal */
912-
export function startsWith(str: string, prefix: string): boolean {
913-
return str.lastIndexOf(prefix, 0) === 0;
914-
}
915-
916-
/* @internal */
917-
export function endsWith(str: string, suffix: string): boolean {
918-
const expectedPos = str.length - suffix.length;
919-
return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos;
920-
}
921-
922942
export function fileExtensionIs(path: string, extension: string): boolean {
923943
return path.length > extension.length && endsWith(path, extension);
924944
}
@@ -1195,7 +1215,8 @@ namespace ts {
11951215
export const supportedJavascriptExtensions = [".js", ".jsx"];
11961216
const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions);
11971217

1198-
export function getSupportedExtensions(options?: CompilerOptions): string[] {
1218+
export function getSupportedExtensions(options?: CompilerOptions, loadJS?: boolean): string[] {
1219+
if (loadJS) return supportedJavascriptExtensions;
11991220
return options && options.allowJs ? allSupportedExtensions : supportedTypeScriptExtensions;
12001221
}
12011222

@@ -1373,4 +1394,49 @@ namespace ts {
13731394
: ((fileName) => fileName.toLowerCase());
13741395
}
13751396

1397+
/**
1398+
* This isn't the strictest deep equal, but it's good enough for us
1399+
* - +0 === -0 (though who really wants to consider them different?)
1400+
* - arguments and arrays can be equal (both typeof === object, both have enumerable keys)
1401+
* - doesn't inspect es6 iterables (not that they're used in this code base)
1402+
* - doesn't inspect regex toString value (so only references to the same regex are equal)
1403+
* - doesn't inspect date primitive number value (so only references to the same date are equal)
1404+
*/
1405+
export function deepEqual(a: any, b: any, memo?: [any, any][]): boolean {
1406+
if (a === b) return true;
1407+
if (typeof a !== typeof b) return false;
1408+
// Special case NaN
1409+
if (typeof a === "number" && isNaN(a) && isNaN(b)) return true;
1410+
// We can't know if function arguments are deep equal, so we say they're equal if they look alike
1411+
if (typeof a === "object" || typeof a === "function") {
1412+
if (memo) {
1413+
for (let i = 0; i < memo.length; i++) {
1414+
if (memo[i][0] === a && memo[i][1] === b) return true;
1415+
if (memo[i][0] === b && memo[i][1] === a) return true;
1416+
}
1417+
}
1418+
else {
1419+
memo = [];
1420+
}
1421+
1422+
const aKeys = ts.getKeys(a);
1423+
const bKeys = ts.getKeys(b);
1424+
aKeys.sort();
1425+
bKeys.sort();
1426+
1427+
if (aKeys.length !== bKeys.length) return false;
1428+
1429+
for (let i = 0; i < aKeys.length; i++) {
1430+
if (aKeys[i] !== bKeys[i]) return false;
1431+
}
1432+
1433+
memo.push([a, b]);
1434+
1435+
for (const key of aKeys) {
1436+
if (!deepEqual(a[key], b[key], memo)) return false;
1437+
}
1438+
return true;
1439+
}
1440+
return false;
1441+
}
13761442
}

src/compiler/diagnosticMessages.json

+14-4
Original file line numberDiff line numberDiff line change
@@ -2676,7 +2676,7 @@
26762676
"category": "Message",
26772677
"code": 6099
26782678
},
2679-
"'package.json' does not have 'types' field.": {
2679+
"'package.json' does not have '{0}' field.": {
26802680
"category": "Message",
26812681
"code": 6100
26822682
},
@@ -2696,7 +2696,7 @@
26962696
"category": "Message",
26972697
"code": 6104
26982698
},
2699-
"Expected type of '{0}' field in 'package.json' to be 'string', got '{1}'.": {
2699+
"Expected type of '{0}' field in 'package.json' to be '{1}', got '{2}'.": {
27002700
"category": "Message",
27012701
"code": 6105
27022702
},
@@ -2824,10 +2824,20 @@
28242824
"category": "Message",
28252825
"code": 6136
28262826
},
2827-
"No types specified in 'package.json' but 'allowJs' is set, so returning 'main' value of '{0}'": {
2827+
2828+
"List of compiler extensions to require.": {
28282829
"category": "Message",
2829-
"code": 6137
2830+
"code": 6150
2831+
},
2832+
"Extension loading failed with error '{0}'.": {
2833+
"category": "Error",
2834+
"code": 6151
28302835
},
2836+
"Extension '{0}' exported member '{1}' has extension kind '{2}', but was type '{3}' when type '{4}' was expected.": {
2837+
"category": "Error",
2838+
"code": 6152
2839+
},
2840+
28312841
"Variable '{0}' implicitly has an '{1}' type.": {
28322842
"category": "Error",
28332843
"code": 7005

0 commit comments

Comments
 (0)