mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-11 22:06:17 -08:00
build(site): [SITE-07] reproduce Monaco CSS sources and verify styled editor
This commit is contained in:
1 parent
23ac6f7128
commit
d2b2f76db8
23 files changed
+16271
-5
No files matched your search
@@ -43,3 +43,4 @@ docs/licenses/monaco-editor/core-origins/** -text whitespace=-trailing-space,cr-
|
||||
refactor/baselines/site-vendor/monaco-core-build/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/monaco-core-locales.json text eol=lf
|
||||
refactor/baselines/site-vendor/monaco-contributions/** -text whitespace=-trailing-space,cr-at-eol
|
||||
refactor/baselines/site-vendor/monaco-css-build/** -text whitespace=-trailing-space,cr-at-eol
|
||||
+2
-1
@@ -171,7 +171,8 @@
|
||||
"verify:monaco-basic-sources": "node scripts/site-vendor/monaco/reproduce-basic.ts",
|
||||
"verify:monaco-core-origins": "node scripts/site-vendor/monaco/reproduce-core-origins.ts",
|
||||
"verify:monaco-core-build": "node scripts/site-vendor/monaco/reproduce-core-build.ts",
|
||||
"verify:monaco-contributions": "node scripts/site-vendor/monaco/reproduce-contributions.ts"
|
||||
"verify:monaco-contributions": "node scripts/site-vendor/monaco/reproduce-contributions.ts",
|
||||
"verify:monaco-css": "node scripts/site-vendor/monaco/reproduce-css.ts"
|
||||
},
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"devDependencies": {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,265 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "SITE-07",
|
||||
"status": "checkpoint-incomplete",
|
||||
"recordedAt": "2026-09-15T03:54:24.439Z",
|
||||
"baseCommit": "23ac6f71284547a5e4dbf6cdbf0966f6cef49c87",
|
||||
"node": "v24.21.0",
|
||||
"yarn": "1.22.22",
|
||||
"fingerprints": {
|
||||
"refactor/baselines/monaco-css-build-provenance.json": "9842dab17ddc7ffedfedb3dbb3c16e8d2ec9fcade5a5cd42ac2ce124cb2fa3ab",
|
||||
"scripts/site-vendor/monaco/css.ts": "b287c31c3d52a88e46f8937ee465907d28573615d59e1f731a69fc5439e2bf3e",
|
||||
"scripts/site-vendor/monaco/reproduce-css.ts": "ce5f077886b90b83d482044e8b5b77d2779bc106d6e4537855b2fd2374f45fd2",
|
||||
"test/monaco-provenance.test.js": "132c76e2daf2a9369b5331014fa05062cb77bb284b5615d067f03e5c03131657",
|
||||
"test/browser/editor-styles.spec.js": "13deeb38582a9bfda94ed10d661c8302224f5b77dcbbcdff63aefa6e35404f11",
|
||||
"docs/assets/js/vs/editor/editor.main.css": "165d5ada907097527448677d0d0f0213578fe5cfaffcb245d7229862e849783a"
|
||||
},
|
||||
"reproduction": {
|
||||
"result": {
|
||||
"gitSources": 81,
|
||||
"styles": 68,
|
||||
"inlinedImages": [
|
||||
"src/vs/editor/contrib/colorPicker/images/opacity-background.png",
|
||||
"src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg",
|
||||
"src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg"
|
||||
],
|
||||
"fonts": [
|
||||
"vs/base/browser/ui/codicons/codicon/codicon.ttf"
|
||||
],
|
||||
"dependencySelectors": 153,
|
||||
"normalizedSeparators": 70,
|
||||
"developmentBytes": 114942,
|
||||
"minifiedBytes": 72052,
|
||||
"siteBytes": 72057,
|
||||
"exactDevelopment": true,
|
||||
"exactMinification": true,
|
||||
"preservedSiteCrlf": 5,
|
||||
"compiler": {
|
||||
"cssnano": "4.1.11",
|
||||
"postcss": "7.0.35"
|
||||
},
|
||||
"originalCoreTypeScriptCompiled": false
|
||||
},
|
||||
"offline": {
|
||||
"exitCode": 0,
|
||||
"logSha256": "8ac42cf42c91a65214244292da8a65813ce58664ab2a5ee225d5b67eac65c2b3"
|
||||
},
|
||||
"online": {
|
||||
"exitCode": 0,
|
||||
"logSha256": "ed86a59cef3c1c314ff6f9d82a7c8bf3d4adeb41b6608521d70a92c17e994ce7"
|
||||
},
|
||||
"earlierFailure": {
|
||||
"code": "ENOTFOUND",
|
||||
"host": "codeload.github.com",
|
||||
"logSha256": "a8dd9a7d79f947e364226fef4b48444e1900a51cdf3bd2bce89bc2cfcb26ae33",
|
||||
"resolvedBy": "Retry of the same verified archive request"
|
||||
}
|
||||
},
|
||||
"unit": {
|
||||
"passed": 25,
|
||||
"failed": 0,
|
||||
"logSha256": "1ddccc2a6b48f578f34a75170853c779a76da71b529d3a4e854b9ba33024a3ea"
|
||||
},
|
||||
"types": {
|
||||
"exitCode": 0,
|
||||
"logSha256": "71642f85fdc68059b2c4f81737d70eb55c3f56f5a7a76523e672764bef7a5034"
|
||||
},
|
||||
"lint": {
|
||||
"exitCode": 0
|
||||
},
|
||||
"browser": {
|
||||
"command": "yarn test:browser test/browser/editor-styles.spec.js --workers=1",
|
||||
"reportSha256": "473741dd39d4296600b66b3e4fdec65ae1e6c48143362d97c608609a88e1eeba",
|
||||
"stats": {
|
||||
"startTime": "2026-09-15T03:50:07.778Z",
|
||||
"duration": 7879.217,
|
||||
"expected": 3,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"errors": [],
|
||||
"tests": [
|
||||
{
|
||||
"title": "docs Monaco styles retain layout, themes and loaded codicon glyphs",
|
||||
"project": "chromium",
|
||||
"status": "passed",
|
||||
"browser": "153.0.8010.12",
|
||||
"platform": "win32",
|
||||
"errors": [],
|
||||
"consoleErrors": [],
|
||||
"failedRequests": [],
|
||||
"styles": {
|
||||
"themes": [
|
||||
{
|
||||
"theme": "vs-dark",
|
||||
"color": "rgb(30, 30, 30)"
|
||||
},
|
||||
{
|
||||
"theme": "vs",
|
||||
"color": "rgb(255, 255, 254)"
|
||||
}
|
||||
],
|
||||
"font": {
|
||||
"loaded": [
|
||||
{
|
||||
"family": "codicon",
|
||||
"status": "loaded"
|
||||
}
|
||||
],
|
||||
"family": "codicon",
|
||||
"content": "\"\""
|
||||
},
|
||||
"hostBox": {
|
||||
"x": 8,
|
||||
"y": 389,
|
||||
"width": 640,
|
||||
"height": 320
|
||||
},
|
||||
"findBox": {
|
||||
"x": 201,
|
||||
"y": 353.1777648925781,
|
||||
"width": 419,
|
||||
"height": 33
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"url": "http://127.0.0.1:8084/assets/js/vs/editor/editor.main.css",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:8084/assets/js/vs/base/browser/ui/codicons/codicon/codicon.ttf",
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"resized": {
|
||||
"width": 420,
|
||||
"height": 240
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "docs Monaco styles retain layout, themes and loaded codicon glyphs",
|
||||
"project": "firefox",
|
||||
"status": "passed",
|
||||
"browser": "155.0",
|
||||
"platform": "win32",
|
||||
"errors": [],
|
||||
"consoleErrors": [],
|
||||
"failedRequests": [],
|
||||
"styles": {
|
||||
"themes": [
|
||||
{
|
||||
"theme": "vs-dark",
|
||||
"color": "rgb(30, 30, 30)"
|
||||
},
|
||||
{
|
||||
"theme": "vs",
|
||||
"color": "rgb(255, 255, 254)"
|
||||
}
|
||||
],
|
||||
"font": {
|
||||
"loaded": [
|
||||
{
|
||||
"family": "codicon",
|
||||
"status": "loaded"
|
||||
}
|
||||
],
|
||||
"family": "codicon",
|
||||
"content": "\"\""
|
||||
},
|
||||
"hostBox": {
|
||||
"x": 8,
|
||||
"y": 390,
|
||||
"width": 640,
|
||||
"height": 320
|
||||
},
|
||||
"findBox": {
|
||||
"x": 201,
|
||||
"y": 357.7498779296875,
|
||||
"width": 419,
|
||||
"height": 33
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"url": "http://127.0.0.1:8084/assets/js/vs/editor/editor.main.css",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:8084/assets/js/vs/base/browser/ui/codicons/codicon/codicon.ttf",
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"resized": {
|
||||
"width": 420,
|
||||
"height": 240
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "docs Monaco styles retain layout, themes and loaded codicon glyphs",
|
||||
"project": "webkit",
|
||||
"status": "passed",
|
||||
"browser": "26.6",
|
||||
"platform": "win32",
|
||||
"errors": [],
|
||||
"consoleErrors": [],
|
||||
"failedRequests": [],
|
||||
"styles": {
|
||||
"themes": [
|
||||
{
|
||||
"theme": "vs-dark",
|
||||
"color": "rgb(30, 30, 30)"
|
||||
},
|
||||
{
|
||||
"theme": "vs",
|
||||
"color": "rgb(255, 255, 254)"
|
||||
}
|
||||
],
|
||||
"font": {
|
||||
"loaded": [
|
||||
{
|
||||
"family": "codicon",
|
||||
"status": "loaded"
|
||||
}
|
||||
],
|
||||
"family": "codicon",
|
||||
"content": "\"\""
|
||||
},
|
||||
"hostBox": {
|
||||
"x": 8,
|
||||
"y": 392,
|
||||
"width": 640,
|
||||
"height": 320
|
||||
},
|
||||
"findBox": {
|
||||
"x": 201,
|
||||
"y": 375.0150146484375,
|
||||
"width": 419,
|
||||
"height": 33
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"url": "http://127.0.0.1:8084/assets/js/vs/editor/editor.main.css",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"url": "http://127.0.0.1:8084/assets/js/vs/base/browser/ui/codicons/codicon/codicon.ttf",
|
||||
"status": 200
|
||||
}
|
||||
],
|
||||
"resized": {
|
||||
"width": 420,
|
||||
"height": 240
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"limitations": [
|
||||
"The original CSS plugin emits 70 CRLF separators. Conversion to the observed LF-only npm development file is explicit; the exact original publication stage responsible remains unidentified.",
|
||||
"Original core TypeScript compilation and remaining embedded-origin review are not completed by CSS reproduction.",
|
||||
"Runtime CSS, font files and notice delivery remain unchanged. No physical device, external SDK, remote CI or publication evidence is claimed.",
|
||||
"Thumbnail default compatibility policy remains pending."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
* text=auto
|
||||
|
||||
LICENSE.txt eol=crlf
|
||||
ThirdPartyNotices.txt eol=crlf
|
||||
|
||||
*.bat eol=crlf
|
||||
*.cmd eol=crlf
|
||||
*.ps1 eol=lf
|
||||
*.sh eol=lf
|
||||
*.rtf -text
|
||||
**/*.json linguist-language=jsonc
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2015 - present Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,481 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const gulp = require('gulp');
|
||||
const path = require('path');
|
||||
const util = require('./lib/util');
|
||||
const task = require('./lib/task');
|
||||
const common = require('./lib/optimize');
|
||||
const es = require('event-stream');
|
||||
const File = require('vinyl');
|
||||
const i18n = require('./lib/i18n');
|
||||
const standalone = require('./lib/standalone');
|
||||
const cp = require('child_process');
|
||||
const compilation = require('./lib/compilation');
|
||||
const monacoapi = require('./lib/monaco-api');
|
||||
const fs = require('fs');
|
||||
|
||||
let root = path.dirname(__dirname);
|
||||
let sha1 = util.getVersion(root);
|
||||
let semver = require('./monaco/package.json').version;
|
||||
let headerVersion = semver + '(' + sha1 + ')';
|
||||
|
||||
// Build
|
||||
|
||||
let editorEntryPoints = [
|
||||
{
|
||||
name: 'vs/editor/editor.main',
|
||||
include: [],
|
||||
exclude: ['vs/css', 'vs/nls'],
|
||||
prepend: ['out-editor-build/vs/css.js', 'out-editor-build/vs/nls.js'],
|
||||
},
|
||||
{
|
||||
name: 'vs/base/common/worker/simpleWorker',
|
||||
include: ['vs/editor/common/services/editorSimpleWorker'],
|
||||
prepend: ['vs/loader.js'],
|
||||
append: ['vs/base/worker/workerMain'],
|
||||
dest: 'vs/base/worker/workerMain.js'
|
||||
}
|
||||
];
|
||||
|
||||
let editorResources = [
|
||||
'out-editor-build/vs/base/browser/ui/codicons/**/*.ttf'
|
||||
];
|
||||
|
||||
let BUNDLED_FILE_HEADER = [
|
||||
'/*!-----------------------------------------------------------',
|
||||
' * Copyright (c) Microsoft Corporation. All rights reserved.',
|
||||
' * Version: ' + headerVersion,
|
||||
' * Released under the MIT license',
|
||||
' * https://github.com/microsoft/vscode/blob/main/LICENSE.txt',
|
||||
' *-----------------------------------------------------------*/',
|
||||
''
|
||||
].join('\n');
|
||||
|
||||
const languages = i18n.defaultLanguages.concat([]); // i18n.defaultLanguages.concat(process.env.VSCODE_QUALITY !== 'stable' ? i18n.extraLanguages : []);
|
||||
|
||||
const extractEditorSrcTask = task.define('extract-editor-src', () => {
|
||||
const apiusages = monacoapi.execute().usageContent;
|
||||
const extrausages = fs.readFileSync(path.join(root, 'build', 'monaco', 'monaco.usage.recipe')).toString();
|
||||
standalone.extractEditor({
|
||||
sourcesRoot: path.join(root, 'src'),
|
||||
entryPoints: [
|
||||
'vs/editor/editor.main',
|
||||
'vs/editor/editor.worker',
|
||||
'vs/base/worker/workerMain',
|
||||
],
|
||||
inlineEntryPoints: [
|
||||
apiusages,
|
||||
extrausages
|
||||
],
|
||||
shakeLevel: 2, // 0-Files, 1-InnerFile, 2-ClassMembers
|
||||
importIgnorePattern: /(^vs\/css!)/,
|
||||
destRoot: path.join(root, 'out-editor-src'),
|
||||
redirects: []
|
||||
});
|
||||
});
|
||||
|
||||
const compileEditorAMDTask = task.define('compile-editor-amd', compilation.compileTask('out-editor-src', 'out-editor-build', true));
|
||||
|
||||
const optimizeEditorAMDTask = task.define('optimize-editor-amd', common.optimizeTask({
|
||||
src: 'out-editor-build',
|
||||
entryPoints: editorEntryPoints,
|
||||
resources: editorResources,
|
||||
loaderConfig: {
|
||||
paths: {
|
||||
'vs': 'out-editor-build/vs',
|
||||
'vs/css': 'out-editor-build/vs/css.build',
|
||||
'vs/nls': 'out-editor-build/vs/nls.build',
|
||||
'vscode': 'empty:'
|
||||
}
|
||||
},
|
||||
bundleLoader: false,
|
||||
header: BUNDLED_FILE_HEADER,
|
||||
bundleInfo: true,
|
||||
out: 'out-editor',
|
||||
languages: languages
|
||||
}));
|
||||
|
||||
const minifyEditorAMDTask = task.define('minify-editor-amd', common.minifyTask('out-editor'));
|
||||
|
||||
const createESMSourcesAndResourcesTask = task.define('extract-editor-esm', () => {
|
||||
standalone.createESMSourcesAndResources2({
|
||||
srcFolder: './out-editor-src',
|
||||
outFolder: './out-editor-esm',
|
||||
outResourcesFolder: './out-monaco-editor-core/esm',
|
||||
ignores: [
|
||||
'inlineEntryPoint:0.ts',
|
||||
'inlineEntryPoint:1.ts',
|
||||
'vs/loader.js',
|
||||
'vs/nls.ts',
|
||||
'vs/nls.build.js',
|
||||
'vs/nls.d.ts',
|
||||
'vs/css.js',
|
||||
'vs/css.build.js',
|
||||
'vs/css.d.ts',
|
||||
'vs/base/worker/workerMain.ts',
|
||||
],
|
||||
renames: {
|
||||
'vs/nls.mock.ts': 'vs/nls.ts'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const compileEditorESMTask = task.define('compile-editor-esm', () => {
|
||||
const KEEP_PREV_ANALYSIS = false;
|
||||
const FAIL_ON_PURPOSE = false;
|
||||
console.log(`Launching the TS compiler at ${path.join(__dirname, '../out-editor-esm')}...`);
|
||||
let result;
|
||||
if (process.platform === 'win32') {
|
||||
result = cp.spawnSync(`..\\node_modules\\.bin\\tsc.cmd`, {
|
||||
cwd: path.join(__dirname, '../out-editor-esm')
|
||||
});
|
||||
} else {
|
||||
result = cp.spawnSync(`node`, [`../node_modules/.bin/tsc`], {
|
||||
cwd: path.join(__dirname, '../out-editor-esm')
|
||||
});
|
||||
}
|
||||
|
||||
console.log(result.stdout.toString());
|
||||
console.log(result.stderr.toString());
|
||||
|
||||
if (FAIL_ON_PURPOSE || result.status !== 0) {
|
||||
console.log(`The TS Compilation failed, preparing analysis folder...`);
|
||||
const destPath = path.join(__dirname, '../../vscode-monaco-editor-esm-analysis');
|
||||
const keepPrevAnalysis = (KEEP_PREV_ANALYSIS && fs.existsSync(destPath));
|
||||
const cleanDestPath = (keepPrevAnalysis ? Promise.resolve() : util.rimraf(destPath)());
|
||||
return cleanDestPath.then(() => {
|
||||
// build a list of files to copy
|
||||
const files = util.rreddir(path.join(__dirname, '../out-editor-esm'));
|
||||
|
||||
if (!keepPrevAnalysis) {
|
||||
fs.mkdirSync(destPath);
|
||||
|
||||
// initialize a new repository
|
||||
cp.spawnSync(`git`, [`init`], {
|
||||
cwd: destPath
|
||||
});
|
||||
|
||||
// copy files from src
|
||||
for (const file of files) {
|
||||
const srcFilePath = path.join(__dirname, '../src', file);
|
||||
const dstFilePath = path.join(destPath, file);
|
||||
if (fs.existsSync(srcFilePath)) {
|
||||
util.ensureDir(path.dirname(dstFilePath));
|
||||
const contents = fs.readFileSync(srcFilePath).toString().replace(/\r\n|\r|\n/g, '\n');
|
||||
fs.writeFileSync(dstFilePath, contents);
|
||||
}
|
||||
}
|
||||
|
||||
// create an initial commit to diff against
|
||||
cp.spawnSync(`git`, [`add`, `.`], {
|
||||
cwd: destPath
|
||||
});
|
||||
|
||||
// create the commit
|
||||
cp.spawnSync(`git`, [`commit`, `-m`, `"original sources"`, `--no-gpg-sign`], {
|
||||
cwd: destPath
|
||||
});
|
||||
}
|
||||
|
||||
// copy files from tree shaken src
|
||||
for (const file of files) {
|
||||
const srcFilePath = path.join(__dirname, '../out-editor-src', file);
|
||||
const dstFilePath = path.join(destPath, file);
|
||||
if (fs.existsSync(srcFilePath)) {
|
||||
util.ensureDir(path.dirname(dstFilePath));
|
||||
const contents = fs.readFileSync(srcFilePath).toString().replace(/\r\n|\r|\n/g, '\n');
|
||||
fs.writeFileSync(dstFilePath, contents);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Open in VS Code the folder at '${destPath}' and you can analyze the compilation error`);
|
||||
throw new Error('Standalone Editor compilation failed. If this is the build machine, simply launch `yarn run gulp editor-distro` on your machine to further analyze the compilation problem.');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
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('\tMonacoEnvironment?') === 0) {
|
||||
lines[i] = ` MonacoEnvironment?: Environment | undefined;`;
|
||||
}
|
||||
}
|
||||
return lines.join('\n').replace(/\n\n\n+/g, '\n\n');
|
||||
}
|
||||
|
||||
function filterStream(testFunc) {
|
||||
return es.through(function (data) {
|
||||
if (!testFunc(data.relative)) {
|
||||
return;
|
||||
}
|
||||
this.emit('data', data);
|
||||
});
|
||||
}
|
||||
|
||||
const finalEditorResourcesTask = task.define('final-editor-resources', () => {
|
||||
return es.merge(
|
||||
// other assets
|
||||
es.merge(
|
||||
gulp.src('build/monaco/LICENSE'),
|
||||
gulp.src('build/monaco/ThirdPartyNotices.txt'),
|
||||
gulp.src('src/vs/monaco.d.ts')
|
||||
).pipe(gulp.dest('out-monaco-editor-core')),
|
||||
|
||||
// place the .d.ts in the esm folder
|
||||
gulp.src('src/vs/monaco.d.ts')
|
||||
.pipe(es.through(function (data) {
|
||||
this.emit('data', new File({
|
||||
path: data.path.replace(/monaco\.d\.ts/, 'editor.api.d.ts'),
|
||||
base: data.base,
|
||||
contents: Buffer.from(toExternalDTS(data.contents.toString()))
|
||||
}));
|
||||
}))
|
||||
.pipe(gulp.dest('out-monaco-editor-core/esm/vs/editor')),
|
||||
|
||||
// package.json
|
||||
gulp.src('build/monaco/package.json')
|
||||
.pipe(es.through(function (data) {
|
||||
let json = JSON.parse(data.contents.toString());
|
||||
json.private = false;
|
||||
data.contents = Buffer.from(JSON.stringify(json, null, ' '));
|
||||
this.emit('data', data);
|
||||
}))
|
||||
.pipe(gulp.dest('out-monaco-editor-core')),
|
||||
|
||||
// version.txt
|
||||
gulp.src('build/monaco/version.txt')
|
||||
.pipe(es.through(function (data) {
|
||||
data.contents = Buffer.from(`monaco-editor-core: https://github.com/microsoft/vscode/tree/${sha1}`);
|
||||
this.emit('data', data);
|
||||
}))
|
||||
.pipe(gulp.dest('out-monaco-editor-core')),
|
||||
|
||||
// README.md
|
||||
gulp.src('build/monaco/README-npm.md')
|
||||
.pipe(es.through(function (data) {
|
||||
this.emit('data', new File({
|
||||
path: data.path.replace(/README-npm\.md/, 'README.md'),
|
||||
base: data.base,
|
||||
contents: data.contents
|
||||
}));
|
||||
}))
|
||||
.pipe(gulp.dest('out-monaco-editor-core')),
|
||||
|
||||
// dev folder
|
||||
es.merge(
|
||||
gulp.src('out-editor/**/*')
|
||||
).pipe(gulp.dest('out-monaco-editor-core/dev')),
|
||||
|
||||
// min folder
|
||||
es.merge(
|
||||
gulp.src('out-editor-min/**/*')
|
||||
).pipe(filterStream(function (path) {
|
||||
// no map files
|
||||
return !/(\.js\.map$)|(nls\.metadata\.json$)|(bundleInfo\.json$)/.test(path);
|
||||
})).pipe(es.through(function (data) {
|
||||
// tweak the sourceMappingURL
|
||||
if (!/\.js$/.test(data.path)) {
|
||||
this.emit('data', data);
|
||||
return;
|
||||
}
|
||||
|
||||
let relativePathToMap = path.relative(path.join(data.relative), path.join('min-maps', data.relative + '.map'));
|
||||
|
||||
let strContents = data.contents.toString();
|
||||
let newStr = '//# sourceMappingURL=' + relativePathToMap.replace(/\\/g, '/');
|
||||
strContents = strContents.replace(/\/\/# sourceMappingURL=[^ ]+$/, newStr);
|
||||
|
||||
data.contents = Buffer.from(strContents);
|
||||
this.emit('data', data);
|
||||
})).pipe(gulp.dest('out-monaco-editor-core/min')),
|
||||
|
||||
// min-maps folder
|
||||
es.merge(
|
||||
gulp.src('out-editor-min/**/*')
|
||||
).pipe(filterStream(function (path) {
|
||||
// no map files
|
||||
return /\.js\.map$/.test(path);
|
||||
})).pipe(gulp.dest('out-monaco-editor-core/min-maps'))
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task('extract-editor-src',
|
||||
task.series(
|
||||
util.rimraf('out-editor-src'),
|
||||
extractEditorSrcTask
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('editor-distro',
|
||||
task.series(
|
||||
task.parallel(
|
||||
util.rimraf('out-editor-src'),
|
||||
util.rimraf('out-editor-build'),
|
||||
util.rimraf('out-editor-esm'),
|
||||
util.rimraf('out-monaco-editor-core'),
|
||||
util.rimraf('out-editor'),
|
||||
util.rimraf('out-editor-min')
|
||||
),
|
||||
extractEditorSrcTask,
|
||||
task.parallel(
|
||||
task.series(
|
||||
compileEditorAMDTask,
|
||||
optimizeEditorAMDTask,
|
||||
minifyEditorAMDTask
|
||||
),
|
||||
task.series(
|
||||
createESMSourcesAndResourcesTask,
|
||||
compileEditorESMTask
|
||||
)
|
||||
),
|
||||
finalEditorResourcesTask
|
||||
)
|
||||
);
|
||||
|
||||
const bundleEditorESMTask = task.define('editor-esm-bundle-webpack', () => {
|
||||
const webpack = require('webpack');
|
||||
const webpackGulp = require('webpack-stream');
|
||||
|
||||
const result = es.through();
|
||||
|
||||
const webpackConfigPath = path.join(root, 'build/monaco/monaco.webpack.config.js');
|
||||
|
||||
const webpackConfig = {
|
||||
...require(webpackConfigPath),
|
||||
...{ mode: 'production' }
|
||||
};
|
||||
|
||||
const webpackDone = (err, stats) => {
|
||||
if (err) {
|
||||
result.emit('error', err);
|
||||
return;
|
||||
}
|
||||
const { compilation } = stats;
|
||||
if (compilation.errors.length > 0) {
|
||||
result.emit('error', compilation.errors.join('\n'));
|
||||
}
|
||||
if (compilation.warnings.length > 0) {
|
||||
result.emit('data', compilation.warnings.join('\n'));
|
||||
}
|
||||
};
|
||||
|
||||
return webpackGulp(webpackConfig, webpack, webpackDone)
|
||||
.pipe(gulp.dest('out-editor-esm-bundle'));
|
||||
});
|
||||
|
||||
gulp.task('editor-esm-bundle',
|
||||
task.series(
|
||||
task.parallel(
|
||||
util.rimraf('out-editor-src'),
|
||||
util.rimraf('out-editor-esm'),
|
||||
util.rimraf('out-monaco-editor-core'),
|
||||
util.rimraf('out-editor-esm-bundle'),
|
||||
),
|
||||
extractEditorSrcTask,
|
||||
createESMSourcesAndResourcesTask,
|
||||
compileEditorESMTask,
|
||||
bundleEditorESMTask,
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('monacodts', task.define('monacodts', () => {
|
||||
const result = monacoapi.execute();
|
||||
fs.writeFileSync(result.filePath, result.content);
|
||||
fs.writeFileSync(path.join(root, 'src/vs/editor/common/standalone/standaloneEnums.ts'), result.enums);
|
||||
return Promise.resolve(true);
|
||||
}));
|
||||
|
||||
//#region monaco type checking
|
||||
|
||||
function createTscCompileTask(watch) {
|
||||
return () => {
|
||||
const createReporter = require('./lib/reporter').createReporter;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const args = ['./node_modules/.bin/tsc', '-p', './src/tsconfig.monaco.json', '--noEmit'];
|
||||
if (watch) {
|
||||
args.push('-w');
|
||||
}
|
||||
const child = cp.spawn(`node`, args, {
|
||||
cwd: path.join(__dirname, '..'),
|
||||
// stdio: [null, 'pipe', 'inherit']
|
||||
});
|
||||
let errors = [];
|
||||
let reporter = createReporter('monaco');
|
||||
let report;
|
||||
// eslint-disable-next-line no-control-regex
|
||||
let magic = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; // https://stackoverflow.com/questions/25245716/remove-all-ansi-colors-styles-from-strings
|
||||
|
||||
child.stdout.on('data', data => {
|
||||
let str = String(data);
|
||||
str = str.replace(magic, '').trim();
|
||||
if (str.indexOf('Starting compilation') >= 0 || str.indexOf('File change detected') >= 0) {
|
||||
errors.length = 0;
|
||||
report = reporter.end(false);
|
||||
|
||||
} else if (str.indexOf('Compilation complete') >= 0) {
|
||||
report.end();
|
||||
|
||||
} else if (str) {
|
||||
let match = /(.*\(\d+,\d+\): )(.*: )(.*)/.exec(str);
|
||||
if (match) {
|
||||
// trying to massage the message so that it matches the gulp-tsb error messages
|
||||
// e.g. src/vs/base/common/strings.ts(663,5): error TS2322: Type '1234' is not assignable to type 'string'.
|
||||
let fullpath = path.join(root, match[1]);
|
||||
let message = match[3];
|
||||
reporter(fullpath + message);
|
||||
} else {
|
||||
reporter(str);
|
||||
}
|
||||
}
|
||||
});
|
||||
child.on('exit', resolve);
|
||||
child.on('error', reject);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const monacoTypecheckWatchTask = task.define('monaco-typecheck-watch', createTscCompileTask(true));
|
||||
exports.monacoTypecheckWatchTask = monacoTypecheckWatchTask;
|
||||
|
||||
const monacoTypecheckTask = task.define('monaco-typecheck', createTscCompileTask(false));
|
||||
exports.monacoTypecheckTask = monacoTypecheckTask;
|
||||
|
||||
//#endregion
|
||||
@@ -0,0 +1,464 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.bundle = void 0;
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const vm = require("vm");
|
||||
/**
|
||||
* Bundle `entryPoints` given config `config`.
|
||||
*/
|
||||
function bundle(entryPoints, config, callback) {
|
||||
const entryPointsMap = {};
|
||||
entryPoints.forEach((module) => {
|
||||
entryPointsMap[module.name] = module;
|
||||
});
|
||||
const allMentionedModulesMap = {};
|
||||
entryPoints.forEach((module) => {
|
||||
allMentionedModulesMap[module.name] = true;
|
||||
(module.include || []).forEach(function (includedModule) {
|
||||
allMentionedModulesMap[includedModule] = true;
|
||||
});
|
||||
(module.exclude || []).forEach(function (excludedModule) {
|
||||
allMentionedModulesMap[excludedModule] = true;
|
||||
});
|
||||
});
|
||||
const code = require('fs').readFileSync(path.join(__dirname, '../../src/vs/loader.js'));
|
||||
const r = vm.runInThisContext('(function(require, module, exports) { ' + code + '\n});');
|
||||
const loaderModule = { exports: {} };
|
||||
r.call({}, require, loaderModule, loaderModule.exports);
|
||||
const loader = loaderModule.exports;
|
||||
config.isBuild = true;
|
||||
config.paths = config.paths || {};
|
||||
if (!config.paths['vs/nls']) {
|
||||
config.paths['vs/nls'] = 'out-build/vs/nls.build';
|
||||
}
|
||||
if (!config.paths['vs/css']) {
|
||||
config.paths['vs/css'] = 'out-build/vs/css.build';
|
||||
}
|
||||
loader.config(config);
|
||||
loader(['require'], (localRequire) => {
|
||||
const resolvePath = (path) => {
|
||||
const r = localRequire.toUrl(path);
|
||||
if (!/\.js/.test(r)) {
|
||||
return r + '.js';
|
||||
}
|
||||
return r;
|
||||
};
|
||||
for (const moduleId in entryPointsMap) {
|
||||
const entryPoint = entryPointsMap[moduleId];
|
||||
if (entryPoint.append) {
|
||||
entryPoint.append = entryPoint.append.map(resolvePath);
|
||||
}
|
||||
if (entryPoint.prepend) {
|
||||
entryPoint.prepend = entryPoint.prepend.map(resolvePath);
|
||||
}
|
||||
}
|
||||
});
|
||||
loader(Object.keys(allMentionedModulesMap), () => {
|
||||
const modules = loader.getBuildInfo();
|
||||
const partialResult = emitEntryPoints(modules, entryPointsMap);
|
||||
const cssInlinedResources = loader('vs/css').getInlinedResources();
|
||||
callback(null, {
|
||||
files: partialResult.files,
|
||||
cssInlinedResources: cssInlinedResources,
|
||||
bundleData: partialResult.bundleData
|
||||
});
|
||||
}, (err) => callback(err, null));
|
||||
}
|
||||
exports.bundle = bundle;
|
||||
function emitEntryPoints(modules, entryPoints) {
|
||||
const modulesMap = {};
|
||||
modules.forEach((m) => {
|
||||
modulesMap[m.id] = m;
|
||||
});
|
||||
const modulesGraph = {};
|
||||
modules.forEach((m) => {
|
||||
modulesGraph[m.id] = m.dependencies;
|
||||
});
|
||||
const sortedModules = topologicalSort(modulesGraph);
|
||||
let result = [];
|
||||
const usedPlugins = {};
|
||||
const bundleData = {
|
||||
graph: modulesGraph,
|
||||
bundles: {}
|
||||
};
|
||||
Object.keys(entryPoints).forEach((moduleToBundle) => {
|
||||
const info = entryPoints[moduleToBundle];
|
||||
const rootNodes = [moduleToBundle].concat(info.include || []);
|
||||
const allDependencies = visit(rootNodes, modulesGraph);
|
||||
const excludes = ['require', 'exports', 'module'].concat(info.exclude || []);
|
||||
excludes.forEach((excludeRoot) => {
|
||||
const allExcludes = visit([excludeRoot], modulesGraph);
|
||||
Object.keys(allExcludes).forEach((exclude) => {
|
||||
delete allDependencies[exclude];
|
||||
});
|
||||
});
|
||||
const includedModules = sortedModules.filter((module) => {
|
||||
return allDependencies[module];
|
||||
});
|
||||
bundleData.bundles[moduleToBundle] = includedModules;
|
||||
const res = emitEntryPoint(modulesMap, modulesGraph, moduleToBundle, includedModules, info.prepend || [], info.append || [], info.dest);
|
||||
result = result.concat(res.files);
|
||||
for (const pluginName in res.usedPlugins) {
|
||||
usedPlugins[pluginName] = usedPlugins[pluginName] || res.usedPlugins[pluginName];
|
||||
}
|
||||
});
|
||||
Object.keys(usedPlugins).forEach((pluginName) => {
|
||||
const plugin = usedPlugins[pluginName];
|
||||
if (typeof plugin.finishBuild === 'function') {
|
||||
const write = (filename, contents) => {
|
||||
result.push({
|
||||
dest: filename,
|
||||
sources: [{
|
||||
path: null,
|
||||
contents: contents
|
||||
}]
|
||||
});
|
||||
};
|
||||
plugin.finishBuild(write);
|
||||
}
|
||||
});
|
||||
return {
|
||||
// TODO@TS 2.1.2
|
||||
files: extractStrings(removeDuplicateTSBoilerplate(result)),
|
||||
bundleData: bundleData
|
||||
};
|
||||
}
|
||||
function extractStrings(destFiles) {
|
||||
const parseDefineCall = (moduleMatch, depsMatch) => {
|
||||
const module = moduleMatch.replace(/^"|"$/g, '');
|
||||
let deps = depsMatch.split(',');
|
||||
deps = deps.map((dep) => {
|
||||
dep = dep.trim();
|
||||
dep = dep.replace(/^"|"$/g, '');
|
||||
dep = dep.replace(/^'|'$/g, '');
|
||||
let prefix = null;
|
||||
let _path = null;
|
||||
const pieces = dep.split('!');
|
||||
if (pieces.length > 1) {
|
||||
prefix = pieces[0] + '!';
|
||||
_path = pieces[1];
|
||||
}
|
||||
else {
|
||||
prefix = '';
|
||||
_path = pieces[0];
|
||||
}
|
||||
if (/^\.\//.test(_path) || /^\.\.\//.test(_path)) {
|
||||
const res = path.join(path.dirname(module), _path).replace(/\\/g, '/');
|
||||
return prefix + res;
|
||||
}
|
||||
return prefix + _path;
|
||||
});
|
||||
return {
|
||||
module: module,
|
||||
deps: deps
|
||||
};
|
||||
};
|
||||
destFiles.forEach((destFile) => {
|
||||
if (!/\.js$/.test(destFile.dest)) {
|
||||
return;
|
||||
}
|
||||
if (/\.nls\.js$/.test(destFile.dest)) {
|
||||
return;
|
||||
}
|
||||
// Do one pass to record the usage counts for each module id
|
||||
const useCounts = {};
|
||||
destFile.sources.forEach((source) => {
|
||||
const matches = source.contents.match(/define\(("[^"]+"),\s*\[(((, )?("|')[^"']+("|'))+)\]/);
|
||||
if (!matches) {
|
||||
return;
|
||||
}
|
||||
const defineCall = parseDefineCall(matches[1], matches[2]);
|
||||
useCounts[defineCall.module] = (useCounts[defineCall.module] || 0) + 1;
|
||||
defineCall.deps.forEach((dep) => {
|
||||
useCounts[dep] = (useCounts[dep] || 0) + 1;
|
||||
});
|
||||
});
|
||||
const sortedByUseModules = Object.keys(useCounts);
|
||||
sortedByUseModules.sort((a, b) => {
|
||||
return useCounts[b] - useCounts[a];
|
||||
});
|
||||
const replacementMap = {};
|
||||
sortedByUseModules.forEach((module, index) => {
|
||||
replacementMap[module] = index;
|
||||
});
|
||||
destFile.sources.forEach((source) => {
|
||||
source.contents = source.contents.replace(/define\(("[^"]+"),\s*\[(((, )?("|')[^"']+("|'))+)\]/, (_, moduleMatch, depsMatch) => {
|
||||
const defineCall = parseDefineCall(moduleMatch, depsMatch);
|
||||
return `define(__m[${replacementMap[defineCall.module]}/*${defineCall.module}*/], __M([${defineCall.deps.map(dep => replacementMap[dep] + '/*' + dep + '*/').join(',')}])`;
|
||||
});
|
||||
});
|
||||
destFile.sources.unshift({
|
||||
path: null,
|
||||
contents: [
|
||||
'(function() {',
|
||||
`var __m = ${JSON.stringify(sortedByUseModules)};`,
|
||||
`var __M = function(deps) {`,
|
||||
` var result = [];`,
|
||||
` for (var i = 0, len = deps.length; i < len; i++) {`,
|
||||
` result[i] = __m[deps[i]];`,
|
||||
` }`,
|
||||
` return result;`,
|
||||
`};`
|
||||
].join('\n')
|
||||
});
|
||||
destFile.sources.push({
|
||||
path: null,
|
||||
contents: '}).call(this);'
|
||||
});
|
||||
});
|
||||
return destFiles;
|
||||
}
|
||||
function removeDuplicateTSBoilerplate(destFiles) {
|
||||
// Taken from typescript compiler => emitFiles
|
||||
const BOILERPLATE = [
|
||||
{ start: /^var __extends/, end: /^}\)\(\);$/ },
|
||||
{ start: /^var __assign/, end: /^};$/ },
|
||||
{ start: /^var __decorate/, end: /^};$/ },
|
||||
{ start: /^var __metadata/, end: /^};$/ },
|
||||
{ start: /^var __param/, end: /^};$/ },
|
||||
{ start: /^var __awaiter/, end: /^};$/ },
|
||||
{ start: /^var __generator/, end: /^};$/ },
|
||||
];
|
||||
destFiles.forEach((destFile) => {
|
||||
const SEEN_BOILERPLATE = [];
|
||||
destFile.sources.forEach((source) => {
|
||||
const lines = source.contents.split(/\r\n|\n|\r/);
|
||||
const newLines = [];
|
||||
let IS_REMOVING_BOILERPLATE = false, END_BOILERPLATE;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
if (IS_REMOVING_BOILERPLATE) {
|
||||
newLines.push('');
|
||||
if (END_BOILERPLATE.test(line)) {
|
||||
IS_REMOVING_BOILERPLATE = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let j = 0; j < BOILERPLATE.length; j++) {
|
||||
const boilerplate = BOILERPLATE[j];
|
||||
if (boilerplate.start.test(line)) {
|
||||
if (SEEN_BOILERPLATE[j]) {
|
||||
IS_REMOVING_BOILERPLATE = true;
|
||||
END_BOILERPLATE = boilerplate.end;
|
||||
}
|
||||
else {
|
||||
SEEN_BOILERPLATE[j] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IS_REMOVING_BOILERPLATE) {
|
||||
newLines.push('');
|
||||
}
|
||||
else {
|
||||
newLines.push(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
source.contents = newLines.join('\n');
|
||||
});
|
||||
});
|
||||
return destFiles;
|
||||
}
|
||||
function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, append, dest) {
|
||||
if (!dest) {
|
||||
dest = entryPoint + '.js';
|
||||
}
|
||||
const mainResult = {
|
||||
sources: [],
|
||||
dest: dest
|
||||
}, results = [mainResult];
|
||||
const usedPlugins = {};
|
||||
const getLoaderPlugin = (pluginName) => {
|
||||
if (!usedPlugins[pluginName]) {
|
||||
usedPlugins[pluginName] = modulesMap[pluginName].exports;
|
||||
}
|
||||
return usedPlugins[pluginName];
|
||||
};
|
||||
includedModules.forEach((c) => {
|
||||
const bangIndex = c.indexOf('!');
|
||||
if (bangIndex >= 0) {
|
||||
const pluginName = c.substr(0, bangIndex);
|
||||
const plugin = getLoaderPlugin(pluginName);
|
||||
mainResult.sources.push(emitPlugin(entryPoint, plugin, pluginName, c.substr(bangIndex + 1)));
|
||||
return;
|
||||
}
|
||||
const module = modulesMap[c];
|
||||
if (module.path === 'empty:') {
|
||||
return;
|
||||
}
|
||||
const contents = readFileAndRemoveBOM(module.path);
|
||||
if (module.shim) {
|
||||
mainResult.sources.push(emitShimmedModule(c, deps[c], module.shim, module.path, contents));
|
||||
}
|
||||
else {
|
||||
mainResult.sources.push(emitNamedModule(c, module.defineLocation, module.path, contents));
|
||||
}
|
||||
});
|
||||
Object.keys(usedPlugins).forEach((pluginName) => {
|
||||
const plugin = usedPlugins[pluginName];
|
||||
if (typeof plugin.writeFile === 'function') {
|
||||
const req = (() => {
|
||||
throw new Error('no-no!');
|
||||
});
|
||||
req.toUrl = something => something;
|
||||
const write = (filename, contents) => {
|
||||
results.push({
|
||||
dest: filename,
|
||||
sources: [{
|
||||
path: null,
|
||||
contents: contents
|
||||
}]
|
||||
});
|
||||
};
|
||||
plugin.writeFile(pluginName, entryPoint, req, write, {});
|
||||
}
|
||||
});
|
||||
const toIFile = (path) => {
|
||||
const contents = readFileAndRemoveBOM(path);
|
||||
return {
|
||||
path: path,
|
||||
contents: contents
|
||||
};
|
||||
};
|
||||
const toPrepend = (prepend || []).map(toIFile);
|
||||
const toAppend = (append || []).map(toIFile);
|
||||
mainResult.sources = toPrepend.concat(mainResult.sources).concat(toAppend);
|
||||
return {
|
||||
files: results,
|
||||
usedPlugins: usedPlugins
|
||||
};
|
||||
}
|
||||
function readFileAndRemoveBOM(path) {
|
||||
const BOM_CHAR_CODE = 65279;
|
||||
let contents = fs.readFileSync(path, 'utf8');
|
||||
// Remove BOM
|
||||
if (contents.charCodeAt(0) === BOM_CHAR_CODE) {
|
||||
contents = contents.substring(1);
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
function emitPlugin(entryPoint, plugin, pluginName, moduleName) {
|
||||
let result = '';
|
||||
if (typeof plugin.write === 'function') {
|
||||
const write = ((what) => {
|
||||
result += what;
|
||||
});
|
||||
write.getEntryPoint = () => {
|
||||
return entryPoint;
|
||||
};
|
||||
write.asModule = (moduleId, code) => {
|
||||
code = code.replace(/^define\(/, 'define("' + moduleId + '",');
|
||||
result += code;
|
||||
};
|
||||
plugin.write(pluginName, moduleName, write);
|
||||
}
|
||||
return {
|
||||
path: null,
|
||||
contents: result
|
||||
};
|
||||
}
|
||||
function emitNamedModule(moduleId, defineCallPosition, path, contents) {
|
||||
// `defineCallPosition` is the position in code: |define()
|
||||
const defineCallOffset = positionToOffset(contents, defineCallPosition.line, defineCallPosition.col);
|
||||
// `parensOffset` is the position in code: define|()
|
||||
const parensOffset = contents.indexOf('(', defineCallOffset);
|
||||
const insertStr = '"' + moduleId + '", ';
|
||||
return {
|
||||
path: path,
|
||||
contents: contents.substr(0, parensOffset + 1) + insertStr + contents.substr(parensOffset + 1)
|
||||
};
|
||||
}
|
||||
function emitShimmedModule(moduleId, myDeps, factory, path, contents) {
|
||||
const strDeps = (myDeps.length > 0 ? '"' + myDeps.join('", "') + '"' : '');
|
||||
const strDefine = 'define("' + moduleId + '", [' + strDeps + '], ' + factory + ');';
|
||||
return {
|
||||
path: path,
|
||||
contents: contents + '\n;\n' + strDefine
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert a position (line:col) to (offset) in string `str`
|
||||
*/
|
||||
function positionToOffset(str, desiredLine, desiredCol) {
|
||||
if (desiredLine === 1) {
|
||||
return desiredCol - 1;
|
||||
}
|
||||
let line = 1;
|
||||
let lastNewLineOffset = -1;
|
||||
do {
|
||||
if (desiredLine === line) {
|
||||
return lastNewLineOffset + 1 + desiredCol - 1;
|
||||
}
|
||||
lastNewLineOffset = str.indexOf('\n', lastNewLineOffset + 1);
|
||||
line++;
|
||||
} while (lastNewLineOffset >= 0);
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* Return a set of reachable nodes in `graph` starting from `rootNodes`
|
||||
*/
|
||||
function visit(rootNodes, graph) {
|
||||
const result = {};
|
||||
const queue = rootNodes;
|
||||
rootNodes.forEach((node) => {
|
||||
result[node] = true;
|
||||
});
|
||||
while (queue.length > 0) {
|
||||
const el = queue.shift();
|
||||
const myEdges = graph[el] || [];
|
||||
myEdges.forEach((toNode) => {
|
||||
if (!result[toNode]) {
|
||||
result[toNode] = true;
|
||||
queue.push(toNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Perform a topological sort on `graph`
|
||||
*/
|
||||
function topologicalSort(graph) {
|
||||
const allNodes = {}, outgoingEdgeCount = {}, inverseEdges = {};
|
||||
Object.keys(graph).forEach((fromNode) => {
|
||||
allNodes[fromNode] = true;
|
||||
outgoingEdgeCount[fromNode] = graph[fromNode].length;
|
||||
graph[fromNode].forEach((toNode) => {
|
||||
allNodes[toNode] = true;
|
||||
outgoingEdgeCount[toNode] = outgoingEdgeCount[toNode] || 0;
|
||||
inverseEdges[toNode] = inverseEdges[toNode] || [];
|
||||
inverseEdges[toNode].push(fromNode);
|
||||
});
|
||||
});
|
||||
// https://en.wikipedia.org/wiki/Topological_sorting
|
||||
const S = [], L = [];
|
||||
Object.keys(allNodes).forEach((node) => {
|
||||
if (outgoingEdgeCount[node] === 0) {
|
||||
delete outgoingEdgeCount[node];
|
||||
S.push(node);
|
||||
}
|
||||
});
|
||||
while (S.length > 0) {
|
||||
// Ensure the exact same order all the time with the same inputs
|
||||
S.sort();
|
||||
const n = S.shift();
|
||||
L.push(n);
|
||||
const myInverseEdges = inverseEdges[n] || [];
|
||||
myInverseEdges.forEach((m) => {
|
||||
outgoingEdgeCount[m]--;
|
||||
if (outgoingEdgeCount[m] === 0) {
|
||||
delete outgoingEdgeCount[m];
|
||||
S.push(m);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (Object.keys(outgoingEdgeCount).length > 0) {
|
||||
throw new Error('Cannot do topological sort on cyclic graph, remaining nodes: ' + Object.keys(outgoingEdgeCount));
|
||||
}
|
||||
return L;
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as es from 'event-stream';
|
||||
import * as gulp from 'gulp';
|
||||
import * as concat from 'gulp-concat';
|
||||
import * as filter from 'gulp-filter';
|
||||
import * as fancyLog from 'fancy-log';
|
||||
import * as ansiColors from 'ansi-colors';
|
||||
import * as path from 'path';
|
||||
import * as pump from 'pump';
|
||||
import * as VinylFile from 'vinyl';
|
||||
import * as bundle from './bundle';
|
||||
import { Language, processNlsFiles } from './i18n';
|
||||
import { createStatsStream } from './stats';
|
||||
import * as util from './util';
|
||||
|
||||
const REPO_ROOT_PATH = path.join(__dirname, '../..');
|
||||
|
||||
function log(prefix: string, message: string): void {
|
||||
fancyLog(ansiColors.cyan('[' + prefix + ']'), message);
|
||||
}
|
||||
|
||||
export function loaderConfig() {
|
||||
const result: any = {
|
||||
paths: {
|
||||
'vs': 'out-build/vs',
|
||||
'vscode': 'empty:'
|
||||
},
|
||||
amdModulesPattern: /^vs\//
|
||||
};
|
||||
|
||||
result['vs/css'] = { inlineResources: true };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i;
|
||||
|
||||
function loader(src: string, bundledFileHeader: string, bundleLoader: boolean, externalLoaderInfo?: any): NodeJS.ReadWriteStream {
|
||||
let sources = [
|
||||
`${src}/vs/loader.js`
|
||||
];
|
||||
if (bundleLoader) {
|
||||
sources = sources.concat([
|
||||
`${src}/vs/css.js`,
|
||||
`${src}/vs/nls.js`
|
||||
]);
|
||||
}
|
||||
|
||||
let isFirst = true;
|
||||
return (
|
||||
gulp
|
||||
.src(sources, { base: `${src}` })
|
||||
.pipe(es.through(function (data) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
this.emit('data', new VinylFile({
|
||||
path: 'fake',
|
||||
base: '.',
|
||||
contents: Buffer.from(bundledFileHeader)
|
||||
}));
|
||||
this.emit('data', data);
|
||||
} else {
|
||||
this.emit('data', data);
|
||||
}
|
||||
}, function () {
|
||||
if (externalLoaderInfo !== undefined) {
|
||||
this.emit('data', new VinylFile({
|
||||
path: 'fake2',
|
||||
base: '.',
|
||||
contents: Buffer.from(`require.config(${JSON.stringify(externalLoaderInfo, undefined, 2)});`)
|
||||
}));
|
||||
}
|
||||
this.emit('end');
|
||||
}))
|
||||
.pipe(concat('vs/loader.js'))
|
||||
);
|
||||
}
|
||||
|
||||
function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string, fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream {
|
||||
const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
|
||||
|
||||
// If a bundle ends up including in any of the sources our copyright, then
|
||||
// insert a fake source at the beginning of each bundle with our copyright
|
||||
let containsOurCopyright = false;
|
||||
for (let i = 0, len = sources.length; i < len; i++) {
|
||||
const fileContents = sources[i].contents;
|
||||
if (IS_OUR_COPYRIGHT_REGEXP.test(fileContents)) {
|
||||
containsOurCopyright = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (containsOurCopyright) {
|
||||
sources.unshift({
|
||||
path: null,
|
||||
contents: bundledFileHeader
|
||||
});
|
||||
}
|
||||
|
||||
const treatedSources = sources.map(function (source) {
|
||||
const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
|
||||
const base = source.path ? root + `/${src}` : '.';
|
||||
const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake';
|
||||
const contents = source.path ? fileContentMapper(source.contents, path) : source.contents;
|
||||
|
||||
return new VinylFile({
|
||||
path: path,
|
||||
base: base,
|
||||
contents: Buffer.from(contents)
|
||||
});
|
||||
});
|
||||
|
||||
return es.readArray(treatedSources)
|
||||
.pipe(useSourcemaps ? util.loadSourcemaps() : es.through())
|
||||
.pipe(concat(dest))
|
||||
.pipe(createStatsStream(dest));
|
||||
}
|
||||
|
||||
function toBundleStream(src: string, bundledFileHeader: string, bundles: bundle.IConcatFile[], fileContentMapper: (contents: string, path: string) => string): NodeJS.ReadWriteStream {
|
||||
return es.merge(bundles.map(function (bundle) {
|
||||
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper);
|
||||
}));
|
||||
}
|
||||
|
||||
export interface IOptimizeTaskOpts {
|
||||
/**
|
||||
* The folder to read files from.
|
||||
*/
|
||||
src: string;
|
||||
/**
|
||||
* (for AMD files, will get bundled and get Copyright treatment)
|
||||
*/
|
||||
entryPoints: bundle.IEntryPoint[];
|
||||
/**
|
||||
* (svg, etc.)
|
||||
*/
|
||||
resources: string[];
|
||||
loaderConfig: any;
|
||||
/**
|
||||
* Additional info we append to the end of the loader
|
||||
*/
|
||||
externalLoaderInfo?: any;
|
||||
/**
|
||||
* (true by default - append css and nls to loader)
|
||||
*/
|
||||
bundleLoader?: boolean;
|
||||
/**
|
||||
* (basically the Copyright treatment)
|
||||
*/
|
||||
header?: string;
|
||||
/**
|
||||
* (emit bundleInfo.json file)
|
||||
*/
|
||||
bundleInfo: boolean;
|
||||
/**
|
||||
* (out folder name)
|
||||
*/
|
||||
out: string;
|
||||
/**
|
||||
* (out folder name)
|
||||
*/
|
||||
languages?: Language[];
|
||||
/**
|
||||
* File contents interceptor
|
||||
* @param contents The contens of the file
|
||||
* @param path The absolute file path, always using `/`, even on Windows
|
||||
*/
|
||||
fileContentMapper?: (contents: string, path: string) => string;
|
||||
}
|
||||
|
||||
const DEFAULT_FILE_HEADER = [
|
||||
'/*!--------------------------------------------------------',
|
||||
' * Copyright (C) Microsoft Corporation. All rights reserved.',
|
||||
' *--------------------------------------------------------*/'
|
||||
].join('\n');
|
||||
|
||||
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
|
||||
const src = opts.src;
|
||||
const entryPoints = opts.entryPoints;
|
||||
const resources = opts.resources;
|
||||
const loaderConfig = opts.loaderConfig;
|
||||
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
|
||||
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
|
||||
const out = opts.out;
|
||||
const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents);
|
||||
|
||||
return function () {
|
||||
const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps');
|
||||
|
||||
const bundlesStream = es.through(); // this stream will contain the bundled files
|
||||
const resourcesStream = es.through(); // this stream will contain the resources
|
||||
const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json
|
||||
|
||||
bundle.bundle(entryPoints, loaderConfig, function (err, result) {
|
||||
if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); }
|
||||
|
||||
toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream);
|
||||
|
||||
// Remove css inlined resources
|
||||
const filteredResources = resources.slice();
|
||||
result.cssInlinedResources.forEach(function (resource) {
|
||||
if (process.env['VSCODE_BUILD_VERBOSE']) {
|
||||
log('optimizer', 'excluding inlined: ' + resource);
|
||||
}
|
||||
filteredResources.push('!' + resource);
|
||||
});
|
||||
gulp.src(filteredResources, { base: `${src}`, allowEmpty: true }).pipe(resourcesStream);
|
||||
|
||||
const bundleInfoArray: VinylFile[] = [];
|
||||
if (opts.bundleInfo) {
|
||||
bundleInfoArray.push(new VinylFile({
|
||||
path: 'bundleInfo.json',
|
||||
base: '.',
|
||||
contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t'))
|
||||
}));
|
||||
}
|
||||
es.readArray(bundleInfoArray).pipe(bundleInfoStream);
|
||||
});
|
||||
|
||||
const result = es.merge(
|
||||
loader(src, bundledFileHeader, bundleLoader, opts.externalLoaderInfo),
|
||||
bundlesStream,
|
||||
resourcesStream,
|
||||
bundleInfoStream
|
||||
);
|
||||
|
||||
return result
|
||||
.pipe(sourcemaps.write('./', {
|
||||
sourceRoot: undefined,
|
||||
addComment: true,
|
||||
includeContent: true
|
||||
}))
|
||||
.pipe(opts.languages && opts.languages.length ? processNlsFiles({
|
||||
fileHeader: bundledFileHeader,
|
||||
languages: opts.languages
|
||||
}) : es.through())
|
||||
.pipe(gulp.dest(out));
|
||||
};
|
||||
}
|
||||
|
||||
export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => void {
|
||||
const esbuild = require('esbuild') as typeof import('esbuild');
|
||||
const sourceMappingURL = sourceMapBaseUrl ? ((f: any) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined;
|
||||
|
||||
return cb => {
|
||||
const cssnano = require('cssnano') as typeof import('cssnano');
|
||||
const postcss = require('gulp-postcss') as typeof import('gulp-postcss');
|
||||
const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps');
|
||||
|
||||
const jsFilter = filter('**/*.js', { restore: true });
|
||||
const cssFilter = filter('**/*.css', { restore: true });
|
||||
|
||||
pump(
|
||||
gulp.src([src + '/**', '!' + src + '/**/*.map']),
|
||||
jsFilter,
|
||||
sourcemaps.init({ loadMaps: true }),
|
||||
es.map((f: any, cb) => {
|
||||
esbuild.build({
|
||||
entryPoints: [f.path],
|
||||
minify: true,
|
||||
sourcemap: 'external',
|
||||
outdir: '.',
|
||||
platform: 'node',
|
||||
target: ['esnext'],
|
||||
write: false
|
||||
}).then(res => {
|
||||
const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path))!;
|
||||
const sourceMapFile = res.outputFiles.find(f => /\.js\.map$/.test(f.path))!;
|
||||
|
||||
f.contents = Buffer.from(jsFile.contents);
|
||||
f.sourceMap = JSON.parse(sourceMapFile.text);
|
||||
|
||||
cb(undefined, f);
|
||||
}, cb);
|
||||
}),
|
||||
jsFilter.restore,
|
||||
cssFilter,
|
||||
postcss([cssnano({ preset: 'default' })]),
|
||||
cssFilter.restore,
|
||||
(<any>sourcemaps).mapSources((sourcePath: string) => {
|
||||
if (sourcePath === 'bootstrap-fork.js') {
|
||||
return 'bootstrap-fork.orig.js';
|
||||
}
|
||||
|
||||
return sourcePath;
|
||||
}),
|
||||
sourcemaps.write('./', {
|
||||
sourceMappingURL,
|
||||
sourceRoot: undefined,
|
||||
includeContent: true,
|
||||
addComment: true
|
||||
} as any),
|
||||
gulp.dest(src + '-min'),
|
||||
(err: any) => cb(err));
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as tss from './treeshaking';
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, '../../');
|
||||
const SRC_DIR = path.join(REPO_ROOT, 'src');
|
||||
|
||||
let dirCache: { [dir: string]: boolean; } = {};
|
||||
|
||||
function writeFile(filePath: string, contents: Buffer | string): void {
|
||||
function ensureDirs(dirPath: string): void {
|
||||
if (dirCache[dirPath]) {
|
||||
return;
|
||||
}
|
||||
dirCache[dirPath] = true;
|
||||
|
||||
ensureDirs(path.dirname(dirPath));
|
||||
if (fs.existsSync(dirPath)) {
|
||||
return;
|
||||
}
|
||||
fs.mkdirSync(dirPath);
|
||||
}
|
||||
ensureDirs(path.dirname(filePath));
|
||||
fs.writeFileSync(filePath, contents);
|
||||
}
|
||||
|
||||
export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: string }): void {
|
||||
const ts = require('typescript') as typeof import('typescript');
|
||||
|
||||
const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.monaco.json')).toString());
|
||||
let compilerOptions: { [key: string]: any };
|
||||
if (tsConfig.extends) {
|
||||
compilerOptions = Object.assign({}, require(path.join(options.sourcesRoot, tsConfig.extends)).compilerOptions, tsConfig.compilerOptions);
|
||||
delete tsConfig.extends;
|
||||
} else {
|
||||
compilerOptions = tsConfig.compilerOptions;
|
||||
}
|
||||
tsConfig.compilerOptions = compilerOptions;
|
||||
|
||||
compilerOptions.noEmit = false;
|
||||
compilerOptions.noUnusedLocals = false;
|
||||
compilerOptions.preserveConstEnums = false;
|
||||
compilerOptions.declaration = false;
|
||||
compilerOptions.moduleResolution = ts.ModuleResolutionKind.Classic;
|
||||
|
||||
|
||||
options.compilerOptions = compilerOptions;
|
||||
|
||||
console.log(`Running tree shaker with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`);
|
||||
|
||||
// Take the extra included .d.ts files from `tsconfig.monaco.json`
|
||||
options.typings = (<string[]>tsConfig.include).filter(includedFile => /\.d\.ts$/.test(includedFile));
|
||||
|
||||
// Add extra .d.ts files from `node_modules/@types/`
|
||||
if (Array.isArray(options.compilerOptions?.types)) {
|
||||
options.compilerOptions.types.forEach((type: string) => {
|
||||
options.typings.push(`../node_modules/@types/${type}/index.d.ts`);
|
||||
});
|
||||
}
|
||||
|
||||
let result = tss.shake(options);
|
||||
for (let fileName in result) {
|
||||
if (result.hasOwnProperty(fileName)) {
|
||||
writeFile(path.join(options.destRoot, fileName), result[fileName]);
|
||||
}
|
||||
}
|
||||
let copied: { [fileName: string]: boolean; } = {};
|
||||
const copyFile = (fileName: string) => {
|
||||
if (copied[fileName]) {
|
||||
return;
|
||||
}
|
||||
copied[fileName] = true;
|
||||
const srcPath = path.join(options.sourcesRoot, fileName);
|
||||
const dstPath = path.join(options.destRoot, fileName);
|
||||
writeFile(dstPath, fs.readFileSync(srcPath));
|
||||
};
|
||||
const writeOutputFile = (fileName: string, contents: string | Buffer) => {
|
||||
writeFile(path.join(options.destRoot, fileName), contents);
|
||||
};
|
||||
for (let fileName in result) {
|
||||
if (result.hasOwnProperty(fileName)) {
|
||||
const fileContents = result[fileName];
|
||||
const info = ts.preProcessFile(fileContents);
|
||||
|
||||
for (let i = info.importedFiles.length - 1; i >= 0; i--) {
|
||||
const importedFileName = info.importedFiles[i].fileName;
|
||||
|
||||
let importedFilePath: string;
|
||||
if (/^vs\/css!/.test(importedFileName)) {
|
||||
importedFilePath = importedFileName.substr('vs/css!'.length) + '.css';
|
||||
} else {
|
||||
importedFilePath = importedFileName;
|
||||
}
|
||||
if (/(^\.\/)|(^\.\.\/)/.test(importedFilePath)) {
|
||||
importedFilePath = path.join(path.dirname(fileName), importedFilePath);
|
||||
}
|
||||
|
||||
if (/\.css$/.test(importedFilePath)) {
|
||||
transportCSS(importedFilePath, copyFile, writeOutputFile);
|
||||
} else {
|
||||
if (fs.existsSync(path.join(options.sourcesRoot, importedFilePath + '.js'))) {
|
||||
copyFile(importedFilePath + '.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete tsConfig.compilerOptions.moduleResolution;
|
||||
writeOutputFile('tsconfig.json', JSON.stringify(tsConfig, null, '\t'));
|
||||
|
||||
[
|
||||
'vs/css.build.js',
|
||||
'vs/css.d.ts',
|
||||
'vs/css.js',
|
||||
'vs/loader.js',
|
||||
'vs/nls.build.js',
|
||||
'vs/nls.d.ts',
|
||||
'vs/nls.js',
|
||||
'vs/nls.mock.ts',
|
||||
].forEach(copyFile);
|
||||
}
|
||||
|
||||
export interface IOptions2 {
|
||||
srcFolder: string;
|
||||
outFolder: string;
|
||||
outResourcesFolder: string;
|
||||
ignores: string[];
|
||||
renames: { [filename: string]: string; };
|
||||
}
|
||||
|
||||
export function createESMSourcesAndResources2(options: IOptions2): void {
|
||||
const ts = require('typescript') as typeof import('typescript');
|
||||
|
||||
const SRC_FOLDER = path.join(REPO_ROOT, options.srcFolder);
|
||||
const OUT_FOLDER = path.join(REPO_ROOT, options.outFolder);
|
||||
const OUT_RESOURCES_FOLDER = path.join(REPO_ROOT, options.outResourcesFolder);
|
||||
|
||||
const getDestAbsoluteFilePath = (file: string): string => {
|
||||
let dest = options.renames[file.replace(/\\/g, '/')] || file;
|
||||
if (dest === 'tsconfig.json') {
|
||||
return path.join(OUT_FOLDER, `tsconfig.json`);
|
||||
}
|
||||
if (/\.ts$/.test(dest)) {
|
||||
return path.join(OUT_FOLDER, dest);
|
||||
}
|
||||
return path.join(OUT_RESOURCES_FOLDER, dest);
|
||||
};
|
||||
|
||||
const allFiles = walkDirRecursive(SRC_FOLDER);
|
||||
for (const file of allFiles) {
|
||||
|
||||
if (options.ignores.indexOf(file.replace(/\\/g, '/')) >= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file === 'tsconfig.json') {
|
||||
const tsConfig = JSON.parse(fs.readFileSync(path.join(SRC_FOLDER, file)).toString());
|
||||
tsConfig.compilerOptions.module = 'es6';
|
||||
tsConfig.compilerOptions.outDir = path.join(path.relative(OUT_FOLDER, OUT_RESOURCES_FOLDER), 'vs').replace(/\\/g, '/');
|
||||
write(getDestAbsoluteFilePath(file), JSON.stringify(tsConfig, null, '\t'));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/\.d\.ts$/.test(file) || /\.css$/.test(file) || /\.js$/.test(file) || /\.ttf$/.test(file)) {
|
||||
// Transport the files directly
|
||||
write(getDestAbsoluteFilePath(file), fs.readFileSync(path.join(SRC_FOLDER, file)));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/\.ts$/.test(file)) {
|
||||
// Transform the .ts file
|
||||
let fileContents = fs.readFileSync(path.join(SRC_FOLDER, file)).toString();
|
||||
|
||||
const info = ts.preProcessFile(fileContents);
|
||||
|
||||
for (let i = info.importedFiles.length - 1; i >= 0; i--) {
|
||||
const importedFilename = info.importedFiles[i].fileName;
|
||||
const pos = info.importedFiles[i].pos;
|
||||
const end = info.importedFiles[i].end;
|
||||
|
||||
let importedFilepath: string;
|
||||
if (/^vs\/css!/.test(importedFilename)) {
|
||||
importedFilepath = importedFilename.substr('vs/css!'.length) + '.css';
|
||||
} else {
|
||||
importedFilepath = importedFilename;
|
||||
}
|
||||
if (/(^\.\/)|(^\.\.\/)/.test(importedFilepath)) {
|
||||
importedFilepath = path.join(path.dirname(file), importedFilepath);
|
||||
}
|
||||
|
||||
let relativePath: string;
|
||||
if (importedFilepath === path.dirname(file).replace(/\\/g, '/')) {
|
||||
relativePath = '../' + path.basename(path.dirname(file));
|
||||
} else if (importedFilepath === path.dirname(path.dirname(file)).replace(/\\/g, '/')) {
|
||||
relativePath = '../../' + path.basename(path.dirname(path.dirname(file)));
|
||||
} else {
|
||||
relativePath = path.relative(path.dirname(file), importedFilepath);
|
||||
}
|
||||
relativePath = relativePath.replace(/\\/g, '/');
|
||||
if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
|
||||
relativePath = './' + relativePath;
|
||||
}
|
||||
fileContents = (
|
||||
fileContents.substring(0, pos + 1)
|
||||
+ relativePath
|
||||
+ fileContents.substring(end + 1)
|
||||
);
|
||||
}
|
||||
|
||||
fileContents = fileContents.replace(/import ([a-zA-z0-9]+) = require\(('[^']+')\);/g, function (_, m1, m2) {
|
||||
return `import * as ${m1} from ${m2};`;
|
||||
});
|
||||
|
||||
write(getDestAbsoluteFilePath(file), fileContents);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`UNKNOWN FILE: ${file}`);
|
||||
}
|
||||
|
||||
|
||||
function walkDirRecursive(dir: string): string[] {
|
||||
if (dir.charAt(dir.length - 1) !== '/' || dir.charAt(dir.length - 1) !== '\\') {
|
||||
dir += '/';
|
||||
}
|
||||
let result: string[] = [];
|
||||
_walkDirRecursive(dir, result, dir.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
function _walkDirRecursive(dir: string, result: string[], trimPos: number): void {
|
||||
const files = fs.readdirSync(dir);
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = path.join(dir, files[i]);
|
||||
if (fs.statSync(file).isDirectory()) {
|
||||
_walkDirRecursive(file, result, trimPos);
|
||||
} else {
|
||||
result.push(file.substr(trimPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function write(absoluteFilePath: string, contents: string | Buffer): void {
|
||||
if (/(\.ts$)|(\.js$)/.test(absoluteFilePath)) {
|
||||
contents = toggleComments(contents.toString());
|
||||
}
|
||||
writeFile(absoluteFilePath, contents);
|
||||
|
||||
function toggleComments(fileContents: string): string {
|
||||
let lines = fileContents.split(/\r\n|\r|\n/);
|
||||
let mode = 0;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
if (mode === 0) {
|
||||
if (/\/\/ ESM-comment-begin/.test(line)) {
|
||||
mode = 1;
|
||||
continue;
|
||||
}
|
||||
if (/\/\/ ESM-uncomment-begin/.test(line)) {
|
||||
mode = 2;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode === 1) {
|
||||
if (/\/\/ ESM-comment-end/.test(line)) {
|
||||
mode = 0;
|
||||
continue;
|
||||
}
|
||||
lines[i] = '// ' + line;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode === 2) {
|
||||
if (/\/\/ ESM-uncomment-end/.test(line)) {
|
||||
mode = 0;
|
||||
continue;
|
||||
}
|
||||
lines[i] = line.replace(/^(\s*)\/\/ ?/, function (_, indent) {
|
||||
return indent;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function transportCSS(module: string, enqueue: (module: string) => void, write: (path: string, contents: string | Buffer) => void): boolean {
|
||||
|
||||
if (!/\.css/.test(module)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const filename = path.join(SRC_DIR, module);
|
||||
const fileContents = fs.readFileSync(filename).toString();
|
||||
const inlineResources = 'base64'; // see https://github.com/microsoft/monaco-editor/issues/148
|
||||
|
||||
const newContents = _rewriteOrInlineUrls(fileContents, inlineResources === 'base64');
|
||||
write(module, newContents);
|
||||
return true;
|
||||
|
||||
function _rewriteOrInlineUrls(contents: string, forceBase64: boolean): string {
|
||||
return _replaceURL(contents, (url) => {
|
||||
const fontMatch = url.match(/^(.*).ttf\?(.*)$/);
|
||||
if (fontMatch) {
|
||||
const relativeFontPath = `${fontMatch[1]}.ttf`; // trim the query parameter
|
||||
const fontPath = path.join(path.dirname(module), relativeFontPath);
|
||||
enqueue(fontPath);
|
||||
return relativeFontPath;
|
||||
}
|
||||
|
||||
const imagePath = path.join(path.dirname(module), url);
|
||||
const fileContents = fs.readFileSync(path.join(SRC_DIR, imagePath));
|
||||
const MIME = /\.svg$/.test(url) ? 'image/svg+xml' : 'image/png';
|
||||
let DATA = ';base64,' + fileContents.toString('base64');
|
||||
|
||||
if (!forceBase64 && /\.svg$/.test(url)) {
|
||||
// .svg => url encode as explained at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
|
||||
let newText = fileContents.toString()
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/</g, '%3C')
|
||||
.replace(/>/g, '%3E')
|
||||
.replace(/&/g, '%26')
|
||||
.replace(/#/g, '%23')
|
||||
.replace(/\s+/g, ' ');
|
||||
let encodedData = ',' + newText;
|
||||
if (encodedData.length < DATA.length) {
|
||||
DATA = encodedData;
|
||||
}
|
||||
}
|
||||
return '"data:' + MIME + DATA + '"';
|
||||
});
|
||||
}
|
||||
|
||||
function _replaceURL(contents: string, replacer: (url: string) => string): string {
|
||||
// Use ")" as the terminator as quotes are oftentimes not used at all
|
||||
return contents.replace(/url\(\s*([^\)]+)\s*\)?/g, (_: string, ...matches: string[]) => {
|
||||
let url = matches[0];
|
||||
// Eliminate starting quotes (the initial whitespace is not captured)
|
||||
if (url.charAt(0) === '"' || url.charAt(0) === '\'') {
|
||||
url = url.substring(1);
|
||||
}
|
||||
// The ending whitespace is captured
|
||||
while (url.length > 0 && (url.charAt(url.length - 1) === ' ' || url.charAt(url.length - 1) === '\t')) {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
// Eliminate ending quotes
|
||||
if (url.charAt(url.length - 1) === '"' || url.charAt(url.length - 1) === '\'') {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
|
||||
if (!_startsWith(url, 'data:') && !_startsWith(url, 'http://') && !_startsWith(url, 'https://')) {
|
||||
url = replacer(url);
|
||||
}
|
||||
|
||||
return 'url(' + url + ')';
|
||||
});
|
||||
}
|
||||
|
||||
function _startsWith(haystack: string, needle: string): boolean {
|
||||
return haystack.length >= needle.length && haystack.substr(0, needle.length) === needle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.62.0",
|
||||
"distro": "68b7698bb44bb140dfd35df9825ea6825edf87af",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "./out/main",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"test-browser": "node test/unit/browser/index.js",
|
||||
"preinstall": "node build/npm/preinstall.js",
|
||||
"postinstall": "node build/npm/postinstall.js",
|
||||
"compile": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile",
|
||||
"watch": "npm-run-all -lp watch-client watch-extensions",
|
||||
"watchd": "deemon yarn watch",
|
||||
"watch-webd": "deemon yarn watch-web",
|
||||
"kill-watchd": "deemon --kill yarn watch",
|
||||
"kill-watch-webd": "deemon --kill yarn watch-web",
|
||||
"restart-watchd": "deemon --restart yarn watch",
|
||||
"restart-watch-webd": "deemon --restart yarn watch-web",
|
||||
"watch-client": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-client",
|
||||
"watch-clientd": "deemon yarn watch-client",
|
||||
"kill-watch-clientd": "deemon --kill yarn watch-client",
|
||||
"watch-extensions": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media",
|
||||
"watch-extensionsd": "deemon yarn watch-extensions",
|
||||
"kill-watch-extensionsd": "deemon --kill yarn watch-extensions",
|
||||
"mocha": "mocha test/unit/node/all.js --delay",
|
||||
"precommit": "node build/hygiene.js",
|
||||
"gulp": "node --max_old_space_size=8192 ./node_modules/gulp/bin/gulp.js",
|
||||
"electron": "node build/lib/electron",
|
||||
"7z": "7z",
|
||||
"update-grammars": "node build/npm/update-all-grammars.js",
|
||||
"update-localization-extension": "node build/npm/update-localization-extension.js",
|
||||
"smoketest": "cd test/smoke && yarn compile && node test/index.js",
|
||||
"smoketest-no-compile": "cd test/smoke && node test/index.js",
|
||||
"download-builtin-extensions": "node build/lib/builtInExtensions.js",
|
||||
"download-builtin-extensions-cg": "node build/lib/builtInExtensionsCG.js",
|
||||
"monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit",
|
||||
"tsec-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.tsec.json",
|
||||
"vscode-dts-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.vscode-dts.json && node node_modules/tsec/bin/tsec -p src/tsconfig.vscode-proposed-dts.json",
|
||||
"valid-layers-check": "node build/lib/layersChecker.js",
|
||||
"update-distro": "node build/npm/update-distro.js",
|
||||
"web": "node resources/web/code-web.js",
|
||||
"compile-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-web",
|
||||
"watch-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-web",
|
||||
"eslint": "node build/eslint",
|
||||
"playwright-install": "node build/azure-pipelines/common/installPlaywright.js",
|
||||
"compile-build": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-build",
|
||||
"compile-extensions-build": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-extensions-build",
|
||||
"minify-vscode": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode",
|
||||
"minify-vscode-reh": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode-reh",
|
||||
"minify-vscode-reh-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode-reh-web",
|
||||
"hygiene": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js hygiene",
|
||||
"core-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js core-ci",
|
||||
"extensions-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js extensions-ci"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/applicationinsights-web": "^2.6.4",
|
||||
"@parcel/watcher": "2.0.0",
|
||||
"@vscode/sqlite3": "4.0.12",
|
||||
"@vscode/vscode-languagedetection": "1.0.21",
|
||||
"applicationinsights": "1.0.8",
|
||||
"chokidar": "3.5.1",
|
||||
"graceful-fs": "4.2.6",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
"https-proxy-agent": "^2.2.3",
|
||||
"iconv-lite-umd": "0.6.8",
|
||||
"jschardet": "3.0.0",
|
||||
"keytar": "7.2.0",
|
||||
"minimist": "^1.2.5",
|
||||
"native-is-elevated": "0.4.3",
|
||||
"native-keymap": "3.0.1",
|
||||
"native-watchdog": "1.3.0",
|
||||
"node-pty": "0.11.0-beta7",
|
||||
"spdlog": "^0.13.0",
|
||||
"sudo-prompt": "9.2.1",
|
||||
"tas-client-umd": "0.1.4",
|
||||
"v8-inspect-profiler": "^0.0.22",
|
||||
"vscode-nsfw": "2.1.8",
|
||||
"vscode-oniguruma": "1.5.1",
|
||||
"vscode-proxy-agent": "^0.11.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-ripgrep": "^1.12.1",
|
||||
"vscode-textmate": "5.4.1",
|
||||
"xterm": "4.15.0-beta.10",
|
||||
"xterm-addon-search": "0.9.0-beta.5",
|
||||
"xterm-addon-serialize": "0.7.0-beta.2",
|
||||
"xterm-addon-unicode11": "0.3.0",
|
||||
"xterm-addon-webgl": "0.12.0-beta.15",
|
||||
"xterm-headless": "4.15.0-beta.10",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"7zip": "0.0.6",
|
||||
"@types/applicationinsights": "0.20.0",
|
||||
"@types/chokidar": "2.1.3",
|
||||
"@types/cookie": "^0.3.3",
|
||||
"@types/copy-webpack-plugin": "^6.0.3",
|
||||
"@types/cssnano": "^4.0.0",
|
||||
"@types/debug": "4.1.5",
|
||||
"@types/graceful-fs": "4.1.2",
|
||||
"@types/gulp-postcss": "^8.0.0",
|
||||
"@types/http-proxy-agent": "^2.0.1",
|
||||
"@types/keytar": "^4.4.0",
|
||||
"@types/minimist": "^1.2.1",
|
||||
"@types/mocha": "^8.2.0",
|
||||
"@types/node": "14.x",
|
||||
"@types/sinon": "^10.0.2",
|
||||
"@types/sinon-test": "^2.4.2",
|
||||
"@types/trusted-types": "^1.0.6",
|
||||
"@types/vscode-windows-registry": "^1.0.0",
|
||||
"@types/webpack": "^4.41.25",
|
||||
"@types/wicg-file-system-access": "^2020.9.2",
|
||||
"@types/windows-foreground-love": "^0.3.0",
|
||||
"@types/windows-mutex": "^0.4.0",
|
||||
"@types/windows-process-tree": "^0.2.0",
|
||||
"@types/winreg": "^1.2.30",
|
||||
"@types/yauzl": "^2.9.1",
|
||||
"@types/yazl": "^2.4.2",
|
||||
"@typescript-eslint/eslint-plugin": "3.2.0",
|
||||
"@typescript-eslint/parser": "^3.3.0",
|
||||
"ansi-colors": "^3.2.3",
|
||||
"asar": "^3.0.3",
|
||||
"chromium-pickle-js": "^0.2.0",
|
||||
"copy-webpack-plugin": "^6.0.3",
|
||||
"cson-parser": "^1.3.3",
|
||||
"css-loader": "^3.2.0",
|
||||
"cssnano": "^4.1.11",
|
||||
"debounce": "^1.0.0",
|
||||
"deemon": "^1.4.0",
|
||||
"electron": "13.5.1",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-plugin-header": "3.1.1",
|
||||
"eslint-plugin-jsdoc": "^19.1.0",
|
||||
"event-stream": "3.3.4",
|
||||
"fancy-log": "^1.3.3",
|
||||
"fast-plist": "0.1.2",
|
||||
"file-loader": "^4.2.0",
|
||||
"glob": "^5.0.13",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-atom-electron": "1.32.0",
|
||||
"gulp-azure-storage": "^0.11.1",
|
||||
"gulp-bom": "^3.0.0",
|
||||
"gulp-buffer": "0.0.2",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-eslint": "^5.0.0",
|
||||
"gulp-filter": "^5.1.0",
|
||||
"gulp-flatmap": "^1.0.2",
|
||||
"gulp-gunzip": "^1.0.0",
|
||||
"gulp-gzip": "^1.4.2",
|
||||
"gulp-json-editor": "^2.5.0",
|
||||
"gulp-plumber": "^1.2.0",
|
||||
"gulp-postcss": "^9.0.0",
|
||||
"gulp-remote-retry-src": "^0.6.0",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-replace": "^0.5.4",
|
||||
"gulp-shell": "^0.6.5",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"gulp-tsb": "4.0.6",
|
||||
"gulp-untar": "^0.0.7",
|
||||
"gulp-vinyl-zip": "^2.1.2",
|
||||
"husky": "^0.13.1",
|
||||
"innosetup": "6.0.5",
|
||||
"is": "^3.1.0",
|
||||
"istanbul-lib-coverage": "^3.0.0",
|
||||
"istanbul-lib-instrument": "^4.0.0",
|
||||
"istanbul-lib-report": "^3.0.0",
|
||||
"istanbul-lib-source-maps": "^4.0.0",
|
||||
"istanbul-reports": "^3.0.0",
|
||||
"jsdom-no-contextify": "^3.1.0",
|
||||
"lazy.js": "^0.4.2",
|
||||
"merge-options": "^1.0.1",
|
||||
"mime": "^1.4.1",
|
||||
"minimatch": "^3.0.4",
|
||||
"minimist": "^1.2.5",
|
||||
"mkdirp": "^1.0.4",
|
||||
"mocha": "^8.2.1",
|
||||
"mocha-junit-reporter": "^2.0.0",
|
||||
"mocha-multi-reporters": "^1.5.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"opn": "^6.0.0",
|
||||
"optimist": "0.3.5",
|
||||
"p-all": "^1.0.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"playwright": "1.15.0",
|
||||
"pump": "^1.0.1",
|
||||
"queue": "3.0.6",
|
||||
"rcedit": "^1.1.0",
|
||||
"request": "^2.85.0",
|
||||
"rimraf": "^2.2.8",
|
||||
"sinon": "^11.1.1",
|
||||
"sinon-test": "^3.1.0",
|
||||
"source-map": "0.6.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"style-loader": "^1.0.0",
|
||||
"ts-loader": "^9.2.3",
|
||||
"tsec": "0.1.4",
|
||||
"typescript": "^4.5.0-dev.20211021",
|
||||
"typescript-formatter": "7.1.0",
|
||||
"underscore": "^1.12.1",
|
||||
"util": "^0.12.4",
|
||||
"vinyl": "^2.0.0",
|
||||
"vinyl-fs": "^3.0.0",
|
||||
"vscode-debugprotocol": "1.48.0",
|
||||
"vscode-nls-dev": "^3.3.1",
|
||||
"vscode-telemetry-extractor": "^1.8.0",
|
||||
"webpack": "^5.42.0",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"webpack-stream": "^6.1.2",
|
||||
"xml2js": "^0.4.17",
|
||||
"yaserver": "^0.2.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/vscode.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/microsoft/vscode/issues"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"vscode-windows-registry": "1.0.3",
|
||||
"windows-foreground-love": "0.4.0",
|
||||
"windows-mutex": "0.4.1",
|
||||
"windows-process-tree": "^0.3.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"elliptic": "^6.5.3",
|
||||
"nwmatcher": "^1.4.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------------------------------
|
||||
* Please make sure to make edits in the .ts file at https://github.com/microsoft/vscode-loader/
|
||||
*---------------------------------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------------------------------
|
||||
*---------------------------------------------------------------------------------------------
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
var _cssPluginGlobal = this;
|
||||
var CSSBuildLoaderPlugin;
|
||||
(function (CSSBuildLoaderPlugin) {
|
||||
var global = (_cssPluginGlobal || {});
|
||||
/**
|
||||
* Known issue:
|
||||
* - In IE there is no way to know if the CSS file loaded successfully or not.
|
||||
*/
|
||||
var BrowserCSSLoader = /** @class */ (function () {
|
||||
function BrowserCSSLoader() {
|
||||
this._pendingLoads = 0;
|
||||
}
|
||||
BrowserCSSLoader.prototype.attachListeners = function (name, linkNode, callback, errorback) {
|
||||
var unbind = function () {
|
||||
linkNode.removeEventListener('load', loadEventListener);
|
||||
linkNode.removeEventListener('error', errorEventListener);
|
||||
};
|
||||
var loadEventListener = function (e) {
|
||||
unbind();
|
||||
callback();
|
||||
};
|
||||
var errorEventListener = function (e) {
|
||||
unbind();
|
||||
errorback(e);
|
||||
};
|
||||
linkNode.addEventListener('load', loadEventListener);
|
||||
linkNode.addEventListener('error', errorEventListener);
|
||||
};
|
||||
BrowserCSSLoader.prototype._onLoad = function (name, callback) {
|
||||
this._pendingLoads--;
|
||||
callback();
|
||||
};
|
||||
BrowserCSSLoader.prototype._onLoadError = function (name, errorback, err) {
|
||||
this._pendingLoads--;
|
||||
errorback(err);
|
||||
};
|
||||
BrowserCSSLoader.prototype._insertLinkNode = function (linkNode) {
|
||||
this._pendingLoads++;
|
||||
var head = document.head || document.getElementsByTagName('head')[0];
|
||||
var other = head.getElementsByTagName('link') || head.getElementsByTagName('script');
|
||||
if (other.length > 0) {
|
||||
head.insertBefore(linkNode, other[other.length - 1]);
|
||||
}
|
||||
else {
|
||||
head.appendChild(linkNode);
|
||||
}
|
||||
};
|
||||
BrowserCSSLoader.prototype.createLinkTag = function (name, cssUrl, externalCallback, externalErrorback) {
|
||||
var _this = this;
|
||||
var linkNode = document.createElement('link');
|
||||
linkNode.setAttribute('rel', 'stylesheet');
|
||||
linkNode.setAttribute('type', 'text/css');
|
||||
linkNode.setAttribute('data-name', name);
|
||||
var callback = function () { return _this._onLoad(name, externalCallback); };
|
||||
var errorback = function (err) { return _this._onLoadError(name, externalErrorback, err); };
|
||||
this.attachListeners(name, linkNode, callback, errorback);
|
||||
linkNode.setAttribute('href', cssUrl);
|
||||
return linkNode;
|
||||
};
|
||||
BrowserCSSLoader.prototype._linkTagExists = function (name, cssUrl) {
|
||||
var i, len, nameAttr, hrefAttr, links = document.getElementsByTagName('link');
|
||||
for (i = 0, len = links.length; i < len; i++) {
|
||||
nameAttr = links[i].getAttribute('data-name');
|
||||
hrefAttr = links[i].getAttribute('href');
|
||||
if (nameAttr === name || hrefAttr === cssUrl) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
BrowserCSSLoader.prototype.load = function (name, cssUrl, externalCallback, externalErrorback) {
|
||||
if (this._linkTagExists(name, cssUrl)) {
|
||||
externalCallback();
|
||||
return;
|
||||
}
|
||||
var linkNode = this.createLinkTag(name, cssUrl, externalCallback, externalErrorback);
|
||||
this._insertLinkNode(linkNode);
|
||||
};
|
||||
return BrowserCSSLoader;
|
||||
}());
|
||||
var NodeCSSLoader = /** @class */ (function () {
|
||||
function NodeCSSLoader() {
|
||||
this.fs = require.nodeRequire('fs');
|
||||
}
|
||||
NodeCSSLoader.prototype.load = function (name, cssUrl, externalCallback, externalErrorback) {
|
||||
var contents = this.fs.readFileSync(cssUrl, 'utf8');
|
||||
// Remove BOM
|
||||
if (contents.charCodeAt(0) === NodeCSSLoader.BOM_CHAR_CODE) {
|
||||
contents = contents.substring(1);
|
||||
}
|
||||
externalCallback(contents);
|
||||
};
|
||||
NodeCSSLoader.BOM_CHAR_CODE = 65279;
|
||||
return NodeCSSLoader;
|
||||
}());
|
||||
// ------------------------------ Finally, the plugin
|
||||
var CSSPlugin = /** @class */ (function () {
|
||||
function CSSPlugin(cssLoader) {
|
||||
this.cssLoader = cssLoader;
|
||||
}
|
||||
CSSPlugin.prototype.load = function (name, req, load, config) {
|
||||
config = config || {};
|
||||
var myConfig = config['vs/css'] || {};
|
||||
global.inlineResources = myConfig.inlineResources;
|
||||
global.inlineResourcesLimit = myConfig.inlineResourcesLimit || 5000;
|
||||
var cssUrl = req.toUrl(name + '.css');
|
||||
this.cssLoader.load(name, cssUrl, function (contents) {
|
||||
// Contents has the CSS file contents if we are in a build
|
||||
if (config.isBuild) {
|
||||
CSSPlugin.BUILD_MAP[name] = contents;
|
||||
CSSPlugin.BUILD_PATH_MAP[name] = cssUrl;
|
||||
}
|
||||
load({});
|
||||
}, function (err) {
|
||||
if (typeof load.error === 'function') {
|
||||
load.error('Could not find ' + cssUrl + ' or it was empty');
|
||||
}
|
||||
});
|
||||
};
|
||||
CSSPlugin.prototype.write = function (pluginName, moduleName, write) {
|
||||
// getEntryPoint is a Monaco extension to r.js
|
||||
var entryPoint = write.getEntryPoint();
|
||||
// r.js destroys the context of this plugin between calling 'write' and 'writeFile'
|
||||
// so the only option at this point is to leak the data to a global
|
||||
global.cssPluginEntryPoints = global.cssPluginEntryPoints || {};
|
||||
global.cssPluginEntryPoints[entryPoint] = global.cssPluginEntryPoints[entryPoint] || [];
|
||||
global.cssPluginEntryPoints[entryPoint].push({
|
||||
moduleName: moduleName,
|
||||
contents: CSSPlugin.BUILD_MAP[moduleName],
|
||||
fsPath: CSSPlugin.BUILD_PATH_MAP[moduleName],
|
||||
});
|
||||
write.asModule(pluginName + '!' + moduleName, 'define([\'vs/css!' + entryPoint + '\'], {});');
|
||||
};
|
||||
CSSPlugin.prototype.writeFile = function (pluginName, moduleName, req, write, config) {
|
||||
if (global.cssPluginEntryPoints && global.cssPluginEntryPoints.hasOwnProperty(moduleName)) {
|
||||
var fileName = req.toUrl(moduleName + '.css');
|
||||
var contents = [
|
||||
'/*---------------------------------------------------------',
|
||||
' * Copyright (c) Microsoft Corporation. All rights reserved.',
|
||||
' *--------------------------------------------------------*/'
|
||||
], entries = global.cssPluginEntryPoints[moduleName];
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (global.inlineResources) {
|
||||
contents.push(Utilities.rewriteOrInlineUrls(entries[i].fsPath, entries[i].moduleName, moduleName, entries[i].contents, global.inlineResources === 'base64', global.inlineResourcesLimit));
|
||||
}
|
||||
else {
|
||||
contents.push(Utilities.rewriteUrls(entries[i].moduleName, moduleName, entries[i].contents));
|
||||
}
|
||||
}
|
||||
write(fileName, contents.join('\r\n'));
|
||||
}
|
||||
};
|
||||
CSSPlugin.prototype.getInlinedResources = function () {
|
||||
return global.cssInlinedResources || [];
|
||||
};
|
||||
CSSPlugin.BUILD_MAP = {};
|
||||
CSSPlugin.BUILD_PATH_MAP = {};
|
||||
return CSSPlugin;
|
||||
}());
|
||||
CSSBuildLoaderPlugin.CSSPlugin = CSSPlugin;
|
||||
var Utilities = /** @class */ (function () {
|
||||
function Utilities() {
|
||||
}
|
||||
Utilities.startsWith = function (haystack, needle) {
|
||||
return haystack.length >= needle.length && haystack.substr(0, needle.length) === needle;
|
||||
};
|
||||
/**
|
||||
* Find the path of a file.
|
||||
*/
|
||||
Utilities.pathOf = function (filename) {
|
||||
var lastSlash = filename.lastIndexOf('/');
|
||||
if (lastSlash !== -1) {
|
||||
return filename.substr(0, lastSlash + 1);
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
/**
|
||||
* A conceptual a + b for paths.
|
||||
* Takes into account if `a` contains a protocol.
|
||||
* Also normalizes the result: e.g.: a/b/ + ../c => a/c
|
||||
*/
|
||||
Utilities.joinPaths = function (a, b) {
|
||||
function findSlashIndexAfterPrefix(haystack, prefix) {
|
||||
if (Utilities.startsWith(haystack, prefix)) {
|
||||
return Math.max(prefix.length, haystack.indexOf('/', prefix.length));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
var aPathStartIndex = 0;
|
||||
aPathStartIndex = aPathStartIndex || findSlashIndexAfterPrefix(a, '//');
|
||||
aPathStartIndex = aPathStartIndex || findSlashIndexAfterPrefix(a, 'http://');
|
||||
aPathStartIndex = aPathStartIndex || findSlashIndexAfterPrefix(a, 'https://');
|
||||
function pushPiece(pieces, piece) {
|
||||
if (piece === './') {
|
||||
// Ignore
|
||||
return;
|
||||
}
|
||||
if (piece === '../') {
|
||||
var prevPiece = (pieces.length > 0 ? pieces[pieces.length - 1] : null);
|
||||
if (prevPiece && prevPiece === '/') {
|
||||
// Ignore
|
||||
return;
|
||||
}
|
||||
if (prevPiece && prevPiece !== '../') {
|
||||
// Pop
|
||||
pieces.pop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Push
|
||||
pieces.push(piece);
|
||||
}
|
||||
function push(pieces, path) {
|
||||
while (path.length > 0) {
|
||||
var slashIndex = path.indexOf('/');
|
||||
var piece = (slashIndex >= 0 ? path.substring(0, slashIndex + 1) : path);
|
||||
path = (slashIndex >= 0 ? path.substring(slashIndex + 1) : '');
|
||||
pushPiece(pieces, piece);
|
||||
}
|
||||
}
|
||||
var pieces = [];
|
||||
push(pieces, a.substr(aPathStartIndex));
|
||||
if (b.length > 0 && b.charAt(0) === '/') {
|
||||
pieces = [];
|
||||
}
|
||||
push(pieces, b);
|
||||
return a.substring(0, aPathStartIndex) + pieces.join('');
|
||||
};
|
||||
Utilities.commonPrefix = function (str1, str2) {
|
||||
var len = Math.min(str1.length, str2.length);
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (str1.charCodeAt(i) !== str2.charCodeAt(i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str1.substring(0, i);
|
||||
};
|
||||
Utilities.commonFolderPrefix = function (fromPath, toPath) {
|
||||
var prefix = Utilities.commonPrefix(fromPath, toPath);
|
||||
var slashIndex = prefix.lastIndexOf('/');
|
||||
if (slashIndex === -1) {
|
||||
return '';
|
||||
}
|
||||
return prefix.substring(0, slashIndex + 1);
|
||||
};
|
||||
Utilities.relativePath = function (fromPath, toPath) {
|
||||
if (Utilities.startsWith(toPath, '/') || Utilities.startsWith(toPath, 'http://') || Utilities.startsWith(toPath, 'https://')) {
|
||||
return toPath;
|
||||
}
|
||||
// Ignore common folder prefix
|
||||
var prefix = Utilities.commonFolderPrefix(fromPath, toPath);
|
||||
fromPath = fromPath.substr(prefix.length);
|
||||
toPath = toPath.substr(prefix.length);
|
||||
var upCount = fromPath.split('/').length;
|
||||
var result = '';
|
||||
for (var i = 1; i < upCount; i++) {
|
||||
result += '../';
|
||||
}
|
||||
return result + toPath;
|
||||
};
|
||||
Utilities._replaceURL = function (contents, replacer) {
|
||||
// Use ")" as the terminator as quotes are oftentimes not used at all
|
||||
return contents.replace(/url\(\s*([^\)]+)\s*\)?/g, function (_) {
|
||||
var matches = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
matches[_i - 1] = arguments[_i];
|
||||
}
|
||||
var url = matches[0];
|
||||
// Eliminate starting quotes (the initial whitespace is not captured)
|
||||
if (url.charAt(0) === '"' || url.charAt(0) === '\'') {
|
||||
url = url.substring(1);
|
||||
}
|
||||
// The ending whitespace is captured
|
||||
while (url.length > 0 && (url.charAt(url.length - 1) === ' ' || url.charAt(url.length - 1) === '\t')) {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
// Eliminate ending quotes
|
||||
if (url.charAt(url.length - 1) === '"' || url.charAt(url.length - 1) === '\'') {
|
||||
url = url.substring(0, url.length - 1);
|
||||
}
|
||||
if (!Utilities.startsWith(url, 'data:') && !Utilities.startsWith(url, 'http://') && !Utilities.startsWith(url, 'https://')) {
|
||||
url = replacer(url);
|
||||
}
|
||||
return 'url(' + url + ')';
|
||||
});
|
||||
};
|
||||
Utilities.rewriteUrls = function (originalFile, newFile, contents) {
|
||||
return this._replaceURL(contents, function (url) {
|
||||
var absoluteUrl = Utilities.joinPaths(Utilities.pathOf(originalFile), url);
|
||||
return Utilities.relativePath(newFile, absoluteUrl);
|
||||
});
|
||||
};
|
||||
Utilities.rewriteOrInlineUrls = function (originalFileFSPath, originalFile, newFile, contents, forceBase64, inlineByteLimit) {
|
||||
var fs = require.nodeRequire('fs');
|
||||
var path = require.nodeRequire('path');
|
||||
return this._replaceURL(contents, function (url) {
|
||||
if (/\.(svg|png)$/.test(url)) {
|
||||
var fsPath = path.join(path.dirname(originalFileFSPath), url);
|
||||
var fileContents = fs.readFileSync(fsPath);
|
||||
if (fileContents.length < inlineByteLimit) {
|
||||
global.cssInlinedResources = global.cssInlinedResources || [];
|
||||
var normalizedFSPath = fsPath.replace(/\\/g, '/');
|
||||
if (global.cssInlinedResources.indexOf(normalizedFSPath) >= 0) {
|
||||
// console.warn('CSS INLINING IMAGE AT ' + fsPath + ' MORE THAN ONCE. CONSIDER CONSOLIDATING CSS RULES');
|
||||
}
|
||||
global.cssInlinedResources.push(normalizedFSPath);
|
||||
var MIME = /\.svg$/.test(url) ? 'image/svg+xml' : 'image/png';
|
||||
var DATA = ';base64,' + fileContents.toString('base64');
|
||||
if (!forceBase64 && /\.svg$/.test(url)) {
|
||||
// .svg => url encode as explained at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
|
||||
var newText = fileContents.toString()
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/</g, '%3C')
|
||||
.replace(/>/g, '%3E')
|
||||
.replace(/&/g, '%26')
|
||||
.replace(/#/g, '%23')
|
||||
.replace(/\s+/g, ' ');
|
||||
var encodedData = ',' + newText;
|
||||
if (encodedData.length < DATA.length) {
|
||||
DATA = encodedData;
|
||||
}
|
||||
}
|
||||
return '"data:' + MIME + DATA + '"';
|
||||
}
|
||||
}
|
||||
var absoluteUrl = Utilities.joinPaths(Utilities.pathOf(originalFile), url);
|
||||
return Utilities.relativePath(newFile, absoluteUrl);
|
||||
});
|
||||
};
|
||||
return Utilities;
|
||||
}());
|
||||
CSSBuildLoaderPlugin.Utilities = Utilities;
|
||||
(function () {
|
||||
var cssLoader = null;
|
||||
var isElectron = (typeof process !== 'undefined' && typeof process.versions !== 'undefined' && typeof process.versions['electron'] !== 'undefined');
|
||||
if (typeof process !== 'undefined' && process.versions && !!process.versions.node && !isElectron) {
|
||||
cssLoader = new NodeCSSLoader();
|
||||
}
|
||||
else {
|
||||
cssLoader = new BrowserCSSLoader();
|
||||
}
|
||||
define('vs/css', new CSSPlugin(cssLoader));
|
||||
})();
|
||||
})(CSSBuildLoaderPlugin || (CSSBuildLoaderPlugin = {}));
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,49 @@
|
||||
# SITE-07 Monaco CSS 来源、压缩与样式回归
|
||||
|
||||
修改前 HEAD:23ac6f71284547a5e4dbf6cdbf0966f6cef49c87。
|
||||
|
||||
## 源码与结构
|
||||
|
||||
新增 css.ts 和 reproduce-css.ts,分开处理注册顺序、原始 CSS 运输/拼接配方与
|
||||
归档/锁/压缩验证。68 份样式从固定 VS Code commit 恢复,连同 3 个内联图片、
|
||||
字体、配方、锁和许可共 81 个 Git 成员验证 blob/SHA-256。原始 transportCSS
|
||||
函数由 AST 定位后在受限读取环境执行;每份准备样式均与 core ESM 产物相等。
|
||||
64 份原文不变,另外四份涉及字体查询参数、URL 引号及 PNG/SVG 内联。字体复制
|
||||
字节也与归档一致。此处 VM 是隔离辅助,不作为安全沙箱保证。
|
||||
|
||||
按实际 AMD 注册次序拼接,不能用模块名表的排列替代。原 CSS 插件生成的 70 个
|
||||
CRLF 分隔符转换为发布包实际 LF,再加原版本头,完整开发文件 114,942 字节精确
|
||||
匹配。这项发布换行归一化的具体原流水线位置尚未确认,因此记录为有证据的
|
||||
字节转换,不声称未经改造地重跑了整个上游发布命令。
|
||||
|
||||
## 工具链与兼容
|
||||
|
||||
cssnano 4.1.11 / PostCSS 7.0.35 按原 preset: default 压缩后,完整 72,052 字节
|
||||
产物匹配。复用 Yarn Classic 1.22.22:在新的忽略目录中按原始 lock 冻结安装,
|
||||
禁用安装脚本,锁内容保持一致;153 个依赖选择器、143 个版本均有原 registry
|
||||
integrity。没有改变项目依赖或根 yarn.lock。默认命令使用离线缓存,--fetch
|
||||
重新取回源归档并允许安装访问 registry。
|
||||
|
||||
最初隔离工具继承父项目 Chrome-only Browserslist,导致 transparent 被压成
|
||||
initial。固定历史默认目标后恢复全部字节,显式拒绝环境覆盖。历史 caniuse
|
||||
数据过期提示不通过更新数据消除。原 archive 的 LICENSE.txt 按 .gitattributes
|
||||
使用 CRLF,Git blob 为 LF;仅对该成员的 Git 身份检查转换,原许可全文保留。
|
||||
|
||||
站点 CSS 为 72,057 字节,精确保留现有五个头部 CRLF 差异;不改变运行代码、
|
||||
CSS/DOM hooks、worker 或资源 URL,没有扩大消费者最低浏览器要求。
|
||||
|
||||
## 验证、后续与回退
|
||||
|
||||
25/25 单元、严格 docs-tools 类型及 lint 通过;来源/完整开发文件/压缩文件的
|
||||
离线与联网复验通过。联网第一次遇到 codeload.github.com DNS ENOTFOUND,保留
|
||||
失败记录后重试。三引擎样式回归 3/3:明暗主题、布局、查找面板边界、字体载入
|
||||
与真实 codicon 字形、CSS/font HTTP、缩放及模型销毁。初始测试误把浅色背景
|
||||
写成纯白,核实原 colorRegistry 的 #fffffe 后修正预期,未改生产颜色。
|
||||
|
||||
详细环境/产物/报告指纹见[验证记录](../baselines/monaco-css-build-validation.json),
|
||||
维护入口见[Monaco README](../../scripts/site-vendor/monaco/README.md)。本批未改变
|
||||
站点 notices;完整原始 core TS 编译、其余内嵌来源和 SITE-07 其他许可交付范围
|
||||
继续开放,未以浏览器样式测试替代设备、SDK、远程 CI 或发布验收。
|
||||
|
||||
SITE-07 doing / VENDOR-06 open,199/265;Thumbnail 默认策略仍待答。本批单独
|
||||
本地提交,可回退新增脚本/基线/测试/文档;无推送、部署或发布。
|
||||
+1
-1
@@ -653,7 +653,7 @@
|
||||
- SITE-AI-DOCS-01: [记录](changes/2026-09-14-SITE-AI-DOCS-01-documentation-pipeline.md) [记录](baselines/documentation-pipeline-validation.json)
|
||||
- SITE-BUILD-01: [记录](changes/2026-09-14-SITE-BUILD-01-staged-builds.md) [记录](baselines/site-build-validation.json)
|
||||
- SITE-03: [记录](changes/2026-09-14-SITE-03-desktop-editor.md) [记录](baselines/site-editor-validation.json)
|
||||
- SITE-07: [记录](site-inventory.md) [记录](baselines/site-provenance.json) [记录](changes/2026-09-14-SITE-07-vendor-notices.md) [记录](baselines/site-notices-checkpoint.json) [记录](baselines/site-codicons-provenance.json) [记录](baselines/site-codicons-validation.json) [记录](changes/2026-09-15-SITE-07-codicons.md) [记录](baselines/vconsole-notices-provenance.json) [记录](baselines/vconsole-notices-validation.json) [记录](changes/2026-09-15-SITE-07-vconsole-notices.md) [记录](console-modernization.md) [记录](baselines/site-console-inventory.json) [记录](baselines/site-console-validation.json) [记录](changes/2026-09-15-SITE-07-console-baseline.md) [记录](baselines/console-feed-provenance.json) [记录](changes/2026-09-15-SITE-07-console-feed-source.md) [记录](baselines/console-commonjs-provenance.json) [记录](changes/2026-09-15-SITE-07-console-commonjs.md) [记录](baselines/console-esm-provenance.json) [记录](changes/2026-09-15-SITE-07-console-esm.md) [记录](baselines/console-embedded-notices.json) [记录](baselines/console-notices-validation.json) [记录](changes/2026-09-15-SITE-07-console-notices.md) [记录](baselines/console-embedded-sources.json) [记录](baselines/console-embedded-validation.json) [记录](changes/2026-09-15-SITE-07-console-embedded-sources.md) [记录](baselines/console-derived-attribution.json) [记录](baselines/console-derived-validation.json) [记录](changes/2026-09-15-SITE-07-console-derived-attribution.md) [记录](baselines/console-stackoverflow-provenance.json) [记录](baselines/console-stackoverflow-validation.json) [记录](changes/2026-09-15-SITE-07-console-stackoverflow.md) [记录](baselines/console-shallowequal-validation.json) [记录](changes/2026-09-15-SITE-07-console-shallowequal.md) [记录](console-notice-review.md) [记录](baselines/console-notice-review-validation.json) [记录](changes/2026-09-15-SITE-07-console-notice-review.md) [记录](baselines/monaco-typescript-provenance.json) [记录](baselines/monaco-typescript-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-typescript.md) [记录](baselines/monaco-languages-provenance.json) [记录](baselines/monaco-languages-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-languages.md) [记录](baselines/monaco-language-notices.json) [记录](baselines/monaco-language-notices-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-language-notices.md) [记录](baselines/monaco-modes-provenance.json) [记录](baselines/monaco-modes-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-modes.md) [记录](baselines/monaco-basic-provenance.json) [记录](baselines/monaco-basic-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-basic.md) [记录](baselines/monaco-core-origins-provenance.json) [记录](baselines/monaco-core-origins-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-origins.md) [记录](baselines/monaco-core-build-provenance.json) [记录](baselines/monaco-core-build-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-build.md) [记录](baselines/monaco-contributions-provenance.json) [记录](baselines/monaco-contributions-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-contributions.md)
|
||||
- SITE-07: [记录](site-inventory.md) [记录](baselines/site-provenance.json) [记录](changes/2026-09-14-SITE-07-vendor-notices.md) [记录](baselines/site-notices-checkpoint.json) [记录](baselines/site-codicons-provenance.json) [记录](baselines/site-codicons-validation.json) [记录](changes/2026-09-15-SITE-07-codicons.md) [记录](baselines/vconsole-notices-provenance.json) [记录](baselines/vconsole-notices-validation.json) [记录](changes/2026-09-15-SITE-07-vconsole-notices.md) [记录](console-modernization.md) [记录](baselines/site-console-inventory.json) [记录](baselines/site-console-validation.json) [记录](changes/2026-09-15-SITE-07-console-baseline.md) [记录](baselines/console-feed-provenance.json) [记录](changes/2026-09-15-SITE-07-console-feed-source.md) [记录](baselines/console-commonjs-provenance.json) [记录](changes/2026-09-15-SITE-07-console-commonjs.md) [记录](baselines/console-esm-provenance.json) [记录](changes/2026-09-15-SITE-07-console-esm.md) [记录](baselines/console-embedded-notices.json) [记录](baselines/console-notices-validation.json) [记录](changes/2026-09-15-SITE-07-console-notices.md) [记录](baselines/console-embedded-sources.json) [记录](baselines/console-embedded-validation.json) [记录](changes/2026-09-15-SITE-07-console-embedded-sources.md) [记录](baselines/console-derived-attribution.json) [记录](baselines/console-derived-validation.json) [记录](changes/2026-09-15-SITE-07-console-derived-attribution.md) [记录](baselines/console-stackoverflow-provenance.json) [记录](baselines/console-stackoverflow-validation.json) [记录](changes/2026-09-15-SITE-07-console-stackoverflow.md) [记录](baselines/console-shallowequal-validation.json) [记录](changes/2026-09-15-SITE-07-console-shallowequal.md) [记录](console-notice-review.md) [记录](baselines/console-notice-review-validation.json) [记录](changes/2026-09-15-SITE-07-console-notice-review.md) [记录](baselines/monaco-typescript-provenance.json) [记录](baselines/monaco-typescript-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-typescript.md) [记录](baselines/monaco-languages-provenance.json) [记录](baselines/monaco-languages-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-languages.md) [记录](baselines/monaco-language-notices.json) [记录](baselines/monaco-language-notices-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-language-notices.md) [记录](baselines/monaco-modes-provenance.json) [记录](baselines/monaco-modes-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-modes.md) [记录](baselines/monaco-basic-provenance.json) [记录](baselines/monaco-basic-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-basic.md) [记录](baselines/monaco-core-origins-provenance.json) [记录](baselines/monaco-core-origins-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-origins.md) [记录](baselines/monaco-core-build-provenance.json) [记录](baselines/monaco-core-build-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-core-build.md) [记录](baselines/monaco-contributions-provenance.json) [记录](baselines/monaco-contributions-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-contributions.md) [记录](baselines/monaco-css-build-provenance.json) [记录](baselines/monaco-css-build-validation.json) [记录](changes/2026-09-15-SITE-07-monaco-css.md)
|
||||
- EX-01: [记录](changes/2026-09-14-EX-01-react-consumer.md) [记录](baselines/react-consumer-validation.json) [记录](scripts/react-consumer.mjs)
|
||||
- EX-02: [记录](changes/2026-09-14-EX-02-vue-consumer.md) [记录](baselines/vue-consumer-validation.json) [记录](scripts/vue-consumer.mjs)
|
||||
- MOD-01: [记录](changes/2026-09-15-MOD-01-bun-evaluation.md) [记录](baselines/bun-install-validation.json) [记录](bun-evaluation.md)
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# 进度与证据
|
||||
|
||||
## SITE-07 Monaco CSS 来源与样式回归
|
||||
|
||||
68 份样式、3 个内联图片和字体按原配方恢复,81 个 Git 成员验证;显式记录
|
||||
70 个生成 CRLF 到发布 LF 的转换后,完整开发 CSS 匹配。历史 cssnano/PostCSS
|
||||
及冻结 Yarn 安装复现完整压缩 CSS,站点五个头部 CRLF 保留。25/25 单元、
|
||||
严格类型/lint、联网重试/离线复验和三引擎主题/字体/布局回归 3/3 通过。
|
||||
见[记录](changes/2026-09-15-SITE-07-monaco-css.md)。该换行归一化的原发布步骤
|
||||
尚未定位;其余内嵌来源与完整原始 core TS 编译仍开放。SITE-07/VENDOR-06
|
||||
保持未完结,199/265;Thumbnail 默认兼容策略仍待答。
|
||||
|
||||
|
||||
## SITE-07 Monaco 完整贡献模块装配
|
||||
|
||||
六个 npm 归档和 102 个 Git 成员支撑 88 个 TS 注册模块,原 RequireJS/Terser
|
||||
|
||||
+5
-2
@@ -655,11 +655,14 @@
|
||||
"refactor/changes/2026-09-15-SITE-07-monaco-core-build.md",
|
||||
"refactor/baselines/monaco-contributions-provenance.json",
|
||||
"refactor/baselines/monaco-contributions-validation.json",
|
||||
"refactor/changes/2026-09-15-SITE-07-monaco-contributions.md"
|
||||
"refactor/changes/2026-09-15-SITE-07-monaco-contributions.md",
|
||||
"refactor/baselines/monaco-css-build-provenance.json",
|
||||
"refactor/baselines/monaco-css-build-validation.json",
|
||||
"refactor/changes/2026-09-15-SITE-07-monaco-css.md"
|
||||
],
|
||||
"compatibleResolution": "Keep separate from owned TS migration. Verify source/version/diff and license notices before replacement; preserve API/CSS/worker URLs and run owning package tests.",
|
||||
"closureCriteria": "固定上游版本/内容差异、完整组件许可与分发 notices,兼容测试通过;仅当前上游许可证名称不足以关闭。",
|
||||
"workspaceState": "Monaco 0.30.1 remains byte-pinned, including its known CSS newline-only difference. Codicons 0.0.26, TypeScript 4.4.4 and language-service licenses are delivered. Three service workers, four modes and 76 basic-language bundles reproduce exactly; all 13 core JS minified outputs reproduce with locked esbuild 0.12.6 on Windows x64. Loader/header and css/nls source origins match fixed Git; two maps inventory 584 prepared-source entries and 549 different names. DOMPurify 2.3.1 and marked 3.0.2 have exact source adaptations and complete notice supplements; 85 site notices were verified by HTTP/mobile browser checks. Latest contribution check verifies six archives and 102 Git members, emits 88 TS registration modules and uses RequireJS 2.3.6/Terser 5.9.0 to reproduce the entire dev/min editor assembly, including core string-table entry, dependency injection, order, alias and map trailer. Latest units 23/23, strict type/lint and offline/network source checks pass; modes/tokenizer regressions pass 6/6 across three engines with 2523 token cases per engine. Earlier ten-locale editing/find 30/30 and diff-worker 3/3 evidence remains recorded separately. Original core TS compilation, CSS reproduction and remaining embedded-origin review stay open; this is not release approval or an exhaustive sanitizer audit."
|
||||
"workspaceState": "Monaco 0.30.1 remains byte-pinned, including its known CSS newline-only difference. Codicons 0.0.26, TypeScript 4.4.4 and language-service licenses are delivered. Three service workers, four modes and 76 basic-language bundles reproduce exactly; all 13 core JS minified outputs reproduce with locked esbuild 0.12.6 on Windows x64. Loader/header and css/nls source origins match fixed Git; two maps inventory 584 prepared-source entries and 549 different names. DOMPurify 2.3.1 and marked 3.0.2 have exact source adaptations and complete notice supplements; 85 site notices were verified by HTTP/mobile browser checks. Latest contribution check verifies six archives and 102 Git members, emits 88 TS registration modules and uses RequireJS 2.3.6/Terser 5.9.0 to reproduce the entire dev/min editor assembly, including core string-table entry, dependency injection, order, alias and map trailer. Latest units 23/23, strict type/lint and offline/network source checks pass; modes/tokenizer regressions pass 6/6 across three engines with 2523 token cases per engine. Earlier ten-locale editing/find 30/30 and diff-worker 3/3 evidence remains recorded separately. CSS now reproduces from 68 styles, three embedded images and the copied font, with 81 verified Git members. The archived transport/plugin recipes match every prepared ESM stylesheet; explicit normalization of 70 generated CRLF separators reproduces the entire development CSS. cssnano 4.1.11/PostCSS 7.0.35 reproduce complete minified CSS using isolated frozen Yarn installs (153 selectors/143 versions) and historical browser defaults. The site retains its five header CRLF differences. The exact upstream stage that normalized the 70 development separators is still unidentified. Latest units 25/25, strict type/lint and offline/network checks pass; new three-engine style/theme/font/resize regressions pass 3/3. Original core TS compilation and remaining embedded-origin review stay open; this is not release approval or an exhaustive sanitizer audit."
|
||||
},
|
||||
{
|
||||
"id": "VENDOR-07",
|
||||
|
||||
+4
-1
@@ -4537,7 +4537,10 @@
|
||||
"changes/2026-09-15-SITE-07-monaco-core-build.md",
|
||||
"baselines/monaco-contributions-provenance.json",
|
||||
"baselines/monaco-contributions-validation.json",
|
||||
"changes/2026-09-15-SITE-07-monaco-contributions.md"
|
||||
"changes/2026-09-15-SITE-07-monaco-contributions.md",
|
||||
"baselines/monaco-css-build-provenance.json",
|
||||
"baselines/monaco-css-build-validation.json",
|
||||
"changes/2026-09-15-SITE-07-monaco-css.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -277,3 +277,51 @@ foreign modules, missing/repeated/already-injected dependencies and false entry
|
||||
strings. Browser regressions exercise real diagnostics/formatting and all pinned
|
||||
tokenizer cases. This does not close original core TS compilation, CSS reproduction,
|
||||
remaining embedded-origin review, or the broader SITE-07 release requirements.
|
||||
|
||||
## CSS sources and historical compression
|
||||
|
||||
`reproduce-css.ts` separately covers all 68 core stylesheets. The AMD string table
|
||||
does not give their assembly order: `coreStyleOrder` follows actual registrations.
|
||||
81 fixed VS Code Git members include styles, three inline images, the codicon font,
|
||||
original transport/build recipes, package/lock and license. Original `transportCSS`
|
||||
is extracted syntactically from the verified recipe and executed with reads limited
|
||||
to verified inputs. It removes the font query, normalizes URL quotes and embeds the
|
||||
images. Every prepared result equals the corresponding core ESM archive member;
|
||||
the copied font also matches. This harness does not run the full VS Code build.
|
||||
|
||||
The original CSS plugin rewrites paths and joins 70 separators with CRLF. The npm
|
||||
development CSS is LF-only. That publication normalization is explicit and counted;
|
||||
its exact upstream pipeline stage has not been established. After the fixed release
|
||||
header and this documented transformation, the whole 114,942-byte development file
|
||||
matches. This is source/output equivalence with an observed newline adaptation,
|
||||
not an assertion that the original publishing command was reproduced unchanged.
|
||||
|
||||
Historical cssnano 4.1.11 and PostCSS 7.0.35 reproduce the complete 72,052-byte
|
||||
minified file. Each run creates a fresh ignored tool directory, writes the fixed
|
||||
historical lock, installs with Yarn 1.22.22 `--frozen-lockfile --ignore-scripts`,
|
||||
and checks that the lock remains identical. The recorded closure has 153 selectors
|
||||
and 143 package versions, all with registry integrity. `--fetch` downloads/verifies
|
||||
source archives and permits registry access; the default uses cached archives and
|
||||
an offline frozen install. No project dependency or root lock changes are needed.
|
||||
|
||||
The private manifest explicitly selects historical Browserslist defaults to prevent
|
||||
the parent project's `last 1 Chrome version` target leaking into the archived build.
|
||||
That leakage changes `transparent` to `initial`. Ambient BROWSERSLIST/config/env
|
||||
overrides are rejected. Do not update historical caniuse data to silence its age
|
||||
warning: these inputs exist only to reproduce the pinned asset. VS Code's archive
|
||||
also obeys `LICENSE.txt eol=crlf`; only that member is converted to LF for its Git
|
||||
blob check, while its frozen license bytes stay intact.
|
||||
|
||||
The site's existing 72,057-byte CSS differs solely by five CRLF header newlines;
|
||||
the verifier requires that exact transformation and leaves the asset unchanged.
|
||||
|
||||
```sh
|
||||
yarn verify:monaco-css --fetch
|
||||
yarn verify:monaco-css
|
||||
yarn test:browser test/browser/editor-styles.spec.js --workers=1
|
||||
```
|
||||
|
||||
Browser checks cover light/dark theme colors, layout and resize, find-widget bounds,
|
||||
successful CSS/font requests, loaded codicon glyphs and model disposal in all three
|
||||
engines. The pinned light theme is intentionally #fffffe. Full original core TS
|
||||
compilation and further embedded-origin review remain separate open work.
|
||||
@@ -0,0 +1,105 @@
|
||||
import type { Buffer } from 'node:buffer'
|
||||
import assert from 'node:assert/strict'
|
||||
import path from 'node:path'
|
||||
import vm from 'node:vm'
|
||||
import ts from 'typescript'
|
||||
|
||||
export function coreStyleOrder(source: string): string[] {
|
||||
const ast = ts.createSourceFile('core.js', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS)
|
||||
const tables = new Map<string, string[]>()
|
||||
const visitTables = (node: ts.Node) => {
|
||||
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer && ts.isArrayLiteralExpression(node.initializer)
|
||||
&& node.initializer.elements.every(item => ts.isStringLiteral(item))) { tables.set(node.name.text, node.initializer.elements.map(item => (item as ts.StringLiteral).text)) }
|
||||
ts.forEachChild(node, visitTables)
|
||||
}
|
||||
visitTables(ast)
|
||||
const styles: string[] = []
|
||||
const visitCalls = (node: ts.Node) => {
|
||||
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'define') {
|
||||
const name = node.arguments[0]
|
||||
if (name && ts.isElementAccessExpression(name) && ts.isIdentifier(name.expression) && ts.isNumericLiteral(name.argumentExpression)) {
|
||||
const id = tables.get(name.expression.text)?.[Number(name.argumentExpression.text)]
|
||||
if (id?.startsWith('vs/css!') && id !== 'vs/css!vs/editor/editor.main')
|
||||
styles.push(id.slice('vs/css!'.length))
|
||||
}
|
||||
}
|
||||
ts.forEachChild(node, visitCalls)
|
||||
}
|
||||
visitCalls(ast)
|
||||
assert(styles.length && new Set(styles).size === styles.length, 'Missing or repeated core CSS modules')
|
||||
return styles
|
||||
}
|
||||
|
||||
interface PreparedStyle { id: string, contents: string, moduleName: string, fsPath: string }
|
||||
interface CssPlugin {
|
||||
writeFile: (plugin: string, entry: string, request: { toUrl: (name: string) => string }, write: (file: string, source: string) => void, config: object) => void
|
||||
}
|
||||
|
||||
// Execute only the pinned transport function and CSS plugin, with reads restricted
|
||||
// to the caller's verified source map. VM is an isolation aid, not a security sandbox.
|
||||
export function prepareCoreStyles(transportRecipe: string, cssRecipe: string, ids: string[], read: (file: string) => Buffer) {
|
||||
const ast = ts.createSourceFile('standalone.ts', transportRecipe, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
const functions = ast.statements.filter(node => ts.isFunctionDeclaration(node) && node.name?.text === 'transportCSS')
|
||||
assert.equal(functions.length, 1, 'Expected one transportCSS function')
|
||||
const code = ts.transpileModule(functions[0]!.getText(ast), { compilerOptions: { target: ts.ScriptTarget.ES2020, module: ts.ModuleKind.None } }).outputText
|
||||
const assets = new Set<string>()
|
||||
const context = vm.createContext({
|
||||
SRC_DIR: '/source',
|
||||
path: path.posix,
|
||||
fs: { readFileSync: (file: string) => {
|
||||
assert(file.startsWith('/source/') && !file.split('/').includes('..'), 'CSS source escaped verified inputs')
|
||||
const source = `src/${file.slice('/source/'.length)}`
|
||||
assets.add(source)
|
||||
return read(source)
|
||||
} },
|
||||
})
|
||||
vm.runInContext(code, context, { timeout: 1000 })
|
||||
const transport = context.transportCSS as (module: string, enqueue: (font: string) => void, write: (file: string, contents: string) => void) => boolean
|
||||
const fonts = new Set<string>()
|
||||
const prepared: PreparedStyle[] = ids.map((id) => {
|
||||
assert(/^vs\/[\w./-]+$/.test(id) && !id.split('/').includes('..'), 'Invalid CSS module')
|
||||
let contents: string | undefined
|
||||
assert(transport(`${id}.css`, font => fonts.add(font), (file, source) => {
|
||||
assert.equal(file, `${id}.css`)
|
||||
assert.equal(contents, undefined, 'Repeated CSS output')
|
||||
contents = source
|
||||
}), 'CSS transport rejected input')
|
||||
assert(typeof contents === 'string', 'Missing transported CSS')
|
||||
return { id, contents, moduleName: id, fsPath: `/source/${id}.css` }
|
||||
})
|
||||
let plugin: CssPlugin | undefined
|
||||
const build = vm.createContext({
|
||||
process: { versions: { node: '24' } },
|
||||
require: { nodeRequire: (name: string) => {
|
||||
if (name === 'path')
|
||||
return path.posix
|
||||
assert.equal(name, 'fs', 'Unexpected CSS build import')
|
||||
return {
|
||||
readFileSync: () => { throw new Error('Unprepared CSS resource') },
|
||||
}
|
||||
} },
|
||||
define: (name: string, value: CssPlugin) => {
|
||||
assert.equal(name, 'vs/css')
|
||||
assert.equal(plugin, undefined)
|
||||
plugin = value
|
||||
},
|
||||
inlineResources: true,
|
||||
inlineResourcesLimit: 5000,
|
||||
cssPluginEntryPoints: { 'vs/editor/editor.main': prepared },
|
||||
})
|
||||
vm.runInContext(cssRecipe, build, { timeout: 1000 })
|
||||
assert(plugin, 'Missing CSS build plugin')
|
||||
let joined: string | undefined
|
||||
plugin.writeFile('vs/css', 'vs/editor/editor.main', { toUrl: name => name }, (file, source) => {
|
||||
assert.equal(file, 'vs/editor/editor.main.css')
|
||||
assert.equal(joined, undefined)
|
||||
joined = source
|
||||
}, {})
|
||||
assert(typeof joined === 'string', 'Missing CSS bundle')
|
||||
return { prepared, assets: [...assets], fonts: [...fonts], joined, normalizedSeparators: (joined.match(/\r\n/g) || []).length }
|
||||
}
|
||||
|
||||
export function coreCssHeader(commit: string): string {
|
||||
assert(/^[a-f0-9]{40}$/.test(commit))
|
||||
return `/*!-----------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Version: 0.30.1(${commit})\n * Released under the MIT license\n * https://github.com/microsoft/vscode/blob/main/LICENSE.txt\n *-----------------------------------------------------------*/\n`
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import type { Archive, Member } from './archives.ts'
|
||||
import assert from 'node:assert/strict'
|
||||
import { Buffer } from 'node:buffer'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { createHash } from 'node:crypto'
|
||||
import fs from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { ArchiveCache, hash } from './archives.ts'
|
||||
import { coreCssHeader, coreStyleOrder, prepareCoreStyles } from './css.ts'
|
||||
|
||||
interface Selector { selector: string, name: string, version: string, resolved: string, integrity: string }
|
||||
interface LockedDependency {
|
||||
version: string
|
||||
resolved?: string
|
||||
integrity?: string
|
||||
dependencies?: Record<string, string>
|
||||
optionalDependencies?: Record<string, string>
|
||||
}
|
||||
interface Provenance {
|
||||
commit: string
|
||||
archives: Archive[]
|
||||
sourceArchive: { url: string, file: string, bytes: number, sha256: string }
|
||||
members: { path: string, member: string, sha256: string, gitBlobSha: string, gitNormalizeCRLF?: boolean, frozen?: string }[]
|
||||
tooling: { manifest: object, selectors: Selector[] }
|
||||
coreJavaScript: Member
|
||||
styles: { id: string, prepared: Member }[]
|
||||
fonts: string[]
|
||||
normalizedSeparators: number
|
||||
development: Member
|
||||
minified: Member
|
||||
editor: Member
|
||||
target: { path: string, sha256: string, crlf: number }
|
||||
}
|
||||
|
||||
const root = fileURLToPath(new URL('../../../', import.meta.url))
|
||||
assert(process.argv.slice(2).every(arg => arg === '--fetch'), 'Use yarn verify:monaco-css [--fetch]')
|
||||
assert.equal(process.version, `v${fs.readFileSync(path.join(root, '.node-version'), 'utf8').trim()}`, 'Use canonical Node')
|
||||
const yarn = process.env.npm_execpath
|
||||
assert(yarn && process.env.npm_config_user_agent?.split(' ')[0] === 'yarn/1.22.22', 'Use Yarn Classic 1.22.22')
|
||||
assert.equal(execFileSync(process.execPath, [yarn, '--version'], { encoding: 'utf8' }).trim(), '1.22.22')
|
||||
for (const variable of ['BROWSERSLIST', 'BROWSERSLIST_CONFIG', 'BROWSERSLIST_ENV'])
|
||||
assert(!process.env[variable], `Historical CSS target must not inherit ${variable}`)
|
||||
const record: Provenance = JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/monaco-css-build-provenance.json'), 'utf8'))
|
||||
const cache = new ArchiveCache(root, path.join(root, 'refactor/.cache/monaco-review'))
|
||||
const online = process.argv.includes('--fetch')
|
||||
await cache.verify(record.archives, [], online)
|
||||
assert.equal(record.sourceArchive.file, 'vscode-source.tgz')
|
||||
assert.equal(record.sourceArchive.url, `https://codeload.github.com/microsoft/vscode/tar.gz/${record.commit}`)
|
||||
const archivePath = path.join(cache.directory, record.sourceArchive.file)
|
||||
let archive: Buffer
|
||||
if (online) {
|
||||
const response = await fetch(record.sourceArchive.url, { signal: AbortSignal.timeout(60000) })
|
||||
assert(response.ok, `VS Code archive HTTP ${response.status}`)
|
||||
archive = Buffer.from(await response.arrayBuffer())
|
||||
}
|
||||
else {
|
||||
archive = fs.readFileSync(archivePath)
|
||||
}
|
||||
assert.equal(archive.length, record.sourceArchive.bytes)
|
||||
assert.equal(hash(archive), record.sourceArchive.sha256, 'VS Code archive changed')
|
||||
if (online)
|
||||
fs.writeFileSync(archivePath, archive)
|
||||
const sources = new Map<string, Buffer>()
|
||||
for (const member of record.members) {
|
||||
assert.equal(member.member, `vscode-${record.commit}/${member.path}`)
|
||||
assert(!member.path.split('/').includes('..'), 'Invalid VS Code source')
|
||||
const bytes = execFileSync('tar', ['-xOzf', archivePath, member.member], { maxBuffer: 5 * 1024 * 1024 })
|
||||
assert.equal(hash(bytes), member.sha256, `Source changed: ${member.path}`)
|
||||
assert.equal(Boolean(member.gitNormalizeCRLF), member.path === 'LICENSE.txt', 'Unexpected Git line-ending adaptation')
|
||||
const gitBytes = member.gitNormalizeCRLF ? Buffer.from(bytes.toString('utf8').replace(/\r\n/g, '\n')) : bytes
|
||||
assert.equal(createHash('sha1').update(`blob ${gitBytes.length}\0`).update(gitBytes).digest('hex'), member.gitBlobSha, 'Git blob changed')
|
||||
if (member.frozen)
|
||||
assert.deepEqual(fs.readFileSync(path.join(root, member.frozen)), bytes, 'Frozen CSS recipe changed')
|
||||
assert(!sources.has(member.path), 'Duplicate CSS source')
|
||||
sources.set(member.path, bytes)
|
||||
}
|
||||
function read(file: string): Buffer {
|
||||
const source = sources.get(file)
|
||||
assert(source, `Unverified CSS source: ${file}`)
|
||||
return source
|
||||
}
|
||||
const ids = coreStyleOrder(cache.member(record.coreJavaScript).toString('utf8'))
|
||||
assert(read('.gitattributes').toString('utf8').includes('LICENSE.txt eol=crlf'), 'Unexplained archive license line endings')
|
||||
assert.deepEqual(ids, record.styles.map(style => style.id))
|
||||
assert.equal(ids.length, 68)
|
||||
const styles = prepareCoreStyles(read('build/lib/standalone.ts').toString('utf8'), read('src/vs/css.build.js').toString('utf8'), ids, read)
|
||||
for (const [index, style] of styles.prepared.entries())
|
||||
assert(Buffer.from(style.contents).equals(cache.member(record.styles[index]!.prepared)), `Prepared CSS differs: ${style.id}`)
|
||||
assert.deepEqual(styles.fonts, record.fonts)
|
||||
for (const font of styles.fonts)
|
||||
assert.deepEqual(read(`src/${font}`), cache.read('monaco-editor-core-0.30.1', `package/esm/${font}`), 'Copied font differs')
|
||||
assert.equal(styles.normalizedSeparators, record.normalizedSeparators)
|
||||
assert.equal(styles.normalizedSeparators, 70)
|
||||
// The archived dev CSS is LF-only; the fixed plugin joins 70 separators with CRLF.
|
||||
// Record this observed publication normalization instead of ignoring whitespace.
|
||||
const development = `${coreCssHeader(record.commit)}\n${styles.joined}`.replace(/\r\n/g, '\n')
|
||||
assert(Buffer.from(development).equals(cache.member(record.development)), 'Complete CSS development bundle differs')
|
||||
|
||||
// The existing Yarn lock parser has no declarations; keep its used boundary local.
|
||||
const lockfile = createRequire(import.meta.url)('@yarnpkg/lockfile') as { parse: (source: string) => { type: string, object: Record<string, LockedDependency> } }
|
||||
const parsed = lockfile.parse(read('yarn.lock').toString('utf8'))
|
||||
assert.equal(parsed.type, 'success')
|
||||
const closure = new Map<string, Selector>()
|
||||
function visit(selector: string) {
|
||||
if (closure.has(selector))
|
||||
return
|
||||
const dependency = parsed.object[selector]
|
||||
assert(dependency?.resolved && dependency.integrity, `Unpinned historical CSS dependency: ${selector}`)
|
||||
closure.set(selector, { selector, name: selector.slice(0, selector.lastIndexOf('@')), version: dependency.version, resolved: dependency.resolved, integrity: dependency.integrity })
|
||||
for (const [name, range] of Object.entries({ ...dependency.dependencies, ...dependency.optionalDependencies }))
|
||||
visit(`${name}@${range}`)
|
||||
}
|
||||
visit('cssnano@^4.1.11')
|
||||
assert.deepEqual([...closure.values()], record.tooling.selectors)
|
||||
assert.equal(JSON.parse(read('package.json').toString('utf8')).devDependencies.cssnano, '^4.1.11')
|
||||
const manifest = { name: 'monaco-css-historical-tools', private: true, browserslist: ['defaults'], dependencies: { cssnano: '^4.1.11' } }
|
||||
assert.deepEqual(manifest, record.tooling.manifest)
|
||||
const compiler = fs.mkdtempSync(path.join(cache.directory, 'css-build-'))
|
||||
fs.writeFileSync(path.join(compiler, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`)
|
||||
fs.writeFileSync(path.join(compiler, 'yarn.lock'), read('yarn.lock'))
|
||||
const install = execFileSync(process.execPath, [yarn, 'install', '--frozen-lockfile', '--ignore-scripts', '--non-interactive', ...online ? [] : ['--offline']], { cwd: compiler, encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 })
|
||||
fs.writeFileSync(path.join(cache.directory, 'css-install-last.log'), install)
|
||||
assert.deepEqual(fs.readFileSync(path.join(compiler, 'yarn.lock')), read('yarn.lock'), 'Frozen historical lock changed')
|
||||
const require = createRequire(path.join(compiler, 'entry.cjs'))
|
||||
const cssnanoPath = require.resolve('cssnano/package.json')
|
||||
const cssRequire = createRequire(cssnanoPath)
|
||||
assert.equal(require(cssnanoPath).version, '4.1.11')
|
||||
assert.equal(cssRequire('postcss/package.json').version, '7.0.35')
|
||||
const minified: { css: string } = await cssRequire('postcss')([require('cssnano')({ preset: 'default' })]).process(development, { from: path.join(compiler, 'editor.main.css'), map: false })
|
||||
|
||||
assert(Buffer.from(minified.css).equals(cache.member(record.minified)), 'Complete CSS minification differs')
|
||||
assert.deepEqual(cache.member(record.minified), cache.member(record.editor), 'Editor CSS archive differs')
|
||||
const target = fs.readFileSync(path.join(root, record.target.path))
|
||||
assert.equal(hash(target), record.target.sha256, 'Site CSS changed')
|
||||
assert.equal((target.toString('utf8').match(/\r\n/g) || []).length, record.target.crlf)
|
||||
assert.equal(record.target.crlf, 5)
|
||||
assert(Buffer.from(minified.css.replace(/\n/g, '\r\n')).equals(target), 'Site CSS differs beyond five header newlines')
|
||||
console.log(JSON.stringify({ gitSources: sources.size, styles: ids.length, inlinedImages: styles.assets.filter(file => !file.endsWith('.css')), fonts: styles.fonts, dependencySelectors: closure.size, normalizedSeparators: styles.normalizedSeparators, developmentBytes: Buffer.byteLength(development), minifiedBytes: Buffer.byteLength(minified.css), siteBytes: target.length, exactDevelopment: true, exactMinification: true, preservedSiteCrlf: 5, compiler: { cssnano: '4.1.11', postcss: '7.0.35' }, originalCoreTypeScriptCompiled: false }))
|
||||
@@ -0,0 +1,68 @@
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
test('docs Monaco styles retain layout, themes and loaded codicon glyphs', async ({ page }, testInfo) => {
|
||||
const assets = []
|
||||
page.on('response', (response) => {
|
||||
if (/\/(?:editor\.main\.css|codicon\.ttf)$/.test(response.url()))
|
||||
assets.push({ url: response.url(), status: response.status() })
|
||||
})
|
||||
await page.goto('/test/player.html?core=candidate&chapter=published')
|
||||
await page.addScriptTag({ url: '/assets/js/vs/loader.js' })
|
||||
await page.evaluate(async () => {
|
||||
window.require.config({ paths: { vs: '/assets/js/vs' } })
|
||||
await new Promise((resolve, reject) => window.require(['vs/editor/editor.main'], resolve, reject))
|
||||
const host = document.createElement('div')
|
||||
host.style.cssText = 'width:640px;height:320px'
|
||||
document.body.appendChild(host)
|
||||
const editor = window.monaco.editor.create(host, { value: 'first\nsecond\nfirst', language: 'plaintext', theme: 'vs-dark', minimap: { enabled: false } })
|
||||
window.styleProbe = { host, editor, model: editor.getModel() }
|
||||
})
|
||||
const editor = page.locator('.monaco-editor').first()
|
||||
const evidence = []
|
||||
try {
|
||||
await expect(editor).toBeVisible()
|
||||
await expect(editor).toHaveCSS('position', 'relative')
|
||||
// The pinned colorRegistry deliberately uses #fffffe for the light theme.
|
||||
for (const [theme, color] of [['vs-dark', 'rgb(30, 30, 30)'], ['vs', 'rgb(255, 255, 254)']]) {
|
||||
await page.evaluate(theme => window.monaco.editor.setTheme(theme), theme)
|
||||
await expect(editor).toHaveCSS('background-color', color)
|
||||
evidence.push({ theme, color })
|
||||
}
|
||||
await page.evaluate(() => window.styleProbe.editor.getAction('actions.find').run())
|
||||
const find = page.locator('.find-widget')
|
||||
await expect(find).toBeVisible()
|
||||
const font = await page.evaluate(async () => {
|
||||
const loaded = await document.fonts.load('16px codicon')
|
||||
const icon = window.styleProbe.host.querySelector('.find-widget .codicon')
|
||||
const style = getComputedStyle(icon, '::before')
|
||||
return { loaded: loaded.map(font => ({ family: font.family, status: font.status })), family: style.fontFamily, content: style.content }
|
||||
})
|
||||
expect(font.loaded.length).toBeGreaterThan(0)
|
||||
expect(font.loaded.every(item => item.status === 'loaded')).toBe(true)
|
||||
expect(font.family).toContain('codicon')
|
||||
expect(['none', 'normal', '""']).not.toContain(font.content)
|
||||
const hostBox = await editor.boundingBox()
|
||||
const findBox = await find.boundingBox()
|
||||
expect(findBox.x).toBeGreaterThanOrEqual(hostBox.x)
|
||||
expect(findBox.x + findBox.width).toBeLessThanOrEqual(hostBox.x + hostBox.width + 1)
|
||||
await page.evaluate(() => {
|
||||
window.styleProbe.host.style.cssText = 'width:420px;height:240px'
|
||||
window.styleProbe.editor.layout()
|
||||
})
|
||||
await expect(editor).toHaveCSS('width', '420px')
|
||||
await expect(editor).toHaveCSS('height', '240px')
|
||||
expect(assets.filter(asset => asset.url.endsWith('/editor.main.css'))).toHaveLength(1)
|
||||
expect(assets.some(asset => asset.url.endsWith('/codicon.ttf'))).toBe(true)
|
||||
expect(assets.every(asset => asset.status === 200)).toBe(true)
|
||||
await testInfo.attach('monaco-style-results', { contentType: 'application/json', body: JSON.stringify({ themes: evidence, font, hostBox, findBox, assets, resized: { width: 420, height: 240 } }) })
|
||||
}
|
||||
finally {
|
||||
await page.evaluate(() => {
|
||||
const { host, editor, model } = window.styleProbe
|
||||
editor.dispose()
|
||||
model.dispose()
|
||||
host.remove()
|
||||
})
|
||||
}
|
||||
expect(await page.evaluate(() => window.monaco.editor.getModels().length)).toBe(0)
|
||||
})
|
||||
@@ -7,6 +7,7 @@ import { emitAmd } from '../scripts/site-vendor/monaco/compiler.ts'
|
||||
import { assembleContributions, injectCoreDependency, readContributionMetadata } from '../scripts/site-vendor/monaco/contributions.ts'
|
||||
import { inventoryCoreMap, readCoreNls, restoreCoreMapComment } from '../scripts/site-vendor/monaco/core-build.ts'
|
||||
import { adaptCoreOrigin } from '../scripts/site-vendor/monaco/core-origins.ts'
|
||||
import { coreStyleOrder, prepareCoreStyles } from '../scripts/site-vendor/monaco/css.ts'
|
||||
import { aliasModule, moduleIds, nameModule, verifyWorkerSources } from '../scripts/site-vendor/monaco/languages.ts'
|
||||
import { browserTypeScript, verifyTypeScriptSource } from '../scripts/site-vendor/monaco/typescript.ts'
|
||||
|
||||
@@ -15,6 +16,23 @@ const contributionGroups = ['typescript', 'css', 'json', 'html', 'languages'].ma
|
||||
return { name: `monaco-${name}`, modulePrefix, contrib: `${modulePrefix}/monaco.contribution` }
|
||||
})
|
||||
|
||||
test('Core CSS inventory follows registration order instead of the module-name table order', () => {
|
||||
const source = 'var names = ["vs/css!vs/editor/editor.main","vs/css!vs/a","vs/css!vs/b"]; define(names[2],[],{}); define(names[1],[],{});'
|
||||
assert.deepEqual(coreStyleOrder(source), ['vs/b', 'vs/a'])
|
||||
assert.throws(() => coreStyleOrder(`${source} define(names[2],[],{});`), /repeated core CSS/)
|
||||
assert.throws(() => coreStyleOrder('define([],{});'), /Missing/)
|
||||
})
|
||||
|
||||
test('CSS source transport cannot silently fall back to unverified or missing inputs', () => {
|
||||
const unexpectedRead = () => {
|
||||
throw new Error('unexpected read')
|
||||
}
|
||||
assert.throws(() => prepareCoreStyles('', '', ['vs/a'], unexpectedRead), /one transportCSS/)
|
||||
const recipe = 'function transportCSS(module: string, enqueue: Function, write: Function) { fs.readFileSync("/outside/a.css"); return true; }'
|
||||
assert.throws(() => prepareCoreStyles(recipe, '', ['vs/a'], unexpectedRead), /escaped verified inputs/)
|
||||
assert.throws(() => prepareCoreStyles('function transportCSS() { return true; }', '', ['vs/a'], unexpectedRead), /Missing transported CSS/)
|
||||
})
|
||||
|
||||
test('Contribution metadata preserves upstream ordering and rejects computed or duplicate values', () => {
|
||||
const plugins = contributionGroups.map(group => ({ ...group, rootPath: `./${group.name}`, paths: { dev: './release/dev', min: './release/min' } }))
|
||||
const metadata = list => `var METADATA = ${JSON.stringify({ PLUGINS: list })};`
|
||||
|
||||
Reference in new issue
Block a user