mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
82 lines
4.0 KiB
TypeScript
82 lines
4.0 KiB
TypeScript
import assert from 'node:assert/strict'
|
|
import ts from 'typescript'
|
|
|
|
function definitions(source: string): ts.CallExpression[] {
|
|
const ast = ts.createSourceFile('worker.js', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS)
|
|
const result: ts.CallExpression[] = []
|
|
const walk = (node: ts.Node) => {
|
|
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'define')
|
|
result.push(node)
|
|
ts.forEachChild(node, walk)
|
|
}
|
|
walk(ast)
|
|
return result
|
|
}
|
|
|
|
export function moduleIds(source: string): string[] {
|
|
const ids = definitions(source).map((call) => {
|
|
assert(call.arguments[0] && ts.isStringLiteral(call.arguments[0]), 'Expected literal AMD name')
|
|
return call.arguments[0].text
|
|
})
|
|
assert.equal(new Set(ids).size, ids.length, 'Duplicate AMD module')
|
|
return ids
|
|
}
|
|
|
|
// RequireJS names one anonymous AMD definition and removes newline-ended maps.
|
|
// Locate the call syntactically so comments/strings containing define( are inert.
|
|
export function nameModule(source: string, id: string): string {
|
|
assert(/^[\w./-]+$/.test(id) && id.split('/').every(part => part !== '.' && part !== '..'), 'Unexpected AMD identifier')
|
|
const calls = definitions(source)
|
|
assert.equal(calls.length, 1, 'Expected one anonymous AMD definition')
|
|
const call = calls[0]!
|
|
assert(call.arguments[0] && ts.isArrayLiteralExpression(call.arguments[0]), 'Expected anonymous AMD dependency array')
|
|
const offset = call.expression.end
|
|
assert.equal(source[offset], '(', 'Unexpected AMD opening boundary')
|
|
const map = /^\/\/# sourceMappingURL=[^\r\n]+(?:\r?\n)?$/gm
|
|
const maps = [...source.matchAll(map)]
|
|
assert(maps.length <= 1, 'Duplicate source map trailer')
|
|
source = `${source.slice(0, offset + 1)}'${id}',${source.slice(offset + 1)}`
|
|
// types/main and uri/index have no final newline. The archived optimizer kept
|
|
// their map comment and appended a semicolon; account for those bytes too.
|
|
if (maps[0] && !maps[0][0].endsWith('\n'))
|
|
return `${source};`
|
|
return source.replace(map, '').trimEnd()
|
|
}
|
|
|
|
export function aliasModule(id: string, main: string): string {
|
|
assert(/^[\w-]+$/.test(id) && /^[\w/-]+$/.test(main), 'Unexpected AMD alias')
|
|
return `define('${id}', ['${id}/${main}'], function (main) { return main; });`
|
|
}
|
|
|
|
// Check whole source fragments, their module ownership and every intervening byte.
|
|
// A module inventory alone would overlook helper code outside define() calls.
|
|
export function verifyWorkerSources(worker: string, ids: string[], fragments: { id: string, source: string }[]): void {
|
|
assert.deepEqual(moduleIds(worker), ids, 'Worker AMD inventory changed')
|
|
assert.deepEqual(fragments.map(item => item.id).sort(), [...ids].sort(), 'Incomplete source coverage')
|
|
const intervals = fragments.map(({ id, source }) => {
|
|
assert.deepEqual(moduleIds(source), [id], 'Wrong source module ownership')
|
|
const start = worker.indexOf(source)
|
|
assert(start >= 0, `Source differs: ${id}`)
|
|
assert.equal(worker.indexOf(source, start + 1), -1, `Repeated source: ${id}`)
|
|
return { start, end: start + source.length }
|
|
}).sort((a, b) => a.start - b.start)
|
|
let end = 0
|
|
for (const interval of intervals) {
|
|
assert(interval.start >= end, 'Overlapping source fragments')
|
|
assert.equal(worker.slice(end, interval.start).trim(), '', 'Unattributed worker content')
|
|
end = interval.end
|
|
}
|
|
assert.equal(worker.slice(end).trim(), '', 'Unattributed worker suffix')
|
|
}
|
|
|
|
export function languageHeader(language: string): string {
|
|
assert(['css', 'html', 'json', 'typescript'].includes(language), 'Unexpected Monaco language')
|
|
return `/*!-----------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* monaco-${language} version: 0.30.1(5a7ba61be909ae9e4889768a3453ebb0dec392e2)
|
|
* Released under the MIT license
|
|
* https://github.com/Microsoft/monaco-${language}/blob/master/LICENSE.md
|
|
*-----------------------------------------------------------------------------*/
|
|
`
|
|
}
|