Browse Source

Move release script off of `gulp`

Alex Dima 3 years ago
parent
commit
cf27b4665e
5 changed files with 521 additions and 597 deletions
  1. 3 3
      .vscode/launch.json
  2. 507 0
      build/release.js
  3. 9 4
      build/utils.js
  4. 0 587
      gulpfile.js
  5. 2 3
      package.json

+ 3 - 3
.vscode/launch.json

@@ -15,10 +15,10 @@
 		{
 			"type": "pwa-node",
 			"request": "launch",
-			"name": "gulp release",
+			"name": "release",
 			"skipFiles": ["<node_internals>/**"],
-			"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
-			"args": ["release"],
+			"program": "${workspaceFolder}/build/release.js",
+			"args": [],
 			"cwd": "${workspaceFolder}"
 		},
 		{

+ 507 - 0
build/release.js

@@ -0,0 +1,507 @@
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+//@ts-check
+
+/**
+ * @typedef { { src:string; built:string; releaseDev:string; releaseMin:string; } } ICorePaths
+ * @typedef { { dev:string; min:string; esm: string; } } IPluginPaths
+ * @typedef { { name:string; contrib:string; modulePrefix:string; rootPath:string; paths:IPluginPaths } } IPlugin
+ * @typedef { { METADATA: {CORE:{paths:ICorePaths}; PLUGINS:IPlugin[];} } } IMetadata
+ */
+
+const glob = require('glob');
+const path = require('path');
+const fs = require('fs');
+const { REPO_ROOT, removeDir, ensureDir } = require('../build/utils');
+const ts = require('typescript');
+/**@type { IMetadata } */
+const metadata = require('../metadata.js');
+
+/** @typedef {{ path:string; contents:Buffer;}} IFile */
+
+removeDir(`release`);
+
+// dev folder
+AMD_releaseOne('dev');
+
+// min folder
+AMD_releaseOne('min');
+
+// esm folder
+ESM_release();
+
+// monaco.d.ts, editor.api.d.ts
+releaseDTS();
+
+// ThirdPartyNotices.txt
+releaseThirdPartyNotices();
+
+// package.json
+(() => {
+	const packageJSON = readFiles('package.json', { base: '' })[0];
+	const json = JSON.parse(packageJSON.contents.toString());
+
+	json.private = false;
+	delete json.scripts['postinstall'];
+
+	packageJSON.contents = Buffer.from(JSON.stringify(json, null, '  '));
+	writeFiles([packageJSON], `release`);
+})();
+
+(() => {
+	/** @type {IFile[]} */
+	let otherFiles = [];
+
+	otherFiles = otherFiles.concat(readFiles('README.md', { base: '' }));
+	otherFiles = otherFiles.concat(readFiles('CHANGELOG.md', { base: '' }));
+	otherFiles = otherFiles.concat(
+		readFiles('node_modules/monaco-editor-core/min-maps/**/*', {
+			base: 'node_modules/monaco-editor-core/'
+		})
+	);
+	otherFiles = otherFiles.concat(
+		readFiles('node_modules/monaco-editor-core/LICENSE', {
+			base: 'node_modules/monaco-editor-core/'
+		})
+	);
+
+	writeFiles(otherFiles, `release`);
+})();
+
+/**
+ * Release to `dev` or `min`.
+ * @param {'dev'|'min'} type
+ */
+function AMD_releaseOne(type) {
+	const coreFiles = readFiles(`node_modules/monaco-editor-core/${type}/**/*`, {
+		base: `node_modules/monaco-editor-core/${type}`
+	});
+	AMD_addPluginContribs(type, coreFiles);
+	writeFiles(coreFiles, `release/${type}`);
+
+	for (const plugin of metadata.METADATA.PLUGINS) {
+		AMD_releasePlugin(plugin, type, `release/${type}`);
+	}
+}
+
+/**
+ * Release a plugin to `dev` or `min`.
+ * @param {IPlugin} plugin
+ * @param {'dev'|'min'} type
+ * @param {string} destinationPath
+ */
+function AMD_releasePlugin(plugin, type, destinationPath) {
+	const pluginPath = path.join(plugin.rootPath, plugin.paths[type]); // dev or min
+	const contribPath =
+		path.join(pluginPath, plugin.contrib.substring(plugin.modulePrefix.length)) + '.js';
+
+	const files = readFiles(`${pluginPath}/**/*`, { base: pluginPath, ignore: [contribPath] });
+	writeFiles(files, path.join(destinationPath, plugin.modulePrefix));
+}
+
+/**
+ * Edit editor.main.js:
+ * - rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
+ * - append monaco.contribution modules from plugins
+ * - append new AMD module 'vs/editor/editor.main' that stiches things together
+ *
+ * @param {'dev'|'min'} type
+ * @param {IFile[]} files
+ */
+function AMD_addPluginContribs(type, files) {
+	for (const file of files) {
+		if (!/editor\.main\.js$/.test(file.path)) {
+			continue;
+		}
+
+		let contents = file.contents.toString();
+
+		// Rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
+		contents = contents.replace(/"vs\/editor\/editor\.main\"/, '"vs/editor/edcore.main"');
+
+		/** @type {string[]} */
+		let extraContent = [];
+		/** @type {string[]} */
+		let allPluginsModuleIds = [];
+
+		metadata.METADATA.PLUGINS.forEach(function (plugin) {
+			allPluginsModuleIds.push(plugin.contrib);
+			const pluginPath = path.join(plugin.rootPath, plugin.paths[type]); // dev or min
+			const contribPath =
+				path.join(REPO_ROOT, pluginPath, plugin.contrib.substring(plugin.modulePrefix.length)) +
+				'.js';
+			let contribContents = fs.readFileSync(contribPath).toString();
+
+			contribContents = contribContents.replace(
+				/define\((['"][a-z\/\-]+\/fillers\/monaco-editor-core['"]),\[\],/,
+				"define($1,['vs/editor/editor.api'],"
+			);
+
+			extraContent.push(contribContents);
+		});
+
+		extraContent.push(
+			`define("vs/editor/editor.main", ["vs/editor/edcore.main","${allPluginsModuleIds.join(
+				'","'
+			)}"], function(api) { return api; });`
+		);
+		let insertIndex = contents.lastIndexOf('//# sourceMappingURL=');
+		if (insertIndex === -1) {
+			insertIndex = contents.length;
+		}
+		contents =
+			contents.substring(0, insertIndex) +
+			'\n' +
+			extraContent.join('\n') +
+			'\n' +
+			contents.substring(insertIndex);
+
+		file.contents = Buffer.from(contents);
+	}
+}
+
+function ESM_release() {
+	const coreFiles = readFiles(`node_modules/monaco-editor-core/esm/**/*`, {
+		base: 'node_modules/monaco-editor-core/esm',
+		// we will create our own editor.api.d.ts which also contains the plugins API
+		ignore: ['node_modules/monaco-editor-core/esm/vs/editor/editor.api.d.ts']
+	});
+	ESM_addImportSuffix(coreFiles);
+	ESM_addPluginContribs(coreFiles);
+	writeFiles(coreFiles, `release/esm`);
+
+	for (const plugin of metadata.METADATA.PLUGINS) {
+		ESM_releasePlugin(plugin, `release/esm`);
+	}
+}
+
+/**
+ * Release a plugin to `esm`.
+ * Adds a dependency to 'vs/editor/editor.api' in contrib files in order for `monaco` to be defined.
+ * Rewrites imports for 'monaco-editor-core/**'
+ * @param {IPlugin} plugin
+ * @param {string} destinationPath
+ */
+function ESM_releasePlugin(plugin, destinationPath) {
+	const pluginPath = path.join(plugin.rootPath, plugin.paths['esm']);
+
+	const files = readFiles(`${pluginPath}/**/*`, { base: pluginPath });
+
+	for (const file of files) {
+		if (!/(\.js$)|(\.ts$)/.test(file.path)) {
+			continue;
+		}
+
+		let contents = file.contents.toString();
+
+		const info = ts.preProcessFile(contents);
+		for (let i = info.importedFiles.length - 1; i >= 0; i--) {
+			let importText = info.importedFiles[i].fileName;
+			const pos = info.importedFiles[i].pos;
+			const end = info.importedFiles[i].end;
+
+			if (!/(^\.\/)|(^\.\.\/)/.test(importText)) {
+				// non-relative import
+				if (!/^monaco-editor-core/.test(importText)) {
+					console.error(`Non-relative import for unknown module: ${importText} in ${file.path}`);
+					process.exit(1);
+				}
+
+				if (importText === 'monaco-editor-core') {
+					importText = 'monaco-editor-core/esm/vs/editor/editor.api';
+				}
+
+				const myFileDestPath = path.join(plugin.modulePrefix, file.path);
+				const importFilePath = importText.substring('monaco-editor-core/esm/'.length);
+				let relativePath = path
+					.relative(path.dirname(myFileDestPath), importFilePath)
+					.replace(/\\/g, '/');
+				if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
+					relativePath = './' + relativePath;
+				}
+
+				contents = contents.substring(0, pos + 1) + relativePath + contents.substring(end + 1);
+			}
+		}
+
+		file.contents = Buffer.from(contents);
+	}
+
+	for (const file of files) {
+		if (!/monaco\.contribution\.js$/.test(file.path)) {
+			continue;
+		}
+
+		const myFileDestPath = path.join(plugin.modulePrefix, file.path);
+		const apiFilePath = 'vs/editor/editor.api';
+		let relativePath = path.relative(path.dirname(myFileDestPath), apiFilePath).replace(/\\/g, '/');
+		if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
+			relativePath = './' + relativePath;
+		}
+
+		let contents = file.contents.toString();
+		contents = `import '${relativePath}';\n` + contents;
+		file.contents = Buffer.from(contents);
+	}
+
+	ESM_addImportSuffix(files);
+	writeFiles(files, path.join(destinationPath, plugin.modulePrefix));
+}
+
+/**
+ * Adds `.js` to all import statements.
+ * @param {IFile[]} files
+ */
+function ESM_addImportSuffix(files) {
+	for (const file of files) {
+		if (!/\.js$/.test(file.path)) {
+			continue;
+		}
+
+		let contents = file.contents.toString();
+
+		const info = ts.preProcessFile(contents);
+		for (let i = info.importedFiles.length - 1; i >= 0; i--) {
+			const importText = info.importedFiles[i].fileName;
+			const pos = info.importedFiles[i].pos;
+			const end = info.importedFiles[i].end;
+
+			if (/\.css$/.test(importText)) {
+				continue;
+			}
+
+			contents = contents.substring(0, pos + 1) + importText + '.js' + contents.substring(end + 1);
+		}
+
+		file.contents = Buffer.from(contents);
+	}
+}
+
+/**
+ * - Rename esm/vs/editor/editor.main.js to esm/vs/editor/edcore.main.js
+ * - Create esm/vs/editor/editor.main.js that that stiches things together
+ * @param {IFile[]} files
+ */
+function ESM_addPluginContribs(files) {
+	for (const file of files) {
+		if (!/editor\.main\.js$/.test(file.path)) {
+			continue;
+		}
+		file.path = file.path.replace(/editor\.main/, 'edcore.main');
+	}
+
+	const mainFileDestPath = 'vs/editor/editor.main.js';
+
+	/** @type {string[]} */
+	let mainFileImports = [];
+	for (const plugin of metadata.METADATA.PLUGINS) {
+		const contribDestPath = plugin.contrib;
+
+		let relativePath = path
+			.relative(path.dirname(mainFileDestPath), contribDestPath)
+			.replace(/\\/g, '/');
+		if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
+			relativePath = './' + relativePath;
+		}
+
+		mainFileImports.push(relativePath);
+	}
+
+	const mainFileContents =
+		mainFileImports.map((name) => `import '${name}';`).join('\n') +
+		`\n\nexport * from './edcore.main';`;
+
+	files.push({
+		path: mainFileDestPath,
+		contents: Buffer.from(mainFileContents)
+	});
+}
+
+/**
+ * Edit monaco.d.ts:
+ * - append monaco.d.ts from plugins
+ */
+function releaseDTS() {
+	const monacodts = readFiles('node_modules/monaco-editor-core/monaco.d.ts', {
+		base: 'node_modules/monaco-editor-core'
+	})[0];
+
+	let contents = monacodts.contents.toString();
+
+	/** @type {string[]} */
+	const extraContent = [];
+	metadata.METADATA.PLUGINS.forEach(function (plugin) {
+		const dtsPath = path.join(plugin.rootPath, './monaco.d.ts');
+		try {
+			let plugindts = fs.readFileSync(dtsPath).toString();
+			plugindts = plugindts.replace(/\/\/\/ <reference.*\n/m, '');
+			extraContent.push(plugindts);
+		} catch (err) {
+			return;
+		}
+	});
+
+	contents =
+		[
+			'/*!-----------------------------------------------------------',
+			' * Copyright (c) Microsoft Corporation. All rights reserved.',
+			' * Type definitions for monaco-editor',
+			' * Released under the MIT license',
+			'*-----------------------------------------------------------*/'
+		].join('\n') +
+		'\n' +
+		contents +
+		'\n' +
+		extraContent.join('\n');
+
+	// Ensure consistent indentation and line endings
+	contents = cleanFile(contents);
+
+	monacodts.contents = Buffer.from(contents);
+
+	const editorapidts = {
+		path: 'esm/vs/editor/editor.api.d.ts',
+		contents: Buffer.from(toExternalDTS(contents))
+	};
+
+	writeFiles([monacodts, editorapidts], `release`);
+
+	fs.writeFileSync('monaco-editor/website/playground/monaco.d.ts.txt', contents);
+	fs.writeFileSync('monaco-editor/typedoc/monaco.d.ts', contents);
+}
+
+/**
+ * Transforms a .d.ts which uses internal modules (namespaces) to one which is usable with external modules
+ * This function is duplicated in the `vscode` repo.
+ * @param {string} contents
+ * @returns string
+ */
+function toExternalDTS(contents) {
+	let lines = contents.split(/\r\n|\r|\n/);
+	let killNextCloseCurlyBrace = false;
+	for (let i = 0; i < lines.length; i++) {
+		let line = lines[i];
+
+		if (killNextCloseCurlyBrace) {
+			if ('}' === line) {
+				lines[i] = '';
+				killNextCloseCurlyBrace = false;
+				continue;
+			}
+
+			if (line.indexOf('    ') === 0) {
+				lines[i] = line.substr(4);
+			} else if (line.charAt(0) === '\t') {
+				lines[i] = line.substr(1);
+			}
+
+			continue;
+		}
+
+		if ('declare namespace monaco {' === line) {
+			lines[i] = '';
+			killNextCloseCurlyBrace = true;
+			continue;
+		}
+
+		if (line.indexOf('declare namespace monaco.') === 0) {
+			lines[i] = line.replace('declare namespace monaco.', 'export namespace ');
+		}
+
+		if (line.indexOf('declare let MonacoEnvironment') === 0) {
+			lines[i] = `declare global {\n    let MonacoEnvironment: Environment | undefined;\n}`;
+		}
+		if (line.indexOf('    MonacoEnvironment?') === 0) {
+			lines[i] = `    MonacoEnvironment?: Environment | undefined;`;
+		}
+	}
+	return lines.join('\n').replace(/\n\n\n+/g, '\n\n');
+}
+
+/**
+ * Normalize line endings and ensure consistent 4 spaces indentation
+ * @param {string} contents
+ * @returns {string}
+ */
+function cleanFile(contents) {
+	return contents
+		.split(/\r\n|\r|\n/)
+		.map(function (line) {
+			const m = line.match(/^(\t+)/);
+			if (!m) {
+				return line;
+			}
+			const tabsCount = m[1].length;
+			let newIndent = '';
+			for (let i = 0; i < 4 * tabsCount; i++) {
+				newIndent += ' ';
+			}
+			return newIndent + line.substring(tabsCount);
+		})
+		.join('\n');
+}
+
+/**
+ * Edit ThirdPartyNotices.txt:
+ * - append ThirdPartyNotices.txt from plugins
+ */
+function releaseThirdPartyNotices() {
+	const tpn = readFiles('node_modules/monaco-editor-core/ThirdPartyNotices.txt', {
+		base: 'node_modules/monaco-editor-core'
+	})[0];
+
+	let contents = tpn.contents.toString();
+
+	console.log('ADDING ThirdPartyNotices from ./ThirdPartyNotices.txt');
+	let thirdPartyNoticeContent = fs
+		.readFileSync(path.join(REPO_ROOT, 'ThirdPartyNotices.txt'))
+		.toString();
+	thirdPartyNoticeContent = thirdPartyNoticeContent.split('\n').slice(8).join('\n');
+
+	contents += '\n' + thirdPartyNoticeContent;
+	tpn.contents = Buffer.from(contents);
+
+	writeFiles([tpn], `release`);
+}
+
+/**
+ * @param {string} pattern
+ * @param {{ base:string; ignore?:string[] }} options
+ * @returns {IFile[]}
+ */
+function readFiles(pattern, options) {
+	let files = glob.sync(pattern, { cwd: REPO_ROOT, ignore: options.ignore });
+	// remove dirs
+	files = files.filter((file) => {
+		const fullPath = path.join(REPO_ROOT, file);
+		const stats = fs.statSync(fullPath);
+		return stats.isFile();
+	});
+
+	const base = options.base;
+	const baseLength = base === '' ? 0 : base.endsWith('/') ? base.length : base.length + 1;
+	return files.map((file) => {
+		const fullPath = path.join(REPO_ROOT, file);
+		const contents = fs.readFileSync(fullPath);
+		const relativePath = file.substring(baseLength);
+		return {
+			path: relativePath,
+			contents
+		};
+	});
+}
+
+/**
+ * @param {IFile[]} files
+ * @param {string} dest
+ */
+function writeFiles(files, dest) {
+	for (const file of files) {
+		const fullPath = path.join(REPO_ROOT, dest, file.path);
+		ensureDir(path.dirname(fullPath));
+		fs.writeFileSync(fullPath, file.contents);
+	}
+}

+ 9 - 4
build/utils.js

@@ -15,6 +15,7 @@ const alias = require('esbuild-plugin-alias');
 const REPO_ROOT = path.join(__dirname, '../');
 exports.REPO_ROOT = REPO_ROOT;
 
+const existingDirCache = new Set();
 /**
  * @param {string} dirname
  */
@@ -27,12 +28,16 @@ function ensureDir(dirname) {
 		dirname = path.dirname(dirname);
 	}
 	dirs.reverse();
-	dirs.forEach(function (dir) {
-		try {
-			fs.mkdirSync(dir);
-		} catch (err) {}
+	dirs.forEach((dir) => {
+		if (!existingDirCache.has(dir)) {
+			try {
+				fs.mkdirSync(dir);
+			} catch (err) {}
+			existingDirCache.add(dir);
+		}
 	});
 }
+exports.ensureDir = ensureDir;
 
 /**
  * Copy a file.

+ 0 - 587
gulpfile.js

@@ -1,12 +1,4 @@
 const gulp = require('gulp');
-/**
- * @typedef { { src:string; 'npm/dev':string; 'npm/min':string; built:string; releaseDev:string; releaseMin:string; } } ICorePaths
- * @typedef { { src:string; dev:string; min:string; esm: string; } } IPluginPaths
- * @typedef { { name:string; contrib:string; modulePrefix:string; rootPath:string; paths:IPluginPaths } } IPlugin
- * @typedef { { METADATA: {CORE:{paths:ICorePaths}; PLUGINS:IPlugin[];} } } IMetadata
- * @type { IMetadata }
- */
-const metadata = require('./metadata.js');
 const es = require('event-stream');
 const path = require('path');
 const fs = require('fs');
@@ -17,7 +9,6 @@ const http = require('http');
 const CleanCSS = require('clean-css');
 const uncss = require('uncss');
 const File = require('vinyl');
-const ts = require('typescript');
 
 const WEBSITE_GENERATED_PATH = path.join(__dirname, 'monaco-editor/website/playground/new-samples');
 /** @type {string} */
@@ -70,584 +61,6 @@ function taskSeries(...tasks) {
 	};
 }
 
-const cleanReleaseTask = function (cb) {
-	rimraf('release', { maxBusyTries: 1 }, cb);
-};
-gulp.task(
-	'release',
-	taskSeries(cleanReleaseTask, function () {
-		return es.merge(
-			// dev folder
-			releaseOne('dev'),
-
-			// min folder
-			releaseOne('min'),
-
-			// esm folder
-			ESM_release(),
-
-			// package.json
-			gulp
-				.src('package.json')
-				.pipe(
-					es.through(function (data) {
-						var json = JSON.parse(data.contents.toString());
-						json.private = false;
-						data.contents = Buffer.from(JSON.stringify(json, null, '  '));
-						delete json.scripts['postinstall'];
-						this.emit('data', data);
-					})
-				)
-				.pipe(gulp.dest('release')),
-
-			gulp.src('CHANGELOG.md').pipe(gulp.dest('release')),
-
-			// min-maps folder
-			gulp.src('node_modules/monaco-editor-core/min-maps/**/*').pipe(gulp.dest('release/min-maps')),
-
-			// other files
-			gulp
-				.src([
-					'node_modules/monaco-editor-core/LICENSE',
-					'node_modules/monaco-editor-core/monaco.d.ts',
-					'node_modules/monaco-editor-core/ThirdPartyNotices.txt',
-					'README.md'
-				])
-				.pipe(addPluginDTS())
-				.pipe(addPluginThirdPartyNotices())
-				.pipe(gulp.dest('release'))
-		);
-	})
-);
-
-/**
- * Release to `dev` or `min`.
- * @param {'dev'|'min'} type
- * @returns {NodeJS.ReadWriteStream}
- */
-function releaseOne(type) {
-	return es.merge(
-		gulp
-			.src('node_modules/monaco-editor-core/' + type + '/**/*')
-			.pipe(addPluginContribs(type))
-			.pipe(gulp.dest('release/' + type)),
-
-		pluginStreams(type, 'release/' + type + '/')
-	);
-}
-
-/**
- * Release plugins to `dev` or `min`.
- * @param {'dev'|'min'} type
- * @param {string} destinationPath
- * @returns {NodeJS.ReadWriteStream}
- */
-function pluginStreams(type, destinationPath) {
-	return es.merge(
-		metadata.METADATA.PLUGINS.map(function (plugin) {
-			return pluginStream(plugin, type, destinationPath);
-		})
-	);
-}
-
-/**
- * Release a plugin to `dev` or `min`.
- * @param {IPlugin} plugin
- * @param {'dev'|'min'} type
- * @param {string} destinationPath
- * @returns {NodeJS.ReadWriteStream}
- */
-function pluginStream(plugin, type, destinationPath) {
-	const pluginPath = path.join(plugin.rootPath, plugin.paths[type]); // dev or min
-	const contribPath =
-		path.join(pluginPath, plugin.contrib.substr(plugin.modulePrefix.length)) + '.js';
-	return gulp
-		.src([pluginPath + '/**/*', '!' + contribPath])
-		.pipe(
-			es.through(
-				/**
-				 * @param {File} data
-				 */
-				function (data) {
-					if (!/_\.contribution/.test(data.path)) {
-						this.emit('data', data);
-						return;
-					}
-
-					let contents = data.contents.toString();
-					contents = contents.replace(
-						'define(["require", "exports"],',
-						'define(["require", "exports", "vs/editor/editor.api"],'
-					);
-					data.contents = Buffer.from(contents);
-					this.emit('data', data);
-				}
-			)
-		)
-		.pipe(gulp.dest(destinationPath + plugin.modulePrefix));
-}
-
-/**
- * Edit editor.main.js:
- * - rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
- * - append monaco.contribution modules from plugins
- * - append new AMD module 'vs/editor/editor.main' that stiches things together
- *
- * @param {'dev'|'min'} type
- * @returns {NodeJS.ReadWriteStream}
- */
-function addPluginContribs(type) {
-	return es.through(
-		/**
-		 * @param {File} data
-		 */
-		function (data) {
-			if (!/editor\.main\.js$/.test(data.path)) {
-				this.emit('data', data);
-				return;
-			}
-			let contents = data.contents.toString();
-
-			// Rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
-			contents = contents.replace(/"vs\/editor\/editor\.main\"/, '"vs/editor/edcore.main"');
-
-			/** @type {string[]} */
-			let extraContent = [];
-			/** @type {string[]} */
-			let allPluginsModuleIds = [];
-
-			metadata.METADATA.PLUGINS.forEach(function (plugin) {
-				allPluginsModuleIds.push(plugin.contrib);
-				const pluginPath = path.join(plugin.rootPath, plugin.paths[type]); // dev or min
-				const contribPath =
-					path.join(__dirname, pluginPath, plugin.contrib.substr(plugin.modulePrefix.length)) +
-					'.js';
-				let contribContents = fs.readFileSync(contribPath).toString();
-
-				contribContents = contribContents.replace(
-					/define\((['"][a-z\/\-]+\/fillers\/monaco-editor-core['"]),\[\],/,
-					"define($1,['vs/editor/editor.api'],"
-				);
-
-				extraContent.push(contribContents);
-			});
-
-			extraContent.push(
-				`define("vs/editor/editor.main", ["vs/editor/edcore.main","${allPluginsModuleIds.join(
-					'","'
-				)}"], function(api) { return api; });`
-			);
-			let insertIndex = contents.lastIndexOf('//# sourceMappingURL=');
-			if (insertIndex === -1) {
-				insertIndex = contents.length;
-			}
-			contents =
-				contents.substring(0, insertIndex) +
-				'\n' +
-				extraContent.join('\n') +
-				'\n' +
-				contents.substring(insertIndex);
-
-			data.contents = Buffer.from(contents);
-			this.emit('data', data);
-		}
-	);
-}
-
-/**
- * @returns {NodeJS.ReadWriteStream}
- */
-function ESM_release() {
-	return es.merge(
-		gulp
-			.src([
-				'node_modules/monaco-editor-core/esm/**/*',
-				// we will create our own editor.api.d.ts which also contains the plugins API
-				'!node_modules/monaco-editor-core/esm/vs/editor/editor.api.d.ts'
-			])
-			.pipe(ESM_addImportSuffix())
-			.pipe(ESM_addPluginContribs('release/esm'))
-			.pipe(gulp.dest('release/esm')),
-
-		ESM_pluginStreams('release/esm/')
-	);
-}
-
-/**
- * Release plugins to `esm`.
- * @param {string} destinationPath
- * @returns {NodeJS.ReadWriteStream}
- */
-function ESM_pluginStreams(destinationPath) {
-	return es.merge(
-		metadata.METADATA.PLUGINS.map(function (plugin) {
-			return ESM_pluginStream(plugin, destinationPath);
-		})
-	);
-}
-
-/**
- * Release a plugin to `esm`.
- * Adds a dependency to 'vs/editor/editor.api' in contrib files in order for `monaco` to be defined.
- * Rewrites imports for 'monaco-editor-core/**'
- * @param {IPlugin} plugin
- * @param {string} destinationPath
- * @returns {NodeJS.ReadWriteStream}
- */
-function ESM_pluginStream(plugin, destinationPath) {
-	const DESTINATION = path.join(__dirname, destinationPath);
-	const pluginPath = path.join(plugin.rootPath, plugin.paths['esm']);
-	return gulp
-		.src([pluginPath + '/**/*'])
-		.pipe(
-			es.through(
-				/**
-				 * @param {File} data
-				 */
-				function (data) {
-					if (!/(\.js$)|(\.ts$)/.test(data.path)) {
-						this.emit('data', data);
-						return;
-					}
-
-					let contents = data.contents.toString();
-
-					const info = ts.preProcessFile(contents);
-					for (let i = info.importedFiles.length - 1; i >= 0; i--) {
-						let importText = info.importedFiles[i].fileName;
-						const pos = info.importedFiles[i].pos;
-						const end = info.importedFiles[i].end;
-
-						if (!/(^\.\/)|(^\.\.\/)/.test(importText)) {
-							// non-relative import
-							if (!/^monaco-editor-core/.test(importText)) {
-								console.error(
-									`Non-relative import for unknown module: ${importText} in ${data.path}`
-								);
-								process.exit(0);
-							}
-
-							if (importText === 'monaco-editor-core') {
-								importText = 'monaco-editor-core/esm/vs/editor/editor.api';
-							}
-
-							const myFileDestPath = path.join(DESTINATION, plugin.modulePrefix, data.relative);
-							const importFilePath = path.join(
-								DESTINATION,
-								importText.substr('monaco-editor-core/esm/'.length)
-							);
-							let relativePath = path
-								.relative(path.dirname(myFileDestPath), importFilePath)
-								.replace(/\\/g, '/');
-							if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
-								relativePath = './' + relativePath;
-							}
-
-							contents =
-								contents.substring(0, pos + 1) + relativePath + contents.substring(end + 1);
-						}
-					}
-
-					data.contents = Buffer.from(contents);
-					this.emit('data', data);
-				}
-			)
-		)
-		.pipe(
-			es.through(
-				/**
-				 * @param {File} data
-				 */
-				function (data) {
-					if (!/monaco\.contribution\.js$/.test(data.path)) {
-						this.emit('data', data);
-						return;
-					}
-
-					const myFileDestPath = path.join(DESTINATION, plugin.modulePrefix, data.relative);
-					const apiFilePath = path.join(DESTINATION, 'vs/editor/editor.api');
-					let relativePath = path
-						.relative(path.dirname(myFileDestPath), apiFilePath)
-						.replace(/\\/g, '/');
-					if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
-						relativePath = './' + relativePath;
-					}
-
-					let contents = data.contents.toString();
-					contents = `import '${relativePath}';\n` + contents;
-
-					data.contents = Buffer.from(contents);
-
-					this.emit('data', data);
-				}
-			)
-		)
-		.pipe(ESM_addImportSuffix())
-		.pipe(gulp.dest(destinationPath + plugin.modulePrefix));
-}
-
-/**
- * Adds `.js` to all import statements.
- * @returns {NodeJS.ReadWriteStream}
- */
-function ESM_addImportSuffix() {
-	return es.through(
-		/**
-		 * @param {File} data
-		 */
-		function (data) {
-			if (!/\.js$/.test(data.path)) {
-				this.emit('data', data);
-				return;
-			}
-
-			let contents = data.contents.toString();
-
-			const info = ts.preProcessFile(contents);
-			for (let i = info.importedFiles.length - 1; i >= 0; i--) {
-				const importText = info.importedFiles[i].fileName;
-				const pos = info.importedFiles[i].pos;
-				const end = info.importedFiles[i].end;
-
-				if (/\.css$/.test(importText)) {
-					continue;
-				}
-
-				contents =
-					contents.substring(0, pos + 1) + importText + '.js' + contents.substring(end + 1);
-			}
-
-			data.contents = Buffer.from(contents);
-			this.emit('data', data);
-		}
-	);
-}
-
-/**
- * - Rename esm/vs/editor/editor.main.js to esm/vs/editor/edcore.main.js
- * - Create esm/vs/editor/editor.main.js that that stiches things together
- * @param {string} dest
- * @returns {NodeJS.ReadWriteStream}
- */
-function ESM_addPluginContribs(dest) {
-	const DESTINATION = path.join(__dirname, dest);
-	return es.through(
-		/**
-		 * @param {File} data
-		 */
-		function (data) {
-			if (!/editor\.main\.js$/.test(data.path)) {
-				this.emit('data', data);
-				return;
-			}
-
-			this.emit(
-				'data',
-				new File({
-					path: data.path.replace(/editor\.main/, 'edcore.main'),
-					base: data.base,
-					contents: data.contents
-				})
-			);
-
-			const mainFileDestPath = path.join(DESTINATION, 'vs/editor/editor.main.js');
-			/** @type {string[]} */
-			let mainFileImports = [];
-			metadata.METADATA.PLUGINS.forEach(function (plugin) {
-				const contribDestPath = path.join(DESTINATION, plugin.contrib);
-
-				let relativePath = path
-					.relative(path.dirname(mainFileDestPath), contribDestPath)
-					.replace(/\\/g, '/');
-				if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
-					relativePath = './' + relativePath;
-				}
-
-				mainFileImports.push(relativePath);
-			});
-
-			const mainFileContents =
-				mainFileImports.map((name) => `import '${name}';`).join('\n') +
-				`\n\nexport * from './edcore.main';`;
-
-			this.emit(
-				'data',
-				new File({
-					path: data.path,
-					base: data.base,
-					contents: Buffer.from(mainFileContents)
-				})
-			);
-		}
-	);
-}
-
-/**
- * Edit monaco.d.ts:
- * - append monaco.d.ts from plugins
- * @returns {NodeJS.ReadWriteStream}
- */
-function addPluginDTS() {
-	return es.through(
-		/**
-		 * @param {File} data
-		 */
-		function (data) {
-			if (!/monaco\.d\.ts$/.test(data.path)) {
-				this.emit('data', data);
-				return;
-			}
-			let contents = data.contents.toString();
-
-			/** @type {string[]} */
-			const extraContent = [];
-			metadata.METADATA.PLUGINS.forEach(function (plugin) {
-				const dtsPath = path.join(plugin.rootPath, './monaco.d.ts');
-				try {
-					let plugindts = fs.readFileSync(dtsPath).toString();
-					plugindts = plugindts.replace(/\/\/\/ <reference.*\n/m, '');
-					extraContent.push(plugindts);
-				} catch (err) {
-					return;
-				}
-			});
-
-			contents =
-				[
-					'/*!-----------------------------------------------------------',
-					' * Copyright (c) Microsoft Corporation. All rights reserved.',
-					' * Type definitions for monaco-editor',
-					' * Released under the MIT license',
-					'*-----------------------------------------------------------*/'
-				].join('\n') +
-				'\n' +
-				contents +
-				'\n' +
-				extraContent.join('\n');
-
-			// Ensure consistent indentation and line endings
-			contents = cleanFile(contents);
-
-			data.contents = Buffer.from(contents);
-
-			this.emit(
-				'data',
-				new File({
-					path: path.join(path.dirname(data.path), 'esm/vs/editor/editor.api.d.ts'),
-					base: data.base,
-					contents: Buffer.from(toExternalDTS(contents))
-				})
-			);
-
-			fs.writeFileSync('monaco-editor/website/playground/monaco.d.ts.txt', contents);
-			fs.writeFileSync('monaco-editor/typedoc/monaco.d.ts', contents);
-			this.emit('data', data);
-		}
-	);
-}
-
-/**
- * Transforms a .d.ts which uses internal modules (namespaces) to one which is usable with external modules
- * This function is duplicated in the `vscode` repo.
- * @param {string} contents
- * @returns string
- */
-function toExternalDTS(contents) {
-	let lines = contents.split(/\r\n|\r|\n/);
-	let killNextCloseCurlyBrace = false;
-	for (let i = 0; i < lines.length; i++) {
-		let line = lines[i];
-
-		if (killNextCloseCurlyBrace) {
-			if ('}' === line) {
-				lines[i] = '';
-				killNextCloseCurlyBrace = false;
-				continue;
-			}
-
-			if (line.indexOf('    ') === 0) {
-				lines[i] = line.substr(4);
-			} else if (line.charAt(0) === '\t') {
-				lines[i] = line.substr(1);
-			}
-
-			continue;
-		}
-
-		if ('declare namespace monaco {' === line) {
-			lines[i] = '';
-			killNextCloseCurlyBrace = true;
-			continue;
-		}
-
-		if (line.indexOf('declare namespace monaco.') === 0) {
-			lines[i] = line.replace('declare namespace monaco.', 'export namespace ');
-		}
-
-		if (line.indexOf('declare let MonacoEnvironment') === 0) {
-			lines[i] = `declare global {\n    let MonacoEnvironment: Environment | undefined;\n}`;
-		}
-		if (line.indexOf('    MonacoEnvironment?') === 0) {
-			lines[i] = `    MonacoEnvironment?: Environment | undefined;`;
-		}
-	}
-	return lines.join('\n').replace(/\n\n\n+/g, '\n\n');
-}
-
-/**
- * Normalize line endings and ensure consistent 4 spaces indentation
- * @param {string} contents
- * @returns {string}
- */
-function cleanFile(contents) {
-	return contents
-		.split(/\r\n|\r|\n/)
-		.map(function (line) {
-			const m = line.match(/^(\t+)/);
-			if (!m) {
-				return line;
-			}
-			const tabsCount = m[1].length;
-			let newIndent = '';
-			for (let i = 0; i < 4 * tabsCount; i++) {
-				newIndent += ' ';
-			}
-			return newIndent + line.substring(tabsCount);
-		})
-		.join('\n');
-}
-
-/**
- * Edit ThirdPartyNotices.txt:
- * - append ThirdPartyNotices.txt from plugins
- * @returns {NodeJS.ReadWriteStream}
- */
-function addPluginThirdPartyNotices() {
-	return es.through(
-		/**
-		 * @param {File} data
-		 */
-		function (data) {
-			if (!/ThirdPartyNotices\.txt$/.test(data.path)) {
-				this.emit('data', data);
-				return;
-			}
-			let contents = data.contents.toString();
-
-			console.log('ADDING ThirdPartyNotices from ./ThirdPartyNotices.txt');
-			let thirdPartyNoticeContent = fs
-				.readFileSync(path.join(__dirname, 'ThirdPartyNotices.txt'))
-				.toString();
-			thirdPartyNoticeContent = thirdPartyNoticeContent.split('\n').slice(8).join('\n');
-
-			contents += '\n' + thirdPartyNoticeContent;
-			data.contents = Buffer.from(contents);
-
-			this.emit('data', data);
-		}
-	);
-}
-
 // --- website
 const cleanWebsiteTask = function (cb) {
 	rimraf('../monaco-editor-website', { maxBusyTries: 1 }, cb);

+ 2 - 3
package.json

@@ -9,14 +9,13 @@
 		"build-website": "gulp build-website && npm run typedoc",
 		"gulp": "node ./node_modules/gulp/bin/gulp.js",
 		"import-typescript": "node ./build/importTypescript.js",
-		"import-editor-webpack-plugin": "node ./build/importEditorWebpackPlugin.js",
 		"playwright-install": "node ./node_modules/playwright/install.js",
 		"playwright-install-deps": "playwright install-deps",
-		"postinstall": "node build/postinstall.js",
+		"postinstall": "node ./build/postinstall.js",
 		"prettier-check": "prettier --check .",
 		"prettier": "prettier --write .",
 		"pretty-quick": "pretty-quick --staged",
-		"release": "node ./build/build.js && gulp release && npm run import-editor-webpack-plugin",
+		"release": "node ./build/build.js && node ./build/release.js && node ./build/importEditorWebpackPlugin.js",
 		"simpleserver": "gulp simpleserver",
 		"smoketest-debug": "node ./test/smoke/runner.js --debug-tests",
 		"smoketest": "node ./test/smoke/runner.js",