提交 238440b7 编写于 作者: A Alex Dima

Change how monaco.d.ts is generated:

- do not use the .d.ts files coming in from gulp-tsb
- remove the generation of .d.ts files
- run before compilation starts
- install file watchers directly
上级 48adb204
......@@ -11,11 +11,13 @@ const bom = require("gulp-bom");
const sourcemaps = require("gulp-sourcemaps");
const tsb = require("gulp-tsb");
const path = require("path");
const ts = require("typescript");
const _ = require("underscore");
const monacodts = require("../monaco/api");
const nls = require("./nls");
const reporter_1 = require("./reporter");
const util = require("./util");
const util2 = require("gulp-util");
const watch = require('./watch');
const reporter = reporter_1.createReporter();
function getTypeScriptCompilerOptions(src) {
......@@ -79,14 +81,15 @@ function compileTask(src, out, build) {
return function () {
const compile = createCompile(src, build, true);
const srcPipe = es.merge(gulp.src(`${src}/**`, { base: `${src}` }), gulp.src(typesDts));
// Do not write .d.ts files to disk, as they are not needed there.
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
let generator = new MonacoGenerator(false);
if (src === 'src') {
generator.execute();
}
return srcPipe
.pipe(generator.stream)
.pipe(compile())
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(src !== 'src' ? es.through() : monacodtsTask(out, false));
.pipe(gulp.dest(out));
// .pipe(src !== 'src' ? es.through() : monacodtsTask(out, false));
};
}
exports.compileTask = compileTask;
......@@ -95,67 +98,116 @@ function watchTask(out, build) {
const compile = createCompile('src', build);
const src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src(typesDts));
const watchSrc = watch('src/**', { base: 'src' });
// Do not write .d.ts files to disk, as they are not needed there.
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
let generator = new MonacoGenerator(true);
generator.execute();
return watchSrc
.pipe(generator.stream)
.pipe(util.incremental(compile, src, true))
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, true));
.pipe(gulp.dest(out));
};
}
exports.watchTask = watchTask;
function monacodtsTask(out, isWatch) {
const basePath = path.resolve(process.cwd(), out);
const neededFiles = {};
monacodts.getFilesToWatch(out).forEach(function (filePath) {
filePath = path.normalize(filePath);
neededFiles[filePath] = true;
});
const inputFiles = {};
for (const filePath in neededFiles) {
if (/\bsrc(\/|\\)vs\b/.test(filePath)) {
// This file is needed from source => simply read it now
inputFiles[filePath] = fs.readFileSync(filePath).toString();
const REPO_SRC_FOLDER = path.join(__dirname, '../../src');
class MonacoGenerator {
constructor(isWatch) {
this._isWatch = isWatch;
this.stream = es.through();
this._inputFiles = monacodts.getIncludesInRecipe().map((moduleId) => {
if (/\.d\.ts$/.test(moduleId)) {
// This source file is already in .d.ts form
return path.join(REPO_SRC_FOLDER, moduleId);
}
else {
return path.join(REPO_SRC_FOLDER, `${moduleId}.ts`);
}
});
// Install watchers
this._watchers = [];
if (this._isWatch) {
this._inputFiles.forEach((filePath) => {
const watcher = fs.watch(filePath);
watcher.addListener('change', () => {
this._inputFileChanged[filePath] = true;
// Avoid hitting empty files... :/
setTimeout(() => this.execute(), 10);
});
this._watchers.push(watcher);
});
const recipeWatcher = fs.watch(monacodts.RECIPE_PATH);
recipeWatcher.addListener('change', () => {
this._recipeFileChanged = true;
// Avoid hitting empty files... :/
setTimeout(() => this.execute(), 10);
});
this._watchers.push(recipeWatcher);
}
this._inputFileChanged = {};
this._inputFiles.forEach(file => this._inputFileChanged[file] = true);
this._recipeFileChanged = true;
this._dtsFilesContents = {};
}
const setInputFile = (filePath, contents) => {
if (inputFiles[filePath] === contents) {
// no change
return;
}
inputFiles[filePath] = contents;
const neededInputFilesCount = Object.keys(neededFiles).length;
const availableInputFilesCount = Object.keys(inputFiles).length;
if (neededInputFilesCount === availableInputFilesCount) {
run();
}
};
const run = () => {
const result = monacodts.run(out, inputFiles);
if (!result.isTheSame) {
if (isWatch) {
fs.writeFileSync(result.filePath, result.content);
dispose() {
this._watchers.forEach(watcher => watcher.close());
}
_run() {
let somethingChanged = false;
const setDTSFileContent = (file, contents) => {
if (this._dtsFilesContents[file] === contents) {
return;
}
else {
fs.writeFileSync(result.filePath, result.content);
resultStream.emit('error', 'monaco.d.ts is no longer up to date. Please run gulp watch and commit the new file.');
this._dtsFilesContents[file] = contents;
somethingChanged = true;
};
const fileMap = {};
this._inputFiles.forEach((inputFile) => {
if (!this._inputFileChanged[inputFile]) {
return;
}
this._inputFileChanged[inputFile] = false;
const inputFileContents = fs.readFileSync(inputFile).toString();
if (/\.d\.ts$/.test(inputFile)) {
// This is a .d.ts file
setDTSFileContent(inputFile, inputFileContents);
return;
}
fileMap[inputFile] = inputFileContents;
});
if (Object.keys(fileMap).length > 0) {
const service = ts.createLanguageService(new monacodts.TypeScriptLanguageServiceHost({}, fileMap, {}));
Object.keys(fileMap).forEach((fileName) => {
const output = service.getEmitOutput(fileName, true).outputFiles[0].text;
const destFileName = fileName.replace(/\.ts$/, '.d.ts');
setDTSFileContent(destFileName, output);
});
}
};
let resultStream;
if (isWatch) {
watch('build/monaco/*').pipe(es.through(function () {
run();
}));
if (this._recipeFileChanged) {
this._recipeFileChanged = false;
somethingChanged = true;
}
if (!somethingChanged) {
// Nothing changed
return null;
}
return monacodts.run('src', this._dtsFilesContents);
}
_log(message, ...rest) {
util2.log(util2.colors.cyan('[monaco.d.ts]'), message, ...rest);
}
resultStream = es.through(function (data) {
const filePath = path.normalize(path.resolve(basePath, data.relative));
if (neededFiles[filePath]) {
setInputFile(filePath, data.contents.toString());
execute() {
const startTime = Date.now();
const result = this._run();
if (!result) {
// nothing really changed
return;
}
if (result.isTheSame) {
this._log(`monaco.d.ts is unchanged - total time took ${Date.now() - startTime} ms`);
return;
}
this.emit('data', data);
});
return resultStream;
fs.writeFileSync(result.filePath, result.content);
this._log(`monaco.d.ts is changed - total time took ${Date.now() - startTime} ms`);
if (!this._isWatch) {
this.stream.emit('error', 'monaco.d.ts is no longer up to date. Please run gulp watch and commit the new file.');
}
}
}
......@@ -12,11 +12,13 @@ import * as bom from 'gulp-bom';
import * as sourcemaps from 'gulp-sourcemaps';
import * as tsb from 'gulp-tsb';
import * as path from 'path';
import * as ts from 'typescript';
import * as _ from 'underscore';
import * as monacodts from '../monaco/api';
import * as nls from './nls';
import { createReporter } from './reporter';
import * as util from './util';
import * as util2 from 'gulp-util';
const watch = require('./watch');
const reporter = createReporter();
......@@ -95,15 +97,16 @@ export function compileTask(src: string, out: string, build: boolean): () => Nod
gulp.src(typesDts),
);
// Do not write .d.ts files to disk, as they are not needed there.
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
let generator = new MonacoGenerator(false);
if (src === 'src') {
generator.execute();
}
return srcPipe
.pipe(generator.stream)
.pipe(compile())
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(src !== 'src' ? es.through() : monacodtsTask(out, false));
.pipe(gulp.dest(out));
// .pipe(src !== 'src' ? es.through() : monacodtsTask(out, false));
};
}
......@@ -118,76 +121,148 @@ export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteSt
);
const watchSrc = watch('src/**', { base: 'src' });
// Do not write .d.ts files to disk, as they are not needed there.
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
let generator = new MonacoGenerator(true);
generator.execute();
return watchSrc
.pipe(generator.stream)
.pipe(util.incremental(compile, src, true))
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, true));
.pipe(gulp.dest(out));
};
}
function monacodtsTask(out: string, isWatch: boolean): NodeJS.ReadWriteStream {
const REPO_SRC_FOLDER = path.join(__dirname, '../../src');
class MonacoGenerator {
private readonly _isWatch: boolean;
public readonly stream: NodeJS.ReadWriteStream;
/**
* This list is never changed for the lifetime of this object.
*/
private readonly _inputFiles: string[];
private readonly _watchers: fs.FSWatcher[];
private _inputFileChanged: { [filePath: string]: boolean; };
private _recipeFileChanged: boolean;
private _dtsFilesContents: { [filePath: string]: string; };
const basePath = path.resolve(process.cwd(), out);
constructor(isWatch: boolean) {
this._isWatch = isWatch;
this.stream = es.through();
this._inputFiles = monacodts.getIncludesInRecipe().map((moduleId) => {
if (/\.d\.ts$/.test(moduleId)) {
// This source file is already in .d.ts form
return path.join(REPO_SRC_FOLDER, moduleId);
} else {
return path.join(REPO_SRC_FOLDER, `${moduleId}.ts`);
}
});
const neededFiles: { [file: string]: boolean; } = {};
monacodts.getFilesToWatch(out).forEach(function (filePath) {
filePath = path.normalize(filePath);
neededFiles[filePath] = true;
});
// Install watchers
this._watchers = [];
if (this._isWatch) {
this._inputFiles.forEach((filePath) => {
const watcher = fs.watch(filePath);
watcher.addListener('change', () => {
this._inputFileChanged[filePath] = true;
// Avoid hitting empty files... :/
setTimeout(() => this.execute(), 10);
});
this._watchers.push(watcher);
});
const inputFiles: { [file: string]: string; } = {};
for (const filePath in neededFiles) {
if (/\bsrc(\/|\\)vs\b/.test(filePath)) {
// This file is needed from source => simply read it now
inputFiles[filePath] = fs.readFileSync(filePath).toString();
const recipeWatcher = fs.watch(monacodts.RECIPE_PATH);
recipeWatcher.addListener('change', () => {
this._recipeFileChanged = true;
// Avoid hitting empty files... :/
setTimeout(() => this.execute(), 10);
});
this._watchers.push(recipeWatcher);
}
this._inputFileChanged = {};
this._inputFiles.forEach(file => this._inputFileChanged[file] = true);
this._recipeFileChanged = true;
this._dtsFilesContents = {};
}
const setInputFile = (filePath: string, contents: string) => {
if (inputFiles[filePath] === contents) {
// no change
return;
public dispose(): void {
this._watchers.forEach(watcher => watcher.close());
}
private _run(): monacodts.IMonacoDeclarationResult | null {
let somethingChanged = false;
const setDTSFileContent = (file: string, contents: string): void => {
if (this._dtsFilesContents[file] === contents) {
return;
}
this._dtsFilesContents[file] = contents;
somethingChanged = true;
};
const fileMap: { [fileName: string]: string; } = {};
this._inputFiles.forEach((inputFile) => {
if (!this._inputFileChanged[inputFile]) {
return;
}
this._inputFileChanged[inputFile] = false;
const inputFileContents = fs.readFileSync(inputFile).toString();
if (/\.d\.ts$/.test(inputFile)) {
// This is a .d.ts file
setDTSFileContent(inputFile, inputFileContents);
return;
}
fileMap[inputFile] = inputFileContents;
});
if (Object.keys(fileMap).length > 0) {
const service = ts.createLanguageService(new monacodts.TypeScriptLanguageServiceHost({}, fileMap, {}));
Object.keys(fileMap).forEach((fileName) => {
const output = service.getEmitOutput(fileName, true).outputFiles[0].text;
const destFileName = fileName.replace(/\.ts$/, '.d.ts');
setDTSFileContent(destFileName, output);
});
}
inputFiles[filePath] = contents;
const neededInputFilesCount = Object.keys(neededFiles).length;
const availableInputFilesCount = Object.keys(inputFiles).length;
if (neededInputFilesCount === availableInputFilesCount) {
run();
if (this._recipeFileChanged) {
this._recipeFileChanged = false;
somethingChanged = true;
}
};
const run = () => {
const result = monacodts.run(out, inputFiles);
if (!result.isTheSame) {
if (isWatch) {
fs.writeFileSync(result.filePath, result.content);
} else {
fs.writeFileSync(result.filePath, result.content);
resultStream.emit('error', 'monaco.d.ts is no longer up to date. Please run gulp watch and commit the new file.');
}
if (!somethingChanged) {
// Nothing changed
return null;
}
};
let resultStream: NodeJS.ReadWriteStream;
return monacodts.run('src', this._dtsFilesContents);
}
if (isWatch) {
watch('build/monaco/*').pipe(es.through(function () {
run();
}));
private _log(message: any, ...rest: any[]): void {
util2.log(util2.colors.cyan('[monaco.d.ts]'), message, ...rest);
}
resultStream = es.through(function (data) {
const filePath = path.normalize(path.resolve(basePath, data.relative));
if (neededFiles[filePath]) {
setInputFile(filePath, data.contents.toString());
public execute(): void {
const startTime = Date.now();
const result = this._run();
if (!result) {
// nothing really changed
return;
}
if (result.isTheSame) {
this._log(`monaco.d.ts is unchanged - total time took ${Date.now() - startTime} ms`);
return;
}
this.emit('data', data);
});
return resultStream;
fs.writeFileSync(result.filePath, result.content);
this._log(`monaco.d.ts is changed - total time took ${Date.now() - startTime} ms`);
if (!this._isWatch) {
this.stream.emit('error', 'monaco.d.ts is no longer up to date. Please run gulp watch and commit the new file.');
}
}
}
......@@ -14,7 +14,7 @@ function log(message, ...rest) {
}
const SRC = path.join(__dirname, '../../src');
const OUT_ROOT = path.join(__dirname, '../../');
const RECIPE_PATH = path.join(__dirname, './monaco.d.ts.recipe');
exports.RECIPE_PATH = path.join(__dirname, './monaco.d.ts.recipe');
const DECLARATION_PATH = path.join(__dirname, '../../src/vs/monaco.d.ts');
var CURRENT_PROCESSING_RULE = '';
function logErr(message, ...rest) {
......@@ -314,7 +314,7 @@ function generateDeclarationFile(out, inputFiles, recipe) {
];
}
function getIncludesInRecipe() {
let recipe = fs.readFileSync(RECIPE_PATH).toString();
let recipe = fs.readFileSync(exports.RECIPE_PATH).toString();
let lines = recipe.split(/\r\n|\n|\r/);
let result = [];
lines.forEach(line => {
......@@ -333,6 +333,7 @@ function getIncludesInRecipe() {
});
return result;
}
exports.getIncludesInRecipe = getIncludesInRecipe;
function getFilesToWatch(out) {
return getIncludesInRecipe().map((moduleId) => moduleIdToPath(out, moduleId));
}
......@@ -340,7 +341,7 @@ exports.getFilesToWatch = getFilesToWatch;
function run(out, inputFiles) {
log('Starting monaco.d.ts generation');
SOURCE_FILE_MAP = {};
let recipe = fs.readFileSync(RECIPE_PATH).toString();
let recipe = fs.readFileSync(exports.RECIPE_PATH).toString();
let [result, usageContent] = generateDeclarationFile(out, inputFiles, recipe);
let currentContent = fs.readFileSync(DECLARATION_PATH).toString();
log('Finished monaco.d.ts generation');
......@@ -404,6 +405,7 @@ class TypeScriptLanguageServiceHost {
return fileName === this.getDefaultLibFileName(this._compilerOptions);
}
}
exports.TypeScriptLanguageServiceHost = TypeScriptLanguageServiceHost;
function execute() {
const OUTPUT_FILES = {};
const SRC_FILES = {};
......
......@@ -16,7 +16,7 @@ function log(message: any, ...rest: any[]): void {
const SRC = path.join(__dirname, '../../src');
const OUT_ROOT = path.join(__dirname, '../../');
const RECIPE_PATH = path.join(__dirname, './monaco.d.ts.recipe');
export const RECIPE_PATH = path.join(__dirname, './monaco.d.ts.recipe');
const DECLARATION_PATH = path.join(__dirname, '../../src/vs/monaco.d.ts');
var CURRENT_PROCESSING_RULE = '';
......@@ -375,7 +375,7 @@ function generateDeclarationFile(out: string, inputFiles: { [file: string]: stri
];
}
function getIncludesInRecipe(): string[] {
export function getIncludesInRecipe(): string[] {
let recipe = fs.readFileSync(RECIPE_PATH).toString();
let lines = recipe.split(/\r\n|\n|\r/);
let result: string[] = [];
......@@ -442,7 +442,7 @@ export function complainErrors() {
interface ILibMap { [libName: string]: string; }
interface IFileMap { [fileName: string]: string; }
class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost {
export class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost {
private readonly _libs: ILibMap;
private readonly _files: IFileMap;
......
......@@ -4,7 +4,6 @@
"removeComments": false,
"preserveConstEnums": true,
"sourceMap": false,
"declaration": true,
"outDir": "../out"
},
"include": [
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册