/
githubmirror
/
angular-cli
Обзор
Документация
Войти
/
githubmirror
/
angular-cli
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/angular/build/src/tools/esbuild/stylesheets/less-language.ts
155 строк
4 KB
Alan Agius
fix(@angular/build): remove deprecated `javascriptEnabled` option for Less
22 сен 2025, 16:47
22 сен 2025, 16:47
1397585
Код
Авторство
О чём код?
/** * @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 type { Location, OnLoadResult, PluginBuild } from 'esbuild'; import { readFile } from 'node:fs/promises'; import { StylesheetLanguage, StylesheetPluginOptions } from './stylesheet-plugin-factory'; /** * The lazy-loaded instance of the less stylesheet preprocessor. * It is only imported and initialized if a less stylesheet is used. */ let lessPreprocessor: typeof import('less') | undefined; interface LessException extends Error { filename: string; line: number; column: number; extract?: string[]; } function isLessException(error: unknown): error is LessException { return !!error && typeof error === 'object' && 'column' in error; } export const LessStylesheetLanguage = Object.freeze<StylesheetLanguage>({ name: 'less', componentFilter: /^less;/, fileFilter: /\.less$/, process(data, file, _, options, build) { return compileString(data, file, options, build.resolve.bind(build)); }, }); async function compileString( data: string, filename: string, options: StylesheetPluginOptions, resolver: PluginBuild['resolve'], ): Promise<OnLoadResult> { try { lessPreprocessor ??= (await import('less')).default; } catch { return { errors: [ { text: 'Unable to load the "less" stylesheet preprocessor.', location: null, notes: [ { text: 'Ensure that the "less" Node.js package is installed within the project. ' + "If not present, installation via the project's package manager should resolve the error.", }, ], }, ], }; } const less = lessPreprocessor; const resolverPlugin: Less.Plugin = { install({ FileManager }, pluginManager): void { const resolverFileManager = new (class extends FileManager { override supportsSync(): boolean { return false; } override supports(): boolean { return true; } override async loadFile( filename: string, currentDirectory: string, options: Less.LoadFileOptions, environment: Less.Environment, ): Promise<Less.FileLoadResult> { // Attempt direct loading as a relative path to avoid resolution overhead try { return await super.loadFile(filename, currentDirectory, options, environment); } catch (error) { // Attempt a full resolution if not found const fullResult = await resolver(filename, { kind: 'import-rule', resolveDir: currentDirectory, }); if (fullResult.path) { return { filename: fullResult.path, contents: await readFile(fullResult.path, 'utf-8'), }; } // Otherwise error by throwing the failing direct result throw error; } } })(); pluginManager.addFileManager(resolverFileManager); }, }; try { const { imports, css } = await less.render(data, { filename, paths: options.includePaths, plugins: [resolverPlugin], rewriteUrls: 'all', sourceMap: options.sourcemap ? { sourceMapFileInline: true, outputSourceFiles: true, } : undefined, } as Less.Options); return { contents: css, loader: 'css', watchFiles: [filename, ...imports], }; } catch (error) { if (isLessException(error)) { const location = convertExceptionLocation(error); return { errors: [ { text: error.message, location, }, ], loader: 'css', watchFiles: location.file ? [filename, location.file] : [filename], }; } throw error; } } function convertExceptionLocation(exception: LessException): Partial<Location> { return { file: exception.filename, line: exception.line, column: exception.column, // Middle element represents the line containing the exception lineText: exception.extract && exception.extract[Math.trunc(exception.extract.length / 2)], }; }