From 9deb8d4a42a329d015858dcb827371eea02bdf9d Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 24 Oct 2018 15:56:37 +0200 Subject: [PATCH] Read monaco.d.ts.recipe files as needed (don't prepare them up front) --- build/lib/compilation.js | 93 +++++------------- build/lib/compilation.ts | 119 ++++++----------------- build/monaco/api.js | 148 +++++++++++----------------- build/monaco/api.ts | 165 ++++++++++++-------------------- build/monaco/monaco.d.ts.recipe | 2 +- src/vs/monaco.d.ts | 2 +- 6 files changed, 175 insertions(+), 354 deletions(-) diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 371107d401a..8164f4aaff0 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -11,7 +11,6 @@ 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"); @@ -112,43 +111,42 @@ class MonacoGenerator { this._executeSoonTimer = null; 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); + this._watchers = []; + this._watchedFiles = {}; + let onWillReadFile = (moduleId, filePath) => { + if (!this._isWatch) { + return; } - else { - return path.join(REPO_SRC_FOLDER, `${moduleId}.ts`); + if (this._watchedFiles[filePath]) { + return; } - }); - // Install watchers - this._watchers = []; - if (this._isWatch) { - this._inputFiles.forEach((filePath) => { - const watcher = fs.watch(filePath); - watcher.addListener('change', () => { - this._inputFileChanged[filePath] = true; - this._executeSoon(); - }); - this._watchers.push(watcher); + this._watchedFiles[filePath] = true; + const watcher = fs.watch(filePath); + watcher.addListener('change', () => { + this._declarationResolver.invalidateCache(moduleId); + this._executeSoon(); }); + this._watchers.push(watcher); + }; + this._fsProvider = new class extends monacodts.FSProvider { + readFileSync(moduleId, filePath) { + onWillReadFile(moduleId, filePath); + return super.readFileSync(moduleId, filePath); + } + }; + this._declarationResolver = new monacodts.DeclarationResolver(this._fsProvider); + if (this._isWatch) { const recipeWatcher = fs.watch(monacodts.RECIPE_PATH); recipeWatcher.addListener('change', () => { - this._recipeFileChanged = true; this._executeSoon(); }); this._watchers.push(recipeWatcher); } - this._inputFileChanged = {}; - this._inputFiles.forEach(file => this._inputFileChanged[file] = true); - this._recipeFileChanged = true; - this._dtsFilesContents = {}; - this._dtsFilesContents2 = {}; } _executeSoon() { if (this._executeSoonTimer !== null) { - // Already scheduled - return; + clearTimeout(this._executeSoonTimer); + this._executeSoonTimer = null; } this._executeSoonTimer = setTimeout(() => { this._executeSoonTimer = null; @@ -159,49 +157,10 @@ class MonacoGenerator { this._watchers.forEach(watcher => watcher.close()); } _run() { - let somethingChanged = false; - const setDTSFileContent = (file, contents) => { - if (this._dtsFilesContents[file] === contents) { - return; - } - this._dtsFilesContents[file] = contents; - this._dtsFilesContents2[file] = ts.createSourceFile(file, contents, ts.ScriptTarget.ES5); - 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); - }); - } - if (this._recipeFileChanged) { - this._recipeFileChanged = false; - somethingChanged = true; - } - if (!somethingChanged) { - // Nothing changed - return null; - } - let r = monacodts.run2('src', this._dtsFilesContents2); + let r = monacodts.run3(this._declarationResolver); if (!r && !this._isWatch) { // The build must always be able to generate the monaco.d.ts - throw new Error(`monaco.d.ts genration error - Cannot continue`); + throw new Error(`monaco.d.ts generation error - Cannot continue`); } return r; } diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index 9316c81e692..b063e0306a1 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -12,7 +12,6 @@ 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'; @@ -135,62 +134,55 @@ 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; }; - private _dtsFilesContents2: { [filePath: string]: ts.SourceFile; }; + private readonly _watchers: fs.FSWatcher[]; + private readonly _watchedFiles: { [filePath: string]: boolean; }; + private readonly _fsProvider: monacodts.FSProvider; + private readonly _declarationResolver: monacodts.DeclarationResolver; 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`); + this._watchers = []; + this._watchedFiles = {}; + let onWillReadFile = (moduleId: string, filePath: string) => { + if (!this._isWatch) { + return; } - }); + if (this._watchedFiles[filePath]) { + return; + } + this._watchedFiles[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; - this._executeSoon(); - }); - this._watchers.push(watcher); + const watcher = fs.watch(filePath); + watcher.addListener('change', () => { + this._declarationResolver.invalidateCache(moduleId); + this._executeSoon(); }); + this._watchers.push(watcher); + }; + this._fsProvider = new class extends monacodts.FSProvider { + public readFileSync(moduleId: string, filePath: string): Buffer { + onWillReadFile(moduleId, filePath); + return super.readFileSync(moduleId, filePath); + } + }; + this._declarationResolver = new monacodts.DeclarationResolver(this._fsProvider); + if (this._isWatch) { const recipeWatcher = fs.watch(monacodts.RECIPE_PATH); recipeWatcher.addListener('change', () => { - this._recipeFileChanged = true; this._executeSoon(); }); this._watchers.push(recipeWatcher); } - - this._inputFileChanged = {}; - this._inputFiles.forEach(file => this._inputFileChanged[file] = true); - this._recipeFileChanged = true; - this._dtsFilesContents = {}; - this._dtsFilesContents2 = {}; } private _executeSoonTimer: NodeJS.Timer | null = null; private _executeSoon(): void { if (this._executeSoonTimer !== null) { - // Already scheduled - return; + clearTimeout(this._executeSoonTimer); + this._executeSoonTimer = null; } this._executeSoonTimer = setTimeout(() => { this._executeSoonTimer = null; @@ -203,59 +195,10 @@ class MonacoGenerator { } 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; - this._dtsFilesContents2[file] = ts.createSourceFile(file, contents, ts.ScriptTarget.ES5); - 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); - }); - } - - if (this._recipeFileChanged) { - this._recipeFileChanged = false; - somethingChanged = true; - } - - if (!somethingChanged) { - // Nothing changed - return null; - } - - let r = monacodts.run2('src', this._dtsFilesContents2); + let r = monacodts.run3(this._declarationResolver); if (!r && !this._isWatch) { // The build must always be able to generate the monaco.d.ts - throw new Error(`monaco.d.ts genration error - Cannot continue`); + throw new Error(`monaco.d.ts generation error - Cannot continue`); } return r; } diff --git a/build/monaco/api.js b/build/monaco/api.js index 035aee5b95f..020323389d9 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -8,29 +8,17 @@ const fs = require("fs"); const ts = require("typescript"); const path = require("path"); const util = require("gulp-util"); -const dtsv = '1'; +const dtsv = '2'; const tsfmt = require('../../tsfmt.json'); function log(message, ...rest) { util.log(util.colors.cyan('[monaco.d.ts]'), message, ...rest); } const SRC = path.join(__dirname, '../../src'); -const OUT_ROOT = path.join(__dirname, '../../'); 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) { - util.log(util.colors.red('[monaco.d.ts]'), 'WHILE HANDLING RULE: ', CURRENT_PROCESSING_RULE); - util.log(util.colors.red('[monaco.d.ts]'), message, ...rest); -} -function _logErr(message, ...rest) { util.log(util.colors.red(`[monaco.d.ts]`), message, ...rest); } -function moduleIdToPath(out, moduleId) { - if (/\.d\.ts/.test(moduleId)) { - return path.join(SRC, moduleId); - } - return path.join(OUT_ROOT, out, moduleId) + '.d.ts'; -} function isDeclaration(a) { return (a.kind === ts.SyntaxKind.InterfaceDeclaration || a.kind === ts.SyntaxKind.EnumDeclaration @@ -339,11 +327,11 @@ function generateDeclarationFile(recipe, sourceFileGetter) { } let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m1) { - CURRENT_PROCESSING_RULE = line; let moduleId = m1[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { - _logErr(`gulp watch restart required. ${moduleId} was added to 'monaco.d.ts.recipe'.`); + logErr(`While handling ${line}`); + logErr(`Cannot find ${moduleId}`); failed = true; return; } @@ -357,7 +345,9 @@ function generateDeclarationFile(recipe, sourceFileGetter) { } let declaration = getTopLevelDeclaration(sourceFile, typeName); if (!declaration) { - logErr('Cannot find type ' + typeName); + logErr(`While handling ${line}`); + logErr(`Cannot find ${typeName}`); + failed = true; return; } result.push(replacer(getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, usage, enums))); @@ -366,11 +356,11 @@ function generateDeclarationFile(recipe, sourceFileGetter) { } let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m2) { - CURRENT_PROCESSING_RULE = line; let moduleId = m2[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { - _logErr(`gulp watch restart required. ${moduleId} was added to 'monaco.d.ts.recipe'.`); + logErr(`While handling ${line}`); + logErr(`Cannot find ${moduleId}`); failed = true; return; } @@ -413,10 +403,10 @@ function generateDeclarationFile(recipe, sourceFileGetter) { } if (version !== dtsv) { if (!version) { - _logErr(`gulp watch restart required. 'monaco.d.ts.recipe' is written before versioning was introduced.`); + logErr(`gulp watch restart required. 'monaco.d.ts.recipe' is written before versioning was introduced.`); } else { - _logErr(`gulp watch restart required. 'monaco.d.ts.recipe' v${version} does not match runtime v${dtsv}.`); + logErr(`gulp watch restart required. 'monaco.d.ts.recipe' v${version} does not match runtime v${dtsv}.`); } return null; } @@ -441,31 +431,6 @@ function generateDeclarationFile(recipe, sourceFileGetter) { enums: resultEnums }; } -function getIncludesInRecipe() { - let recipe = fs.readFileSync(exports.RECIPE_PATH).toString(); - let lines = recipe.split(/\r\n|\n|\r/); - let result = []; - lines.forEach(line => { - let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); - if (m1) { - let moduleId = m1[1]; - result.push(moduleId); - return; - } - let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); - if (m2) { - let moduleId = m2[1]; - result.push(moduleId); - return; - } - }); - return result; -} -exports.getIncludesInRecipe = getIncludesInRecipe; -function getFilesToWatch(out) { - return getIncludesInRecipe().map((moduleId) => moduleIdToPath(out, moduleId)); -} -exports.getFilesToWatch = getFilesToWatch; function _run(sourceFileGetter) { log('Starting monaco.d.ts generation'); const recipe = fs.readFileSync(exports.RECIPE_PATH).toString(); @@ -489,35 +454,57 @@ function _run(sourceFileGetter) { isTheSame }; } -function run(out, inputFiles) { - let SOURCE_FILE_MAP = {}; - const sourceFileGetter = (moduleId) => { - if (!SOURCE_FILE_MAP[moduleId]) { - let filePath = path.normalize(moduleIdToPath(out, moduleId)); - if (!inputFiles.hasOwnProperty(filePath)) { - logErr('CANNOT FIND FILE ' + filePath + '. YOU MIGHT NEED TO RESTART gulp'); +class FSProvider { + existsSync(filePath) { + return fs.existsSync(filePath); + } + readFileSync(_moduleId, filePath) { + return fs.readFileSync(filePath); + } +} +exports.FSProvider = FSProvider; +class DeclarationResolver { + constructor(_fsProvider) { + this._fsProvider = _fsProvider; + this._sourceFileCache = Object.create(null); + } + invalidateCache(moduleId) { + this._sourceFileCache[moduleId] = null; + } + getDeclarationSourceFile(moduleId) { + if (!this._sourceFileCache[moduleId]) { + this._sourceFileCache[moduleId] = this._getDeclarationSourceFile(moduleId); + } + return this._sourceFileCache[moduleId]; + } + _getDeclarationSourceFile(moduleId) { + if (/\.d\.ts$/.test(moduleId)) { + const fileName = path.join(SRC, moduleId); + if (!this._fsProvider.existsSync(fileName)) { return null; } - let fileContents = inputFiles[filePath]; - let sourceFile = ts.createSourceFile(filePath, fileContents, ts.ScriptTarget.ES5); - SOURCE_FILE_MAP[moduleId] = sourceFile; + const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString(); + return ts.createSourceFile(fileName, fileContents, ts.ScriptTarget.ES5); } - return SOURCE_FILE_MAP[moduleId]; - }; - return _run(sourceFileGetter); + const fileName = path.join(SRC, `${moduleId}.ts`); + if (!this._fsProvider.existsSync(fileName)) { + return null; + } + const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString(); + const fileMap = { + 'file.ts': fileContents + }; + const service = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, fileMap, {})); + const text = service.getEmitOutput('file.ts', true).outputFiles[0].text; + return ts.createSourceFile(fileName, text, ts.ScriptTarget.ES5); + } } -function run2(out, sourceFileMap) { - const sourceFileGetter = (moduleId) => { - let filePath = path.normalize(moduleIdToPath(out, moduleId)); - return sourceFileMap[filePath]; - }; +exports.DeclarationResolver = DeclarationResolver; +function run3(resolver) { + const sourceFileGetter = (moduleId) => resolver.getDeclarationSourceFile(moduleId); return _run(sourceFileGetter); } -exports.run2 = run2; -function complainErrors() { - logErr('Not running monaco.d.ts generation due to compile errors'); -} -exports.complainErrors = complainErrors; +exports.run3 = run3; class TypeScriptLanguageServiceHost { constructor(libs, files, compilerOptions) { this._libs = libs; @@ -563,31 +550,10 @@ class TypeScriptLanguageServiceHost { return fileName === this.getDefaultLibFileName(this._compilerOptions); } } -exports.TypeScriptLanguageServiceHost = TypeScriptLanguageServiceHost; function execute() { - const OUTPUT_FILES = {}; - const SRC_FILES = {}; - const SRC_FILE_TO_EXPECTED_NAME = {}; - getIncludesInRecipe().forEach((moduleId) => { - if (/\.d\.ts$/.test(moduleId)) { - let fileName = path.join(SRC, moduleId); - OUTPUT_FILES[moduleIdToPath('src', moduleId)] = fs.readFileSync(fileName).toString(); - return; - } - let fileName = path.join(SRC, moduleId) + '.ts'; - SRC_FILES[fileName] = fs.readFileSync(fileName).toString(); - SRC_FILE_TO_EXPECTED_NAME[fileName] = moduleIdToPath('src', moduleId); - }); - const languageService = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, SRC_FILES, {})); - var t1 = Date.now(); - Object.keys(SRC_FILES).forEach((fileName) => { - const emitOutput = languageService.getEmitOutput(fileName, true); - OUTPUT_FILES[SRC_FILE_TO_EXPECTED_NAME[fileName]] = emitOutput.outputFiles[0].text; - }); - console.log(`Generating .d.ts took ${Date.now() - t1} ms`); - let r = run('src', OUTPUT_FILES); + let r = run3(new DeclarationResolver(new FSProvider())); if (!r) { - throw new Error(`monaco.d.ts genration error - Cannot continue`); + throw new Error(`monaco.d.ts generation error - Cannot continue`); } return r; } diff --git a/build/monaco/api.ts b/build/monaco/api.ts index a8ad7018793..4ad9368bad8 100644 --- a/build/monaco/api.ts +++ b/build/monaco/api.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; import * as path from 'path'; import * as util from 'gulp-util'; -const dtsv = '1'; +const dtsv = '2'; const tsfmt = require('../../tsfmt.json'); @@ -17,30 +17,14 @@ function log(message: any, ...rest: any[]): void { } const SRC = path.join(__dirname, '../../src'); -const OUT_ROOT = path.join(__dirname, '../../'); 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 = ''; function logErr(message: any, ...rest: any[]): void { - util.log(util.colors.red('[monaco.d.ts]'), 'WHILE HANDLING RULE: ', CURRENT_PROCESSING_RULE); - util.log(util.colors.red('[monaco.d.ts]'), message, ...rest); -} -function _logErr(message: any, ...rest: any[]): void { util.log(util.colors.red(`[monaco.d.ts]`), message, ...rest); } -function moduleIdToPath(out: string, moduleId: string): string { - if (/\.d\.ts/.test(moduleId)) { - return path.join(SRC, moduleId); - } - return path.join(OUT_ROOT, out, moduleId) + '.d.ts'; -} - -export interface ISourceFileMap { - [moduleId: string]: ts.SourceFile; -} -export type SourceFileGetter = (moduleId: string) => ts.SourceFile | null; +type SourceFileGetter = (moduleId: string) => ts.SourceFile | null; type TSTopLevelDeclaration = ts.InterfaceDeclaration | ts.EnumDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration | ts.FunctionDeclaration | ts.ModuleDeclaration; type TSTopLevelDeclare = TSTopLevelDeclaration | ts.VariableStatement; @@ -410,11 +394,11 @@ function generateDeclarationFile(recipe: string, sourceFileGetter: SourceFileGet let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m1) { - CURRENT_PROCESSING_RULE = line; let moduleId = m1[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { - _logErr(`gulp watch restart required. ${moduleId} was added to 'monaco.d.ts.recipe'.`); + logErr(`While handling ${line}`); + logErr(`Cannot find ${moduleId}`); failed = true; return; } @@ -431,7 +415,9 @@ function generateDeclarationFile(recipe: string, sourceFileGetter: SourceFileGet } let declaration = getTopLevelDeclaration(sourceFile, typeName); if (!declaration) { - logErr('Cannot find type ' + typeName); + logErr(`While handling ${line}`); + logErr(`Cannot find ${typeName}`); + failed = true; return; } result.push(replacer(getMassagedTopLevelDeclarationText(sourceFile, declaration, importName, usage, enums))); @@ -441,11 +427,11 @@ function generateDeclarationFile(recipe: string, sourceFileGetter: SourceFileGet let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); if (m2) { - CURRENT_PROCESSING_RULE = line; let moduleId = m2[1]; const sourceFile = sourceFileGetter(moduleId); if (!sourceFile) { - _logErr(`gulp watch restart required. ${moduleId} was added to 'monaco.d.ts.recipe'.`); + logErr(`While handling ${line}`); + logErr(`Cannot find ${moduleId}`); failed = true; return; } @@ -494,9 +480,9 @@ function generateDeclarationFile(recipe: string, sourceFileGetter: SourceFileGet if (version !== dtsv) { if (!version) { - _logErr(`gulp watch restart required. 'monaco.d.ts.recipe' is written before versioning was introduced.`); + logErr(`gulp watch restart required. 'monaco.d.ts.recipe' is written before versioning was introduced.`); } else { - _logErr(`gulp watch restart required. 'monaco.d.ts.recipe' v${version} does not match runtime v${dtsv}.`); + logErr(`gulp watch restart required. 'monaco.d.ts.recipe' v${version} does not match runtime v${dtsv}.`); } return null; } @@ -525,35 +511,6 @@ function generateDeclarationFile(recipe: string, sourceFileGetter: SourceFileGet }; } -export function getIncludesInRecipe(): string[] { - let recipe = fs.readFileSync(RECIPE_PATH).toString(); - let lines = recipe.split(/\r\n|\n|\r/); - let result: string[] = []; - - lines.forEach(line => { - - let m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/); - if (m1) { - let moduleId = m1[1]; - result.push(moduleId); - return; - } - - let m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/); - if (m2) { - let moduleId = m2[1]; - result.push(moduleId); - return; - } - }); - - return result; -} - -export function getFilesToWatch(out: string): string[] { - return getIncludesInRecipe().map((moduleId) => moduleIdToPath(out, moduleId)); -} - export interface IMonacoDeclarationResult { content: string; usageContent: string; @@ -591,48 +548,69 @@ function _run(sourceFileGetter: SourceFileGetter): IMonacoDeclarationResult | nu }; } -function run(out: string, inputFiles: { [file: string]: string; }): IMonacoDeclarationResult | null { +export class FSProvider { + public existsSync(filePath: string): boolean { + return fs.existsSync(filePath); + } + public readFileSync(_moduleId: string, filePath: string): Buffer { + return fs.readFileSync(filePath); + } +} - let SOURCE_FILE_MAP: { [moduleId: string]: ts.SourceFile; } = {}; - const sourceFileGetter = (moduleId: string): ts.SourceFile | null => { - if (!SOURCE_FILE_MAP[moduleId]) { - let filePath = path.normalize(moduleIdToPath(out, moduleId)); +export class DeclarationResolver { - if (!inputFiles.hasOwnProperty(filePath)) { - logErr('CANNOT FIND FILE ' + filePath + '. YOU MIGHT NEED TO RESTART gulp'); - return null; - } + private _sourceFileCache: { [moduleId: string]: ts.SourceFile | null; }; - let fileContents = inputFiles[filePath]; - let sourceFile = ts.createSourceFile(filePath, fileContents, ts.ScriptTarget.ES5); + constructor(private readonly _fsProvider: FSProvider) { + this._sourceFileCache = Object.create(null); + } - SOURCE_FILE_MAP[moduleId] = sourceFile; + public invalidateCache(moduleId: string): void { + this._sourceFileCache[moduleId] = null; + } + + public getDeclarationSourceFile(moduleId: string): ts.SourceFile | null { + if (!this._sourceFileCache[moduleId]) { + this._sourceFileCache[moduleId] = this._getDeclarationSourceFile(moduleId); } - return SOURCE_FILE_MAP[moduleId]; - }; + return this._sourceFileCache[moduleId]; + } - return _run(sourceFileGetter); + private _getDeclarationSourceFile(moduleId: string): ts.SourceFile | null { + if (/\.d\.ts$/.test(moduleId)) { + const fileName = path.join(SRC, moduleId); + if (!this._fsProvider.existsSync(fileName)) { + return null; + } + const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString(); + return ts.createSourceFile(fileName, fileContents, ts.ScriptTarget.ES5); + } + const fileName = path.join(SRC, `${moduleId}.ts`); + if (!this._fsProvider.existsSync(fileName)) { + return null; + } + const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString(); + const fileMap: IFileMap = { + 'file.ts': fileContents + }; + const service = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, fileMap, {})); + const text = service.getEmitOutput('file.ts', true).outputFiles[0].text; + return ts.createSourceFile(fileName, text, ts.ScriptTarget.ES5); + } } -export function run2(out: string, sourceFileMap: ISourceFileMap): IMonacoDeclarationResult | null { - const sourceFileGetter = (moduleId: string): ts.SourceFile | null => { - let filePath = path.normalize(moduleIdToPath(out, moduleId)); - return sourceFileMap[filePath]; - }; - +export function run3(resolver: DeclarationResolver): IMonacoDeclarationResult | null { + const sourceFileGetter = (moduleId: string) => resolver.getDeclarationSourceFile(moduleId); return _run(sourceFileGetter); } -export function complainErrors() { - logErr('Not running monaco.d.ts generation due to compile errors'); -} interface ILibMap { [libName: string]: string; } interface IFileMap { [fileName: string]: string; } -export class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost { +class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost { private readonly _libs: ILibMap; private readonly _files: IFileMap; @@ -686,34 +664,9 @@ export class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost { } export function execute(): IMonacoDeclarationResult { - - const OUTPUT_FILES: { [file: string]: string; } = {}; - const SRC_FILES: IFileMap = {}; - const SRC_FILE_TO_EXPECTED_NAME: { [filename: string]: string; } = {}; - getIncludesInRecipe().forEach((moduleId) => { - if (/\.d\.ts$/.test(moduleId)) { - let fileName = path.join(SRC, moduleId); - OUTPUT_FILES[moduleIdToPath('src', moduleId)] = fs.readFileSync(fileName).toString(); - return; - } - - let fileName = path.join(SRC, moduleId) + '.ts'; - SRC_FILES[fileName] = fs.readFileSync(fileName).toString(); - SRC_FILE_TO_EXPECTED_NAME[fileName] = moduleIdToPath('src', moduleId); - }); - - const languageService = ts.createLanguageService(new TypeScriptLanguageServiceHost({}, SRC_FILES, {})); - - var t1 = Date.now(); - Object.keys(SRC_FILES).forEach((fileName) => { - const emitOutput = languageService.getEmitOutput(fileName, true); - OUTPUT_FILES[SRC_FILE_TO_EXPECTED_NAME[fileName]] = emitOutput.outputFiles[0].text; - }); - console.log(`Generating .d.ts took ${Date.now() - t1} ms`); - - let r = run('src', OUTPUT_FILES); + let r = run3(new DeclarationResolver(new FSProvider())); if (!r) { - throw new Error(`monaco.d.ts genration error - Cannot continue`); + throw new Error(`monaco.d.ts generation error - Cannot continue`); } return r; } diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index 8a59ce79b52..356ef3ff046 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -86,4 +86,4 @@ declare namespace monaco.worker { } -//dtsv=1 \ No newline at end of file +//dtsv=2 \ No newline at end of file diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 737b51181b6..a99ccbd2176 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5543,4 +5543,4 @@ declare namespace monaco.worker { } -//dtsv=1 \ No newline at end of file +//dtsv=2 \ No newline at end of file -- GitLab