diff --git a/build/gulpfile.js b/build/gulpfile.js index d8c87ded92825..65dda505fa712 100644 --- a/build/gulpfile.js +++ b/build/gulpfile.js @@ -11,27 +11,29 @@ require('events').EventEmitter.defaultMaxListeners = 100; const gulp = require('gulp'); const util = require('./lib/util'); const task = require('./lib/task'); -const compilation = require('./lib/compilation'); +const { compileTask, watchTask, compileApiProposalNamesTask, watchApiProposalNamesTask } = require('./lib/compilation'); const { monacoTypecheckTask/* , monacoTypecheckWatchTask */ } = require('./gulpfile.editor'); const { compileExtensionsTask, watchExtensionsTask, compileExtensionMediaTask } = require('./gulpfile.extensions'); +// API proposal names +gulp.task(compileApiProposalNamesTask); +gulp.task(watchApiProposalNamesTask); + // Fast compile for development time -const compileApiProposalNames = task.define('compile-api-proposal-names', compilation.compileApiProposalNames()); -const compileClientTask = task.define('compile-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), compileApiProposalNames, compilation.compileTask('src', 'out', false))); +const compileClientTask = task.define('compile-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), compileApiProposalNamesTask, compileTask('src', 'out', false))); gulp.task(compileClientTask); -const watchApiProposalNames = task.define('watch-api-proposal-names', compilation.watchApiProposalNames()); -const watchClientTask = task.define('watch-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), task.parallel(compilation.watchTask('out', false), watchApiProposalNames))); +const watchClientTask = task.define('watch-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), task.parallel(watchTask('out', false), watchApiProposalNamesTask))); gulp.task(watchClientTask); // All -const compileTask = task.define('compile', task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask, compileExtensionMediaTask)); -gulp.task(compileTask); +const _compileTask = task.define('compile', task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask, compileExtensionMediaTask)); +gulp.task(_compileTask); gulp.task(task.define('watch', task.parallel(/* monacoTypecheckWatchTask, */ watchClientTask, watchExtensionsTask))); // Default -gulp.task('default', compileTask); +gulp.task('default', _compileTask); process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); diff --git a/build/lib/compilation.js b/build/lib/compilation.js index beb69369e15eb..5c160b7b7aac0 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); -exports.watchApiProposalNames = exports.compileApiProposalNames = exports.watchTask = exports.compileTask = void 0; +exports.watchApiProposalNamesTask = exports.compileApiProposalNamesTask = exports.watchTask = exports.compileTask = void 0; const es = require("event-stream"); const fs = require("fs"); const gulp = require("gulp"); @@ -16,6 +16,8 @@ const util = require("./util"); const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); const os = require("os"); +const File = require("vinyl"); +const task = require("./task"); const watch = require('./watch'); const reporter = (0, reporter_1.createReporter)(); function getTypeScriptCompilerOptions(src) { @@ -175,65 +177,54 @@ class MonacoGenerator { } } } -function apiProposalNamesGenerator() { - const stream = es.through(); - const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts/; - const dtsFolder = path.join(REPO_SRC_FOLDER, 'vscode-dts'); - const generateFile = () => { - try { - const t1 = Date.now(); - const proposalNames = []; - for (let file of fs.readdirSync(dtsFolder).sort()) { - const match = pattern.exec(file); - if (match) { - proposalNames.push([match[1], `https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/${file}`]); - } - } - const source = [ - '/*---------------------------------------------------------------------------------------------', - ' * Copyright (c) Microsoft Corporation. All rights reserved.', - ' * Licensed under the MIT License. See License.txt in the project root for license information.', - ' *--------------------------------------------------------------------------------------------*/', - '', - '// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.', - '', - 'export const allApiProposals = Object.freeze({', - `${proposalNames.map(t => `\t${t[0]}: '${t[1]}'`).join(`,${os.EOL}`)}`, - '});', - 'export type ApiProposalName = keyof typeof allApiProposals;', - '', - ].join(os.EOL); - const outFile = path.join(dtsFolder, '../vs/workbench/services/extensions/common/extensionsApiProposals.ts'); - if (fs.readFileSync(outFile).toString() !== source) { - fs.writeFileSync(outFile, source); - console.log(`Generated 'extensionsApiProposals.ts' in ${Date.now() - t1}ms`); - } - } - catch (err) { - stream.emit('error', err); +function generateApiProposalNames() { + const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts$/; + const proposalNames = new Set(); + const input = es.through(); + const output = input + .pipe(util.filter((f) => pattern.test(f.path))) + .pipe(es.through((f) => { + const name = path.basename(f.path); + const match = pattern.exec(name); + if (match) { + proposalNames.add(match[1]); } - }; - let handle; - stream.on('data', () => { - clearTimeout(handle); - handle = setTimeout(generateFile, 250); - }); - return stream; -} -function compileApiProposalNames() { - return function () { - const srcPipe = gulp.src('src/vscode-dts/**', { base: 'src' }); - const proposals = apiProposalNamesGenerator(); - return srcPipe.pipe(proposals); - }; -} -exports.compileApiProposalNames = compileApiProposalNames; -function watchApiProposalNames() { - return function () { - const watchSrc = watch('src/vscode-dts/**', { base: 'src', readDelay: 200 }); - const proposals = apiProposalNamesGenerator(); - proposals.write(undefined); // send something to trigger initial generate - return watchSrc.pipe(proposals); - }; + }, function () { + const names = [...proposalNames.values()].sort(); + const contents = [ + '/*---------------------------------------------------------------------------------------------', + ' * Copyright (c) Microsoft Corporation. All rights reserved.', + ' * Licensed under the MIT License. See License.txt in the project root for license information.', + ' *--------------------------------------------------------------------------------------------*/', + '', + '// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.', + '', + 'export const allApiProposals = Object.freeze({', + `${names.map(name => `\t${name}: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.${name}.d.ts'`).join(`,${os.EOL}`)}`, + '});', + 'export type ApiProposalName = keyof typeof allApiProposals;', + '', + ].join(os.EOL); + this.emit('data', new File({ + path: 'vs/workbench/services/extensions/common/extensionsApiProposals.ts', + contents: Buffer.from(contents) + })); + this.emit('end'); + })); + return es.duplex(input, output); } -exports.watchApiProposalNames = watchApiProposalNames; +const apiProposalNamesReporter = (0, reporter_1.createReporter)('api-proposal-names'); +exports.compileApiProposalNamesTask = task.define('compile-api-proposal-names', () => { + return gulp.src('src/vscode-dts/**') + .pipe(generateApiProposalNames()) + .pipe(gulp.dest('src')) + .pipe(apiProposalNamesReporter.end(true)); +}); +exports.watchApiProposalNamesTask = task.define('watch-api-proposal-names', () => { + const task = () => gulp.src('src/vscode-dts/**') + .pipe(generateApiProposalNames()) + .pipe(apiProposalNamesReporter.end(true)); + return watch('src/vscode-dts/**', { readDelay: 200 }) + .pipe(util.debounce(task)) + .pipe(gulp.dest('src')); +}); diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index 73e54fc982669..a4c8441effc17 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -17,6 +17,8 @@ import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; import * as os from 'os'; import ts = require('typescript'); +import * as File from 'vinyl'; +import * as task from './task'; const watch = require('./watch'); @@ -212,26 +214,23 @@ class MonacoGenerator { } } -function apiProposalNamesGenerator() { - const stream = es.through(); +function generateApiProposalNames() { + const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts$/; + const proposalNames = new Set(); - const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts/; - const dtsFolder = path.join(REPO_SRC_FOLDER, 'vscode-dts'); + const input = es.through(); + const output = input + .pipe(util.filter((f: File) => pattern.test(f.path))) + .pipe(es.through((f: File) => { + const name = path.basename(f.path); + const match = pattern.exec(name); - const generateFile = () => { - - try { - - const t1 = Date.now(); - const proposalNames: [name: string, url: string][] = []; - for (let file of fs.readdirSync(dtsFolder).sort()) { - const match = pattern.exec(file); - if (match) { - proposalNames.push([match[1], `https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/${file}`]); - } + if (match) { + proposalNames.add(match[1]); } - - const source = [ + }, function () { + const names = [...proposalNames.values()].sort(); + const contents = [ '/*---------------------------------------------------------------------------------------------', ' * Copyright (c) Microsoft Corporation. All rights reserved.', ' * Licensed under the MIT License. See License.txt in the project root for license information.', @@ -240,46 +239,37 @@ function apiProposalNamesGenerator() { '// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.', '', 'export const allApiProposals = Object.freeze({', - `${proposalNames.map(t => `\t${t[0]}: '${t[1]}'`).join(`,${os.EOL}`)}`, + `${names.map(name => `\t${name}: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.${name}.d.ts'`).join(`,${os.EOL}`)}`, '});', 'export type ApiProposalName = keyof typeof allApiProposals;', '', ].join(os.EOL); - const outFile = path.join(dtsFolder, '../vs/workbench/services/extensions/common/extensionsApiProposals.ts'); + this.emit('data', new File({ + path: 'vs/workbench/services/extensions/common/extensionsApiProposals.ts', + contents: Buffer.from(contents) + })); + this.emit('end'); + })); - if (fs.readFileSync(outFile).toString() !== source) { - fs.writeFileSync(outFile, source); - console.log(`Generated 'extensionsApiProposals.ts' in ${Date.now() - t1}ms`); - } + return es.duplex(input, output); +} - } catch (err) { - stream.emit('error', err); - } - }; +const apiProposalNamesReporter = createReporter('api-proposal-names'); - let handle: NodeJS.Timeout; - stream.on('data', () => { - clearTimeout(handle); - handle = setTimeout(generateFile, 250); - }); +export const compileApiProposalNamesTask = task.define('compile-api-proposal-names', () => { + return gulp.src('src/vscode-dts/**') + .pipe(generateApiProposalNames()) + .pipe(gulp.dest('src')) + .pipe(apiProposalNamesReporter.end(true)); +}); - return stream; -} +export const watchApiProposalNamesTask = task.define('watch-api-proposal-names', () => { + const task = () => gulp.src('src/vscode-dts/**') + .pipe(generateApiProposalNames()) + .pipe(apiProposalNamesReporter.end(true)); -export function compileApiProposalNames(): () => NodeJS.ReadWriteStream { - return function () { - const srcPipe = gulp.src('src/vscode-dts/**', { base: 'src' }); - const proposals = apiProposalNamesGenerator(); - return srcPipe.pipe(proposals); - }; -} - -export function watchApiProposalNames(): () => NodeJS.ReadWriteStream { - return function () { - const watchSrc = watch('src/vscode-dts/**', { base: 'src', readDelay: 200 }); - const proposals = apiProposalNamesGenerator(); - proposals.write(undefined); // send something to trigger initial generate - return watchSrc.pipe(proposals); - }; -} + return watch('src/vscode-dts/**', { readDelay: 200 }) + .pipe(util.debounce(task)) + .pipe(gulp.dest('src')); +}); diff --git a/build/lib/util.js b/build/lib/util.js index 3e15bd5e42261..9effd6a0f22ef 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.getVersion = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.incremental = void 0; +exports.buildWebNodePaths = exports.createExternalLoaderConfig = exports.acquireWebNodePaths = exports.getElectronVersion = exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.getVersion = exports.ensureDir = exports.rreddir = exports.rimraf = exports.rewriteSourceMappingURL = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.debounce = exports.incremental = void 0; const es = require("event-stream"); -const debounce = require("debounce"); +const _debounce = require("debounce"); const _filter = require("gulp-filter"); const rename = require("gulp-rename"); const path = require("path"); @@ -36,7 +36,7 @@ function incremental(streamProvider, initial, supportsCancellation) { if (initial) { run(initial, false); } - const eventuallyRun = debounce(() => { + const eventuallyRun = _debounce(() => { const paths = Object.keys(buffer); if (paths.length === 0) { return; @@ -54,6 +54,35 @@ function incremental(streamProvider, initial, supportsCancellation) { return es.duplex(input, output); } exports.incremental = incremental; +function debounce(task) { + const input = es.through(); + const output = es.through(); + let state = 'idle'; + const run = () => { + state = 'running'; + task() + .pipe(es.through(undefined, () => { + const shouldRunAgain = state === 'stale'; + state = 'idle'; + if (shouldRunAgain) { + eventuallyRun(); + } + })) + .pipe(output); + }; + run(); + const eventuallyRun = _debounce(() => run(), 500); + input.on('data', () => { + if (state === 'idle') { + eventuallyRun(); + } + else { + state = 'stale'; + } + }); + return es.duplex(input, output); +} +exports.debounce = debounce; function fixWin32DirectoryPermissions() { if (!/win32/.test(process.platform)) { return es.through(); diff --git a/build/lib/util.ts b/build/lib/util.ts index 585479d3ab21d..229fffd425c7e 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -6,7 +6,7 @@ 'use strict'; import * as es from 'event-stream'; -import debounce = require('debounce'); +import _debounce = require('debounce'); import * as _filter from 'gulp-filter'; import * as rename from 'gulp-rename'; import * as _ from 'underscore'; @@ -56,7 +56,7 @@ export function incremental(streamProvider: IStreamProvider, initial: NodeJS.Rea run(initial, false); } - const eventuallyRun = debounce(() => { + const eventuallyRun = _debounce(() => { const paths = Object.keys(buffer); if (paths.length === 0) { @@ -79,6 +79,41 @@ export function incremental(streamProvider: IStreamProvider, initial: NodeJS.Rea return es.duplex(input, output); } +export function debounce(task: () => NodeJS.ReadWriteStream): NodeJS.ReadWriteStream { + const input = es.through(); + const output = es.through(); + let state = 'idle'; + + const run = () => { + state = 'running'; + + task() + .pipe(es.through(undefined, () => { + const shouldRunAgain = state === 'stale'; + state = 'idle'; + + if (shouldRunAgain) { + eventuallyRun(); + } + })) + .pipe(output); + }; + + run(); + + const eventuallyRun = _debounce(() => run(), 500); + + input.on('data', () => { + if (state === 'idle') { + eventuallyRun(); + } else { + state = 'stale'; + } + }); + + return es.duplex(input, output); +} + export function fixWin32DirectoryPermissions(): NodeJS.ReadWriteStream { if (!/win32/.test(process.platform)) { return es.through();