From 8b74a50e7be0889171c55545b43a28119191b04a Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:02:37 -0400 Subject: [PATCH] fix(@angular-devkit/build-angular): encode Sass package resolve directories in importer URLs When using the new developer preview application build system, Sass import/use usage that specifies a package is adjusted to contain the resolve directory to workaround Sass import plugin limitations. This resolve directory is now encoded to prevent the new specifier from looking like a URL with a scheme to the Sass compiler. This can occur on Windows when a drive letter is present (`C:\`). --- .../src/tools/sass/rebasing-importer.ts | 23 ++++++++++++------- .../build/styles/scss-partial-resolution.ts | 8 +++++-- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/tools/sass/rebasing-importer.ts b/packages/angular_devkit/build_angular/src/tools/sass/rebasing-importer.ts index 3d72ef5fbc4f..7e8ad4a9e6ab 100644 --- a/packages/angular_devkit/build_angular/src/tools/sass/rebasing-importer.ts +++ b/packages/angular_devkit/build_angular/src/tools/sass/rebasing-importer.ts @@ -33,13 +33,20 @@ export interface DirectoryEntry { const MODULE_RESOLUTION_PREFIX = '__NG_PACKAGE__'; function packModuleSpecifier(specifier: string, resolveDir: string): string { - const packed = MODULE_RESOLUTION_PREFIX + ';' + resolveDir + ';' + specifier; - - // Normalize path separators and escape characters - // https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax - const normalizedPacked = packed.replace(/\\/g, '/').replace(/[()\s'"]/g, '\\$&'); - - return normalizedPacked; + const packed = + MODULE_RESOLUTION_PREFIX + + ';' + + // Encode the resolve directory to prevent unsupported characters from being present when + // Sass processes the URL. This is important on Windows which can contain drive letters + // and colons which would otherwise be interpreted as a URL scheme. + encodeURIComponent(resolveDir) + + ';' + + // Escape characters instead of encoding to provide more friendly not found error messages. + // Unescaping is automatically handled by Sass. + // https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax + specifier.replace(/[()\s'"]/g, '\\$&'); + + return packed; } function unpackModuleSpecifier(specifier: string): { specifier: string; resolveDir?: string } { @@ -51,7 +58,7 @@ function unpackModuleSpecifier(specifier: string): { specifier: string; resolveD return { specifier: values[2], - resolveDir: values[1], + resolveDir: decodeURIComponent(values[1]), }; } diff --git a/tests/legacy-cli/e2e/tests/build/styles/scss-partial-resolution.ts b/tests/legacy-cli/e2e/tests/build/styles/scss-partial-resolution.ts index f3863ad72adb..313ec5e03e58 100644 --- a/tests/legacy-cli/e2e/tests/build/styles/scss-partial-resolution.ts +++ b/tests/legacy-cli/e2e/tests/build/styles/scss-partial-resolution.ts @@ -12,10 +12,14 @@ export default async function () { await writeMultipleFiles({ 'src/styles.scss': ` - @use '@material/button/button' as mat; + @use '@material/button/button'; + + @include button.core-styles; `, 'src/app/app.component.scss': ` - @use '@material/button/button' as mat; + @use '@material/button/button'; + + @include button.core-styles; `, });