mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-15 07:28:05 +00:00
Merge pull request #292461 from microsoft/dev/mjbvz/ext-ts-go
Use ts-go for building our extensions
This commit is contained in:
@@ -7,21 +7,22 @@
|
||||
import { EventEmitter } from 'events';
|
||||
EventEmitter.defaultMaxListeners = 100;
|
||||
|
||||
import es from 'event-stream';
|
||||
import glob from 'glob';
|
||||
import gulp from 'gulp';
|
||||
import filter from 'gulp-filter';
|
||||
import plumber from 'gulp-plumber';
|
||||
import sourcemaps from 'gulp-sourcemaps';
|
||||
import * as path from 'path';
|
||||
import * as nodeUtil from 'util';
|
||||
import es from 'event-stream';
|
||||
import filter from 'gulp-filter';
|
||||
import * as util from './lib/util.ts';
|
||||
import { getVersion } from './lib/getVersion.ts';
|
||||
import * as task from './lib/task.ts';
|
||||
import watcher from './lib/watch/index.ts';
|
||||
import { createReporter } from './lib/reporter.ts';
|
||||
import glob from 'glob';
|
||||
import plumber from 'gulp-plumber';
|
||||
import * as ext from './lib/extensions.ts';
|
||||
import { getVersion } from './lib/getVersion.ts';
|
||||
import { createReporter } from './lib/reporter.ts';
|
||||
import * as task from './lib/task.ts';
|
||||
import * as tsb from './lib/tsb/index.ts';
|
||||
import sourcemaps from 'gulp-sourcemaps';
|
||||
import { createTsgoStream, spawnTsgo } from './lib/tsgo.ts';
|
||||
import * as util from './lib/util.ts';
|
||||
import watcher from './lib/watch/index.ts';
|
||||
|
||||
const root = path.dirname(import.meta.dirname);
|
||||
const commit = getVersion(root);
|
||||
@@ -150,25 +151,22 @@ const tasks = compilations.map(function (tsconfigFile) {
|
||||
.pipe(gulp.dest(out));
|
||||
}));
|
||||
|
||||
const compileTask = task.define(`compile-extension:${name}`, task.series(cleanTask, () => {
|
||||
const pipeline = createPipeline(false, true);
|
||||
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts']));
|
||||
const input = es.merge(nonts, pipeline.tsProjectSrc());
|
||||
const compileTask = task.define(`compile-extension:${name}`, task.series(cleanTask, async () => {
|
||||
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts'], { dot: true }));
|
||||
const copyNonTs = util.streamToPromise(nonts.pipe(gulp.dest(out)));
|
||||
const tsgo = spawnTsgo(absolutePath);
|
||||
|
||||
return input
|
||||
.pipe(pipeline())
|
||||
.pipe(gulp.dest(out));
|
||||
await Promise.all([copyNonTs, tsgo]);
|
||||
}));
|
||||
|
||||
const watchTask = task.define(`watch-extension:${name}`, task.series(cleanTask, () => {
|
||||
const pipeline = createPipeline(false);
|
||||
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts']));
|
||||
const input = es.merge(nonts, pipeline.tsProjectSrc());
|
||||
const nonts = gulp.src(src, srcOpts).pipe(filter(['**', '!**/*.ts'], { dot: true }));
|
||||
const watchInput = watcher(src, { ...srcOpts, ...{ readDelay: 200 } });
|
||||
const watchNonTs = watchInput.pipe(filter(['**', '!**/*.ts'], { dot: true })).pipe(gulp.dest(out));
|
||||
const tsgoStream = watchInput.pipe(util.debounce(() => createTsgoStream(absolutePath), 200));
|
||||
const watchStream = es.merge(nonts.pipe(gulp.dest(out)), watchNonTs, tsgoStream);
|
||||
|
||||
return watchInput
|
||||
.pipe(util.incremental(pipeline, input))
|
||||
.pipe(gulp.dest(out));
|
||||
return watchStream;
|
||||
}));
|
||||
|
||||
// Tasks
|
||||
|
||||
116
build/lib/tsgo.ts
Normal file
116
build/lib/tsgo.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import es from 'event-stream';
|
||||
import * as path from 'path';
|
||||
import { createReporter } from './reporter.ts';
|
||||
|
||||
const root = path.dirname(path.dirname(import.meta.dirname));
|
||||
const npx = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
||||
const ansiRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
||||
|
||||
export function spawnTsgo(projectPath: string): Promise<void> {
|
||||
const reporter = createReporter('extensions');
|
||||
let report: NodeJS.ReadWriteStream | undefined;
|
||||
|
||||
const beginReport = (emitError: boolean) => {
|
||||
if (report) {
|
||||
report.end();
|
||||
}
|
||||
report = reporter.end(emitError);
|
||||
};
|
||||
|
||||
const endReport = () => {
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
report.end();
|
||||
report = undefined;
|
||||
};
|
||||
|
||||
const args = ['tsgo', '--project', projectPath, '--pretty', 'false'];
|
||||
|
||||
beginReport(false);
|
||||
|
||||
const child = cp.spawn(npx, args, {
|
||||
cwd: root,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
shell: true
|
||||
});
|
||||
|
||||
let buffer = '';
|
||||
const handleLine = (line: string) => {
|
||||
const trimmed = line.replace(ansiRegex, '').trim();
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
if (/Starting compilation|File change detected/i.test(trimmed)) {
|
||||
beginReport(false);
|
||||
return;
|
||||
}
|
||||
if (/Compilation complete/i.test(trimmed)) {
|
||||
endReport();
|
||||
return;
|
||||
}
|
||||
|
||||
const match = /(.*\(\d+,\d+\): )(.*: )(.*)/.exec(trimmed);
|
||||
|
||||
if (match) {
|
||||
const fullpath = path.isAbsolute(match[1]) ? match[1] : path.join(root, match[1]);
|
||||
const message = match[3];
|
||||
reporter(fullpath + message);
|
||||
} else {
|
||||
reporter(trimmed);
|
||||
}
|
||||
};
|
||||
|
||||
const handleData = (data: Buffer) => {
|
||||
buffer += data.toString('utf8');
|
||||
const lines = buffer.split(/\r?\n/);
|
||||
buffer = lines.pop() ?? '';
|
||||
for (const line of lines) {
|
||||
handleLine(line);
|
||||
}
|
||||
};
|
||||
|
||||
child.stdout?.on('data', handleData);
|
||||
child.stderr?.on('data', handleData);
|
||||
|
||||
const done = new Promise<void>((resolve, reject) => {
|
||||
child.on('exit', code => {
|
||||
if (buffer.trim()) {
|
||||
handleLine(buffer);
|
||||
buffer = '';
|
||||
}
|
||||
endReport();
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
reject(new Error(`tsgo exited with code ${code ?? 'unknown'}`));
|
||||
});
|
||||
child.on('error', err => {
|
||||
endReport();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
export function createTsgoStream(projectPath: string): NodeJS.ReadWriteStream {
|
||||
const stream = es.through();
|
||||
|
||||
spawnTsgo(projectPath).then(() => {
|
||||
stream.emit('end');
|
||||
}).catch(() => {
|
||||
// Errors are already reported by spawnTsgo via the reporter.
|
||||
// Don't emit 'error' on the stream as that would exit the watch process.
|
||||
stream.emit('end');
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
@@ -47,11 +47,11 @@ function _throttle<T>(fn: Function, key: string): Function {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
function decorate(decorator: (fn: Function, key: string) => Function): Function {
|
||||
return function (original: any, context: ClassMethodDecoratorContext) {
|
||||
if (context.kind !== 'method') {
|
||||
function decorate(decorator: (fn: Function, key: string) => Function): MethodDecorator {
|
||||
return (_target: any, key: string | symbol, descriptor: PropertyDescriptor): void => {
|
||||
if (typeof descriptor.value !== 'function') {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
return decorator(original, context.name.toString());
|
||||
descriptor.value = decorator(descriptor.value, String(key));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ import { ApiRepository, ApiImpl } from './api1';
|
||||
import { Event, EventEmitter } from 'vscode';
|
||||
import { CloneManager } from '../cloneManager';
|
||||
|
||||
function deprecated(original: unknown, context: ClassMemberDecoratorContext) {
|
||||
if (typeof original !== 'function' || context.kind !== 'method') {
|
||||
function deprecated(_target: unknown, key: string | symbol, descriptor: PropertyDescriptor): void {
|
||||
if (typeof descriptor.value !== 'function') {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
|
||||
const key = context.name.toString();
|
||||
return function (this: unknown, ...args: unknown[]) {
|
||||
console.warn(`Git extension API method '${key}' is deprecated.`);
|
||||
const original = descriptor.value;
|
||||
descriptor.value = function (this: unknown, ...args: unknown[]) {
|
||||
console.warn(`Git extension API method '${String(key)}' is deprecated.`);
|
||||
return original.apply(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -372,13 +372,12 @@ interface ScmCommand {
|
||||
|
||||
const Commands: ScmCommand[] = [];
|
||||
|
||||
function command(commandId: string, options: ScmCommandOptions = {}): Function {
|
||||
return (value: unknown, context: ClassMethodDecoratorContext) => {
|
||||
if (typeof value !== 'function' || context.kind !== 'method') {
|
||||
function command(commandId: string, options: ScmCommandOptions = {}): MethodDecorator {
|
||||
return (_target: any, key: string | symbol, descriptor: PropertyDescriptor): void => {
|
||||
if (typeof descriptor.value !== 'function') {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
const key = context.name.toString();
|
||||
Commands.push({ commandId, key, method: value, options });
|
||||
Commands.push({ commandId, key: String(key), method: descriptor.value, options });
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,14 @@
|
||||
import { done } from './util';
|
||||
|
||||
function decorate(decorator: (fn: Function, key: string) => Function): Function {
|
||||
return function (original: unknown, context: ClassMethodDecoratorContext) {
|
||||
if (typeof original === 'function' && (context.kind === 'method' || context.kind === 'getter' || context.kind === 'setter')) {
|
||||
return decorator(original, context.name.toString());
|
||||
return (_target: any, key: string, descriptor: PropertyDescriptor): void => {
|
||||
if (typeof descriptor.value === 'function') {
|
||||
descriptor.value = decorator(descriptor.value, key);
|
||||
} else if (typeof descriptor.get === 'function') {
|
||||
descriptor.get = decorator(descriptor.get, key) as () => any;
|
||||
} else {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
throw new Error('not supported');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -85,5 +88,5 @@ export function debounce(delay: number): Function {
|
||||
clearTimeout(this[timerKey]);
|
||||
this[timerKey] = setTimeout(() => fn.apply(this, args), delay);
|
||||
};
|
||||
});
|
||||
}) as MethodDecorator;
|
||||
}
|
||||
|
||||
@@ -24,11 +24,14 @@ export class DisposableStore {
|
||||
}
|
||||
|
||||
function decorate(decorator: (fn: Function, key: string) => Function): Function {
|
||||
return function (original: any, context: ClassMethodDecoratorContext) {
|
||||
if (context.kind === 'method' || context.kind === 'getter' || context.kind === 'setter') {
|
||||
return decorator(original, context.name.toString());
|
||||
return (_target: any, key: string, descriptor: PropertyDescriptor): void => {
|
||||
if (typeof descriptor.value === 'function') {
|
||||
descriptor.value = decorator(descriptor.value, key);
|
||||
} else if (typeof descriptor.get === 'function') {
|
||||
descriptor.get = decorator(descriptor.get, key) as () => any;
|
||||
} else {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
throw new Error('not supported');
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
]
|
||||
],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"noImplicitOverride": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"experimentalDecorators": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user