From 5bcd19275bcb5079d3c2d2bbc41c62dadd1cf1d9 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 4 Jun 2018 11:31:49 -0700 Subject: [PATCH] Tests to acknowledge the public watch api --- tests/baselines/reference/APISample_Watch.js | 133 ++++++++++++++++++ .../reference/APISample_WatchWithDefaults.js | 90 ++++++++++++ ...APISample_WatchWithOwnWatchHost.errors.txt | 71 ++++++++++ .../APISample_WatchWithOwnWatchHost.js | 102 ++++++++++++++ tests/cases/compiler/APISample_Watch.ts | 80 +++++++++++ .../compiler/APISample_WatchWithDefaults.ts | 53 +++++++ .../APISample_WatchWithOwnWatchHost.ts | 60 ++++++++ 7 files changed, 589 insertions(+) create mode 100644 tests/baselines/reference/APISample_Watch.js create mode 100644 tests/baselines/reference/APISample_WatchWithDefaults.js create mode 100644 tests/baselines/reference/APISample_WatchWithOwnWatchHost.errors.txt create mode 100644 tests/baselines/reference/APISample_WatchWithOwnWatchHost.js create mode 100644 tests/cases/compiler/APISample_Watch.ts create mode 100644 tests/cases/compiler/APISample_WatchWithDefaults.ts create mode 100644 tests/cases/compiler/APISample_WatchWithOwnWatchHost.ts diff --git a/tests/baselines/reference/APISample_Watch.js b/tests/baselines/reference/APISample_Watch.js new file mode 100644 index 00000000000..5e3a67e827d --- /dev/null +++ b/tests/baselines/reference/APISample_Watch.js @@ -0,0 +1,133 @@ +//// [APISample_Watch.ts] +/* + * Note: This test is a public API sample. The sample sources can be found + at: https://github.com/Microsoft/TypeScript-wiki/blob/master/Using-the-Compiler-API.md#writing-an-incremental-program-watcher + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + +declare var process: any; +declare var console: any; +declare var os: any; + +import ts = require("typescript"); + +const formatHost: ts.FormatDiagnosticsHost = { + getCanonicalFileName: path => path, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, +} + +function watchMain() { + const configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json"); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy to only re-check and emit files whose + // contents may have changed, or whose dependencies may have changes which may impact change the result of prior type-check and emit. + // The last uses an ordinary program which does a full type check after every change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + + // Note that there is another overload for `createWatchCompilerHost` that takes a set of root files. + const host = ts.createWatchCompilerHost(configPath, {}, ts.sys, + ts.createSemanticDiagnosticsBuilderProgram, + reportDiagnostic, + reportWatchStatusChanged, + ); + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames: ReadonlyArray, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} + +function reportDiagnostic(diagnostic: ts.Diagnostic) { + console.error("Error", diagnostic.code, ":", + ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine()) + ); +} + +/** + * Prints a diagnostic every time the watch status changes. + * This is mainly for messages like "Starting compilation" or "Compilation completed". + */ +function reportWatchStatusChanged(diagnostic: ts.Diagnostic) { + console.info(ts.formatDiagnostic(diagnostic, formatHost)); +} + +watchMain(); + + +//// [APISample_Watch.js] +"use strict"; +/* + * Note: This test is a public API sample. The sample sources can be found + at: https://github.com/Microsoft/TypeScript-wiki/blob/master/Using-the-Compiler-API.md#writing-an-incremental-program-watcher + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ +exports.__esModule = true; +var ts = require("typescript"); +var formatHost = { + getCanonicalFileName: function (path) { return path; }, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: function () { return ts.sys.newLine; } +}; +function watchMain() { + var configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json"); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy to only re-check and emit files whose + // contents may have changed, or whose dependencies may have changes which may impact change the result of prior type-check and emit. + // The last uses an ordinary program which does a full type check after every change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + // Note that there is another overload for `createWatchCompilerHost` that takes a set of root files. + var host = ts.createWatchCompilerHost(configPath, {}, ts.sys, ts.createSemanticDiagnosticsBuilderProgram, reportDiagnostic, reportWatchStatusChanged); + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + var origCreateProgram = host.createProgram; + host.createProgram = function (rootNames, options, host, oldProgram) { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + }; + var origPostProgramCreate = host.afterProgramCreate; + host.afterProgramCreate = function (program) { + console.log("** We finished making the program! **"); + origPostProgramCreate(program); + }; + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} +function reportDiagnostic(diagnostic) { + console.error("Error", diagnostic.code, ":", ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine())); +} +/** + * Prints a diagnostic every time the watch status changes. + * This is mainly for messages like "Starting compilation" or "Compilation completed". + */ +function reportWatchStatusChanged(diagnostic) { + console.info(ts.formatDiagnostic(diagnostic, formatHost)); +} +watchMain(); diff --git a/tests/baselines/reference/APISample_WatchWithDefaults.js b/tests/baselines/reference/APISample_WatchWithDefaults.js new file mode 100644 index 00000000000..493bef221f6 --- /dev/null +++ b/tests/baselines/reference/APISample_WatchWithDefaults.js @@ -0,0 +1,90 @@ +//// [APISample_WatchWithDefaults.ts] +/* + * Note: This test is a public API sample. This uses default sys interface without having to pass anything + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + +declare var console: any; + +import ts = require("typescript"); + +function watchMain() { + const configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json"); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy to only re-check and emit files whose + // contents may have changed, or whose dependencies may have changes which may impact change the result of prior type-check and emit. + // The last uses an ordinary program which does a full type check after every change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + + // Note that there is another overload for `createWatchCompilerHost` that takes a set of root files. + const host = ts.createWatchCompilerHost(configPath, {}, ts.sys); + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} + +watchMain(); + + +//// [APISample_WatchWithDefaults.js] +"use strict"; +/* + * Note: This test is a public API sample. This uses default sys interface without having to pass anything + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ +exports.__esModule = true; +var ts = require("typescript"); +function watchMain() { + var configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json"); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy to only re-check and emit files whose + // contents may have changed, or whose dependencies may have changes which may impact change the result of prior type-check and emit. + // The last uses an ordinary program which does a full type check after every change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + // Note that there is another overload for `createWatchCompilerHost` that takes a set of root files. + var host = ts.createWatchCompilerHost(configPath, {}, ts.sys); + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + var origCreateProgram = host.createProgram; + host.createProgram = function (rootNames, options, host, oldProgram) { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + }; + var origPostProgramCreate = host.afterProgramCreate; + host.afterProgramCreate = function (program) { + console.log("** We finished making the program! **"); + origPostProgramCreate(program); + }; + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} +watchMain(); diff --git a/tests/baselines/reference/APISample_WatchWithOwnWatchHost.errors.txt b/tests/baselines/reference/APISample_WatchWithOwnWatchHost.errors.txt new file mode 100644 index 00000000000..46910d16b63 --- /dev/null +++ b/tests/baselines/reference/APISample_WatchWithOwnWatchHost.errors.txt @@ -0,0 +1,71 @@ +tests/cases/compiler/APISample_WatchWithOwnWatchHost.ts(15,11): error TS2322: Type '{ rootFiles: string[]; options: CompilerOptions; useCaseSensitiveFileNames: () => boolean; getNewLine: () => string; getCurrentDirectory: () => string; getDefaultLibFileName: (options: CompilerOptions) => string; fileExists: (path: string) => boolean; readFile: (path: string, encoding?: string | undefined) => string | undefined; directoryExists: (path: string) => boolean; getDirectories: (path: string) => string[]; readDirectory: (path: string, extensions?: ReadonlyArray | undefined, exclude?: ReadonlyArray | undefined, include?: ReadonlyArray | undefined, depth?: number | undefined) => string[]; realpath: ((path: string) => string) | undefined; watchFile: (path: string, callback: FileWatcherCallback, pollingInterval?: number | undefined) => FileWatcher; watchDirectory: (path: string, callback: DirectoryWatcherCallback, recursive?: boolean | undefined) => FileWatcher; createProgram: { (newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost | undefined, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; }; }' is not assignable to type 'WatchCompilerHostOfFilesAndCompilerOptions'. + Types of property 'createProgram' are incompatible. + Type '{ (newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost | undefined, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; }' is not assignable to type 'CreateProgram'. + Types of parameters 'newProgram' and 'rootNames' are incompatible. + Type 'ReadonlyArray | undefined' is not assignable to type 'Program'. + Type 'undefined' is not assignable to type 'Program'. + + +==== tests/cases/compiler/APISample_WatchWithOwnWatchHost.ts (1 errors) ==== + /* + * Note: This test is a public API sample. This sample verifies creating abstract builder to watch list of root files + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + + declare var console: any; + + import ts = require("typescript"); + + function watchMain() { + // get list of files and compiler options somehow + const files: string[] = []; + const options: ts.CompilerOptions = {}; + + const host: ts.WatchCompilerHostOfFilesAndCompilerOptions = { + ~~~~ +!!! error TS2322: Type '{ rootFiles: string[]; options: CompilerOptions; useCaseSensitiveFileNames: () => boolean; getNewLine: () => string; getCurrentDirectory: () => string; getDefaultLibFileName: (options: CompilerOptions) => string; fileExists: (path: string) => boolean; readFile: (path: string, encoding?: string | undefined) => string | undefined; directoryExists: (path: string) => boolean; getDirectories: (path: string) => string[]; readDirectory: (path: string, extensions?: ReadonlyArray | undefined, exclude?: ReadonlyArray | undefined, include?: ReadonlyArray | undefined, depth?: number | undefined) => string[]; realpath: ((path: string) => string) | undefined; watchFile: (path: string, callback: FileWatcherCallback, pollingInterval?: number | undefined) => FileWatcher; watchDirectory: (path: string, callback: DirectoryWatcherCallback, recursive?: boolean | undefined) => FileWatcher; createProgram: { (newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost | undefined, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; }; }' is not assignable to type 'WatchCompilerHostOfFilesAndCompilerOptions'. +!!! error TS2322: Types of property 'createProgram' are incompatible. +!!! error TS2322: Type '{ (newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost | undefined, oldProgram?: BuilderProgram | undefined, configFileParsingDiagnostics?: ReadonlyArray | undefined): BuilderProgram; }' is not assignable to type 'CreateProgram'. +!!! error TS2322: Types of parameters 'newProgram' and 'rootNames' are incompatible. +!!! error TS2322: Type 'ReadonlyArray | undefined' is not assignable to type 'Program'. +!!! error TS2322: Type 'undefined' is not assignable to type 'Program'. + rootFiles: files, + options, + + useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, + getNewLine: () => ts.sys.newLine, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getDefaultLibFileName: options => ts.getDefaultLibFilePath(options), + + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile, + directoryExists: ts.sys.directoryExists, + getDirectories: ts.sys.getDirectories, + readDirectory: ts.sys.readDirectory, + realpath: ts.sys.realpath, + + watchFile: ts.sys.watchFile!, + watchDirectory: ts.sys.watchDirectory!, + createProgram: ts.createAbstractBuilder + }; + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); + } + + watchMain(); + \ No newline at end of file diff --git a/tests/baselines/reference/APISample_WatchWithOwnWatchHost.js b/tests/baselines/reference/APISample_WatchWithOwnWatchHost.js new file mode 100644 index 00000000000..95f6df3fb51 --- /dev/null +++ b/tests/baselines/reference/APISample_WatchWithOwnWatchHost.js @@ -0,0 +1,102 @@ +//// [APISample_WatchWithOwnWatchHost.ts] +/* + * Note: This test is a public API sample. This sample verifies creating abstract builder to watch list of root files + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + +declare var console: any; + +import ts = require("typescript"); + +function watchMain() { + // get list of files and compiler options somehow + const files: string[] = []; + const options: ts.CompilerOptions = {}; + + const host: ts.WatchCompilerHostOfFilesAndCompilerOptions = { + rootFiles: files, + options, + + useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, + getNewLine: () => ts.sys.newLine, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getDefaultLibFileName: options => ts.getDefaultLibFilePath(options), + + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile, + directoryExists: ts.sys.directoryExists, + getDirectories: ts.sys.getDirectories, + readDirectory: ts.sys.readDirectory, + realpath: ts.sys.realpath, + + watchFile: ts.sys.watchFile!, + watchDirectory: ts.sys.watchDirectory!, + createProgram: ts.createAbstractBuilder + }; + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} + +watchMain(); + + +//// [APISample_WatchWithOwnWatchHost.js] +"use strict"; +/* + * Note: This test is a public API sample. This sample verifies creating abstract builder to watch list of root files + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ +exports.__esModule = true; +var ts = require("typescript"); +function watchMain() { + // get list of files and compiler options somehow + var files = []; + var options = {}; + var host = { + rootFiles: files, + options: options, + useCaseSensitiveFileNames: function () { return ts.sys.useCaseSensitiveFileNames; }, + getNewLine: function () { return ts.sys.newLine; }, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getDefaultLibFileName: function (options) { return ts.getDefaultLibFilePath(options); }, + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile, + directoryExists: ts.sys.directoryExists, + getDirectories: ts.sys.getDirectories, + readDirectory: ts.sys.readDirectory, + realpath: ts.sys.realpath, + watchFile: ts.sys.watchFile, + watchDirectory: ts.sys.watchDirectory, + createProgram: ts.createAbstractBuilder + }; + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + var origCreateProgram = host.createProgram; + host.createProgram = function (rootNames, options, host, oldProgram) { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + }; + var origPostProgramCreate = host.afterProgramCreate; + host.afterProgramCreate = function (program) { + console.log("** We finished making the program! **"); + origPostProgramCreate(program); + }; + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} +watchMain(); diff --git a/tests/cases/compiler/APISample_Watch.ts b/tests/cases/compiler/APISample_Watch.ts new file mode 100644 index 00000000000..e1506676426 --- /dev/null +++ b/tests/cases/compiler/APISample_Watch.ts @@ -0,0 +1,80 @@ +// @module: commonjs +// @skipLibCheck: true +// @includebuiltfile: typescript_standalone.d.ts +// @noImplicitAny:true +// @strictNullChecks:true + +/* + * Note: This test is a public API sample. The sample sources can be found + at: https://github.com/Microsoft/TypeScript-wiki/blob/master/Using-the-Compiler-API.md#writing-an-incremental-program-watcher + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + +declare var process: any; +declare var console: any; +declare var os: any; + +import ts = require("typescript"); + +const formatHost: ts.FormatDiagnosticsHost = { + getCanonicalFileName: path => path, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, +} + +function watchMain() { + const configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json"); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy to only re-check and emit files whose + // contents may have changed, or whose dependencies may have changes which may impact change the result of prior type-check and emit. + // The last uses an ordinary program which does a full type check after every change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + + // Note that there is another overload for `createWatchCompilerHost` that takes a set of root files. + const host = ts.createWatchCompilerHost(configPath, {}, ts.sys, + ts.createSemanticDiagnosticsBuilderProgram, + reportDiagnostic, + reportWatchStatusChanged, + ); + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames: ReadonlyArray, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} + +function reportDiagnostic(diagnostic: ts.Diagnostic) { + console.error("Error", diagnostic.code, ":", + ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine()) + ); +} + +/** + * Prints a diagnostic every time the watch status changes. + * This is mainly for messages like "Starting compilation" or "Compilation completed". + */ +function reportWatchStatusChanged(diagnostic: ts.Diagnostic) { + console.info(ts.formatDiagnostic(diagnostic, formatHost)); +} + +watchMain(); diff --git a/tests/cases/compiler/APISample_WatchWithDefaults.ts b/tests/cases/compiler/APISample_WatchWithDefaults.ts new file mode 100644 index 00000000000..24f251daca2 --- /dev/null +++ b/tests/cases/compiler/APISample_WatchWithDefaults.ts @@ -0,0 +1,53 @@ +// @module: commonjs +// @skipLibCheck: true +// @includebuiltfile: typescript_standalone.d.ts +// @noImplicitAny:true +// @strict:true + +/* + * Note: This test is a public API sample. This uses default sys interface without having to pass anything + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + +declare var console: any; + +import ts = require("typescript"); + +function watchMain() { + const configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json"); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } + + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy to only re-check and emit files whose + // contents may have changed, or whose dependencies may have changes which may impact change the result of prior type-check and emit. + // The last uses an ordinary program which does a full type check after every change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + + // Note that there is another overload for `createWatchCompilerHost` that takes a set of root files. + const host = ts.createWatchCompilerHost(configPath, {}, ts.sys); + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} + +watchMain(); diff --git a/tests/cases/compiler/APISample_WatchWithOwnWatchHost.ts b/tests/cases/compiler/APISample_WatchWithOwnWatchHost.ts new file mode 100644 index 00000000000..18f170bd5f6 --- /dev/null +++ b/tests/cases/compiler/APISample_WatchWithOwnWatchHost.ts @@ -0,0 +1,60 @@ +// @module: commonjs +// @skipLibCheck: true +// @includebuiltfile: typescript_standalone.d.ts +// @noImplicitAny:true +// @strict:true + +/* + * Note: This test is a public API sample. This sample verifies creating abstract builder to watch list of root files + * Please log a "breaking change" issue for any API breaking change affecting this issue + */ + +declare var console: any; + +import ts = require("typescript"); + +function watchMain() { + // get list of files and compiler options somehow + const files: string[] = []; + const options: ts.CompilerOptions = {}; + + const host: ts.WatchCompilerHostOfFilesAndCompilerOptions = { + rootFiles: files, + options, + + useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, + getNewLine: () => ts.sys.newLine, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getDefaultLibFileName: options => ts.getDefaultLibFilePath(options), + + fileExists: ts.sys.fileExists, + readFile: ts.sys.readFile, + directoryExists: ts.sys.directoryExists, + getDirectories: ts.sys.getDirectories, + readDirectory: ts.sys.readDirectory, + realpath: ts.sys.realpath, + + watchFile: ts.sys.watchFile!, + watchDirectory: ts.sys.watchDirectory!, + createProgram: ts.createAbstractBuilder + }; + + // You can technically override any given hook on the host, though you probably don't need to. + // Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all. + const origCreateProgram = host.createProgram; + host.createProgram = (rootNames, options, host, oldProgram) => { + console.log("** We're about to create the program! **"); + return origCreateProgram(rootNames, options, host, oldProgram); + } + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = program => { + console.log("** We finished making the program! **"); + origPostProgramCreate!(program); + }; + + // `createWatchProgram` creates an initial program, watches files, and updates the program over time. + ts.createWatchProgram(host); +} + +watchMain();