Skip to content

Commit b7918bf

Browse files
committed
Fix runtests-parallel, tsserverlibrary, up-to-date checks
1 parent 0bb8972 commit b7918bf

File tree

4 files changed

+113
-68
lines changed

4 files changed

+113
-68
lines changed

Gulpfile.js

+24-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ const browserify = require("browserify");
1414
const through2 = require("through2");
1515
const fold = require("travis-fold");
1616
const rename = require("gulp-rename");
17-
const concat = require("gulp-concat");
1817
const convertMap = require("convert-source-map");
1918
const sorcery = require("sorcery");
2019
const Vinyl = require("vinyl");
@@ -155,7 +154,7 @@ gulp.task(typescriptServicesProject, /*help*/ false, () => {
155154
const typescriptServicesJs = "built/local/typescriptServices.js";
156155
const typescriptServicesDts = "built/local/typescriptServices.d.ts";
157156
gulp.task(typescriptServicesJs, /*help*/ false, ["lib", "generate-diagnostics", typescriptServicesProject], () =>
158-
project.compile(typescriptServicesProject, { dts: convertConstEnums() }),
157+
project.compile(typescriptServicesProject, { dts: files => files.pipe(convertConstEnums()) }),
159158
{ aliases: [typescriptServicesDts] });
160159

161160
const typescriptJs = "built/local/typescript.js";
@@ -182,7 +181,7 @@ gulp.task(typescriptStandaloneDts, /*help*/ false, [typescriptServicesDts], () =
182181
.pipe(gulp.dest("built/local")));
183182

184183
// build all 'typescriptServices'-related outputs
185-
gulp.task("typescriptServices", /*help*/ false, [typescriptServicesJs, typescriptServicesDts, typescriptJs, typescriptDts, typescriptStandaloneDts]);
184+
gulp.task("services", /*help*/ false, [typescriptServicesJs, typescriptServicesDts, typescriptJs, typescriptDts, typescriptStandaloneDts]);
186185

187186
const tscProject = "src/tsc/tsconfig.json";
188187
const tscJs = "built/local/tsc.js";
@@ -211,13 +210,28 @@ gulp.task(typesMapJson, /*help*/ false, [], () =>
211210
.pipe(insert.transform(contents => (JSON.parse(contents), contents)))
212211
.pipe(gulp.dest("built/local")));
213212

213+
const tsserverlibraryProject = "built/local/tsserverlibrary.tsconfig.json";
214+
gulp.task(tsserverlibraryProject, /*help*/ false, () => {
215+
// NOTE: flatten tsserverlibrary so that we can properly strip @internal
216+
project.flatten("src/tsserver/tsconfig.json", tsserverlibraryProject, {
217+
exclude: ["src/tsserver/server.ts"],
218+
compilerOptions: {
219+
"removeComments": true,
220+
"stripInternal": true,
221+
"outFile": "tsserverlibrary.js"
222+
}
223+
});
224+
});
225+
226+
const tsserverlibraryJs = "built/local/tsserverlibrary.js";
214227
const tsserverlibraryDts = "built/local/tsserverlibrary.d.ts";
215-
gulp.task(tsserverlibraryDts, /*help*/ false, [tsserverJs], () =>
216-
gulp.src(["built/local/compiler.d.ts", "built/local/jsTyping.d.ts", "built/local/services.d.ts", "built/local/server.d.ts"], { base: "built/local" })
217-
.pipe(convertConstEnums())
218-
.pipe(concat("tsserverlibrary.d.ts", { newLine: "\n" }))
219-
.pipe(append("\nexport = ts;\nexport as namespace ts;"))
220-
.pipe(gulp.dest("built/local")));
228+
gulp.task(tsserverlibraryJs, /*help*/ false, [typescriptServicesJs, tsserverlibraryProject], () =>
229+
project.compile(tsserverlibraryProject, {
230+
dts: files => files
231+
.pipe(convertConstEnums())
232+
.pipe(append("\nexport = ts;\nexport as namespace ts;")),
233+
typescript: "built"
234+
}), { aliases: [tsserverlibraryDts] });
221235

222236
gulp.task(
223237
"lssl",
@@ -227,7 +241,7 @@ gulp.task(
227241
gulp.task(
228242
"local",
229243
"Builds the full compiler and services",
230-
[tscJs, "typescriptServices", tsserverJs, builtGeneratedDiagnosticMessagesJson, tsserverlibraryDts, "localize"]);
244+
[tscJs, "services", tsserverJs, builtGeneratedDiagnosticMessagesJson, tsserverlibraryDts, "localize"]);
231245

232246
gulp.task(
233247
"tsc",

scripts/build/gulp-typescript-oop.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ function createProject(tsConfigFileName, settings, options) {
2424

2525
const project = tsConfigFileName === undefined ? tsc.createProject(localSettings) : tsc.createProject(tsConfigFileName, localSettings);
2626
const wrappedProject = /** @type {tsc.Project} */(() => {
27-
const proc = child_process.fork(require.resolve("./main.js"));
27+
const proc = child_process.fork(require.resolve("./main.js"), [], {
28+
// Prevent errors when debugging gulpfile due to the same debug port being passed to forked children.
29+
execArgv: []
30+
});
2831
/** @type {Duplex & { js?: Readable, dts?: Readable }} */
2932
const compileStream = new Duplex({
3033
objectMode: true,

scripts/build/project.js

+59-53
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,41 @@ const del = require("del");
1313
const needsUpdate = require("./needsUpdate");
1414
const mkdirp = require("./mkdirp");
1515
const { reportDiagnostics } = require("./diagnostics");
16-
const { PassThrough } = require("stream");
1716

1817
class CompilationGulp extends gulp.Gulp {
1918
/**
20-
* @param {import("gulp-help").GulpHelp | import("gulp").Gulp} gulp
19+
* @param {boolean} [verbose]
2120
*/
22-
constructor(gulp) {
23-
super();
24-
// forward notifications to the outer gulp.
25-
this.on("task_start", e => gulp.emit("task_start", e));
26-
this.on("task_stop", e => gulp.emit("task_stop", e));
27-
this.on("task_err", e => gulp.emit("task_err", e));
28-
this.on("task_not_found", e => gulp.emit("task_not_found", e));
29-
this.on("task_recursion", e => gulp.emit("task_recursion", e));
30-
this.on("err", e => gulp.emit("err", e));
21+
fork(verbose) {
22+
const child = new ForkedGulp(this.tasks);
23+
if (verbose) {
24+
this.on("task_start", e => gulp.emit("task_start", e));
25+
this.on("task_stop", e => gulp.emit("task_stop", e));
26+
this.on("task_err", e => gulp.emit("task_err", e));
27+
this.on("task_not_found", e => gulp.emit("task_not_found", e));
28+
this.on("task_recursion", e => gulp.emit("task_recursion", e));
29+
}
30+
return child;
3131
}
32+
}
3233

33-
dispose() {
34-
this.removeAllListeners();
35-
this.reset();
34+
class ForkedGulp extends gulp.Gulp {
35+
/**
36+
* @param {gulp.Gulp["tasks"]} tasks
37+
*/
38+
constructor(tasks) {
39+
super();
40+
this.tasks = tasks;
3641
}
37-
38-
// Do not reset tasks when `gulp.start()` is called
42+
43+
// Do not reset tasks
3944
_resetAllTasks() {}
4045
_resetSpecificTasks() {}
4146
_resetTask() {}
4247
}
4348

4449
// internal `Gulp` instance for compilation artifacts.
45-
const compilationGulp = new CompilationGulp(gulp);
50+
const compilationGulp = new CompilationGulp();
4651

4752
/** @type {Map<ResolvedProjectSpec, ProjectGraph>} */
4853
const projectGraphCache = new Map();
@@ -60,7 +65,9 @@ function createCompiler(projectSpec, options) {
6065
const resolvedOptions = resolveProjectOptions(options);
6166
const resolvedProjectSpec = resolveProjectSpec(projectSpec, resolvedOptions.paths, /*referrer*/ undefined);
6267
const taskName = compileTaskName(ensureCompileTask(getOrCreateProjectGraph(resolvedProjectSpec, resolvedOptions.paths), resolvedOptions), resolvedOptions.typescript);
63-
return () => new Promise((resolve, reject) => compilationGulp.start(taskName, err => err ? reject(err) : resolve(err)));
68+
return () => new Promise((resolve, reject) => compilationGulp
69+
.fork(resolvedOptions.verbose)
70+
.start(taskName, err => err ? reject(err) : resolve()));
6471
}
6572
exports.createCompiler = createCompiler;
6673

@@ -74,13 +81,13 @@ exports.createCompiler = createCompiler;
7481
* @property {string} [cwd] The path to use for the current working directory. Defaults to `process.cwd()`.
7582
* @property {string} [base] The path to use as the base for relative paths. Defaults to `cwd`.
7683
* @property {string} [typescript] A module specifier or path (relative to gulpfile.js) to the version of TypeScript to use.
77-
* @property {Hook} [js] Pipeline hook for .js file outputs. For multiple steps, use `stream-combiner`.
78-
* @property {Hook} [dts] Pipeline hook for .d.ts file outputs. For multiple steps, use `stream-combiner`.
84+
* @property {Hook} [js] Pipeline hook for .js file outputs.
85+
* @property {Hook} [dts] Pipeline hook for .d.ts file outputs.
7986
* @property {boolean} [verbose] Indicates whether verbose logging is enabled.
8087
* @property {boolean} [force] Force recompilation (no up-to-date check).
8188
* @property {boolean} [inProcess] Indicates whether to run gulp-typescript in-process or out-of-process (default).
8289
*
83-
* @typedef {NodeJS.ReadWriteStream | (() => NodeJS.ReadWriteStream)} Hook
90+
* @typedef {(stream: NodeJS.ReadableStream) => NodeJS.ReadWriteStream} Hook
8491
*/
8592
function compile(projectSpec, options) {
8693
const compiler = createCompiler(projectSpec, options);
@@ -97,7 +104,9 @@ function createCleaner(projectSpec, options) {
97104
const paths = resolvePathOptions(options);
98105
const resolvedProjectSpec = resolveProjectSpec(projectSpec, paths, /*referrer*/ undefined);
99106
const taskName = cleanTaskName(ensureCleanTask(getOrCreateProjectGraph(resolvedProjectSpec, paths)));
100-
return () => new Promise((resolve, reject) => compilationGulp.start(taskName, err => err ? reject(err) : resolve(err)));
107+
return () => new Promise((resolve, reject) => compilationGulp
108+
.fork()
109+
.start(taskName, err => err ? reject(err) : resolve()));
101110
}
102111
exports.createCleaner = createCleaner;
103112

@@ -134,6 +143,7 @@ exports.addTypeScript = addTypeScript;
134143
* @property {string} [cwd] The path to use for the current working directory. Defaults to `process.cwd()`.
135144
* @property {CompilerOptions} [compilerOptions] Compiler option overrides.
136145
* @property {boolean} [force] Forces creation of the output project.
146+
* @property {string[]} [exclude] Files to exclude (relative to `cwd`)
137147
*/
138148
function flatten(projectSpec, flattenedProjectSpec, options = {}) {
139149
const paths = resolvePathOptions(options);
@@ -142,15 +152,16 @@ function flatten(projectSpec, flattenedProjectSpec, options = {}) {
142152
const resolvedOutputDirectory = path.dirname(resolvedOutputSpec);
143153
const resolvedProjectSpec = resolveProjectSpec(projectSpec, paths, /*referrer*/ undefined);
144154
const projectGraph = getOrCreateProjectGraph(resolvedProjectSpec, paths);
155+
const skipProjects = /**@type {Set<ProjectGraph>}*/(new Set());
156+
const skipFiles = new Set(options && options.exclude && options.exclude.map(file => path.resolve(paths.cwd, file)));
145157
recur(projectGraph);
146158

147-
const config = {
148-
extends: normalizeSlashes(path.relative(resolvedOutputDirectory, resolvedProjectSpec)),
149-
compilerOptions: options.compilerOptions || {},
150-
files
151-
};
152-
153159
if (options.force || needsUpdate(files, resolvedOutputSpec)) {
160+
const config = {
161+
extends: normalizeSlashes(path.relative(resolvedOutputDirectory, resolvedProjectSpec)),
162+
compilerOptions: options.compilerOptions || {},
163+
files: files.map(file => normalizeSlashes(path.relative(resolvedOutputDirectory, file)))
164+
};
154165
mkdirp.sync(resolvedOutputDirectory);
155166
fs.writeFileSync(resolvedOutputSpec, JSON.stringify(config, undefined, 2), "utf8");
156167
}
@@ -159,11 +170,16 @@ function flatten(projectSpec, flattenedProjectSpec, options = {}) {
159170
* @param {ProjectGraph} projectGraph
160171
*/
161172
function recur(projectGraph) {
173+
if (skipProjects.has(projectGraph)) return;
174+
skipProjects.add(projectGraph);
162175
for (const ref of projectGraph.references) {
163176
recur(ref.target);
164177
}
165-
for (const file of projectGraph.project.fileNames) {
166-
files.push(normalizeSlashes(path.relative(resolvedOutputDirectory, path.resolve(projectGraph.projectDirectory, file))));
178+
for (let file of projectGraph.project.fileNames) {
179+
file = path.resolve(projectGraph.projectDirectory, file);
180+
if (skipFiles.has(file)) continue;
181+
skipFiles.add(file);
182+
files.push(file);
167183
}
168184
}
169185
}
@@ -257,14 +273,6 @@ function resolveProjectOptions(options = {}) {
257273
};
258274
}
259275

260-
/**
261-
* @param {Hook} hook
262-
* @returns {NodeJS.ReadWriteStream}
263-
*/
264-
function evaluateHook(hook) {
265-
return (typeof hook === "function" ? hook() : hook) || new PassThrough({ objectMode: true });
266-
}
267-
268276
/**
269277
* @param {ResolvedProjectOptions} left
270278
* @param {ResolvedProjectOptions} right
@@ -448,31 +456,29 @@ function resolveDestPath(projectGraph, paths) {
448456

449457
/**
450458
* @param {ProjectGraph} projectGraph
451-
* @param {ResolvedProjectOptions} resolvedOptions
459+
* @param {ResolvedProjectOptions} options
452460
*/
453-
function ensureCompileTask(projectGraph, resolvedOptions) {
454-
const projectGraphConfig = getOrCreateProjectGraphConfiguration(projectGraph, resolvedOptions);
455-
projectGraphConfig.resolvedOptions = resolvedOptions = mergeProjectOptions(resolvedOptions, resolvedOptions);
461+
function ensureCompileTask(projectGraph, options) {
462+
const projectGraphConfig = getOrCreateProjectGraphConfiguration(projectGraph, options);
463+
projectGraphConfig.resolvedOptions = options = mergeProjectOptions(options, options);
456464
if (!projectGraphConfig.compileTaskCreated) {
457-
const deps = makeProjectReferenceCompileTasks(projectGraph, resolvedOptions.typescript, resolvedOptions.paths);
458-
compilationGulp.task(compileTaskName(projectGraph, resolvedOptions.typescript), deps, () => {
459-
const destPath = resolveDestPath(projectGraph, resolvedOptions.paths);
465+
const deps = makeProjectReferenceCompileTasks(projectGraph, options.typescript, options.paths);
466+
compilationGulp.task(compileTaskName(projectGraph, options.typescript), deps, () => {
467+
const destPath = resolveDestPath(projectGraph, options.paths);
460468
const { sourceMap, inlineSourceMap, inlineSources = false, sourceRoot, declarationMap } = projectGraph.project.options;
461469
const configFilePath = projectGraph.project.options.configFilePath;
462470
const sourceMapPath = inlineSourceMap ? undefined : ".";
463471
const sourceMapOptions = { includeContent: inlineSources, sourceRoot, destPath };
464-
const project = resolvedOptions.inProcess
465-
? tsc.createProject(configFilePath, { typescript: require(resolvedOptions.typescript.typescript) })
466-
: tsc_oop.createProject(configFilePath, {}, { typescript: resolvedOptions.typescript.typescript });
472+
const project = options.inProcess
473+
? tsc.createProject(configFilePath, { typescript: require(options.typescript.typescript) })
474+
: tsc_oop.createProject(configFilePath, {}, { typescript: options.typescript.typescript });
467475
const stream = project.src()
468-
.pipe(gulpif(!resolvedOptions.force, upToDate(projectGraph.project, { verbose: resolvedOptions.verbose })))
476+
.pipe(gulpif(!options.force, upToDate(projectGraph.project, { verbose: options.verbose })))
469477
.pipe(gulpif(sourceMap || inlineSourceMap, sourcemaps.init()))
470478
.pipe(project());
471-
const js = stream.js
472-
.pipe(evaluateHook(resolvedOptions.js))
479+
const js = (options.js ? options.js(stream.js) : stream.js)
473480
.pipe(gulpif(sourceMap || inlineSourceMap, sourcemaps.write(sourceMapPath, sourceMapOptions)));
474-
const dts = stream.dts
475-
.pipe(evaluateHook(resolvedOptions.dts))
481+
const dts = (options.dts ? options.dts(stream.dts) : stream.dts)
476482
.pipe(gulpif(declarationMap, sourcemaps.write(sourceMapPath, sourceMapOptions)));
477483
return merge2([js, dts])
478484
.pipe(gulp.dest(destPath));

scripts/build/upToDate.js

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-check
22
const path = require("path");
3+
const fs = require("fs");
34
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
45
const ts = require("../../lib/typescript");
56
const { Duplex } = require("stream");
@@ -10,20 +11,26 @@ const Vinyl = require("vinyl");
1011
* Creates a stream that passes through its inputs only if the project outputs are not up to date
1112
* with respect to the inputs.
1213
* @param {ParsedCommandLine} parsedProject
13-
* @param {{verbose?: boolean}} [options]
14+
* @param {UpToDateOptions} [options]
15+
*
16+
* @typedef UpToDateOptions
17+
* @property {boolean} [verbose]
1418
*/
1519
function upToDate(parsedProject, options) {
1620
/** @type {File[]} */
1721
const inputs = [];
1822
/** @type {Map<string, File>} */
1923
const inputMap = new Map();
24+
/** @type {Map<string, fs.Stats>} */
25+
const statCache = new Map();
2026
/** @type {UpToDateHost} */
2127
const upToDateHost = {
2228
fileExists(fileName) {
23-
return inputMap.has(path.resolve(fileName));
29+
const stats = getStat(fileName);
30+
return stats ? stats.isFile() : false;
2431
},
2532
getModifiedTime(fileName) {
26-
return inputMap.get(path.resolve(fileName)).stat.mtime;
33+
return getStat(fileName).mtime;
2734
}
2835
};
2936
const duplex = new Duplex({
@@ -34,7 +41,7 @@ function upToDate(parsedProject, options) {
3441
write(file, _, cb) {
3542
if (Vinyl.isVinyl(file)) {
3643
inputs.push(file);
37-
inputMap.set(file.path, file);
44+
inputMap.set(path.resolve(file.path), file);
3845
}
3946
cb();
4047
},
@@ -45,12 +52,27 @@ function upToDate(parsedProject, options) {
4552
for (const input of inputs) duplex.push(input);
4653
}
4754
duplex.push(null);
55+
inputMap.clear();
56+
statCache.clear();
4857
cb();
4958
},
5059
read() {
5160
}
5261
});
5362
return duplex;
63+
64+
function getStat(fileName) {
65+
fileName = path.resolve(fileName);
66+
const inputFile = inputMap.get(fileName);
67+
if (inputFile && inputFile.stat) return inputFile.stat;
68+
69+
let stats = statCache.get(fileName);
70+
if (!stats && fs.existsSync(fileName)) {
71+
stats = fs.statSync(fileName);
72+
statCache.set(fileName, stats);
73+
}
74+
return stats;
75+
}
5476
}
5577
module.exports = exports = upToDate;
5678

0 commit comments

Comments
 (0)