diff --git a/.vscode/launch.json b/.vscode/launch.json index 8d147034907..1ba9c3000cf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -526,7 +526,7 @@ "name": "Monaco Editor Playground", "type": "chrome", "request": "launch", - "url": "https://microsoft.github.io/monaco-editor/playground.html?source=http%3A%2F%2Flocalhost%3A5001%2Fout%2Fvs", + "url": "http://localhost:5001", "preLaunchTask": "Launch Http Server", "presentation": { "group": "monaco", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f97b01e8c62..1a6554bec65 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -260,7 +260,7 @@ // Used for monaco editor playground launch config "label": "Launch Http Server", "type": "shell", - "command": "node_modules/.bin/http-server --cors --port 5001 -a 127.0.0.1 -c-1 -s", + "command": "node_modules/.bin/ts-node -T ./scripts/playground-server", "isBackground": true, "problemMatcher": { "pattern": { diff --git a/package.json b/package.json index a311a5c01e2..51124f5bc92 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,6 @@ "gulp-sourcemaps": "^3.0.0", "gulp-svgmin": "^4.1.0", "gulp-untar": "^0.0.7", - "http-server": "^14.1.1", "husky": "^0.13.1", "innosetup": "6.0.5", "is": "^3.1.0", diff --git a/scripts/playground-server.ts b/scripts/playground-server.ts new file mode 100644 index 00000000000..133bd375d89 --- /dev/null +++ b/scripts/playground-server.ts @@ -0,0 +1,710 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as fsPromise from 'fs/promises'; +import path from 'path'; +import * as http from 'http'; +import * as parcelWatcher from '@parcel/watcher'; + +/** + * Launches the server for the monaco editor playground + */ +function main() { + const server = new HttpServer({ host: 'localhost', port: 5001, cors: true }); + server.use('/', redirectToMonacoEditorPlayground()); + + const rootDir = path.join(__dirname, '..'); + const fileServer = new FileServer(rootDir); + server.use(fileServer.handleRequest); + + const moduleIdMapper = new SimpleModuleIdPathMapper(path.join(rootDir, 'out')); + const editorMainBundle = new CachedBundle('vs/editor/editor.main', moduleIdMapper); + fileServer.overrideFileContent(editorMainBundle.entryModulePath, () => editorMainBundle.bundle()); + + const hotReloadJsCode = getHotReloadCode(new URL('/file-changes', server.url)); + const loaderPath = path.join(rootDir, 'out/vs/loader.js'); + fileServer.overrideFileContent(loaderPath, async () => + Buffer.from(new TextEncoder().encode(`${await fsPromise.readFile(loaderPath, 'utf8')}\n${hotReloadJsCode}`)) + ); + + const watcher = DirWatcher.watchRecursively(moduleIdMapper.rootDir); + watcher.onDidChange((path, newContent) => { + editorMainBundle.setModuleContent(path, newContent); + editorMainBundle.bundle(); + console.log(`${new Date().toLocaleTimeString()}, file change: ${path}`); + }); + server.use('/file-changes', handleGetFileChangesRequest(watcher, fileServer)); + + console.log(`Server listening on ${server.url}`); +} +setTimeout(main, 0); + +// #region Http/File Server + +type RequestHandler = (req: http.IncomingMessage, res: http.ServerResponse) => Promise; +type ChainableRequestHandler = (req: http.IncomingMessage, res: http.ServerResponse, next: RequestHandler) => Promise; + +class HttpServer { + private readonly server: http.Server; + public readonly url: URL; + + private handler: ChainableRequestHandler[] = []; + + constructor(options: { host: string; port: number; cors: boolean }) { + this.server = http.createServer(async (req, res) => { + if (options.cors) { + res.setHeader('Access-Control-Allow-Origin', '*'); + } + + let i = 0; + const next = async (req: http.IncomingMessage, res: http.ServerResponse) => { + if (i >= this.handler.length) { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.end('404 Not Found'); + return; + } + const handler = this.handler[i]; + i++; + await handler(req, res, next); + }; + await next(req, res); + }); + this.server.listen(options.port, options.host); + this.url = new URL(`http://${options.host}:${options.port}`); + } + + use(handler: ChainableRequestHandler); + use(path: string, handler: ChainableRequestHandler); + use(...args: [path: string, handler: ChainableRequestHandler] | [handler: ChainableRequestHandler]) { + const handler = args.length === 1 ? args[0] : (req, res, next) => { + const path = args[0]; + const requestedUrl = new URL(req.url, this.url); + if (requestedUrl.pathname === path) { + return args[1](req, res, next); + } else { + return next(req, res); + } + }; + + this.handler.push(handler); + } +} + +function redirectToMonacoEditorPlayground(): ChainableRequestHandler { + return async (req, res) => { + const url = new URL('https://microsoft.github.io/monaco-editor/playground.html'); + url.searchParams.append('source', `http://${req.headers.host}/out/vs`); + res.writeHead(302, { Location: url.toString() }); + res.end(); + }; +} + +class FileServer { + private readonly overrides = new Map Promise>(); + + constructor(public readonly publicDir: string) { } + + public readonly handleRequest: ChainableRequestHandler = async (req, res, next) => { + const requestedUrl = new URL(req.url!, `http://${req.headers.host}`); + + const pathName = requestedUrl.pathname; + + const filePath = path.join(this.publicDir, pathName); + if (!filePath.startsWith(this.publicDir)) { + res.writeHead(403, { 'Content-Type': 'text/plain' }); + res.end('403 Forbidden'); + return; + } + + try { + const override = this.overrides.get(filePath); + let content: Buffer; + if (override) { + content = await override(); + } else { + content = await fsPromise.readFile(filePath); + } + + const contentType = getContentType(filePath); + res.writeHead(200, { 'Content-Type': contentType }); + res.end(content); + } catch (err) { + if (err.code === 'ENOENT') { + next(req, res); + } else { + res.writeHead(500, { 'Content-Type': 'text/plain' }); + res.end('500 Internal Server Error'); + } + } + }; + + public filePathToUrlPath(filePath: string): string | undefined { + const relative = path.relative(this.publicDir, filePath); + const isSubPath = !!relative && !relative.startsWith('..') && !path.isAbsolute(relative); + + if (!isSubPath) { + return undefined; + } + const relativePath = relative.replace(/\\/g, '/'); + return `/${relativePath}`; + } + + public overrideFileContent(filePath: string, content: () => Promise): void { + this.overrides.set(filePath, content); + } +} + +function getContentType(filePath: string): string { + const extname = path.extname(filePath); + switch (extname) { + case '.js': + return 'text/javascript'; + case '.css': + return 'text/css'; + case '.json': + return 'application/json'; + case '.png': + return 'image/png'; + case '.jpg': + return 'image/jpg'; + default: + return 'text/plain'; + } +} + +// #endregion + +// #region File Watching + +interface IDisposable { + dispose(): void; +} + +class DirWatcher { + public static watchRecursively(dir: string): DirWatcher { + const listeners: ((path: string, newContent: string) => void)[] = []; + const fileContents = new Map(); + const event = (handler: (path: string, newContent: string) => void) => { + listeners.push(handler); + return { + dispose: () => { + const idx = listeners.indexOf(handler); + if (idx >= 0) { + listeners.splice(idx, 1); + } + } + }; + }; + parcelWatcher.subscribe(dir, async (err, events) => { + for (const e of events) { + if (e.type === 'update') { + const newContent = await fsPromise.readFile(e.path, 'utf8'); + if (fileContents.get(e.path) !== newContent) { + fileContents.set(e.path, newContent); + listeners.forEach(l => l(e.path, newContent)); + } + } + } + }); + return new DirWatcher(event); + } + + constructor(public readonly onDidChange: (handler: (path: string, newContent: string) => void) => IDisposable) { + } +} + +function handleGetFileChangesRequest(watcher: DirWatcher, fileServer: FileServer): ChainableRequestHandler { + return async (req, res) => { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + const d = watcher.onDidChange(fsPath => { + const path = fileServer.filePathToUrlPath(fsPath); + if (path) { + res.write(JSON.stringify({ changedPath: path }) + '\n'); + } + }); + res.on('close', () => d.dispose()); + }; +} + +function getHotReloadCode(fileChangesUrl: URL): string { + const additionalJsCode = ` +function $watchChanges() { + console.log("Connecting to server to watch for changes..."); + fetch(${JSON.stringify(fileChangesUrl)}) + .then(async request => { + const reader = request.body.getReader(); + let buffer = ''; + while (true) { + const { done, value } = await reader.read(); + if (done) { break; } + buffer += new TextDecoder().decode(value); + const lines = buffer.split('\\n'); + buffer = lines.pop(); + for (const line of lines) { + const data = JSON.parse(line); + if (data.changedPath.endsWith('.css')) { + console.log('css changed', data.changedPath); + const styleSheet = [...document.querySelectorAll("link[rel='stylesheet']")].find(l => new URL(l.href, document.location.href).pathname.endsWith(data.changedPath)); + if (styleSheet) { + styleSheet.href = styleSheet.href.replace(/\\?.*/, '') + '?' + Date.now(); + } + } else { + $sendMessageToParent({ kind: "reload" }); + } + } + } + }) + .catch(err => { + console.error(err); + setTimeout($watchChanges, 1000); + }); + +} +$watchChanges(); +`; + return additionalJsCode; +} + +// #endregion + +// #region Bundling + +class CachedBundle { + public readonly entryModulePath = this.mapper.resolveRequestToPath(this.moduleId)!; + + constructor( + private readonly moduleId: string, + private readonly mapper: SimpleModuleIdPathMapper, + ) { + } + + private loader: ModuleLoader | undefined = undefined; + + private bundlePromise: Promise | undefined = undefined; + public async bundle(): Promise { + if (!this.bundlePromise) { + this.bundlePromise = (async () => { + if (!this.loader) { + this.loader = new ModuleLoader(this.mapper); + await this.loader.addModuleAndDependencies(this.entryModulePath); + } + const editorEntryPoint = await this.loader.getModule(this.entryModulePath); + const content = bundleWithDependencies(editorEntryPoint!); + return content; + })(); + } + return this.bundlePromise; + } + + public async setModuleContent(path: string, newContent: string): Promise { + if (!this.loader) { + return; + } + const module = await this.loader!.getModule(path); + if (module) { + if (!this.loader.updateContent(module, newContent)) { + this.loader = undefined; + } + } + this.bundlePromise = undefined; + } +} + +function bundleWithDependencies(module: IModule): Buffer { + const visited = new Set(); + const builder = new SourceMapBuilder(); + + function visit(module: IModule) { + if (visited.has(module)) { + return; + } + visited.add(module); + for (const dep of module.dependencies) { + visit(dep); + } + builder.addSource(module.source); + } + + visit(module); + + const sourceMap = builder.toSourceMap(); + sourceMap.sourceRoot = module.source.sourceMap.sourceRoot; + const sourceMapBase64Str = Buffer.from(JSON.stringify(sourceMap)).toString('base64'); + + builder.addLine(`//# sourceMappingURL=data:application/json;base64,${sourceMapBase64Str}`); + + return builder.toContent(); +} + +class ModuleLoader { + private readonly modules = new Map>(); + + constructor(private readonly mapper: SimpleModuleIdPathMapper) { } + + public getModule(path: string): Promise { + return Promise.resolve(this.modules.get(path)); + } + + public updateContent(module: IModule, newContent: string): boolean { + const parsedModule = parseModule(newContent, module.path, this.mapper); + if (!parsedModule) { + return false; + } + if (!arrayEquals(parsedModule.dependencyRequests, module.dependencyRequests)) { + return false; + } + + module.dependencyRequests = parsedModule.dependencyRequests; + module.source = parsedModule.source; + + return true; + } + + async addModuleAndDependencies(path: string): Promise { + if (this.modules.has(path)) { + return this.modules.get(path)!; + } + + const promise = (async () => { + const content = await fsPromise.readFile(path, { encoding: 'utf-8' }); + + const parsedModule = parseModule(content, path, this.mapper); + if (!parsedModule) { + return undefined; + } + + const dependencies = (await Promise.all(parsedModule.dependencyRequests.map(async r => { + if (r === 'require' || r === 'exports' || r === 'module') { + return null; + } + + const depPath = this.mapper.resolveRequestToPath(r, path); + if (!depPath) { + return null; + } + return await this.addModuleAndDependencies(depPath); + }))).filter((d): d is IModule => !!d); + + const module: IModule = { + id: this.mapper.getModuleId(path)!, + dependencyRequests: parsedModule.dependencyRequests, + dependencies, + path, + source: parsedModule.source, + }; + return module; + })(); + + this.modules.set(path, promise); + return promise; + } +} + +function arrayEquals(a: T[], b: T[]): boolean { + if (a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +} + +const encoder = new TextEncoder(); + +function parseModule(content: string, path: string, mapper: SimpleModuleIdPathMapper): { source: Source; dependencyRequests: string[] } | undefined { + const m = content.match(/define\((\[.*?\])/); + if (!m) { + return undefined; + } + + const dependencyRequests = JSON.parse(m[1].replace(/'/g, '"')) as string[]; + + const sourceMapHeader = '//# sourceMappingURL=data:application/json;base64,'; + const idx = content.indexOf(sourceMapHeader); + + let sourceMap: any = null; + if (idx !== -1) { + const sourceMapJsonStr = Buffer.from(content.substring(idx + sourceMapHeader.length), 'base64').toString('utf-8'); + sourceMap = JSON.parse(sourceMapJsonStr); + content = content.substring(0, idx); + } + + content = content.replace('define([', `define("${mapper.getModuleId(path)}", [`); + + const contentBuffer = Buffer.from(encoder.encode(content)); + const source = new Source(contentBuffer, sourceMap); + + return { dependencyRequests, source }; +} + +class SimpleModuleIdPathMapper { + constructor(public readonly rootDir: string) { } + + public getModuleId(path: string): string | null { + if (!path.startsWith(this.rootDir) || !path.endsWith('.js')) { + return null; + } + const moduleId = path.substring(this.rootDir.length + 1); + + + return moduleId.replace(/\\/g, '/').substring(0, moduleId.length - 3); + } + + public resolveRequestToPath(request: string, requestingModulePath?: string): string | null { + if (request.indexOf('css!') !== -1) { + return null; + } + + if (request.startsWith('.')) { + return path.join(path.dirname(requestingModulePath!), request + '.js'); + } else { + return path.join(this.rootDir, request + '.js'); + } + } +} + +interface IModule { + id: string; + dependencyRequests: string[]; + dependencies: IModule[]; + path: string; + source: Source; +} + +// #endregion + +// #region SourceMapBuilder + +// From https://stackoverflow.com/questions/29905373/how-to-create-sourcemaps-for-concatenated-files with modifications + +class Source { + // Ends with \n + public readonly content: Buffer; + public readonly sourceMap: SourceMap; + public readonly sourceLines: number; + + public readonly sourceMapMappings: Buffer; + + + constructor(content: Buffer, sourceMap: SourceMap | undefined) { + if (!sourceMap) { + sourceMap = SourceMapBuilder.emptySourceMap; + } + + let sourceLines = countNL(content); + if (content.length > 0 && content[content.length - 1] !== 10) { + sourceLines++; + content = Buffer.concat([content, Buffer.from([10])]); + } + + this.content = content; + this.sourceMap = sourceMap; + this.sourceLines = sourceLines; + this.sourceMapMappings = typeof this.sourceMap.mappings === 'string' + ? Buffer.from(encoder.encode(sourceMap.mappings as string)) + : this.sourceMap.mappings; + } +} + +class SourceMapBuilder { + public static emptySourceMap: SourceMap = { version: 3, sources: [], mappings: Buffer.alloc(0) }; + + private readonly outputBuffer = new DynamicBuffer(); + private readonly sources: string[] = []; + private readonly mappings = new DynamicBuffer(); + private lastSourceIndex = 0; + private lastSourceLine = 0; + private lastSourceCol = 0; + + addLine(text: string) { + this.outputBuffer.addString(text); + this.outputBuffer.addByte(10); + this.mappings.addByte(59); // ; + } + + addSource(source: Source) { + const sourceMap = source.sourceMap; + this.outputBuffer.addBuffer(source.content); + + const sourceRemap: number[] = []; + for (const v of sourceMap.sources) { + let pos = this.sources.indexOf(v); + if (pos < 0) { + pos = this.sources.length; + this.sources.push(v); + } + sourceRemap.push(pos); + } + let lastOutputCol = 0; + + const inputMappings = source.sourceMapMappings; + let outputLine = 0; + let ip = 0; + let inOutputCol = 0; + let inSourceIndex = 0; + let inSourceLine = 0; + let inSourceCol = 0; + let shift = 0; + let value = 0; + let valpos = 0; + const commit = () => { + if (valpos === 0) { return; } + this.mappings.addVLQ(inOutputCol - lastOutputCol); + lastOutputCol = inOutputCol; + if (valpos === 1) { + valpos = 0; + return; + } + const outSourceIndex = sourceRemap[inSourceIndex]; + this.mappings.addVLQ(outSourceIndex - this.lastSourceIndex); + this.lastSourceIndex = outSourceIndex; + this.mappings.addVLQ(inSourceLine - this.lastSourceLine); + this.lastSourceLine = inSourceLine; + this.mappings.addVLQ(inSourceCol - this.lastSourceCol); + this.lastSourceCol = inSourceCol; + valpos = 0; + }; + while (ip < inputMappings.length) { + let b = inputMappings[ip++]; + if (b === 59) { // ; + commit(); + this.mappings.addByte(59); + inOutputCol = 0; + lastOutputCol = 0; + outputLine++; + } else if (b === 44) { // , + commit(); + this.mappings.addByte(44); + } else { + b = charToInteger[b]; + if (b === 255) { throw new Error('Invalid sourceMap'); } + value += (b & 31) << shift; + if (b & 32) { + shift += 5; + } else { + const shouldNegate = value & 1; + value >>= 1; + if (shouldNegate) { value = -value; } + switch (valpos) { + case 0: inOutputCol += value; break; + case 1: inSourceIndex += value; break; + case 2: inSourceLine += value; break; + case 3: inSourceCol += value; break; + } + valpos++; + value = shift = 0; + } + } + } + commit(); + while (outputLine < source.sourceLines) { + this.mappings.addByte(59); + outputLine++; + } + } + + toContent(): Buffer { + return this.outputBuffer.toBuffer(); + } + + toSourceMap(sourceRoot?: string): SourceMap { + return { version: 3, sourceRoot, sources: this.sources, mappings: this.mappings.toBuffer().toString() }; + } +} + +export interface SourceMap { + version: number; // always 3 + file?: string; + sourceRoot?: string; + sources: string[]; + sourcesContent?: string[]; + names?: string[]; + mappings: string | Buffer; +} + +const charToInteger = Buffer.alloc(256); +const integerToChar = Buffer.alloc(64); + +charToInteger.fill(255); + +'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('').forEach((char, i) => { + charToInteger[char.charCodeAt(0)] = i; + integerToChar[i] = char.charCodeAt(0); +}); + +class DynamicBuffer { + private buffer: Buffer; + private size: number; + + constructor() { + this.buffer = Buffer.alloc(512); + this.size = 0; + } + + ensureCapacity(capacity: number) { + if (this.buffer.length >= capacity) { + return; + } + const oldBuffer = this.buffer; + this.buffer = Buffer.alloc(Math.max(oldBuffer.length * 2, capacity)); + oldBuffer.copy(this.buffer); + } + + addByte(b: number) { + this.ensureCapacity(this.size + 1); + this.buffer[this.size++] = b; + } + + addVLQ(num: number) { + let clamped: number; + + if (num < 0) { + num = (-num << 1) | 1; + } else { + num <<= 1; + } + + do { + clamped = num & 31; + num >>= 5; + + if (num > 0) { + clamped |= 32; + } + + this.addByte(integerToChar[clamped]); + } while (num > 0); + } + + addString(s: string) { + const l = Buffer.byteLength(s); + this.ensureCapacity(this.size + l); + this.buffer.write(s, this.size); + this.size += l; + } + + addBuffer(b: Buffer) { + this.ensureCapacity(this.size + b.length); + b.copy(this.buffer, this.size); + this.size += b.length; + } + + toBuffer(): Buffer { + return this.buffer.slice(0, this.size); + } +} + +function countNL(b: Buffer): number { + let res = 0; + for (let i = 0; i < b.length; i++) { + if (b[i] === 10) { res++; } + } + return res; +} + +// #endregion diff --git a/yarn.lock b/yarn.lock index 0522a5dbe8a..c1128d17671 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2007,13 +2007,6 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" -async@^2.6.4: - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2067,7 +2060,7 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -basic-auth@^2.0.1, basic-auth@~2.0.1: +basic-auth@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== @@ -2422,7 +2415,7 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.1.2, chalk@^4.x: +chalk@^4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2893,11 +2886,6 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -corser@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" - integrity sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ== - cosmiconfig@^5.0.0: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" @@ -3157,7 +3145,7 @@ debug@3.1.0: dependencies: ms "2.0.0" -debug@3.X, debug@^3.2.7: +debug@3.X: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -4074,11 +4062,6 @@ event-stream@~3.3.4: stream-combiner "^0.2.2" through "^2.3.8" -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - events@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" @@ -4452,11 +4435,6 @@ flush-write-stream@^1.0.2: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@^1.0.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== - for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -5276,7 +5254,7 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -he@1.2.0, he@^1.2.0: +he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== @@ -5317,13 +5295,6 @@ hsla-regex@^1.0.0: resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= -html-encoding-sniffer@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" - integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== - dependencies: - whatwg-encoding "^2.0.0" - html-escaper@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491" @@ -5400,34 +5371,6 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy@^1.18.1: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-server@^14.1.1: - version "14.1.1" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-14.1.1.tgz#d60fbb37d7c2fdff0f0fbff0d0ee6670bd285e2e" - integrity sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A== - dependencies: - basic-auth "^2.0.1" - chalk "^4.1.2" - corser "^2.0.1" - he "^1.2.0" - html-encoding-sniffer "^3.0.0" - http-proxy "^1.18.1" - mime "^1.6.0" - minimist "^1.2.6" - opener "^1.5.1" - portfinder "^1.0.28" - secure-compare "3.0.1" - union "~0.5.0" - url-join "^4.0.1" - http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" @@ -5470,13 +5413,6 @@ husky@^0.13.1: is-ci "^1.0.9" normalize-path "^1.0.0" -iconv-lite@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - iconv-lite@^0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -6822,7 +6758,7 @@ mime@^1.3.4: resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== -mime@^1.4.1, mime@^1.6.0: +mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -6923,7 +6859,7 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: dependencies: minimist "^1.2.5" -mkdirp@^0.5.5, mkdirp@^0.5.6: +mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -7346,11 +7282,6 @@ object-inspect@^1.8.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== -object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -7461,11 +7392,6 @@ only@~0.0.2: resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= -opener@^1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - opn@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/opn/-/opn-6.0.0.tgz#3c5b0db676d5f97da1233d1ed42d182bc5a27d2d" @@ -7899,15 +7825,6 @@ plugin-error@^1.0.0, plugin-error@^1.0.1: arr-union "^3.1.0" extend-shallow "^3.0.2" -portfinder@^1.0.28: - version "1.0.32" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.32.tgz#2fe1b9e58389712429dc2bea5beb2146146c7f81" - integrity sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg== - dependencies: - async "^2.6.4" - debug "^3.2.7" - mkdirp "^0.5.6" - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -8390,13 +8307,6 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qs@^6.4.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - queue@3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/queue/-/queue-3.0.6.tgz#66c0ffd0a1d9d28045adebda966a2d3946ab9f13" @@ -8640,11 +8550,6 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - resolve-alpn@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" @@ -8826,7 +8731,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -8864,11 +8769,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" -secure-compare@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" - integrity sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw== - seek-bzip@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" @@ -9009,15 +8909,6 @@ shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - sigmund@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -10122,13 +10013,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -union@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075" - integrity sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA== - dependencies: - qs "^6.4.0" - uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -10195,11 +10079,6 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-join@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" - integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -10549,13 +10428,6 @@ webpack@^5.77.0: watchpack "^2.4.0" webpack-sources "^3.2.3" -whatwg-encoding@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" - integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== - dependencies: - iconv-lite "0.6.3" - whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"