3990 lines
140 KiB
Go
3990 lines
140 KiB
Go
package tsctests
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/stringtestutil"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/vfstest"
|
|
)
|
|
|
|
func TestTscCommandline(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped",
|
|
env: map[string]string{
|
|
"TS_TEST_TERMINAL_WIDTH": "120",
|
|
},
|
|
commandLineArgs: nil,
|
|
},
|
|
{
|
|
subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped when host cannot provide terminal width",
|
|
commandLineArgs: nil,
|
|
},
|
|
{
|
|
subScenario: "does not add color when NO_COLOR is set",
|
|
env: map[string]string{
|
|
"NO_COLOR": "true",
|
|
},
|
|
commandLineArgs: nil,
|
|
},
|
|
{
|
|
subScenario: "when build not first argument",
|
|
commandLineArgs: []string{"--verbose", "--build"},
|
|
},
|
|
{
|
|
subScenario: "help",
|
|
commandLineArgs: []string{"--help"},
|
|
},
|
|
{
|
|
subScenario: "help all",
|
|
commandLineArgs: []string{"--help", "--all"},
|
|
},
|
|
{
|
|
subScenario: "Parse --lib option with file name",
|
|
files: FileMap{"/home/src/workspaces/project/first.ts": `export const Key = Symbol()`},
|
|
commandLineArgs: []string{"--lib", "es6 ", "first.ts"},
|
|
},
|
|
{
|
|
subScenario: "Project is empty string",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/first.ts": `export const a = 1`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"noEmit": true
|
|
}
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{},
|
|
},
|
|
{
|
|
subScenario: "Parse -p",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/first.ts": `export const a = 1`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"noEmit": true
|
|
}
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"-p", "."},
|
|
},
|
|
{
|
|
subScenario: "Parse -p with path to tsconfig file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/first.ts": `export const a = 1`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"noEmit": true
|
|
}
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"-p", "/home/src/workspaces/project/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "Parse -p with path to tsconfig folder",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/first.ts": `export const a = 1`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"noEmit": true
|
|
}
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"-p", "/home/src/workspaces/project"},
|
|
},
|
|
{
|
|
subScenario: "Parse enum type options",
|
|
commandLineArgs: []string{"--moduleResolution", "nodenext ", "first.ts", "--module", "nodenext", "--target", "esnext", "--moduleDetection", "auto", "--jsx", "react", "--newLine", "crlf"},
|
|
},
|
|
{
|
|
subScenario: "Parse watch interval option",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/first.ts": `export const a = 1`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"noEmit": true
|
|
}
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"-w", "--watchInterval", "1000"},
|
|
},
|
|
{
|
|
subScenario: "Parse watch interval option without tsconfig.json",
|
|
commandLineArgs: []string{"-w", "--watchInterval", "1000"},
|
|
},
|
|
{
|
|
subScenario: "Config with references and empty file and refers to config with noEmit",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`{
|
|
"files": [],
|
|
"references": [
|
|
{
|
|
"path": "./packages/pkg1"
|
|
},
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/project/packages/pkg1/tsconfig.json": stringtestutil.Dedent(`{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"noEmit": true
|
|
},
|
|
"files": [
|
|
"./index.ts",
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/project/packages/pkg1/index.ts": `export const a = 1;`,
|
|
},
|
|
commandLineArgs: []string{"-p", "."},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
testCase.run(t, "commandLine")
|
|
}
|
|
}
|
|
|
|
func TestTscComposite(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "when setting composite false on command line",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"composite": true,
|
|
},
|
|
"include": [
|
|
"src/**/*.ts",
|
|
],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--composite", "false"},
|
|
},
|
|
{
|
|
// !!! sheetal null is not reflected in final options
|
|
subScenario: "when setting composite null on command line",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"composite": true,
|
|
},
|
|
"include": [
|
|
"src/**/*.ts",
|
|
],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--composite", "null"},
|
|
},
|
|
{
|
|
subScenario: "when setting composite false on command line but has tsbuild info in config",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"composite": true,
|
|
"tsBuildInfoFile": "tsconfig.json.tsbuildinfo",
|
|
},
|
|
"include": [
|
|
"src/**/*.ts",
|
|
],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--composite", "false"},
|
|
},
|
|
{
|
|
subScenario: "when setting composite false and tsbuildinfo as null on command line but has tsbuild info in config",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"composite": true,
|
|
"tsBuildInfoFile": "tsconfig.json.tsbuildinfo",
|
|
},
|
|
"include": [
|
|
"src/**/*.ts",
|
|
],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--composite", "false", "--tsBuildInfoFile", "null"},
|
|
},
|
|
{
|
|
subScenario: "converting to modules",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "none",
|
|
"composite": true,
|
|
},
|
|
}`),
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "convert to modules",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/tsconfig.json", "none", "es2015")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "synthetic jsx import of ESM module from CJS module no crash no jsx element",
|
|
files: FileMap{
|
|
"/home/src/projects/project/src/main.ts": "export default 42;",
|
|
"/home/src/projects/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"module": "Node16",
|
|
"jsx": "react-jsx",
|
|
"jsxImportSource": "solid-js",
|
|
},
|
|
}`),
|
|
"/home/src/projects/project/node_modules/solid-js/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "solid-js",
|
|
"type": "module"
|
|
}
|
|
`),
|
|
"/home/src/projects/project/node_modules/solid-js/jsx-runtime.d.ts": stringtestutil.Dedent(`
|
|
export namespace JSX {
|
|
type IntrinsicElements = { div: {}; };
|
|
}
|
|
`),
|
|
},
|
|
cwd: "/home/src/projects/project",
|
|
},
|
|
{
|
|
subScenario: "synthetic jsx import of ESM module from CJS module error on jsx element",
|
|
files: FileMap{
|
|
"/home/src/projects/project/src/main.tsx": "export default <div/>;",
|
|
"/home/src/projects/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"module": "Node16",
|
|
"jsx": "react-jsx",
|
|
"jsxImportSource": "solid-js",
|
|
},
|
|
}`),
|
|
"/home/src/projects/project/node_modules/solid-js/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "solid-js",
|
|
"type": "module"
|
|
}
|
|
`),
|
|
"/home/src/projects/project/node_modules/solid-js/jsx-runtime.d.ts": stringtestutil.Dedent(`
|
|
export namespace JSX {
|
|
type IntrinsicElements = { div: {}; };
|
|
}
|
|
`),
|
|
},
|
|
cwd: "/home/src/projects/project",
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
testCase.run(t, "composite")
|
|
}
|
|
}
|
|
|
|
func TestTscDeclarationEmit(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildDeclarationEmitDtsReferenceAsTrippleSlashMap := func(useNoRef bool) FileMap {
|
|
files := FileMap{
|
|
"/home/src/workspaces/solution/tsconfig.base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"rootDir": "./",
|
|
"outDir": "lib",
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": [{ "path": "./src" }],
|
|
"include": [],
|
|
}`),
|
|
"/home/src/workspaces/solution/src/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": [{ "path": "./subProject" }, { "path": "./subProject2" }],
|
|
"include": [],
|
|
}`),
|
|
"/home/src/workspaces/solution/src/subProject/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"compilerOptions": { "composite": true },
|
|
"references": [{ "path": "../common" }],
|
|
"include": ["./index.ts"],
|
|
}`),
|
|
"/home/src/workspaces/solution/src/subProject/index.ts": stringtestutil.Dedent(`
|
|
import { Nominal } from '../common/nominal';
|
|
export type MyNominal = Nominal<string, 'MyNominal'>;`),
|
|
"/home/src/workspaces/solution/src/subProject2/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"compilerOptions": { "composite": true },
|
|
"references": [{ "path": "../subProject" }],
|
|
"include": ["./index.ts"],
|
|
}`),
|
|
"/home/src/workspaces/solution/src/subProject2/index.ts": stringtestutil.Dedent(`
|
|
import { MyNominal } from '../subProject/index';
|
|
const variable = {
|
|
key: 'value' as MyNominal,
|
|
};
|
|
export function getVar(): keyof typeof variable {
|
|
return 'key';
|
|
}`),
|
|
"/home/src/workspaces/solution/src/common/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"compilerOptions": { "composite": true },
|
|
"include": ["./nominal.ts"],
|
|
}`),
|
|
"/home/src/workspaces/solution/src/common/nominal.ts": stringtestutil.Dedent(`
|
|
/// <reference path="./types.d.ts" preserve="true" />
|
|
export declare type Nominal<T, Name extends string> = MyNominal<T, Name>;`),
|
|
"/home/src/workspaces/solution/src/common/types.d.ts": stringtestutil.Dedent(`
|
|
declare type MyNominal<T, Name extends string> = T & {
|
|
specialKey: Name;
|
|
};`),
|
|
}
|
|
if useNoRef {
|
|
files["/home/src/workspaces/solution/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./tsconfig.base.json",
|
|
"compilerOptions": { "composite": true },
|
|
"include": ["./src/**/*.ts"],
|
|
}`)
|
|
}
|
|
return files
|
|
}
|
|
|
|
getTscDeclarationEmitDtsErrorsFileMap := func(composite bool, incremental bool) FileMap {
|
|
return FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "NodeNext",
|
|
"moduleResolution": "NodeNext",
|
|
"composite": %t,
|
|
"incremental": %t,
|
|
"declaration": true,
|
|
"skipLibCheck": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`, composite, incremental)),
|
|
"/home/src/workspaces/project/index.ts": stringtestutil.Dedent(`
|
|
import ky from 'ky';
|
|
export const api = ky.extend({});
|
|
`),
|
|
"/home/src/workspaces/project/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"type": "module"
|
|
}`),
|
|
"/home/src/workspaces/project/node_modules/ky/distribution/index.d.ts": stringtestutil.Dedent(`
|
|
type KyInstance = {
|
|
extend(options: Record<string,unknown>): KyInstance;
|
|
}
|
|
declare const ky: KyInstance;
|
|
export default ky;
|
|
`),
|
|
"/home/src/workspaces/project/node_modules/ky/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "ky",
|
|
"type": "module",
|
|
"main": "./distribution/index.js"
|
|
}
|
|
`),
|
|
}
|
|
}
|
|
|
|
pluginOneConfig := func() string {
|
|
return stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"declaration": true,
|
|
"traceResolution": true,
|
|
},
|
|
}`)
|
|
}
|
|
|
|
pluginOneIndex := func() string {
|
|
return `import pluginTwo from "plugin-two"; // include this to add reference to symlink`
|
|
}
|
|
|
|
pluginOneAction := func() string {
|
|
return stringtestutil.Dedent(`
|
|
import { actionCreatorFactory } from "typescript-fsa"; // Include version of shared lib
|
|
const action = actionCreatorFactory("somekey");
|
|
const featureOne = action<{ route: string }>("feature-one");
|
|
export const actions = { featureOne };`)
|
|
}
|
|
|
|
pluginTwoDts := func() string {
|
|
return stringtestutil.Dedent(`
|
|
declare const _default: {
|
|
features: {
|
|
featureOne: {
|
|
actions: {
|
|
featureOne: {
|
|
(payload: {
|
|
name: string;
|
|
order: number;
|
|
}, meta?: {
|
|
[key: string]: any;
|
|
}): import("typescript-fsa").Action<{
|
|
name: string;
|
|
order: number;
|
|
}>;
|
|
};
|
|
};
|
|
path: string;
|
|
};
|
|
};
|
|
};
|
|
export default _default;`)
|
|
}
|
|
|
|
fsaPackageJson := func() string {
|
|
return stringtestutil.Dedent(`
|
|
{
|
|
"name": "typescript-fsa",
|
|
"version": "3.0.0-beta-2"
|
|
}`)
|
|
}
|
|
|
|
fsaIndex := func() string {
|
|
return stringtestutil.Dedent(`
|
|
export interface Action<Payload> {
|
|
type: string;
|
|
payload: Payload;
|
|
}
|
|
export declare type ActionCreator<Payload> = {
|
|
type: string;
|
|
(payload: Payload): Action<Payload>;
|
|
}
|
|
export interface ActionCreatorFactory {
|
|
<Payload = void>(type: string): ActionCreator<Payload>;
|
|
}
|
|
export declare function actionCreatorFactory(prefix?: string | null): ActionCreatorFactory;
|
|
export default actionCreatorFactory;`)
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "when declaration file is referenced through triple slash",
|
|
files: getBuildDeclarationEmitDtsReferenceAsTrippleSlashMap(false),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "when declaration file is referenced through triple slash but uses no references",
|
|
files: getBuildDeclarationEmitDtsReferenceAsTrippleSlashMap(true),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "when declaration file used inferred type from referenced project",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"paths": { "@fluentui/*": ["./packages/*/src"] },
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/packages/pkg1/src/index.ts": stringtestutil.Dedent(`
|
|
export interface IThing {
|
|
a: string;
|
|
}
|
|
export interface IThings {
|
|
thing1: IThing;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/packages/pkg1/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig",
|
|
"compilerOptions": { "outDir": "lib" },
|
|
"include": ["src"],
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/packages/pkg2/src/index.ts": stringtestutil.Dedent(`
|
|
import { IThings } from '@fluentui/pkg1';
|
|
export function fn4() {
|
|
const a: IThings = { thing1: { a: 'b' } };
|
|
return a.thing1;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/packages/pkg2/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig",
|
|
"compilerOptions": { "outDir": "lib" },
|
|
"include": ["src"],
|
|
"references": [{ "path": "../pkg1" }],
|
|
}
|
|
`),
|
|
},
|
|
commandLineArgs: []string{"--b", "packages/pkg2/tsconfig.json", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "reports dts generation errors",
|
|
files: getTscDeclarationEmitDtsErrorsFileMap(false, false),
|
|
commandLineArgs: []string{"-b", "--explainFiles", "--listEmittedFiles", "--v"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "reports dts generation errors with incremental",
|
|
files: getTscDeclarationEmitDtsErrorsFileMap(false, true),
|
|
commandLineArgs: []string{"-b", "--explainFiles", "--listEmittedFiles", "--v"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "reports dts generation errors",
|
|
files: getTscDeclarationEmitDtsErrorsFileMap(false, false),
|
|
commandLineArgs: []string{"--explainFiles", "--listEmittedFiles"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "build -b",
|
|
commandLineArgs: []string{"-b", "--explainFiles", "--listEmittedFiles", "--v"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "reports dts generation errors with incremental",
|
|
files: getTscDeclarationEmitDtsErrorsFileMap(true, true),
|
|
commandLineArgs: []string{"--explainFiles", "--listEmittedFiles"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "build -b",
|
|
commandLineArgs: []string{"-b", "--explainFiles", "--listEmittedFiles", "--v"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when using Windows paths and uppercase letters",
|
|
files: FileMap{
|
|
"D:/Work/pkg1/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "ts-specifier-bug",
|
|
"version": "1.0.0",
|
|
"main": "index.js"
|
|
}`),
|
|
"D:/Work/pkg1/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"declaration": true,
|
|
"target": "es2017",
|
|
"outDir": "./dist",
|
|
},
|
|
"include": ["src"],
|
|
}`),
|
|
"D:/Work/pkg1/src/main.ts": stringtestutil.Dedent(`
|
|
import { PartialType } from './utils';
|
|
|
|
class Common {}
|
|
|
|
export class Sub extends PartialType(Common) {
|
|
id: string;
|
|
}
|
|
`),
|
|
"D:/Work/pkg1/src/utils/index.ts": stringtestutil.Dedent(`
|
|
import { MyType, MyReturnType } from './type-helpers';
|
|
|
|
export function PartialType<T>(classRef: MyType<T>) {
|
|
abstract class PartialClassType {
|
|
constructor() {}
|
|
}
|
|
|
|
return PartialClassType as MyReturnType;
|
|
}
|
|
`),
|
|
"D:/Work/pkg1/src/utils/type-helpers.ts": stringtestutil.Dedent(`
|
|
export type MyReturnType = {
|
|
new (...args: any[]): any;
|
|
};
|
|
|
|
export interface MyType<T = any> extends Function {
|
|
new (...args: any[]): T;
|
|
}
|
|
`),
|
|
},
|
|
cwd: "D:/Work/pkg1",
|
|
windowsStyleRoot: "D:/",
|
|
ignoreCase: true,
|
|
commandLineArgs: []string{"-p", "D:\\Work\\pkg1", "--explainFiles"},
|
|
},
|
|
{
|
|
// !!! sheetal redirected files not yet implemented
|
|
subScenario: "when same version is referenced through source and another symlinked package",
|
|
files: FileMap{
|
|
`/user/username/projects/myproject/plugin-two/index.d.ts`: pluginTwoDts(),
|
|
`/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`: fsaPackageJson(),
|
|
`/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`: fsaIndex(),
|
|
`/user/username/projects/myproject/plugin-one/tsconfig.json`: pluginOneConfig(),
|
|
`/user/username/projects/myproject/plugin-one/index.ts`: pluginOneIndex(),
|
|
`/user/username/projects/myproject/plugin-one/action.ts`: pluginOneAction(),
|
|
`/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`: fsaPackageJson(),
|
|
`/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`: fsaIndex(),
|
|
`/user/username/projects/myproject/plugin-one/node_modules/plugin-two`: vfstest.Symlink(`/user/username/projects/myproject/plugin-two`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-p", "plugin-one", "--explainFiles"},
|
|
},
|
|
{
|
|
// !!! sheetal redirected files not yet implemented
|
|
subScenario: "when same version is referenced through source and another symlinked package with indirect link",
|
|
files: FileMap{
|
|
`/user/username/projects/myproject/plugin-two/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "plugin-two",
|
|
"version": "0.1.3",
|
|
"main": "dist/commonjs/index.js"
|
|
}`),
|
|
`/user/username/projects/myproject/plugin-two/dist/commonjs/index.d.ts`: pluginTwoDts(),
|
|
`/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`: fsaPackageJson(),
|
|
`/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`: fsaIndex(),
|
|
`/user/username/projects/myproject/plugin-one/tsconfig.json`: pluginOneConfig(),
|
|
`/user/username/projects/myproject/plugin-one/index.ts`: pluginOneIndex() + "\n" + pluginOneAction(),
|
|
`/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`: fsaPackageJson(),
|
|
`/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`: fsaIndex(),
|
|
`/temp/yarn/data/link/plugin-two`: vfstest.Symlink(`/user/username/projects/myproject/plugin-two`),
|
|
`/user/username/projects/myproject/plugin-one/node_modules/plugin-two`: vfstest.Symlink(`/temp/yarn/data/link/plugin-two`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-p", "plugin-one", "--explainFiles"},
|
|
},
|
|
{
|
|
// !!! sheetal strada has error for d.ts generation in pkg3/src/keys.ts but corsa doesnt have that
|
|
subScenario: "when pkg references sibling package through indirect symlink",
|
|
files: FileMap{
|
|
`/user/username/projects/myproject/pkg1/dist/index.d.ts`: `export * from './types';`,
|
|
`/user/username/projects/myproject/pkg1/dist/types.d.ts`: stringtestutil.Dedent(`
|
|
export declare type A = {
|
|
id: string;
|
|
};
|
|
export declare type B = {
|
|
id: number;
|
|
};
|
|
export declare type IdType = A | B;
|
|
export declare class MetadataAccessor<T, D extends IdType = IdType> {
|
|
readonly key: string;
|
|
private constructor();
|
|
toString(): string;
|
|
static create<T, D extends IdType = IdType>(key: string): MetadataAccessor<T, D>;
|
|
}`),
|
|
`/user/username/projects/myproject/pkg1/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "@raymondfeng/pkg1",
|
|
"version": "1.0.0",
|
|
"main": "dist/index.js",
|
|
"typings": "dist/index.d.ts"
|
|
}`),
|
|
`/user/username/projects/myproject/pkg2/dist/index.d.ts`: `export * from './types';`,
|
|
`/user/username/projects/myproject/pkg2/dist/types.d.ts`: `export {MetadataAccessor} from '@raymondfeng/pkg1';`,
|
|
`/user/username/projects/myproject/pkg2/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "@raymondfeng/pkg2",
|
|
"version": "1.0.0",
|
|
"main": "dist/index.js",
|
|
"typings": "dist/index.d.ts"
|
|
}`),
|
|
`/user/username/projects/myproject/pkg3/src/index.ts`: `export * from './keys';`,
|
|
`/user/username/projects/myproject/pkg3/src/keys.ts`: stringtestutil.Dedent(`
|
|
import {MetadataAccessor} from "@raymondfeng/pkg2";
|
|
export const ADMIN = MetadataAccessor.create<boolean>('1');`),
|
|
`/user/username/projects/myproject/pkg3/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "dist",
|
|
"rootDir": "src",
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"strict": true,
|
|
"esModuleInterop": true,
|
|
"declaration": true,
|
|
},
|
|
}`),
|
|
`/user/username/projects/myproject/pkg2/node_modules/@raymondfeng/pkg1`: vfstest.Symlink(`/user/username/projects/myproject/pkg1`),
|
|
`/user/username/projects/myproject/pkg3/node_modules/@raymondfeng/pkg2`: vfstest.Symlink(`/user/username/projects/myproject/pkg2`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-p", "pkg3", "--explainFiles"},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "declarationEmit")
|
|
}
|
|
}
|
|
|
|
func TestTscExtends(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildConfigFileExtendsFileMap := func() FileMap {
|
|
return FileMap{
|
|
"/home/src/workspaces/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "./shared/tsconfig.json" },
|
|
{ "path": "./webpack/tsconfig.json" },
|
|
],
|
|
"files": [],
|
|
}`),
|
|
"/home/src/workspaces/solution/shared/tsconfig-base.json": stringtestutil.Dedent(`
|
|
{
|
|
"include": ["./typings-base/"],
|
|
}`),
|
|
"/home/src/workspaces/solution/shared/typings-base/globals.d.ts": `type Unrestricted = any;`,
|
|
"/home/src/workspaces/solution/shared/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "../target-tsc-build/",
|
|
"rootDir": "..",
|
|
},
|
|
"files": ["./index.ts"],
|
|
}`),
|
|
"/home/src/workspaces/solution/shared/index.ts": `export const a: Unrestricted = 1;`,
|
|
"/home/src/workspaces/solution/webpack/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../shared/tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "../target-tsc-build/",
|
|
"rootDir": "..",
|
|
},
|
|
"files": ["./index.ts"],
|
|
"references": [{ "path": "../shared/tsconfig.json" }],
|
|
}`),
|
|
"/home/src/workspaces/solution/webpack/index.ts": `export const b: Unrestricted = 1;`,
|
|
}
|
|
}
|
|
getTscExtendsWithSymlinkTestCase := func(builtType string) *tscInput {
|
|
return &tscInput{
|
|
subScenario: "resolves the symlink path",
|
|
files: FileMap{
|
|
"/users/user/projects/myconfigs/node_modules/@something/tsconfig-node/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "@something/tsconfig-base/tsconfig.json",
|
|
"compilerOptions": {
|
|
"removeComments": true
|
|
}
|
|
}
|
|
`),
|
|
"/users/user/projects/myconfigs/node_modules/@something/tsconfig-base/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true }
|
|
}
|
|
`),
|
|
"/users/user/projects/myproject/src/index.ts": stringtestutil.Dedent(`
|
|
// some comment
|
|
export const x = 10;
|
|
`),
|
|
"/users/user/projects/myproject/src/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "@something/tsconfig-node/tsconfig.json"
|
|
}`),
|
|
"/users/user/projects/myproject/node_modules/@something/tsconfig-node": vfstest.Symlink("/users/user/projects/myconfigs/node_modules/@something/tsconfig-node"),
|
|
},
|
|
cwd: "/users/user/projects/myproject",
|
|
commandLineArgs: []string{builtType, "src", "--extendedDiagnostics"},
|
|
}
|
|
}
|
|
getTscExtendsConfigDirTestCase := func(subScenarioSufix string, commandLineArgs []string, edits []*tscEdit) *tscInput {
|
|
return &tscInput{
|
|
subScenario: "configDir template" + subScenarioSufix,
|
|
files: FileMap{
|
|
"/home/src/projects/configs/first/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../second/tsconfig.json",
|
|
"include": ["${configDir}/src"],
|
|
"compilerOptions": {
|
|
"typeRoots": ["root1", "${configDir}/root2", "root3"],
|
|
"types": [],
|
|
},
|
|
}`),
|
|
"/home/src/projects/configs/second/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": ["${configDir}/main.ts"],
|
|
"compilerOptions": {
|
|
"declarationDir": "${configDir}/decls",
|
|
"paths": {
|
|
"@myscope/*": ["${configDir}/types/*"],
|
|
},
|
|
},
|
|
"watchOptions": {
|
|
"excludeFiles": ["${configDir}/main.ts"],
|
|
},
|
|
}`),
|
|
"/home/src/projects/myproject/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../configs/first/tsconfig.json",
|
|
"compilerOptions": {
|
|
"declaration": true,
|
|
"outDir": "outDir",
|
|
"traceResolution": true,
|
|
},
|
|
}`),
|
|
"/home/src/projects/myproject/main.ts": stringtestutil.Dedent(`
|
|
// some comment
|
|
export const y = 10;
|
|
import { x } from "@myscope/sometype";
|
|
`),
|
|
"/home/src/projects/myproject/types/sometype.ts": stringtestutil.Dedent(`
|
|
export const x = 10;
|
|
`),
|
|
},
|
|
cwd: "/home/src/projects/myproject",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
}
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "when building solution with projects extends config with include",
|
|
files: getBuildConfigFileExtendsFileMap(),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "--v", "--listFiles"},
|
|
},
|
|
{
|
|
subScenario: "when building project uses reference and both extend config with include",
|
|
files: getBuildConfigFileExtendsFileMap(),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "webpack/tsconfig.json", "--v", "--listFiles"},
|
|
},
|
|
getTscExtendsWithSymlinkTestCase("-p"),
|
|
getTscExtendsWithSymlinkTestCase("-b"),
|
|
getTscExtendsConfigDirTestCase("", []string{"--explainFiles"}, nil),
|
|
getTscExtendsConfigDirTestCase(" showConfig", []string{"--showConfig"}, nil),
|
|
getTscExtendsConfigDirTestCase(" with commandline", []string{"--explainFiles", "--outDir", "${configDir}/outDir"}, nil),
|
|
getTscExtendsConfigDirTestCase("", []string{"--b", "--explainFiles", "--v"}, nil),
|
|
getTscExtendsConfigDirTestCase("", []string{"--b", "-w", "--explainFiles", "--v"}, []*tscEdit{
|
|
{
|
|
caption: "edit extended config file",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(
|
|
"/home/src/projects/configs/first/tsconfig.json",
|
|
stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../second/tsconfig.json",
|
|
"include": ["${configDir}/src"],
|
|
"compilerOptions": {
|
|
"typeRoots": ["${configDir}/root2"],
|
|
"types": [],
|
|
},
|
|
}`),
|
|
false,
|
|
)
|
|
},
|
|
},
|
|
}),
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "extends")
|
|
}
|
|
}
|
|
|
|
func TestTscIncremental(t *testing.T) {
|
|
t.Parallel()
|
|
getConstEnumTest := func(bdsContents string, changeEnumFile string, testSuffix string) *tscInput {
|
|
return &tscInput{
|
|
subScenario: "const enums" + testSuffix,
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/a.ts": stringtestutil.Dedent(`
|
|
import {A} from "./c"
|
|
let a = A.ONE
|
|
`),
|
|
"/home/src/workspaces/project/b.d.ts": stringtestutil.Dedent(bdsContents),
|
|
"/home/src/workspaces/project/c.ts": stringtestutil.Dedent(`
|
|
import {A} from "./b"
|
|
let b = A.ONE
|
|
export {A}
|
|
`),
|
|
"/home/src/workspaces/project/worker.d.ts": stringtestutil.Dedent(`
|
|
export const enum AWorker {
|
|
ONE = 1
|
|
}
|
|
`),
|
|
},
|
|
commandLineArgs: []string{"-i", `a.ts`, "--tsbuildinfofile", "a.tsbuildinfo"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "change enum value",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(changeEnumFile, "1", "2")
|
|
},
|
|
},
|
|
{
|
|
caption: "change enum value again",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(changeEnumFile, "2", "3")
|
|
},
|
|
},
|
|
{
|
|
caption: "something else changes in b.d.ts",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/b.d.ts", "export const randomThing = 10;")
|
|
},
|
|
},
|
|
{
|
|
caption: "something else changes in b.d.ts again",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/b.d.ts", "export const randomThing2 = 10;")
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "serializing error chain",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"strict": true,
|
|
"jsx": "react",
|
|
"module": "esnext",
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/index.tsx": stringtestutil.Dedent(`
|
|
declare namespace JSX {
|
|
interface ElementChildrenAttribute { children: {}; }
|
|
interface IntrinsicElements { div: {} }
|
|
}
|
|
|
|
declare var React: any;
|
|
|
|
declare function Component(props: never): any;
|
|
declare function Component(props: { children?: number }): any;
|
|
(<Component>
|
|
<div />
|
|
<div />
|
|
</Component>)`),
|
|
},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "serializing composite project",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"strict": true,
|
|
"module": "esnext",
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/index.tsx": `export const a = 1;`,
|
|
"/home/src/workspaces/project/other.ts": `export const b = 2;`,
|
|
},
|
|
},
|
|
{
|
|
subScenario: "change to modifier of class expression field with declaration emit enabled",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "esnext",
|
|
"declaration": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/main.ts": stringtestutil.Dedent(`
|
|
import MessageablePerson from './MessageablePerson.js';
|
|
function logMessage( person: MessageablePerson ) {
|
|
console.log( person.message );
|
|
}`),
|
|
"/home/src/workspaces/project/MessageablePerson.ts": stringtestutil.Dedent(`
|
|
const Messageable = () => {
|
|
return class MessageableClass {
|
|
public message = 'hello';
|
|
}
|
|
};
|
|
const wrapper = () => Messageable();
|
|
type MessageablePerson = InstanceType<ReturnType<typeof wrapper>>;
|
|
export default MessageablePerson;`),
|
|
tscLibPath + "/lib.d.ts": tscDefaultLibContent + "\n" + stringtestutil.Dedent(`
|
|
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
|
|
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;`),
|
|
},
|
|
commandLineArgs: []string{"--incremental"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "modify public to protected",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/MessageablePerson.ts", "public", "protected")
|
|
},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "modify protected to public",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/MessageablePerson.ts", "protected", "public")
|
|
},
|
|
},
|
|
noChange,
|
|
},
|
|
},
|
|
{
|
|
subScenario: "change to modifier of class expression field",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "esnext"
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/main.ts": stringtestutil.Dedent(`
|
|
import MessageablePerson from './MessageablePerson.js';
|
|
function logMessage( person: MessageablePerson ) {
|
|
console.log( person.message );
|
|
}`),
|
|
"/home/src/workspaces/project/MessageablePerson.ts": stringtestutil.Dedent(`
|
|
const Messageable = () => {
|
|
return class MessageableClass {
|
|
public message = 'hello';
|
|
}
|
|
};
|
|
const wrapper = () => Messageable();
|
|
type MessageablePerson = InstanceType<ReturnType<typeof wrapper>>;
|
|
export default MessageablePerson;`),
|
|
tscLibPath + "/lib.d.ts": tscDefaultLibContent + "\n" + stringtestutil.Dedent(`
|
|
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
|
|
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;`),
|
|
},
|
|
commandLineArgs: []string{"--incremental"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "modify public to protected",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/MessageablePerson.ts", "public", "protected")
|
|
},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "modify protected to public",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/MessageablePerson.ts", "protected", "public")
|
|
},
|
|
},
|
|
noChange,
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when passing filename for buildinfo on commandline",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"module": "commonjs"
|
|
},
|
|
"include": [
|
|
"src/**/*.ts"
|
|
],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--incremental", "--tsBuildInfoFile", ".tsbuildinfo", "--explainFiles"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "when passing rootDir from commandline",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"outDir": "dist"
|
|
}
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--rootDir", "src"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "with only dts files",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.d.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/src/another.d.ts": "export const y = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": "{}",
|
|
},
|
|
commandLineArgs: []string{"--incremental"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "modify d.ts file",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/src/main.d.ts", "export const xy = 100;")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when passing rootDir is in the tsconfig",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"outDir": "dist",
|
|
"rootDir": "./"
|
|
}
|
|
}`),
|
|
},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "tsbuildinfo has error",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": "{}",
|
|
"/home/src/workspaces/project/tsconfig.tsbuildinfo": "Some random string",
|
|
},
|
|
commandLineArgs: []string{"-i"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "tsbuildinfo written has error",
|
|
edit: func(sys *testSys) {
|
|
sys.prependFile("/home/src/workspaces/project/tsconfig.tsbuildinfo", "Some random string")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when global file is added, the signatures are updated",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/main.ts": stringtestutil.Dedent(`
|
|
/// <reference path="./filePresent.ts"/>
|
|
/// <reference path="./fileNotFound.ts"/>
|
|
function main() { }
|
|
`),
|
|
"/home/src/workspaces/project/src/anotherFileWithSameReferenes.ts": stringtestutil.Dedent(`
|
|
/// <reference path="./filePresent.ts"/>
|
|
/// <reference path="./fileNotFound.ts"/>
|
|
function anotherFileWithSameReferenes() { }
|
|
`),
|
|
"/home/src/workspaces/project/src/filePresent.ts": `function something() { return 10; }`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"include": ["src/**/*.ts"],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "Modify main file",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(`/home/src/workspaces/project/src/main.ts`, `something();`)
|
|
},
|
|
},
|
|
{
|
|
caption: "Modify main file again",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(`/home/src/workspaces/project/src/main.ts`, `something();`)
|
|
},
|
|
},
|
|
{
|
|
caption: "Add new file and update main file",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(`/home/src/workspaces/project/src/newFile.ts`, "function foo() { return 20; }", false)
|
|
sys.prependFile(
|
|
`/home/src/workspaces/project/src/main.ts`,
|
|
`/// <reference path="./newFile.ts"/>
|
|
`,
|
|
)
|
|
sys.appendFile(`/home/src/workspaces/project/src/main.ts`, `foo();`)
|
|
},
|
|
},
|
|
{
|
|
caption: "Write file that could not be resolved",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(`/home/src/workspaces/project/src/fileNotFound.ts`, "function something2() { return 20; }", false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Modify main file",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(`/home/src/workspaces/project/src/main.ts`, `something();`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "react-jsx-emit-mode with no backing types found doesnt crash",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result
|
|
"/home/src/workspaces/project/node_modules/@types/react/index.d.ts": stringtestutil.Dedent(`
|
|
export {};
|
|
declare global {
|
|
namespace JSX {
|
|
interface Element {}
|
|
interface IntrinsicElements {
|
|
div: {
|
|
propA?: boolean;
|
|
};
|
|
}
|
|
}
|
|
}`), // doesn't contain a jsx-runtime definition
|
|
"/home/src/workspaces/project/src/index.tsx": `export const App = () => <div propA={true}></div>;`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "commonjs",
|
|
"jsx": "react-jsx",
|
|
"incremental": true,
|
|
"jsxImportSource": "react"
|
|
}
|
|
}`),
|
|
},
|
|
},
|
|
{
|
|
subScenario: "react-jsx-emit-mode with no backing types found doesnt crash under --strict",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result
|
|
"/home/src/workspaces/project/node_modules/@types/react/index.d.ts": stringtestutil.Dedent(`
|
|
export {};
|
|
declare global {
|
|
namespace JSX {
|
|
interface Element {}
|
|
interface IntrinsicElements {
|
|
div: {
|
|
propA?: boolean;
|
|
};
|
|
}
|
|
}
|
|
}`), // doesn't contain a jsx-runtime definition
|
|
"/home/src/workspaces/project/src/index.tsx": `export const App = () => <div propA={true}></div>;`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "commonjs",
|
|
"jsx": "react-jsx",
|
|
"incremental": true,
|
|
"jsxImportSource": "react"
|
|
}
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--strict"},
|
|
},
|
|
{
|
|
subScenario: "change to type that gets used as global through export in another file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/class1.ts": stringtestutil.Dedent(`
|
|
const a: MagicNumber = 1;
|
|
console.log(a);`),
|
|
"/home/src/workspaces/project/constants.ts": "export default 1;",
|
|
"/home/src/workspaces/project/types.d.ts": `type MagicNumber = typeof import('./constants').default`,
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Modify imports used in global file",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/workspaces/project/constants.ts", "export default 2;", false)
|
|
},
|
|
expectedDiff: "Currently there is issue with d.ts emit for export default = 1 to widen in dts which is why we are not re-computing errors and results in incorrect error reporting",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "change to type that gets used as global through export in another file through indirect import",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/class1.ts": stringtestutil.Dedent(`
|
|
const a: MagicNumber = 1;
|
|
console.log(a);`),
|
|
"/home/src/workspaces/project/constants.ts": "export default 1;",
|
|
"/home/src/workspaces/project/reexport.ts": `export { default as ConstantNumber } from "./constants"`,
|
|
"/home/src/workspaces/project/types.d.ts": `type MagicNumber = typeof import('./reexport').ConstantNumber`,
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Modify imports used in global file",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/workspaces/project/constants.ts", "export default 2;", false)
|
|
},
|
|
expectedDiff: "Currently there is issue with d.ts emit for export default = 1 to widen in dts which is why we are not re-computing errors and results in incorrect error reporting",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when file is deleted",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "outDir"
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/file1.ts": `export class C { }`,
|
|
"/home/src/workspaces/project/file2.ts": `export class D { }`,
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete file with imports",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/project/file2.ts")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "generates typerefs correctly",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "outDir",
|
|
"checkJs": true
|
|
},
|
|
"include": ["src"],
|
|
}`),
|
|
"/home/src/workspaces/project/src/box.ts": stringtestutil.Dedent(`
|
|
export interface Box<T> {
|
|
unbox(): T
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/src/bug.js": stringtestutil.Dedent(`
|
|
import * as B from "./box.js"
|
|
import * as W from "./wrap.js"
|
|
|
|
/**
|
|
* @template {object} C
|
|
* @param {C} source
|
|
* @returns {W.Wrap<C>}
|
|
*/
|
|
const wrap = source => {
|
|
throw source
|
|
}
|
|
|
|
/**
|
|
* @returns {B.Box<number>}
|
|
*/
|
|
const box = (n = 0) => ({ unbox: () => n })
|
|
|
|
export const bug = wrap({ n: box(1) });
|
|
`),
|
|
"/home/src/workspaces/project/src/wrap.ts": stringtestutil.Dedent(`
|
|
export type Wrap<C> = {
|
|
[K in keyof C]: { wrapped: C[K] }
|
|
}
|
|
`),
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "modify js file",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/src/bug.js", `export const something = 1;`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
getConstEnumTest(`
|
|
export const enum A {
|
|
ONE = 1
|
|
}
|
|
`, "/home/src/workspaces/project/b.d.ts", ""),
|
|
getConstEnumTest(`
|
|
export const enum AWorker {
|
|
ONE = 1
|
|
}
|
|
export { AWorker as A };
|
|
`, "/home/src/workspaces/project/b.d.ts", " aliased"),
|
|
getConstEnumTest(`export { AWorker as A } from "./worker";`, "/home/src/workspaces/project/worker.d.ts", " aliased in different file"),
|
|
{
|
|
subScenario: "option changes with composite",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/a.ts": `export const a = 10;const aLocal = 10;`,
|
|
"/home/src/workspaces/project/b.ts": `export const b = 10;const bLocal = 10;`,
|
|
"/home/src/workspaces/project/c.ts": `import { a } from "./a";export const c = a;`,
|
|
"/home/src/workspaces/project/d.ts": `import { b } from "./b";export const d = b;`,
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--sourceMap"},
|
|
},
|
|
{
|
|
caption: "should re-emit only js so they dont contain sourcemap",
|
|
},
|
|
{
|
|
caption: "with declaration should not emit anything",
|
|
commandLineArgs: []string{"--declaration"},
|
|
// discrepancyExplanation: () => [
|
|
// `Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/-/g, "")}`,
|
|
// `Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option composite only`,
|
|
// ],
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "with declaration and declarationMap",
|
|
commandLineArgs: []string{"--declaration", "--declarationMap"},
|
|
},
|
|
{
|
|
caption: "should re-emit only dts so they dont contain sourcemap",
|
|
},
|
|
{
|
|
caption: "with emitDeclarationOnly should not emit anything",
|
|
commandLineArgs: []string{"--emitDeclarationOnly"},
|
|
// discrepancyExplanation: () => [
|
|
// `Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/-/g, "")}`,
|
|
// `Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option composite only`,
|
|
// ],
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "local change",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/a.ts", "Local = 1", "Local = 10")
|
|
},
|
|
},
|
|
{
|
|
caption: "with declaration should not emit anything",
|
|
commandLineArgs: []string{"--declaration"},
|
|
// discrepancyExplanation: () => [
|
|
// `Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/-/g, "")}`,
|
|
// `Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option composite only`,
|
|
// ],
|
|
},
|
|
{
|
|
caption: "with inlineSourceMap",
|
|
commandLineArgs: []string{"--inlineSourceMap"},
|
|
},
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--sourceMap"},
|
|
},
|
|
{
|
|
caption: "declarationMap enabling",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/tsconfig.json", `"composite": true,`, `"composite": true, "declarationMap": true`)
|
|
},
|
|
},
|
|
{
|
|
caption: "with sourceMap should not emit d.ts",
|
|
commandLineArgs: []string{"--sourceMap"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "option changes with incremental",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/a.ts": `export const a = 10;const aLocal = 10;`,
|
|
"/home/src/workspaces/project/b.ts": `export const b = 10;const bLocal = 10;`,
|
|
"/home/src/workspaces/project/c.ts": `import { a } from "./a";export const c = a;`,
|
|
"/home/src/workspaces/project/d.ts": `import { b } from "./b";export const d = b;`,
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--sourceMap"},
|
|
},
|
|
{
|
|
caption: "should re-emit only js so they dont contain sourcemap",
|
|
},
|
|
{
|
|
caption: "with declaration, emit Dts and should not emit js",
|
|
commandLineArgs: []string{"--declaration"},
|
|
},
|
|
{
|
|
caption: "with declaration and declarationMap",
|
|
commandLineArgs: []string{"--declaration", "--declarationMap"},
|
|
},
|
|
{
|
|
caption: "no change",
|
|
// discrepancyExplanation: () => [
|
|
// `Clean build tsbuildinfo will have compilerOptions {}`,
|
|
// `Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option declaration and declarationMap`,
|
|
// ],
|
|
},
|
|
{
|
|
caption: "local change",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/a.ts", "Local = 1", "Local = 10")
|
|
},
|
|
},
|
|
{
|
|
caption: "with declaration and declarationMap",
|
|
commandLineArgs: []string{"--declaration", "--declarationMap"},
|
|
},
|
|
{
|
|
caption: "no change",
|
|
// discrepancyExplanation: () => [
|
|
// `Clean build tsbuildinfo will have compilerOptions {}`,
|
|
// `Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option declaration and declarationMap`,
|
|
// ],
|
|
},
|
|
{
|
|
caption: "with inlineSourceMap",
|
|
commandLineArgs: []string{"--inlineSourceMap"},
|
|
},
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--sourceMap"},
|
|
},
|
|
{
|
|
caption: "emit js files",
|
|
},
|
|
{
|
|
caption: "with declaration and declarationMap",
|
|
commandLineArgs: []string{"--declaration", "--declarationMap"},
|
|
},
|
|
{
|
|
caption: "with declaration and declarationMap, should not re-emit",
|
|
commandLineArgs: []string{"--declaration", "--declarationMap"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when there is bind diagnostics thats ignored",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"skipLibCheck": true,
|
|
"incremental": true,
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/a.ts": `export const a = 10;`,
|
|
"/home/src/workspaces/project/b.d.ts": stringtestutil.Dedent(`
|
|
interface NoName {
|
|
Profiler: new ({ sampleInterval: number, maxBufferSize: number }) => {
|
|
stop: () => Promise<any>;
|
|
};
|
|
}
|
|
`),
|
|
},
|
|
commandLineArgs: []string{""},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "no change and tsc -b",
|
|
commandLineArgs: []string{"-b", "-v"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "incremental")
|
|
}
|
|
}
|
|
|
|
func TestTscLibraryResolution(t *testing.T) {
|
|
t.Parallel()
|
|
getTscLibraryResolutionFileMap := func(libReplacement bool) FileMap {
|
|
files := FileMap{
|
|
"/home/src/workspace/projects/project1/utils.d.ts": `export const y = 10;`,
|
|
"/home/src/workspace/projects/project1/file.ts": `export const file = 10;`,
|
|
"/home/src/workspace/projects/project1/core.d.ts": `export const core = 10;`,
|
|
"/home/src/workspace/projects/project1/index.ts": `export const x = "type1";`,
|
|
"/home/src/workspace/projects/project1/file2.ts": stringtestutil.Dedent(`
|
|
/// <reference lib="webworker"/>
|
|
/// <reference lib="scripthost"/>
|
|
/// <reference lib="es5"/>
|
|
`),
|
|
"/home/src/workspace/projects/project1/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"typeRoots": ["./typeroot1"],
|
|
"lib": ["es5", "dom"],
|
|
"traceResolution": true,
|
|
"libReplacement": %t
|
|
}
|
|
}
|
|
`, libReplacement)),
|
|
"/home/src/workspace/projects/project1/typeroot1/sometype/index.d.ts": `export type TheNum = "type1";`,
|
|
"/home/src/workspace/projects/project2/utils.d.ts": `export const y = 10;`,
|
|
"/home/src/workspace/projects/project2/index.ts": `export const y = 10`,
|
|
"/home/src/workspace/projects/project2/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"lib": ["es5", "dom"],
|
|
"traceResolution": true,
|
|
"libReplacement": %t
|
|
}
|
|
}
|
|
`, libReplacement)),
|
|
"/home/src/workspace/projects/project3/utils.d.ts": `export const y = 10;`,
|
|
"/home/src/workspace/projects/project3/index.ts": `export const z = 10`,
|
|
"/home/src/workspace/projects/project3/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"lib": ["es5", "dom"],
|
|
"traceResolution": true,
|
|
"libReplacement": %t
|
|
}
|
|
}
|
|
`, libReplacement)),
|
|
"/home/src/workspace/projects/project4/utils.d.ts": `export const y = 10;`,
|
|
"/home/src/workspace/projects/project4/index.ts": `export const z = 10`,
|
|
"/home/src/workspace/projects/project4/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"lib": ["esnext", "dom", "webworker"],
|
|
"traceResolution": true,
|
|
"libReplacement": %t
|
|
}
|
|
}
|
|
`, libReplacement)),
|
|
getTestLibPathFor("dom"): "interface DOMInterface { }",
|
|
getTestLibPathFor("webworker"): "interface WebWorkerInterface { }",
|
|
getTestLibPathFor("scripthost"): "interface ScriptHostInterface { }",
|
|
"/home/src/workspace/projects/node_modules/@typescript/unlreated/index.d.ts": "export const unrelated = 10;",
|
|
}
|
|
if libReplacement {
|
|
files["/home/src/workspace/projects/node_modules/@typescript/lib-es5/index.d.ts"] = tscDefaultLibContent
|
|
files["/home/src/workspace/projects/node_modules/@typescript/lib-esnext/index.d.ts"] = tscDefaultLibContent
|
|
files["/home/src/workspace/projects/node_modules/@typescript/lib-dom/index.d.ts"] = "interface DOMInterface { }"
|
|
files["/home/src/workspace/projects/node_modules/@typescript/lib-webworker/index.d.ts"] = "interface WebWorkerInterface { }"
|
|
files["/home/src/workspace/projects/node_modules/@typescript/lib-scripthost/index.d.ts"] = "interface ScriptHostInterface { }"
|
|
}
|
|
return files
|
|
}
|
|
getTscLibResolutionTestCases := func(commandLineArgs []string) []*tscInput {
|
|
return []*tscInput{
|
|
{
|
|
subScenario: "with config",
|
|
files: getTscLibraryResolutionFileMap(false),
|
|
cwd: "/home/src/workspace/projects",
|
|
commandLineArgs: commandLineArgs,
|
|
},
|
|
{
|
|
subScenario: "with config with libReplacement",
|
|
files: getTscLibraryResolutionFileMap(true),
|
|
cwd: "/home/src/workspace/projects",
|
|
commandLineArgs: commandLineArgs,
|
|
},
|
|
}
|
|
}
|
|
getTscLibraryResolutionUnknown := func() FileMap {
|
|
return FileMap{
|
|
"/home/src/workspace/projects/project1/utils.d.ts": `export const y = 10;`,
|
|
"/home/src/workspace/projects/project1/file.ts": `export const file = 10;`,
|
|
"/home/src/workspace/projects/project1/core.d.ts": `export const core = 10;`,
|
|
"/home/src/workspace/projects/project1/index.ts": `export const x = "type1";`,
|
|
"/home/src/workspace/projects/project1/file2.ts": stringtestutil.Dedent(`
|
|
/// <reference lib="webworker2"/>
|
|
/// <reference lib="unknownlib"/>
|
|
/// <reference lib="scripthost"/>
|
|
`),
|
|
"/home/src/workspace/projects/project1/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"traceResolution": true,
|
|
"libReplacement": true
|
|
}
|
|
}`),
|
|
getTestLibPathFor("webworker"): "interface WebWorkerInterface { }",
|
|
getTestLibPathFor("scripthost"): "interface ScriptHostInterface { }",
|
|
}
|
|
}
|
|
testCases := slices.Concat(
|
|
getTscLibResolutionTestCases([]string{"-b", "project1", "project2", "project3", "project4", "--verbose", "--explainFiles"}),
|
|
getTscLibResolutionTestCases([]string{"-p", "project1", "--explainFiles"}),
|
|
getTscLibResolutionTestCases([]string{"-b", "-w", "project1", "project2", "project3", "project4", "--verbose", "--explainFiles"}),
|
|
[]*tscInput{
|
|
{
|
|
subScenario: "unknown lib",
|
|
files: getTscLibraryResolutionUnknown(),
|
|
cwd: "/home/src/workspace/projects",
|
|
commandLineArgs: []string{"-p", "project1", "--explainFiles"},
|
|
},
|
|
{
|
|
subScenario: "when noLib toggles",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/a.d.ts": `declare const a = "hello";`,
|
|
"/home/src/workspaces/project/b.ts": `const b = 10;`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"declaration": true,
|
|
"incremental": true,
|
|
"lib": ["es6"],
|
|
},
|
|
}
|
|
`),
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "with --noLib",
|
|
commandLineArgs: []string{"--noLib"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
)
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "libraryResolution")
|
|
}
|
|
}
|
|
|
|
func TestTscListFilesOnly(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "loose file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/test.ts": "export const x = 1;",
|
|
},
|
|
commandLineArgs: []string{"test.ts", "--listFilesOnly"},
|
|
},
|
|
{
|
|
subScenario: "combined with incremental",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/test.ts": "export const x = 1;",
|
|
"/home/src/workspaces/project/tsconfig.json": "{}",
|
|
},
|
|
commandLineArgs: []string{"--incremental", "--listFilesOnly"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental actual build",
|
|
commandLineArgs: []string{"--incremental"},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "incremental should not build",
|
|
commandLineArgs: []string{"--incremental"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
testCase.run(t, "listFilesOnly")
|
|
}
|
|
}
|
|
|
|
func TestTscModuleResolution(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildModuleResolutionInProjectRefTestCase := func(preserveSymlinks bool) *tscInput {
|
|
return &tscInput{
|
|
subScenario: `resolves specifier in output declaration file from referenced project correctly` + core.IfElse(preserveSymlinks, " with preserveSymlinks", ""),
|
|
files: FileMap{
|
|
`/user/username/projects/myproject/packages/pkg1/index.ts`: stringtestutil.Dedent(`
|
|
import type { TheNum } from 'pkg2'
|
|
export const theNum: TheNum = 42;`),
|
|
`/user/username/projects/myproject/packages/pkg1/tsconfig.json`: stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "build",
|
|
"preserveSymlinks": %t
|
|
},
|
|
"references": [{ "path": "../pkg2" }]
|
|
}
|
|
`, preserveSymlinks)),
|
|
`/user/username/projects/myproject/packages/pkg2/const.ts`: stringtestutil.Dedent(`
|
|
export type TheNum = 42;
|
|
`),
|
|
`/user/username/projects/myproject/packages/pkg2/index.ts`: stringtestutil.Dedent(`
|
|
export type { TheNum } from 'const';
|
|
`),
|
|
`/user/username/projects/myproject/packages/pkg2/tsconfig.json`: stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "build",
|
|
"paths": {
|
|
"const": ["./const"]
|
|
},
|
|
"preserveSymlinks": %t,
|
|
},
|
|
}
|
|
`, preserveSymlinks)),
|
|
`/user/username/projects/myproject/packages/pkg2/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "pkg2",
|
|
"version": "1.0.0",
|
|
"main": "build/index.js"
|
|
}
|
|
`),
|
|
`/user/username/projects/myproject/node_modules/pkg2`: vfstest.Symlink(`/user/username/projects/myproject/packages/pkg2`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-b", "packages/pkg1", "--verbose", "--traceResolution"},
|
|
}
|
|
}
|
|
getTscModuleResolutionSharingFileMap := func() FileMap {
|
|
return FileMap{
|
|
"/home/src/workspaces/project/packages/a/index.js": `export const a = 'a';`,
|
|
"/home/src/workspaces/project/packages/a/test/index.js": `import 'a';`,
|
|
"/home/src/workspaces/project/packages/a/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"checkJs": true,
|
|
"composite": true,
|
|
"declaration": true,
|
|
"emitDeclarationOnly": true,
|
|
"module": "nodenext",
|
|
"outDir": "types",
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/packages/a/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "a",
|
|
"version": "0.0.0",
|
|
"type": "module",
|
|
"exports": {
|
|
".": {
|
|
"types": "./types/index.d.ts",
|
|
"default": "./index.js"
|
|
}
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/packages/b/index.js": `export { a } from 'a';`,
|
|
"/home/src/workspaces/project/packages/b/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [{ "path": "../a" }],
|
|
"compilerOptions": {
|
|
"checkJs": true,
|
|
"module": "nodenext",
|
|
"noEmit": true,
|
|
"noImplicitAny": true,
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/packages/b/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "b",
|
|
"version": "0.0.0",
|
|
"type": "module"
|
|
}`),
|
|
"/home/src/workspaces/project/node_modules/a": vfstest.Symlink("/home/src/workspaces/project/packages/a"),
|
|
}
|
|
}
|
|
getTscModuleResolutionAlternateResultAtTypesPackageJson := func(packageName string, addTypesCondition bool) string {
|
|
var typesString string
|
|
if addTypesCondition {
|
|
typesString = `"types": "./index.d.ts",`
|
|
}
|
|
return stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"name": "@types/%s",
|
|
"version": "1.0.0",
|
|
"types": "index.d.ts",
|
|
"exports": {
|
|
".": {
|
|
%s
|
|
"require": "./index.d.ts"
|
|
}
|
|
}
|
|
}`, packageName, typesString))
|
|
}
|
|
getTscModuleResolutionAlternateResultPackageJson := func(packageName string, addTypes bool, addTypesCondition bool) string {
|
|
var types string
|
|
if addTypes {
|
|
types = `"types": "index.d.ts",`
|
|
}
|
|
var typesString string
|
|
if addTypesCondition {
|
|
typesString = `"types": "./index.d.ts",`
|
|
}
|
|
return stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"name": "%s",
|
|
"version": "1.0.0",
|
|
"main": "index.js",
|
|
%s
|
|
"exports": {
|
|
".": {
|
|
%s
|
|
"import": "./index.mjs",
|
|
"require": "./index.js"
|
|
}
|
|
}
|
|
}`, packageName, types, typesString))
|
|
}
|
|
getTscModuleResolutionAlternateResultDts := func(packageName string) string {
|
|
return fmt.Sprintf(`export declare const %s: number;`, packageName)
|
|
}
|
|
getTscModuleResolutionAlternateResultJs := func(packageName string) string {
|
|
return fmt.Sprintf(`module.exports = { %s: 1 };`, packageName)
|
|
}
|
|
getTscModuleResolutionAlternateResultMjs := func(packageName string) string {
|
|
return fmt.Sprintf(`export const %s = 1;`, packageName)
|
|
}
|
|
testCases := []*tscInput{
|
|
getBuildModuleResolutionInProjectRefTestCase(false),
|
|
getBuildModuleResolutionInProjectRefTestCase(true),
|
|
{
|
|
subScenario: `type reference resolution uses correct options for different resolution options referenced project`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/packages/pkg1_index.ts": `export const theNum: TheNum = "type1";`,
|
|
"/home/src/workspaces/project/packages/pkg1.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"typeRoots": ["./typeroot1"]
|
|
},
|
|
"files": ["./pkg1_index.ts"],
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/packages/typeroot1/sometype/index.d.ts": `declare type TheNum = "type1";`,
|
|
"/home/src/workspaces/project/packages/pkg2_index.ts": `export const theNum: TheNum2 = "type2";`,
|
|
"/home/src/workspaces/project/packages/pkg2.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"typeRoots": ["./typeroot2"]
|
|
},
|
|
"files": ["./pkg2_index.ts"],
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/packages/typeroot2/sometype/index.d.ts": `declare type TheNum2 = "type2";`,
|
|
},
|
|
commandLineArgs: []string{"-b", "packages/pkg1.tsconfig.json", "packages/pkg2.tsconfig.json", "--verbose", "--traceResolution"},
|
|
},
|
|
{
|
|
subScenario: "impliedNodeFormat differs between projects for shared file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/a/src/index.ts": "",
|
|
"/home/src/workspaces/project/a/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true
|
|
}
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/b/src/index.ts": stringtestutil.Dedent(`
|
|
import pg from "pg";
|
|
pg.foo();
|
|
`),
|
|
"/home/src/workspaces/project/b/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"module": "node16"
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/b/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "b",
|
|
"type": "module"
|
|
}`),
|
|
"/home/src/workspaces/project/node_modules/@types/pg/index.d.ts": "export function foo(): void;",
|
|
"/home/src/workspaces/project/node_modules/@types/pg/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "@types/pg",
|
|
"types": "index.d.ts"
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"-b", "a", "b", "--verbose", "--traceResolution", "--explainFiles"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "shared resolution should not report error",
|
|
files: getTscModuleResolutionSharingFileMap(),
|
|
commandLineArgs: []string{"-b", "packages/b", "--verbose", "--traceResolution", "--explainFiles"},
|
|
},
|
|
{
|
|
subScenario: "when resolution is not shared",
|
|
files: getTscModuleResolutionSharingFileMap(),
|
|
commandLineArgs: []string{"-b", "packages/a", "--verbose", "--traceResolution", "--explainFiles"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "build b",
|
|
commandLineArgs: []string{"-b", "packages/b", "--verbose", "--traceResolution", "--explainFiles"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "pnpm style layout",
|
|
files: FileMap{
|
|
// button@0.0.1
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.1/node_modules/@component-type-checker/button/src/index.ts": stringtestutil.Dedent(`
|
|
export interface Button {
|
|
a: number;
|
|
b: number;
|
|
}
|
|
export function createButton(): Button {
|
|
return {
|
|
a: 0,
|
|
b: 1,
|
|
};
|
|
}
|
|
`),
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.1/node_modules/@component-type-checker/button/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "@component-type-checker/button",
|
|
"version": "0.0.1",
|
|
"main": "./src/index.ts"
|
|
}`),
|
|
|
|
// button@0.0.2
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.2/node_modules/@component-type-checker/button/src/index.ts": stringtestutil.Dedent(`
|
|
export interface Button {
|
|
a: number;
|
|
c: number;
|
|
}
|
|
export function createButton(): Button {
|
|
return {
|
|
a: 0,
|
|
c: 2,
|
|
};
|
|
}
|
|
`),
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.2/node_modules/@component-type-checker/button/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "@component-type-checker/button",
|
|
"version": "0.0.2",
|
|
"main": "./src/index.ts"
|
|
}`),
|
|
|
|
// @component-type-checker+components@0.0.1_@component-type-checker+button@0.0.1
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.1/node_modules/@component-type-checker/button": vfstest.Symlink(
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.1/node_modules/@component-type-checker/button",
|
|
),
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.1/node_modules/@component-type-checker/components/src/index.ts": stringtestutil.Dedent(`
|
|
export { createButton, Button } from "@component-type-checker/button";
|
|
`),
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.1/node_modules/@component-type-checker/components/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "@component-type-checker/components",
|
|
"version": "0.0.1",
|
|
"main": "./src/index.ts",
|
|
"peerDependencies": {
|
|
"@component-type-checker/button": "*"
|
|
},
|
|
"devDependencies": {
|
|
"@component-type-checker/button": "0.0.2"
|
|
}
|
|
}`),
|
|
|
|
// @component-type-checker+components@0.0.1_@component-type-checker+button@0.0.2
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.2/node_modules/@component-type-checker/button": vfstest.Symlink(
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.2/node_modules/@component-type-checker/button",
|
|
),
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.2/node_modules/@component-type-checker/components/src/index.ts": stringtestutil.Dedent(`
|
|
export { createButton, Button } from "@component-type-checker/button";
|
|
`),
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.2/node_modules/@component-type-checker/components/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "@component-type-checker/components",
|
|
"version": "0.0.1",
|
|
"main": "./src/index.ts",
|
|
"peerDependencies": {
|
|
"@component-type-checker/button": "*"
|
|
},
|
|
"devDependencies": {
|
|
"@component-type-checker/button": "0.0.2"
|
|
}
|
|
}`),
|
|
|
|
// sdk => @component-type-checker+components@0.0.1_@component-type-checker+button@0.0.1
|
|
"/home/src/projects/component-type-checker/packages/sdk/src/index.ts": stringtestutil.Dedent(`
|
|
export { Button, createButton } from "@component-type-checker/components";
|
|
export const VERSION = "0.0.2";
|
|
`),
|
|
"/home/src/projects/component-type-checker/packages/sdk/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "@component-type-checker/sdk1",
|
|
"version": "0.0.2",
|
|
"main": "./src/index.ts",
|
|
"dependencies": {
|
|
"@component-type-checker/components": "0.0.1",
|
|
"@component-type-checker/button": "0.0.1"
|
|
}
|
|
}`),
|
|
"/home/src/projects/component-type-checker/packages/sdk/node_modules/@component-type-checker/button": vfstest.Symlink(
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.1/node_modules/@component-type-checker/button",
|
|
),
|
|
"/home/src/projects/component-type-checker/packages/sdk/node_modules/@component-type-checker/components": vfstest.Symlink(
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.1/node_modules/@component-type-checker/components",
|
|
),
|
|
|
|
// app => @component-type-checker+components@0.0.1_@component-type-checker+button@0.0.2
|
|
"/home/src/projects/component-type-checker/packages/app/src/app.tsx": stringtestutil.Dedent(`
|
|
import { VERSION } from "@component-type-checker/sdk";
|
|
import { Button } from "@component-type-checker/components";
|
|
import { createButton } from "@component-type-checker/button";
|
|
const button: Button = createButton();
|
|
`),
|
|
"/home/src/projects/component-type-checker/packages/app/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "app",
|
|
"version": "1.0.0",
|
|
"dependencies": {
|
|
"@component-type-checker/button": "0.0.2",
|
|
"@component-type-checker/components": "0.0.1",
|
|
"@component-type-checker/sdk": "0.0.2"
|
|
}
|
|
}`),
|
|
"/home/src/projects/component-type-checker/packages/app/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"module": "esnext",
|
|
"lib": ["ES5"],
|
|
"moduleResolution": "node",
|
|
"outDir": "dist",
|
|
},
|
|
"include": ["src"],
|
|
}`),
|
|
"/home/src/projects/component-type-checker/packages/app/node_modules/@component-type-checker/button": vfstest.Symlink(
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+button@0.0.2/node_modules/@component-type-checker/button",
|
|
),
|
|
"/home/src/projects/component-type-checker/packages/app/node_modules/@component-type-checker/components": vfstest.Symlink(
|
|
"/home/src/projects/component-type-checker/node_modules/.pnpm/@component-type-checker+components@0.0.1_@component-type-checker+button@0.0.2/node_modules/@component-type-checker/components",
|
|
),
|
|
"/home/src/projects/component-type-checker/packages/app/node_modules/@component-type-checker/sdk": vfstest.Symlink(
|
|
"/home/src/projects/component-type-checker/packages/sdk",
|
|
),
|
|
},
|
|
cwd: "/home/src/projects/component-type-checker/packages/app",
|
|
commandLineArgs: []string{"--traceResolution", "--explainFiles"},
|
|
},
|
|
{
|
|
subScenario: "package json scope",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "ES2016",
|
|
"composite": true,
|
|
"module": "Node16",
|
|
"traceResolution": true,
|
|
},
|
|
"files": [
|
|
"main.ts",
|
|
"fileA.ts",
|
|
"fileB.mts",
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/project/src/main.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/src/fileA.ts": stringtestutil.Dedent(`
|
|
import { foo } from "./fileB.mjs";
|
|
foo();
|
|
`),
|
|
"/home/src/workspaces/project/src/fileB.mts": "export function foo() {}",
|
|
"/home/src/workspaces/project/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "app",
|
|
"version": "1.0.0"
|
|
}
|
|
`),
|
|
},
|
|
commandLineArgs: []string{"-p", "src", "--explainFiles", "--extendedDiagnostics"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Delete package.json",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/project/package.json")
|
|
},
|
|
// !!! repopulateInfo on diagnostics not yet implemented
|
|
expectedDiff: "Currently we arent repopulating error chain so errors will be different",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "alternateResult",
|
|
files: FileMap{
|
|
"/home/src/projects/project/node_modules/@types/bar/package.json": getTscModuleResolutionAlternateResultAtTypesPackageJson("bar" /*addTypesCondition*/, false),
|
|
"/home/src/projects/project/node_modules/@types/bar/index.d.ts": getTscModuleResolutionAlternateResultDts("bar"),
|
|
"/home/src/projects/project/node_modules/bar/package.json": getTscModuleResolutionAlternateResultPackageJson("bar" /*addTypes*/, false /*addTypesCondition*/, false),
|
|
"/home/src/projects/project/node_modules/bar/index.js": getTscModuleResolutionAlternateResultJs("bar"),
|
|
"/home/src/projects/project/node_modules/bar/index.mjs": getTscModuleResolutionAlternateResultMjs("bar"),
|
|
"/home/src/projects/project/node_modules/foo/package.json": getTscModuleResolutionAlternateResultPackageJson("foo" /*addTypes*/, true /*addTypesCondition*/, false),
|
|
"/home/src/projects/project/node_modules/foo/index.js": getTscModuleResolutionAlternateResultJs("foo"),
|
|
"/home/src/projects/project/node_modules/foo/index.mjs": getTscModuleResolutionAlternateResultMjs("foo"),
|
|
"/home/src/projects/project/node_modules/foo/index.d.ts": getTscModuleResolutionAlternateResultDts("foo"),
|
|
"/home/src/projects/project/node_modules/@types/bar2/package.json": getTscModuleResolutionAlternateResultAtTypesPackageJson("bar2" /*addTypesCondition*/, true),
|
|
"/home/src/projects/project/node_modules/@types/bar2/index.d.ts": getTscModuleResolutionAlternateResultDts("bar2"),
|
|
"/home/src/projects/project/node_modules/bar2/package.json": getTscModuleResolutionAlternateResultPackageJson("bar2" /*addTypes*/, false /*addTypesCondition*/, false),
|
|
"/home/src/projects/project/node_modules/bar2/index.js": getTscModuleResolutionAlternateResultJs("bar2"),
|
|
"/home/src/projects/project/node_modules/bar2/index.mjs": getTscModuleResolutionAlternateResultMjs("bar2"),
|
|
"/home/src/projects/project/node_modules/foo2/package.json": getTscModuleResolutionAlternateResultPackageJson("foo2" /*addTypes*/, true /*addTypesCondition*/, true),
|
|
"/home/src/projects/project/node_modules/foo2/index.js": getTscModuleResolutionAlternateResultJs("foo2"),
|
|
"/home/src/projects/project/node_modules/foo2/index.mjs": getTscModuleResolutionAlternateResultMjs("foo2"),
|
|
"/home/src/projects/project/node_modules/foo2/index.d.ts": getTscModuleResolutionAlternateResultDts("foo2"),
|
|
"/home/src/projects/project/index.mts": stringtestutil.Dedent(`
|
|
import { foo } from "foo";
|
|
import { bar } from "bar";
|
|
import { foo2 } from "foo2";
|
|
import { bar2 } from "bar2";
|
|
`),
|
|
"/home/src/projects/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "node16",
|
|
"moduleResolution": "node16",
|
|
"traceResolution": true,
|
|
"incremental": true,
|
|
"strict": true,
|
|
"types": [],
|
|
},
|
|
"files": ["index.mts"],
|
|
}`),
|
|
},
|
|
cwd: "/home/src/projects/project",
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete the alternateResult in @types",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/projects/project/node_modules/@types/bar/index.d.ts")
|
|
},
|
|
// !!! repopulateInfo on diagnostics not yet implemented
|
|
expectedDiff: "Currently we arent repopulating error chain so errors will be different",
|
|
},
|
|
{
|
|
caption: "delete the node10Result in package/types",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/projects/project/node_modules/foo/index.d.ts")
|
|
},
|
|
// !!! repopulateInfo on diagnostics not yet implemented
|
|
expectedDiff: "Currently we arent repopulating error chain so errors will be different",
|
|
},
|
|
{
|
|
caption: "add the alternateResult in @types",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/@types/bar/index.d.ts", getTscModuleResolutionAlternateResultDts("bar"), false)
|
|
},
|
|
// !!! repopulateInfo on diagnostics not yet implemented
|
|
expectedDiff: "Currently we arent repopulating error chain so errors will be different",
|
|
},
|
|
{
|
|
caption: "add the alternateResult in package/types",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/foo/index.d.ts", getTscModuleResolutionAlternateResultDts("foo"), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "update package.json from @types so error is fixed",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/@types/bar/package.json", getTscModuleResolutionAlternateResultAtTypesPackageJson("bar" /*addTypesCondition*/, true), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "update package.json so error is fixed",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/foo/package.json", getTscModuleResolutionAlternateResultPackageJson("foo" /*addTypes*/, true /*addTypesCondition*/, true), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "update package.json from @types so error is introduced",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/@types/bar2/package.json", getTscModuleResolutionAlternateResultAtTypesPackageJson("bar2" /*addTypesCondition*/, false), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "update package.json so error is introduced",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/foo2/package.json", getTscModuleResolutionAlternateResultPackageJson("foo2" /*addTypes*/, true /*addTypesCondition*/, false), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "delete the alternateResult in @types",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/projects/project/node_modules/@types/bar2/index.d.ts")
|
|
},
|
|
// !!! repopulateInfo on diagnostics not yet implemented
|
|
expectedDiff: "Currently we arent repopulating error chain so errors will be different",
|
|
},
|
|
{
|
|
caption: "delete the node10Result in package/types",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/projects/project/node_modules/foo2/index.d.ts")
|
|
},
|
|
// !!! repopulateInfo on diagnostics not yet implemented
|
|
expectedDiff: "Currently we arent repopulating error chain so errors will be different",
|
|
},
|
|
{
|
|
caption: "add the alternateResult in @types",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/@types/bar2/index.d.ts", getTscModuleResolutionAlternateResultDts("bar2"), false)
|
|
},
|
|
// !!! repopulateInfo on diagnostics not yet implemented
|
|
expectedDiff: "Currently we arent repopulating error chain so errors will be different",
|
|
},
|
|
{
|
|
caption: "add the ndoe10Result in package/types",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/node_modules/foo2/index.d.ts", getTscModuleResolutionAlternateResultDts("foo2"), false)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "handles the cache correctly when two projects use different module resolution settings",
|
|
files: FileMap{
|
|
`/user/username/projects/myproject/project1/index.ts`: `import { foo } from "file";`,
|
|
`/user/username/projects/myproject/project1/node_modules/file/index.d.ts`: "export const foo = 10;",
|
|
`/user/username/projects/myproject/project1/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"types": ["foo", "bar"]
|
|
},
|
|
"files": ["index.ts"],
|
|
}`),
|
|
`/user/username/projects/myproject/project2/index.ts`: `import { foo } from "file";`,
|
|
`/user/username/projects/myproject/project2/node_modules/file/index.d.ts`: "export const foo = 10;",
|
|
`/user/username/projects/myproject/project2/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"types": ["foo"],
|
|
"module": "nodenext",
|
|
"moduleResolution": "nodenext"
|
|
},
|
|
"files": ["index.ts"],
|
|
}`),
|
|
`/user/username/projects/myproject/node_modules/@types/foo/index.d.ts`: "export const foo = 10;",
|
|
`/user/username/projects/myproject/node_modules/@types/bar/index.d.ts`: "export const bar = 10;",
|
|
`/user/username/projects/myproject/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"files": [],
|
|
"references": [
|
|
{ "path": "./project1" },
|
|
{ "path": "./project2" },
|
|
],
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"--b", "-w", "-v"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Append text",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(`/user/username/projects/myproject/project1/index.ts`, "const bar = 10;")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
// !!! sheetal package.json watches not yet implemented
|
|
subScenario: `resolves specifier in output declaration file from referenced project correctly with cts and mts extensions`,
|
|
files: FileMap{
|
|
`/user/username/projects/myproject/packages/pkg1/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "pkg1",
|
|
"version": "1.0.0",
|
|
"main": "build/index.js",
|
|
"type": "module"
|
|
}`),
|
|
`/user/username/projects/myproject/packages/pkg1/index.ts`: stringtestutil.Dedent(`
|
|
import type { TheNum } from 'pkg2'
|
|
export const theNum: TheNum = 42;`),
|
|
`/user/username/projects/myproject/packages/pkg1/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "build",
|
|
"module": "node16",
|
|
},
|
|
"references": [{ "path": "../pkg2" }],
|
|
}`),
|
|
`/user/username/projects/myproject/packages/pkg2/const.cts`: `export type TheNum = 42;`,
|
|
`/user/username/projects/myproject/packages/pkg2/index.ts`: `export type { TheNum } from './const.cjs';`,
|
|
`/user/username/projects/myproject/packages/pkg2/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "build",
|
|
"module": "node16",
|
|
},
|
|
}`),
|
|
`/user/username/projects/myproject/packages/pkg2/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "pkg2",
|
|
"version": "1.0.0",
|
|
"main": "build/index.js",
|
|
"type": "module"
|
|
}`),
|
|
`/user/username/projects/myproject/node_modules/pkg2`: vfstest.Symlink(`/user/username/projects/myproject/packages/pkg2`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-b", "packages/pkg1", "-w", "--verbose", "--traceResolution"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "reports import errors after change to package file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"module"`, `"commonjs"`)
|
|
},
|
|
expectedDiff: "Package.json watch pending, so no change detected yet",
|
|
},
|
|
{
|
|
caption: "removes those errors when a package file is changed back",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"commonjs"`, `"module"`)
|
|
},
|
|
},
|
|
{
|
|
caption: "reports import errors after change to package file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"module"`, `"commonjs"`)
|
|
},
|
|
expectedDiff: "Package.json watch pending, so no change detected yet",
|
|
},
|
|
{
|
|
caption: "removes those errors when a package file is changed to cjs extensions",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `"build/index.js"`, `"build/index.cjs"`)
|
|
sys.renameFileNoError(`/user/username/projects/myproject/packages/pkg2/index.ts`, `/user/username/projects/myproject/packages/pkg2/index.cts`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: `build mode watches for changes to package-json main fields`,
|
|
files: FileMap{
|
|
`/user/username/projects/myproject/packages/pkg1/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "pkg1",
|
|
"version": "1.0.0",
|
|
"main": "build/index.js"
|
|
}`),
|
|
`/user/username/projects/myproject/packages/pkg1/index.ts`: stringtestutil.Dedent(`
|
|
import type { TheNum } from 'pkg2'
|
|
export const theNum: TheNum = 42;`),
|
|
`/user/username/projects/myproject/packages/pkg1/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "build",
|
|
},
|
|
"references": [{ "path": "../pkg2" }],
|
|
}`),
|
|
`/user/username/projects/myproject/packages/pkg2/tsconfig.json`: stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "build",
|
|
},
|
|
}`),
|
|
`/user/username/projects/myproject/packages/pkg2/const.ts`: `export type TheNum = 42;`,
|
|
`/user/username/projects/myproject/packages/pkg2/index.ts`: `export type { TheNum } from './const.js';`,
|
|
`/user/username/projects/myproject/packages/pkg2/other.ts`: `export type TheStr = string;`,
|
|
`/user/username/projects/myproject/packages/pkg2/package.json`: stringtestutil.Dedent(`
|
|
{
|
|
"name": "pkg2",
|
|
"version": "1.0.0",
|
|
"main": "build/index.js"
|
|
}`),
|
|
`/user/username/projects/myproject/node_modules/pkg2`: vfstest.Symlink(`/user/username/projects/myproject/packages/pkg2`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-b", "packages/pkg1", "--verbose", "-w", "--traceResolution"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "reports import errors after change to package file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `index.js`, `other.js`)
|
|
},
|
|
expectedDiff: "Package.json watch pending, so no change detected yet",
|
|
},
|
|
{
|
|
caption: "removes those errors when a package file is changed back",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `other.js`, `index.js`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "resolution from d.ts of referenced project",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/common.d.ts": "export type OnValue = (value: number) => void",
|
|
"/home/src/workspaces/project/producer/index.ts": stringtestutil.Dedent(`
|
|
export { ValueProducerDeclaration } from "./in-js"
|
|
import { OnValue } from "@common"
|
|
export interface ValueProducerFromTs {
|
|
onValue: OnValue;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/producer/in-js.d.ts": stringtestutil.Dedent(`
|
|
import { OnValue } from "@common"
|
|
export interface ValueProducerDeclaration {
|
|
onValue: OnValue;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/producer/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"composite": true,
|
|
"module": "nodenext",
|
|
"moduleResolution": "nodenext",
|
|
"paths": {
|
|
"@common": ["../common.d.ts"],
|
|
},
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/consumer/index.ts": stringtestutil.Dedent(`
|
|
import { ValueProducerDeclaration, ValueProducerFromTs } from "@producer"
|
|
declare let v: ValueProducerDeclaration;
|
|
// n is implicitly any because onValue is actually any (despite what the tooltip says)
|
|
v.onValue = (n) => {
|
|
}
|
|
// n is implicitly number as expected
|
|
declare let v2: ValueProducerFromTs;
|
|
v2.onValue = (n) => {
|
|
}`),
|
|
"/home/src/workspaces/project/consumer/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
"module": "nodenext",
|
|
"moduleResolution": "nodenext",
|
|
"paths": {
|
|
"@producer": ["../producer/index"],
|
|
},
|
|
},
|
|
"references": [
|
|
{ "path": "../producer" },
|
|
],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b", "consumer", "--traceResolution", "-v"},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "moduleResolution")
|
|
}
|
|
}
|
|
|
|
func TestTscNoCheck(t *testing.T) {
|
|
t.Parallel()
|
|
type noCheckScenario struct {
|
|
subScenario string
|
|
aText string
|
|
}
|
|
getTscNoCheckTestCase := func(scenario *noCheckScenario, incremental bool, commandLineArgs []string) *tscInput {
|
|
noChangeWithCheck := &tscEdit{
|
|
caption: "No Change run with checking",
|
|
commandLineArgs: commandLineArgs,
|
|
}
|
|
fixErrorNoCheck := &tscEdit{
|
|
caption: "Fix `a` error with noCheck",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/workspaces/project/a.ts", `export const a = "hello";`, false)
|
|
},
|
|
}
|
|
addErrorNoCheck := &tscEdit{
|
|
caption: "Introduce error with noCheck",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/workspaces/project/a.ts", scenario.aText, false)
|
|
},
|
|
}
|
|
return &tscInput{
|
|
subScenario: scenario.subScenario + core.IfElse(incremental, " with incremental", ""),
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/a.ts": scenario.aText,
|
|
"/home/src/workspaces/project/b.ts": `export const b = 10;`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"declaration": true,
|
|
"incremental": %t
|
|
}
|
|
}`, incremental)),
|
|
},
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noCheck"}),
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
fixErrorNoCheck, // Fix error with noCheck
|
|
noChange, // Should be no op
|
|
noChangeWithCheck, // Check errors - should not report any errors - update buildInfo
|
|
noChangeWithCheck, // Should be no op
|
|
noChange, // Should be no op
|
|
addErrorNoCheck,
|
|
noChange, // Should be no op
|
|
noChangeWithCheck, // Should check errors and update buildInfo
|
|
fixErrorNoCheck, // Fix error with noCheck
|
|
noChangeWithCheck, // Should check errors and update buildInfo
|
|
{
|
|
caption: "Add file with error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/workspaces/project/c.ts", `export const c: number = "hello";`, false)
|
|
},
|
|
commandLineArgs: commandLineArgs,
|
|
},
|
|
addErrorNoCheck,
|
|
fixErrorNoCheck,
|
|
noChangeWithCheck,
|
|
noChange, // Should be no op
|
|
noChangeWithCheck, // Should be no op
|
|
},
|
|
}
|
|
}
|
|
|
|
cases := []noCheckScenario{
|
|
{"syntax errors", `export const a = "hello`},
|
|
{"semantic errors", `export const a: number = "hello";`},
|
|
{"dts errors", `export const a = class { private p = 10; };`},
|
|
}
|
|
testCases := core.FlatMap(cases, func(c noCheckScenario) []*tscInput {
|
|
return []*tscInput{
|
|
getTscNoCheckTestCase(&c, false, []string{}),
|
|
getTscNoCheckTestCase(&c, true, []string{}),
|
|
getTscNoCheckTestCase(&c, false, []string{"-b", "-v"}),
|
|
getTscNoCheckTestCase(&c, true, []string{"-b", "-v"}),
|
|
}
|
|
})
|
|
for _, test := range testCases {
|
|
test.run(t, "noCheck")
|
|
}
|
|
}
|
|
|
|
func TestTscNoEmit(t *testing.T) {
|
|
t.Parallel()
|
|
type tscNoEmitScenario struct {
|
|
subScenario string
|
|
aText string
|
|
dtsEnabled bool
|
|
}
|
|
noEmitScenarios := []*tscNoEmitScenario{
|
|
{
|
|
subScenario: "syntax errors",
|
|
aText: `const a = "hello`,
|
|
},
|
|
{
|
|
subScenario: "semantic errors",
|
|
aText: `const a: number = "hello"`,
|
|
},
|
|
{
|
|
subScenario: "dts errors",
|
|
aText: `const a = class { private p = 10; };`,
|
|
dtsEnabled: true,
|
|
},
|
|
{
|
|
subScenario: "dts errors without dts enabled",
|
|
aText: `const a = class { private p = 10; };`,
|
|
},
|
|
}
|
|
getTscNoEmitAndErrorsFileMap := func(scenario *tscNoEmitScenario, incremental bool, asModules bool, modify func(FileMap)) FileMap {
|
|
files := FileMap{
|
|
"/home/src/projects/project/a.ts": core.IfElse(asModules, `export `, "") + scenario.aText,
|
|
"/home/src/projects/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": %t,
|
|
"declaration": %t
|
|
}
|
|
}
|
|
`, incremental, scenario.dtsEnabled)),
|
|
}
|
|
if asModules {
|
|
files["/home/src/projects/project/b.ts"] = `export const b = 10;`
|
|
}
|
|
if modify != nil {
|
|
modify(files)
|
|
}
|
|
return files
|
|
}
|
|
getTscNoEmitAndErrorsTestCasesWorker := func(commandLineArgs []string, addNoEmitOnCommandLine bool, modify func(FileMap), edits func(scenario *tscNoEmitScenario, commandLineArgs []string, asModules bool) []*tscEdit) []*tscInput {
|
|
testingCases := make([]*tscInput, 0, len(noEmitScenarios)*3)
|
|
commandLineArgsForInput := commandLineArgs
|
|
if addNoEmitOnCommandLine {
|
|
commandLineArgsForInput = slices.Concat(commandLineArgs, []string{"--noEmit"})
|
|
}
|
|
for _, scenario := range noEmitScenarios {
|
|
testingCases = append(
|
|
testingCases,
|
|
&tscInput{
|
|
subScenario: scenario.subScenario,
|
|
commandLineArgs: commandLineArgsForInput,
|
|
files: getTscNoEmitAndErrorsFileMap(scenario, false, false, modify),
|
|
cwd: "/home/src/projects/project",
|
|
edits: edits(scenario, commandLineArgs, false),
|
|
},
|
|
&tscInput{
|
|
subScenario: scenario.subScenario + " with incremental",
|
|
commandLineArgs: commandLineArgsForInput,
|
|
files: getTscNoEmitAndErrorsFileMap(scenario, true, false, modify),
|
|
cwd: "/home/src/projects/project",
|
|
edits: edits(scenario, commandLineArgs, false),
|
|
},
|
|
&tscInput{
|
|
subScenario: scenario.subScenario + " with incremental as modules",
|
|
commandLineArgs: commandLineArgsForInput,
|
|
files: getTscNoEmitAndErrorsFileMap(scenario, true, true, modify),
|
|
cwd: "/home/src/projects/project",
|
|
edits: edits(scenario, commandLineArgs, true),
|
|
},
|
|
)
|
|
}
|
|
return testingCases
|
|
}
|
|
getTscNoEmitAndErrorsTestCases := func(commandLineArgs []string) []*tscInput {
|
|
return getTscNoEmitAndErrorsTestCasesWorker(
|
|
commandLineArgs,
|
|
true,
|
|
nil,
|
|
func(scenario *tscNoEmitScenario, commandLineArgs []string, asModules bool) []*tscEdit {
|
|
fixedATsContent := core.IfElse(asModules, "export ", "") + `const a = "hello";`
|
|
return []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "Fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/a.ts", fixedATsContent, false)
|
|
},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "Emit after fixing error",
|
|
commandLineArgs: commandLineArgs,
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "Introduce error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/a.ts", scenario.aText, false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Emit when error",
|
|
commandLineArgs: commandLineArgs,
|
|
},
|
|
noChange,
|
|
}
|
|
},
|
|
)
|
|
}
|
|
getTscNoEmitAndErrorsWatchTestCases := func(commandLineArgs []string) []*tscInput {
|
|
return getTscNoEmitAndErrorsTestCasesWorker(
|
|
commandLineArgs,
|
|
false,
|
|
func(files FileMap) {
|
|
files["/home/src/projects/project/tsconfig.json"] = strings.Replace(files["/home/src/projects/project/tsconfig.json"].(string), "}", `, "noEmit": true }`, 1)
|
|
},
|
|
func(scenario *tscNoEmitScenario, commandLineArgs []string, asModules bool) []*tscEdit {
|
|
fixedATsContent := core.IfElse(asModules, "export ", "") + `const a = "hello";`
|
|
return []*tscEdit{
|
|
{
|
|
caption: "Fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/a.ts", fixedATsContent, false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Emit after fixing error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/projects/project/tsconfig.json", `"noEmit": true`, `"noEmit": false`)
|
|
},
|
|
},
|
|
{
|
|
caption: "no Emit run after fixing error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/projects/project/tsconfig.json", `"noEmit": false`, `"noEmit": true`)
|
|
},
|
|
},
|
|
{
|
|
caption: "Introduce error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/projects/project/a.ts", scenario.aText, false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Emit when error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/projects/project/tsconfig.json", `"noEmit": true`, `"noEmit": false`)
|
|
},
|
|
},
|
|
{
|
|
caption: "no Emit run when error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/projects/project/tsconfig.json", `"noEmit": false`, `"noEmit": true`)
|
|
},
|
|
},
|
|
}
|
|
},
|
|
)
|
|
}
|
|
getTscNoEmitChangesFileMap := func(optionsStr string) FileMap {
|
|
return FileMap{
|
|
"/home/src/workspaces/project/src/class.ts": stringtestutil.Dedent(`
|
|
export class classC {
|
|
prop = 1;
|
|
}`),
|
|
"/home/src/workspaces/project/src/indirectClass.ts": stringtestutil.Dedent(`
|
|
import { classC } from './class';
|
|
export class indirectClass {
|
|
classC = new classC();
|
|
}`),
|
|
"/home/src/workspaces/project/src/directUse.ts": stringtestutil.Dedent(`
|
|
import { indirectClass } from './indirectClass';
|
|
new indirectClass().classC.prop;`),
|
|
"/home/src/workspaces/project/src/indirectUse.ts": stringtestutil.Dedent(`
|
|
import { indirectClass } from './indirectClass';
|
|
new indirectClass().classC.prop;`),
|
|
"/home/src/workspaces/project/src/noChangeFile.ts": stringtestutil.Dedent(`
|
|
export function writeLog(s: string) {
|
|
}`),
|
|
"/home/src/workspaces/project/src/noChangeFileWithEmitSpecificError.ts": stringtestutil.Dedent(`
|
|
function someFunc(arguments: boolean, ...rest: any[]) {
|
|
}`),
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": { %s }
|
|
}`, optionsStr)),
|
|
}
|
|
}
|
|
|
|
type tscNoEmitChangesScenario struct {
|
|
subScenario string
|
|
optionsString string
|
|
}
|
|
noEmitChangesScenarios := []*tscNoEmitChangesScenario{
|
|
{
|
|
// !!! sheetal missing initial reporting of Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters is absent
|
|
subScenario: "composite",
|
|
optionsString: `"composite": true`,
|
|
},
|
|
{
|
|
subScenario: "incremental declaration",
|
|
optionsString: `"incremental": true, "declaration": true`,
|
|
},
|
|
{
|
|
subScenario: "incremental",
|
|
optionsString: `"incremental": true`,
|
|
},
|
|
}
|
|
getTscNoEmitChangesTestCases := func(commandLineArgs []string) []*tscInput {
|
|
noChangeWithNoEmit := &tscEdit{
|
|
caption: "No Change run with noEmit",
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noEmit"}),
|
|
}
|
|
noChangeWithEmit := &tscEdit{
|
|
caption: "No Change run with emit",
|
|
commandLineArgs: commandLineArgs,
|
|
}
|
|
introduceError := func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/src/class.ts", "prop", "prop1")
|
|
}
|
|
fixError := func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/src/class.ts", "prop1", "prop")
|
|
}
|
|
testCases := make([]*tscInput, 0, len(noEmitChangesScenarios))
|
|
for _, scenario := range noEmitChangesScenarios {
|
|
testCases = append(
|
|
testCases,
|
|
&tscInput{
|
|
subScenario: "changes " + scenario.subScenario,
|
|
commandLineArgs: commandLineArgs,
|
|
files: getTscNoEmitChangesFileMap(scenario.optionsString),
|
|
edits: []*tscEdit{
|
|
noChangeWithNoEmit,
|
|
noChangeWithNoEmit,
|
|
{
|
|
caption: "Introduce error but still noEmit",
|
|
commandLineArgs: noChangeWithNoEmit.commandLineArgs,
|
|
edit: introduceError,
|
|
},
|
|
{
|
|
caption: "Fix error and emit",
|
|
edit: fixError,
|
|
},
|
|
noChangeWithEmit,
|
|
noChangeWithNoEmit,
|
|
noChangeWithNoEmit,
|
|
noChangeWithEmit,
|
|
{
|
|
caption: "Introduce error and emit",
|
|
edit: introduceError,
|
|
},
|
|
noChangeWithEmit,
|
|
noChangeWithNoEmit,
|
|
noChangeWithNoEmit,
|
|
noChangeWithEmit,
|
|
{
|
|
caption: "Fix error and no emit",
|
|
commandLineArgs: noChangeWithNoEmit.commandLineArgs,
|
|
edit: fixError,
|
|
},
|
|
noChangeWithEmit,
|
|
noChangeWithNoEmit,
|
|
noChangeWithNoEmit,
|
|
noChangeWithEmit,
|
|
},
|
|
},
|
|
&tscInput{
|
|
subScenario: "changes with initial noEmit " + scenario.subScenario,
|
|
commandLineArgs: noChangeWithNoEmit.commandLineArgs,
|
|
files: getTscNoEmitChangesFileMap(scenario.optionsString),
|
|
edits: []*tscEdit{
|
|
noChangeWithEmit,
|
|
{
|
|
caption: "Introduce error with emit",
|
|
commandLineArgs: commandLineArgs,
|
|
edit: introduceError,
|
|
},
|
|
{
|
|
caption: "Fix error and no emit",
|
|
edit: fixError,
|
|
},
|
|
noChangeWithEmit,
|
|
},
|
|
},
|
|
)
|
|
}
|
|
return testCases
|
|
}
|
|
getTscNoEmitDtsChangesFileMap := func(incremental bool, asModules bool) FileMap {
|
|
files := FileMap{
|
|
"/home/src/projects/project/a.ts": core.IfElse(asModules, `export const a = class { private p = 10; };`, `const a = class { private p = 10; };`),
|
|
"/home/src/projects/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": %t,
|
|
}
|
|
}
|
|
`, incremental)),
|
|
}
|
|
if asModules {
|
|
files["/home/src/projects/project/b.ts"] = `export const b = 10;`
|
|
}
|
|
return files
|
|
}
|
|
getTscNoEmitDtsChangesEdits := func(commandLineArgs []string) []*tscEdit {
|
|
return []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "With declaration enabled noEmit - Should report errors",
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noEmit", "--declaration"}),
|
|
},
|
|
{
|
|
caption: "With declaration and declarationMap noEmit - Should report errors",
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noEmit", "--declaration", "--declarationMap"}),
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "Dts Emit with error",
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--declaration"}),
|
|
},
|
|
{
|
|
caption: "Fix the error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/projects/project/a.ts", "private", "public")
|
|
},
|
|
},
|
|
{
|
|
caption: "With declaration enabled noEmit",
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noEmit", "--declaration"}),
|
|
},
|
|
{
|
|
caption: "With declaration and declarationMap noEmit",
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noEmit", "--declaration", "--declarationMap"}),
|
|
},
|
|
}
|
|
}
|
|
getTscNoEmitDtsChangesTestCases := func() []*tscInput {
|
|
return []*tscInput{
|
|
{
|
|
subScenario: "dts errors with declaration enable changes",
|
|
commandLineArgs: []string{"-b", "-v", "--noEmit"},
|
|
files: getTscNoEmitDtsChangesFileMap(false, false),
|
|
cwd: "/home/src/projects/project",
|
|
edits: getTscNoEmitDtsChangesEdits([]string{"-b", "-v"}),
|
|
},
|
|
{
|
|
subScenario: "dts errors with declaration enable changes with incremental",
|
|
commandLineArgs: []string{"-b", "-v", "--noEmit"},
|
|
files: getTscNoEmitDtsChangesFileMap(true, false),
|
|
cwd: "/home/src/projects/project",
|
|
edits: getTscNoEmitDtsChangesEdits([]string{"-b", "-v"}),
|
|
},
|
|
{
|
|
subScenario: "dts errors with declaration enable changes with incremental as modules",
|
|
commandLineArgs: []string{"-b", "-v", "--noEmit"},
|
|
files: getTscNoEmitDtsChangesFileMap(true, true),
|
|
cwd: "/home/src/projects/project",
|
|
edits: getTscNoEmitDtsChangesEdits([]string{"-b", "-v"}),
|
|
},
|
|
}
|
|
}
|
|
getTscNoEmitDtsChangesMultiFileErrorsTestCases := func(commandLineArgs []string) []*tscInput {
|
|
aContent := `export const a = class { private p = 10; };`
|
|
return []*tscInput{
|
|
{
|
|
subScenario: "dts errors with declaration enable changes with multiple files",
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noEmit"}),
|
|
files: FileMap{
|
|
"/home/src/projects/project/a.ts": aContent,
|
|
"/home/src/projects/project/b.ts": `export const b = 10;`,
|
|
"/home/src/projects/project/c.ts": strings.Replace(aContent, "a", "c", 1),
|
|
"/home/src/projects/project/d.ts": strings.Replace(aContent, "a", "d", 1),
|
|
"/home/src/projects/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
cwd: "/home/src/projects/project",
|
|
edits: slices.Concat(
|
|
getTscNoEmitDtsChangesEdits(commandLineArgs),
|
|
[]*tscEdit{
|
|
{
|
|
caption: "Fix the another ",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/projects/project/c.ts", "private", "public")
|
|
},
|
|
commandLineArgs: slices.Concat(commandLineArgs, []string{"--noEmit", "--declaration", "--declarationMap"}),
|
|
},
|
|
},
|
|
),
|
|
},
|
|
}
|
|
}
|
|
getTscNoEmitLoopTestCase := func(suffix string, commandLineArgs []string) *tscInput {
|
|
return &tscInput{
|
|
subScenario: "does not go in loop when watching when no files are emitted" + suffix,
|
|
files: FileMap{
|
|
"/user/username/projects/myproject/a.js": "",
|
|
"/user/username/projects/myproject/b.ts": "",
|
|
"/user/username/projects/myproject/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"allowJs": true,
|
|
"noEmit": true,
|
|
},
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "No change",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(`/user/username/projects/myproject/a.js`, sys.readFileNoError(`/user/username/projects/myproject/a.js`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "change",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(`/user/username/projects/myproject/a.js`, "const x = 10;", false)
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
testCases := slices.Concat(
|
|
[]*tscInput{
|
|
{
|
|
subScenario: "when project has strict true",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"strict": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/class1.ts": `export class class1 {}`,
|
|
},
|
|
commandLineArgs: []string{"--noEmit"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
getTscNoEmitLoopTestCase("", []string{"-b", "-w", "-verbose"}),
|
|
getTscNoEmitLoopTestCase(" with incremental", []string{"-b", "-w", "-verbose", "--incremental"}),
|
|
},
|
|
getTscNoEmitAndErrorsTestCases([]string{}),
|
|
getTscNoEmitAndErrorsTestCases([]string{"-b", "-v"}),
|
|
getTscNoEmitChangesTestCases([]string{}),
|
|
getTscNoEmitChangesTestCases([]string{"-b", "-v"}),
|
|
getTscNoEmitDtsChangesTestCases(),
|
|
getTscNoEmitDtsChangesMultiFileErrorsTestCases([]string{}),
|
|
getTscNoEmitDtsChangesMultiFileErrorsTestCases([]string{"-b", "-v"}),
|
|
getTscNoEmitAndErrorsWatchTestCases([]string{"-b", "-verbose", "-w"}),
|
|
)
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "noEmit")
|
|
}
|
|
}
|
|
|
|
func TestTscNoEmitOnError(t *testing.T) {
|
|
t.Parallel()
|
|
type tscNoEmitOnErrorScenario struct {
|
|
subScenario string
|
|
mainErrorContent string
|
|
fixedErrorContent string
|
|
}
|
|
getTscNoEmitOnErrorFileMap := func(scenario *tscNoEmitOnErrorScenario, declaration bool, incremental bool) FileMap {
|
|
return FileMap{
|
|
"/user/username/projects/noEmitOnError/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "./dev-build",
|
|
"declaration": %t,
|
|
"incremental": %t,
|
|
"noEmitOnError": true,
|
|
},
|
|
}`, declaration, incremental)),
|
|
"/user/username/projects/noEmitOnError/shared/types/db.ts": stringtestutil.Dedent(`
|
|
export interface A {
|
|
name: string;
|
|
}
|
|
`),
|
|
"/user/username/projects/noEmitOnError/src/main.ts": scenario.mainErrorContent,
|
|
"/user/username/projects/noEmitOnError/src/other.ts": stringtestutil.Dedent(`
|
|
console.log("hi");
|
|
export { }
|
|
`),
|
|
}
|
|
}
|
|
getTscNoEmitOnErrorTestCases := func(scenarios []*tscNoEmitOnErrorScenario, commandLineArgs []string) []*tscInput {
|
|
testCases := make([]*tscInput, 0, len(scenarios)*4)
|
|
for _, scenario := range scenarios {
|
|
edits := []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "Fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/noEmitOnError/src/main.ts", scenario.fixedErrorContent, false)
|
|
},
|
|
},
|
|
noChange,
|
|
}
|
|
testCases = append(
|
|
testCases,
|
|
&tscInput{
|
|
subScenario: scenario.subScenario,
|
|
files: getTscNoEmitOnErrorFileMap(scenario, false, false),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
&tscInput{
|
|
subScenario: scenario.subScenario + " with declaration",
|
|
files: getTscNoEmitOnErrorFileMap(scenario, true, false),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
&tscInput{
|
|
subScenario: scenario.subScenario + " with incremental",
|
|
files: getTscNoEmitOnErrorFileMap(scenario, false, true),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
&tscInput{
|
|
subScenario: scenario.subScenario + " with declaration with incremental",
|
|
files: getTscNoEmitOnErrorFileMap(scenario, true, true),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
)
|
|
}
|
|
return testCases
|
|
}
|
|
getTscWatchNoEmitOnErrorTestCases := func(scenarios []*tscNoEmitOnErrorScenario, commandLineArgs []string) []*tscInput {
|
|
var edits []*tscEdit
|
|
for _, scenario := range scenarios {
|
|
if edits != nil {
|
|
edits = append(edits, &tscEdit{
|
|
caption: scenario.subScenario,
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(`/user/username/projects/noEmitOnError/src/main.ts`, scenario.mainErrorContent, false)
|
|
},
|
|
})
|
|
}
|
|
edits = append(edits,
|
|
&tscEdit{
|
|
caption: "No Change",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(`/user/username/projects/noEmitOnError/src/main.ts`, sys.readFileNoError(`/user/username/projects/noEmitOnError/src/main.ts`), false)
|
|
},
|
|
},
|
|
&tscEdit{
|
|
caption: "Fix " + scenario.subScenario,
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/noEmitOnError/src/main.ts", scenario.fixedErrorContent, false)
|
|
},
|
|
},
|
|
&tscEdit{
|
|
caption: "No Change",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(`/user/username/projects/noEmitOnError/src/main.ts`, sys.readFileNoError(`/user/username/projects/noEmitOnError/src/main.ts`), false)
|
|
},
|
|
},
|
|
)
|
|
}
|
|
return []*tscInput{
|
|
{
|
|
subScenario: "noEmitOnError",
|
|
files: getTscNoEmitOnErrorFileMap(scenarios[0], false, false),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
{
|
|
subScenario: "noEmitOnError with declaration",
|
|
files: getTscNoEmitOnErrorFileMap(scenarios[0], true, false),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
{
|
|
subScenario: "noEmitOnError with incremental",
|
|
files: getTscNoEmitOnErrorFileMap(scenarios[0], false, true),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
{
|
|
subScenario: "noEmitOnError with declaration with incremental",
|
|
files: getTscNoEmitOnErrorFileMap(scenarios[0], true, true),
|
|
cwd: "/user/username/projects/noEmitOnError",
|
|
commandLineArgs: commandLineArgs,
|
|
edits: edits,
|
|
},
|
|
}
|
|
}
|
|
scenarios := []*tscNoEmitOnErrorScenario{
|
|
{
|
|
subScenario: "syntax errors",
|
|
mainErrorContent: stringtestutil.Dedent(`
|
|
import { A } from "../shared/types/db";
|
|
const a = {
|
|
lastName: 'sdsd'
|
|
;
|
|
`),
|
|
fixedErrorContent: stringtestutil.Dedent(`
|
|
import { A } from "../shared/types/db";
|
|
const a = {
|
|
lastName: 'sdsd'
|
|
};`),
|
|
},
|
|
{
|
|
subScenario: "semantic errors",
|
|
mainErrorContent: stringtestutil.Dedent(`
|
|
import { A } from "../shared/types/db";
|
|
const a: string = 10;`),
|
|
fixedErrorContent: stringtestutil.Dedent(`
|
|
import { A } from "../shared/types/db";
|
|
const a: string = "hello";`),
|
|
},
|
|
{
|
|
subScenario: "dts errors",
|
|
mainErrorContent: stringtestutil.Dedent(`
|
|
import { A } from "../shared/types/db";
|
|
export const a = class { private p = 10; };
|
|
`),
|
|
fixedErrorContent: stringtestutil.Dedent(`
|
|
import { A } from "../shared/types/db";
|
|
export const a = class { p = 10; };
|
|
`),
|
|
},
|
|
}
|
|
testCases := slices.Concat(
|
|
getTscNoEmitOnErrorTestCases(scenarios, []string{}),
|
|
getTscNoEmitOnErrorTestCases(scenarios, []string{"-b", "-v"}),
|
|
[]*tscInput{
|
|
{
|
|
subScenario: `when declarationMap changes`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"noEmitOnError": true,
|
|
"declaration": true,
|
|
"composite": true,
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/a.ts": "const x = 10;",
|
|
"/home/src/workspaces/project/b.ts": "const y = 10;",
|
|
},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "error and enable declarationMap",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/a.ts", "x", "x: 20")
|
|
},
|
|
commandLineArgs: []string{"--declarationMap"},
|
|
},
|
|
{
|
|
caption: "fix error declarationMap",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/a.ts", "x: 20", "x")
|
|
},
|
|
commandLineArgs: []string{"--declarationMap"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "file deleted before fixing error with noEmitOnError",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "outDir",
|
|
"noEmitOnError": true,
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/project/file1.ts": `export const x: 30 = "hello";`,
|
|
"/home/src/workspaces/project/file2.ts": `export class D { }`,
|
|
},
|
|
commandLineArgs: []string{"-i"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete file without error",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/project/file2.ts")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
getTscWatchNoEmitOnErrorTestCases(scenarios, []string{"-b", "-w", "-v"}),
|
|
)
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "noEmitOnError")
|
|
}
|
|
}
|
|
|
|
func TestTscProjectReferences(t *testing.T) {
|
|
t.Parallel()
|
|
cases := []tscInput{
|
|
{
|
|
subScenario: "when project references composite project with noEmit",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/utils/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/solution/utils/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"noEmit": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/solution/project/index.ts": `import { x } from "../utils";`,
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../utils" },
|
|
],
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "project"},
|
|
},
|
|
{
|
|
subScenario: "when project references composite",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/utils/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/solution/utils/index.d.ts": "export declare const x = 10;",
|
|
"/home/src/workspaces/solution/utils/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/solution/project/index.ts": `import { x } from "../utils";`,
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../utils" },
|
|
],
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "project"},
|
|
},
|
|
{
|
|
subScenario: "when project reference is not built",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/utils/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/solution/utils/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/solution/project/index.ts": `import { x } from "../utils";`,
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../utils" },
|
|
],
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "project"},
|
|
},
|
|
{
|
|
subScenario: "when project contains invalid project reference",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/project/index.ts": `export const x = 10;`,
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../utils" },
|
|
],
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "project"},
|
|
},
|
|
{
|
|
subScenario: "default import interop uses referenced project settings",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/node_modules/ambiguous-package/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "ambiguous-package"
|
|
}`),
|
|
"/home/src/workspaces/project/node_modules/ambiguous-package/index.d.ts": "export declare const ambiguous: number;",
|
|
"/home/src/workspaces/project/node_modules/esm-package/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "esm-package",
|
|
"type": "module"
|
|
}`),
|
|
"/home/src/workspaces/project/node_modules/esm-package/index.d.ts": "export declare const esm: number;",
|
|
"/home/src/workspaces/project/lib/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"rootDir": "src",
|
|
"outDir": "dist",
|
|
"module": "esnext",
|
|
"moduleResolution": "bundler",
|
|
},
|
|
"include": ["src"],
|
|
}`),
|
|
"/home/src/workspaces/project/lib/src/a.ts": "export const a = 0;",
|
|
"/home/src/workspaces/project/lib/dist/a.d.ts": "export declare const a = 0;",
|
|
"/home/src/workspaces/project/app/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "esnext",
|
|
"moduleResolution": "bundler",
|
|
"rootDir": "src",
|
|
"outDir": "dist",
|
|
},
|
|
"include": ["src"],
|
|
"references": [
|
|
{ "path": "../lib" },
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/project/app/src/local.ts": "export const local = 0;",
|
|
"/home/src/workspaces/project/app/src/index.ts": stringtestutil.Dedent(`
|
|
import local from "./local"; // Error
|
|
import esm from "esm-package"; // Error
|
|
import referencedSource from "../../lib/src/a"; // Error
|
|
import referencedDeclaration from "../../lib/dist/a"; // Error
|
|
import ambiguous from "ambiguous-package"; // Ok`),
|
|
},
|
|
commandLineArgs: []string{"--p", "app", "--pretty", "false"},
|
|
},
|
|
{
|
|
subScenario: "referencing ambient const enum from referenced project with preserveConstEnums",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/utils/index.ts": "export const enum E { A = 1 }",
|
|
"/home/src/workspaces/solution/utils/index.d.ts": "export declare const enum E { A = 1 }",
|
|
"/home/src/workspaces/solution/utils/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"preserveConstEnums": true,
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/solution/project/index.ts": `import { E } from "../utils"; E.A;`,
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"isolatedModules": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../utils" },
|
|
],
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "project"},
|
|
},
|
|
{
|
|
subScenario: "importing const enum from referenced project with preserveConstEnums and verbatimModuleSyntax",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/preserve/index.ts": "export const enum E { A = 1 }",
|
|
"/home/src/workspaces/solution/preserve/index.d.ts": "export declare const enum E { A = 1 }",
|
|
"/home/src/workspaces/solution/preserve/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"preserveConstEnums": true,
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/solution/no-preserve/index.ts": "export const enum E { A = 1 }",
|
|
"/home/src/workspaces/solution/no-preserve/index.d.ts": "export declare const enum F { A = 1 }",
|
|
"/home/src/workspaces/solution/no-preserve/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"preserveConstEnums": false,
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/solution/project/index.ts": stringtestutil.Dedent(`
|
|
import { E } from "../preserve";
|
|
import { F } from "../no-preserve";
|
|
E.A;
|
|
F.A;`),
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "preserve",
|
|
"verbatimModuleSyntax": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../preserve" },
|
|
{ "path": "../no-preserve" },
|
|
],
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "project", "--pretty", "false"},
|
|
},
|
|
{
|
|
subScenario: "rewriteRelativeImportExtensionsProjectReferences1",
|
|
files: FileMap{
|
|
"/home/src/workspaces/packages/common/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"rootDir": "src",
|
|
"outDir": "dist",
|
|
"module": "nodenext"
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/packages/common/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"name": "common",
|
|
"version": "1.0.0",
|
|
"type": "module",
|
|
"exports": {
|
|
".": {
|
|
"source": "./src/index.ts",
|
|
"default": "./dist/index.js"
|
|
}
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/packages/common/src/index.ts": "export {};",
|
|
"/home/src/workspaces/packages/common/dist/index.d.ts": "export {};",
|
|
"/home/src/workspaces/packages/main/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "nodenext",
|
|
"rewriteRelativeImportExtensions": true,
|
|
"rootDir": "src",
|
|
"outDir": "dist"
|
|
},
|
|
"references": [
|
|
{ "path": "../common" }
|
|
]
|
|
}`),
|
|
"/home/src/workspaces/packages/main/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"type": "module"
|
|
}`),
|
|
"/home/src/workspaces/packages/main/src/index.ts": `import {} from "../../common/src/index.ts";`,
|
|
},
|
|
cwd: "/home/src/workspaces",
|
|
commandLineArgs: []string{"-p", "packages/main", "--pretty", "false"},
|
|
},
|
|
{
|
|
subScenario: "rewriteRelativeImportExtensionsProjectReferences2",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/src/tsconfig-base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "nodenext",
|
|
"composite": true,
|
|
"rootDir": ".",
|
|
"outDir": "../dist",
|
|
"rewriteRelativeImportExtensions": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/solution/src/compiler/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {}
|
|
}`),
|
|
"/home/src/workspaces/solution/src/compiler/parser.ts": "export {};",
|
|
"/home/src/workspaces/solution/dist/compiler/parser.d.ts": "export {};",
|
|
"/home/src/workspaces/solution/src/services/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {},
|
|
"references": [
|
|
{ "path": "../compiler" }
|
|
]
|
|
}`),
|
|
"/home/src/workspaces/solution/src/services/services.ts": `import {} from "../compiler/parser.ts";`,
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "src/services", "--pretty", "false"},
|
|
},
|
|
{
|
|
subScenario: "rewriteRelativeImportExtensionsProjectReferences3",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/src/tsconfig-base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"module": "nodenext",
|
|
"composite": true,
|
|
"rewriteRelativeImportExtensions": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/solution/src/compiler/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"rootDir": ".",
|
|
"outDir": "../../dist/compiler"
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/solution/src/compiler/parser.ts": "export {};",
|
|
"/home/src/workspaces/solution/dist/compiler/parser.d.ts": "export {};",
|
|
"/home/src/workspaces/solution/src/services/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"rootDir": ".",
|
|
"outDir": "../../dist/services"
|
|
},
|
|
"references": [
|
|
{ "path": "../compiler" }
|
|
]
|
|
}`),
|
|
"/home/src/workspaces/solution/src/services/services.ts": `import {} from "../compiler/parser.ts";`,
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--p", "src/services", "--pretty", "false"},
|
|
},
|
|
{
|
|
subScenario: "default setup was created correctly",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/primary/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/primary/a.ts": "export { };",
|
|
"/home/src/workspaces/project/secondary/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"references": [{
|
|
"path": "../primary"
|
|
}]
|
|
}`),
|
|
"/home/src/workspaces/project/secondary/b.ts": `import * as mod_1 from "../primary/a";`,
|
|
},
|
|
commandLineArgs: []string{"--p", "primary/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "errors when declaration = false",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/primary/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
"declaration": false
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/primary/a.ts": "export { };",
|
|
},
|
|
commandLineArgs: []string{"--p", "primary/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "errors when the referenced project doesnt have composite",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/primary/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": false,
|
|
"outDir": "bin",
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/primary/a.ts": "export { };",
|
|
"/home/src/workspaces/project/reference/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"files": [ "b.ts" ],
|
|
"references": [ { "path": "../primary" } ]
|
|
}`),
|
|
"/home/src/workspaces/project/reference/b.ts": `import * as mod_1 from "../primary/a";`,
|
|
},
|
|
commandLineArgs: []string{"--p", "reference/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "does not error when the referenced project doesnt have composite if its a container project",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/primary/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": false,
|
|
"outDir": "bin",
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/primary/a.ts": "export { };",
|
|
"/home/src/workspaces/project/reference/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"files": [ ],
|
|
"references": [{
|
|
"path": "../primary"
|
|
}]
|
|
}`),
|
|
"/home/src/workspaces/project/reference/b.ts": `import * as mod_1 from "../primary/a";`,
|
|
},
|
|
commandLineArgs: []string{"--p", "reference/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "errors when the file list is not exhaustive",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/primary/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"files": [ "a.ts" ]
|
|
}`),
|
|
"/home/src/workspaces/project/primary/a.ts": "import * as b from './b'",
|
|
"/home/src/workspaces/project/primary/b.ts": "export {}",
|
|
},
|
|
commandLineArgs: []string{"--p", "primary/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "errors when the referenced project doesnt exist",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/primary/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"references": [{
|
|
"path": "../foo"
|
|
}]
|
|
}`),
|
|
"/home/src/workspaces/project/primary/a.ts": "export { };",
|
|
},
|
|
commandLineArgs: []string{"--p", "primary/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "redirects to the output dts file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/alpha/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/alpha/a.ts": "export const m: number = 3;",
|
|
"/home/src/workspaces/project/alpha/bin/a.d.ts": "export { };",
|
|
"/home/src/workspaces/project/beta/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"references": [ { "path": "../alpha" } ]
|
|
}`),
|
|
"/home/src/workspaces/project/beta/b.ts": "import { m } from '../alpha/a'",
|
|
},
|
|
commandLineArgs: []string{"--p", "beta/tsconfig.json", "--explainFiles"},
|
|
},
|
|
{
|
|
subScenario: "issues a nice error when the input file is missing",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/alpha/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"references": []
|
|
}`),
|
|
"/home/src/workspaces/project/alpha/a.ts": "export const m: number = 3;",
|
|
"/home/src/workspaces/project/beta/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"references": [ { "path": "../alpha" } ]
|
|
}`),
|
|
"/home/src/workspaces/project/beta/b.ts": "import { m } from '../alpha/a'",
|
|
},
|
|
commandLineArgs: []string{"--p", "beta/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "issues a nice error when the input file is missing when module reference is not relative",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/alpha/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/alpha/a.ts": "export const m: number = 3;",
|
|
"/home/src/workspaces/project/beta/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
"paths": {
|
|
"@alpha/*": ["../alpha/*"],
|
|
},
|
|
},
|
|
"references": [ { "path": "../alpha" } ]
|
|
}`),
|
|
"/home/src/workspaces/project/beta/b.ts": "import { m } from '@alpha/a'",
|
|
},
|
|
commandLineArgs: []string{"--p", "beta/tsconfig.json"},
|
|
},
|
|
{
|
|
subScenario: "doesnt infer the rootDir from source paths",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/alpha/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"references": []
|
|
}`),
|
|
"/home/src/workspaces/project/alpha/src/a.ts": "export const m: number = 3;",
|
|
},
|
|
commandLineArgs: []string{"--p", "alpha/tsconfig.json"},
|
|
},
|
|
{
|
|
// !!! sheetal rootDir error not reported
|
|
subScenario: "errors when a file is outside the rootdir",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/alpha/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "bin",
|
|
},
|
|
"references": []
|
|
}`),
|
|
"/home/src/workspaces/project/alpha/src/a.ts": "import * as b from '../../beta/b'",
|
|
"/home/src/workspaces/project/beta/b.ts": "export { }",
|
|
},
|
|
commandLineArgs: []string{"--p", "alpha/tsconfig.json"},
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
c.run(t, "projectReferences")
|
|
}
|
|
}
|
|
|
|
func TestTypeAcquisition(t *testing.T) {
|
|
t.Parallel()
|
|
(&tscInput{
|
|
subScenario: "parse tsconfig with typeAcquisition",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"noEmit": true,
|
|
},
|
|
"typeAcquisition": {
|
|
"enable": true,
|
|
"include": ["0.d.ts", "1.d.ts"],
|
|
"exclude": ["0.js", "1.js"],
|
|
"disableFilenameBasedTypeAcquisition": true,
|
|
},
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{},
|
|
}).run(t, "typeAcquisition")
|
|
}
|