From f17b78de7efabd788a315902174700caa1a1eed8 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 29 May 2024 11:07:32 -0400 Subject: [PATCH] fix(@angular/build): improve Sass rebaser ident token detection When rebasing URLs within Sass files, the `url` token will now be more accurately detected by ensuring it is not part of a larger token. This prevents custom Sass functions that happen to have a name the ends with `url` from being incorrectly detected. --- .../stylesheet-url-resolution_spec.ts | 27 +++++++++++++++++++ .../angular/build/src/tools/sass/lexer.ts | 15 ++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/application/tests/behavior/stylesheet-url-resolution_spec.ts b/packages/angular/build/src/builders/application/tests/behavior/stylesheet-url-resolution_spec.ts index a66248b55561..ebe3a8f2762f 100644 --- a/packages/angular/build/src/builders/application/tests/behavior/stylesheet-url-resolution_spec.ts +++ b/packages/angular/build/src/builders/application/tests/behavior/stylesheet-url-resolution_spec.ts @@ -321,6 +321,33 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => { harness.expectFile('dist/browser/media/logo.svg').toExist(); }); + it('should not rebase Sass function definition with name ending in "url"', async () => { + await harness.writeFiles({ + 'src/styles.scss': `@use 'theme/a';`, + 'src/theme/a.scss': ` + @import './b'; + .a { + $asset: my-function-url('logo'); + background-image: url($asset) + } + `, + 'src/theme/b.scss': `@function my-function-url($name) { @return "./images/" + $name + ".svg"; }`, + 'src/theme/images/logo.svg': ``, + }); + + harness.useTarget('build', { + ...BASE_OPTIONS, + outputHashing: OutputHashing.None, + styles: ['src/styles.scss'], + }); + + const { result } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + + harness.expectFile('dist/browser/styles.css').content.toContain(`url("./media/logo.svg")`); + harness.expectFile('dist/browser/media/logo.svg').toExist(); + }); + it('should not process a URL that has been marked as external', async () => { await harness.writeFiles({ 'src/styles.scss': `@use 'theme/a';`, diff --git a/packages/angular/build/src/tools/sass/lexer.ts b/packages/angular/build/src/tools/sass/lexer.ts index abd9a65eb556..35387cd73492 100644 --- a/packages/angular/build/src/tools/sass/lexer.ts +++ b/packages/angular/build/src/tools/sass/lexer.ts @@ -49,9 +49,22 @@ export function* findUrls( // Based on https://www.w3.org/TR/css-syntax-3/#consume-ident-like-token while ((pos = contents.indexOf('url(', pos)) !== -1) { + width = 1; + + // Ensure whitespace, comma, or colon before `url(` + if (pos > 0) { + pos -= 2; + next(); + if (!isWhitespace(current) && current !== 0x0027 && current !== 0x003a) { + // Skip - not a url token + pos += 3; + continue; + } + pos += 1; + } + // Set to position of the ( pos += 3; - width = 1; // Consume all leading whitespace while (isWhitespace(next())) {