3935 lines
129 KiB
Go
3935 lines
129 KiB
Go
package tsctests
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/harnessutil"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/stringtestutil"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/vfstest"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
func TestBuildCommandLine(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildCommandLineDifferentOptionsMap := func(optionName string) FileMap {
|
|
return FileMap{
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"%s": true
|
|
}
|
|
}`, optionName)),
|
|
"/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;`,
|
|
}
|
|
}
|
|
getBuildCommandLineEmitDeclarationOnlyMap := func(options []string) FileMap {
|
|
compilerOptionsStr := strings.Join(core.Map(options, func(opt string) string {
|
|
return fmt.Sprintf(`"%s": true`, opt)
|
|
}), ", ")
|
|
return FileMap{
|
|
"/home/src/workspaces/solution/project1/src/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": { %s }
|
|
}`, compilerOptionsStr)),
|
|
"/home/src/workspaces/solution/project1/src/a.ts": `export const a = 10;const aLocal = 10;`,
|
|
"/home/src/workspaces/solution/project1/src/b.ts": `export const b = 10;const bLocal = 10;`,
|
|
"/home/src/workspaces/solution/project1/src/c.ts": `import { a } from "./a";export const c = a;`,
|
|
"/home/src/workspaces/solution/project1/src/d.ts": `import { b } from "./b";export const d = b;`,
|
|
"/home/src/workspaces/solution/project2/src/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": { %s },
|
|
"references": [{ "path": "../../project1/src" }]
|
|
}`, compilerOptionsStr)),
|
|
"/home/src/workspaces/solution/project2/src/e.ts": `export const e = 10;`,
|
|
"/home/src/workspaces/solution/project2/src/f.ts": `import { a } from "../../project1/src/a"; export const f = a;`,
|
|
"/home/src/workspaces/solution/project2/src/g.ts": `import { b } from "../../project1/src/b"; export const g = b;`,
|
|
}
|
|
}
|
|
getBuildCommandLineEmitDeclarationOnlyTestCases := func(options []string, suffix string) []*tscInput {
|
|
return []*tscInput{
|
|
{
|
|
subScenario: "emitDeclarationOnly on commandline" + suffix,
|
|
files: getBuildCommandLineEmitDeclarationOnlyMap(options),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose", "--emitDeclarationOnly"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "local change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/a.ts", "const aa = 10;")
|
|
},
|
|
},
|
|
{
|
|
caption: "non local change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/a.ts", "export const aaa = 10;")
|
|
},
|
|
},
|
|
{
|
|
caption: "emit js files",
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose"},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "js emit with change without emitDeclarationOnly",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/b.ts", "const alocal = 10;")
|
|
},
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose"},
|
|
},
|
|
{
|
|
caption: "local change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/b.ts", "const aaaa = 10;")
|
|
},
|
|
},
|
|
{
|
|
caption: "non local change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/b.ts", "export const aaaaa = 10;")
|
|
},
|
|
},
|
|
{
|
|
caption: "js emit with change without emitDeclarationOnly",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/b.ts", "export const a2 = 10;")
|
|
},
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "emitDeclarationOnly false on commandline" + suffix,
|
|
files: getBuildCommandLineEmitDeclarationOnlyMap(slices.Concat(options, []string{"emitDeclarationOnly"})),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/a.ts", "const aa = 10;")
|
|
},
|
|
},
|
|
{
|
|
caption: "emit js files",
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose", "--emitDeclarationOnly", "false"},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "no change run with js emit",
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose", "--emitDeclarationOnly", "false"},
|
|
},
|
|
{
|
|
caption: "js emit with change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/project1/src/b.ts", "const blocal = 10;")
|
|
},
|
|
commandLineArgs: []string{"--b", "project2/src", "--verbose", "--emitDeclarationOnly", "false"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
testCases := slices.Concat(
|
|
[]*tscInput{
|
|
{
|
|
subScenario: "help",
|
|
files: FileMap{},
|
|
commandLineArgs: []string{"--build", "--help"},
|
|
},
|
|
{
|
|
subScenario: "different options",
|
|
files: getBuildCommandLineDifferentOptionsMap("composite"),
|
|
commandLineArgs: []string{"--build", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--sourceMap"},
|
|
},
|
|
{
|
|
caption: "should re-emit only js so they dont contain sourcemap",
|
|
},
|
|
{
|
|
caption: "with declaration should not emit anything",
|
|
commandLineArgs: []string{"--build", "--verbose", "--declaration"},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "with declaration and declarationMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--declaration", "--declarationMap"},
|
|
},
|
|
{
|
|
caption: "should re-emit only dts so they dont contain sourcemap",
|
|
},
|
|
{
|
|
caption: "with emitDeclarationOnly should not emit anything",
|
|
commandLineArgs: []string{"--build", "--verbose", "--emitDeclarationOnly"},
|
|
},
|
|
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{"--build", "--verbose", "--declaration"},
|
|
},
|
|
{
|
|
caption: "with inlineSourceMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--inlineSourceMap"},
|
|
},
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--sourceMap"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "different options with incremental",
|
|
files: getBuildCommandLineDifferentOptionsMap("incremental"),
|
|
commandLineArgs: []string{"--build", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--sourceMap"},
|
|
},
|
|
{
|
|
caption: "should re-emit only js so they dont contain sourcemap",
|
|
},
|
|
{
|
|
caption: "with declaration, emit Dts and should not emit js",
|
|
commandLineArgs: []string{"--build", "--verbose", "--declaration"},
|
|
},
|
|
{
|
|
caption: "with declaration and declarationMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--declaration", "--declarationMap"},
|
|
},
|
|
noChange,
|
|
{
|
|
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{"--build", "--verbose", "--declaration", "--declarationMap"},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "with inlineSourceMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--inlineSourceMap"},
|
|
},
|
|
{
|
|
caption: "with sourceMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--sourceMap"},
|
|
},
|
|
{
|
|
caption: "emit js files",
|
|
},
|
|
{
|
|
caption: "with declaration and declarationMap",
|
|
commandLineArgs: []string{"--build", "--verbose", "--declaration", "--declarationMap"},
|
|
},
|
|
{
|
|
caption: "with declaration and declarationMap, should not re-emit",
|
|
commandLineArgs: []string{"--build", "--verbose", "--declaration", "--declarationMap"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
getBuildCommandLineEmitDeclarationOnlyTestCases([]string{"composite"}, ""),
|
|
getBuildCommandLineEmitDeclarationOnlyTestCases([]string{"incremental", "declaration"}, " with declaration and incremental"),
|
|
getBuildCommandLineEmitDeclarationOnlyTestCases([]string{"declaration"}, " with declaration"),
|
|
)
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "commandLine")
|
|
}
|
|
}
|
|
|
|
func TestBuildClean(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "file name and output name clashing",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/index.js": "",
|
|
"/home/src/workspaces/solution/bar.ts": "",
|
|
"/home/src/workspaces/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "allowJs": true }
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "--clean"},
|
|
},
|
|
{
|
|
subScenario: "tsx with dts emit",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/project/src/main.tsx": "export const x = 10;",
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "declaration": true },
|
|
"include": ["src/**/*.tsx", "src/**/*.ts"]
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "project", "-v", "--explainFiles"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "clean build",
|
|
commandLineArgs: []string{"-b", "project", "--clean"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "clean")
|
|
}
|
|
}
|
|
|
|
func TestBuildConfigFileErrors(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "when tsconfig extends the missing file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/tsconfig.first.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./foobar.json",
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/tsconfig.second.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./foobar.json",
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "./tsconfig.first.json" },
|
|
{ "path": "./tsconfig.second.json" }
|
|
]
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b"},
|
|
},
|
|
{
|
|
subScenario: "reports syntax errors in config file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/a.ts": "export function foo() { }",
|
|
"/home/src/workspaces/project/b.ts": "export function bar() { }",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"files": [
|
|
"a.ts"
|
|
"b.ts"
|
|
]
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "reports syntax errors after change to config file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/tsconfig.json", ",", `, "declaration": true`)
|
|
},
|
|
},
|
|
{
|
|
caption: "reports syntax errors after change to ts file",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/a.ts", "export function fooBar() { }")
|
|
},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "builds after fixing config file errors",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true, "declaration": true
|
|
},
|
|
"files": [
|
|
"a.ts",
|
|
"b.ts"
|
|
]
|
|
}`), false)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "missing config file",
|
|
files: FileMap{},
|
|
commandLineArgs: []string{"--b", "bogus.json"},
|
|
},
|
|
{
|
|
subScenario: "reports syntax errors in config file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/a.ts": "export function foo() { }",
|
|
"/home/src/workspaces/project/b.ts": "export function bar() { }",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"files": [
|
|
"a.ts"
|
|
"b.ts"
|
|
]
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b", "-w"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "reports syntax errors after change to config file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/tsconfig.json", ",", `, "declaration": true`)
|
|
},
|
|
},
|
|
{
|
|
caption: "reports syntax errors after change to ts file",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/a.ts", "export function fooBar() { }")
|
|
},
|
|
},
|
|
{
|
|
caption: "reports error when there is no change to tsconfig file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/tsconfig.json", "", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "builds after fixing config file errors",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/home/src/workspaces/project/tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true, "declaration": true
|
|
},
|
|
"files": [
|
|
"a.ts",
|
|
"b.ts"
|
|
]
|
|
}`), false)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "configFileErrors")
|
|
}
|
|
}
|
|
|
|
func TestBuildDemoProject(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
getBuildDemoFileMap := func(modify func(FileMap)) FileMap {
|
|
files := FileMap{
|
|
"/user/username/projects/demo/animals/animal.ts": stringtestutil.Dedent(`
|
|
export type Size = "small" | "medium" | "large";
|
|
export default interface Animal {
|
|
size: Size;
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/animals/dog.ts": stringtestutil.Dedent(`
|
|
import Animal from '.';
|
|
import { makeRandomName } from '../core/utilities';
|
|
|
|
export interface Dog extends Animal {
|
|
woof(): void;
|
|
name: string;
|
|
}
|
|
|
|
export function createDog(): Dog {
|
|
return ({
|
|
size: "medium",
|
|
woof: function(this: Dog) {
|
|
console.log(` + "`" + `${ this.name } says "Woof"!` + "`" + `);
|
|
},
|
|
name: makeRandomName()
|
|
});
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/animals/index.ts": stringtestutil.Dedent(`
|
|
import Animal from './animal';
|
|
|
|
export default Animal;
|
|
import { createDog, Dog } from './dog';
|
|
export { createDog, Dog };
|
|
`),
|
|
"/user/username/projects/demo/animals/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/animals",
|
|
"rootDir": "."
|
|
},
|
|
"references": [
|
|
{ "path": "../core" }
|
|
]
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/core/utilities.ts": stringtestutil.Dedent(`
|
|
|
|
export function makeRandomName() {
|
|
return "Bob!?! ";
|
|
}
|
|
|
|
export function lastElementOf<T>(arr: T[]): T | undefined {
|
|
if (arr.length === 0) return undefined;
|
|
return arr[arr.length - 1];
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/core/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/core",
|
|
"rootDir": "."
|
|
},
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/zoo/zoo.ts": stringtestutil.Dedent(`
|
|
import { Dog, createDog } from '../animals/index';
|
|
|
|
export function createZoo(): Array<Dog> {
|
|
return [
|
|
createDog()
|
|
];
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/zoo/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/zoo",
|
|
"rootDir": "."
|
|
},
|
|
"references": [
|
|
{
|
|
"path": "../animals"
|
|
}
|
|
]
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/tsconfig-base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"declaration": true,
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"strict": true,
|
|
"noUnusedLocals": true,
|
|
"noUnusedParameters": true,
|
|
"noImplicitReturns": true,
|
|
"noFallthroughCasesInSwitch": true,
|
|
"composite": true,
|
|
},
|
|
}
|
|
`),
|
|
"/user/username/projects/demo/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": [],
|
|
"references": [
|
|
{
|
|
"path": "./core"
|
|
},
|
|
{
|
|
"path": "./animals",
|
|
},
|
|
{
|
|
"path": "./zoo",
|
|
},
|
|
],
|
|
}
|
|
`),
|
|
}
|
|
if modify != nil {
|
|
modify(files)
|
|
}
|
|
return files
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "in master branch with everything setup correctly and reports no error",
|
|
files: getBuildDemoFileMap(nil),
|
|
cwd: "/user/username/projects/demo",
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "in circular branch reports the error about it by stopping build",
|
|
files: getBuildDemoFileMap(func(files FileMap) {
|
|
files["/user/username/projects/demo/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/core",
|
|
"rootDir": "."
|
|
},
|
|
"references": [
|
|
{
|
|
"path": "../zoo",
|
|
}
|
|
]
|
|
}
|
|
`)
|
|
}),
|
|
cwd: "/user/username/projects/demo",
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
},
|
|
{
|
|
// !!! sheetal - this has missing errors from strada about files not in rootDir (3)
|
|
subScenario: "in bad-ref branch reports the error about files not in rootDir at the import location",
|
|
files: getBuildDemoFileMap(func(files FileMap) {
|
|
files["/user/username/projects/demo/core/utilities.ts"] = `import * as A from '../animals'
|
|
` + files["/user/username/projects/demo/core/utilities.ts"].(string)
|
|
}),
|
|
cwd: "/user/username/projects/demo",
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "in circular is set in the reference",
|
|
files: getBuildDemoFileMap(func(files FileMap) {
|
|
files["/user/username/projects/demo/a/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/a",
|
|
"rootDir": "."
|
|
},
|
|
"references": [
|
|
{
|
|
"path": "../b",
|
|
"circular": true
|
|
}
|
|
]
|
|
}`)
|
|
files["/user/username/projects/demo/b/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/b",
|
|
"rootDir": "."
|
|
},
|
|
"references": [
|
|
{
|
|
"path": "../a",
|
|
}
|
|
]
|
|
}`)
|
|
files["/user/username/projects/demo/a/index.ts"] = "export const a = 10;"
|
|
files["/user/username/projects/demo/b/index.ts"] = "export const b = 10;"
|
|
files["/user/username/projects/demo/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"files": [],
|
|
"references": [
|
|
{
|
|
"path": "./core"
|
|
},
|
|
{
|
|
"path": "./animals",
|
|
},
|
|
{
|
|
"path": "./zoo",
|
|
},
|
|
{
|
|
"path": "./a",
|
|
},
|
|
{
|
|
"path": "./b",
|
|
},
|
|
],
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/demo",
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "updates with circular reference",
|
|
files: getBuildDemoFileMap(func(files FileMap) {
|
|
files["/user/username/projects/demo/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/core",
|
|
"rootDir": "."
|
|
},
|
|
"references": [
|
|
{
|
|
"path": "../zoo",
|
|
}
|
|
]
|
|
}
|
|
`)
|
|
}),
|
|
cwd: "/user/username/projects/demo",
|
|
commandLineArgs: []string{"--b", "-w", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/demo/core/tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"outDir": "../lib/core",
|
|
"rootDir": "."
|
|
},
|
|
}
|
|
`), false)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
// !!! sheetal - this has missing errors from strada about files not in rootDir (3)
|
|
subScenario: "updates with bad reference",
|
|
files: getBuildDemoFileMap(func(files FileMap) {
|
|
files["/user/username/projects/demo/core/utilities.ts"] = `import * as A from '../animals'
|
|
` + files["/user/username/projects/demo/core/utilities.ts"].(string)
|
|
}),
|
|
cwd: "/user/username/projects/demo",
|
|
commandLineArgs: []string{"--b", "-w", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Prepend a line",
|
|
edit: func(sys *testSys) {
|
|
sys.prependFile("/user/username/projects/demo/core/utilities.ts", "\n")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "demo")
|
|
}
|
|
}
|
|
|
|
func TestBuildEmitDeclarationOnly(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildEmitDeclarationOnlyImportFileMap := func(declarationMap bool, circularRef bool) FileMap {
|
|
files := FileMap{
|
|
"/home/src/workspaces/project/src/a.ts": stringtestutil.Dedent(`
|
|
import { B } from "./b";
|
|
|
|
export interface A {
|
|
b: B;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/src/b.ts": stringtestutil.Dedent(`
|
|
import { C } from "./c";
|
|
|
|
export interface B {
|
|
b: C;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/src/c.ts": stringtestutil.Dedent(`
|
|
import { A } from "./a";
|
|
|
|
export interface C {
|
|
a: A;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/src/index.ts": stringtestutil.Dedent(`
|
|
export { A } from "./a";
|
|
export { B } from "./b";
|
|
export { C } from "./c";
|
|
`),
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"declaration": true,
|
|
"declarationMap": %t,
|
|
"sourceMap": true,
|
|
"outDir": "./lib",
|
|
"composite": true,
|
|
"strict": true,
|
|
"esModuleInterop": true,
|
|
"alwaysStrict": true,
|
|
"rootDir": "src",
|
|
"emitDeclarationOnly": true,
|
|
},
|
|
}`, declarationMap)),
|
|
}
|
|
if !circularRef {
|
|
delete(files, "/home/src/workspaces/project/src/index.ts")
|
|
files["/home/src/workspaces/project/src/a.ts"] = stringtestutil.Dedent(`
|
|
export class B { prop = "hello"; }
|
|
|
|
export interface A {
|
|
b: B;
|
|
}
|
|
`)
|
|
}
|
|
return files
|
|
}
|
|
getBuildEmitDeclarationOnlyTestCase := func(declarationMap bool) *tscInput {
|
|
return &tscInput{
|
|
subScenario: `only dts output in circular import project with emitDeclarationOnly` + core.IfElse(declarationMap, " and declarationMap", ""),
|
|
files: getBuildEmitDeclarationOnlyImportFileMap(declarationMap, true),
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/src/a.ts", "b: B;", "b: B; foo: any;")
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
testCases := []*tscInput{
|
|
getBuildEmitDeclarationOnlyTestCase(false),
|
|
getBuildEmitDeclarationOnlyTestCase(true),
|
|
{
|
|
subScenario: `only dts output in non circular imports project with emitDeclarationOnly`,
|
|
files: getBuildEmitDeclarationOnlyImportFileMap(true, false),
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-doesnt-change",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(
|
|
"/home/src/workspaces/project/src/a.ts",
|
|
"export interface A {",
|
|
stringtestutil.Dedent(`
|
|
class C { }
|
|
export interface A {`),
|
|
)
|
|
},
|
|
},
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/src/a.ts", "b: B;", "b: B; foo: any;")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "emitDeclarationOnly")
|
|
}
|
|
}
|
|
|
|
func TestBuildFileDelete(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "detects deleted file",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/child/child.ts": stringtestutil.Dedent(`
|
|
import { child2 } from "../child/child2";
|
|
export function child() {
|
|
child2();
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/child/child2.ts": stringtestutil.Dedent(`
|
|
export function child2() {
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/child/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true }
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/main/main.ts": stringtestutil.Dedent(`
|
|
import { child } from "../child/child";
|
|
export function main() {
|
|
child();
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/main/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": [{ "path": "../child" }],
|
|
}
|
|
`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "main/tsconfig.json", "-v", "--traceResolution", "--explainFiles"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete child2 file",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/solution/child/child2.ts")
|
|
sys.removeNoError("/home/src/workspaces/solution/child/child2.js")
|
|
sys.removeNoError("/home/src/workspaces/solution/child/child2.d.ts")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "deleted file without composite",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/child/child.ts": stringtestutil.Dedent(`
|
|
import { child2 } from "../child/child2";
|
|
export function child() {
|
|
child2();
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/child/child2.ts": stringtestutil.Dedent(`
|
|
export function child2() {
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/child/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { }
|
|
}
|
|
`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "child/tsconfig.json", "-v", "--traceResolution", "--explainFiles"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete child2 file",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/solution/child/child2.ts")
|
|
sys.removeNoError("/home/src/workspaces/solution/child/child2.js")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "fileDelete")
|
|
}
|
|
}
|
|
|
|
func TestBuildInferredTypeFromTransitiveModule(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildInferredTypeFromTransitiveModuleMap := func(isolatedModules bool, lazyExtraContents string) FileMap {
|
|
return FileMap{
|
|
"/home/src/workspaces/project/bar.ts": stringtestutil.Dedent(`
|
|
interface RawAction {
|
|
(...args: any[]): Promise<any> | void;
|
|
}
|
|
interface ActionFactory {
|
|
<T extends RawAction>(target: T): T;
|
|
}
|
|
declare function foo<U extends any[] = any[]>(): ActionFactory;
|
|
export default foo()(function foobar(param: string): void {
|
|
});
|
|
`),
|
|
"/home/src/workspaces/project/bundling.ts": stringtestutil.Dedent(`
|
|
export class LazyModule<TModule> {
|
|
constructor(private importCallback: () => Promise<TModule>) {}
|
|
}
|
|
|
|
export class LazyAction<
|
|
TAction extends (...args: any[]) => any,
|
|
TModule
|
|
> {
|
|
constructor(_lazyModule: LazyModule<TModule>, _getter: (module: TModule) => TAction) {
|
|
}
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/global.d.ts": stringtestutil.Dedent(`
|
|
interface PromiseConstructor {
|
|
new <T>(): Promise<T>;
|
|
}
|
|
declare var Promise: PromiseConstructor;
|
|
interface Promise<T> {
|
|
}
|
|
`),
|
|
"/home/src/workspaces/project/index.ts": stringtestutil.Dedent(`
|
|
import { LazyAction, LazyModule } from './bundling';
|
|
const lazyModule = new LazyModule(() =>
|
|
import('./lazyIndex')
|
|
);
|
|
export const lazyBar = new LazyAction(lazyModule, m => m.bar);
|
|
`),
|
|
"/home/src/workspaces/project/lazyIndex.ts": stringtestutil.Dedent(`
|
|
export { default as bar } from './bar';
|
|
`) + lazyExtraContents,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"declaration": true,
|
|
"outDir": "obj",
|
|
"incremental": true,
|
|
"isolatedModules": %t,
|
|
},
|
|
}`, isolatedModules)),
|
|
}
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "inferred type from transitive module",
|
|
files: getBuildInferredTypeFromTransitiveModuleMap(false, ""),
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/bar.ts", "param: string", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/bar.ts", "foobar()", "foobar(param: string)")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "inferred type from transitive module with isolatedModules",
|
|
files: getBuildInferredTypeFromTransitiveModuleMap(true, ""),
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/bar.ts", "param: string", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/bar.ts", "foobar()", "foobar(param: string)")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "reports errors in files affected by change in signature with isolatedModules",
|
|
files: getBuildInferredTypeFromTransitiveModuleMap(true, stringtestutil.Dedent(`
|
|
import { default as bar } from './bar';
|
|
bar("hello");
|
|
`)),
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/bar.ts", "param: string", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/bar.ts", "foobar()", "foobar(param: string)")
|
|
},
|
|
},
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/bar.ts", "param: string", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "Fix Error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/lazyIndex.ts", `bar("hello")`, "bar()")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "inferredTypeFromTransitiveModule")
|
|
}
|
|
}
|
|
|
|
func TestBuildJavascriptProjectEmit(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
// !!! sheetal errors seem different
|
|
subScenario: "loads js-based projects and emits them correctly",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/common/nominal.js": stringtestutil.Dedent(`
|
|
/**
|
|
* @template T, Name
|
|
* @typedef {T & {[Symbol.species]: Name}} Nominal
|
|
*/
|
|
module.exports = {};
|
|
`),
|
|
"/home/src/workspaces/solution/common/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"include": ["nominal.js"],
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/sub-project/index.js": stringtestutil.Dedent(`
|
|
import { Nominal } from '../common/nominal';
|
|
|
|
/**
|
|
* @typedef {Nominal<string, 'MyNominal'>} MyNominal
|
|
*/
|
|
`),
|
|
"/home/src/workspaces/solution/sub-project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../common" },
|
|
],
|
|
"include": ["./index.js"],
|
|
}`),
|
|
"/home/src/workspaces/solution/sub-project-2/index.js": stringtestutil.Dedent(`
|
|
import { MyNominal } from '../sub-project/index';
|
|
|
|
const variable = {
|
|
key: /** @type {MyNominal} */('value'),
|
|
};
|
|
|
|
/**
|
|
* @return {keyof typeof variable}
|
|
*/
|
|
export function getVar() {
|
|
return 'key';
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/sub-project-2/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../sub-project" },
|
|
],
|
|
"include": ["./index.js"],
|
|
}`),
|
|
"/home/src/workspaces/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "./sub-project" },
|
|
{ "path": "./sub-project-2" },
|
|
],
|
|
"include": [],
|
|
}`),
|
|
"/home/src/workspaces/solution/tsconfig.base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"skipLibCheck": true,
|
|
"rootDir": "./",
|
|
"outDir": "../lib",
|
|
"allowJs": true,
|
|
"checkJs": true,
|
|
"declaration": true,
|
|
},
|
|
}`),
|
|
tscLibPath + "/lib.d.ts": strings.Replace(tscDefaultLibContent, "interface SymbolConstructor {", "interface SymbolConstructor {\n readonly species: symbol;", 1),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b"},
|
|
},
|
|
{
|
|
subScenario: `loads js-based projects with non-moved json files and emits them correctly`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/common/obj.json": stringtestutil.Dedent(`
|
|
{
|
|
"val": 42,
|
|
}`),
|
|
"/home/src/workspaces/solution/common/index.ts": stringtestutil.Dedent(`
|
|
import x = require("./obj.json");
|
|
export = x;
|
|
`),
|
|
"/home/src/workspaces/solution/common/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"outDir": null,
|
|
"composite": true,
|
|
},
|
|
"include": ["index.ts", "obj.json"],
|
|
}`),
|
|
"/home/src/workspaces/solution/sub-project/index.js": stringtestutil.Dedent(`
|
|
import mod from '../common';
|
|
|
|
export const m = mod;
|
|
`),
|
|
"/home/src/workspaces/solution/sub-project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../common" },
|
|
],
|
|
"include": ["./index.js"],
|
|
}`),
|
|
"/home/src/workspaces/solution/sub-project-2/index.js": stringtestutil.Dedent(`
|
|
import { m } from '../sub-project/index';
|
|
|
|
const variable = {
|
|
key: m,
|
|
};
|
|
|
|
export function getVar() {
|
|
return variable;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/sub-project-2/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../sub-project" },
|
|
],
|
|
"include": ["./index.js"],
|
|
}`),
|
|
"/home/src/workspaces/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "./sub-project" },
|
|
{ "path": "./sub-project-2" },
|
|
],
|
|
"include": [],
|
|
}`),
|
|
"/home/src/workspaces/solution/tsconfig.base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"skipLibCheck": true,
|
|
"rootDir": "./",
|
|
"outDir": "../out",
|
|
"allowJs": true,
|
|
"checkJs": true,
|
|
"resolveJsonModule": true,
|
|
"esModuleInterop": true,
|
|
"declaration": true,
|
|
},
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"-b"},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "javascriptProjectEmit")
|
|
}
|
|
}
|
|
|
|
func TestBuildLateBoundSymbol(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "interface is merged and contains late bound member",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/globals.d.ts": stringtestutil.Dedent(`
|
|
interface SymbolConstructor {
|
|
(description?: string | number): symbol;
|
|
}
|
|
declare var Symbol: SymbolConstructor;
|
|
`),
|
|
"/home/src/workspaces/project/src/hkt.ts": `export interface HKT<T> { }`,
|
|
"/home/src/workspaces/project/src/main.ts": stringtestutil.Dedent(`
|
|
import { HKT } from "./hkt";
|
|
|
|
const sym = Symbol();
|
|
|
|
declare module "./hkt" {
|
|
interface HKT<T> {
|
|
[sym]: { a: T }
|
|
}
|
|
}
|
|
const x = 10;
|
|
type A = HKT<number>[typeof sym];
|
|
`),
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"rootDir": "src",
|
|
"incremental": true,
|
|
},
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-doesnt-change",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/project/src/main.ts", "const x = 10;", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "incremental-declaration-doesnt-change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/src/main.ts", "const x = 10;")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "lateBoundSymbol")
|
|
}
|
|
}
|
|
|
|
func TestBuildModuleSpecifiers(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: `synthesized module specifiers resolve correctly`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/packages/solution/common/nominal.ts": stringtestutil.Dedent(`
|
|
export declare type Nominal<T, Name extends string> = T & {
|
|
[Symbol.species]: Name;
|
|
};
|
|
`),
|
|
"/home/src/workspaces/packages/solution/common/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"include": ["nominal.ts"]
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/solution/sub-project/index.ts": stringtestutil.Dedent(`
|
|
import { Nominal } from '../common/nominal';
|
|
|
|
export type MyNominal = Nominal<string, 'MyNominal'>;
|
|
`),
|
|
"/home/src/workspaces/packages/solution/sub-project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "../common" }
|
|
],
|
|
"include": ["./index.ts"]
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/solution/sub-project-2/index.ts": stringtestutil.Dedent(`
|
|
import { MyNominal } from '../sub-project/index';
|
|
|
|
const variable = {
|
|
key: 'value' as MyNominal,
|
|
};
|
|
|
|
export function getVar(): keyof typeof variable {
|
|
return 'key';
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/solution/sub-project-2/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "../sub-project" }
|
|
],
|
|
"include": ["./index.ts"]
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "./sub-project" },
|
|
{ "path": "./sub-project-2" }
|
|
],
|
|
"include": []
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/tsconfig.base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"skipLibCheck": true,
|
|
"rootDir": "./",
|
|
"outDir": "lib"
|
|
}
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "./solution" },
|
|
],
|
|
"include": [],
|
|
}
|
|
`),
|
|
tscLibPath + "/lib.d.ts": strings.Replace(tscDefaultLibContent, "interface SymbolConstructor {", "interface SymbolConstructor {\n readonly species: symbol;", 1),
|
|
},
|
|
cwd: "/home/src/workspaces/packages",
|
|
commandLineArgs: []string{"-b", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: `synthesized module specifiers across projects resolve correctly`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/packages/src-types/index.ts": stringtestutil.Dedent(`
|
|
export * from './dogconfig.js';`),
|
|
"/home/src/workspaces/packages/src-types/dogconfig.ts": stringtestutil.Dedent(`
|
|
export interface DogConfig {
|
|
name: string;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/src-dogs/index.ts": stringtestutil.Dedent(`
|
|
export * from 'src-types';
|
|
export * from './lassie/lassiedog.js';
|
|
`),
|
|
"/home/src/workspaces/packages/src-dogs/dogconfig.ts": stringtestutil.Dedent(`
|
|
import { DogConfig } from 'src-types';
|
|
|
|
export const DOG_CONFIG: DogConfig = {
|
|
name: 'Default dog',
|
|
};
|
|
`),
|
|
"/home/src/workspaces/packages/src-dogs/dog.ts": stringtestutil.Dedent(`
|
|
import { DogConfig } from 'src-types';
|
|
import { DOG_CONFIG } from './dogconfig.js';
|
|
|
|
export abstract class Dog {
|
|
|
|
public static getCapabilities(): DogConfig {
|
|
return DOG_CONFIG;
|
|
}
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/src-dogs/lassie/lassiedog.ts": stringtestutil.Dedent(`
|
|
import { Dog } from '../dog.js';
|
|
import { LASSIE_CONFIG } from './lassieconfig.js';
|
|
|
|
export class LassieDog extends Dog {
|
|
protected static getDogConfig = () => LASSIE_CONFIG;
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/src-dogs/lassie/lassieconfig.ts": stringtestutil.Dedent(`
|
|
import { DogConfig } from 'src-types';
|
|
|
|
export const LASSIE_CONFIG: DogConfig = { name: 'Lassie' };
|
|
`),
|
|
"/home/src/workspaces/packages/tsconfig-base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"declaration": true,
|
|
"module": "node16",
|
|
},
|
|
}
|
|
`),
|
|
"/home/src/workspaces/packages/src-types/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"type": "module",
|
|
"exports": "./index.js"
|
|
}`),
|
|
"/home/src/workspaces/packages/src-dogs/package.json": stringtestutil.Dedent(`
|
|
{
|
|
"type": "module",
|
|
"exports": "./index.js"
|
|
}`),
|
|
"/home/src/workspaces/packages/src-types/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"include": [
|
|
"**/*",
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/packages/src-dogs/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig-base.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../src-types" },
|
|
],
|
|
"include": [
|
|
"**/*",
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/packages/src-types/node_modules": vfstest.Symlink("/home/src/workspaces/packages"),
|
|
"/home/src/workspaces/packages/src-dogs/node_modules": vfstest.Symlink("/home/src/workspaces/packages"),
|
|
},
|
|
cwd: "/home/src/workspaces/packages",
|
|
commandLineArgs: []string{"-b", "src-types", "src-dogs", "--verbose"},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "moduleSpecifiers")
|
|
}
|
|
}
|
|
|
|
func TestBuildOutputPaths(t *testing.T) {
|
|
t.Parallel()
|
|
type tscOutputPathScenario struct {
|
|
subScenario string
|
|
files FileMap
|
|
expectedDtsNames []string
|
|
}
|
|
runOutputPaths := func(s *tscOutputPathScenario) {
|
|
t.Helper()
|
|
input := &tscInput{
|
|
subScenario: s.subScenario,
|
|
files: s.files,
|
|
commandLineArgs: []string{"-b", "-v"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "Normal build without change, that does not block emit on error to show files that get emitted",
|
|
commandLineArgs: []string{"-p", "/home/src/workspaces/project/tsconfig.json"},
|
|
},
|
|
},
|
|
}
|
|
input.run(t, "outputPaths")
|
|
t.Run("GetOutputFileNames/"+s.subScenario, func(t *testing.T) {
|
|
t.Parallel()
|
|
sys := newTestSys(input, false)
|
|
config, _ := tsoptions.GetParsedCommandLineOfConfigFile("/home/src/workspaces/project/tsconfig.json", &core.CompilerOptions{}, sys, nil)
|
|
assert.DeepEqual(t, slices.Collect(config.GetOutputFileNames()), s.expectedDtsNames)
|
|
})
|
|
}
|
|
testCases := []*tscOutputPathScenario{
|
|
{
|
|
subScenario: "when rootDir is not specified",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "dist",
|
|
},
|
|
}`),
|
|
},
|
|
expectedDtsNames: []string{
|
|
"/home/src/workspaces/project/dist/index.js",
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when rootDir is not specified and is composite",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "dist",
|
|
"composite": true,
|
|
},
|
|
}`),
|
|
},
|
|
expectedDtsNames: []string{
|
|
"/home/src/workspaces/project/dist/src/index.js",
|
|
"/home/src/workspaces/project/dist/src/index.d.ts",
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when rootDir is specified",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "dist",
|
|
"rootDir": "src",
|
|
},
|
|
}`),
|
|
},
|
|
expectedDtsNames: []string{
|
|
"/home/src/workspaces/project/dist/index.js",
|
|
},
|
|
},
|
|
{
|
|
// !!! sheetal error missing as not yet implemented
|
|
subScenario: "when rootDir is specified but not all files belong to rootDir",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/types/type.ts": "export type t = string;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "dist",
|
|
"rootDir": "src",
|
|
},
|
|
}`),
|
|
},
|
|
expectedDtsNames: []string{
|
|
"/home/src/workspaces/project/dist/index.js",
|
|
"/home/src/workspaces/project/types/type.js",
|
|
},
|
|
},
|
|
{
|
|
// !!! sheetal error missing as not yet implemented
|
|
subScenario: "when rootDir is specified but not all files belong to rootDir and is composite",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/src/index.ts": "export const x = 10;",
|
|
"/home/src/workspaces/project/types/type.ts": "export type t = string;",
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "dist",
|
|
"rootDir": "src",
|
|
"composite": true
|
|
},
|
|
}`),
|
|
},
|
|
expectedDtsNames: []string{
|
|
"/home/src/workspaces/project/dist/index.js",
|
|
"/home/src/workspaces/project/dist/index.d.ts",
|
|
"/home/src/workspaces/project/types/type.js",
|
|
"/home/src/workspaces/project/types/type.d.ts",
|
|
},
|
|
},
|
|
}
|
|
for _, test := range testCases {
|
|
runOutputPaths(test)
|
|
}
|
|
}
|
|
|
|
func TestBuildProgramUpdates(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "when referenced project change introduces error in the down stream project and then fixes it",
|
|
files: FileMap{
|
|
"/user/username/projects/sample1/Library/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
"/user/username/projects/sample1/Library/library.ts": stringtestutil.Dedent(`
|
|
interface SomeObject
|
|
{
|
|
message: string;
|
|
}
|
|
|
|
export function createSomeObject(): SomeObject
|
|
{
|
|
return {
|
|
message: "new Object"
|
|
};
|
|
}
|
|
`),
|
|
"/user/username/projects/sample1/App/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [{ "path": "../Library" }]
|
|
}`),
|
|
"/user/username/projects/sample1/App/app.ts": stringtestutil.Dedent(`
|
|
import { createSomeObject } from "../Library/library";
|
|
createSomeObject().message;
|
|
`),
|
|
},
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"-b", "-w", "App"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Introduce error",
|
|
// Change message in library to message2
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileTextAll("/user/username/projects/sample1/Library/library.ts", "message", "message2")
|
|
},
|
|
},
|
|
{
|
|
caption: "Fix error",
|
|
// Revert library changes
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileTextAll("/user/username/projects/sample1/Library/library.ts", "message2", "message")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "declarationEmitErrors when fixing error files all files are emitted",
|
|
files: FileMap{
|
|
"/user/username/projects/solution/app/fileWithError.ts": stringtestutil.Dedent(`
|
|
export var myClassWithError = class {
|
|
tags() { }
|
|
private p = 12
|
|
};
|
|
`),
|
|
"/user/username/projects/solution/app/fileWithoutError.ts": "export class myClass { }",
|
|
"/user/username/projects/solution/app/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/solution",
|
|
commandLineArgs: []string{"-b", "-w", "app"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/solution/app/fileWithError.ts", "private p = 12", "")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "declarationEmitErrors when file with no error changes",
|
|
files: FileMap{
|
|
"/user/username/projects/solution/app/fileWithError.ts": stringtestutil.Dedent(`
|
|
export var myClassWithError = class {
|
|
tags() { }
|
|
private p = 12
|
|
};
|
|
`),
|
|
"/user/username/projects/solution/app/fileWithoutError.ts": "export class myClass { }",
|
|
"/user/username/projects/solution/app/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/solution",
|
|
commandLineArgs: []string{"-b", "-w", "app"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Change fileWithoutError",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileTextAll("/user/username/projects/solution/app/fileWithoutError.ts", "myClass", "myClass2")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "declarationEmitErrors introduceError when fixing errors only changed file is emitted",
|
|
files: FileMap{
|
|
"/user/username/projects/solution/app/fileWithError.ts": stringtestutil.Dedent(`
|
|
export var myClassWithError = class {
|
|
tags() { }
|
|
|
|
};
|
|
`),
|
|
"/user/username/projects/solution/app/fileWithoutError.ts": "export class myClass { }",
|
|
"/user/username/projects/solution/app/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/solution",
|
|
commandLineArgs: []string{"-b", "-w", "app"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Introduce error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/solution/app/fileWithError.ts", stringtestutil.Dedent(`
|
|
export var myClassWithError = class {
|
|
tags() { }
|
|
private p = 12
|
|
};
|
|
`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/solution/app/fileWithError.ts", "private p = 12", "")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "declarationEmitErrors introduceError when file with no error changes",
|
|
files: FileMap{
|
|
"/user/username/projects/solution/app/fileWithError.ts": stringtestutil.Dedent(`
|
|
export var myClassWithError = class {
|
|
tags() { }
|
|
|
|
};
|
|
`),
|
|
"/user/username/projects/solution/app/fileWithoutError.ts": "export class myClass { }",
|
|
"/user/username/projects/solution/app/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/solution",
|
|
commandLineArgs: []string{"-b", "-w", "app"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Introduce error",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/solution/app/fileWithError.ts", stringtestutil.Dedent(`
|
|
export var myClassWithError = class {
|
|
tags() { }
|
|
private p = 12
|
|
};
|
|
`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Change fileWithoutError",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileTextAll("/user/username/projects/solution/app/fileWithoutError.ts", "myClass", "myClass2")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "works when noUnusedParameters changes to false",
|
|
files: FileMap{
|
|
"/user/username/projects/myproject/index.ts": `const fn = (a: string, b: string) => b;`,
|
|
"/user/username/projects/myproject/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"noUnusedParameters": true,
|
|
},
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-b", "-w"},
|
|
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Change tsconfig to set noUnusedParameters to false",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError(
|
|
`/user/username/projects/myproject/tsconfig.json`,
|
|
stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"noUnusedParameters": false,
|
|
},
|
|
}`),
|
|
false,
|
|
)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "works with extended source files",
|
|
cwd: "/user/username/projects/project",
|
|
files: FileMap{
|
|
"/user/username/projects/project/commonFile1.ts": "let x = 1",
|
|
"/user/username/projects/project/commonFile2.ts": "let y = 1",
|
|
"/user/username/projects/project/alpha.tsconfig.json": "{}",
|
|
"/user/username/projects/project/project1.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./alpha.tsconfig.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"files": ["commonFile1.ts", "commonFile2.ts"],
|
|
}
|
|
`),
|
|
"/user/username/projects/project/bravo.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./alpha.tsconfig.json",
|
|
}
|
|
`),
|
|
"/user/username/projects/project/other.ts": "let z = 0;",
|
|
"/user/username/projects/project/project2.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./bravo.tsconfig.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"files": ["other.ts"],
|
|
}
|
|
`),
|
|
"/user/username/projects/project/other2.ts": "let k = 0;",
|
|
"/user/username/projects/project/extendsConfig1.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
}
|
|
`),
|
|
"/user/username/projects/project/extendsConfig2.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strictNullChecks": false,
|
|
},
|
|
}
|
|
`),
|
|
"/user/username/projects/project/extendsConfig3.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"noImplicitAny": true,
|
|
},
|
|
}
|
|
`),
|
|
"/user/username/projects/project/project3.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": [
|
|
"./extendsConfig1.tsconfig.json",
|
|
"./extendsConfig2.tsconfig.json",
|
|
"./extendsConfig3.tsconfig.json",
|
|
],
|
|
"compilerOptions": {
|
|
"composite": false,
|
|
},
|
|
"files": ["other2.ts"],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"-b", "-w", "-v", "project1.tsconfig.json", "project2.tsconfig.json", "project3.tsconfig.json"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Modify alpha config",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/project/alpha.tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true
|
|
}
|
|
}`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "change bravo config",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/project/bravo.tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./alpha.tsconfig.json",
|
|
"compilerOptions": { "strict": false }
|
|
}`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "project 2 extends alpha",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/project/project2.tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./alpha.tsconfig.json",
|
|
}`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "update aplha config",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/project/alpha.tsconfig.json", "{}", false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Modify extendsConfigFile2",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/project/extendsConfig2.tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "strictNullChecks": true }
|
|
}`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Modify project 3",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/project/project3.tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"extends": ["./extendsConfig1.tsconfig.json", "./extendsConfig2.tsconfig.json"],
|
|
"compilerOptions": { "composite": false },
|
|
"files": ["other2.ts"],
|
|
}`), false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Delete extendedConfigFile2 and report error",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/user/username/projects/project/extendsConfig2.tsconfig.json")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "works correctly when project with extended config is removed",
|
|
files: FileMap{
|
|
"/user/username/projects/project/commonFile1.ts": "let x = 1",
|
|
"/user/username/projects/project/commonFile2.ts": "let y = 1",
|
|
"/user/username/projects/project/alpha.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
},
|
|
}`),
|
|
"/user/username/projects/project/project1.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./alpha.tsconfig.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"files": ["commonFile1.ts", "commonFile2.ts"],
|
|
}`),
|
|
"/user/username/projects/project/bravo.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"strict": true,
|
|
},
|
|
}`),
|
|
"/user/username/projects/project/other.ts": "let z = 0;",
|
|
"/user/username/projects/project/project2.tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "./bravo.tsconfig.json",
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"files": ["other.ts"],
|
|
}`),
|
|
"/user/username/projects/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{
|
|
"path": "./project1.tsconfig.json",
|
|
},
|
|
{
|
|
"path": "./project2.tsconfig.json",
|
|
},
|
|
],
|
|
"files": [],
|
|
}`),
|
|
},
|
|
cwd: "/user/username/projects/project",
|
|
commandLineArgs: []string{"-b", "-w", "-v"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Remove project2 from base config",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/project/tsconfig.json", stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{
|
|
"path": "./project1.tsconfig.json",
|
|
},
|
|
],
|
|
"files": [],
|
|
}`), false)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "tsbuildinfo has error",
|
|
files: FileMap{
|
|
"/user/username/projects/project/main.ts": "export const x = 10;",
|
|
"/user/username/projects/project/tsconfig.json": "{}",
|
|
"/user/username/projects/project/tsconfig.tsbuildinfo": "Some random string",
|
|
},
|
|
cwd: "/user/username/projects/project",
|
|
commandLineArgs: []string{"--b", "-i", "-w"},
|
|
},
|
|
{
|
|
subScenario: "when root is source from project reference",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/lib/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "./dist"
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/lib/foo.ts": `export const FOO: string = 'THEFOOEXPORT';`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [ { "path": "./lib" } ]
|
|
}`),
|
|
"/home/src/workspaces/project/index.ts": `import { FOO } from "./lib/foo";`,
|
|
},
|
|
commandLineArgs: []string{"--b"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "dts doesnt change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/lib/foo.ts", "const Bar = 10;")
|
|
},
|
|
},
|
|
},
|
|
cwd: "/home/src/workspaces/project",
|
|
},
|
|
{
|
|
subScenario: "when root is source from project reference with composite",
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/lib/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "./dist"
|
|
}
|
|
}`),
|
|
"/home/src/workspaces/project/lib/foo.ts": `export const FOO: string = 'THEFOOEXPORT';`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [ { "path": "./lib" } ]
|
|
}`),
|
|
"/home/src/workspaces/project/index.ts": `import { FOO } from "./lib/foo";`,
|
|
},
|
|
commandLineArgs: []string{"--b"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "dts doesnt change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/project/lib/foo.ts", "const Bar = 10;")
|
|
},
|
|
},
|
|
},
|
|
cwd: "/home/src/workspaces/project",
|
|
},
|
|
}
|
|
for _, test := range testCases {
|
|
test.run(t, "programUpdates")
|
|
}
|
|
}
|
|
|
|
func TestBuildProjectsBuilding(t *testing.T) {
|
|
t.Parallel()
|
|
addPackageFiles := func(files FileMap, index int) {
|
|
files[fmt.Sprintf(`/user/username/projects/myproject/pkg%d/index.ts`, index)] = fmt.Sprintf(`export const pkg%d = %d;`, index, index)
|
|
var references string
|
|
if index > 0 {
|
|
references = `"references": [{ "path": "../pkg0" }],`
|
|
}
|
|
files[fmt.Sprintf(`/user/username/projects/myproject/pkg%d/tsconfig.json`, index)] = stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
%s
|
|
}`, references))
|
|
}
|
|
addSolution := func(files FileMap, count int) {
|
|
var pkgReferences []string
|
|
for i := range count {
|
|
pkgReferences = append(pkgReferences, fmt.Sprintf(`{ "path": "./pkg%d" }`, i))
|
|
}
|
|
files[`/user/username/projects/myproject/tsconfig.json`] = stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": [
|
|
%s
|
|
]
|
|
}`, strings.Join(pkgReferences, ",\n\t\t\t\t")))
|
|
}
|
|
files := func(count int) FileMap {
|
|
files := FileMap{}
|
|
for i := range count {
|
|
addPackageFiles(files, i)
|
|
}
|
|
addSolution(files, count)
|
|
return files
|
|
}
|
|
|
|
getTestCases := func(pkgCount int) []*tscInput {
|
|
edits := []*tscEdit{
|
|
{
|
|
caption: "dts doesn't change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`)
|
|
},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "dts change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`)
|
|
},
|
|
},
|
|
noChange,
|
|
}
|
|
return []*tscInput{
|
|
{
|
|
subScenario: fmt.Sprintf(`when there are %d projects in a solution`, pkgCount),
|
|
files: files(pkgCount),
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-b", "-v"},
|
|
edits: edits,
|
|
},
|
|
{
|
|
subScenario: fmt.Sprintf(`when there are %d projects in a solution`, pkgCount),
|
|
files: files(pkgCount),
|
|
cwd: "/user/username/projects/myproject",
|
|
commandLineArgs: []string{"-b", "-w", "-v"},
|
|
edits: edits,
|
|
},
|
|
}
|
|
}
|
|
|
|
testCases := slices.Concat(
|
|
getTestCases(3),
|
|
getTestCases(5),
|
|
getTestCases(8),
|
|
getTestCases(23),
|
|
)
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "projectsBuilding")
|
|
}
|
|
}
|
|
|
|
func TestBuildProjectReferenceWithRootDirInParent(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildProjectReferenceWithRootDirInParentFileMap := func(modify func(files FileMap)) FileMap {
|
|
files := FileMap{
|
|
"/home/src/workspaces/solution/src/main/a.ts": stringtestutil.Dedent(`
|
|
import { b } from './b';
|
|
const a = b;
|
|
`),
|
|
"/home/src/workspaces/solution/src/main/b.ts": stringtestutil.Dedent(`
|
|
export const b = 0;
|
|
`),
|
|
"/home/src/workspaces/solution/src/main/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"references": [
|
|
{ "path": "../other" },
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/solution/src/other/other.ts": stringtestutil.Dedent(`
|
|
export const Other = 0;
|
|
`),
|
|
"/home/src/workspaces/solution/src/other/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/tsconfig.base.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"rootDir": "./src/",
|
|
"outDir": "./dist/",
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
"exclude": [
|
|
"node_modules",
|
|
],
|
|
}`),
|
|
}
|
|
if modify != nil {
|
|
modify(files)
|
|
}
|
|
return files
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "builds correctly",
|
|
files: getBuildProjectReferenceWithRootDirInParentFileMap(nil),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "src/main", "/home/src/workspaces/solution/src/other"},
|
|
},
|
|
{
|
|
subScenario: "reports error for same tsbuildinfo file because no rootDir in the base",
|
|
files: getBuildProjectReferenceWithRootDirInParentFileMap(
|
|
func(files FileMap) {
|
|
text, _ := files["/home/src/workspaces/solution/tsconfig.base.json"]
|
|
files["/home/src/workspaces/solution/tsconfig.base.json"] = strings.Replace(text.(string), `"rootDir": "./src/",`, "", 1)
|
|
},
|
|
),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "src/main", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "reports error for same tsbuildinfo file",
|
|
files: getBuildProjectReferenceWithRootDirInParentFileMap(
|
|
func(files FileMap) {
|
|
files["/home/src/workspaces/solution/src/main/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true, "outDir": "../../dist/" },
|
|
"references": [{ "path": "../other" }]
|
|
}`)
|
|
files["/home/src/workspaces/solution/src/other/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true, "outDir": "../../dist/" },
|
|
}`)
|
|
},
|
|
),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "src/main", "--verbose"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "reports error for same tsbuildinfo file without incremental",
|
|
files: getBuildProjectReferenceWithRootDirInParentFileMap(
|
|
func(files FileMap) {
|
|
files["/home/src/workspaces/solution/src/main/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "outDir": "../../dist/" },
|
|
"references": [{ "path": "../other" }]
|
|
}`)
|
|
files["/home/src/workspaces/solution/src/other/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true, "outDir": "../../dist/" },
|
|
}`)
|
|
},
|
|
),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "src/main", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "reports error for same tsbuildinfo file without incremental with tsc",
|
|
files: getBuildProjectReferenceWithRootDirInParentFileMap(
|
|
func(files FileMap) {
|
|
files["/home/src/workspaces/solution/src/main/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "outDir": "../../dist/" },
|
|
"references": [{ "path": "../other" }]
|
|
}`)
|
|
files["/home/src/workspaces/solution/src/other/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true, "outDir": "../../dist/" },
|
|
}`)
|
|
},
|
|
),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "src/other", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Running tsc on main",
|
|
commandLineArgs: []string{"-p", "src/main"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "reports no error when tsbuildinfo differ",
|
|
files: getBuildProjectReferenceWithRootDirInParentFileMap(
|
|
func(files FileMap) {
|
|
delete(files, "/home/src/workspaces/solution/src/main/tsconfig.json")
|
|
delete(files, "/home/src/workspaces/solution/src/other/tsconfig.json")
|
|
files["/home/src/workspaces/solution/src/main/tsconfig.main.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true, "outDir": "../../dist/" },
|
|
"references": [{ "path": "../other/tsconfig.other.json" }]
|
|
}`)
|
|
files["/home/src/workspaces/solution/src/other/tsconfig.other.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true, "outDir": "../../dist/" },
|
|
}`)
|
|
},
|
|
),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "src/main/tsconfig.main.json", "--verbose"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "projectReferenceWithRootDirInParent")
|
|
}
|
|
}
|
|
|
|
func TestBuildReexport(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "Reports errors correctly",
|
|
files: FileMap{
|
|
"/user/username/projects/reexport/src/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": [],
|
|
"include": [],
|
|
"references": [{ "path": "./pure" }, { "path": "./main" }],
|
|
}`),
|
|
"/user/username/projects/reexport/src/main/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"outDir": "../../out",
|
|
"rootDir": "../",
|
|
},
|
|
"include": ["**/*.ts"],
|
|
"references": [{ "path": "../pure" }],
|
|
}`),
|
|
"/user/username/projects/reexport/src/main/index.ts": stringtestutil.Dedent(`
|
|
import { Session } from "../pure";
|
|
|
|
export const session: Session = {
|
|
foo: 1
|
|
};
|
|
`),
|
|
"/user/username/projects/reexport/src/pure/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "../../out",
|
|
"rootDir": "../",
|
|
},
|
|
"include": ["**/*.ts"],
|
|
}`),
|
|
"/user/username/projects/reexport/src/pure/index.ts": `export * from "./session";`,
|
|
"/user/username/projects/reexport/src/pure/session.ts": stringtestutil.Dedent(`
|
|
export interface Session {
|
|
foo: number;
|
|
// bar: number;
|
|
}
|
|
`),
|
|
},
|
|
cwd: `/user/username/projects/reexport`,
|
|
commandLineArgs: []string{"-b", "-w", "-verbose", "src"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Introduce error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/reexport/src/pure/session.ts`, "// ", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "Fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(`/user/username/projects/reexport/src/pure/session.ts`, "bar: ", "// bar: ")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "reexport")
|
|
}
|
|
}
|
|
|
|
func TestBuildResolveJsonModule(t *testing.T) {
|
|
t.Parallel()
|
|
type buildResolveJsonModuleScenario struct {
|
|
subScenario string
|
|
tsconfigFiles string
|
|
additionalCompilerOptions string
|
|
skipOutdir bool
|
|
modifyFiles func(files FileMap)
|
|
edits []*tscEdit
|
|
}
|
|
getBuildResolveJsonModuleFileMap := func(composite bool, s *buildResolveJsonModuleScenario) FileMap {
|
|
var outDirStr string
|
|
if !s.skipOutdir {
|
|
outDirStr = `"outDir": "dist",`
|
|
}
|
|
files := FileMap{
|
|
"/home/src/workspaces/solution/project/src/hello.json": stringtestutil.Dedent(`
|
|
{
|
|
"hello": "world"
|
|
}`),
|
|
"/home/src/workspaces/solution/project/src/index.ts": stringtestutil.Dedent(`
|
|
import hello from "./hello.json"
|
|
export default hello.hello
|
|
`),
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": %t,
|
|
"moduleResolution": "node",
|
|
"module": "commonjs",
|
|
"resolveJsonModule": true,
|
|
"esModuleInterop": true,
|
|
"allowSyntheticDefaultImports": true,
|
|
%s
|
|
"skipDefaultLibCheck": true,
|
|
%s
|
|
},
|
|
%s
|
|
}`, composite, outDirStr, s.additionalCompilerOptions, s.tsconfigFiles)),
|
|
}
|
|
if s.modifyFiles != nil {
|
|
s.modifyFiles(files)
|
|
}
|
|
return files
|
|
}
|
|
getBuildResolveJsonModuleTestCases := func(scenarios []*buildResolveJsonModuleScenario) []*tscInput {
|
|
testCases := make([]*tscInput, 0, len(scenarios)*2)
|
|
for _, s := range scenarios {
|
|
testCases = append(
|
|
testCases,
|
|
&tscInput{
|
|
subScenario: s.subScenario,
|
|
files: getBuildResolveJsonModuleFileMap(true, s),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "project", "--v", "--explainFiles", "--listEmittedFiles"},
|
|
edits: s.edits,
|
|
},
|
|
&tscInput{
|
|
subScenario: s.subScenario + " non-composite",
|
|
files: getBuildResolveJsonModuleFileMap(false, s),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "project", "--v", "--explainFiles", "--listEmittedFiles"},
|
|
edits: s.edits,
|
|
},
|
|
)
|
|
}
|
|
return testCases
|
|
}
|
|
scenarios := []*buildResolveJsonModuleScenario{
|
|
{
|
|
subScenario: "include only",
|
|
tsconfigFiles: `"include": [ "src/**/*" ],`,
|
|
},
|
|
{
|
|
subScenario: "include only without outDir",
|
|
tsconfigFiles: `"include": [ "src/**/*" ],`,
|
|
skipOutdir: true,
|
|
},
|
|
{
|
|
subScenario: "include only with json not in rootDir",
|
|
tsconfigFiles: `"include": [ "src/**/*" ],`,
|
|
additionalCompilerOptions: `"rootDir": "src",`,
|
|
modifyFiles: func(files FileMap) {
|
|
text, _ := files["/home/src/workspaces/solution/project/src/hello.json"]
|
|
delete(files, "/home/src/workspaces/solution/project/src/hello.json")
|
|
files["/home/src/workspaces/solution/project/hello.json"] = text
|
|
text, _ = files["/home/src/workspaces/solution/project/src/index.ts"]
|
|
files["/home/src/workspaces/solution/project/src/index.ts"] = strings.Replace(text.(string), "./hello.json", "../hello.json", 1)
|
|
},
|
|
},
|
|
{
|
|
subScenario: "include only with json without rootDir but outside configDirectory",
|
|
tsconfigFiles: `"include": [ "src/**/*" ],`,
|
|
modifyFiles: func(files FileMap) {
|
|
text, _ := files["/home/src/workspaces/solution/project/src/hello.json"]
|
|
delete(files, "/home/src/workspaces/solution/project/src/hello.json")
|
|
files["/home/src/workspaces/solution/hello.json"] = text
|
|
text, _ = files["/home/src/workspaces/solution/project/src/index.ts"]
|
|
files["/home/src/workspaces/solution/project/src/index.ts"] = strings.Replace(text.(string), "./hello.json", "../../hello.json", 1)
|
|
},
|
|
},
|
|
{
|
|
subScenario: "include of json along with other include",
|
|
tsconfigFiles: `"include": [ "src/**/*", "src/**/*.json" ],`,
|
|
},
|
|
{
|
|
subScenario: "include of json along with other include and file name matches ts file",
|
|
tsconfigFiles: `"include": [ "src/**/*", "src/**/*.json" ],`,
|
|
modifyFiles: func(files FileMap) {
|
|
text, _ := files["/home/src/workspaces/solution/project/src/hello.json"]
|
|
delete(files, "/home/src/workspaces/solution/project/src/hello.json")
|
|
files["/home/src/workspaces/solution/project/src/index.json"] = text
|
|
text, _ = files["/home/src/workspaces/solution/project/src/index.ts"]
|
|
files["/home/src/workspaces/solution/project/src/index.ts"] = strings.Replace(text.(string), "./hello.json", "./index.json", 1)
|
|
},
|
|
},
|
|
{
|
|
subScenario: "files containing json file",
|
|
tsconfigFiles: `"files": [ "src/index.ts", "src/hello.json", ],`,
|
|
},
|
|
{
|
|
subScenario: "include and files",
|
|
tsconfigFiles: `"files": [ "src/hello.json" ], "include": [ "src/**/*" ],`,
|
|
},
|
|
{
|
|
subScenario: "sourcemap",
|
|
tsconfigFiles: `"files": [ "src/index.ts", "src/hello.json", ],`,
|
|
additionalCompilerOptions: `"sourceMap": true,`,
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "without outDir",
|
|
tsconfigFiles: `"files": [ "src/index.ts", "src/hello.json", ],`,
|
|
skipOutdir: true,
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
}
|
|
testCases := slices.Concat(
|
|
getBuildResolveJsonModuleTestCases(scenarios),
|
|
[]*tscInput{
|
|
{
|
|
subScenario: "importing json module from project reference",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/project/strings/foo.json": stringtestutil.Dedent(`
|
|
{
|
|
"foo": "bar baz"
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/project/strings/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.json",
|
|
"include": ["foo.json"],
|
|
"references": [],
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/project/main/index.ts": stringtestutil.Dedent(`
|
|
import { foo } from '../strings/foo.json';
|
|
console.log(foo);
|
|
`),
|
|
"/home/src/workspaces/solution/project/main/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../tsconfig.json",
|
|
"include": [
|
|
"./**/*.ts",
|
|
],
|
|
"references": [{
|
|
"path": "../strings/tsconfig.json",
|
|
}],
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5",
|
|
"module": "commonjs",
|
|
"rootDir": "./",
|
|
"composite": true,
|
|
"resolveJsonModule": true,
|
|
"strict": true,
|
|
"esModuleInterop": true,
|
|
},
|
|
"references": [
|
|
{ "path": "./strings/tsconfig.json" },
|
|
{ "path": "./main/tsconfig.json" },
|
|
],
|
|
"files": [],
|
|
}
|
|
`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "project", "--verbose", "--explainFiles"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
},
|
|
)
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "resolveJsonModule")
|
|
}
|
|
}
|
|
|
|
func TestBuildRoots(t *testing.T) {
|
|
t.Parallel()
|
|
getBuildRootsFromProjectReferencedProjectFileMap := func(serverFirst bool) FileMap {
|
|
include := core.IfElse(serverFirst, `"src/**/*.ts", "../shared/src/**/*.ts"`, `"../shared/src/**/*.ts", "src/**/*.ts"`)
|
|
return FileMap{
|
|
"/home/src/workspaces/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
"references": [
|
|
{ "path": "projects/server" },
|
|
{ "path": "projects/shared" },
|
|
],
|
|
}`),
|
|
"/home/src/workspaces/solution/projects/shared/src/myClass.ts": `export class MyClass { }`,
|
|
"/home/src/workspaces/solution/projects/shared/src/logging.ts": stringtestutil.Dedent(`
|
|
export function log(str: string) {
|
|
console.log(str);
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/projects/shared/src/random.ts": stringtestutil.Dedent(`
|
|
export function randomFn(str: string) {
|
|
console.log(str);
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/projects/shared/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"extends": "../../tsconfig.json",
|
|
"compilerOptions": {
|
|
"outDir": "./dist",
|
|
},
|
|
"include": ["src/**/*.ts"],
|
|
}`),
|
|
"/home/src/workspaces/solution/projects/server/src/server.ts": stringtestutil.Dedent(`
|
|
import { MyClass } from ':shared/myClass.js';
|
|
console.log('Hello, world!');
|
|
`),
|
|
"/home/src/workspaces/solution/projects/server/tsconfig.json": stringtestutil.Dedent(fmt.Sprintf(`
|
|
{
|
|
"extends": "../../tsconfig.json",
|
|
"compilerOptions": {
|
|
"rootDir": "..",
|
|
"outDir": "./dist",
|
|
"paths": {
|
|
":shared/*": ["./src/../../shared/src/*"],
|
|
},
|
|
},
|
|
"include": [ %s ],
|
|
"references": [
|
|
{ "path": "../shared" },
|
|
],
|
|
}`, include)),
|
|
}
|
|
}
|
|
getBuildRootsFromProjectReferencedProjectTestEdits := func() []*tscEdit {
|
|
return []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "edit logging file",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/home/src/workspaces/solution/projects/shared/src/logging.ts", "export const x = 10;")
|
|
},
|
|
},
|
|
noChange,
|
|
{
|
|
caption: "delete random file",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/solution/projects/shared/src/random.ts")
|
|
},
|
|
},
|
|
noChange,
|
|
}
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: `when two root files are consecutive`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/file1.ts": `export const x = "hello";`,
|
|
"/home/src/workspaces/project/file2.ts": `export const y = "world";`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"include": ["*.ts"],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b", "-v"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete file1",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/project/file1.ts")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.js")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.d.ts")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: `when multiple root files are consecutive`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/file1.ts": `export const x = "hello";`,
|
|
"/home/src/workspaces/project/file2.ts": `export const y = "world";`,
|
|
"/home/src/workspaces/project/file3.ts": `export const y = "world";`,
|
|
"/home/src/workspaces/project/file4.ts": `export const y = "world";`,
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"include": ["*.ts"],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b", "-v"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete file1",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/project/file1.ts")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.js")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.d.ts")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: `when files are not consecutive`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/file1.ts": `export const x = "hello";`,
|
|
"/home/src/workspaces/project/random.d.ts": `export const random = "world";`,
|
|
"/home/src/workspaces/project/file2.ts": stringtestutil.Dedent(`
|
|
import { random } from "./random";
|
|
export const y = "world";
|
|
`),
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"include": ["file*.ts"],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b", "-v"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete file1",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/project/file1.ts")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.js")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.d.ts")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: `when consecutive and non consecutive are mixed`,
|
|
files: FileMap{
|
|
"/home/src/workspaces/project/file1.ts": `export const x = "hello";`,
|
|
"/home/src/workspaces/project/file2.ts": `export const y = "world";`,
|
|
"/home/src/workspaces/project/random.d.ts": `export const random = "hello";`,
|
|
"/home/src/workspaces/project/nonconsecutive.ts": stringtestutil.Dedent(`
|
|
import { random } from "./random";
|
|
export const nonConsecutive = "hello";
|
|
`),
|
|
"/home/src/workspaces/project/random1.d.ts": `export const random = "hello";`,
|
|
"/home/src/workspaces/project/asArray1.ts": stringtestutil.Dedent(`
|
|
import { random } from "./random1";
|
|
export const x = "hello";
|
|
`),
|
|
"/home/src/workspaces/project/asArray2.ts": `export const x = "hello";`,
|
|
"/home/src/workspaces/project/asArray3.ts": `export const x = "hello";`,
|
|
"/home/src/workspaces/project/random2.d.ts": `export const random = "hello";`,
|
|
"/home/src/workspaces/project/anotherNonConsecutive.ts": stringtestutil.Dedent(`
|
|
import { random } from "./random2";
|
|
export const nonConsecutive = "hello";
|
|
`),
|
|
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"include": ["file*.ts", "nonconsecutive*.ts", "asArray*.ts", "anotherNonConsecutive.ts"],
|
|
}`),
|
|
},
|
|
commandLineArgs: []string{"--b", "-v"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "delete file1",
|
|
edit: func(sys *testSys) {
|
|
sys.removeNoError("/home/src/workspaces/project/file1.ts")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.js")
|
|
sys.removeNoError("/home/src/workspaces/project/file1.d.ts")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when root file is from referenced project",
|
|
files: getBuildRootsFromProjectReferencedProjectFileMap(true),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "projects/server", "-v", "--traceResolution", "--explainFiles"},
|
|
edits: getBuildRootsFromProjectReferencedProjectTestEdits(),
|
|
},
|
|
{
|
|
subScenario: "when root file is from referenced project and shared is first",
|
|
files: getBuildRootsFromProjectReferencedProjectFileMap(false),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "projects/server", "-v", "--traceResolution", "--explainFiles"},
|
|
edits: getBuildRootsFromProjectReferencedProjectTestEdits(),
|
|
},
|
|
{
|
|
subScenario: "when root file is from referenced project",
|
|
files: getBuildRootsFromProjectReferencedProjectFileMap(true),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "-w", "projects/server", "-v", "--traceResolution", "--explainFiles"},
|
|
edits: getBuildRootsFromProjectReferencedProjectTestEdits(),
|
|
},
|
|
{
|
|
subScenario: "when root file is from referenced project and shared is first",
|
|
files: getBuildRootsFromProjectReferencedProjectFileMap(false),
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "-w", "projects/server", "-v", "--traceResolution", "--explainFiles"},
|
|
edits: getBuildRootsFromProjectReferencedProjectTestEdits(),
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "roots")
|
|
}
|
|
}
|
|
|
|
func TestBuildSample(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
getLogicConfig := func() string {
|
|
return stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"sourceMap": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
"references": [
|
|
{ "path": "../core" },
|
|
],
|
|
}`)
|
|
}
|
|
|
|
getBuildSampleFileMap := func(modify func(files FileMap)) FileMap {
|
|
files := FileMap{
|
|
"/user/username/projects/sample1/core/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"declarationMap": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`),
|
|
"/user/username/projects/sample1/core/index.ts": stringtestutil.Dedent(`
|
|
export const someString: string = "HELLO WORLD";
|
|
export function leftPad(s: string, n: number) { return s + n; }
|
|
export function multiply(a: number, b: number) { return a * b; }
|
|
`),
|
|
"/user/username/projects/sample1/core/some_decl.d.ts": `declare const dts: any;`,
|
|
"/user/username/projects/sample1/core/anotherModule.ts": `export const World = "hello";`,
|
|
"/user/username/projects/sample1/logic/tsconfig.json": getLogicConfig(),
|
|
"/user/username/projects/sample1/logic/index.ts": stringtestutil.Dedent(`
|
|
import * as c from '../core/index';
|
|
export function getSecondsInDay() {
|
|
return c.multiply(10, 15);
|
|
}
|
|
import * as mod from '../core/anotherModule';
|
|
export const m = mod;
|
|
`),
|
|
"/user/username/projects/sample1/tests/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../core" },
|
|
{ "path": "../logic" },
|
|
],
|
|
"files": ["index.ts"],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`),
|
|
"/user/username/projects/sample1/tests/index.ts": stringtestutil.Dedent(`
|
|
import * as c from '../core/index';
|
|
import * as logic from '../logic/index';
|
|
|
|
c.leftPad("", 10);
|
|
logic.getSecondsInDay();
|
|
|
|
import * as mod from '../core/anotherModule';
|
|
export const m = mod;
|
|
`),
|
|
}
|
|
if modify != nil {
|
|
modify(files)
|
|
}
|
|
return files
|
|
}
|
|
getStopBuildOnErrorTests := func(options []string) []*tscInput {
|
|
noChange := core.IfElse(options == nil, noChangeOnlyEdit, nil)
|
|
return []*tscInput{
|
|
{
|
|
subScenario: "skips builds downstream projects if upstream projects have errors with stopBuildOnErrors",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
text, _ := files["/user/username/projects/sample1/core/index.ts"]
|
|
files["/user/username/projects/sample1/core/index.ts"] = text.(string) + `multiply();`
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: slices.Concat([]string{"--b", "tests", "--verbose", "--stopBuildOnErrors"}, options),
|
|
edits: slices.Concat(
|
|
noChange,
|
|
[]*tscEdit{
|
|
{
|
|
caption: "fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/index.ts", "multiply();", "")
|
|
},
|
|
},
|
|
},
|
|
),
|
|
},
|
|
{
|
|
subScenario: "skips builds downstream projects if upstream projects have errors with stopBuildOnErrors when test does not reference core",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/tests/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../logic" },
|
|
],
|
|
"files": ["index.ts"],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`)
|
|
text, _ := files["/user/username/projects/sample1/core/index.ts"]
|
|
files["/user/username/projects/sample1/core/index.ts"] = text.(string) + `multiply();`
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: slices.Concat([]string{"--b", "tests", "--verbose", "--stopBuildOnErrors"}, options),
|
|
edits: slices.Concat(
|
|
noChange,
|
|
[]*tscEdit{
|
|
{
|
|
caption: "fix error",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/index.ts", "multiply();", "")
|
|
},
|
|
},
|
|
},
|
|
),
|
|
},
|
|
}
|
|
}
|
|
getBuildSampleCoreChangeEdits := func() []*tscEdit {
|
|
return []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(
|
|
"/user/username/projects/sample1/core/index.ts",
|
|
`
|
|
export class someClass { }`,
|
|
)
|
|
},
|
|
},
|
|
{
|
|
caption: "incremental-declaration-doesnt-change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile(
|
|
"/user/username/projects/sample1/core/index.ts",
|
|
`
|
|
class someClass2 { }`,
|
|
)
|
|
},
|
|
},
|
|
noChange,
|
|
}
|
|
}
|
|
getBuildSampleWatchDtsChangingEdits := func() []*tscEdit {
|
|
return []*tscEdit{
|
|
{
|
|
caption: "Make change to core",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/user/username/projects/sample1/core/index.ts", "\nexport class someClass { }")
|
|
},
|
|
},
|
|
{
|
|
caption: "Revert core file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/index.ts", "\nexport class someClass { }", "")
|
|
},
|
|
},
|
|
{
|
|
caption: "Make two changes",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/user/username/projects/sample1/core/index.ts", "\nexport class someClass { }")
|
|
sys.appendFile("/user/username/projects/sample1/core/index.ts", "\nexport class someClass2 { }")
|
|
},
|
|
},
|
|
}
|
|
}
|
|
getBuildSampleWatchNonDtsChangingEdits := func() []*tscEdit {
|
|
return []*tscEdit{
|
|
{
|
|
caption: "Make local change to core",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/user/username/projects/sample1/core/index.ts", "\nfunction foo() { }")
|
|
},
|
|
},
|
|
}
|
|
}
|
|
getBuildSampleWatchNewFileEdits := func() []*tscEdit {
|
|
return []*tscEdit{
|
|
{
|
|
caption: "Change to new File and build core",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/sample1/core/newfile.ts", `export const newFileConst = 30;`, false)
|
|
},
|
|
},
|
|
{
|
|
caption: "Change to new File and build core",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/sample1/core/newfile.ts", "\nexport class someClass2 { }", false)
|
|
},
|
|
},
|
|
}
|
|
}
|
|
makeCircularReferences := func(files FileMap) {
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true
|
|
},
|
|
"references": [
|
|
{ "path": "../tests", "circular": true }
|
|
],
|
|
}`)
|
|
}
|
|
getIncrementalErrorTest := func(subScenario string, options []string) *tscInput {
|
|
var expectedDiffWithLogicError string
|
|
if slices.Contains(options, "--stopBuildOnErrors") {
|
|
expectedDiffWithLogicError = stringtestutil.Dedent(`
|
|
Clean build will stop on error in core and will not report error in logic
|
|
Watch build will retain previous errors from logic and report it
|
|
`)
|
|
}
|
|
return &tscInput{
|
|
subScenario: "reportErrors " + subScenario,
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: slices.Concat([]string{"-b", "-w", "tests"}, options),
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "change logic",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/user/username/projects/sample1/logic/index.ts", "\nlet y: string = 10;")
|
|
},
|
|
},
|
|
{
|
|
caption: "change core",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/user/username/projects/sample1/core/index.ts", "\nlet x: string = 10;")
|
|
},
|
|
expectedDiff: expectedDiffWithLogicError,
|
|
},
|
|
{
|
|
caption: "fix error in logic",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/logic/index.ts", "\nlet y: string = 10;", "")
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
testCases := slices.Concat([]*tscInput{
|
|
{
|
|
subScenario: "builds correctly when outDir is specified",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/logic/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"sourceMap": true,
|
|
"outDir": "outDir",
|
|
},
|
|
"references": [
|
|
{ "path": "../core" },
|
|
],
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests"},
|
|
},
|
|
{
|
|
subScenario: "builds correctly when declarationDir is specified",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/logic/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"sourceMap": true,
|
|
"declarationDir": "out/decls",
|
|
},
|
|
"references": [
|
|
{ "path": "../core" },
|
|
],
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests"},
|
|
},
|
|
{
|
|
subScenario: "builds correctly when project is not composite or doesnt have any references",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
text, _ := files["/user/username/projects/sample1/core/tsconfig.json"]
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = strings.Replace(text.(string), `"composite": true,`, "", 1)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "core", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "does not write any files in a dry build",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--dry"},
|
|
},
|
|
{
|
|
subScenario: "removes all files it built",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "removes all files it built",
|
|
commandLineArgs: []string{"--b", "tests", "--clean"},
|
|
},
|
|
{
|
|
caption: "no change --clean",
|
|
commandLineArgs: []string{"--b", "tests", "--clean"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "cleaning project in not build order doesnt throw error",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "logic2", "--clean"},
|
|
},
|
|
{
|
|
subScenario: "always builds under with force option",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--force"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "can detect when and what to rebuild",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
// Update a file in the leaf node (tests), only it should rebuild the last one
|
|
caption: "Only builds the leaf node project",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/sample1/tests/index.ts", "const m = 10;", false)
|
|
},
|
|
},
|
|
{
|
|
// Update a file in the parent (without affecting types), should get fast downstream builds
|
|
caption: "Detects type-only changes in upstream projects",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/index.ts", "HELLO WORLD", "WELCOME PLANET")
|
|
},
|
|
},
|
|
{
|
|
caption: "rebuilds when tsconfig changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/tests/tsconfig.json", `"composite": true`, `"composite": true, "target": "es2020"`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when input file text does not change but its modified time changes",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "upstream project changes without changing file text",
|
|
edit: func(sys *testSys) {
|
|
err := sys.FS().Chtimes("/user/username/projects/sample1/core/index.ts", time.Time{}, sys.Now())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when declarationMap changes",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Disable declarationMap",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/tsconfig.json", `"declarationMap": true,`, `"declarationMap": false,`)
|
|
},
|
|
},
|
|
{
|
|
caption: "Enable declarationMap",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/tsconfig.json", `"declarationMap": false,`, `"declarationMap": true,`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "indicates that it would skip builds during a dry build",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "--dry",
|
|
commandLineArgs: []string{"--b", "tests", "--dry"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "rebuilds from start if force option is set",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "--force build",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose", "--force"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
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{"--b", "-i", "-v"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "tsbuildinfo written has error",
|
|
edit: func(sys *testSys) {
|
|
// This is to ensure the non incremental doesnt crash - as it wont have tsbuildInfo
|
|
if !sys.forIncrementalCorrectness {
|
|
sys.prependFile("/home/src/workspaces/project/tsconfig.tsbuildinfo", "Some random string")
|
|
sys.replaceFileText("/home/src/workspaces/project/tsconfig.tsbuildinfo", fmt.Sprintf(`"version":"%s"`, core.Version()), fmt.Sprintf(`"version":"%s"`, harnessutil.FakeTSVersion)) // build info won't parse, need to manually sterilize for baseline
|
|
}
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "rebuilds completely when version in tsbuildinfo doesnt match ts version",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "convert tsbuildInfo version to something that is say to previous version",
|
|
edit: func(sys *testSys) {
|
|
// This is to ensure the non incremental doesnt crash - as it wont have tsbuildInfo
|
|
if !sys.forIncrementalCorrectness {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/tsconfig.tsbuildinfo", fmt.Sprintf(`"version":"%s"`, harnessutil.FakeTSVersion), fmt.Sprintf(`"version":"%s"`, "FakeTsPreviousVersion"))
|
|
sys.replaceFileText("/user/username/projects/sample1/logic/tsconfig.tsbuildinfo", fmt.Sprintf(`"version":"%s"`, harnessutil.FakeTSVersion), fmt.Sprintf(`"version":"%s"`, "FakeTsPreviousVersion"))
|
|
sys.replaceFileText("/user/username/projects/sample1/tests/tsconfig.tsbuildinfo", fmt.Sprintf(`"version":"%s"`, harnessutil.FakeTSVersion), fmt.Sprintf(`"version":"%s"`, "FakeTsPreviousVersion"))
|
|
}
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "rebuilds when extended config file changes",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/tests/tsconfig.base.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"target": "es5"
|
|
}
|
|
}`)
|
|
text, _ := files["/user/username/projects/sample1/tests/tsconfig.json"]
|
|
files["/user/username/projects/sample1/tests/tsconfig.json"] = strings.Replace(text.(string), `"references": [`, `"extends": "./tsconfig.base.json", "references": [`, 1)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "change extended file",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/sample1/tests/tsconfig.base.json", stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { }
|
|
}`), false)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "building project in not build order doesnt throw error",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "logic2/tsconfig.json", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "builds downstream projects even if upstream projects have errors",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
text, _ := files["/user/username/projects/sample1/logic/index.ts"]
|
|
files["/user/username/projects/sample1/logic/index.ts"] = strings.Replace(text.(string), "c.multiply(10, 15)", `c.muitply()`, 1)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "listFiles",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--listFiles"},
|
|
edits: getBuildSampleCoreChangeEdits(),
|
|
},
|
|
{
|
|
subScenario: "listEmittedFiles",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--listEmittedFiles"},
|
|
edits: getBuildSampleCoreChangeEdits(),
|
|
},
|
|
{
|
|
subScenario: "explainFiles",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--explainFiles", "--v"},
|
|
edits: getBuildSampleCoreChangeEdits(),
|
|
},
|
|
{
|
|
subScenario: "sample",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: slices.Concat(
|
|
getBuildSampleCoreChangeEdits(),
|
|
[]*tscEdit{
|
|
{
|
|
caption: "when logic config changes declaration dir",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText(
|
|
"/user/username/projects/sample1/logic/tsconfig.json",
|
|
`"declaration": true,`,
|
|
`"declaration": true,
|
|
"declarationDir": "decls",`,
|
|
)
|
|
},
|
|
},
|
|
noChange,
|
|
},
|
|
),
|
|
},
|
|
{
|
|
subScenario: "when logic specifies tsBuildInfoFile",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
text, _ := files["/user/username/projects/sample1/logic/tsconfig.json"]
|
|
files["/user/username/projects/sample1/logic/tsconfig.json"] = strings.Replace(
|
|
text.(string),
|
|
`"composite": true,`,
|
|
`"composite": true,
|
|
"tsBuildInfoFile": "ownFile.tsbuildinfo",`,
|
|
1,
|
|
)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
},
|
|
{
|
|
subScenario: "when declaration option changes",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "core", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/tsconfig.json", `"incremental": true,`, `"incremental": true, "declaration": true,`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when target option changes",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files[getTestLibPathFor("esnext.full")] = `/// <reference no-default-lib="true"/>
|
|
/// <reference lib="esnext" />`
|
|
files[tscLibPath+"/lib.d.ts"] = `/// <reference no-default-lib="true"/>
|
|
/// <reference lib="esnext" />`
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"listFiles": true,
|
|
"listEmittedFiles": true,
|
|
"target": "esnext",
|
|
},
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "core", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/tsconfig.json", `esnext`, `es5`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when module option changes",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"incremental": true,
|
|
"module": "node18",
|
|
},
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "core", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/core/tsconfig.json", `node18`, `nodenext`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "when esModuleInterop option changes",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/tests/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../core" },
|
|
{ "path": "../logic" },
|
|
],
|
|
"files": ["index.ts"],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"skipDefaultLibCheck": true,
|
|
"esModuleInterop": false,
|
|
},
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "incremental-declaration-changes",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/tests/tsconfig.json", `"esModuleInterop": false`, `"esModuleInterop": true`)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
// !!! sheetal this is not reporting error as file not found is not yet implemented
|
|
subScenario: "reports error if input file is missing",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"files": ["anotherModule.ts", "index.ts", "some_decl.d.ts"],
|
|
}`)
|
|
delete(files, "/user/username/projects/sample1/core/anotherModule.ts")
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose"},
|
|
},
|
|
{
|
|
// !!! sheetal this is not reporting error as file not found is not yet implemented
|
|
subScenario: "reports error if input file is missing with force",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"files": ["anotherModule.ts", "index.ts", "some_decl.d.ts"],
|
|
}`)
|
|
delete(files, "/user/username/projects/sample1/core/anotherModule.ts")
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "tests", "--verbose", "--force"},
|
|
},
|
|
{
|
|
subScenario: "change builds changes and reports found errors message",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests"},
|
|
edits: getBuildSampleWatchDtsChangingEdits(),
|
|
},
|
|
{
|
|
subScenario: "non local change does not start build of referencing projects",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests"},
|
|
edits: getBuildSampleWatchNonDtsChangingEdits(),
|
|
},
|
|
{
|
|
subScenario: "builds when new file is added, and its subsequent updates",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests"},
|
|
edits: getBuildSampleWatchNewFileEdits(),
|
|
},
|
|
{
|
|
subScenario: "change builds changes and reports found errors message with circular references",
|
|
files: getBuildSampleFileMap(makeCircularReferences),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests"},
|
|
edits: getBuildSampleWatchDtsChangingEdits(),
|
|
},
|
|
{
|
|
subScenario: "non local change does not start build of referencing projects with circular references",
|
|
files: getBuildSampleFileMap(makeCircularReferences),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests"},
|
|
edits: getBuildSampleWatchNonDtsChangingEdits(),
|
|
},
|
|
{
|
|
subScenario: "builds when new file is added, and its subsequent updates with circular references",
|
|
files: getBuildSampleFileMap(makeCircularReferences),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests"},
|
|
edits: getBuildSampleWatchNewFileEdits(),
|
|
},
|
|
{
|
|
subScenario: "watches config files that are not present",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
delete(files, "/user/username/projects/sample1/logic/tsconfig.json")
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Write logic",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/sample1/logic/tsconfig.json", getLogicConfig(), false)
|
|
},
|
|
},
|
|
},
|
|
},
|
|
getIncrementalErrorTest("when preserveWatchOutput is not used", nil),
|
|
getIncrementalErrorTest("when preserveWatchOutput is passed on command line", []string{"--preserveWatchOutput"}),
|
|
getIncrementalErrorTest("when stopBuildOnErrors is passed on command line", []string{"--stopBuildOnErrors"}),
|
|
{
|
|
subScenario: "incremental updates in verbose mode",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "tests", "--verbose"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "Make non dts change",
|
|
edit: func(sys *testSys) {
|
|
sys.appendFile("/user/username/projects/sample1/logic/index.ts", "\nfunction someFn() { }")
|
|
},
|
|
},
|
|
{
|
|
caption: "Make dts change",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/user/username/projects/sample1/logic/index.ts", "\nfunction someFn() { }", "\nexport function someFn() { }")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "should not trigger recompilation because of program emit",
|
|
files: getBuildSampleFileMap(nil),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "core", "--verbose"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "Add new file",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/sample1/core/file3.ts", `export const y = 10;`, false)
|
|
},
|
|
},
|
|
noChange,
|
|
},
|
|
},
|
|
{
|
|
subScenario: "should not trigger recompilation because of program emit with outDir specified",
|
|
files: getBuildSampleFileMap(func(files FileMap) {
|
|
files["/user/username/projects/sample1/core/tsconfig.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"outDir": "outDir"
|
|
}
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/sample1",
|
|
commandLineArgs: []string{"--b", "-w", "core", "--verbose"},
|
|
edits: []*tscEdit{
|
|
noChange,
|
|
{
|
|
caption: "Add new file",
|
|
edit: func(sys *testSys) {
|
|
sys.writeFileNoError("/user/username/projects/sample1/core/file3.ts", `export const y = 10;`, false)
|
|
},
|
|
},
|
|
noChange,
|
|
},
|
|
},
|
|
}, getStopBuildOnErrorTests(nil), getStopBuildOnErrorTests([]string{"--watch"}))
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "sample")
|
|
}
|
|
}
|
|
|
|
func TestBuildTransitiveReferences(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
getBuildTransitiveReferencesFileMap := func(modify func(files FileMap)) FileMap {
|
|
files := FileMap{
|
|
"/user/username/projects/transitiveReferences/refs/a.d.ts": stringtestutil.Dedent(`
|
|
export class X {}
|
|
export class A {}
|
|
`),
|
|
"/user/username/projects/transitiveReferences/a.ts": stringtestutil.Dedent(`
|
|
export class A {}
|
|
`),
|
|
"/user/username/projects/transitiveReferences/b.ts": stringtestutil.Dedent(`
|
|
import {A} from '@ref/a';
|
|
export const b = new A();
|
|
`),
|
|
"/user/username/projects/transitiveReferences/c.ts": stringtestutil.Dedent(`
|
|
import {b} from './b';
|
|
import {X} from "@ref/a";
|
|
b;
|
|
X;
|
|
`),
|
|
"/user/username/projects/transitiveReferences/tsconfig.a.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": ["a.ts"],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
},
|
|
}`),
|
|
"/user/username/projects/transitiveReferences/tsconfig.b.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": ["b.ts"],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"paths": {
|
|
"@ref/*": ["./*"],
|
|
},
|
|
},
|
|
"references": [{ "path": "tsconfig.a.json" }],
|
|
}`),
|
|
"/user/username/projects/transitiveReferences/tsconfig.c.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": ["c.ts"],
|
|
"compilerOptions": {
|
|
"paths": {
|
|
"@ref/*": ["./refs/*"],
|
|
},
|
|
},
|
|
"references": [{ "path": "tsconfig.b.json" }],
|
|
}`),
|
|
}
|
|
if modify != nil {
|
|
modify(files)
|
|
}
|
|
return files
|
|
}
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "builds correctly",
|
|
files: getBuildTransitiveReferencesFileMap(nil),
|
|
cwd: "/user/username/projects/transitiveReferences",
|
|
commandLineArgs: []string{"--b", "tsconfig.c.json", "--listFiles"},
|
|
},
|
|
{
|
|
subScenario: "reports error about module not found with node resolution with external module name",
|
|
files: getBuildTransitiveReferencesFileMap(func(files FileMap) {
|
|
files["/user/username/projects/transitiveReferences/b.ts"] = `import {A} from 'a';
|
|
export const b = new A();`
|
|
files["/user/username/projects/transitiveReferences/tsconfig.b.json"] = stringtestutil.Dedent(`
|
|
{
|
|
"files": ["b.ts"],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"module": "nodenext",
|
|
},
|
|
"references": [{ "path": "tsconfig.a.json" }],
|
|
}`)
|
|
}),
|
|
cwd: "/user/username/projects/transitiveReferences",
|
|
commandLineArgs: []string{"--b", "tsconfig.c.json", "--listFiles"},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "transitiveReferences")
|
|
}
|
|
}
|
|
|
|
func TestBuildSolutionProject(t *testing.T) {
|
|
t.Parallel()
|
|
testCases := []*tscInput{
|
|
{
|
|
subScenario: "verify that subsequent builds after initial build doesnt build anything",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/src/folder/index.ts": `export const x = 10;`,
|
|
"/home/src/workspaces/solution/src/folder/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": ["index.ts"],
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/src/folder2/index.ts": `export const x = 10;`,
|
|
"/home/src/workspaces/solution/src/folder2/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": ["index.ts"],
|
|
"compilerOptions": {
|
|
"composite": true
|
|
}
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/src/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": [],
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "./folder" },
|
|
{ "path": "./folder2" },
|
|
]
|
|
}`),
|
|
"/home/src/workspaces/solution/tests/index.ts": `export const x = 10;`,
|
|
"/home/src/workspaces/solution/tests/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": ["index.ts"],
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "../src" }
|
|
]
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"files": [],
|
|
"compilerOptions": {
|
|
"composite": true
|
|
},
|
|
"references": [
|
|
{ "path": "./src" },
|
|
{ "path": "./tests" }
|
|
]
|
|
}
|
|
`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "--v"},
|
|
edits: noChangeOnlyEdit,
|
|
},
|
|
{
|
|
subScenario: "when solution is referenced indirectly",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/project1/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": []
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/project2/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": []
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/project2/src/b.ts": "export const b = 10;",
|
|
"/home/src/workspaces/solution/project3/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": [
|
|
{ "path": "../project1" },
|
|
{ "path": "../project2" }
|
|
]
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/project3/src/c.ts": "export const c = 10;",
|
|
"/home/src/workspaces/solution/project4/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": { "composite": true },
|
|
"references": [{ "path": "../project3" }]
|
|
}
|
|
`),
|
|
"/home/src/workspaces/solution/project4/src/d.ts": "export const d = 10;",
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "project4", "--verbose", "--explainFiles"},
|
|
edits: []*tscEdit{
|
|
{
|
|
caption: "modify project3 file",
|
|
edit: func(sys *testSys) {
|
|
sys.replaceFileText("/home/src/workspaces/solution/project3/src/c.ts", "c = ", "cc = ")
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
subScenario: "has empty files diagnostic when files is empty and no references are provided",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/no-references/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [],
|
|
"files": [],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"forceConsistentCasingInFileNames": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "no-references"},
|
|
},
|
|
{
|
|
subScenario: "does not have empty files diagnostic when files is empty and references are provided",
|
|
files: FileMap{
|
|
"/home/src/workspaces/solution/core/index.ts": "export function multiply(a: number, b: number) { return a * b; }",
|
|
"/home/src/workspaces/solution/core/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"declarationMap": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`),
|
|
"/home/src/workspaces/solution/with-references/tsconfig.json": stringtestutil.Dedent(`
|
|
{
|
|
"references": [
|
|
{ "path": "../core" },
|
|
],
|
|
"files": [],
|
|
"compilerOptions": {
|
|
"composite": true,
|
|
"declaration": true,
|
|
"forceConsistentCasingInFileNames": true,
|
|
"skipDefaultLibCheck": true,
|
|
},
|
|
}`),
|
|
},
|
|
cwd: "/home/src/workspaces/solution",
|
|
commandLineArgs: []string{"--b", "with-references"},
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
test.run(t, "solution")
|
|
}
|
|
}
|