Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for experimental ".mjs" output #23678

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 24 additions & 20 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,9 +743,9 @@ namespace ts {
export function deduplicate<T>(array: ReadonlyArray<T>, equalityComparer: EqualityComparer<T>, comparer?: Comparer<T>): T[] {
return !array ? undefined :
array.length === 0 ? [] :
array.length === 1 ? array.slice() :
comparer ? deduplicateRelational(array, equalityComparer, comparer) :
deduplicateEquality(array, equalityComparer);
array.length === 1 ? array.slice() :
comparer ? deduplicateRelational(array, equalityComparer, comparer) :
deduplicateEquality(array, equalityComparer);
}

/**
Expand Down Expand Up @@ -1008,15 +1008,17 @@ namespace ts {

export function arrayIterator<T>(array: ReadonlyArray<T>): Iterator<T> {
let i = 0;
return { next: () => {
if (i === array.length) {
return { value: undefined as never, done: true };
}
else {
i++;
return { value: array[i - 1], done: false };
return {
next: () => {
if (i === array.length) {
return { value: undefined as never, done: true };
}
else {
i++;
return { value: array[i - 1], done: false };
}
}
}};
};
}

/**
Expand Down Expand Up @@ -1710,9 +1712,9 @@ namespace ts {
function compareComparableValues(a: string | number, b: string | number) {
return a === b ? Comparison.EqualTo :
a === undefined ? Comparison.LessThan :
b === undefined ? Comparison.GreaterThan :
a < b ? Comparison.LessThan :
Comparison.GreaterThan;
b === undefined ? Comparison.GreaterThan :
a < b ? Comparison.LessThan :
Comparison.GreaterThan;
}

/**
Expand Down Expand Up @@ -1882,8 +1884,8 @@ namespace ts {
export function compareProperties<T, K extends keyof T>(a: T, b: T, key: K, comparer: Comparer<T[K]>) {
return a === b ? Comparison.EqualTo :
a === undefined ? Comparison.LessThan :
b === undefined ? Comparison.GreaterThan :
comparer(a[key], b[key]);
b === undefined ? Comparison.GreaterThan :
comparer(a[key], b[key]);
}

function getDiagnosticFileName(diagnostic: Diagnostic): string {
Expand Down Expand Up @@ -2036,7 +2038,7 @@ namespace ts {
return compilerOptions.target || ScriptTarget.ES3;
}

export function getEmitModuleKind(compilerOptions: {module?: CompilerOptions["module"], target?: CompilerOptions["target"]}) {
export function getEmitModuleKind(compilerOptions: { module?: CompilerOptions["module"], target?: CompilerOptions["target"] }) {
return typeof compilerOptions.module === "number" ?
compilerOptions.module :
getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 ? ModuleKind.ES2015 : ModuleKind.CommonJS;
Expand Down Expand Up @@ -2653,6 +2655,8 @@ namespace ts {
export function getScriptKindFromFileName(fileName: string): ScriptKind {
const ext = fileName.substr(fileName.lastIndexOf("."));
switch (ext.toLowerCase()) {
case Extension.Mjs:
return ScriptKind.JS;
case Extension.Js:
return ScriptKind.JS;
case Extension.Jsx:
Expand All @@ -2674,7 +2678,7 @@ namespace ts {
export const supportedTypeScriptExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Mjs, Extension.Js, Extension.Jsx];
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];

export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>): ReadonlyArray<string> {
Expand Down Expand Up @@ -2760,7 +2764,7 @@ namespace ts {
}
}

const extensionsToRemove = [Extension.Dts, Extension.Ts, Extension.Js, Extension.Tsx, Extension.Jsx];
const extensionsToRemove = [Extension.Dts, Extension.Ts, Extension.Mjs, Extension.Js, Extension.Tsx, Extension.Jsx];
export function removeFileExtension(path: string): string {
for (const ext of extensionsToRemove) {
const extensionless = tryRemoveExtension(path, ext);
Expand Down Expand Up @@ -2822,7 +2826,7 @@ namespace ts {
}
}

function Signature() {} // tslint:disable-line no-empty
function Signature() { } // tslint:disable-line no-empty

function Node(this: Node, kind: SyntaxKind, pos: number, end: number) {
this.pos = pos;
Expand Down
12 changes: 8 additions & 4 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ namespace ts {
return Extension.Jsx;
}
}
return Extension.Js;
return options.target === ScriptTarget.ESNext
&& options.module === ModuleKind.ESNext
&& options.esModuleInterop
&& options.allowSyntheticDefaultImports
&& Extension.Mjs || Extension.Js;
}

/*@internal*/
Expand Down Expand Up @@ -3236,10 +3240,10 @@ namespace ts {
pushNameGenerationScope(/*node*/ undefined);
tempFlags = savedTempFlags;
return result;
}
else {
}
else {
return generateNameCached(getNodeForGeneratedName(name));
}
}
}
else {
// Auto, Loop, and Unique names are cached based on their unique
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/moduleNameResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ namespace ts {
case Extensions.TypeScript:
return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || tryExtension(Extension.Dts);
case Extensions.JavaScript:
return tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
return tryExtension(Extension.Mjs) || tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
}

function tryExtension(ext: Extension): PathAndExtension | undefined {
Expand Down Expand Up @@ -996,7 +996,7 @@ namespace ts {
else {
const jsPath = tryReadPackageJsonFields(/*readTypes*/ false, packageJsonContent, nodeModuleDirectory, state);
if (typeof jsPath === "string") {
subModuleName = removeExtension(removeExtension(jsPath.substring(nodeModuleDirectory.length + 1), Extension.Js), Extension.Jsx) + Extension.Dts;
subModuleName = removeExtension(removeExtension(removeExtension(jsPath.substring(nodeModuleDirectory.length + 1), Extension.Mjs), Extension.Js), Extension.Jsx) + Extension.Dts;
}
else {
subModuleName = "index.d.ts";
Expand Down Expand Up @@ -1068,7 +1068,7 @@ namespace ts {
function extensionIsOk(extensions: Extensions, extension: Extension): boolean {
switch (extensions) {
case Extensions.JavaScript:
return extension === Extension.Js || extension === Extension.Jsx;
return extension === Extension.Mjs || extension === Extension.Js || extension === Extension.Jsx;
case Extensions.TypeScript:
return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Dts;
case Extensions.DtsOnly:
Expand Down
7 changes: 4 additions & 3 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,14 +328,14 @@ namespace ts {

output += formatColorAndReset(relativeFileName, ForegroundColorEscapeSequences.Cyan);
output += ":";
output += formatColorAndReset(`${ firstLine + 1 }`, ForegroundColorEscapeSequences.Yellow);
output += formatColorAndReset(`${firstLine + 1}`, ForegroundColorEscapeSequences.Yellow);
output += ":";
output += formatColorAndReset(`${ firstLineChar + 1 }`, ForegroundColorEscapeSequences.Yellow);
output += formatColorAndReset(`${firstLineChar + 1}`, ForegroundColorEscapeSequences.Yellow);
output += " - ";
}

output += formatColorAndReset(diagnosticCategoryName(diagnostic), getCategoryFormat(diagnostic.category));
output += formatColorAndReset(` TS${ diagnostic.code }: `, ForegroundColorEscapeSequences.Grey);
output += formatColorAndReset(` TS${diagnostic.code}: `, ForegroundColorEscapeSequences.Grey);
output += flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine());

if (diagnostic.file) {
Expand Down Expand Up @@ -2428,6 +2428,7 @@ namespace ts {
return needJsx();
case Extension.Jsx:
return needJsx() || needAllowJs();
case Extension.Mjs:
case Extension.Js:
return needAllowJs();
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/resolutionCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ namespace ts {
* This helps in not having to comb through all resolutions when files are added/removed
* Note that .d.ts file also has .d.ts extension hence will be part of default extensions
*/
const failedLookupDefaultExtensions = [Extension.Ts, Extension.Tsx, Extension.Js, Extension.Jsx, Extension.Json];
const failedLookupDefaultExtensions = [Extension.Ts, Extension.Tsx, Extension.Mjs, Extension.Js, Extension.Jsx, Extension.Json];
const customFailedLookupPaths = createMap<number>();

const directoryWatchesOfFailedLookups = createMap<DirectoryWatchesOfFailedLookup>();
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4583,6 +4583,7 @@ namespace ts {
Ts = ".ts",
Tsx = ".tsx",
Dts = ".d.ts",
Mjs = ".mjs",
Js = ".js",
Jsx = ".jsx",
Json = ".json"
Expand Down
45 changes: 29 additions & 16 deletions src/harness/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ namespace Utils {
export function memoize<T extends ts.AnyFunction>(f: T, memoKey: (...anything: any[]) => string): T {
const cache = ts.createMap<any>();

return <any>(function(this: any, ...args: any[]) {
return <any>(function (this: any, ...args: any[]) {
const key = memoKey(...args);
if (cache.has(key)) {
return cache.get(key);
Expand Down Expand Up @@ -1343,7 +1343,7 @@ namespace Harness {
export function getErrorBaseline(inputFiles: ReadonlyArray<TestFile>, diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean) {
let outputLines = "";
const gen = iterateErrorBaseline(inputFiles, diagnostics, pretty);
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
for (let { done, value } = gen.next(); !done; { done, value } = gen.next()) {
const [, content] = value;
outputLines += content;
}
Expand All @@ -1352,7 +1352,7 @@ namespace Harness {

export const diagnosticSummaryMarker = "__diagnosticSummary";
export const globalErrorsMarker = "__globalErrors";
export function *iterateErrorBaseline(inputFiles: ReadonlyArray<TestFile>, diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean): IterableIterator<[string, string, number]> {
export function* iterateErrorBaseline(inputFiles: ReadonlyArray<TestFile>, diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean): IterableIterator<[string, string, number]> {
diagnostics = ts.sort(diagnostics, ts.compareDiagnostics);
let outputLines = "";
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
Expand Down Expand Up @@ -1496,7 +1496,7 @@ namespace Harness {
});
}

export function doTypeAndSymbolBaseline(baselinePath: string, program: ts.Program, allFiles: {unitName: string, content: string}[], opts?: Baseline.BaselineOptions, multifile?: boolean, skipTypeBaselines?: boolean, skipSymbolBaselines?: boolean) {
export function doTypeAndSymbolBaseline(baselinePath: string, program: ts.Program, allFiles: { unitName: string, content: string }[], opts?: Baseline.BaselineOptions, multifile?: boolean, skipTypeBaselines?: boolean, skipSymbolBaselines?: boolean) {
// The full walker simulates the types that you would get from doing a full
// compile. The pull walker simulates the types you get when you just do
// a type query for a random node (like how the LS would do it). Most of the
Expand Down Expand Up @@ -1567,7 +1567,7 @@ namespace Harness {
function generateBaseLine(isSymbolBaseline: boolean, skipBaseline?: boolean): string {
let result = "";
const gen = iterateBaseLine(isSymbolBaseline, skipBaseline);
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
for (let { done, value } = gen.next(); !done; { done, value } = gen.next()) {
const [, content] = value;
result += content;
}
Expand All @@ -1576,7 +1576,7 @@ namespace Harness {
/* tslint:enable:no-null-keyword */
}

function *iterateBaseLine(isSymbolBaseline: boolean, skipBaseline?: boolean): IterableIterator<[string, string]> {
function* iterateBaseLine(isSymbolBaseline: boolean, skipBaseline?: boolean): IterableIterator<[string, string]> {
if (skipBaseline) {
return;
}
Expand All @@ -1588,7 +1588,7 @@ namespace Harness {
const codeLines = ts.flatMap(file.content.split(/\r?\n/g), e => e.split(/[\r\u2028\u2029]/g));
const gen: IterableIterator<TypeWriterResult> = isSymbolBaseline ? fullWalker.getSymbols(unitName) : fullWalker.getTypes(unitName);
let lastIndexWritten: number | undefined;
for (let {done, value: result} = gen.next(); !done; { done, value: result } = gen.next()) {
for (let { done, value: result } = gen.next(); !done; { done, value: result } = gen.next()) {
if (isSymbolBaseline && !result.symbol) {
return;
}
Expand Down Expand Up @@ -1644,7 +1644,14 @@ namespace Harness {
throw new Error("Number of sourcemap files should be same as js files.");
}

Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js.map"), () => {
const outExt = options.target === ts.ScriptTarget.ESNext
&& options.module === ts.ModuleKind.ESNext
&& options.esModuleInterop
&& options.allowSyntheticDefaultImports
? ts.Extension.Mjs : ts.Extension.Js;
const mapExt = `${outExt}.map`;

Baseline.runBaseline(baselinePath.replace(/\.tsx?/, mapExt), () => {
if ((options.noEmitOnError && result.errors.length !== 0) || result.sourceMaps.length === 0) {
// We need to return null here or the runBaseLine will actually create a empty file.
// Baselining isn't required here because there is no output.
Expand All @@ -1668,8 +1675,11 @@ namespace Harness {
throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
}

const outExt = options.target === ts.ScriptTarget.ESNext
? ts.Extension.Mjs : ts.Extension.Js;

// check js output
Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ts.Extension.Js), () => {
Baseline.runBaseline(baselinePath.replace(/\.tsx?/, outExt), () => {
let tsCode = "";
const tsSources = otherFiles.concat(toBeCompiled);
if (tsSources.length > 1) {
Expand Down Expand Up @@ -1723,7 +1733,7 @@ namespace Harness {
const gen = iterateOutputs(outputFiles);
// Emit them
let result = "";
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
for (let { done, value } = gen.next(); !done; { done, value } = gen.next()) {
// Some extra spacing if this isn't the first file
if (result.length) {
result += "\r\n\r\n";
Expand All @@ -1735,7 +1745,7 @@ namespace Harness {
return result;
}

export function *iterateOutputs(outputFiles: GeneratedFile[]): IterableIterator<[string, string]> {
export function* iterateOutputs(outputFiles: GeneratedFile[]): IterableIterator<[string, string]> {
// Collect, test, and sort the fileNames
outputFiles.sort((a, b) => ts.compareStringsCaseSensitive(cleanName(a.fileName), cleanName(b.fileName)));
const dupeCase = ts.createMap<number>();
Expand Down Expand Up @@ -1797,14 +1807,17 @@ namespace Harness {
}

export function isJS(fileName: string) {
return ts.endsWith(fileName, ts.Extension.Js);
return ts.endsWith(fileName, ts.Extension.Mjs)
|| ts.endsWith(fileName, ts.Extension.Js);
}
export function isJSX(fileName: string) {
return ts.endsWith(fileName, ts.Extension.Jsx);
}

export function isJSMap(fileName: string) {
return ts.endsWith(fileName, ".js.map") || ts.endsWith(fileName, ".jsx.map");
return ts.endsWith(fileName, ".mjs.map")
|| ts.endsWith(fileName, ".js.map")
|| ts.endsWith(fileName, ".jsx.map");
}

export function isDTSMap(fileName: string) {
Expand Down Expand Up @@ -1874,7 +1887,7 @@ namespace Harness {
let match: RegExpExecArray;
/* tslint:disable:no-null-keyword */
while ((match = optionRegex.exec(content)) !== null) {
/* tslint:enable:no-null-keyword */
/* tslint:enable:no-null-keyword */
opts[match[1]] = match[2].trim();
}

Expand Down Expand Up @@ -2056,7 +2069,7 @@ namespace Harness {

/* tslint:disable:no-null-keyword */
if (actual === null) {
/* tslint:enable:no-null-keyword */
/* tslint:enable:no-null-keyword */
actual = noContent;
}

Expand Down Expand Up @@ -2119,7 +2132,7 @@ namespace Harness {
const errors: Error[] = [];
// tslint:disable-next-line:no-null-keyword
if (gen !== null) {
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
for (let { done, value } = gen.next(); !done; { done, value } = gen.next()) {
const [name, content, count] = value as [string, string, number | undefined];
if (count === 0) continue; // Allow error reporter to skip writing files without errors
const relativeFileName = relativeFileBase + "/" + name + extension;
Expand Down
Loading