feat: docker compose maybe
This commit is contained in:
469
node_modules/css-tree/lib/utils/List.js
generated
vendored
Normal file
469
node_modules/css-tree/lib/utils/List.js
generated
vendored
Normal file
@ -0,0 +1,469 @@
|
||||
//
|
||||
// list
|
||||
// ┌──────┐
|
||||
// ┌──────────────┼─head │
|
||||
// │ │ tail─┼──────────────┐
|
||||
// │ └──────┘ │
|
||||
// ▼ ▼
|
||||
// item item item item
|
||||
// ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
|
||||
// null ◀──┼─prev │◀───┼─prev │◀───┼─prev │◀───┼─prev │
|
||||
// │ next─┼───▶│ next─┼───▶│ next─┼───▶│ next─┼──▶ null
|
||||
// ├──────┤ ├──────┤ ├──────┤ ├──────┤
|
||||
// │ data │ │ data │ │ data │ │ data │
|
||||
// └──────┘ └──────┘ └──────┘ └──────┘
|
||||
//
|
||||
|
||||
let releasedCursors = null;
|
||||
|
||||
export class List {
|
||||
static createItem(data) {
|
||||
return {
|
||||
prev: null,
|
||||
next: null,
|
||||
data
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
this.cursor = null;
|
||||
}
|
||||
createItem(data) {
|
||||
return List.createItem(data);
|
||||
}
|
||||
|
||||
// cursor helpers
|
||||
allocateCursor(prev, next) {
|
||||
let cursor;
|
||||
|
||||
if (releasedCursors !== null) {
|
||||
cursor = releasedCursors;
|
||||
releasedCursors = releasedCursors.cursor;
|
||||
cursor.prev = prev;
|
||||
cursor.next = next;
|
||||
cursor.cursor = this.cursor;
|
||||
} else {
|
||||
cursor = {
|
||||
prev,
|
||||
next,
|
||||
cursor: this.cursor
|
||||
};
|
||||
}
|
||||
|
||||
this.cursor = cursor;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
releaseCursor() {
|
||||
const { cursor } = this;
|
||||
|
||||
this.cursor = cursor.cursor;
|
||||
cursor.prev = null;
|
||||
cursor.next = null;
|
||||
cursor.cursor = releasedCursors;
|
||||
releasedCursors = cursor;
|
||||
}
|
||||
updateCursors(prevOld, prevNew, nextOld, nextNew) {
|
||||
let { cursor } = this;
|
||||
|
||||
while (cursor !== null) {
|
||||
if (cursor.prev === prevOld) {
|
||||
cursor.prev = prevNew;
|
||||
}
|
||||
|
||||
if (cursor.next === nextOld) {
|
||||
cursor.next = nextNew;
|
||||
}
|
||||
|
||||
cursor = cursor.cursor;
|
||||
}
|
||||
}
|
||||
*[Symbol.iterator]() {
|
||||
for (let cursor = this.head; cursor !== null; cursor = cursor.next) {
|
||||
yield cursor.data;
|
||||
}
|
||||
}
|
||||
|
||||
// getters
|
||||
get size() {
|
||||
let size = 0;
|
||||
|
||||
for (let cursor = this.head; cursor !== null; cursor = cursor.next) {
|
||||
size++;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
get isEmpty() {
|
||||
return this.head === null;
|
||||
}
|
||||
get first() {
|
||||
return this.head && this.head.data;
|
||||
}
|
||||
get last() {
|
||||
return this.tail && this.tail.data;
|
||||
}
|
||||
|
||||
// convertors
|
||||
fromArray(array) {
|
||||
let cursor = null;
|
||||
this.head = null;
|
||||
|
||||
for (let data of array) {
|
||||
const item = List.createItem(data);
|
||||
|
||||
if (cursor !== null) {
|
||||
cursor.next = item;
|
||||
} else {
|
||||
this.head = item;
|
||||
}
|
||||
|
||||
item.prev = cursor;
|
||||
cursor = item;
|
||||
}
|
||||
|
||||
this.tail = cursor;
|
||||
return this;
|
||||
}
|
||||
toArray() {
|
||||
return [...this];
|
||||
}
|
||||
toJSON() {
|
||||
return [...this];
|
||||
}
|
||||
|
||||
// array-like methods
|
||||
forEach(fn, thisArg = this) {
|
||||
// push cursor
|
||||
const cursor = this.allocateCursor(null, this.head);
|
||||
|
||||
while (cursor.next !== null) {
|
||||
const item = cursor.next;
|
||||
cursor.next = item.next;
|
||||
fn.call(thisArg, item.data, item, this);
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.releaseCursor();
|
||||
}
|
||||
forEachRight(fn, thisArg = this) {
|
||||
// push cursor
|
||||
const cursor = this.allocateCursor(this.tail, null);
|
||||
|
||||
while (cursor.prev !== null) {
|
||||
const item = cursor.prev;
|
||||
cursor.prev = item.prev;
|
||||
fn.call(thisArg, item.data, item, this);
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.releaseCursor();
|
||||
}
|
||||
reduce(fn, initialValue, thisArg = this) {
|
||||
// push cursor
|
||||
let cursor = this.allocateCursor(null, this.head);
|
||||
let acc = initialValue;
|
||||
let item;
|
||||
|
||||
while (cursor.next !== null) {
|
||||
item = cursor.next;
|
||||
cursor.next = item.next;
|
||||
|
||||
acc = fn.call(thisArg, acc, item.data, item, this);
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.releaseCursor();
|
||||
|
||||
return acc;
|
||||
}
|
||||
reduceRight(fn, initialValue, thisArg = this) {
|
||||
// push cursor
|
||||
let cursor = this.allocateCursor(this.tail, null);
|
||||
let acc = initialValue;
|
||||
let item;
|
||||
|
||||
while (cursor.prev !== null) {
|
||||
item = cursor.prev;
|
||||
cursor.prev = item.prev;
|
||||
|
||||
acc = fn.call(thisArg, acc, item.data, item, this);
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.releaseCursor();
|
||||
|
||||
return acc;
|
||||
}
|
||||
some(fn, thisArg = this) {
|
||||
for (let cursor = this.head; cursor !== null; cursor = cursor.next) {
|
||||
if (fn.call(thisArg, cursor.data, cursor, this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
map(fn, thisArg = this) {
|
||||
const result = new List();
|
||||
|
||||
for (let cursor = this.head; cursor !== null; cursor = cursor.next) {
|
||||
result.appendData(fn.call(thisArg, cursor.data, cursor, this));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
filter(fn, thisArg = this) {
|
||||
const result = new List();
|
||||
|
||||
for (let cursor = this.head; cursor !== null; cursor = cursor.next) {
|
||||
if (fn.call(thisArg, cursor.data, cursor, this)) {
|
||||
result.appendData(cursor.data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nextUntil(start, fn, thisArg = this) {
|
||||
if (start === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// push cursor
|
||||
const cursor = this.allocateCursor(null, start);
|
||||
|
||||
while (cursor.next !== null) {
|
||||
const item = cursor.next;
|
||||
cursor.next = item.next;
|
||||
if (fn.call(thisArg, item.data, item, this)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.releaseCursor();
|
||||
}
|
||||
prevUntil(start, fn, thisArg = this) {
|
||||
if (start === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// push cursor
|
||||
const cursor = this.allocateCursor(start, null);
|
||||
|
||||
while (cursor.prev !== null) {
|
||||
const item = cursor.prev;
|
||||
cursor.prev = item.prev;
|
||||
if (fn.call(thisArg, item.data, item, this)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.releaseCursor();
|
||||
}
|
||||
|
||||
// mutation
|
||||
clear() {
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
}
|
||||
copy() {
|
||||
const result = new List();
|
||||
|
||||
for (let data of this) {
|
||||
result.appendData(data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
prepend(item) {
|
||||
// head
|
||||
// ^
|
||||
// item
|
||||
this.updateCursors(null, item, this.head, item);
|
||||
|
||||
// insert to the beginning of the list
|
||||
if (this.head !== null) {
|
||||
// new item <- first item
|
||||
this.head.prev = item;
|
||||
// new item -> first item
|
||||
item.next = this.head;
|
||||
} else {
|
||||
// if list has no head, then it also has no tail
|
||||
// in this case tail points to the new item
|
||||
this.tail = item;
|
||||
}
|
||||
|
||||
// head always points to new item
|
||||
this.head = item;
|
||||
return this;
|
||||
}
|
||||
prependData(data) {
|
||||
return this.prepend(List.createItem(data));
|
||||
}
|
||||
append(item) {
|
||||
return this.insert(item);
|
||||
}
|
||||
appendData(data) {
|
||||
return this.insert(List.createItem(data));
|
||||
}
|
||||
insert(item, before = null) {
|
||||
if (before !== null) {
|
||||
// prev before
|
||||
// ^
|
||||
// item
|
||||
this.updateCursors(before.prev, item, before, item);
|
||||
|
||||
if (before.prev === null) {
|
||||
// insert to the beginning of list
|
||||
if (this.head !== before) {
|
||||
throw new Error('before doesn\'t belong to list');
|
||||
}
|
||||
// since head points to before therefore list doesn't empty
|
||||
// no need to check tail
|
||||
this.head = item;
|
||||
before.prev = item;
|
||||
item.next = before;
|
||||
this.updateCursors(null, item);
|
||||
} else {
|
||||
// insert between two items
|
||||
before.prev.next = item;
|
||||
item.prev = before.prev;
|
||||
before.prev = item;
|
||||
item.next = before;
|
||||
}
|
||||
} else {
|
||||
// tail
|
||||
// ^
|
||||
// item
|
||||
this.updateCursors(this.tail, item, null, item);
|
||||
|
||||
// insert to the ending of the list
|
||||
if (this.tail !== null) {
|
||||
// last item -> new item
|
||||
this.tail.next = item;
|
||||
// last item <- new item
|
||||
item.prev = this.tail;
|
||||
} else {
|
||||
// if list has no tail, then it also has no head
|
||||
// in this case head points to new item
|
||||
this.head = item;
|
||||
}
|
||||
|
||||
// tail always points to new item
|
||||
this.tail = item;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
insertData(data, before) {
|
||||
return this.insert(List.createItem(data), before);
|
||||
}
|
||||
remove(item) {
|
||||
// item
|
||||
// ^
|
||||
// prev next
|
||||
this.updateCursors(item, item.prev, item, item.next);
|
||||
|
||||
if (item.prev !== null) {
|
||||
item.prev.next = item.next;
|
||||
} else {
|
||||
if (this.head !== item) {
|
||||
throw new Error('item doesn\'t belong to list');
|
||||
}
|
||||
|
||||
this.head = item.next;
|
||||
}
|
||||
|
||||
if (item.next !== null) {
|
||||
item.next.prev = item.prev;
|
||||
} else {
|
||||
if (this.tail !== item) {
|
||||
throw new Error('item doesn\'t belong to list');
|
||||
}
|
||||
|
||||
this.tail = item.prev;
|
||||
}
|
||||
|
||||
item.prev = null;
|
||||
item.next = null;
|
||||
|
||||
return item;
|
||||
}
|
||||
push(data) {
|
||||
this.insert(List.createItem(data));
|
||||
}
|
||||
pop() {
|
||||
return this.tail !== null ? this.remove(this.tail) : null;
|
||||
}
|
||||
unshift(data) {
|
||||
this.prepend(List.createItem(data));
|
||||
}
|
||||
shift() {
|
||||
return this.head !== null ? this.remove(this.head) : null;
|
||||
}
|
||||
prependList(list) {
|
||||
return this.insertList(list, this.head);
|
||||
}
|
||||
appendList(list) {
|
||||
return this.insertList(list);
|
||||
}
|
||||
insertList(list, before) {
|
||||
// ignore empty lists
|
||||
if (list.head === null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (before !== undefined && before !== null) {
|
||||
this.updateCursors(before.prev, list.tail, before, list.head);
|
||||
|
||||
// insert in the middle of dist list
|
||||
if (before.prev !== null) {
|
||||
// before.prev <-> list.head
|
||||
before.prev.next = list.head;
|
||||
list.head.prev = before.prev;
|
||||
} else {
|
||||
this.head = list.head;
|
||||
}
|
||||
|
||||
before.prev = list.tail;
|
||||
list.tail.next = before;
|
||||
} else {
|
||||
this.updateCursors(this.tail, list.tail, null, list.head);
|
||||
|
||||
// insert to end of the list
|
||||
if (this.tail !== null) {
|
||||
// if destination list has a tail, then it also has a head,
|
||||
// but head doesn't change
|
||||
// dest tail -> source head
|
||||
this.tail.next = list.head;
|
||||
// dest tail <- source head
|
||||
list.head.prev = this.tail;
|
||||
} else {
|
||||
// if list has no a tail, then it also has no a head
|
||||
// in this case points head to new item
|
||||
this.head = list.head;
|
||||
}
|
||||
|
||||
// tail always start point to new item
|
||||
this.tail = list.tail;
|
||||
}
|
||||
|
||||
list.head = null;
|
||||
list.tail = null;
|
||||
return this;
|
||||
}
|
||||
replace(oldItem, newItemOrList) {
|
||||
if ('head' in newItemOrList) {
|
||||
this.insertList(newItemOrList, oldItem);
|
||||
} else {
|
||||
this.insert(newItemOrList, oldItem);
|
||||
}
|
||||
|
||||
this.remove(oldItem);
|
||||
}
|
||||
}
|
21
node_modules/css-tree/lib/utils/clone.js
generated
vendored
Normal file
21
node_modules/css-tree/lib/utils/clone.js
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
import { List } from './List.js';
|
||||
|
||||
export function clone(node) {
|
||||
const result = {};
|
||||
|
||||
for (const key in node) {
|
||||
let value = node[key];
|
||||
|
||||
if (value) {
|
||||
if (Array.isArray(value) || value instanceof List) {
|
||||
value = value.map(clone);
|
||||
} else if (value.constructor === Object) {
|
||||
value = clone(value);
|
||||
}
|
||||
}
|
||||
|
||||
result[key] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
14
node_modules/css-tree/lib/utils/create-custom-error.js
generated
vendored
Normal file
14
node_modules/css-tree/lib/utils/create-custom-error.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
export function createCustomError(name, message) {
|
||||
// use Object.create(), because some VMs prevent setting line/column otherwise
|
||||
// (iOS Safari 10 even throws an exception)
|
||||
const error = Object.create(SyntaxError.prototype);
|
||||
const errorStack = new Error();
|
||||
|
||||
return Object.assign(error, {
|
||||
name,
|
||||
message,
|
||||
get stack() {
|
||||
return (errorStack.stack || '').replace(/^(.+\n){1,3}/, `${name}: ${message}\n`);
|
||||
}
|
||||
});
|
||||
};
|
101
node_modules/css-tree/lib/utils/ident.js
generated
vendored
Normal file
101
node_modules/css-tree/lib/utils/ident.js
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
import {
|
||||
isName,
|
||||
isValidEscape,
|
||||
consumeEscaped,
|
||||
decodeEscaped
|
||||
} from '../tokenizer/index.js';
|
||||
|
||||
const REVERSE_SOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\)
|
||||
|
||||
export function decode(str) {
|
||||
const end = str.length - 1;
|
||||
let decoded = '';
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
let code = str.charCodeAt(i);
|
||||
|
||||
if (code === REVERSE_SOLIDUS) {
|
||||
// special case at the ending
|
||||
if (i === end) {
|
||||
// if the next input code point is EOF, do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
code = str.charCodeAt(++i);
|
||||
|
||||
// consume escaped
|
||||
if (isValidEscape(REVERSE_SOLIDUS, code)) {
|
||||
const escapeStart = i - 1;
|
||||
const escapeEnd = consumeEscaped(str, escapeStart);
|
||||
|
||||
i = escapeEnd - 1;
|
||||
decoded += decodeEscaped(str.substring(escapeStart + 1, escapeEnd));
|
||||
} else {
|
||||
// \r\n
|
||||
if (code === 0x000d && str.charCodeAt(i + 1) === 0x000a) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decoded += str[i];
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#serialize-an-identifier
|
||||
// § 2.1. Common Serializing Idioms
|
||||
export function encode(str) {
|
||||
let encoded = '';
|
||||
|
||||
// If the character is the first character and is a "-" (U+002D),
|
||||
// and there is no second character, then the escaped character.
|
||||
// Note: That's means a single dash string "-" return as escaped dash,
|
||||
// so move the condition out of the main loop
|
||||
if (str.length === 1 && str.charCodeAt(0) === 0x002D) {
|
||||
return '\\-';
|
||||
}
|
||||
|
||||
// To serialize an identifier means to create a string represented
|
||||
// by the concatenation of, for each character of the identifier:
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const code = str.charCodeAt(i);
|
||||
|
||||
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
|
||||
if (code === 0x0000) {
|
||||
encoded += '\uFFFD';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F ...
|
||||
// Note: Do not compare with 0x0001 since 0x0000 is precessed before
|
||||
code <= 0x001F || code === 0x007F ||
|
||||
// [or] ... is in the range [0-9] (U+0030 to U+0039),
|
||||
(code >= 0x0030 && code <= 0x0039 && (
|
||||
// If the character is the first character ...
|
||||
i === 0 ||
|
||||
// If the character is the second character ... and the first character is a "-" (U+002D)
|
||||
i === 1 && str.charCodeAt(0) === 0x002D
|
||||
))
|
||||
) {
|
||||
// ... then the character escaped as code point.
|
||||
encoded += '\\' + code.toString(16) + ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the character is not handled by one of the above rules and is greater
|
||||
// than or equal to U+0080, is "-" (U+002D) or "_" (U+005F), or is in one
|
||||
// of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to U+005A),
|
||||
// or \[a-z] (U+0061 to U+007A), then the character itself.
|
||||
if (isName(code)) {
|
||||
encoded += str.charAt(i);
|
||||
} else {
|
||||
// Otherwise, the escaped character.
|
||||
encoded += '\\' + str.charAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
6
node_modules/css-tree/lib/utils/index.js
generated
vendored
Normal file
6
node_modules/css-tree/lib/utils/index.js
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './clone.js';
|
||||
export * as ident from './ident.js';
|
||||
export * from './List.js';
|
||||
export * from './names.js';
|
||||
export * as string from './string.js';
|
||||
export * as url from './url.js';
|
106
node_modules/css-tree/lib/utils/names.js
generated
vendored
Normal file
106
node_modules/css-tree/lib/utils/names.js
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
const keywords = new Map();
|
||||
const properties = new Map();
|
||||
const HYPHENMINUS = 45; // '-'.charCodeAt()
|
||||
|
||||
export const keyword = getKeywordDescriptor;
|
||||
export const property = getPropertyDescriptor;
|
||||
export const vendorPrefix = getVendorPrefix;
|
||||
export function isCustomProperty(str, offset) {
|
||||
offset = offset || 0;
|
||||
|
||||
return str.length - offset >= 2 &&
|
||||
str.charCodeAt(offset) === HYPHENMINUS &&
|
||||
str.charCodeAt(offset + 1) === HYPHENMINUS;
|
||||
}
|
||||
|
||||
function getVendorPrefix(str, offset) {
|
||||
offset = offset || 0;
|
||||
|
||||
// verdor prefix should be at least 3 chars length
|
||||
if (str.length - offset >= 3) {
|
||||
// vendor prefix starts with hyper minus following non-hyper minus
|
||||
if (str.charCodeAt(offset) === HYPHENMINUS &&
|
||||
str.charCodeAt(offset + 1) !== HYPHENMINUS) {
|
||||
// vendor prefix should contain a hyper minus at the ending
|
||||
const secondDashIndex = str.indexOf('-', offset + 2);
|
||||
|
||||
if (secondDashIndex !== -1) {
|
||||
return str.substring(offset, secondDashIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function getKeywordDescriptor(keyword) {
|
||||
if (keywords.has(keyword)) {
|
||||
return keywords.get(keyword);
|
||||
}
|
||||
|
||||
const name = keyword.toLowerCase();
|
||||
let descriptor = keywords.get(name);
|
||||
|
||||
if (descriptor === undefined) {
|
||||
const custom = isCustomProperty(name, 0);
|
||||
const vendor = !custom ? getVendorPrefix(name, 0) : '';
|
||||
descriptor = Object.freeze({
|
||||
basename: name.substr(vendor.length),
|
||||
name,
|
||||
prefix: vendor,
|
||||
vendor,
|
||||
custom
|
||||
});
|
||||
}
|
||||
|
||||
keywords.set(keyword, descriptor);
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
function getPropertyDescriptor(property) {
|
||||
if (properties.has(property)) {
|
||||
return properties.get(property);
|
||||
}
|
||||
|
||||
let name = property;
|
||||
let hack = property[0];
|
||||
|
||||
if (hack === '/') {
|
||||
hack = property[1] === '/' ? '//' : '/';
|
||||
} else if (hack !== '_' &&
|
||||
hack !== '*' &&
|
||||
hack !== '$' &&
|
||||
hack !== '#' &&
|
||||
hack !== '+' &&
|
||||
hack !== '&') {
|
||||
hack = '';
|
||||
}
|
||||
|
||||
const custom = isCustomProperty(name, hack.length);
|
||||
|
||||
// re-use result when possible (the same as for lower case)
|
||||
if (!custom) {
|
||||
name = name.toLowerCase();
|
||||
if (properties.has(name)) {
|
||||
const descriptor = properties.get(name);
|
||||
properties.set(property, descriptor);
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
const vendor = !custom ? getVendorPrefix(name, hack.length) : '';
|
||||
const prefix = name.substr(0, hack.length + vendor.length);
|
||||
const descriptor = Object.freeze({
|
||||
basename: name.substr(prefix.length),
|
||||
name: name.substr(hack.length),
|
||||
hack,
|
||||
vendor,
|
||||
prefix,
|
||||
custom
|
||||
});
|
||||
|
||||
properties.set(property, descriptor);
|
||||
|
||||
return descriptor;
|
||||
}
|
99
node_modules/css-tree/lib/utils/string.js
generated
vendored
Normal file
99
node_modules/css-tree/lib/utils/string.js
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
import {
|
||||
isHexDigit,
|
||||
isWhiteSpace,
|
||||
isValidEscape,
|
||||
consumeEscaped,
|
||||
decodeEscaped
|
||||
} from '../tokenizer/index.js';
|
||||
|
||||
const REVERSE_SOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\)
|
||||
const QUOTATION_MARK = 0x0022; // "
|
||||
const APOSTROPHE = 0x0027; // '
|
||||
|
||||
export function decode(str) {
|
||||
const len = str.length;
|
||||
const firstChar = str.charCodeAt(0);
|
||||
const start = firstChar === QUOTATION_MARK || firstChar === APOSTROPHE ? 1 : 0;
|
||||
const end = start === 1 && len > 1 && str.charCodeAt(len - 1) === firstChar ? len - 2 : len - 1;
|
||||
let decoded = '';
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
let code = str.charCodeAt(i);
|
||||
|
||||
if (code === REVERSE_SOLIDUS) {
|
||||
// special case at the ending
|
||||
if (i === end) {
|
||||
// if the next input code point is EOF, do nothing
|
||||
// otherwise include last quote as escaped
|
||||
if (i !== len - 1) {
|
||||
decoded = str.substr(i + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
code = str.charCodeAt(++i);
|
||||
|
||||
// consume escaped
|
||||
if (isValidEscape(REVERSE_SOLIDUS, code)) {
|
||||
const escapeStart = i - 1;
|
||||
const escapeEnd = consumeEscaped(str, escapeStart);
|
||||
|
||||
i = escapeEnd - 1;
|
||||
decoded += decodeEscaped(str.substring(escapeStart + 1, escapeEnd));
|
||||
} else {
|
||||
// \r\n
|
||||
if (code === 0x000d && str.charCodeAt(i + 1) === 0x000a) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decoded += str[i];
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#serialize-a-string
|
||||
// § 2.1. Common Serializing Idioms
|
||||
export function encode(str, apostrophe) {
|
||||
const quote = apostrophe ? '\'' : '"';
|
||||
const quoteCode = apostrophe ? APOSTROPHE : QUOTATION_MARK;
|
||||
let encoded = '';
|
||||
let wsBeforeHexIsNeeded = false;
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const code = str.charCodeAt(i);
|
||||
|
||||
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
|
||||
if (code === 0x0000) {
|
||||
encoded += '\uFFFD';
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F,
|
||||
// the character escaped as code point.
|
||||
// Note: Do not compare with 0x0001 since 0x0000 is precessed before
|
||||
if (code <= 0x001f || code === 0x007F) {
|
||||
encoded += '\\' + code.toString(16);
|
||||
wsBeforeHexIsNeeded = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the character is '"' (U+0022) or "\" (U+005C), the escaped character.
|
||||
if (code === quoteCode || code === REVERSE_SOLIDUS) {
|
||||
encoded += '\\' + str.charAt(i);
|
||||
wsBeforeHexIsNeeded = false;
|
||||
} else {
|
||||
if (wsBeforeHexIsNeeded && (isHexDigit(code) || isWhiteSpace(code))) {
|
||||
encoded += ' ';
|
||||
}
|
||||
|
||||
// Otherwise, the character itself.
|
||||
encoded += str.charAt(i);
|
||||
wsBeforeHexIsNeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
return quote + encoded + quote;
|
||||
}
|
108
node_modules/css-tree/lib/utils/url.js
generated
vendored
Normal file
108
node_modules/css-tree/lib/utils/url.js
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
import {
|
||||
isHexDigit,
|
||||
isWhiteSpace,
|
||||
isValidEscape,
|
||||
consumeEscaped,
|
||||
decodeEscaped
|
||||
} from '../tokenizer/index.js';
|
||||
|
||||
const SPACE = 0x0020; // U+0020 SPACE
|
||||
const REVERSE_SOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\)
|
||||
const QUOTATION_MARK = 0x0022; // "
|
||||
const APOSTROPHE = 0x0027; // '
|
||||
const LEFTPARENTHESIS = 0x0028; // U+0028 LEFT PARENTHESIS (()
|
||||
const RIGHTPARENTHESIS = 0x0029; // U+0029 RIGHT PARENTHESIS ())
|
||||
|
||||
export function decode(str) {
|
||||
const len = str.length;
|
||||
let start = 4; // length of "url("
|
||||
let end = str.charCodeAt(len - 1) === RIGHTPARENTHESIS ? len - 2 : len - 1;
|
||||
let decoded = '';
|
||||
|
||||
while (start < end && isWhiteSpace(str.charCodeAt(start))) {
|
||||
start++;
|
||||
}
|
||||
|
||||
while (start < end && isWhiteSpace(str.charCodeAt(end))) {
|
||||
end--;
|
||||
}
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
let code = str.charCodeAt(i);
|
||||
|
||||
if (code === REVERSE_SOLIDUS) {
|
||||
// special case at the ending
|
||||
if (i === end) {
|
||||
// if the next input code point is EOF, do nothing
|
||||
// otherwise include last left parenthesis as escaped
|
||||
if (i !== len - 1) {
|
||||
decoded = str.substr(i + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
code = str.charCodeAt(++i);
|
||||
|
||||
// consume escaped
|
||||
if (isValidEscape(REVERSE_SOLIDUS, code)) {
|
||||
const escapeStart = i - 1;
|
||||
const escapeEnd = consumeEscaped(str, escapeStart);
|
||||
|
||||
i = escapeEnd - 1;
|
||||
decoded += decodeEscaped(str.substring(escapeStart + 1, escapeEnd));
|
||||
} else {
|
||||
// \r\n
|
||||
if (code === 0x000d && str.charCodeAt(i + 1) === 0x000a) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decoded += str[i];
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
export function encode(str) {
|
||||
let encoded = '';
|
||||
let wsBeforeHexIsNeeded = false;
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const code = str.charCodeAt(i);
|
||||
|
||||
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER (U+FFFD).
|
||||
if (code === 0x0000) {
|
||||
encoded += '\uFFFD';
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the character is in the range [\1-\1f] (U+0001 to U+001F) or is U+007F,
|
||||
// the character escaped as code point.
|
||||
// Note: Do not compare with 0x0001 since 0x0000 is precessed before
|
||||
if (code <= 0x001f || code === 0x007F) {
|
||||
encoded += '\\' + code.toString(16);
|
||||
wsBeforeHexIsNeeded = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code === SPACE ||
|
||||
code === REVERSE_SOLIDUS ||
|
||||
code === QUOTATION_MARK ||
|
||||
code === APOSTROPHE ||
|
||||
code === LEFTPARENTHESIS ||
|
||||
code === RIGHTPARENTHESIS) {
|
||||
encoded += '\\' + str.charAt(i);
|
||||
wsBeforeHexIsNeeded = false;
|
||||
} else {
|
||||
if (wsBeforeHexIsNeeded && isHexDigit(code)) {
|
||||
encoded += ' ';
|
||||
}
|
||||
|
||||
encoded += str.charAt(i);
|
||||
wsBeforeHexIsNeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 'url(' + encoded + ')';
|
||||
}
|
Reference in New Issue
Block a user