diff --git a/backend.js b/backend.js index b5181866..63b202bb 100644 --- a/backend.js +++ b/backend.js @@ -7,7 +7,7 @@ const path = require('path'); const http = require('http'); const https = require('https'); const express = require('express'); -const corrosion = require('./lib'); +const corrosion = require('./'); const config = require('./config.json'); const insert = require('./randomization.json'); const app = express(); diff --git a/lib/server/bundle.js b/lib/server/bundle.js new file mode 100644 index 00000000..d2ae2dd8 --- /dev/null +++ b/lib/server/bundle.js @@ -0,0 +1,30145 @@ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ([ +/* 0 */, +/* 1 */ +/***/ ((module) => { + +function createDocumentRewriter(ctx) { + return function rewriteDocument() { + if (ctx.serviceWorker) return; + const { + HTMLMediaElement, + HTMLScriptElement, + HTMLAudioElement, + HTMLVideoElement, + HTMLInputElement, + HTMLEmbedElement, + HTMLTrackElement, + HTMLAnchorElement, + HTMLIFrameElement, + HTMLAreaElement, + HTMLLinkElement, + HTMLBaseElement, + HTMLFormElement, + HTMLImageElement, + HTMLSourceElement, + } = ctx.window; + const cookie = Object.getOwnPropertyDescriptor(ctx.window.Document.prototype, 'cookie'); + const domain = Object.getOwnPropertyDescriptor(ctx.window.Document.prototype, 'domain'); + const title = Object.getOwnPropertyDescriptor(ctx.window.Document.prototype, 'title'); + const baseURI = Object.getOwnPropertyDescriptor(ctx.window.Node.prototype, 'baseURI'); + const cookieEnabled = Object.getOwnPropertyDescriptor(ctx.window.Navigator.prototype, 'cookieEnabled'); + let spoofTitle = ''; + let spoofDomain = ctx.location.hostname; + + if (ctx.window.Document.prototype.write) { + ctx.window.Document.prototype.write = new Proxy(ctx.window.Document.prototype.write, { + apply: (target, that , args) => { + if (args.length) args = [ ctx.html.process(args.join(''), ctx.meta) ]; + return Reflect.apply(target, that, args); + }, + }); + }; + if (ctx.window.Document.prototype.hasOwnProperty('cookie')) { + Object.defineProperty(ctx.window.Document.prototype, 'cookie', { + get: new Proxy(cookie.get, { + apply: (target, that, args) => { + const cookies = Reflect.apply(target, that, args); + return ctx.config.cookie ? ctx.cookies.decode(cookies, ctx.meta) : ''; + }, + }), + set: new Proxy(cookie.set, { + apply: (target, that, [ val ]) => { + return Reflect.apply(target, that, [ ctx.config.cookie ? ctx.cookies.encode(val, ctx.meta) : '' ]); + }, + }), + }); + }; + if (ctx.window.Document.prototype.writeln) { + ctx.window.Document.prototype.writeln = new Proxy(ctx.window.Document.prototype.writeln, { + apply: (target, that , args) => { + if (args.length) args = [ ctx.html.process(args.join(''), ctx.meta) ]; + return Reflect.apply(target, that, args); + }, + }); + }; + if (ctx.window.Element.prototype.setAttribute) { + ctx.window.Element.prototype.setAttribute = new Proxy(ctx.window.Element.prototype.setAttribute, { + apply: (target, that, args) => { + if (args[0] && args[1]) { + const handler = ctx.html.attributeRoute({ + name: args[0], + value: args[1], + node: that, + }); + switch(handler) { + case 'url': + Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]); + //if (that.tagName == 'SCRIPT' && args[0] == 'src') flags.push('js'); + args[1] = ctx.url.wrap(args[1], ctx.meta); + break; + case 'srcset': + Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]); + args[1] = ctx.html.srcset(args[1], ctx.meta); + break; + case 'css': + Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]); + args[1] = ctx.css.process(args[1], { ...ctx.meta, context: 'declarationList' }); + break; + case 'html': + Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]); + args[1] = ctx.html.process(args[1], ctx.meta); + break; + case 'delete': + return Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]); + }; + }; + return Reflect.apply(target, that, args); + }, + }); + }; + if (ctx.window.Element.prototype.getAttribute) { + ctx.window.Element.prototype.getAttribute = new Proxy(ctx.window.Element.prototype.getAttribute, { + apply: (target, that, args) => { + if (args[0] && that.hasAttribute(`corrosion-${args[0]}`)) args[0] = `corrosion-${args[0]}`; + return Reflect.apply(target, that, args); + }, + }); + }; + ctx.window.CSSStyleDeclaration.prototype.setProperty = new Proxy(ctx.window.CSSStyleDeclaration.prototype.setProperty, { + apply: (target, that, args) => { + if (args[1]) args[1] = ctx.css.process(args[1], { context: 'value', ...ctx.meta, }); + return Reflect.apply(target, that, args); + }, + }); + if (ctx.window.Audio) { + ctx.window.Audio = new Proxy(ctx.window.Audio, { + construct: (target, args) => { + if (args[0]) args[0] = ctx.url.wrap(args[0], ctx.meta); + return Reflect.construct(target, args); + }, + }); + }; + [ + 'innerHTML', + 'outerHTML', + ].forEach(html => { + const descriptor = Object.getOwnPropertyDescriptor(ctx.window.Element.prototype, html); + Object.defineProperty(ctx.window.Element.prototype, html, { + get: new Proxy(descriptor.get, { + apply: (target, that, args) => { + const body = Reflect.apply(target, that, args); + if (!body || html == 'innerHTML' && that.tagName == 'SCRIPT') return body; + return ctx.html.source(body, ctx.meta); + }, + }), + set: new Proxy(descriptor.set, { + apply(target, that, [ val ]) { + return Reflect.apply(target, that, [ val ? ctx.html.process(val.toString(), ctx.meta) : val, ]); + }, + }), + }); + }); + [ + ['background', 'background'], + ['backgroundImage', 'background-image'], + ['listStyleImage', 'list-style-image'], + ].forEach(([key, cssProperty]) => { + Object.defineProperty(ctx.window.CSS2Properties ? ctx.window.CSS2Properties.prototype : ctx.window.CSSStyleDeclaration.prototype, key, { + get() { + return this.getPropertyValue(cssProperty); + }, + set(val) { + return this.setProperty(cssProperty, val); + }, + }); + }); + Object.defineProperty(ctx.window.Document.prototype, 'domain', { + get: new Proxy(domain.get, { + apply: () => spoofDomain, + }), + set: new Proxy(domain.set, { + apply: (target, that, [ val ]) => { + if (!val.toString().endsWith(ctx.location.hostname.split('.').slice(-2).join('.'))) return Reflect.apply(target, that, ['']); + return spoofDomain = val; + }, + }), + }); + if (ctx.config.title) Object.defineProperty(ctx.window.Document.prototype, 'title', { + get: new Proxy(title.get, { + apply: () => spoofTitle, + }), + set: new Proxy(title.set, { + apply: (target, that, [ val ]) => spoofTitle = val, + }), + }); + Object.defineProperty(ctx.window.Navigator.prototype, 'cookieEnabled', { + get: new Proxy(cookieEnabled.get, { + apply: () => ctx.config.cookie, + }), + }); + Object.defineProperty(ctx.window.Node.prototype, 'baseURI', { + get: new Proxy(baseURI.get, { + apply: (target, that, args) => { + const val = Reflect.apply(target, that, args); + return val.startsWith(ctx.meta.origin) ? ctx.url.unwrap(val, ctx.meta) : val; + }, + }), + }); + [ + { + elements: [ HTMLScriptElement, HTMLMediaElement, HTMLImageElement, HTMLAudioElement, HTMLVideoElement, HTMLInputElement, HTMLEmbedElement, HTMLIFrameElement, HTMLTrackElement, HTMLSourceElement], + properties: ['src'], + handler: 'url', + }, + { + elements: [ HTMLFormElement ], + properties: ['action'], + handler: 'url', + }, + { + elements: [ HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, HTMLBaseElement ], + properties: ['href'], + handler: 'url', + }, + { + elements: [ HTMLImageElement, HTMLSourceElement ], + properties: ['srcset'], + handler: 'srcset', + }, + { + elements: [ HTMLScriptElement ], + properties: ['integrity'], + handler: 'delete', + }, + { + elements: [ HTMLIFrameElement ], + properties: ['contentWindow'], + handler: 'window', + }, + ].forEach(entry => { + entry.elements.forEach(element => { + if (!element) return; + entry.properties.forEach(property => { + if (!element.prototype.hasOwnProperty(property)) return; + const descriptor = Object.getOwnPropertyDescriptor(element.prototype, property); + Object.defineProperty(element.prototype, property, { + get: descriptor.get ? new Proxy(descriptor.get, { + apply: (target, that, args) => { + let val = Reflect.apply(target, that, args); + let flags = []; + switch(entry.handler) { + case 'url': + //if (that.tagName == 'SCRIPT' && property == 'src') flags.push('js'); + val = ctx.url.unwrap(val, ctx.meta); + break; + case 'srcset': + val = ctx.html.unsrcset(val, ctx.meta); + break; + case 'delete': + val = that.getAttribute(`corrosion-${property}`); + break; + case 'window': + try { + if (!val.$corrosion) { + val.$corrosion = new ctx.constructor({ ...ctx.config, window: val, }); + val.$corrosion.init(); + val.$corrosion.meta = ctx.meta; + }; + } catch(e) {}; + }; + return val; + }, + }) : undefined, + set: descriptor.set ? new Proxy(descriptor.set, { + apply(target, that, [ val ]) { + let newVal = val; + switch(entry.handler) { + case 'url': + newVal = ctx.url.wrap(newVal, ctx.meta); + break; + case 'srcset': + newVal = ctx.html.srcset(newVal, ctx.meta); + break; + case 'delete': + that.setAttribute(property, newVal); + return newVal; + }; + return Reflect.apply(target, that, [ newVal ]); + }, + }) : undefined, + }); + }); + }); + }); + }; +}; +module.exports = createDocumentRewriter; + +/***/ }), +/* 2 */ +/***/ ((module) => { + +function createHistoryRewriter(ctx) { + return function rewriteHistory() { + if (ctx.serviceWorker) return; + if (ctx.window.History.prototype.pushState) { + ctx.window.History.prototype.pushState = new Proxy(ctx.window.History.prototype.pushState, { + apply: (target, that, args) => { + if (args[2]) args[2] = ctx.url.wrap(args[2], ctx.meta); + const ret = Reflect.apply(target, that, args); + ctx.updateLocation(); + return ret; + }, + }); + }; + if (ctx.window.History.prototype.replaceState) { + ctx.window.History.prototype.replaceState = new Proxy(ctx.window.History.prototype.replaceState, { + apply: (target, that, args) => { + if (args[2]) args[2] = ctx.url.wrap(args[2], ctx.meta); + const ret = Reflect.apply(target, that, args); + ctx.updateLocation(); + return ret; + }, + }); + }; + }; +}; +module.exports = createHistoryRewriter; + +/***/ }), +/* 3 */ +/***/ ((module) => { + +function createHttpRewriter(ctx = {}) { + return function rewriteHttp() { + if (ctx.window.Request) { + const requestURL = Object.getOwnPropertyDescriptor(ctx.window.Request.prototype, 'url'); + ctx.window.Request = new Proxy(ctx.window.Request, { + construct(target, args) { + if (args[0]) args[0] = ctx.url.wrap(args[0], { ...ctx.meta, flags: ['xhr'], }) + return Reflect.construct(target, args); + }, + }); + Object.defineProperty(ctx.window.Request.prototype, 'url', { + get: new Proxy(requestURL.get, { + apply: (target, that, args) => { + var url = Reflect.apply(target, that, args); + return url ? ctx.url.unwrap(url, ctx.meta) : url; + }, + }), + }); + }; + if (ctx.window.Response) { + const responseURL = Object.getOwnPropertyDescriptor(ctx.window.Response.prototype, 'url'); + Object.defineProperty(ctx.window.Response.prototype, 'url', { + get: new Proxy(responseURL.get, { + apply: (target, that, args) => { + var url = Reflect.apply(target, that, args); + return url ? ctx.url.unwrap(url, ctx.meta) : url; + }, + }), + }); + }; + if (ctx.window.open) { + ctx.window.open = new Proxy(ctx.window.open, { + apply: (target, that, args) => { + if (args[0]) args[0] = ctx.url.wrap(args[0], ctx.meta); + return Reflect.apply(target, that, args) + }, + }); + }; + if (ctx.window.fetch) { + ctx.window.fetch = new Proxy(ctx.window.fetch, { + apply: (target, that, args) => { + if (args[0] instanceof ctx.window.Request) return Reflect.apply(target, that, args); + if (args[0]) args[0] = ctx.url.wrap(args[0], { ...ctx.meta, flags: ['xhr'], }); + return Reflect.apply(target, that, args); + }, + }); + }; + if (ctx.window.Navigator && ctx.window.Navigator.prototype.sendBeacon) { + ctx.window.Navigator.prototype.sendBeacon = new Proxy(ctx.window.Navigator.prototype.sendBeacon, { + apply: (target, that, args) => { + if (args[0]) ctx.url.wrap(args[0], { ...ctx.meta, flags: ['xhr'], }); + return Reflect.apply(target, that, args); + }, + }); + }; + if (ctx.window.XMLHttpRequest) { + const responseURL = Object.getOwnPropertyDescriptor(ctx.window.XMLHttpRequest.prototype, 'responseURL'); + ctx.window.XMLHttpRequest.prototype.open = new Proxy(ctx.window.XMLHttpRequest.prototype.open, { + apply: (target, that, args) => { + if (args[1]) args[1] = ctx.url.wrap(args[1], { ...ctx.meta, flags: ['xhr'], }); + return Reflect.apply(target, that, args); + }, + }); + Object.defineProperty(ctx.window.XMLHttpRequest.prototype, 'responseURL', { + get: new Proxy(responseURL.get, { + apply: (target, that, args) => { + const url = Reflect.apply(target, that, args); + return url ? ctx.url.unwrap(url, ctx.meta) : url; + }, + }), + }); + }; + if (ctx.window.postMessage) { + ctx.window.postMessage = new Proxy(ctx.window.postMessage, { + apply: (target, that, args) => { + if (!ctx.serviceWorker && args[1]) args[1] = ctx.meta.origin; + return Reflect.apply(target, that, args); + }, + }); + }; + if (ctx.window.WebSocket && ctx.config.ws) { + ctx.window.WebSocket = new Proxy(ctx.window.WebSocket, { + construct: (target, args) => { + if (args[0]) args[0] = ctx.url.wrap(args[0].toString().replace('ws', 'http'), ctx.meta).replace('http', 'ws') + '?origin=' + ctx.location.origin; + return Reflect.construct(target, args); + }, + }); + }; + }; +}; + +module.exports = createHttpRewriter; + +/***/ }), +/* 4 */ +/***/ ((module) => { + +class Location { + get [Symbol.toPrimitive]() { + return () => this.href; + }; +}; + +function createLocation(ctx, url) { + const _location = new Location(); + const _url = new URL(url); + [ + 'hash', + 'host', + 'hostname', + 'href', + 'pathname', + 'port', + 'protocol', + 'search', + 'origin', + ].forEach(property => { + Object.defineProperty(_location, property, { + get() { + return _url[property]; + }, + set(val) { + if (ctx.serviceWorker || property == 'origin') return; + if (property == 'href') { + return ctx.window.location.href = ctx.url.wrap(new URL(val, _url).href); + }; + _url[property] = val; + return ctx.window.location.href = ctx.url.wrap(_url); + }, + }); + }); + if (!ctx.serviceWorker) [ + 'assign', + 'replace', + 'reload', + ].forEach(method => { + _location[method] = new Proxy(ctx.window.location[method], { + apply(target, that, args) { + if (args[0]) args[0] = ctx.url.wrap(args[0], ctx.meta); + return Reflect.apply(target.bind(ctx.window.location), that, args); + }, + }); + }); + _location.toString = new Proxy(_url.toString, { + apply(target, that, args) { + return Reflect.apply(target.bind(_url), that, args); + }, + }); + return _location; +}; + +createLocation.Location = Location; +module.exports = createLocation; + +/***/ }), +/* 5 */ +/***/ ((module) => { + +function createWorkerRewriter(ctx = {}) { + return function rewriteWorker() { + if (ctx.window.Worker) { + ctx.window.Worker = new Proxy(ctx.window.Worker, { + construct: (target, args) => { + if (args[0]) { + if (args[0].trim().startsWith(`blob:${ctx.window.location.origin}`)) { + const xhr = new ctx.originalXhr(); + xhr.open('GET', args[0], false); + xhr.send(); + const script = ctx.js.process(xhr.responseText, ctx.location.origin + args[0].trim().slice(`blob:${ctx.window.location.origin}`.length)); + const blob = new Blob([ script ], { type: 'application/javascript' }); + args[0] = URL.createObjectURL(blob); + } else { + args[0] = ctx.url.wrap(args[0], ctx.meta); + }; + }; + return Reflect.construct(target, args); + }, + }); + }; + if (ctx.serviceWorker && ctx.window.importScripts) { + ctx.window.importScripts = new Proxy(ctx.window.importScripts, { + apply: (target, that, args) => { + if (args[0]) args[0] = ctx.url.wrap(args[0], ctx.meta); + return Reflect.apply(target, that, args); + }, + }); + }; + }; +}; + +module.exports = createWorkerRewriter; + +/***/ }), +/* 6 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// ------------------------------------------------------------- +// WARNING: this file is used by both the client and the server. +// Do not use any browser or node-specific API! +// ------------------------------------------------------------- +const URLWrapper = __webpack_require__(7); +const CookieRewriter = __webpack_require__(9); +const CSSRewriter = __webpack_require__(11); +const HTMLRewriter = __webpack_require__(134); +const JSRewriter = __webpack_require__(159); +const defaultConfig = { + prefix: '/service/', + codec: 'plain', + ws: true, + cookie: true, + title: 'Service', +}; + +class Rewrite { + constructor(config = defaultConfig) { + this.config = Object.assign(defaultConfig, config); + this.prefix = this.config.prefix; + this.forceHttps = this.config.forceHttps; + this.url = new URLWrapper(this.config || {}); + this.codec = this.url.codec; + this.cookies = new CookieRewriter(this); + this.css = new CSSRewriter(this); + this.js = new JSRewriter(this); + this.html = new HTMLRewriter(this); + }; +}; + +module.exports = Rewrite; + + +/***/ }), +/* 7 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// ------------------------------------------------------------- +// WARNING: this file is used by both the client and the server. +// Do not use any browser or node-specific API! +// ------------------------------------------------------------- +const codec = __webpack_require__(8); +const defaultConfig = { + prefix: '/service/', + codec: 'plain' +}; + +class URLWrapper { + constructor(config = defaultConfig) { + this.prefix = config.prefix || defaultConfig.prefix; + this.codec = codec[config.codec || 'plain'] || codec['plain']; + this.regex = /^(#|about:|data:|blob:|mailto:|javascript:)/; + }; + wrap(val, config = {}) { + if (!val || this.regex.test(val)) return val; + let flags = ''; + (config.flags || []).forEach(flag => flags += `${flag}_/`); + if (config.base) try { + if (!['http:', 'https:', 'ws:', 'wss:'].includes(new URL(val, config.base).protocol)) return val; + } catch(e) { + return val; + }; + return (config.origin || '') + this.prefix + flags + this.codec.encode(config.base ? new URL(val, config.base) : val) + '/'; + }; + unwrap(val, config = {}) { + if (!val || this.regex.test(val)) return val; + let processed = val.slice((config.origin || '').length + this.prefix.length); + const flags = ('/' + processed).match(/(?<=\/)(.*?)(?=_\/)/g) || []; + flags.forEach(flag => processed = processed.slice(`${flag}_/`.length)); + let [ url, leftovers ] = processed.split(/\/(.+)?/); + return config.flags ? { value: this.codec.decode((url || '')) + (config.leftovers && leftovers ? leftovers : ''), flags } : this.codec.decode((url || '')) + (config.leftovers && leftovers ? leftovers : ''); + }; +}; + +module.exports = URLWrapper; + + +/***/ }), +/* 8 */ +/***/ ((__unused_webpack_module, exports) => { + +// ------------------------------------------------------------- +// WARNING: this file is used by both the client and the server. +// Do not use any browser or node-specific API! +// ------------------------------------------------------------- +exports.xor = { + encode(str){ + if (!str) return str; + return encodeURIComponent(str.toString().split('').map((char, ind) => ind % 2 ? String.fromCharCode(char.charCodeAt() ^ 2) : char).join('')); + }, + decode(str){ + if (!str) return str; + return decodeURIComponent(str).split('').map((char, ind) => ind % 2 ? String.fromCharCode(char.charCodeAt() ^ 2) : char).join(''); + }, +}; +exports.plain = { + encode(str) { + if (!str) return str; + return encodeURIComponent(str); + }, + decode(str) { + if (!str) return str; + return decodeURIComponent(str); + }, +}; +exports.base64 = { + encode(str){ + if (!str) return str; + str = str.toString(); + const b64chs = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='); + let u32; + let c0; + let c1; + let c2; + let asc = ''; + let pad = str.length % 3; + + for (let i = 0; i < str.length;) { + if((c0 = str.charCodeAt(i++)) > 255 || (c1 = str.charCodeAt(i++)) > 255 || (c2 = str.charCodeAt(i++)) > 255)throw new TypeError('invalid character found'); + u32 = (c0 << 16) | (c1 << 8) | c2; + asc += b64chs[u32 >> 18 & 63] + + b64chs[u32 >> 12 & 63] + + b64chs[u32 >> 6 & 63] + + b64chs[u32 & 63]; + } + + return encodeURIComponent(pad ? asc.slice(0, pad - 3) + '==='.substr(pad) : asc); + }, + decode(str){ + if (!str) return str; + str = decodeURIComponent(str.toString()); + const b64tab = {"0":52,"1":53,"2":54,"3":55,"4":56,"5":57,"6":58,"7":59,"8":60,"9":61,"A":0,"B":1,"C":2,"D":3,"E":4,"F":5,"G":6,"H":7,"I":8,"J":9,"K":10,"L":11,"M":12,"N":13,"O":14,"P":15,"Q":16,"R":17,"S":18,"T":19,"U":20,"V":21,"W":22,"X":23,"Y":24,"Z":25,"a":26,"b":27,"c":28,"d":29,"e":30,"f":31,"g":32,"h":33,"i":34,"j":35,"k":36,"l":37,"m":38,"n":39,"o":40,"p":41,"q":42,"r":43,"s":44,"t":45,"u":46,"v":47,"w":48,"x":49,"y":50,"z":51,"+":62,"/":63,"=":64}; + str = str.replace(/\s+/g, ''); + str += '=='.slice(2 - (str.length & 3)); + let u24; + let bin = ''; + let r1; + let r2; + + for (let i = 0; i < str.length;) { + u24 = b64tab[str.charAt(i++)] << 18 + | b64tab[str.charAt(i++)] << 12 + | (r1 = b64tab[str.charAt(i++)]) << 6 + | (r2 = b64tab[str.charAt(i++)]); + bin += r1 === 64 ? String.fromCharCode(u24 >> 16 & 255) + : r2 === 64 ? String.fromCharCode(u24 >> 16 & 255, u24 >> 8 & 255) + : String.fromCharCode(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255); + }; + return bin; + }, +}; + + +/***/ }), +/* 9 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// ------------------------------------------------------------- +// WARNING: this file is used by both the client and the server. +// Do not use any browser or node-specific API! +// ------------------------------------------------------------- +const { SetCookie, CookieStore } = __webpack_require__(10); + +class CookieRewriter { + constructor(ctx) { + this.ctx = ctx; + }; + decode(store, config = {}) { + const url = new URL(config.url); + const cookies = new CookieStore(store); + cookies.forEach((val, key) => { + if (!key.includes('@') || key.slice(key.length - url.hostname.length) != url.hostname) return cookies.delete(key); + cookies.delete(key); + cookies.set(key.substr(0, key.length - url.hostname.length - 1), val); + }); + return cookies.serialize(); + }; + encode(input, config = {}) { + if (Array.isArray(input)) { + const rw = [ ...input ]; + for (let i in rw) rw[i] = this.encode(rw[i], config); + return rw; + }; + const url = new URL(config.url); + const cookie = new SetCookie(input); + if (!cookie.name) return null; + cookie.domain = config.domain; + cookie.secure = config.secure; + cookie.name += `@${url.hostname}`; + cookie.path = this.ctx.prefix; + return cookie.serialize() || ''; + }; +}; + +module.exports = CookieRewriter; + + +/***/ }), +/* 10 */ +/***/ ((__unused_webpack_module, exports) => { + +// ------------------------------------------------------------- +// WARNING: this file is used by both the client and the server. +// Do not use any browser or node-specific API! +// ------------------------------------------------------------- +class CookieStore { + constructor(val = ''){ + this.data = {}; + val.split(';').map(cookie => { + var [ name, val = ''] = cookie.trimStart().split('='); + if (name) this.data[name] = val; + }); + }; + has(name){ + if (!name || !this.data[name]) return false; + return true; + }; + get(name){ + return this.has(name) ? this.data[name] : null; + }; + set(name, val){ + if (!name || !val) return; + return this.data[name] = val; + }; + delete(name){ + if (!name) return; + return delete this.data[name]; + }; + forEach(action = (node, key) => null){ + for (let prop in this.data) action(this.data[prop], prop); + }; + serialize(){ + var str = ''; + for (let i in this.data) str += ` ${i}=${this.data[i]};`; + return str.substr(1); + }; +}; + +class SetCookie { + constructor(val = ''){ + + var [ [ name, value = '' ], ...data ] = val.split(';').map(str => str.trimStart().split('=')); + + this.name = name; + this.value = value; + this.expires = null; + this.maxAge = null; + this.domain = null; + this.secure = false; + this.httpOnly = false; + this.path = null; + this.sameSite = null; + + data.forEach(([name = null, value = null]) => { + if (typeof name == 'string') switch(name.toLowerCase()){ + case 'domain': + this.domain = value; + break; + case 'secure': + this.secure = true; + break; + case 'httponly': + this.httpOnly = true; + break; + case 'samesite': + this.sameSite = value; + break; + case 'path': + this.path = value; + break; + case 'expires': + this.expires = value; + break; + case 'maxage': + this.maxAge = value; + break; + }; + }); + }; + serialize(){ + if (!this.name) return; + var str = `${this.name}=${this.value};`; + if (this.expires) str += ` Expires=${this.expires};`; + if (this.maxAge) str += ` Max-Age=${this.max_age};`; + if (this.domain) str += ` Domain=${this.domain};`; + if (this.secure) str += ` Secure;`; + if (this.httpOnly) str += ` HttpOnly;`; + if (this.path) str += ` Path=${this.path};`; + if (this.sameSite) str += ` SameSite=${this.sameSite};`; + return str; + }; +}; + +exports.CookieStore = CookieStore; +exports.SetCookie = SetCookie; + + +/***/ }), +/* 11 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// ------------------------------------------------------------- +// WARNING: this file is used by both the client and the server. +// Do not use any browser or node-specific API! +// ------------------------------------------------------------- +const csstree = __webpack_require__(12); + +class CSSRewriter { + constructor(ctx) { + this.ctx = ctx; + }; + process(source, config = {}) { + const ast = csstree.parse(source, { + context: config.context || 'stylesheet', + parseCustomProperty: true, + }); + const urls = csstree.findAll(ast, node => + node.type == 'Url' + ); + const imports = csstree.findAll(ast, node => + node.type == 'Atrule' && node.name == 'import' && node.prelude && node.prelude.type == 'AtrulePrelude' && node.prelude.children.head.data.type == 'String' + ); + urls.forEach(({ value }) => { + switch(value.type) { + case 'String': + const quote = value.value.substring(0, 1); + value.value = quote + this.ctx.url.wrap(value.value.slice(1).slice(0, -1), config) + quote; + break; + case 'Raw': + value.value = this.ctx.url.wrap(value.value, config); + break; + }; + }); + imports.forEach(({ prelude }) => { + const { data } = prelude.children.head; + const quote = data.value.substring(0, 1); + data.value = quote + this.ctx.url.wrap(data.value.slice(1).slice(0, -1), config) + quote; + }); + return csstree.generate(ast); + }; + source(processed, config = {}) { + const ast = csstree.parse(processed, { + context: config.context || 'stylesheet', + parseCustomProperty: true, + }); + const urls = csstree.findAll(ast, node => + node.type == 'Url' + ); + const imports = csstree.findAll(ast, node => + node.type == 'Atrule' && node.name == 'import' && node.prelude && node.prelude.type == 'AtrulePrelude' && node.prelude.children.head.data.type == 'String' + ); + urls.forEach(({ value }) => { + switch(value.type) { + case 'String': + const quote = value.value.substring(0, 1); + value.value = quote + this.ctx.url.unwrap(value.value.slice(1).slice(0, -1), config) + quote; + break; + case 'Raw': + value.value = this.ctx.url.unwrap(value.value, config); + break; + }; + }); + imports.forEach(({ prelude }) => { + const { data } = prelude.children.head; + const quote = data.value.substring(0, 1); + data.value = quote + this.ctx.url.unwrap(data.value.slice(1).slice(0, -1), config) + quote; + }); + return csstree.generate(ast); + }; +}; + +module.exports = CSSRewriter; + + +/***/ }), +/* 12 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +module.exports = __webpack_require__(13); + + +/***/ }), +/* 13 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +function merge() { + var dest = {}; + + for (var i = 0; i < arguments.length; i++) { + var src = arguments[i]; + for (var key in src) { + dest[key] = src[key]; + } + } + + return dest; +} + +module.exports = __webpack_require__(14).create( + merge( + __webpack_require__(57), + __webpack_require__(104), + __webpack_require__(132) + ) +); +module.exports.version = __webpack_require__(133).version; + + +/***/ }), +/* 14 */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +var List = __webpack_require__(15); +var SyntaxError = __webpack_require__(16); +var TokenStream = __webpack_require__(18); +var Lexer = __webpack_require__(22); +var definitionSyntax = __webpack_require__(41); +var tokenize = __webpack_require__(27); +var createParser = __webpack_require__(42); +var createGenerator = __webpack_require__(45); +var createConvertor = __webpack_require__(53); +var createWalker = __webpack_require__(54); +var clone = __webpack_require__(55); +var names = __webpack_require__(25); +var mix = __webpack_require__(56); + +function createSyntax(config) { + var parse = createParser(config); + var walk = createWalker(config); + var generate = createGenerator(config); + var convert = createConvertor(walk); + + var syntax = { + List: List, + SyntaxError: SyntaxError, + TokenStream: TokenStream, + Lexer: Lexer, + + vendorPrefix: names.vendorPrefix, + keyword: names.keyword, + property: names.property, + isCustomProperty: names.isCustomProperty, + + definitionSyntax: definitionSyntax, + lexer: null, + createLexer: function(config) { + return new Lexer(config, syntax, syntax.lexer.structure); + }, + + tokenize: tokenize, + parse: parse, + walk: walk, + generate: generate, + + find: walk.find, + findLast: walk.findLast, + findAll: walk.findAll, + + clone: clone, + fromPlainObject: convert.fromPlainObject, + toPlainObject: convert.toPlainObject, + + createSyntax: function(config) { + return createSyntax(mix({}, config)); + }, + fork: function(extension) { + var base = mix({}, config); // copy of config + return createSyntax( + typeof extension === 'function' + ? extension(base, Object.assign) + : mix(base, extension) + ); + } + }; + + syntax.lexer = new Lexer({ + generic: true, + types: config.types, + atrules: config.atrules, + properties: config.properties, + node: config.node + }, syntax); + + return syntax; +}; + +exports.create = function(config) { + return createSyntax(mix({}, config)); +}; + + +/***/ }), +/* 15 */ +/***/ ((module) => { + +// +// list +// ┌──────┐ +// ┌──────────────┼─head │ +// │ │ tail─┼──────────────┐ +// │ └──────┘ │ +// ▼ ▼ +// item item item item +// ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ +// null ◀──┼─prev │◀───┼─prev │◀───┼─prev │◀───┼─prev │ +// │ next─┼───▶│ next─┼───▶│ next─┼───▶│ next─┼──▶ null +// ├──────┤ ├──────┤ ├──────┤ ├──────┤ +// │ data │ │ data │ │ data │ │ data │ +// └──────┘ └──────┘ └──────┘ └──────┘ +// + +function createItem(data) { + return { + prev: null, + next: null, + data: data + }; +} + +function allocateCursor(node, prev, next) { + var cursor; + + if (cursors !== null) { + cursor = cursors; + cursors = cursors.cursor; + cursor.prev = prev; + cursor.next = next; + cursor.cursor = node.cursor; + } else { + cursor = { + prev: prev, + next: next, + cursor: node.cursor + }; + } + + node.cursor = cursor; + + return cursor; +} + +function releaseCursor(node) { + var cursor = node.cursor; + + node.cursor = cursor.cursor; + cursor.prev = null; + cursor.next = null; + cursor.cursor = cursors; + cursors = cursor; +} + +var cursors = null; +var List = function() { + this.cursor = null; + this.head = null; + this.tail = null; +}; + +List.createItem = createItem; +List.prototype.createItem = createItem; + +List.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) { + var cursor = this.cursor; + + while (cursor !== null) { + if (cursor.prev === prevOld) { + cursor.prev = prevNew; + } + + if (cursor.next === nextOld) { + cursor.next = nextNew; + } + + cursor = cursor.cursor; + } +}; + +List.prototype.getSize = function() { + var size = 0; + var cursor = this.head; + + while (cursor) { + size++; + cursor = cursor.next; + } + + return size; +}; + +List.prototype.fromArray = function(array) { + var cursor = null; + + this.head = null; + + for (var i = 0; i < array.length; i++) { + var item = createItem(array[i]); + + if (cursor !== null) { + cursor.next = item; + } else { + this.head = item; + } + + item.prev = cursor; + cursor = item; + } + + this.tail = cursor; + + return this; +}; + +List.prototype.toArray = function() { + var cursor = this.head; + var result = []; + + while (cursor) { + result.push(cursor.data); + cursor = cursor.next; + } + + return result; +}; + +List.prototype.toJSON = List.prototype.toArray; + +List.prototype.isEmpty = function() { + return this.head === null; +}; + +List.prototype.first = function() { + return this.head && this.head.data; +}; + +List.prototype.last = function() { + return this.tail && this.tail.data; +}; + +List.prototype.each = function(fn, context) { + var item; + + if (context === undefined) { + context = this; + } + + // push cursor + var cursor = allocateCursor(this, null, this.head); + + while (cursor.next !== null) { + item = cursor.next; + cursor.next = item.next; + + fn.call(context, item.data, item, this); + } + + // pop cursor + releaseCursor(this); +}; + +List.prototype.forEach = List.prototype.each; + +List.prototype.eachRight = function(fn, context) { + var item; + + if (context === undefined) { + context = this; + } + + // push cursor + var cursor = allocateCursor(this, this.tail, null); + + while (cursor.prev !== null) { + item = cursor.prev; + cursor.prev = item.prev; + + fn.call(context, item.data, item, this); + } + + // pop cursor + releaseCursor(this); +}; + +List.prototype.forEachRight = List.prototype.eachRight; + +List.prototype.reduce = function(fn, initialValue, context) { + var item; + + if (context === undefined) { + context = this; + } + + // push cursor + var cursor = allocateCursor(this, null, this.head); + var acc = initialValue; + + while (cursor.next !== null) { + item = cursor.next; + cursor.next = item.next; + + acc = fn.call(context, acc, item.data, item, this); + } + + // pop cursor + releaseCursor(this); + + return acc; +}; + +List.prototype.reduceRight = function(fn, initialValue, context) { + var item; + + if (context === undefined) { + context = this; + } + + // push cursor + var cursor = allocateCursor(this, this.tail, null); + var acc = initialValue; + + while (cursor.prev !== null) { + item = cursor.prev; + cursor.prev = item.prev; + + acc = fn.call(context, acc, item.data, item, this); + } + + // pop cursor + releaseCursor(this); + + return acc; +}; + +List.prototype.nextUntil = function(start, fn, context) { + if (start === null) { + return; + } + + var item; + + if (context === undefined) { + context = this; + } + + // push cursor + var cursor = allocateCursor(this, null, start); + + while (cursor.next !== null) { + item = cursor.next; + cursor.next = item.next; + + if (fn.call(context, item.data, item, this)) { + break; + } + } + + // pop cursor + releaseCursor(this); +}; + +List.prototype.prevUntil = function(start, fn, context) { + if (start === null) { + return; + } + + var item; + + if (context === undefined) { + context = this; + } + + // push cursor + var cursor = allocateCursor(this, start, null); + + while (cursor.prev !== null) { + item = cursor.prev; + cursor.prev = item.prev; + + if (fn.call(context, item.data, item, this)) { + break; + } + } + + // pop cursor + releaseCursor(this); +}; + +List.prototype.some = function(fn, context) { + var cursor = this.head; + + if (context === undefined) { + context = this; + } + + while (cursor !== null) { + if (fn.call(context, cursor.data, cursor, this)) { + return true; + } + + cursor = cursor.next; + } + + return false; +}; + +List.prototype.map = function(fn, context) { + var result = new List(); + var cursor = this.head; + + if (context === undefined) { + context = this; + } + + while (cursor !== null) { + result.appendData(fn.call(context, cursor.data, cursor, this)); + cursor = cursor.next; + } + + return result; +}; + +List.prototype.filter = function(fn, context) { + var result = new List(); + var cursor = this.head; + + if (context === undefined) { + context = this; + } + + while (cursor !== null) { + if (fn.call(context, cursor.data, cursor, this)) { + result.appendData(cursor.data); + } + cursor = cursor.next; + } + + return result; +}; + +List.prototype.clear = function() { + this.head = null; + this.tail = null; +}; + +List.prototype.copy = function() { + var result = new List(); + var cursor = this.head; + + while (cursor !== null) { + result.insert(createItem(cursor.data)); + cursor = cursor.next; + } + + return result; +}; + +List.prototype.prepend = function(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; +}; + +List.prototype.prependData = function(data) { + return this.prepend(createItem(data)); +}; + +List.prototype.append = function(item) { + return this.insert(item); +}; + +List.prototype.appendData = function(data) { + return this.insert(createItem(data)); +}; + +List.prototype.insert = function(item, before) { + if (before !== undefined && 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; +}; + +List.prototype.insertData = function(data, before) { + return this.insert(createItem(data), before); +}; + +List.prototype.remove = function(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; +}; + +List.prototype.push = function(data) { + this.insert(createItem(data)); +}; + +List.prototype.pop = function() { + if (this.tail !== null) { + return this.remove(this.tail); + } +}; + +List.prototype.unshift = function(data) { + this.prepend(createItem(data)); +}; + +List.prototype.shift = function() { + if (this.head !== null) { + return this.remove(this.head); + } +}; + +List.prototype.prependList = function(list) { + return this.insertList(list, this.head); +}; + +List.prototype.appendList = function(list) { + return this.insertList(list); +}; + +List.prototype.insertList = function(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; +}; + +List.prototype.replace = function(oldItem, newItemOrList) { + if ('head' in newItemOrList) { + this.insertList(newItemOrList, oldItem); + } else { + this.insert(newItemOrList, oldItem); + } + + this.remove(oldItem); +}; + +module.exports = List; + + +/***/ }), +/* 16 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +var createCustomError = __webpack_require__(17); +var MAX_LINE_LENGTH = 100; +var OFFSET_CORRECTION = 60; +var TAB_REPLACEMENT = ' '; + +function sourceFragment(error, extraLines) { + function processLines(start, end) { + return lines.slice(start, end).map(function(line, idx) { + var num = String(start + idx + 1); + + while (num.length < maxNumLength) { + num = ' ' + num; + } + + return num + ' |' + line; + }).join('\n'); + } + + var lines = error.source.split(/\r\n?|\n|\f/); + var line = error.line; + var column = error.column; + var startLine = Math.max(1, line - extraLines) - 1; + var endLine = Math.min(line + extraLines, lines.length + 1); + var maxNumLength = Math.max(4, String(endLine).length) + 1; + var cutLeft = 0; + + // column correction according to replaced tab before column + column += (TAB_REPLACEMENT.length - 1) * (lines[line - 1].substr(0, column - 1).match(/\t/g) || []).length; + + if (column > MAX_LINE_LENGTH) { + cutLeft = column - OFFSET_CORRECTION + 3; + column = OFFSET_CORRECTION - 2; + } + + for (var i = startLine; i <= endLine; i++) { + if (i >= 0 && i < lines.length) { + lines[i] = lines[i].replace(/\t/g, TAB_REPLACEMENT); + lines[i] = + (cutLeft > 0 && lines[i].length > cutLeft ? '\u2026' : '') + + lines[i].substr(cutLeft, MAX_LINE_LENGTH - 2) + + (lines[i].length > cutLeft + MAX_LINE_LENGTH - 1 ? '\u2026' : ''); + } + } + + return [ + processLines(startLine, line), + new Array(column + maxNumLength + 2).join('-') + '^', + processLines(line, endLine) + ].filter(Boolean).join('\n'); +} + +var SyntaxError = function(message, source, offset, line, column) { + var error = createCustomError('SyntaxError', message); + + error.source = source; + error.offset = offset; + error.line = line; + error.column = column; + + error.sourceFragment = function(extraLines) { + return sourceFragment(error, isNaN(extraLines) ? 0 : extraLines); + }; + Object.defineProperty(error, 'formattedMessage', { + get: function() { + return ( + 'Parse error: ' + error.message + '\n' + + sourceFragment(error, 2) + ); + } + }); + + // for backward capability + error.parseError = { + offset: offset, + line: line, + column: column + }; + + return error; +}; + +module.exports = SyntaxError; + + +/***/ }), +/* 17 */ +/***/ ((module) => { + +module.exports = function createCustomError(name, message) { + // use Object.create(), because some VMs prevent setting line/column otherwise + // (iOS Safari 10 even throws an exception) + var error = Object.create(SyntaxError.prototype); + var errorStack = new Error(); + + error.name = name; + error.message = message; + + Object.defineProperty(error, 'stack', { + get: function() { + return (errorStack.stack || '').replace(/^(.+\n){1,3}/, name + ': ' + message + '\n'); + } + }); + + return error; +}; + + +/***/ }), +/* 18 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +var constants = __webpack_require__(19); +var TYPE = constants.TYPE; +var NAME = constants.NAME; + +var utils = __webpack_require__(20); +var cmpStr = utils.cmpStr; + +var EOF = TYPE.EOF; +var WHITESPACE = TYPE.WhiteSpace; +var COMMENT = TYPE.Comment; + +var OFFSET_MASK = 0x00FFFFFF; +var TYPE_SHIFT = 24; + +var TokenStream = function() { + this.offsetAndType = null; + this.balance = null; + + this.reset(); +}; + +TokenStream.prototype = { + reset: function() { + this.eof = false; + this.tokenIndex = -1; + this.tokenType = 0; + this.tokenStart = this.firstCharOffset; + this.tokenEnd = this.firstCharOffset; + }, + + lookupType: function(offset) { + offset += this.tokenIndex; + + if (offset < this.tokenCount) { + return this.offsetAndType[offset] >> TYPE_SHIFT; + } + + return EOF; + }, + lookupOffset: function(offset) { + offset += this.tokenIndex; + + if (offset < this.tokenCount) { + return this.offsetAndType[offset - 1] & OFFSET_MASK; + } + + return this.source.length; + }, + lookupValue: function(offset, referenceStr) { + offset += this.tokenIndex; + + if (offset < this.tokenCount) { + return cmpStr( + this.source, + this.offsetAndType[offset - 1] & OFFSET_MASK, + this.offsetAndType[offset] & OFFSET_MASK, + referenceStr + ); + } + + return false; + }, + getTokenStart: function(tokenIndex) { + if (tokenIndex === this.tokenIndex) { + return this.tokenStart; + } + + if (tokenIndex > 0) { + return tokenIndex < this.tokenCount + ? this.offsetAndType[tokenIndex - 1] & OFFSET_MASK + : this.offsetAndType[this.tokenCount] & OFFSET_MASK; + } + + return this.firstCharOffset; + }, + + // TODO: -> skipUntilBalanced + getRawLength: function(startToken, mode) { + var cursor = startToken; + var balanceEnd; + var offset = this.offsetAndType[Math.max(cursor - 1, 0)] & OFFSET_MASK; + var type; + + loop: + for (; cursor < this.tokenCount; cursor++) { + balanceEnd = this.balance[cursor]; + + // stop scanning on balance edge that points to offset before start token + if (balanceEnd < startToken) { + break loop; + } + + type = this.offsetAndType[cursor] >> TYPE_SHIFT; + + // check token is stop type + switch (mode(type, this.source, offset)) { + case 1: + break loop; + + case 2: + cursor++; + break loop; + + default: + // fast forward to the end of balanced block + if (this.balance[balanceEnd] === cursor) { + cursor = balanceEnd; + } + + offset = this.offsetAndType[cursor] & OFFSET_MASK; + } + } + + return cursor - this.tokenIndex; + }, + isBalanceEdge: function(pos) { + return this.balance[this.tokenIndex] < pos; + }, + isDelim: function(code, offset) { + if (offset) { + return ( + this.lookupType(offset) === TYPE.Delim && + this.source.charCodeAt(this.lookupOffset(offset)) === code + ); + } + + return ( + this.tokenType === TYPE.Delim && + this.source.charCodeAt(this.tokenStart) === code + ); + }, + + getTokenValue: function() { + return this.source.substring(this.tokenStart, this.tokenEnd); + }, + getTokenLength: function() { + return this.tokenEnd - this.tokenStart; + }, + substrToCursor: function(start) { + return this.source.substring(start, this.tokenStart); + }, + + skipWS: function() { + for (var i = this.tokenIndex, skipTokenCount = 0; i < this.tokenCount; i++, skipTokenCount++) { + if ((this.offsetAndType[i] >> TYPE_SHIFT) !== WHITESPACE) { + break; + } + } + + if (skipTokenCount > 0) { + this.skip(skipTokenCount); + } + }, + skipSC: function() { + while (this.tokenType === WHITESPACE || this.tokenType === COMMENT) { + this.next(); + } + }, + skip: function(tokenCount) { + var next = this.tokenIndex + tokenCount; + + if (next < this.tokenCount) { + this.tokenIndex = next; + this.tokenStart = this.offsetAndType[next - 1] & OFFSET_MASK; + next = this.offsetAndType[next]; + this.tokenType = next >> TYPE_SHIFT; + this.tokenEnd = next & OFFSET_MASK; + } else { + this.tokenIndex = this.tokenCount; + this.next(); + } + }, + next: function() { + var next = this.tokenIndex + 1; + + if (next < this.tokenCount) { + this.tokenIndex = next; + this.tokenStart = this.tokenEnd; + next = this.offsetAndType[next]; + this.tokenType = next >> TYPE_SHIFT; + this.tokenEnd = next & OFFSET_MASK; + } else { + this.tokenIndex = this.tokenCount; + this.eof = true; + this.tokenType = EOF; + this.tokenStart = this.tokenEnd = this.source.length; + } + }, + + forEachToken(fn) { + for (var i = 0, offset = this.firstCharOffset; i < this.tokenCount; i++) { + var start = offset; + var item = this.offsetAndType[i]; + var end = item & OFFSET_MASK; + var type = item >> TYPE_SHIFT; + + offset = end; + + fn(type, start, end, i); + } + }, + + dump() { + var tokens = new Array(this.tokenCount); + + this.forEachToken((type, start, end, index) => { + tokens[index] = { + idx: index, + type: NAME[type], + chunk: this.source.substring(start, end), + balance: this.balance[index] + }; + }); + + return tokens; + } +}; + +module.exports = TokenStream; + + +/***/ }), +/* 19 */ +/***/ ((module) => { + +// CSS Syntax Module Level 3 +// https://www.w3.org/TR/css-syntax-3/ +var TYPE = { + EOF: 0, // + Ident: 1, // + Function: 2, // + AtKeyword: 3, // + Hash: 4, // + String: 5, // + BadString: 6, // + Url: 7, // + BadUrl: 8, // + Delim: 9, // + Number: 10, // + Percentage: 11, // + Dimension: 12, // + WhiteSpace: 13, // + CDO: 14, // + CDC: 15, // + Colon: 16, // : + Semicolon: 17, // ; + Comma: 18, // , + LeftSquareBracket: 19, // <[-token> + RightSquareBracket: 20, // <]-token> + LeftParenthesis: 21, // <(-token> + RightParenthesis: 22, // <)-token> + LeftCurlyBracket: 23, // <{-token> + RightCurlyBracket: 24, // <}-token> + Comment: 25 +}; + +var NAME = Object.keys(TYPE).reduce(function(result, key) { + result[TYPE[key]] = key; + return result; +}, {}); + +module.exports = { + TYPE: TYPE, + NAME: NAME +}; + + +/***/ }), +/* 20 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +var charCodeDef = __webpack_require__(21); +var isDigit = charCodeDef.isDigit; +var isHexDigit = charCodeDef.isHexDigit; +var isUppercaseLetter = charCodeDef.isUppercaseLetter; +var isName = charCodeDef.isName; +var isWhiteSpace = charCodeDef.isWhiteSpace; +var isValidEscape = charCodeDef.isValidEscape; + +function getCharCode(source, offset) { + return offset < source.length ? source.charCodeAt(offset) : 0; +} + +function getNewlineLength(source, offset, code) { + if (code === 13 /* \r */ && getCharCode(source, offset + 1) === 10 /* \n */) { + return 2; + } + + return 1; +} + +function cmpChar(testStr, offset, referenceCode) { + var code = testStr.charCodeAt(offset); + + // code.toLowerCase() for A..Z + if (isUppercaseLetter(code)) { + code = code | 32; + } + + return code === referenceCode; +} + +function cmpStr(testStr, start, end, referenceStr) { + if (end - start !== referenceStr.length) { + return false; + } + + if (start < 0 || end > testStr.length) { + return false; + } + + for (var i = start; i < end; i++) { + var testCode = testStr.charCodeAt(i); + var referenceCode = referenceStr.charCodeAt(i - start); + + // testCode.toLowerCase() for A..Z + if (isUppercaseLetter(testCode)) { + testCode = testCode | 32; + } + + if (testCode !== referenceCode) { + return false; + } + } + + return true; +} + +function findWhiteSpaceStart(source, offset) { + for (; offset >= 0; offset--) { + if (!isWhiteSpace(source.charCodeAt(offset))) { + break; + } + } + + return offset + 1; +} + +function findWhiteSpaceEnd(source, offset) { + for (; offset < source.length; offset++) { + if (!isWhiteSpace(source.charCodeAt(offset))) { + break; + } + } + + return offset; +} + +function findDecimalNumberEnd(source, offset) { + for (; offset < source.length; offset++) { + if (!isDigit(source.charCodeAt(offset))) { + break; + } + } + + return offset; +} + +// § 4.3.7. Consume an escaped code point +function consumeEscaped(source, offset) { + // It assumes that the U+005C REVERSE SOLIDUS (\) has already been consumed and + // that the next input code point has already been verified to be part of a valid escape. + offset += 2; + + // hex digit + if (isHexDigit(getCharCode(source, offset - 1))) { + // Consume as many hex digits as possible, but no more than 5. + // Note that this means 1-6 hex digits have been consumed in total. + for (var maxOffset = Math.min(source.length, offset + 5); offset < maxOffset; offset++) { + if (!isHexDigit(getCharCode(source, offset))) { + break; + } + } + + // If the next input code point is whitespace, consume it as well. + var code = getCharCode(source, offset); + if (isWhiteSpace(code)) { + offset += getNewlineLength(source, offset, code); + } + } + + return offset; +} + +// §4.3.11. Consume a name +// Note: This algorithm does not do the verification of the first few code points that are necessary +// to ensure the returned code points would constitute an . If that is the intended use, +// ensure that the stream starts with an identifier before calling this algorithm. +function consumeName(source, offset) { + // Let result initially be an empty string. + // Repeatedly consume the next input code point from the stream: + for (; offset < source.length; offset++) { + var code = source.charCodeAt(offset); + + // name code point + if (isName(code)) { + // Append the code point to result. + continue; + } + + // the stream starts with a valid escape + if (isValidEscape(code, getCharCode(source, offset + 1))) { + // Consume an escaped code point. Append the returned code point to result. + offset = consumeEscaped(source, offset) - 1; + continue; + } + + // anything else + // Reconsume the current input code point. Return result. + break; + } + + return offset; +} + +// §4.3.12. Consume a number +function consumeNumber(source, offset) { + var code = source.charCodeAt(offset); + + // 2. If the next input code point is U+002B PLUS SIGN (+) or U+002D HYPHEN-MINUS (-), + // consume it and append it to repr. + if (code === 0x002B || code === 0x002D) { + code = source.charCodeAt(offset += 1); + } + + // 3. While the next input code point is a digit, consume it and append it to repr. + if (isDigit(code)) { + offset = findDecimalNumberEnd(source, offset + 1); + code = source.charCodeAt(offset); + } + + // 4. If the next 2 input code points are U+002E FULL STOP (.) followed by a digit, then: + if (code === 0x002E && isDigit(source.charCodeAt(offset + 1))) { + // 4.1 Consume them. + // 4.2 Append them to repr. + code = source.charCodeAt(offset += 2); + + // 4.3 Set type to "number". + // TODO + + // 4.4 While the next input code point is a digit, consume it and append it to repr. + + offset = findDecimalNumberEnd(source, offset); + } + + // 5. If the next 2 or 3 input code points are U+0045 LATIN CAPITAL LETTER E (E) + // or U+0065 LATIN SMALL LETTER E (e), ... , followed by a digit, then: + if (cmpChar(source, offset, 101 /* e */)) { + var sign = 0; + code = source.charCodeAt(offset + 1); + + // ... optionally followed by U+002D HYPHEN-MINUS (-) or U+002B PLUS SIGN (+) ... + if (code === 0x002D || code === 0x002B) { + sign = 1; + code = source.charCodeAt(offset + 2); + } + + // ... followed by a digit + if (isDigit(code)) { + // 5.1 Consume them. + // 5.2 Append them to repr. + + // 5.3 Set type to "number". + // TODO + + // 5.4 While the next input code point is a digit, consume it and append it to repr. + offset = findDecimalNumberEnd(source, offset + 1 + sign + 1); + } + } + + return offset; +} + +// § 4.3.14. Consume the remnants of a bad url +// ... its sole use is to consume enough of the input stream to reach a recovery point +// where normal tokenizing can resume. +function consumeBadUrlRemnants(source, offset) { + // Repeatedly consume the next input code point from the stream: + for (; offset < source.length; offset++) { + var code = source.charCodeAt(offset); + + // U+0029 RIGHT PARENTHESIS ()) + // EOF + if (code === 0x0029) { + // Return. + offset++; + break; + } + + if (isValidEscape(code, getCharCode(source, offset + 1))) { + // Consume an escaped code point. + // Note: This allows an escaped right parenthesis ("\)") to be encountered + // without ending the . This is otherwise identical to + // the "anything else" clause. + offset = consumeEscaped(source, offset); + } + } + + return offset; +} + +module.exports = { + consumeEscaped: consumeEscaped, + consumeName: consumeName, + consumeNumber: consumeNumber, + consumeBadUrlRemnants: consumeBadUrlRemnants, + + cmpChar: cmpChar, + cmpStr: cmpStr, + + getNewlineLength: getNewlineLength, + findWhiteSpaceStart: findWhiteSpaceStart, + findWhiteSpaceEnd: findWhiteSpaceEnd +}; + + +/***/ }), +/* 21 */ +/***/ ((module) => { + +var EOF = 0; + +// https://drafts.csswg.org/css-syntax-3/ +// § 4.2. Definitions + +// digit +// A code point between U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9). +function isDigit(code) { + return code >= 0x0030 && code <= 0x0039; +} + +// hex digit +// A digit, or a code point between U+0041 LATIN CAPITAL LETTER A (A) and U+0046 LATIN CAPITAL LETTER F (F), +// or a code point between U+0061 LATIN SMALL LETTER A (a) and U+0066 LATIN SMALL LETTER F (f). +function isHexDigit(code) { + return ( + isDigit(code) || // 0 .. 9 + (code >= 0x0041 && code <= 0x0046) || // A .. F + (code >= 0x0061 && code <= 0x0066) // a .. f + ); +} + +// uppercase letter +// A code point between U+0041 LATIN CAPITAL LETTER A (A) and U+005A LATIN CAPITAL LETTER Z (Z). +function isUppercaseLetter(code) { + return code >= 0x0041 && code <= 0x005A; +} + +// lowercase letter +// A code point between U+0061 LATIN SMALL LETTER A (a) and U+007A LATIN SMALL LETTER Z (z). +function isLowercaseLetter(code) { + return code >= 0x0061 && code <= 0x007A; +} + +// letter +// An uppercase letter or a lowercase letter. +function isLetter(code) { + return isUppercaseLetter(code) || isLowercaseLetter(code); +} + +// non-ASCII code point +// A code point with a value equal to or greater than U+0080 . +function isNonAscii(code) { + return code >= 0x0080; +} + +// name-start code point +// A letter, a non-ASCII code point, or U+005F LOW LINE (_). +function isNameStart(code) { + return isLetter(code) || isNonAscii(code) || code === 0x005F; +} + +// name code point +// A name-start code point, a digit, or U+002D HYPHEN-MINUS (-). +function isName(code) { + return isNameStart(code) || isDigit(code) || code === 0x002D; +} + +// non-printable code point +// A code point between U+0000 NULL and U+0008 BACKSPACE, or U+000B LINE TABULATION, +// or a code point between U+000E SHIFT OUT and U+001F INFORMATION SEPARATOR ONE, or U+007F DELETE. +function isNonPrintable(code) { + return ( + (code >= 0x0000 && code <= 0x0008) || + (code === 0x000B) || + (code >= 0x000E && code <= 0x001F) || + (code === 0x007F) + ); +} + +// newline +// U+000A LINE FEED. Note that U+000D CARRIAGE RETURN and U+000C FORM FEED are not included in this definition, +// as they are converted to U+000A LINE FEED during preprocessing. +// TODO: we doesn't do a preprocessing, so check a code point for U+000D CARRIAGE RETURN and U+000C FORM FEED +function isNewline(code) { + return code === 0x000A || code === 0x000D || code === 0x000C; +} + +// whitespace +// A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE. +function isWhiteSpace(code) { + return isNewline(code) || code === 0x0020 || code === 0x0009; +} + +// § 4.3.8. Check if two code points are a valid escape +function isValidEscape(first, second) { + // If the first code point is not U+005C REVERSE SOLIDUS (\), return false. + if (first !== 0x005C) { + return false; + } + + // Otherwise, if the second code point is a newline or EOF, return false. + if (isNewline(second) || second === EOF) { + return false; + } + + // Otherwise, return true. + return true; +} + +// § 4.3.9. Check if three code points would start an identifier +function isIdentifierStart(first, second, third) { + // Look at the first code point: + + // U+002D HYPHEN-MINUS + if (first === 0x002D) { + // If the second code point is a name-start code point or a U+002D HYPHEN-MINUS, + // or the second and third code points are a valid escape, return true. Otherwise, return false. + return ( + isNameStart(second) || + second === 0x002D || + isValidEscape(second, third) + ); + } + + // name-start code point + if (isNameStart(first)) { + // Return true. + return true; + } + + // U+005C REVERSE SOLIDUS (\) + if (first === 0x005C) { + // If the first and second code points are a valid escape, return true. Otherwise, return false. + return isValidEscape(first, second); + } + + // anything else + // Return false. + return false; +} + +// § 4.3.10. Check if three code points would start a number +function isNumberStart(first, second, third) { + // Look at the first code point: + + // U+002B PLUS SIGN (+) + // U+002D HYPHEN-MINUS (-) + if (first === 0x002B || first === 0x002D) { + // If the second code point is a digit, return true. + if (isDigit(second)) { + return 2; + } + + // Otherwise, if the second code point is a U+002E FULL STOP (.) + // and the third code point is a digit, return true. + // Otherwise, return false. + return second === 0x002E && isDigit(third) ? 3 : 0; + } + + // U+002E FULL STOP (.) + if (first === 0x002E) { + // If the second code point is a digit, return true. Otherwise, return false. + return isDigit(second) ? 2 : 0; + } + + // digit + if (isDigit(first)) { + // Return true. + return 1; + } + + // anything else + // Return false. + return 0; +} + +// +// Misc +// + +// detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark) +function isBOM(code) { + // UTF-16BE + if (code === 0xFEFF) { + return 1; + } + + // UTF-16LE + if (code === 0xFFFE) { + return 1; + } + + return 0; +} + +// Fast code category +// +// https://drafts.csswg.org/css-syntax/#tokenizer-definitions +// > non-ASCII code point +// > A code point with a value equal to or greater than U+0080 +// > name-start code point +// > A letter, a non-ASCII code point, or U+005F LOW LINE (_). +// > name code point +// > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-) +// That means only ASCII code points has a special meaning and we define a maps for 0..127 codes only +var CATEGORY = new Array(0x80); +charCodeCategory.Eof = 0x80; +charCodeCategory.WhiteSpace = 0x82; +charCodeCategory.Digit = 0x83; +charCodeCategory.NameStart = 0x84; +charCodeCategory.NonPrintable = 0x85; + +for (var i = 0; i < CATEGORY.length; i++) { + switch (true) { + case isWhiteSpace(i): + CATEGORY[i] = charCodeCategory.WhiteSpace; + break; + + case isDigit(i): + CATEGORY[i] = charCodeCategory.Digit; + break; + + case isNameStart(i): + CATEGORY[i] = charCodeCategory.NameStart; + break; + + case isNonPrintable(i): + CATEGORY[i] = charCodeCategory.NonPrintable; + break; + + default: + CATEGORY[i] = i || charCodeCategory.Eof; + } +} + +function charCodeCategory(code) { + return code < 0x80 ? CATEGORY[code] : charCodeCategory.NameStart; +}; + +module.exports = { + isDigit: isDigit, + isHexDigit: isHexDigit, + isUppercaseLetter: isUppercaseLetter, + isLowercaseLetter: isLowercaseLetter, + isLetter: isLetter, + isNonAscii: isNonAscii, + isNameStart: isNameStart, + isName: isName, + isNonPrintable: isNonPrintable, + isNewline: isNewline, + isWhiteSpace: isWhiteSpace, + isValidEscape: isValidEscape, + isIdentifierStart: isIdentifierStart, + isNumberStart: isNumberStart, + + isBOM: isBOM, + charCodeCategory: charCodeCategory +}; + + +/***/ }), +/* 22 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +var SyntaxReferenceError = __webpack_require__(23).SyntaxReferenceError; +var SyntaxMatchError = __webpack_require__(23).SyntaxMatchError; +var names = __webpack_require__(25); +var generic = __webpack_require__(26); +var parse = __webpack_require__(31); +var generate = __webpack_require__(24); +var walk = __webpack_require__(34); +var prepareTokens = __webpack_require__(35); +var buildMatchGraph = __webpack_require__(36).buildMatchGraph; +var matchAsTree = __webpack_require__(37).matchAsTree; +var trace = __webpack_require__(38); +var search = __webpack_require__(39); +var getStructureFromConfig = __webpack_require__(40).getStructureFromConfig; +var cssWideKeywords = buildMatchGraph('inherit | initial | unset'); +var cssWideKeywordsWithExpression = buildMatchGraph('inherit | initial | unset | <-ms-legacy-expression>'); + +function dumpMapSyntax(map, compact, syntaxAsAst) { + var result = {}; + + for (var name in map) { + if (map[name].syntax) { + result[name] = syntaxAsAst + ? map[name].syntax + : generate(map[name].syntax, { compact: compact }); + } + } + + return result; +} + +function dumpAtruleMapSyntax(map, compact, syntaxAsAst) { + const result = {}; + + for (const [name, atrule] of Object.entries(map)) { + result[name] = { + prelude: atrule.prelude && ( + syntaxAsAst + ? atrule.prelude.syntax + : generate(atrule.prelude.syntax, { compact }) + ), + descriptors: atrule.descriptors && dumpMapSyntax(atrule.descriptors, compact, syntaxAsAst) + }; + } + + return result; +} + +function valueHasVar(tokens) { + for (var i = 0; i < tokens.length; i++) { + if (tokens[i].value.toLowerCase() === 'var(') { + return true; + } + } + + return false; +} + +function buildMatchResult(match, error, iterations) { + return { + matched: match, + iterations: iterations, + error: error, + getTrace: trace.getTrace, + isType: trace.isType, + isProperty: trace.isProperty, + isKeyword: trace.isKeyword + }; +} + +function matchSyntax(lexer, syntax, value, useCommon) { + var tokens = prepareTokens(value, lexer.syntax); + var result; + + if (valueHasVar(tokens)) { + return buildMatchResult(null, new Error('Matching for a tree with var() is not supported')); + } + + if (useCommon) { + result = matchAsTree(tokens, lexer.valueCommonSyntax, lexer); + } + + if (!useCommon || !result.match) { + result = matchAsTree(tokens, syntax.match, lexer); + if (!result.match) { + return buildMatchResult( + null, + new SyntaxMatchError(result.reason, syntax.syntax, value, result), + result.iterations + ); + } + } + + return buildMatchResult(result.match, null, result.iterations); +} + +var Lexer = function(config, syntax, structure) { + this.valueCommonSyntax = cssWideKeywords; + this.syntax = syntax; + this.generic = false; + this.atrules = {}; + this.properties = {}; + this.types = {}; + this.structure = structure || getStructureFromConfig(config); + + if (config) { + if (config.types) { + for (var name in config.types) { + this.addType_(name, config.types[name]); + } + } + + if (config.generic) { + this.generic = true; + for (var name in generic) { + this.addType_(name, generic[name]); + } + } + + if (config.atrules) { + for (var name in config.atrules) { + this.addAtrule_(name, config.atrules[name]); + } + } + + if (config.properties) { + for (var name in config.properties) { + this.addProperty_(name, config.properties[name]); + } + } + } +}; + +Lexer.prototype = { + structure: {}, + checkStructure: function(ast) { + function collectWarning(node, message) { + warns.push({ + node: node, + message: message + }); + } + + var structure = this.structure; + var warns = []; + + this.syntax.walk(ast, function(node) { + if (structure.hasOwnProperty(node.type)) { + structure[node.type].check(node, collectWarning); + } else { + collectWarning(node, 'Unknown node type `' + node.type + '`'); + } + }); + + return warns.length ? warns : false; + }, + + createDescriptor: function(syntax, type, name, parent = null) { + var ref = { + type: type, + name: name + }; + var descriptor = { + type: type, + name: name, + parent: parent, + syntax: null, + match: null + }; + + if (typeof syntax === 'function') { + descriptor.match = buildMatchGraph(syntax, ref); + } else { + if (typeof syntax === 'string') { + // lazy parsing on first access + Object.defineProperty(descriptor, 'syntax', { + get: function() { + Object.defineProperty(descriptor, 'syntax', { + value: parse(syntax) + }); + + return descriptor.syntax; + } + }); + } else { + descriptor.syntax = syntax; + } + + // lazy graph build on first access + Object.defineProperty(descriptor, 'match', { + get: function() { + Object.defineProperty(descriptor, 'match', { + value: buildMatchGraph(descriptor.syntax, ref) + }); + + return descriptor.match; + } + }); + } + + return descriptor; + }, + addAtrule_: function(name, syntax) { + if (!syntax) { + return; + } + + this.atrules[name] = { + type: 'Atrule', + name: name, + prelude: syntax.prelude ? this.createDescriptor(syntax.prelude, 'AtrulePrelude', name) : null, + descriptors: syntax.descriptors + ? Object.keys(syntax.descriptors).reduce((res, descName) => { + res[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name); + return res; + }, {}) + : null + }; + }, + addProperty_: function(name, syntax) { + if (!syntax) { + return; + } + + this.properties[name] = this.createDescriptor(syntax, 'Property', name); + }, + addType_: function(name, syntax) { + if (!syntax) { + return; + } + + this.types[name] = this.createDescriptor(syntax, 'Type', name); + + if (syntax === generic['-ms-legacy-expression']) { + this.valueCommonSyntax = cssWideKeywordsWithExpression; + } + }, + + checkAtruleName: function(atruleName) { + if (!this.getAtrule(atruleName)) { + return new SyntaxReferenceError('Unknown at-rule', '@' + atruleName); + } + }, + checkAtrulePrelude: function(atruleName, prelude) { + let error = this.checkAtruleName(atruleName); + + if (error) { + return error; + } + + var atrule = this.getAtrule(atruleName); + + if (!atrule.prelude && prelude) { + return new SyntaxError('At-rule `@' + atruleName + '` should not contain a prelude'); + } + + if (atrule.prelude && !prelude) { + return new SyntaxError('At-rule `@' + atruleName + '` should contain a prelude'); + } + }, + checkAtruleDescriptorName: function(atruleName, descriptorName) { + let error = this.checkAtruleName(atruleName); + + if (error) { + return error; + } + + var atrule = this.getAtrule(atruleName); + var descriptor = names.keyword(descriptorName); + + if (!atrule.descriptors) { + return new SyntaxError('At-rule `@' + atruleName + '` has no known descriptors'); + } + + if (!atrule.descriptors[descriptor.name] && + !atrule.descriptors[descriptor.basename]) { + return new SyntaxReferenceError('Unknown at-rule descriptor', descriptorName); + } + }, + checkPropertyName: function(propertyName) { + var property = names.property(propertyName); + + // don't match syntax for a custom property + if (property.custom) { + return new Error('Lexer matching doesn\'t applicable for custom properties'); + } + + if (!this.getProperty(propertyName)) { + return new SyntaxReferenceError('Unknown property', propertyName); + } + }, + + matchAtrulePrelude: function(atruleName, prelude) { + var error = this.checkAtrulePrelude(atruleName, prelude); + + if (error) { + return buildMatchResult(null, error); + } + + if (!prelude) { + return buildMatchResult(null, null); + } + + return matchSyntax(this, this.getAtrule(atruleName).prelude, prelude, false); + }, + matchAtruleDescriptor: function(atruleName, descriptorName, value) { + var error = this.checkAtruleDescriptorName(atruleName, descriptorName); + + if (error) { + return buildMatchResult(null, error); + } + + var atrule = this.getAtrule(atruleName); + var descriptor = names.keyword(descriptorName); + + return matchSyntax(this, atrule.descriptors[descriptor.name] || atrule.descriptors[descriptor.basename], value, false); + }, + matchDeclaration: function(node) { + if (node.type !== 'Declaration') { + return buildMatchResult(null, new Error('Not a Declaration node')); + } + + return this.matchProperty(node.property, node.value); + }, + matchProperty: function(propertyName, value) { + var error = this.checkPropertyName(propertyName); + + if (error) { + return buildMatchResult(null, error); + } + + return matchSyntax(this, this.getProperty(propertyName), value, true); + }, + matchType: function(typeName, value) { + var typeSyntax = this.getType(typeName); + + if (!typeSyntax) { + return buildMatchResult(null, new SyntaxReferenceError('Unknown type', typeName)); + } + + return matchSyntax(this, typeSyntax, value, false); + }, + match: function(syntax, value) { + if (typeof syntax !== 'string' && (!syntax || !syntax.type)) { + return buildMatchResult(null, new SyntaxReferenceError('Bad syntax')); + } + + if (typeof syntax === 'string' || !syntax.match) { + syntax = this.createDescriptor(syntax, 'Type', 'anonymous'); + } + + return matchSyntax(this, syntax, value, false); + }, + + findValueFragments: function(propertyName, value, type, name) { + return search.matchFragments(this, value, this.matchProperty(propertyName, value), type, name); + }, + findDeclarationValueFragments: function(declaration, type, name) { + return search.matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name); + }, + findAllFragments: function(ast, type, name) { + var result = []; + + this.syntax.walk(ast, { + visit: 'Declaration', + enter: function(declaration) { + result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name)); + }.bind(this) + }); + + return result; + }, + + getAtrule: function(atruleName, fallbackBasename = true) { + var atrule = names.keyword(atruleName); + var atruleEntry = atrule.vendor && fallbackBasename + ? this.atrules[atrule.name] || this.atrules[atrule.basename] + : this.atrules[atrule.name]; + + return atruleEntry || null; + }, + getAtrulePrelude: function(atruleName, fallbackBasename = true) { + const atrule = this.getAtrule(atruleName, fallbackBasename); + + return atrule && atrule.prelude || null; + }, + getAtruleDescriptor: function(atruleName, name) { + return this.atrules.hasOwnProperty(atruleName) && this.atrules.declarators + ? this.atrules[atruleName].declarators[name] || null + : null; + }, + getProperty: function(propertyName, fallbackBasename = true) { + var property = names.property(propertyName); + var propertyEntry = property.vendor && fallbackBasename + ? this.properties[property.name] || this.properties[property.basename] + : this.properties[property.name]; + + return propertyEntry || null; + }, + getType: function(name) { + return this.types.hasOwnProperty(name) ? this.types[name] : null; + }, + + validate: function() { + function validate(syntax, name, broken, descriptor) { + if (broken.hasOwnProperty(name)) { + return broken[name]; + } + + broken[name] = false; + if (descriptor.syntax !== null) { + walk(descriptor.syntax, function(node) { + if (node.type !== 'Type' && node.type !== 'Property') { + return; + } + + var map = node.type === 'Type' ? syntax.types : syntax.properties; + var brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties; + + if (!map.hasOwnProperty(node.name) || validate(syntax, node.name, brokenMap, map[node.name])) { + broken[name] = true; + } + }, this); + } + } + + var brokenTypes = {}; + var brokenProperties = {}; + + for (var key in this.types) { + validate(this, key, brokenTypes, this.types[key]); + } + + for (var key in this.properties) { + validate(this, key, brokenProperties, this.properties[key]); + } + + brokenTypes = Object.keys(brokenTypes).filter(function(name) { + return brokenTypes[name]; + }); + brokenProperties = Object.keys(brokenProperties).filter(function(name) { + return brokenProperties[name]; + }); + + if (brokenTypes.length || brokenProperties.length) { + return { + types: brokenTypes, + properties: brokenProperties + }; + } + + return null; + }, + dump: function(syntaxAsAst, pretty) { + return { + generic: this.generic, + types: dumpMapSyntax(this.types, !pretty, syntaxAsAst), + properties: dumpMapSyntax(this.properties, !pretty, syntaxAsAst), + atrules: dumpAtruleMapSyntax(this.atrules, !pretty, syntaxAsAst) + }; + }, + toString: function() { + return JSON.stringify(this.dump()); + } +}; + +module.exports = Lexer; + + +/***/ }), +/* 23 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +const createCustomError = __webpack_require__(17); +const generate = __webpack_require__(24); +const defaultLoc = { offset: 0, line: 1, column: 1 }; + +function locateMismatch(matchResult, node) { + const tokens = matchResult.tokens; + const longestMatch = matchResult.longestMatch; + const mismatchNode = longestMatch < tokens.length ? tokens[longestMatch].node || null : null; + const badNode = mismatchNode !== node ? mismatchNode : null; + let mismatchOffset = 0; + let mismatchLength = 0; + let entries = 0; + let css = ''; + let start; + let end; + + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i].value; + + if (i === longestMatch) { + mismatchLength = token.length; + mismatchOffset = css.length; + } + + if (badNode !== null && tokens[i].node === badNode) { + if (i <= longestMatch) { + entries++; + } else { + entries = 0; + } + } + + css += token; + } + + if (longestMatch === tokens.length || entries > 1) { // last + start = fromLoc(badNode || node, 'end') || buildLoc(defaultLoc, css); + end = buildLoc(start); + } else { + start = fromLoc(badNode, 'start') || + buildLoc(fromLoc(node, 'start') || defaultLoc, css.slice(0, mismatchOffset)); + end = fromLoc(badNode, 'end') || + buildLoc(start, css.substr(mismatchOffset, mismatchLength)); + } + + return { + css, + mismatchOffset, + mismatchLength, + start, + end + }; +} + +function fromLoc(node, point) { + const value = node && node.loc && node.loc[point]; + + if (value) { + return 'line' in value ? buildLoc(value) : value; + } + + return null; +} + +function buildLoc({ offset, line, column }, extra) { + const loc = { + offset, + line, + column + }; + + if (extra) { + const lines = extra.split(/\n|\r\n?|\f/); + + loc.offset += extra.length; + loc.line += lines.length - 1; + loc.column = lines.length === 1 ? loc.column + extra.length : lines.pop().length + 1; + } + + return loc; +} + +const SyntaxReferenceError = function(type, referenceName) { + const error = createCustomError( + 'SyntaxReferenceError', + type + (referenceName ? ' `' + referenceName + '`' : '') + ); + + error.reference = referenceName; + + return error; +}; + +const SyntaxMatchError = function(message, syntax, node, matchResult) { + const error = createCustomError('SyntaxMatchError', message); + const { + css, + mismatchOffset, + mismatchLength, + start, + end + } = locateMismatch(matchResult, node); + + error.rawMessage = message; + error.syntax = syntax ? generate(syntax) : ''; + error.css = css; + error.mismatchOffset = mismatchOffset; + error.mismatchLength = mismatchLength; + error.message = message + '\n' + + ' syntax: ' + error.syntax + '\n' + + ' value: ' + (css || '') + '\n' + + ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^'; + + Object.assign(error, start); + error.loc = { + source: (node && node.loc && node.loc.source) || '', + start, + end + }; + + return error; +}; + +module.exports = { + SyntaxReferenceError, + SyntaxMatchError +}; + + +/***/ }), +/* 24 */ +/***/ ((module) => { + +function noop(value) { + return value; +} + +function generateMultiplier(multiplier) { + if (multiplier.min === 0 && multiplier.max === 0) { + return '*'; + } + + if (multiplier.min === 0 && multiplier.max === 1) { + return '?'; + } + + if (multiplier.min === 1 && multiplier.max === 0) { + return multiplier.comma ? '#' : '+'; + } + + if (multiplier.min === 1 && multiplier.max === 1) { + return ''; + } + + return ( + (multiplier.comma ? '#' : '') + + (multiplier.min === multiplier.max + ? '{' + multiplier.min + '}' + : '{' + multiplier.min + ',' + (multiplier.max !== 0 ? multiplier.max : '') + '}' + ) + ); +} + +function generateTypeOpts(node) { + switch (node.type) { + case 'Range': + return ( + ' [' + + (node.min === null ? '-∞' : node.min) + + ',' + + (node.max === null ? '∞' : node.max) + + ']' + ); + + default: + throw new Error('Unknown node type `' + node.type + '`'); + } +} + +function generateSequence(node, decorate, forceBraces, compact) { + var combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' '; + var result = node.terms.map(function(term) { + return generate(term, decorate, forceBraces, compact); + }).join(combinator); + + if (node.explicit || forceBraces) { + result = (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]'); + } + + return result; +} + +function generate(node, decorate, forceBraces, compact) { + var result; + + switch (node.type) { + case 'Group': + result = + generateSequence(node, decorate, forceBraces, compact) + + (node.disallowEmpty ? '!' : ''); + break; + + case 'Multiplier': + // return since node is a composition + return ( + generate(node.term, decorate, forceBraces, compact) + + decorate(generateMultiplier(node), node) + ); + + case 'Type': + result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>'; + break; + + case 'Property': + result = '<\'' + node.name + '\'>'; + break; + + case 'Keyword': + result = node.name; + break; + + case 'AtKeyword': + result = '@' + node.name; + break; + + case 'Function': + result = node.name + '('; + break; + + case 'String': + case 'Token': + result = node.value; + break; + + case 'Comma': + result = ','; + break; + + default: + throw new Error('Unknown node type `' + node.type + '`'); + } + + return decorate(result, node); +} + +module.exports = function(node, options) { + var decorate = noop; + var forceBraces = false; + var compact = false; + + if (typeof options === 'function') { + decorate = options; + } else if (options) { + forceBraces = Boolean(options.forceBraces); + compact = Boolean(options.compact); + if (typeof options.decorate === 'function') { + decorate = options.decorate; + } + } + + return generate(node, decorate, forceBraces, compact); +}; + + +/***/ }), +/* 25 */ +/***/ ((module) => { + +var hasOwnProperty = Object.prototype.hasOwnProperty; +var keywords = Object.create(null); +var properties = Object.create(null); +var HYPHENMINUS = 45; // '-'.charCodeAt() + +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 + var secondDashIndex = str.indexOf('-', offset + 2); + + if (secondDashIndex !== -1) { + return str.substring(offset, secondDashIndex + 1); + } + } + } + + return ''; +} + +function getKeywordDescriptor(keyword) { + if (hasOwnProperty.call(keywords, keyword)) { + return keywords[keyword]; + } + + var name = keyword.toLowerCase(); + + if (hasOwnProperty.call(keywords, name)) { + return keywords[keyword] = keywords[name]; + } + + var custom = isCustomProperty(name, 0); + var vendor = !custom ? getVendorPrefix(name, 0) : ''; + + return keywords[keyword] = Object.freeze({ + basename: name.substr(vendor.length), + name: name, + vendor: vendor, + prefix: vendor, + custom: custom + }); +} + +function getPropertyDescriptor(property) { + if (hasOwnProperty.call(properties, property)) { + return properties[property]; + } + + var name = property; + var hack = property[0]; + + if (hack === '/') { + hack = property[1] === '/' ? '//' : '/'; + } else if (hack !== '_' && + hack !== '*' && + hack !== '$' && + hack !== '#' && + hack !== '+' && + hack !== '&') { + hack = ''; + } + + var custom = isCustomProperty(name, hack.length); + + // re-use result when possible (the same as for lower case) + if (!custom) { + name = name.toLowerCase(); + if (hasOwnProperty.call(properties, name)) { + return properties[property] = properties[name]; + } + } + + var vendor = !custom ? getVendorPrefix(name, hack.length) : ''; + var prefix = name.substr(0, hack.length + vendor.length); + + return properties[property] = Object.freeze({ + basename: name.substr(prefix.length), + name: name.substr(hack.length), + hack: hack, + vendor: vendor, + prefix: prefix, + custom: custom + }); +} + +module.exports = { + keyword: getKeywordDescriptor, + property: getPropertyDescriptor, + isCustomProperty: isCustomProperty, + vendorPrefix: getVendorPrefix +}; + + +/***/ }), +/* 26 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +var tokenizer = __webpack_require__(27); +var isIdentifierStart = tokenizer.isIdentifierStart; +var isHexDigit = tokenizer.isHexDigit; +var isDigit = tokenizer.isDigit; +var cmpStr = tokenizer.cmpStr; +var consumeNumber = tokenizer.consumeNumber; +var TYPE = tokenizer.TYPE; +var anPlusB = __webpack_require__(29); +var urange = __webpack_require__(30); + +var cssWideKeywords = ['unset', 'initial', 'inherit']; +var calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc(']; + +// https://www.w3.org/TR/css-values-3/#lengths +var LENGTH = { + // absolute length units + 'px': true, + 'mm': true, + 'cm': true, + 'in': true, + 'pt': true, + 'pc': true, + 'q': true, + + // relative length units + 'em': true, + 'ex': true, + 'ch': true, + 'rem': true, + + // viewport-percentage lengths + 'vh': true, + 'vw': true, + 'vmin': true, + 'vmax': true, + 'vm': true +}; + +var ANGLE = { + 'deg': true, + 'grad': true, + 'rad': true, + 'turn': true +}; + +var TIME = { + 's': true, + 'ms': true +}; + +var FREQUENCY = { + 'hz': true, + 'khz': true +}; + +// https://www.w3.org/TR/css-values-3/#resolution (https://drafts.csswg.org/css-values/#resolution) +var RESOLUTION = { + 'dpi': true, + 'dpcm': true, + 'dppx': true, + 'x': true // https://github.com/w3c/csswg-drafts/issues/461 +}; + +// https://drafts.csswg.org/css-grid/#fr-unit +var FLEX = { + 'fr': true +}; + +// https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume +var DECIBEL = { + 'db': true +}; + +// https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch +var SEMITONES = { + 'st': true +}; + +// safe char code getter +function charCode(str, index) { + return index < str.length ? str.charCodeAt(index) : 0; +} + +function eqStr(actual, expected) { + return cmpStr(actual, 0, actual.length, expected); +} + +function eqStrAny(actual, expected) { + for (var i = 0; i < expected.length; i++) { + if (eqStr(actual, expected[i])) { + return true; + } + } + + return false; +} + +// IE postfix hack, i.e. 123\0 or 123px\9 +function isPostfixIeHack(str, offset) { + if (offset !== str.length - 2) { + return false; + } + + return ( + str.charCodeAt(offset) === 0x005C && // U+005C REVERSE SOLIDUS (\) + isDigit(str.charCodeAt(offset + 1)) + ); +} + +function outOfRange(opts, value, numEnd) { + if (opts && opts.type === 'Range') { + var num = Number( + numEnd !== undefined && numEnd !== value.length + ? value.substr(0, numEnd) + : value + ); + + if (isNaN(num)) { + return true; + } + + if (opts.min !== null && num < opts.min) { + return true; + } + + if (opts.max !== null && num > opts.max) { + return true; + } + } + + return false; +} + +function consumeFunction(token, getNextToken) { + var startIdx = token.index; + var length = 0; + + // balanced token consuming + do { + length++; + + if (token.balance <= startIdx) { + break; + } + } while (token = getNextToken(length)); + + return length; +} + +// TODO: implement +// can be used wherever , , ,