@pi-r/chrome 0.12.5 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extensions/css/remove-unused/index.js +1 -1
- package/index.js +109 -89
- package/package.json +3 -2
|
@@ -7,7 +7,7 @@ const { escapePattern, manageGlobalObject } = require('@e-mc/types');
|
|
|
7
7
|
const { PATTERN_PARENTHESIS, findClosingIndex, getNewlineString, replaceMatch, spliceSource, splitEnclosing } = require('@pi-r/chrome/util');
|
|
8
8
|
const PATTERN_STRING_SOME = '(?:\\s|' + DomWriter.PATTERN_COMMENT + '|`[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}`)*';
|
|
9
9
|
const PATTERN_STRING_MANY = PATTERN_STRING_SOME.slice(0, -1) + '+';
|
|
10
|
-
const PATTERN_VARIABLE = '--(?:[
|
|
10
|
+
const PATTERN_VARIABLE = '--(?:[\\w-]+|\\\\\\S|[^\\u0000-\\u007F])+';
|
|
11
11
|
const CACHE_ATRULES = Object.create(null);
|
|
12
12
|
const CACHE_QUERY = new Map();
|
|
13
13
|
const CACHE_SELECTOR = new Map();
|
package/index.js
CHANGED
|
@@ -4,14 +4,15 @@ const path = require('node:path');
|
|
|
4
4
|
const fs = require('node:fs');
|
|
5
5
|
const { randomUUID } = require('node:crypto');
|
|
6
6
|
const { imageSize } = require('image-size');
|
|
7
|
+
const { JSONPath } = require('jsonpath-plus');
|
|
7
8
|
const Cloud = require('@e-mc/cloud');
|
|
8
9
|
const { ClientDb } = require('@e-mc/core');
|
|
9
10
|
const { DomWriter, HtmlElement, IGNORE_FLAG } = require('@e-mc/document/parse/dom');
|
|
10
11
|
const { ERR_CODE, FILE_TYPE, WATCH_EVENT, asExt, asFunction, cascadeObject, cloneFlag, cloneObject, coerceObject, createAbortError, errorMessage, errorValue, escapePattern, existsFlag, getEncoding, ignoreFlag, isArray, isEmpty, isError, isErrorCode, isFunction, isObject, isPlainObject, isString, modifiedFlag, processFlag, randomString, renameExt, requireESM, watchFlag } = require('@e-mc/types');
|
|
11
12
|
const { isEqual, setInitialValue } = require('@e-mc/document/asset');
|
|
12
|
-
const { appendSuffix, getHashData, getModuleName, getNewline, hasValue, spliceString, trimQuote } = require('@e-mc/document/util');
|
|
13
|
+
const { appendSuffix, getHashData, getModuleName, getNewline, hasValue, spliceMatch, spliceString, splitEnclosing, trimQuote } = require('@e-mc/document/util');
|
|
13
14
|
const { SourceMap } = require('@e-mc/document/transform');
|
|
14
|
-
const {
|
|
15
|
+
const { findClosingIndex, getNewlineString, isSpace, replaceMatch } = require('@pi-r/chrome/util');
|
|
15
16
|
const Document = require('@e-mc/document');
|
|
16
17
|
const kChrome = Symbol.for('chrome:constructor');
|
|
17
18
|
const CACHE_DBRESULT = new Map();
|
|
@@ -32,7 +33,7 @@ const REGEXP_BLOCKEXCLUDE = new RegExp(`(\\s*)<!--\\s*exclude\\s*:\\s*(?:start|e
|
|
|
32
33
|
const REGEXP_STYLE = new RegExp(`(<style${DomWriter.PATTERN_TAGOPEN}*>)(.*?)(<\\/style\\s*>)`, 'gis');
|
|
33
34
|
const REGEXP_SANITIZEALL = new RegExp(`(?:\\s+|\\b)data-(?:pathname|filename|intl-locales|(?:use|exclude)-[^=\\s]+)\\s*${DomWriter.PATTERN_ATTRVALUE}(?=(?:[^"<]+"[^"]*"|[^'<]+'[^']*')*[^<>]*>)`, 'g');
|
|
34
35
|
const REGEXP_IMAGESET_URL = /(?:^|[^(])\s*("(\s*[^)][^"]*)"|'(\s*[^)][^"]*)')\s*(?:,|$|[^)][^,]*,?)/gd;
|
|
35
|
-
const
|
|
36
|
+
const REGEXP_URLMODIFIER = /\b(?<!-)url\(\s*(["'])(.+)\1\s*((?:cross-origin|integrity|referrer-policy)\([^)]+\))\s*\)/gi;
|
|
36
37
|
function removeNamespace(name, source, newline, comments) {
|
|
37
38
|
if (source.includes('-' + name)) {
|
|
38
39
|
const [a, b, c, d, e] = CACHE_DATASET[name] ||= [
|
|
@@ -324,8 +325,8 @@ const isHtmlOnly = (assets, items, htmlFile) => !items.find(item => item !== htm
|
|
|
324
325
|
class SessionOutput {
|
|
325
326
|
host;
|
|
326
327
|
startTime;
|
|
327
|
-
contentMap =
|
|
328
|
-
bufferMap =
|
|
328
|
+
contentMap = Object.create(null);
|
|
329
|
+
bufferMap = Object.create(null);
|
|
329
330
|
cacheMiss = [];
|
|
330
331
|
hashed = new Set();
|
|
331
332
|
productionRelease;
|
|
@@ -544,7 +545,7 @@ class ChromeDocument extends Document {
|
|
|
544
545
|
const mapped = [];
|
|
545
546
|
for (const localDir in serverRootMapping) {
|
|
546
547
|
const subDir = path.normalize(serverRootMapping[localDir]);
|
|
547
|
-
const destDir = validateDir(Document.normalizePath(subDir.
|
|
548
|
+
const destDir = validateDir(Document.normalizePath(subDir.at(-1) === path.sep ? path.join(outputDir, subDir, localDir) : path.join(outputDir, subDir), true));
|
|
548
549
|
if (destDir.startsWith(outputDir)) {
|
|
549
550
|
if (this.canWrite(destDir)) {
|
|
550
551
|
mapped.push([Document.normalizePath(localDir, true), destDir, 0]);
|
|
@@ -1116,23 +1117,24 @@ class ChromeDocument extends Document {
|
|
|
1116
1117
|
}
|
|
1117
1118
|
catch {
|
|
1118
1119
|
}
|
|
1119
|
-
continue;
|
|
1120
1120
|
}
|
|
1121
|
-
|
|
1122
|
-
if (
|
|
1123
|
-
|
|
1121
|
+
else {
|
|
1122
|
+
if (relative) {
|
|
1123
|
+
if (ignorePath) {
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
pathname = path.join(localFile, from);
|
|
1124
1127
|
}
|
|
1125
|
-
pathname =
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1128
|
+
else if (!(pathname = this.findSourceRoot(from)) || !Document.isPath(pathname)) {
|
|
1129
|
+
const asset = host.findAsset(from);
|
|
1130
|
+
if (!asset || asset.invalid) {
|
|
1131
|
+
continue;
|
|
1132
|
+
}
|
|
1133
|
+
pathname = asset.localUri;
|
|
1134
|
+
}
|
|
1135
|
+
if (pathname && Document.isPath(pathname)) {
|
|
1136
|
+
output = spliceString(output, a, b, quote + pathname + quote, REGEXP_IMPORTMODULE);
|
|
1131
1137
|
}
|
|
1132
|
-
pathname = asset.localUri;
|
|
1133
|
-
}
|
|
1134
|
-
if (pathname && Document.isPath(pathname)) {
|
|
1135
|
-
output = spliceString(output, a, b, quote + pathname + quote, REGEXP_IMPORTMODULE);
|
|
1136
1138
|
}
|
|
1137
1139
|
}
|
|
1138
1140
|
REGEXP_IMPORTMODULE.lastIndex = 0;
|
|
@@ -1234,21 +1236,35 @@ class ChromeDocument extends Document {
|
|
|
1234
1236
|
replaceContent(source, statement, mimeType) {
|
|
1235
1237
|
switch (mimeType) {
|
|
1236
1238
|
case "text/css": {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1239
|
+
let content = (typeof statement === 'string' ? statement : statement[0]).trim();
|
|
1240
|
+
const url = /^@import\s+(?:(url\()|"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(?!$)/i.exec(content);
|
|
1241
|
+
if (url) {
|
|
1242
|
+
if (!url[1]) {
|
|
1243
|
+
content = content.slice(url[0].length);
|
|
1244
|
+
}
|
|
1245
|
+
else if (!(content = splitEnclosing(content, 1)[2])) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
const items = splitEnclosing(content, /(?<=[\s)"'])(?:layer|supports)/gi);
|
|
1240
1249
|
let layer, supports;
|
|
1241
|
-
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1250
|
+
for (let i = 0; i < items.length; ++i) {
|
|
1251
|
+
const item = items[i];
|
|
1252
|
+
let match = /^(layer|supports)\((.+)\)$/i.exec(item);
|
|
1253
|
+
if (match) {
|
|
1254
|
+
if (match[1].toLowerCase() === 'layer') {
|
|
1255
|
+
layer = match[2].trim();
|
|
1256
|
+
}
|
|
1257
|
+
else {
|
|
1258
|
+
supports = match[2].trim();
|
|
1259
|
+
}
|
|
1260
|
+
items[i] = '';
|
|
1246
1261
|
}
|
|
1247
|
-
else {
|
|
1248
|
-
|
|
1262
|
+
else if (match = /^\s*layer(?:\s+|$)/i.exec(item)) {
|
|
1263
|
+
layer ??= '';
|
|
1264
|
+
items[i] = item.slice(match[0].length);
|
|
1249
1265
|
}
|
|
1250
1266
|
}
|
|
1251
|
-
const query =
|
|
1267
|
+
const query = items.join('').trim().replace(/\s*;+$/, '');
|
|
1252
1268
|
if (typeof layer === 'string' || supports || query) {
|
|
1253
1269
|
const newline = getNewline(source);
|
|
1254
1270
|
let result = supports ? `@supports (${normalizeSpace(supports)}) {` + newline : '';
|
|
@@ -1999,29 +2015,22 @@ class ChromeDocument extends Document {
|
|
|
1999
2015
|
else if (item.fallback !== undefined) {
|
|
2000
2016
|
data = item.fallback;
|
|
2001
2017
|
}
|
|
2002
|
-
else if (!item.query) {
|
|
2003
|
-
return null;
|
|
2004
|
-
}
|
|
2005
2018
|
}
|
|
2006
2019
|
if (data) {
|
|
2007
2020
|
if (isString(item.query)) {
|
|
2008
|
-
const
|
|
2021
|
+
const jp = item.query.at(0) === '$';
|
|
2009
2022
|
try {
|
|
2010
|
-
if (
|
|
2011
|
-
data =
|
|
2012
|
-
}
|
|
2013
|
-
else if (pkg === 'jsonpath') {
|
|
2014
|
-
data = require(pkg).query(data, item.query);
|
|
2023
|
+
if (jp) {
|
|
2024
|
+
data = JSONPath({ path: item.query, json: data });
|
|
2015
2025
|
}
|
|
2016
2026
|
else {
|
|
2017
|
-
|
|
2018
|
-
data = JSONPath({ path: item.query, json: data });
|
|
2027
|
+
data = require('jmespath').search(data, item.query);
|
|
2019
2028
|
}
|
|
2020
2029
|
}
|
|
2021
2030
|
catch (err) {
|
|
2022
2031
|
this.abort(item.source);
|
|
2023
|
-
if (
|
|
2024
|
-
this.checkPackage(err,
|
|
2032
|
+
if (!jp) {
|
|
2033
|
+
this.checkPackage(err, 'jmespath', ["Unable to filter results", item.source]);
|
|
2025
2034
|
}
|
|
2026
2035
|
}
|
|
2027
2036
|
}
|
|
@@ -2029,12 +2038,18 @@ class ChromeDocument extends Document {
|
|
|
2029
2038
|
coerceObject(data);
|
|
2030
2039
|
}
|
|
2031
2040
|
}
|
|
2032
|
-
|
|
2041
|
+
if (Array.isArray(data)) {
|
|
2042
|
+
return data;
|
|
2043
|
+
}
|
|
2044
|
+
if (typeof data === 'object') {
|
|
2045
|
+
return [data];
|
|
2046
|
+
}
|
|
2047
|
+
throw errorMessage(item.source, "Invalid value", Cloud.asString(data) || "Unknown");
|
|
2033
2048
|
};
|
|
2034
2049
|
const setElements = async (sourceSet) => {
|
|
2035
2050
|
const db = this.Db;
|
|
2036
2051
|
const cloud = host.Cloud;
|
|
2037
|
-
const batchMap =
|
|
2052
|
+
const batchMap = {};
|
|
2038
2053
|
const batchGroup = [];
|
|
2039
2054
|
for (const item of sourceSet) {
|
|
2040
2055
|
if (!item.element) {
|
|
@@ -2362,12 +2377,6 @@ class ChromeDocument extends Document {
|
|
|
2362
2377
|
}
|
|
2363
2378
|
switch (type) {
|
|
2364
2379
|
case 'mongodb':
|
|
2365
|
-
for (let j = 0; j < length; ++j) {
|
|
2366
|
-
const cmd = batch[j];
|
|
2367
|
-
if (cmd.cascade) {
|
|
2368
|
-
cmd.cacheObjectKey ||= cmd.cascade;
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
2380
|
break;
|
|
2372
2381
|
case 'redis':
|
|
2373
2382
|
for (let j = 0; j < length; ++j) {
|
|
@@ -2399,12 +2408,6 @@ class ChromeDocument extends Document {
|
|
|
2399
2408
|
search.schema = undefined;
|
|
2400
2409
|
}
|
|
2401
2410
|
}
|
|
2402
|
-
if (cmd.key) {
|
|
2403
|
-
const { cascade, query } = cmd;
|
|
2404
|
-
if (cascade || query) {
|
|
2405
|
-
cmd.cacheObjectKey ||= (cascade ? cascade : '') + '_' + (query ? Document.asString(query, true) : '');
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
2411
|
}
|
|
2409
2412
|
break;
|
|
2410
2413
|
default:
|
|
@@ -3037,10 +3040,15 @@ class ChromeDocument extends Document {
|
|
|
3037
3040
|
format && (hasValue(format, 'base64') || hasValue(format, 'woff') || hasValue(format, 'woff2')) ? true : false);
|
|
3038
3041
|
}
|
|
3039
3042
|
async processData(item, result, method, validate) {
|
|
3040
|
-
let callback;
|
|
3043
|
+
let callback = null;
|
|
3041
3044
|
if (typeof method === 'string') {
|
|
3042
3045
|
const template = this.findDataValue(method) || method;
|
|
3043
|
-
|
|
3046
|
+
if (this.hasEval('userconfig')) {
|
|
3047
|
+
callback = Document.parseFunction(template, { absolute: this.hasEval('absolute'), default: true });
|
|
3048
|
+
}
|
|
3049
|
+
else if (this.hasEval('function')) {
|
|
3050
|
+
callback = asFunction(template);
|
|
3051
|
+
}
|
|
3044
3052
|
}
|
|
3045
3053
|
else {
|
|
3046
3054
|
callback = method;
|
|
@@ -3139,7 +3147,15 @@ class ChromeDocument extends Document {
|
|
|
3139
3147
|
const isJs = type === 'js';
|
|
3140
3148
|
const imageSet = /(?:\b(?<!-)|(?<!-)-webkit-)image-set\(/gi;
|
|
3141
3149
|
const pattern = isJs ? /\b(?<!-)import\(/g : !isHtml ? /(?:\b(?<!-)url\(|@import\s+(["']))/gi : /(?:\b(?<!-)url\(|@import\s+(["'])|\b(?<!-)(href)\s*=)/gi;
|
|
3142
|
-
let length = source.length, modified = false, match;
|
|
3150
|
+
let length = source.length, modified = false, replaced, match;
|
|
3151
|
+
if (!isJs) {
|
|
3152
|
+
while (match = REGEXP_URLMODIFIER.exec(source)) {
|
|
3153
|
+
const placeholder = randomUUID();
|
|
3154
|
+
(replaced ||= {})[placeholder] = match[3];
|
|
3155
|
+
source = spliceMatch(source, match, `url(${match[1] + match[2] + match[1]} ${placeholder})`, REGEXP_URLMODIFIER);
|
|
3156
|
+
}
|
|
3157
|
+
REGEXP_URLMODIFIER.lastIndex = 0;
|
|
3158
|
+
}
|
|
3143
3159
|
while (match = imageSet.exec(source)) {
|
|
3144
3160
|
const startIndex = match.index + match[0].length;
|
|
3145
3161
|
const endIndex = findClosingIndex(source, startIndex, '(');
|
|
@@ -3183,39 +3199,40 @@ class ChromeDocument extends Document {
|
|
|
3183
3199
|
}
|
|
3184
3200
|
}
|
|
3185
3201
|
j = i + 1;
|
|
3186
|
-
continue;
|
|
3187
3202
|
}
|
|
3188
|
-
|
|
3189
|
-
quote
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
if (
|
|
3196
|
-
if (
|
|
3197
|
-
|
|
3203
|
+
else {
|
|
3204
|
+
if (!quote && (ch === '"' || ch === "'" || ch === '`' && isJs) && (isHref || !content.trim())) {
|
|
3205
|
+
quote = ch;
|
|
3206
|
+
}
|
|
3207
|
+
else if (isHref && (ch === '#' || !quote && isSpace(ch)) && content.trim()) {
|
|
3208
|
+
break pass;
|
|
3209
|
+
}
|
|
3210
|
+
else if (ch === ')') {
|
|
3211
|
+
if (isUrl) {
|
|
3212
|
+
if (quote && closed !== -1 || !quote && (isJs || source[i - 1] !== '\\')) {
|
|
3213
|
+
break;
|
|
3214
|
+
}
|
|
3215
|
+
j = i;
|
|
3198
3216
|
}
|
|
3199
|
-
j = i;
|
|
3200
3217
|
}
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3218
|
+
else if (j !== -1 && (ch === '\n' ||
|
|
3219
|
+
isText && (ch === ';' || ch === '{') ||
|
|
3220
|
+
isHref && (ch === '=' || ch === '>') ||
|
|
3221
|
+
isUrl && (ch === ';' ||
|
|
3222
|
+
!isJs && (!isHtml && (ch === ':' && !isJs || ch === '}') ||
|
|
3223
|
+
isHtml && (ch === '"' || ch === "'" || ch === ':' || ch === '>'))))) {
|
|
3224
|
+
if (closed !== -1) {
|
|
3225
|
+
i = closed;
|
|
3226
|
+
}
|
|
3227
|
+
else {
|
|
3228
|
+
i = j;
|
|
3229
|
+
content = content.slice(0, i);
|
|
3230
|
+
}
|
|
3231
|
+
break;
|
|
3210
3232
|
}
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
content = content.slice(0, i);
|
|
3233
|
+
if (closed === -1) {
|
|
3234
|
+
content += ch;
|
|
3214
3235
|
}
|
|
3215
|
-
break;
|
|
3216
|
-
}
|
|
3217
|
-
if (closed === -1) {
|
|
3218
|
-
content += ch;
|
|
3219
3236
|
}
|
|
3220
3237
|
}
|
|
3221
3238
|
const setOutputURL = (value, asset) => {
|
|
@@ -3394,6 +3411,9 @@ class ChromeDocument extends Document {
|
|
|
3394
3411
|
}
|
|
3395
3412
|
}
|
|
3396
3413
|
if (modified) {
|
|
3414
|
+
for (const placeholder in replaced) {
|
|
3415
|
+
source = source.replace(placeholder, replaced[placeholder]);
|
|
3416
|
+
}
|
|
3397
3417
|
if (related.length > 0) {
|
|
3398
3418
|
const previous = this.related.get(file);
|
|
3399
3419
|
if (previous) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-r/chrome",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Chrome document constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"@e-mc/core": "^0.14.6",
|
|
22
22
|
"@e-mc/document": "^0.14.6",
|
|
23
23
|
"@e-mc/types": "^0.14.6",
|
|
24
|
-
"image-size": "^2.0.2"
|
|
24
|
+
"image-size": "^2.0.2",
|
|
25
|
+
"jsonpath-plus": "^10.4.0"
|
|
25
26
|
}
|
|
26
27
|
}
|