mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-12 06:26:16 -08:00
build(site): [SITE-07] reproduce core outputs and validate localized editing
This commit is contained in:
1 parent
244695e726
commit
0cfdf4a7e3
24 files changed
+10598
-5
No files matched your search
@@ -195,3 +195,45 @@ temporary sanitizer hooks. The site test checks every delivered notice byte and
|
||||
relative attribution link while exercising mobile playback/logging/disposal.
|
||||
Neither is an exhaustive sanitizer audit. Loader, other core modules, localization,
|
||||
and further embedded-origin details remain under SITE-07/VENDOR-06.
|
||||
|
||||
## Core minification, loader and locales
|
||||
|
||||
`reproduce-core-build.ts` verifies all 13 JavaScript outputs in monaco-editor-core
|
||||
0.30.1: editor, worker, loader, English and nine translations. The fixed VS Code
|
||||
recipe and lock identify esbuild 0.12.6. The selected executable is read from a
|
||||
SHA-512/SHA-256-verified archive and run directly in an ignored cache, without
|
||||
install scripts or root dependency changes. Windows/Linux x64 archives are pinned;
|
||||
only Windows execution has been validated. Other hosts fail explicitly.
|
||||
|
||||
The historical build's node platform/esnext target/minify options reproduce every
|
||||
complete output, including the exact extra newline and relative source-map comment.
|
||||
Twelve files copy directly into the site; editor.main has the previously verified
|
||||
entry rename and core prefix before appended language registrations. This command
|
||||
does not claim to reconstruct those registrations or CSS. The loader's full source
|
||||
and release header match fixed Git; css/nls loader sources match their map entries.
|
||||
|
||||
`core-build.ts` contains static NLS parsing, source-map inventory and map-comment
|
||||
assembly. The NLS parser accepts the archived trailing commas but rejects computed
|
||||
values, duplicate keys and extra statements without evaluating downloaded code.
|
||||
Two archived maps contain 584 prepared-source entries, 549 different names, with
|
||||
content hashes and byte lengths. They are prepared build inputs, not proof of a
|
||||
complete original VS Code TypeScript compilation or license review.
|
||||
|
||||
```sh
|
||||
yarn verify:monaco-core-build --fetch
|
||||
yarn verify:monaco-core-build
|
||||
yarn test:browser test/browser/editor-core.spec.js --workers=1
|
||||
```
|
||||
|
||||
Ten locales each exercise actual keyboard edits, undo/redo, localized find UI,
|
||||
next-match navigation and model disposal in all engines. The test waits for the
|
||||
new selected range after changing the query, not a fixed delay or an old cursor
|
||||
position. A separate diff-editor test requires a real worker, checks changed lines,
|
||||
updates the input to equality, and disposes both models.
|
||||
|
||||
Remaining origin review can start from the map inventory: `dom.ts` references WinJS;
|
||||
`strings.ts` names unicode-utils generators; `color.ts` references HSL formulas;
|
||||
marked names a Stack Overflow snippet; `path.ts` identifies Node 14.16.0 while the
|
||||
older supplied notice links a different commit. Reference comments alone do not
|
||||
establish copied expression or a missing license; inspect actual boundaries and
|
||||
original terms before deciding. Core registration assembly and CSS remain separate.
|
||||
@@ -0,0 +1,47 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import path from 'node:path'
|
||||
import ts from 'typescript'
|
||||
import { hash } from './archives.ts'
|
||||
|
||||
export interface CoreSourceMap { sources: string[], sourcesContent: string[] }
|
||||
|
||||
export function inventoryCoreMap(map: CoreSourceMap): { source: string, bytes: number, sha256: string }[] {
|
||||
assert.equal(map.sources.length, map.sourcesContent.length, 'Missing mapped source content')
|
||||
assert.equal(new Set(map.sources).size, map.sources.length, 'Repeated mapped source name')
|
||||
return map.sources.map((source, index) => {
|
||||
const content = map.sourcesContent[index]
|
||||
assert(typeof content === 'string', 'Missing mapped source text')
|
||||
const bytes = new TextEncoder().encode(content)
|
||||
return { source, bytes: bytes.length, sha256: hash(bytes) }
|
||||
})
|
||||
}
|
||||
|
||||
export function restoreCoreMapComment(minified: string, relative: string): string {
|
||||
assert(/^vs\/[\w./-]+\.js$/.test(relative) && !relative.split('/').includes('..'), 'Invalid core output path')
|
||||
assert(minified.endsWith('\n'), 'Expected esbuild output newline')
|
||||
const url = path.posix.relative(path.posix.dirname(`min/${relative}`), `min-maps/${relative}.map`)
|
||||
return `${minified}\n//# sourceMappingURL=${url}`
|
||||
}
|
||||
|
||||
export function readCoreNls(source: string): { id: string, messages: Record<string, string[]> } {
|
||||
const file = ts.createSourceFile('nls.js', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS)
|
||||
assert.equal(file.statements.length, 1, 'Expected one NLS registration')
|
||||
const statement = file.statements[0]!
|
||||
assert(ts.isExpressionStatement(statement) && ts.isCallExpression(statement.expression), 'Expected literal NLS call')
|
||||
const call = statement.expression
|
||||
assert(ts.isIdentifier(call.expression) && call.expression.text === 'define' && call.arguments.length === 2, 'Expected AMD NLS definition')
|
||||
const name = call.arguments[0]!
|
||||
assert(ts.isStringLiteral(name), 'Expected NLS module name')
|
||||
const data = call.arguments[1]!
|
||||
assert(ts.isObjectLiteralExpression(data), 'Expected literal translation object')
|
||||
const entries = data.properties.map((property) => {
|
||||
assert(ts.isPropertyAssignment(property) && ts.isStringLiteral(property.name) && ts.isArrayLiteralExpression(property.initializer), 'Expected literal translation arrays')
|
||||
return [property.name.text, property.initializer.elements.map((item) => {
|
||||
assert(ts.isStringLiteral(item), 'Expected literal translation text')
|
||||
return item.text
|
||||
})] as const
|
||||
})
|
||||
assert.equal(new Set(entries.map(([name]) => name)).size, entries.length, 'Repeated translation module')
|
||||
const messages = Object.fromEntries(entries)
|
||||
return { id: name.text, messages }
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import type { Archive, Member, Remote } from './archives.ts'
|
||||
import type { CoreSourceMap } from './core-build.ts'
|
||||
import assert from 'node:assert/strict'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { ArchiveCache, hash } from './archives.ts'
|
||||
import { inventoryCoreMap, readCoreNls, restoreCoreMapComment } from './core-build.ts'
|
||||
|
||||
interface Record {
|
||||
commit: string
|
||||
archives: Archive[]
|
||||
remotes: Remote[]
|
||||
binaries: { [platform: string]: Member }
|
||||
files: { relative: string, development: Member, minified: Member, target: { path: string, sha256: string }, appendedContributions: boolean }[]
|
||||
sourceMaps: (Member & { sources: ReturnType<typeof inventoryCoreMap> })[]
|
||||
locales: { path: string, sha256: string }
|
||||
}
|
||||
|
||||
const root = fileURLToPath(new URL('../../../', import.meta.url))
|
||||
assert(process.argv.slice(2).every(arg => arg === '--fetch'), 'Use reproduce-core-build.ts [--fetch]')
|
||||
assert.equal(process.version, `v${fs.readFileSync(path.join(root, '.node-version'), 'utf8').trim()}`, 'Use canonical Node')
|
||||
const record: Record = JSON.parse(fs.readFileSync(path.join(root, 'refactor/baselines/monaco-core-build-provenance.json'), 'utf8'))
|
||||
const host = `${process.platform}-${process.arch}`
|
||||
const binary = record.binaries[host]
|
||||
assert(binary, `No frozen esbuild binary for ${host}`)
|
||||
const cache = new ArchiveCache(root, path.join(root, 'refactor/.cache/monaco-review'))
|
||||
const archives = record.archives.filter(item => !item.name.startsWith('esbuild-') || `${item.name}-${item.version}` === binary.archive)
|
||||
await cache.verify(archives, record.remotes, process.argv.includes('--fetch'))
|
||||
const lock = fs.readFileSync(path.join(root, 'refactor/baselines/site-vendor/monaco-core-build/build-yarn.lock.txt'), 'utf8')
|
||||
const esbuild = archives.find(archive => archive.name === 'esbuild')
|
||||
assert(esbuild && lock.includes(`esbuild@^0.12.6:\n version "0.12.6"`) && lock.includes(`integrity ${esbuild.integrity}`), 'Wrong historical minifier')
|
||||
const executable = path.join(cache.directory, process.platform === 'win32' ? 'core-esbuild.exe' : 'core-esbuild')
|
||||
assert(!fs.existsSync(executable) || !fs.lstatSync(executable).isSymbolicLink(), 'Redirected historical executable')
|
||||
fs.writeFileSync(executable, cache.member(binary), { mode: 0o700 })
|
||||
assert.equal(execFileSync(executable, ['--version'], { encoding: 'utf8' }).trim(), '0.12.6')
|
||||
const sourceFile = path.join(cache.directory, 'core-reproduction-input.js')
|
||||
assert(!fs.existsSync(sourceFile) || !fs.lstatSync(sourceFile).isSymbolicLink(), 'Redirected historical input')
|
||||
const archiveFiles = execFileSync('tar', ['-tzf', path.join(cache.directory, 'monaco-editor-core-0.30.1.tgz')], { encoding: 'utf8' }).trim().split(/\r?\n/)
|
||||
assert.deepEqual(record.files.map(file => file.development.member).sort(), archiveFiles.filter(file => file.startsWith('package/dev/') && file.endsWith('.js')).sort(), 'Missing core JavaScript output')
|
||||
assert.equal(record.files.length, 13)
|
||||
const results = []
|
||||
for (const file of record.files) {
|
||||
const development = cache.member(file.development)
|
||||
fs.writeFileSync(sourceFile, development)
|
||||
const output = execFileSync(executable, [sourceFile, '--minify', '--platform=node', '--target=esnext'], { encoding: 'utf8', maxBuffer: 30 * 1024 * 1024 })
|
||||
const minified = cache.member(file.minified).toString('utf8')
|
||||
assert.equal(restoreCoreMapComment(output, file.relative), minified, 'Core minification differs')
|
||||
const shipped = fs.readFileSync(path.join(root, file.target.path))
|
||||
assert.equal(hash(shipped), file.target.sha256, 'Core site asset changed')
|
||||
assert.deepEqual(shipped, cache.read('monaco-editor-0.30.1', `package/min/${file.relative}`), 'Core editor archive differs')
|
||||
if (file.appendedContributions) {
|
||||
assert.equal(file.relative, 'vs/editor/editor.main.js')
|
||||
const renamed = minified.replace('"vs/editor/editor.main"', '"vs/editor/edcore.main"')
|
||||
const offset = renamed.lastIndexOf('//# sourceMappingURL=')
|
||||
assert(shipped.toString('utf8').startsWith(renamed.slice(0, offset)) && shipped.toString('utf8').endsWith(renamed.slice(offset)), 'Editor core boundary differs')
|
||||
}
|
||||
else {
|
||||
assert.equal(shipped.toString('utf8'), minified, 'Core copied output differs')
|
||||
}
|
||||
results.push({ relative: file.relative, exactMinification: true, appendedContributions: file.appendedContributions, sha256: hash(shipped) })
|
||||
}
|
||||
const maps: CoreSourceMap[] = []
|
||||
for (const member of record.sourceMaps) {
|
||||
const map: CoreSourceMap = JSON.parse(cache.member(member).toString('utf8'))
|
||||
assert.deepEqual(inventoryCoreMap(map), member.sources, 'Prepared source inventory differs')
|
||||
maps.push(map)
|
||||
}
|
||||
for (const name of ['loader', 'css', 'nls']) {
|
||||
const remote = record.remotes.find(remote => remote.source.endsWith(`src-vs-${name}.js.txt`))
|
||||
assert(remote)
|
||||
const source = fs.readFileSync(path.join(root, remote.source), 'utf8')
|
||||
const map = maps.find(map => map.sources.includes(`vs/${name}.js`))
|
||||
assert(map)
|
||||
assert.equal(map.sourcesContent[map.sources.indexOf(`vs/${name}.js`)], source, 'Loader source differs')
|
||||
if (name === 'loader') {
|
||||
const header = `/*!-----------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Version: 0.30.1(${record.commit})\n * Released under the MIT license\n * https://github.com/microsoft/vscode/blob/main/LICENSE.txt\n *-----------------------------------------------------------*/\n\n`
|
||||
assert.equal(cache.read('monaco-editor-core-0.30.1', 'package/dev/vs/loader.js').toString('utf8'), header + source, 'Loader release header differs')
|
||||
}
|
||||
}
|
||||
const locales = fs.readFileSync(path.join(root, record.locales.path))
|
||||
assert.equal(hash(locales), record.locales.sha256)
|
||||
for (const locale of JSON.parse(locales.toString('utf8'))) {
|
||||
assert(record.files.some(file => file.development.member === locale.member), 'Unverified locale')
|
||||
const { id, messages } = readCoreNls(cache.read('monaco-editor-core-0.30.1', locale.member).toString('utf8'))
|
||||
assert.equal(id, `vs/editor/editor.main.nls${locale.locale === 'en' ? '' : `.${locale.locale}`}`)
|
||||
const labels = messages['vs/editor/contrib/find/findWidget']!
|
||||
assert.deepEqual([locale.find, locale.next, locale.close], [labels[7], labels[10], labels[12]], 'Locale fixture differs')
|
||||
}
|
||||
console.log(JSON.stringify({ host, archives: archives.length, gitSources: record.remotes.length, outputs: results, mappedInstances: maps.reduce((count, map) => count + map.sources.length, 0), uniqueMappedSources: new Set(maps.flatMap(map => map.sources)).size, completeTypeScriptBuild: false, remainingEmbeddedOriginsReviewed: false }))
|
||||
Reference in new issue
Block a user