/
githubmirror
/
angular-cli
Обзор
Документация
Войти
/
githubmirror
/
angular-cli
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/angular/build/src/utils/load-proxy-config.ts
187 строк
5 KB
Alan Agius
refactor: replace `loadEsmModule` with dynamic `import()`
21 окт 2025, 16:05
21 окт 2025, 16:05
b356bb1
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import { existsSync } from 'node:fs'; import { readFile } from 'node:fs/promises'; import { extname, resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; import { makeRe as makeRegExpFromGlob } from 'picomatch'; import { isDynamicPattern } from 'tinyglobby'; import { assertIsError } from './error'; import { loadEsmModule } from './load-esm'; export async function loadProxyConfiguration( root: string, proxyConfig: string | undefined, ): Promise<Record<string, object> | undefined> { if (!proxyConfig) { return undefined; } const proxyPath = resolve(root, proxyConfig); if (!existsSync(proxyPath)) { throw new Error(`Proxy configuration file ${proxyPath} does not exist.`); } let proxyConfiguration; switch (extname(proxyPath)) { case '.json': { const content = await readFile(proxyPath, 'utf-8'); const { parse, printParseErrorCode } = await import('jsonc-parser'); const parseErrors: import('jsonc-parser').ParseError[] = []; proxyConfiguration = parse(content, parseErrors, { allowTrailingComma: true }); if (parseErrors.length > 0) { let errorMessage = `Proxy configuration file ${proxyPath} contains parse errors:`; for (const parseError of parseErrors) { const { line, column } = getJsonErrorLineColumn(parseError.offset, content); errorMessage += `\n[${line}, ${column}] ${printParseErrorCode(parseError.error)}`; } throw new Error(errorMessage); } break; } default: { try { proxyConfiguration = await import(proxyPath); } catch (e) { assertIsError(e); if (e.code !== 'ERR_REQUIRE_ASYNC_MODULE') { throw e; } proxyConfiguration = await loadEsmModule<{ default: unknown }>(pathToFileURL(proxyPath)); } break; } } if ('default' in proxyConfiguration) { proxyConfiguration = proxyConfiguration.default; } return normalizeProxyConfiguration(proxyConfiguration); } /** * Converts glob patterns to regular expressions to support Vite's proxy option. * Also converts the Webpack supported array form to an object form supported by both. * * @param proxy A proxy configuration object. */ function normalizeProxyConfiguration( proxy: Record<string, object> | object[], ): Record<string, object> { let normalizedProxy: Record<string, object> | undefined; if (Array.isArray(proxy)) { // Construct an object-form proxy configuration from the array normalizedProxy = {}; for (const proxyEntry of proxy) { if (!('context' in proxyEntry)) { continue; } if (!Array.isArray(proxyEntry.context)) { continue; } // Array-form entries contain a context string array with the path(s) // to use for the configuration entry. const context = proxyEntry.context; delete proxyEntry.context; for (const contextEntry of context) { if (typeof contextEntry !== 'string') { continue; } normalizedProxy[contextEntry] = proxyEntry; } } } else { normalizedProxy = proxy; } // TODO: Consider upstreaming glob support for (const key of Object.keys(normalizedProxy)) { if (key[0] !== '^' && isDynamicPattern(key)) { const pattern = makeRegExpFromGlob(key).source; normalizedProxy[pattern] = normalizedProxy[key]; delete normalizedProxy[key]; } } // Replace `pathRewrite` field with a `rewrite` function for (const proxyEntry of Object.values(normalizedProxy)) { if ( typeof proxyEntry === 'object' && 'pathRewrite' in proxyEntry && proxyEntry.pathRewrite && typeof proxyEntry.pathRewrite === 'object' ) { // Preprocess path rewrite entries const pathRewriteEntries: [RegExp, string][] = []; for (const [pattern, value] of Object.entries( proxyEntry.pathRewrite as Record<string, string>, )) { pathRewriteEntries.push([new RegExp(pattern), value]); } (proxyEntry as Record<string, unknown>).rewrite = pathRewriter.bind( undefined, pathRewriteEntries, ); delete proxyEntry.pathRewrite; } } return normalizedProxy; } function pathRewriter(pathRewriteEntries: [RegExp, string][], path: string): string { for (const [pattern, value] of pathRewriteEntries) { const updated = path.replace(pattern, value); if (path !== updated) { return updated; } } return path; } /** * Calculates the line and column for an error offset in the content of a JSON file. * @param location The offset error location from the beginning of the content. * @param content The full content of the file containing the error. * @returns An object containing the line and column */ function getJsonErrorLineColumn(offset: number, content: string) { if (offset === 0) { return { line: 1, column: 1 }; } let line = 0; let position = 0; // eslint-disable-next-line no-constant-condition while (true) { ++line; const nextNewline = content.indexOf('\n', position); if (nextNewline === -1 || nextNewline > offset) { break; } position = nextNewline + 1; } return { line, column: offset - position + 1 }; }