117 lines
4.2 KiB
JavaScript
Executable file
117 lines
4.2 KiB
JavaScript
Executable file
"use strict";
|
|
/**
|
|
* @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
|
|
*/
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.findImports = findImports;
|
|
/**
|
|
* Determines if a unicode code point is a CSS whitespace character.
|
|
* @param code The unicode code point to test.
|
|
* @returns true, if the code point is CSS whitespace; false, otherwise.
|
|
*/
|
|
function isWhitespace(code) {
|
|
// Based on https://www.w3.org/TR/css-syntax-3/#whitespace
|
|
switch (code) {
|
|
case 0x0009: // tab
|
|
case 0x0020: // space
|
|
case 0x000a: // line feed
|
|
case 0x000c: // form feed
|
|
case 0x000d: // carriage return
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Scans a CSS or Sass file and locates all valid import/use directive values as defined by the
|
|
* syntax specification.
|
|
* @param contents A string containing a CSS or Sass file to scan.
|
|
* @returns An iterable that yields each CSS directive value found.
|
|
*/
|
|
function* findImports(contents, sass) {
|
|
yield* find(contents, '@import ');
|
|
if (sass) {
|
|
for (const result of find(contents, '@use ')) {
|
|
yield { ...result, fromUse: true };
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Scans a CSS or Sass file and locates all valid function/directive values as defined by the
|
|
* syntax specification.
|
|
* @param contents A string containing a CSS or Sass file to scan.
|
|
* @param prefix The prefix to start a valid segment.
|
|
* @returns An iterable that yields each CSS url function value found.
|
|
*/
|
|
function* find(contents, prefix) {
|
|
let pos = 0;
|
|
let width = 1;
|
|
let current = -1;
|
|
const next = () => {
|
|
pos += width;
|
|
current = contents.codePointAt(pos) ?? -1;
|
|
width = current > 0xffff ? 2 : 1;
|
|
return current;
|
|
};
|
|
// Based on https://www.w3.org/TR/css-syntax-3/#consume-ident-like-token
|
|
while ((pos = contents.indexOf(prefix, pos)) !== -1) {
|
|
// Set to position of the last character in prefix
|
|
pos += prefix.length - 1;
|
|
width = 1;
|
|
// Consume all leading whitespace
|
|
while (isWhitespace(next())) {
|
|
/* empty */
|
|
}
|
|
// Initialize URL state
|
|
const url = { start: pos, end: -1, specifier: '' };
|
|
let complete = false;
|
|
// If " or ', then consume the value as a string
|
|
if (current === 0x0022 || current === 0x0027) {
|
|
const ending = current;
|
|
// Based on https://www.w3.org/TR/css-syntax-3/#consume-string-token
|
|
while (!complete) {
|
|
switch (next()) {
|
|
case -1: // EOF
|
|
return;
|
|
case 0x000a: // line feed
|
|
case 0x000c: // form feed
|
|
case 0x000d: // carriage return
|
|
// Invalid
|
|
complete = true;
|
|
break;
|
|
case 0x005c: // \ -- character escape
|
|
// If not EOF or newline, add the character after the escape
|
|
switch (next()) {
|
|
case -1:
|
|
return;
|
|
case 0x000a: // line feed
|
|
case 0x000c: // form feed
|
|
case 0x000d: // carriage return
|
|
// Skip when inside a string
|
|
break;
|
|
default:
|
|
// TODO: Handle hex escape codes
|
|
url.specifier += String.fromCodePoint(current);
|
|
break;
|
|
}
|
|
break;
|
|
case ending:
|
|
// Full string position should include the quotes for replacement
|
|
url.end = pos + 1;
|
|
complete = true;
|
|
yield url;
|
|
break;
|
|
default:
|
|
url.specifier += String.fromCodePoint(current);
|
|
break;
|
|
}
|
|
}
|
|
next();
|
|
continue;
|
|
}
|
|
}
|
|
}
|