@pi-r/chrome 0.2.2 → 0.5.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/index.js CHANGED
@@ -12,6 +12,8 @@ const transform_1 = require("@e-mc/document/transform");
12
12
  const Document = require('@e-mc/document');
13
13
  const CACHE_DBRESULT = new Map();
14
14
  const CACHE_LOCALFILE = new Map();
15
+ const CACHE_QUERY = new Map();
16
+ const CACHE_SELECTOR = new Map();
15
17
  const CACHE_DATASET = {};
16
18
  const CACHE_ATRULES = {};
17
19
  let CACHE_TOTAL = 0;
@@ -19,11 +21,11 @@ const REGEXP_SRCSETSIZE = /~\s*([\d.]+)\s*([wx])/i;
19
21
  const REGEXP_TEMPLATECONDITIONAL = /(\n\s+)?\{\{if\s+((?:[^}]|}(?!}))+?)\}\}(\s*)([\S\s]*?)(?:\s*\{\{else(?:\s+if\s+((?:[^}]|}(?!}))+?))?\}\}(\s*)([\S\s]*?)\s*)?\s*\{\{end\}\}/g;
20
22
  const REGEXP_TEMPLATECOMPARISON = /\s*\(\s*(?:(eq|ne|lt|le|gt|ge)\s+)?("[^"]+"|'[^']+'|[^\s)]+)(?:\s+("[^"]+"|'[^']+'|[^\s)]+))?\s*\)/g;
21
23
  const REGEXP_TEMPLATEMATCH = new RegExp(`^(?:(and|or|not)\\s+)?((?:${REGEXP_TEMPLATECOMPARISON.source})+)|(!|not\\s+)?([^\\s][\\S\\s]*)$`);
22
- const REGEXP_IMPORTMODULE = /(?:(?:^|[\n;]+)\s*import\s+(?:("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')|.+?from\s+("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(?:[ \t]+assert[ \t]+\{((?:"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+'|`(?:[^`]|(?<=\\)`)+`|{[^{]+{|{[^}]+}|}[^}]+}|(?![{}])[^"'`])+)\})?)|\bimport\(\s*("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')\s*(?:,\s*\{((?:"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+'|`(?:[^`]|(?<=\\)`)+`|{[^{]+{|{[^}]+}|}[^}]+}|(?![{}])[^"'`])+)\}\s*)?\))/g;
24
+ const REGEXP_IMPORTMODULE = /(?:(?:^|[\n;]+)\s*import\s+(?:("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')|.+?from\s+("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(?:[ \t]+assert[ \t]+\{((?:"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+'|`(?:[^`]|(?<=\\)`)+`|{[^{]*{|{[^}]*}|}[^}]*}|(?![{}])[^"'`])+)\})?)|\bimport\(\s*("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')\s*(?:,\s*\{((?:"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+'|`(?:[^`]|(?<=\\)`)+`|{[^{]*{|{[^}]*}|}[^}]*}|(?![{}])[^"'`])+)\}\s*)?\))/g;
23
25
  const REGEXP_BLOCKEXCLUDE = new RegExp(`(\\s*)<!--\\s*exclude\\s*:\\s*(?:start|end)\\s*-->` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi');
24
26
  const [PATTERN_STRING_SOME, PATTERN_STRING_MANY] = (function () {
25
- const pattern = '(?:\\s|' + dom_1.DomWriter.PATTERN_COMMENT + '|`[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}`)';
26
- return [pattern + '*', pattern + '+'];
27
+ const grouping = '(?:\\s|' + dom_1.DomWriter.PATTERN_COMMENT + '|`[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}`)';
28
+ return [grouping + '*', grouping + '+'];
27
29
  })();
28
30
  const REGEXP_COMMENT = new RegExp(dom_1.DomWriter.PATTERN_COMMENT, 'g');
29
31
  const REGEXP_CONTENT = new RegExp(`\\bcontent${PATTERN_STRING_SOME}:${PATTERN_STRING_SOME}(?:"[^"]*"|'[^']*')`, 'gi');
@@ -32,15 +34,27 @@ const REGEXP_VARIABLES = new RegExp(`(\\s*)(--[^\\s:]*)${PATTERN_STRING_SOME}:[^
32
34
  const REGEXP_FONTFACE = new RegExp(`(\\s*)@font-face${PATTERN_STRING_SOME}{([^}]+)}` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi');
33
35
  const REGEXP_FONTFAMILY = new RegExp(`font-family${PATTERN_STRING_SOME}:([^;}]+)`, 'i');
34
36
  const REGEXP_KEYFRAMES = new RegExp(`(\\s*)@keyframes${PATTERN_STRING_MANY}([^{]+){`, 'gi');
37
+ const REGEXP_PROPERTY = new RegExp(`(\\s*)@property${PATTERN_STRING_MANY}(--[^\\s]+)${PATTERN_STRING_SOME}{`, 'gi');
35
38
  const REGEXP_NTHCHILD = new RegExp(`\\(${PATTERN_STRING_SOME}([+-])?(?:(\\d*)[nN]|(0))${PATTERN_STRING_SOME}([+-])?${PATTERN_STRING_SOME}(\\d*)${PATTERN_STRING_SOME}\\)`, 'g');
36
39
  const REGEXP_VARIABLES_UNSAFE = new RegExp(`(\\s*)(--[^\\s:]*)\\s*:[^;}]*([;}])` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'g');
37
40
  const REGEXP_FONTFACE_UNSAFE = new RegExp(`(\\s*)@font-face\\s*{([^}]+)}` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi');
38
41
  const REGEXP_FONTFAMILY_UNSAFE = /font-family\s*:([^;}]+)/i;
39
42
  const REGEXP_KEYFRAMES_UNSAFE = /(\s*)@keyframes\s+([^{]+){/gi;
43
+ const REGEXP_PROPERTY_UNSAFE = /(\s*)@property\s+(--[^\s]+)\s*{/gi;
40
44
  const REGEXP_NTHCHILD_UNSAFE = /\(\s*([+-])?(?:(\d*)[nN]|(0))\s*([+-])?\s*(\d*)\s*\)/g;
45
+ const REGEXP_OBJECT_NAME = /([^[.\s]+)((?:\s*\[[^\]]+\]\s*)+)?\s*\.?\s*/g;
46
+ const REGEXP_OBJECT_SUBSCRIPT = /\[\s*(["'])?(.+?)\1\s*\]/g;
47
+ const REGEXP_TEMPLATE_LEADING = /\s*\{\{- \s*((?:[^}]|}(?!}))+?)\}\}/g;
48
+ const REGEXP_TEMPLATE_TRAILING = /\{\{((?:[^}]|}(?!}))+?)\s*? -\}\}\s*/g;
49
+ const REGEXP_URL = /(?:\b[Uu][Rr][Ll]\(|@import\s+(["'])|\b([Hh][Rr][Ee][Ff])\s*=)/g;
50
+ const REGEXP_URL_JS = /\bimport\(/g;
51
+ const REGEXP_URL_SVG = /(?:\b[Uu][Rr][Ll]\(|@import\s+(["'])|\b([Hh][Rr][Ee][Ff])\s*=)/g;
52
+ const REGEXP_IMAGESET = /(?:-webkit-)?image-set\(/gi;
53
+ const REGEXP_IMAGESET_URL = /(?:^|[^(])\s*("(\s*[^)][^"]*)"|'(\s*[^)][^"]*)')\s*(?:,|$|[^)][^,]*,?)/g;
54
+ const REGEXP_REPLACECSS = /^@import\s+(?:url\((?:[^)]|(?<=\\)\))+\)|"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(\s*layer(?:\(([^)]*)\)|\b))?(?:\s*supports\(((?:\([^(]+\(|\([^)]+\)|\)[^)]+\)|(?:(?!\))[^(])+|(?:(?!\()[^)])+)+)\))?(.*?);?$/;
41
55
  function removeNamespace(name, source, newline, comments) {
42
56
  if (source.indexOf('-' + name) !== -1) {
43
- const dataset = CACHE_DATASET[name] || (CACHE_DATASET[name] = [
57
+ const [a, b, c, d, e] = CACHE_DATASET[name] || (CACHE_DATASET[name] = [
44
58
  new RegExp(`(\\s*)<(script|style)(${dom_1.DomWriter.PATTERN_TAGOPEN}+)>[\\S\\s]*?<\\/\\2\\s*>` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi'),
45
59
  new RegExp(`(\\s*)<link(${dom_1.DomWriter.PATTERN_TAGOPEN}+)>` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi'),
46
60
  new RegExp(`\\s+data-${name}-[a-z-]+\\s*` + dom_1.DomWriter.PATTERN_ATTRVALUE, 'g'),
@@ -48,24 +62,26 @@ function removeNamespace(name, source, newline, comments) {
48
62
  new RegExp(`data-${name}-template\\s*` + dom_1.DomWriter.PATTERN_ATTRVALUE)
49
63
  ]);
50
64
  source = source
51
- .replace(dataset[0], (...capture) => dataset[3].test(capture[3]) || dataset[4].test(capture[3]) ? getNewlineString(capture[1], capture[7], newline) : capture[0])
52
- .replace(dataset[1], (...capture) => dataset[3].test(capture[2]) ? getNewlineString(capture[1], capture[6], newline) : capture[0])
53
- .replace(dataset[2], '');
65
+ .replace(a, (...capture) => d.test(capture[3]) || e.test(capture[3]) ? getNewlineString(capture[1], capture[7], newline) : capture[0])
66
+ .replace(b, (...capture) => d.test(capture[2]) ? getNewlineString(capture[1], capture[6], newline) : capture[0])
67
+ .replace(c, '');
54
68
  }
55
69
  return (0, types_1.isArray)(comments) ? source.replace(REGEXP_BLOCKEXCLUDE, (...capture) => getNewlineString(capture[1], capture[2], newline)) : source;
56
70
  }
57
71
  function getObjectValue(value, key) {
58
- const pattern = /([^[.\s]+)((?:\s*\[[^\]]+\]\s*)+)?\s*\.?\s*/g;
72
+ REGEXP_OBJECT_NAME.lastIndex = 0;
59
73
  let found, match;
60
- while (match = pattern.exec(key)) {
74
+ while (match = REGEXP_OBJECT_NAME.exec(key)) {
61
75
  if ((0, types_1.isObject)(value)) {
62
76
  value = value[match[1]];
63
- if (match[2]) {
64
- const subscript = /\[\s*(["'])?(.+?)\1\s*\]/g;
77
+ const name = match[2];
78
+ if (name) {
79
+ REGEXP_OBJECT_SUBSCRIPT.lastIndex = 0;
65
80
  let index;
66
- while (index = subscript.exec(match[2])) {
67
- const attr = index[1] ? index[2] : index[2].trim();
68
- if (index[1] && (0, types_1.isObject)(value) || /^\d+$/.test(attr) && (typeof value === 'string' || (0, types_1.isObject)(value))) {
81
+ while (index = REGEXP_OBJECT_SUBSCRIPT.exec(name)) {
82
+ const quote = index[1];
83
+ const attr = quote ? index[2] : index[2].trim();
84
+ if (quote && (0, types_1.isObject)(value) || /^\d+$/.test(attr) && (typeof value === 'string' || (0, types_1.isObject)(value))) {
69
85
  value = value[attr];
70
86
  }
71
87
  else {
@@ -83,14 +99,14 @@ function getObjectValue(value, key) {
83
99
  return found ? value : null;
84
100
  }
85
101
  function trimTemplate(value) {
86
- const leading = /\s*\{\{- \s*((?:[^}]|}(?!}))+?)\}\}/g;
102
+ REGEXP_TEMPLATE_LEADING.lastIndex = 0;
87
103
  let match;
88
- while (match = leading.exec(value)) {
89
- value = replaceMatch(match, value, 1, leading);
104
+ while (match = REGEXP_TEMPLATE_LEADING.exec(value)) {
105
+ value = replaceMatch(match, value, 1, REGEXP_TEMPLATE_LEADING);
90
106
  }
91
- const trailing = /\{\{((?:[^}]|}(?!}))+?)\s*? -\}\}\s*/g;
92
- while (match = trailing.exec(value)) {
93
- value = replaceMatch(match, value, 1, trailing);
107
+ REGEXP_TEMPLATE_TRAILING.lastIndex = 0;
108
+ while (match = REGEXP_TEMPLATE_TRAILING.exec(value)) {
109
+ value = replaceMatch(match, value, 1, REGEXP_TEMPLATE_TRAILING);
94
110
  }
95
111
  return value;
96
112
  }
@@ -100,15 +116,18 @@ function trimQuote(value) {
100
116
  const last = value[value.length - 1];
101
117
  return first === last && (first === '"' || first === "'") ? value.substring(1, value.length - 1).trim() : value;
102
118
  }
103
- function findClosingIndex(source, lastIndex) {
104
- const pattern = /[{}]/g;
119
+ function findClosingIndex(source, lastIndex, char) {
120
+ const pattern = char === '{' ? /[{}]/g : /[()]/g;
105
121
  pattern.lastIndex = lastIndex;
106
122
  let opened = 1, closed = 0, endIndex = -1, trailing = '', match;
107
123
  while (match = pattern.exec(source)) {
108
- if (match[0] === '{') {
124
+ if (match[0] === char) {
109
125
  ++opened;
110
126
  }
111
127
  else if (++closed === opened) {
128
+ if (char === '(') {
129
+ return match.index;
130
+ }
112
131
  endIndex = match.index + 1;
113
132
  let ch;
114
133
  while (isSpace(ch = source[endIndex])) {
@@ -123,23 +142,9 @@ function findClosingIndex(source, lastIndex) {
123
142
  }
124
143
  return [endIndex, trailing];
125
144
  }
126
- function getPackageName(err, value) {
145
+ function getPackageName(err) {
127
146
  if (err instanceof Error && err.code === types_1.ERR_CODE.MODULE_NOT_FOUND) {
128
- switch (value) {
129
- case 'mongodb':
130
- case 'redis':
131
- return value;
132
- case 'mysql':
133
- return 'mysql2';
134
- case 'postgres':
135
- return 'pg';
136
- case 'oracle':
137
- return 'oracledb';
138
- case 'mssql':
139
- return 'tedious';
140
- default:
141
- return (0, util_1.getModuleName)(err);
142
- }
147
+ return (0, util_1.getModuleName)(err);
143
148
  }
144
149
  }
145
150
  function getCacheItem(map, key) {
@@ -182,9 +187,9 @@ function hasCondition(data, condition) {
182
187
  }
183
188
  let match = REGEXP_TEMPLATEMATCH.exec(condition.trim());
184
189
  if (match) {
185
- if (match[2]) {
190
+ const comparison = match[2];
191
+ if (comparison) {
186
192
  const join = match[1];
187
- const comparison = match[2];
188
193
  const items = [];
189
194
  while (match = REGEXP_TEMPLATECOMPARISON.exec(comparison)) {
190
195
  if (items.length && !isSpace(match[0][0])) {
@@ -269,37 +274,33 @@ function isTruthy(data, attr, falsey) {
269
274
  }
270
275
  function hasSameOrigin(value, ...other) {
271
276
  for (let url of other) {
272
- if (!url) {
273
- continue;
274
- }
275
- try {
276
- if (typeof value === 'string') {
277
- value = new URL(value);
278
- }
279
- if (typeof url === 'string') {
280
- url = new URL(url);
277
+ if (url) {
278
+ try {
279
+ if (typeof value === 'string') {
280
+ value = new URL(value);
281
+ }
282
+ if (typeof url === 'string') {
283
+ url = new URL(url);
284
+ }
285
+ if (value.origin === url.origin) {
286
+ return true;
287
+ }
281
288
  }
282
- if (value.origin === url.origin) {
283
- return true;
289
+ catch {
284
290
  }
285
291
  }
286
- catch {
287
- }
288
292
  }
289
293
  return false;
290
294
  }
291
295
  function restoreSearchParams(value, prefix = '__sqd') {
292
- if (value) {
293
- if (value.indexOf(prefix) !== -1) {
294
- const params = new URLSearchParams(value);
295
- params.forEach((_, key) => key.startsWith(prefix) && params.delete(key));
296
- if (value = params.toString()) {
297
- return '?' + value;
298
- }
296
+ if (value?.indexOf(prefix) !== -1) {
297
+ const params = new URLSearchParams(value);
298
+ params.forEach((_, key) => key.startsWith(prefix) && params.delete(key));
299
+ if (value = params.toString()) {
300
+ return '?' + value;
299
301
  }
300
- return value;
301
302
  }
302
- return '';
303
+ return value || '';
303
304
  }
304
305
  function getBaseURLs(asset, baseUrl) {
305
306
  const result = [];
@@ -327,28 +328,25 @@ function getBaseURLs(asset, baseUrl) {
327
328
  }
328
329
  return result;
329
330
  }
330
- function createHash(host, file, bufferMap) {
331
- const hash = file.hash;
332
- if (hash) {
333
- try {
334
- const localUri = file.localUri;
335
- const buffer = localUri && bufferMap[localUri] || getBuffer(file);
336
- if (buffer) {
337
- const [algorithm, length] = (0, util_1.getHashData)(hash);
338
- let value;
339
- if (algorithm && (value = Document.asHash(buffer, { algorithm, encoding: file.encoding }))) {
340
- if (localUri) {
341
- bufferMap[localUri] = buffer;
342
- }
343
- host.rename(file, (0, util_1.appendSuffix)(file.filename, length ? value.substring(0, length) : value));
344
- return file.filename;
331
+ function createHash(host, file, hash, bufferMap) {
332
+ const { filename, localUri } = file;
333
+ try {
334
+ const buffer = localUri && bufferMap[localUri] || getBuffer(file, localUri);
335
+ if (buffer) {
336
+ const [algorithm, length] = (0, util_1.getHashData)(hash);
337
+ let value;
338
+ if (algorithm && (value = Document.asHash(buffer, { algorithm, encoding: file.encoding }))) {
339
+ if (localUri) {
340
+ bufferMap[localUri] = buffer;
345
341
  }
342
+ host.rename(file, (0, util_1.appendSuffix)(filename, length ? value.substring(0, length) : value));
343
+ return file.filename;
346
344
  }
347
- throw (0, types_1.errorMessage)('hash', 'Source not found', file.filename);
348
- }
349
- catch (err) {
350
- host.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, file.filename], err, 32 /* LOG_TYPE.FILE */);
351
345
  }
346
+ throw (0, types_1.errorMessage)('hash', 'Source not found', filename);
347
+ }
348
+ catch (err) {
349
+ host.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, filename], err, 32 /* LOG_TYPE.FILE */);
352
350
  }
353
351
  }
354
352
  function getSrcURL(parent, file) {
@@ -387,8 +385,29 @@ function transformURL(host, parent, type, source, importFile) {
387
385
  const baseHref = getBaseURLs(importFile || parent, this.baseUrl);
388
386
  const isHtml = type === 'html';
389
387
  const isJs = type === 'js';
390
- const pattern = isJs ? /\bimport\(/g : type === 'svg' ? /(?:\b[Uu][Rr][Ll]\(|@import\s+(["'])|\b([Hh][Rr][Ee][Ff])\s*=)/g : /\b[Uu][Rr][Ll]\(|@import\s+(["'])/g;
388
+ const pattern = isJs ? REGEXP_URL_JS : type === 'svg' ? REGEXP_URL_SVG : REGEXP_URL;
389
+ pattern.lastIndex = 0;
390
+ REGEXP_IMAGESET.lastIndex = 0;
391
391
  let length = source.length, modified, match;
392
+ while (match = REGEXP_IMAGESET.exec(source)) {
393
+ const startIndex = match.index + match[0].length;
394
+ const endIndex = findClosingIndex(source, startIndex, '(');
395
+ if (endIndex === -1) {
396
+ continue;
397
+ }
398
+ REGEXP_IMAGESET_URL.lastIndex = 0;
399
+ const original = source.substring(startIndex, endIndex);
400
+ let content = original, url;
401
+ while (url = REGEXP_IMAGESET_URL.exec(original)) {
402
+ const quote = url[2] ? '"' : "'";
403
+ content = content.replace(url[1], `url(${quote + (url[2] || url[3]).trim() + quote})`);
404
+ modified = true;
405
+ }
406
+ if (modified) {
407
+ source = spliceString(source, startIndex, REGEXP_IMAGESET.lastIndex = endIndex, content);
408
+ modified = false;
409
+ }
410
+ }
392
411
  while (match = pattern.exec(source)) {
393
412
  const isText = !!match[1];
394
413
  const isHref = !!match[2];
@@ -668,7 +687,7 @@ function transformOptions(file, mimeType, code, bundleContent) {
668
687
  const metadata = { userAgentData: this.userAgentData };
669
688
  switch (mimeType) {
670
689
  case 'text/html':
671
- metadata['__fromhtml__'] = true;
690
+ metadata.__fromhtml__ = true;
672
691
  case 'text/css':
673
692
  Object.assign(metadata, this.config);
674
693
  default:
@@ -745,7 +764,7 @@ function transformJs(host, file, output) {
745
764
  });
746
765
  }
747
766
  else {
748
- this.writeFail(['Unable to create element entry point', path.basename(chunkUri)], (0, types_1.errorMessage)('js', 'Element not found', chunkUri), 4 /* LOG_TYPE.PROCESS */);
767
+ this.writeFail(['Unable to create script entry point', path.basename(chunkUri)], (0, types_1.errorMessage)('js', 'Element not found', chunkUri), 4 /* LOG_TYPE.PROCESS */);
749
768
  }
750
769
  }
751
770
  }
@@ -767,19 +786,25 @@ function replaceCss(file) {
767
786
  map[id] = this.removeServerRoot(map[id]);
768
787
  }
769
788
  };
770
- if (file.inlineUrlMap) {
771
- sanitize(file.inlineUrlMap);
789
+ const { inlineUrlMap, inlineUrlCloudMap } = file;
790
+ if (inlineUrlMap) {
791
+ sanitize(inlineUrlMap);
772
792
  }
773
- if (file.inlineUrlCloudMap) {
774
- sanitize(file.inlineUrlCloudMap);
793
+ if (inlineUrlCloudMap) {
794
+ sanitize(inlineUrlCloudMap);
775
795
  }
776
796
  }
777
797
  function replaceHtml(source, { productionRelease, contentMap }, cssMap) {
778
- for (const data of [cssMap, contentMap]) {
798
+ const finalize = (value, data) => {
779
799
  for (const id in data) {
780
- source = source.replace(new RegExp((0, types_1.escapePattern)(id), 'g'), data[id]);
800
+ value = value.replace(new RegExp((0, types_1.escapePattern)(id), 'g'), data[id]);
781
801
  }
802
+ return value;
803
+ };
804
+ if (cssMap) {
805
+ source = finalize(source, cssMap);
782
806
  }
807
+ source = finalize(source, contentMap);
783
808
  return productionRelease ? this.removeServerRoot(source) : source;
784
809
  }
785
810
  function isWatched(file) {
@@ -858,11 +883,11 @@ const asString = Document.asString.bind(Document);
858
883
  const resolvePath = Document.resolvePath.bind(Document);
859
884
  const toPosix = Document.toPosix.bind(Document);
860
885
  const isDir = Document.isDir.bind(Document);
861
- const hasSourceMap = (metadata, value) => (0, types_1.isObject)(metadata) && metadata['__sourcemap__'] === value;
886
+ const getBuffer = (item, localUri) => item.sourceUTF8 || item.buffer || ((localUri || (localUri = item.localUri)) && isPath(localUri) ? fs.readFileSync(localUri, item.encoding) : null);
887
+ const hasSourceMap = (metadata, value) => (0, types_1.isObject)(metadata) && metadata.__sourcemap__ === value;
862
888
  const isBundled = (value, main) => typeof value === 'number' && (value > 0 || main && value === 0);
863
889
  const isFont = (value) => value === 'truetype' || value === 'opentype' || value === 'woff' || value === 'woff2';
864
890
  const isImage = (value) => typeof value === 'string' && value.startsWith('image/') && value !== 'image/svg+xml';
865
- const getBuffer = (item) => item.sourceUTF8 || item.buffer || (item.localUri && isPath(item.localUri) ? fs.readFileSync(item.localUri, item.encoding) : null);
866
891
  const isRemoved = (item) => item.exclude === true || isBundled(item.bundleIndex);
867
892
  const isUnedited = (item) => !item.attributes && !item.inlineContent && !item.srcSet && !item.element.dynamic && item.element.textContent === undefined && (!item.uri && !isBundled(item.bundleIndex, true) || (0, util_1.hasValue)(item.format, 'crossorigin'));
868
893
  const isIgnored = (item, exists) => item.invalid || (0, types_1.ignoreFlag)(item.flags) || !exists && (0, types_1.existsFlag)(item.flags);
@@ -888,6 +913,7 @@ class ChromeDocument extends Document {
888
913
  useOriginalHtmlPage: undefined,
889
914
  useUnsafeHtmlReplace: undefined,
890
915
  useUnsafeCssReplace: undefined,
916
+ useSessionCache: undefined,
891
917
  stripCommentsAndCDATA: undefined,
892
918
  normalizeHtmlOutput: undefined,
893
919
  escapeReservedCharacters: undefined,
@@ -910,7 +936,8 @@ class ChromeDocument extends Document {
910
936
  this._elements = null;
911
937
  this._idMap = Object.create(null);
912
938
  this._editing = [];
913
- this._selectorMap = {};
939
+ this._queryMap = new Map();
940
+ this._selectorMap = new Map();
914
941
  }
915
942
  static async purgeMemory(percent = 1, limit = 0, parent) {
916
943
  if (typeof limit === 'boolean') {
@@ -918,14 +945,14 @@ class ChromeDocument extends Document {
918
945
  limit = 0;
919
946
  }
920
947
  let result = 0;
921
- if (limit === 0 || CACHE_TOTAL >= limit) {
948
+ if ((limit === 0 || CACHE_TOTAL >= limit) && percent > 0) {
922
949
  if (percent >= 1) {
923
950
  result += CACHE_DBRESULT.size + CACHE_LOCALFILE.size;
924
951
  CACHE_DBRESULT.clear();
925
952
  CACHE_LOCALFILE.clear();
926
953
  CACHE_TOTAL = 0;
927
954
  }
928
- else if (percent > 0) {
955
+ else {
929
956
  const stored = [];
930
957
  for (const map of [CACHE_DBRESULT, CACHE_LOCALFILE]) {
931
958
  for (const [key, value] of map) {
@@ -940,6 +967,8 @@ class ChromeDocument extends Document {
940
967
  }
941
968
  CACHE_TOTAL = stored.length - result;
942
969
  }
970
+ CACHE_QUERY.clear();
971
+ CACHE_SELECTOR.clear();
943
972
  }
944
973
  return result + (parent && result > 0 ? await super.purgeMemory(typeof parent === 'number' && parent > 0 ? parent : percent, limit, true) : 0);
945
974
  }
@@ -1050,34 +1079,35 @@ class ChromeDocument extends Document {
1050
1079
  }
1051
1080
  }
1052
1081
  let productionRelease = instance.productionRelease;
1053
- if ((0, types_1.isString)(productionRelease)) {
1054
- if (path.isAbsolute(productionRelease = path.normalize(productionRelease)) && isDir(productionRelease)) {
1055
- if (this.canWrite(productionRelease)) {
1056
- const serverRoot = ChromeDocument.INTERNAL_SERVERROOT;
1057
- const srcDir = path.join(this.baseDirectory, serverRoot);
1058
- if (isDir(srcDir)) {
1059
- const result = await Document.copyDir(srcDir, productionRelease, this.incremental !== 'staging');
1060
- const failed = result.failed.map(value => this.removeCwd(value));
1061
- for (const value of this.files) {
1062
- if (value.startsWith(serverRoot)) {
1063
- if (!failed.includes(value)) {
1064
- this.delete(value);
1065
- }
1066
- else {
1067
- instance.writeFail(["Unable to move file" /* ERR_MESSAGE.MOVE_FILE */, instance.moduleName], (0, types_1.errorMessage)('production', path.join(this.baseDirectory, value)), { fatal: true });
1068
- }
1082
+ if (!(0, types_1.isString)(productionRelease)) {
1083
+ return;
1084
+ }
1085
+ if (path.isAbsolute(productionRelease = path.normalize(productionRelease)) && isDir(productionRelease)) {
1086
+ if (this.canWrite(productionRelease)) {
1087
+ const serverRoot = ChromeDocument.INTERNAL_SERVERROOT;
1088
+ const srcDir = path.join(this.baseDirectory, serverRoot);
1089
+ if (isDir(srcDir)) {
1090
+ const result = await Document.copyDir(srcDir, productionRelease, this.incremental !== 'staging');
1091
+ const failed = result.failed.map(value => this.removeCwd(value));
1092
+ for (const value of this.files) {
1093
+ if (value.startsWith(serverRoot)) {
1094
+ if (!failed.includes(value)) {
1095
+ this.delete(value);
1096
+ }
1097
+ else {
1098
+ instance.writeFail(["Unable to move file" /* ERR_MESSAGE.MOVE_FILE */, instance.moduleName], (0, types_1.errorMessage)('production', path.join(this.baseDirectory, value)), { fatal: true });
1069
1099
  }
1070
1100
  }
1071
1101
  }
1072
1102
  }
1073
- else {
1074
- instance.writeFail(["Unable to write directory" /* ERR_MESSAGE.WRITE_DIRECTORY */, instance.moduleName], (0, types_1.errorMessage)('production', 'Access denied', productionRelease));
1075
- }
1076
1103
  }
1077
1104
  else {
1078
- instance.writeFail(["Unable to read directory" /* ERR_MESSAGE.READ_DIRECTORY */, instance.moduleName], (0, types_1.errorMessage)('production', 'Invalid directory', productionRelease), 32 /* LOG_TYPE.FILE */);
1105
+ instance.writeFail(["Unable to write directory" /* ERR_MESSAGE.WRITE_DIRECTORY */, instance.moduleName], (0, types_1.errorMessage)('production', 'Access denied', productionRelease));
1079
1106
  }
1080
1107
  }
1108
+ else {
1109
+ instance.writeFail(["Unable to read directory" /* ERR_MESSAGE.READ_DIRECTORY */, instance.moduleName], (0, types_1.errorMessage)('production', 'Invalid directory', productionRelease), 32 /* LOG_TYPE.FILE */);
1110
+ }
1081
1111
  }
1082
1112
  static sanitizeAssets(assets, exclusions = []) {
1083
1113
  assets.forEach(item => {
@@ -1158,8 +1188,9 @@ class ChromeDocument extends Document {
1158
1188
  }
1159
1189
  return 0;
1160
1190
  });
1191
+ let imports;
1161
1192
  if (config) {
1162
- const { useUnsafeReplace, baseUrl, productionRelease, productionIncremental, templateMap, userAgentData, imports, cache } = config;
1193
+ const { useUnsafeReplace, baseUrl, productionRelease, productionIncremental, templateMap, userAgentData, cache } = config;
1163
1194
  const target = this.config;
1164
1195
  for (const attr in config) {
1165
1196
  if (attr in target) {
@@ -1204,22 +1235,37 @@ class ChromeDocument extends Document {
1204
1235
  if ((0, types_1.isObject)(userAgentData)) {
1205
1236
  this.userAgentData = userAgentData;
1206
1237
  }
1207
- this.imports = (0, types_1.isPlainObject)(imports) ? { ...this.module.imports, ...imports } : this.module.imports;
1208
1238
  if ((0, types_1.isObject)(cache) && 'transform' in cache) {
1209
1239
  this.customize({ transform: cache.transform });
1210
1240
  }
1241
+ if (!(0, types_1.isPlainObject)(imports = config.imports)) {
1242
+ imports = undefined;
1243
+ }
1211
1244
  }
1212
1245
  super.init(assets, config);
1213
1246
  const mimeMap = this._mimeMap;
1214
- if (mimeMap && 'format' in mimeMap) {
1215
- const format = mimeMap.format;
1216
- if ((0, types_1.isObject)(format)) {
1217
- this.formatMap = 'pathname' in format || 'filename' in format || 'dictionary' in format ? { uuid: format } : format;
1247
+ if (mimeMap) {
1248
+ if ('imports' in mimeMap) {
1249
+ const imported = mimeMap.imports;
1250
+ if ((0, types_1.isPlainObject)(imported)) {
1251
+ imports = imports ? Object.assign(imported, imports) : imported;
1252
+ }
1253
+ delete mimeMap.imports;
1218
1254
  }
1219
- else {
1220
- this.formatMap = undefined;
1255
+ if ('format' in mimeMap) {
1256
+ const format = mimeMap.format;
1257
+ if ((0, types_1.isObject)(format)) {
1258
+ this.formatMap = 'pathname' in format || 'filename' in format || 'dictionary' in format ? { uuid: format } : format;
1259
+ }
1260
+ else {
1261
+ this.formatMap = undefined;
1262
+ }
1263
+ delete mimeMap.format;
1221
1264
  }
1222
1265
  }
1266
+ if (imports) {
1267
+ this.imports = imports;
1268
+ }
1223
1269
  for (const storage of cloud) {
1224
1270
  for (const { service, upload, download } of storage) {
1225
1271
  if (upload) {
@@ -1588,7 +1634,7 @@ class ChromeDocument extends Document {
1588
1634
  replaceContent(source, statement, mimeType) {
1589
1635
  switch (mimeType) {
1590
1636
  case 'text/css': {
1591
- const match = /^@import\s+(?:url\((?:[^)]|(?<=\\)\))+\)|"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(\s*layer(?:\(([^)]*)\)|\b))?(?:\s*supports\(((?:\([^(]+\(|\([^)]+\)|\)[^)]+\)|(?:(?!\))[^(])+|(?:(?!\()[^)])+)+)\))?(.*?);?$/.exec((typeof statement === 'string' ? statement : statement[0]).trim());
1637
+ const match = REGEXP_REPLACECSS.exec((typeof statement === 'string' ? statement : statement[0]).trim());
1592
1638
  if (match) {
1593
1639
  const layer = match[1];
1594
1640
  const supports = match[3]?.trim();
@@ -1643,8 +1689,9 @@ class ChromeDocument extends Document {
1643
1689
  this._cloudUrlMap = Object.create(null);
1644
1690
  this._cloudUploaded = new Set();
1645
1691
  this._cloudEndpoint = null;
1646
- if (this.htmlFile) {
1647
- const endpoint = instance.getStorage('upload', this.htmlFile.cloudStorage)?.upload?.endpoint;
1692
+ const htmlFile = this.htmlFile;
1693
+ if (htmlFile) {
1694
+ const endpoint = instance.getStorage('upload', htmlFile.cloudStorage)?.upload?.endpoint;
1648
1695
  if (endpoint) {
1649
1696
  this._cloudEndpoint = new RegExp((0, types_1.escapePattern)(toPosix(endpoint)) + '/', 'g');
1650
1697
  }
@@ -1822,9 +1869,7 @@ class ChromeDocument extends Document {
1822
1869
  }
1823
1870
  }
1824
1871
  search ?? (search = restoreSearchParams(asset.url?.search));
1825
- if (status) {
1826
- status = status.filter(item => item.type >= types_1.STATUS_TYPE.FATAL && item.type <= types_1.STATUS_TYPE.WARN);
1827
- }
1872
+ status && (status = status.filter(item => item.type >= types_1.STATUS_TYPE.FATAL && item.type <= types_1.STATUS_TYPE.WARN));
1828
1873
  watch.send(types_1.WATCH_EVENT.MODIFIED, {
1829
1874
  action: pathname && watch.hot && !watch.main ? 'hot' : '',
1830
1875
  type: asset.mimeType,
@@ -1924,12 +1969,12 @@ class ChromeDocument extends Document {
1924
1969
  }
1925
1970
  }
1926
1971
  if (productionRelease) {
1927
- const { imported, inlineUrl: inlineUrl, inlineUrlCloud: inlineUrlCloud } = item;
1972
+ const { inlineUrl, inlineUrlCloud, imported, hash } = item;
1928
1973
  if (inlineUrl || inlineUrlCloud) {
1929
- const filename = createHash(host, item, bufferMap);
1974
+ const filename = hash && createHash(host, item, hash, bufferMap);
1930
1975
  if (filename) {
1931
- for (const hash of this.assets) {
1932
- const url = inlineUrl ? hash.inlineUrlMap?.[inlineUrl] : hash.inlineUrlCloudMap?.[inlineUrlCloud];
1976
+ for (const asset of this.assets) {
1977
+ const url = inlineUrl ? asset.inlineUrlMap?.[inlineUrl] : asset.inlineUrlCloudMap?.[inlineUrlCloud];
1933
1978
  if (url) {
1934
1979
  const search = url.indexOf('?');
1935
1980
  const index = (search !== -1 ? url.substring(0, search) : url).lastIndexOf('/');
@@ -1942,17 +1987,17 @@ class ChromeDocument extends Document {
1942
1987
  result += url.substring(search);
1943
1988
  }
1944
1989
  if (inlineUrl) {
1945
- hash.inlineUrlMap[inlineUrl] = result;
1990
+ asset.inlineUrlMap[inlineUrl] = result;
1946
1991
  }
1947
1992
  else {
1948
- hash.inlineUrlCloudMap[inlineUrlCloud] = result;
1993
+ asset.inlineUrlCloudMap[inlineUrlCloud] = result;
1949
1994
  }
1950
1995
  }
1951
1996
  }
1952
1997
  }
1953
1998
  hashed.add(item);
1954
1999
  }
1955
- else if ((!item.editing || imported) && createHash(host, item, bufferMap)) {
2000
+ else if (hash && (!item.editing || imported) && createHash(host, item, hash, bufferMap)) {
1956
2001
  hashed.add(item);
1957
2002
  }
1958
2003
  }
@@ -1999,15 +2044,16 @@ class ChromeDocument extends Document {
1999
2044
  item.modified = true;
2000
2045
  }
2001
2046
  source = sanitizeSource(item, source);
2002
- if (item.format) {
2003
- const result = await this.transform('html', source, item.format, transformOptions.call(this, item, 'image/svg+xml'));
2047
+ const format = item.format;
2048
+ if (format) {
2049
+ const result = await this.transform('html', source, format, transformOptions.call(this, item, 'image/svg+xml'));
2004
2050
  if (result) {
2005
2051
  item.modified = true;
2006
2052
  source = result.code;
2007
2053
  }
2008
2054
  }
2009
2055
  item.sourceUTF8 = source;
2010
- if (productionRelease && !hashed.has(item) && createHash(host, item, bufferMap)) {
2056
+ if (productionRelease && item.hash && !hashed.has(item) && createHash(host, item, item.hash, bufferMap)) {
2011
2057
  hashed.add(item);
2012
2058
  }
2013
2059
  }
@@ -2110,11 +2156,12 @@ class ChromeDocument extends Document {
2110
2156
  await this.setElementAttributes(processing, domBase);
2111
2157
  await this.applyDataSource(processing, domBase);
2112
2158
  for (const item of this.assets) {
2113
- if (item.element && isRemoved(item) && !(0, types_1.ignoreFlag)(item.flags)) {
2114
- const domElement = new dom_1.HtmlElement(moduleName, item.element, item.attributes);
2159
+ const element = item.element;
2160
+ if (element && isRemoved(item) && !(0, types_1.ignoreFlag)(item.flags)) {
2161
+ const domElement = new dom_1.HtmlElement(moduleName, element, item.attributes);
2115
2162
  domElement.remove = true;
2116
2163
  if (!domBase.write(domElement)) {
2117
- this.writeFail('Unable to exclude HTML element', errorHtml(item.element), 4 /* LOG_TYPE.PROCESS */);
2164
+ this.writeFail('Unable to exclude HTML element', errorHtml(element), 4 /* LOG_TYPE.PROCESS */);
2118
2165
  }
2119
2166
  }
2120
2167
  }
@@ -2135,13 +2182,15 @@ class ChromeDocument extends Document {
2135
2182
  if ((0, types_1.isString)(config.stripCommentsAndCDATA)) {
2136
2183
  source = dom_1.DomWriter.getCommentsAndCDATA(source, config.stripCommentsAndCDATA, true, true);
2137
2184
  }
2138
- if (htmlFile.format) {
2139
- const result = await this.transform('html', source, htmlFile.format, {
2185
+ const format = htmlFile.format;
2186
+ if (format) {
2187
+ const { filename, uri, encoding, metadata } = htmlFile;
2188
+ const result = await this.transform('html', source, format, {
2140
2189
  pathname: path.dirname(localUri),
2141
- filename: htmlFile.filename,
2190
+ filename,
2142
2191
  mimeType: 'text/html',
2143
- metadata: Object.assign({ '__fromhtml__': true, ...this.config }, htmlFile.metadata),
2144
- cacheData: !productionRelease || this.productionIncremental ? { uri: htmlFile.uri, encoding: htmlFile.encoding } : undefined
2192
+ metadata: Object.assign({ '__fromhtml__': true, ...this.config }, metadata),
2193
+ cacheData: !productionRelease || this.productionIncremental ? { uri, encoding } : undefined
2145
2194
  });
2146
2195
  if (result) {
2147
2196
  source = result.code;
@@ -2175,12 +2224,12 @@ class ChromeDocument extends Document {
2175
2224
  const cloud = host.Cloud;
2176
2225
  const removeWatchReload = (item) => (0, types_1.isObject)(item.watch) && delete item.watch.reload;
2177
2226
  for (const item of this.assets) {
2178
- const element = item.element;
2227
+ const { element, inlineContent } = item;
2179
2228
  if (!element || element.removed || isRemoved(item) || isUnedited(item) || (0, types_1.ignoreFlag)(item.flags) && !(0, types_1.processFlag)(item.flags)) {
2180
2229
  continue;
2181
2230
  }
2182
2231
  const domElement = new dom_1.HtmlElement(moduleName, element, item.attributes);
2183
- if (item.inlineContent) {
2232
+ if (inlineContent) {
2184
2233
  let [innerXml, sourceMappingURL, inlineMap] = transform_1.SourceMap.removeSourceMappingURL(host.getUTF8String(item).trim());
2185
2234
  if (sourceMappingURL && !inlineMap && item.localUri) {
2186
2235
  let mapUri = path.resolve(sourceMappingURL = decodeURIComponent(sourceMappingURL));
@@ -2189,7 +2238,7 @@ class ChromeDocument extends Document {
2189
2238
  }
2190
2239
  host.deleteFile(mapUri);
2191
2240
  }
2192
- domElement.tagName = item.inlineContent;
2241
+ domElement.tagName = inlineContent;
2193
2242
  domElement.innerXml = innerXml;
2194
2243
  domElement.removeAttribute('src', 'href');
2195
2244
  }
@@ -2279,10 +2328,10 @@ class ChromeDocument extends Document {
2279
2328
  }
2280
2329
  }
2281
2330
  if (!domBase.write(domElement)) {
2282
- this.writeFail(item.inlineContent ? 'Inline tag replacement' : 'Element attribute replacement', errorHtml(element), { type: 4 /* LOG_TYPE.PROCESS */, startTime });
2331
+ this.writeFail(inlineContent ? 'Inline tag replacement' : 'Element attribute replacement', errorHtml(element), { type: 4 /* LOG_TYPE.PROCESS */, startTime });
2283
2332
  delete item.inlineUrlCloud;
2284
2333
  }
2285
- else if (item.inlineContent) {
2334
+ else if (inlineContent) {
2286
2335
  host.removeAsset(item);
2287
2336
  removeWatchReload(item);
2288
2337
  }
@@ -2309,7 +2358,7 @@ class ChromeDocument extends Document {
2309
2358
  };
2310
2359
  const errorCredential = (item, err) => {
2311
2360
  removeElement(item);
2312
- const pkg = getPackageName(err, item.source);
2361
+ const pkg = getPackageName(err);
2313
2362
  if (!(pkg && this.checkPackage(err, pkg))) {
2314
2363
  this.writeFail(["Invalid credentials" /* ERR_DB.CREDENTIALS */, item.source], err);
2315
2364
  }
@@ -2421,13 +2470,13 @@ class ChromeDocument extends Document {
2421
2470
  const length = batch.length;
2422
2471
  const current = batch[0];
2423
2472
  const type = current.source;
2424
- let result = new Array(length);
2473
+ let result = new Array(length), errors;
2425
2474
  switch (type) {
2426
2475
  case 'cloud':
2427
2476
  result = await cloud.getDatabaseBatchRows(batch, true, sessionKey).catch(err => {
2428
2477
  this.abort(type);
2429
2478
  if (err instanceof Error) {
2430
- cloud.addLog(this.aborted ? types_1.STATUS_TYPE.ERROR : types_1.STATUS_TYPE.WARN, err);
2479
+ cloud.addLog(this.aborted ? types_1.STATUS_TYPE.ERROR : types_1.STATUS_TYPE.WARN, errors = err);
2431
2480
  }
2432
2481
  return [];
2433
2482
  });
@@ -2593,9 +2642,7 @@ class ChromeDocument extends Document {
2593
2642
  }
2594
2643
  if (!getData) {
2595
2644
  const { settings, encoding, persist = true } = current;
2596
- if (!target) {
2597
- target = settings && this.settings.export?.[settings] || pathname;
2598
- }
2645
+ target || (target = settings && this.settings.export?.[settings] || pathname);
2599
2646
  if (typeof target === 'function') {
2600
2647
  getData = target;
2601
2648
  hint = target.name;
@@ -2683,7 +2730,7 @@ class ChromeDocument extends Document {
2683
2730
  search.schema = loadLocalFile.call(this, current, pathname, cacheData, cmd.encoding);
2684
2731
  }
2685
2732
  catch (err) {
2686
- this.writeFail(['Unable to parse document', path.basename(pathname)], err, { startTime });
2733
+ this.writeFail(['Unable to parse document', path.basename(pathname)], err instanceof Error ? errors = err : err, { startTime });
2687
2734
  search.schema = undefined;
2688
2735
  }
2689
2736
  }
@@ -2769,7 +2816,7 @@ class ChromeDocument extends Document {
2769
2816
  this.abort(type);
2770
2817
  }
2771
2818
  if (err) {
2772
- this.writeFail(["Unable to execute query" /* ERR_DB.EXEC_QUERY */, message || "Unknown" /* ERR_MESSAGE.UNKNOWN */], err, { type: 65536 /* LOG_TYPE.DB */, startTime });
2819
+ this.writeFail(["Unable to execute query" /* ERR_DB.EXEC_QUERY */, message || "Unknown" /* ERR_MESSAGE.UNKNOWN */], err instanceof Error ? errors = err : err, { type: 65536 /* LOG_TYPE.DB */, startTime });
2773
2820
  }
2774
2821
  return this.aborted;
2775
2822
  };
@@ -2778,7 +2825,7 @@ class ChromeDocument extends Document {
2778
2825
  }
2779
2826
  catch (err) {
2780
2827
  this.abort(type);
2781
- const pkg = getPackageName(err, type);
2828
+ const pkg = getPackageName(err);
2782
2829
  errorClient(current, pkg && this.checkPackage(err, pkg) ? null : err);
2783
2830
  }
2784
2831
  break;
@@ -2822,7 +2869,7 @@ class ChromeDocument extends Document {
2822
2869
  if (items.length && !item.transactionFail) {
2823
2870
  const { element, preRender } = item;
2824
2871
  const domElement = new dom_1.HtmlElement(moduleName, element);
2825
- let errors, value = '';
2872
+ let value = '';
2826
2873
  const checkValue = async (name) => {
2827
2874
  const data = await checkData.call(this, item, name, value, row => typeof row === 'string');
2828
2875
  if (data) {
@@ -2879,7 +2926,7 @@ class ChromeDocument extends Document {
2879
2926
  for (let j = 0, match; j < items.length; ++j) {
2880
2927
  const row = items[j];
2881
2928
  if ((0, types_1.isPlainObject)(row)) {
2882
- row['__index__'] ?? (row['__index__'] = j + 1);
2929
+ row.__index__ ?? (row.__index__ = j + 1);
2883
2930
  }
2884
2931
  let segment = template;
2885
2932
  while (match = REGEXP_TEMPLATECONDITIONAL.exec(segment)) {
@@ -2911,7 +2958,7 @@ class ChromeDocument extends Document {
2911
2958
  else {
2912
2959
  const pattern = /\$\{\s*([^\s}]+)\s*\}/g;
2913
2960
  while (match = pattern.exec(segment)) {
2914
- segment = replaceMatch(match, segment, match[1] === '__index__' && !(0, types_1.isObject)(row) ? (j + 1).toString() : valueAsString(getObjectValue(row, match[1]), ', '), pattern);
2961
+ segment = replaceMatch(match, segment, match[1] === "__index__" /* PROPERTIES.INDEX */ && !(0, types_1.isObject)(row) ? (j + 1).toString() : valueAsString(getObjectValue(row, match[1]), ', '), pattern);
2915
2962
  }
2916
2963
  }
2917
2964
  value += trimTemplate(segment);
@@ -3118,7 +3165,10 @@ class ChromeDocument extends Document {
3118
3165
  }
3119
3166
  else {
3120
3167
  if (!empty && item.type !== 'display' || item.transactionFail) {
3121
- const emptyResponse = (value, service = item.source) => errorDataSource(service + ' -> Empty', value || "Unknown" /* ERR_MESSAGE.UNKNOWN */);
3168
+ const emptyResponse = (value, service = item.source) => {
3169
+ value || (value = "Unknown" /* ERR_MESSAGE.UNKNOWN */);
3170
+ return errors instanceof Error ? (0, types_1.errorMessage)(service, value, errors.message) : errorDataSource(service + ' -> Empty', value);
3171
+ };
3122
3172
  switch (item.source) {
3123
3173
  case 'cloud': {
3124
3174
  const { service, table, id, query } = item;
@@ -3166,8 +3216,8 @@ class ChromeDocument extends Document {
3166
3216
  if (isIgnored(item, true)) {
3167
3217
  continue;
3168
3218
  }
3169
- if (!hashed.has(item)) {
3170
- createHash(host, item, bufferMap);
3219
+ if (item.hash && !hashed.has(item)) {
3220
+ createHash(host, item, item.hash, bufferMap);
3171
3221
  }
3172
3222
  switch (item.element?.tagName.toLowerCase()) {
3173
3223
  case 'style':
@@ -3208,12 +3258,13 @@ class ChromeDocument extends Document {
3208
3258
  }
3209
3259
  }
3210
3260
  }
3211
- removeUnusedStyles(source, { useUnsafeCssReplace, usedVariables, usedFontFace, usedKeyframes, unusedStyles, unusedMedia, unusedContainer, unusedSupports } = this.config) {
3261
+ removeUnusedStyles(source, { useUnsafeCssReplace, usedVariables, usedFontFace, usedKeyframes, unusedStyles, unusedMedia, unusedContainer, unusedSupports, useSessionCache } = this.config) {
3212
3262
  var _a;
3213
3263
  if (!usedVariables && !usedFontFace && !usedKeyframes && !unusedStyles && !unusedMedia && !unusedContainer && !unusedSupports) {
3214
3264
  return;
3215
3265
  }
3216
- const selectorMap = this._selectorMap;
3266
+ const queryMap = useSessionCache ? CACHE_QUERY : this._queryMap;
3267
+ const selectorMap = useSessionCache ? CACHE_SELECTOR : this._selectorMap;
3217
3268
  const replaceMap = [];
3218
3269
  const getStringSome = () => useUnsafeCssReplace ? '\\s*' : PATTERN_STRING_SOME;
3219
3270
  const getStringMany = () => useUnsafeCssReplace ? '\\s+' : PATTERN_STRING_MANY;
@@ -3310,17 +3361,17 @@ class ChromeDocument extends Document {
3310
3361
  return `[${capture[1]}]`;
3311
3362
  }
3312
3363
  });
3313
- for (let i = 0; i < items.length; ++i) {
3364
+ for (let i = 0, length = revised.length; i < length; ++i) {
3314
3365
  selector = selector.replace('`%' + i + '`', items[i]);
3315
3366
  }
3316
- return selector.replace(/[ ]+/g, getStringMany()) + getStringSome();
3367
+ return selector.replace(/ +/g, getStringMany()) + getStringSome();
3317
3368
  };
3318
3369
  const replaceUnunsed = (name, items) => {
3319
3370
  for (let value of items) {
3320
3371
  const key = name + '_' + (value = value.trim()) + (useUnsafeCssReplace ? '_1' : '');
3321
- let [pattern] = selectorMap[key] || [], selector = '', rule;
3372
+ let pattern = queryMap.get(key), rule;
3322
3373
  if (!pattern) {
3323
- let flags = 'gi', revised;
3374
+ let flags = 'gi', selector = '', revised;
3324
3375
  if (name === 'container') {
3325
3376
  for (let i = 0, length = value.length, casing = true; i < length; i++) {
3326
3377
  let ch = value[i];
@@ -3356,27 +3407,25 @@ class ChromeDocument extends Document {
3356
3407
  .replace(/\s*(\\[()])\s*/g, (...capture) => getStringSome() + capture[1] + getStringSome())
3357
3408
  .replace(/:\s+/g, getStringSome() + ':' + getStringSome())
3358
3409
  .replace(/\s+([<>/]|<=|>=|\\\*)\s+/g, (...capture) => getStringSome() + capture[1] + getStringSome())
3359
- .replace(/[ ]+/g, getStringMany());
3410
+ .replace(/ +/g, getStringMany());
3360
3411
  if (flags === 'g') {
3361
3412
  selector = selector.replace(/`([a-z][A-Z])`/g, (...capture) => `[${capture[1]}]`);
3362
3413
  }
3363
3414
  }
3364
3415
  pattern = new RegExp('(\\s*)@' + (flags === 'g' ? name.split('').map(ch => `[${ch + ch.toUpperCase()}]`).join('') : name) + getStringMany() + selector + getStringSome() + '{', flags);
3416
+ queryMap.set(key, pattern);
3365
3417
  }
3366
3418
  else {
3367
3419
  pattern.lastIndex = 0;
3368
3420
  }
3369
3421
  while (rule = pattern.exec(current)) {
3370
- const [endIndex, trailing] = findClosingIndex(current, getEndIndex(rule));
3422
+ const [endIndex, trailing] = findClosingIndex(current, getEndIndex(rule), '{');
3371
3423
  if (endIndex !== -1) {
3372
3424
  current = spliceSource(current, rule.index, endIndex, pattern, rule[1], trailing);
3373
3425
  (checkEmpty || (checkEmpty = {}))[name] = true;
3374
3426
  modified = true;
3375
3427
  }
3376
3428
  }
3377
- if (selector) {
3378
- selectorMap[key] = [pattern];
3379
- }
3380
3429
  }
3381
3430
  };
3382
3431
  if (!useUnsafeCssReplace) {
@@ -3415,41 +3464,110 @@ class ChromeDocument extends Document {
3415
3464
  replaceUnunsed('container', unusedContainer);
3416
3465
  }
3417
3466
  if (unusedStyles) {
3418
- for (const value of unusedStyles) {
3419
- const key = value + (useUnsafeCssReplace ? '_1' : '');
3420
- let [single, group] = selectorMap[key] || [], selector;
3421
- if (!single || !group) {
3422
- single = new RegExp(`(}|^)(${getStringSome()})(?<!@[^}]*)${selector = parseSelector(value)}\\{([^}]*)\\}` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'g');
3423
- group = new RegExp(`((?:}|^)[^{]*?)((?:,${getStringSome()}|(?<!@[^}]*))${selector})(,[^{]*)?\\{`, 'g');
3424
- }
3425
- else {
3426
- single.lastIndex = 0;
3427
- group.lastIndex = 0;
3428
- }
3429
- while ((match = single.exec(current)) && match[3].indexOf('{') === -1) {
3430
- current = spliceSource(current, match.index, getEndIndex(match), single, match[2], match[4], match[1] || '');
3431
- modified = true;
3432
- }
3433
- while (match = group.exec(current)) {
3434
- const opening = match.index + match[0].length;
3435
- const closing = current.indexOf('}', opening);
3436
- if (closing !== -1 && current.substring(opening, closing).indexOf('{') === -1) {
3437
- const middle = match[2][0] === ',';
3438
- const leading = middle ? match[1].trimEnd() : match[1];
3439
- const trailing = match[3];
3440
- const segment = trailing ? (!middle ? (!isSpace(leading[leading.length - 1]) ? ' ' : '') + trailing.substring(1).trimStart() : trailing).trimEnd() : '';
3441
- current = replaceMatch(match, current, leading + segment + ' {');
3442
- group.lastIndex = match.index;
3443
- modified = true;
3467
+ current = (function recurse(target, child) {
3468
+ let output = '', index = 0, pendingStart = 0, pendingEnd = 0, found = -1;
3469
+ while ((found = target.indexOf('{', index)) !== -1) {
3470
+ ++found;
3471
+ const closing = findClosingIndex(target, found, '{')[0];
3472
+ if (closing === -1) {
3473
+ break;
3474
+ }
3475
+ let header = target.substring(index, found), invalid = 0, content;
3476
+ for (const value of unusedStyles) {
3477
+ const key = value + (child ? '_1' : '') + (useUnsafeCssReplace ? '_2' : '');
3478
+ const pattern = selectorMap.get(key);
3479
+ let single, group;
3480
+ if (!pattern) {
3481
+ const selector = parseSelector(value) + (child ? `(?:${getStringSome()}&${getStringSome()})*` : '');
3482
+ single = new RegExp(`(^|;)(${getStringSome()})(?<!${child ? '&|' : ''}@[^};]*)${selector}\\{$`);
3483
+ group = new RegExp(`((?:^|;)[^{]*?${getStringSome()}(,${getStringSome()}|(?<!@[^};]*)))(${(child ? '(?:&\\s+|(?<!&))' : '') + selector})(,[^{]*)?\\{$`, 'g');
3484
+ selectorMap.set(key, [single, group]);
3485
+ }
3486
+ else {
3487
+ [single, group] = pattern;
3488
+ }
3489
+ if (match = single.exec(header)) {
3490
+ content = match[1] === ';' ? header.substring(0, match.index + 1) + match[2].replace(/[^\n]+$/, '') : undefined;
3491
+ invalid = 1;
3492
+ break;
3493
+ }
3494
+ let leading = -1, first = true;
3495
+ while (match = group.exec(header)) {
3496
+ const start = match.index + match[1].length;
3497
+ if (!child && first) {
3498
+ if (match[1].trimEnd().endsWith(';')) {
3499
+ leading = start;
3500
+ }
3501
+ first = false;
3502
+ }
3503
+ const sibling = match[2][0] === ',';
3504
+ const trailing = match[4];
3505
+ const offset = trailing && !sibling ? /^,\s*/.exec(trailing)[0].length : 1;
3506
+ header = header.substring(0, start - (sibling ? match[2].length : 0)) + header.substring(start + match[3].length + (trailing ? sibling ? 0 : offset : /\s$/.test(match[3]) ? -1 : 0));
3507
+ group.lastIndex = match.index;
3508
+ invalid = 2;
3509
+ }
3510
+ if (invalid) {
3511
+ group.lastIndex = 0;
3512
+ const empty = /(.)\s*{$/.exec(header);
3513
+ if (empty) {
3514
+ if (header.trim() === '{') {
3515
+ content = undefined;
3516
+ invalid = 1;
3517
+ break;
3518
+ }
3519
+ else if (leading !== -1 && empty[1] === ';') {
3520
+ content = target.substring(index, found).substring(0, leading).replace(/[^\n;]+$/, '');
3521
+ invalid = 1;
3522
+ break;
3523
+ }
3524
+ }
3525
+ }
3526
+ }
3527
+ if (invalid === 0 || invalid === 2) {
3528
+ const trailing = target.substring(found, closing);
3529
+ if (content = recurse(trailing, true)) {
3530
+ content = header + content;
3531
+ }
3532
+ else if (invalid === 2) {
3533
+ content = header + trailing;
3534
+ }
3535
+ }
3536
+ if (content) {
3537
+ if (pendingEnd) {
3538
+ output = target.substring(pendingStart, pendingEnd) + content;
3539
+ pendingEnd = 0;
3540
+ }
3541
+ else {
3542
+ output += content;
3543
+ }
3544
+ }
3545
+ else if (!invalid) {
3546
+ if (output) {
3547
+ output += target.substring(index, closing);
3548
+ }
3549
+ else {
3550
+ pendingEnd = closing;
3551
+ }
3552
+ }
3553
+ else if (pendingEnd) {
3554
+ output = target.substring(pendingStart, pendingEnd);
3555
+ pendingEnd = 0;
3444
3556
  }
3557
+ else {
3558
+ pendingStart = closing;
3559
+ }
3560
+ index = closing;
3445
3561
  }
3446
- if (selector) {
3447
- selectorMap[key] = [single, group];
3562
+ if (output) {
3563
+ modified = true;
3564
+ return output + target.substring(index);
3448
3565
  }
3449
- }
3566
+ return !child ? target : '';
3567
+ })(current, false);
3450
3568
  }
3451
3569
  if (usedVariables) {
3452
- const pattern = useUnsafeCssReplace ? REGEXP_VARIABLES_UNSAFE : REGEXP_VARIABLES;
3570
+ let pattern = useUnsafeCssReplace ? REGEXP_VARIABLES_UNSAFE : REGEXP_VARIABLES;
3453
3571
  while (match = pattern.exec(current)) {
3454
3572
  if (!usedVariables.includes(match[2])) {
3455
3573
  current = replaceMatch(match, current, match[3] === ';' ? getNewlineString(match[1], match[4]) : '', pattern);
@@ -3457,24 +3575,35 @@ class ChromeDocument extends Document {
3457
3575
  }
3458
3576
  }
3459
3577
  pattern.lastIndex = 0;
3578
+ pattern = useUnsafeCssReplace ? REGEXP_PROPERTY_UNSAFE : REGEXP_PROPERTY;
3579
+ while (match = pattern.exec(current)) {
3580
+ if (!usedVariables.includes(match[2])) {
3581
+ const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match), '{');
3582
+ if (endIndex !== -1) {
3583
+ current = spliceSource(current, match.index, endIndex, pattern, match[1], trailing);
3584
+ modified = true;
3585
+ }
3586
+ }
3587
+ }
3588
+ pattern.lastIndex = 0;
3460
3589
  }
3461
3590
  if (usedFontFace) {
3462
- const fontFace = useUnsafeCssReplace ? REGEXP_FONTFACE_UNSAFE : REGEXP_FONTFACE;
3591
+ const pattern = useUnsafeCssReplace ? REGEXP_FONTFACE_UNSAFE : REGEXP_FONTFACE;
3463
3592
  const fontFamily = useUnsafeCssReplace ? REGEXP_FONTFAMILY_UNSAFE : REGEXP_FONTFAMILY;
3464
- while (match = fontFace.exec(current)) {
3593
+ while (match = pattern.exec(current)) {
3465
3594
  const font = fontFamily.exec(match[0]);
3466
3595
  if (font && !usedFontFace.includes(font[1].trim().replace(/^(["'])([\S\s]+)\1$/, (...content) => content[2]))) {
3467
- current = spliceSource(current, match.index, getEndIndex(match), fontFace, match[1], match[3]);
3596
+ current = spliceSource(current, match.index, getEndIndex(match), pattern, match[1], match[3]);
3468
3597
  modified = true;
3469
3598
  }
3470
3599
  }
3471
- fontFace.lastIndex = 0;
3600
+ pattern.lastIndex = 0;
3472
3601
  }
3473
3602
  if (usedKeyframes) {
3474
3603
  const pattern = useUnsafeCssReplace ? REGEXP_KEYFRAMES_UNSAFE : REGEXP_KEYFRAMES;
3475
3604
  while (match = pattern.exec(current)) {
3476
3605
  if (!usedKeyframes.includes(match[2].trim())) {
3477
- const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match));
3606
+ const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match), '{');
3478
3607
  if (endIndex !== -1) {
3479
3608
  current = spliceSource(current, match.index, endIndex, pattern, match[1], trailing);
3480
3609
  modified = true;
@@ -3529,7 +3658,9 @@ class ChromeDocument extends Document {
3529
3658
  return this._editing;
3530
3659
  }
3531
3660
  set dataSource(value) {
3532
- this._dataSource = value;
3661
+ if (Array.isArray(value)) {
3662
+ this._dataSource = value;
3663
+ }
3533
3664
  }
3534
3665
  get dataSource() {
3535
3666
  const result = this._dataSource;
@@ -3552,7 +3683,7 @@ class ChromeDocument extends Document {
3552
3683
  return (_a = this.module).settings || (_a.settings = {});
3553
3684
  }
3554
3685
  }
3555
- ChromeDocument.INTERNAL_ASSIGNUUID = '__assign__';
3556
- ChromeDocument.INTERNAL_SERVERROOT = '__serverroot__';
3686
+ ChromeDocument.INTERNAL_ASSIGNUUID = "__assign__" /* PROPERTIES.ASSIGN */;
3687
+ ChromeDocument.INTERNAL_SERVERROOT = "__serverroot__" /* PROPERTIES.SERVERROOT */;
3557
3688
 
3558
3689
  module.exports = ChromeDocument;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/chrome",
3
- "version": "0.2.2",
3
+ "version": "0.5.0",
4
4
  "description": "Chrome document constructor for E-mc.",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
@@ -20,9 +20,9 @@
20
20
  "license": "MIT",
21
21
  "homepage": "https://github.com/anpham6/pi-r#readme",
22
22
  "dependencies": {
23
- "@e-mc/cloud": "^0.5.3",
24
- "@e-mc/core": "^0.5.3",
25
- "@e-mc/document": "^0.5.3",
26
- "@e-mc/types": "^0.5.3"
23
+ "@e-mc/cloud": "^0.7.0",
24
+ "@e-mc/core": "^0.7.0",
25
+ "@e-mc/document": "^0.7.0",
26
+ "@e-mc/types": "^0.7.0"
27
27
  }
28
28
  }
package/types/index.d.ts CHANGED
@@ -10,6 +10,13 @@ import type { IDomWriter, IXmlElement } from '@e-mc/document/parse/types';
10
10
 
11
11
  import type { ChromeAsset, CssRuleData, DataSource, DocumentOutput } from './squared';
12
12
 
13
+ export const enum PROPERTIES {
14
+ INDEX = '__index__',
15
+ FROM_HTML = '__fromhtml__',
16
+ ASSIGN = '__assign__',
17
+ SERVERROOT = '__serverroot__'
18
+ }
19
+
13
20
  interface DocumentDirectory extends IDocumentDirectory {
14
21
  template?: string;
15
22
  data?: string;
@@ -104,10 +111,11 @@ export interface IChromeDocument<T extends IFileManager<U>, U extends DocumentAs
104
111
  cloudObject(state: CloudScopeOrigin<T, U, V>, file: U): boolean;
105
112
  cloudUpload(state: CloudScopeOrigin<T, U, V>, file: U, url: string, active: boolean): Promise<boolean>;
106
113
  cloudFinalize(state: CloudScopeOrigin<T, U, V>): Promise<unknown[]>;
107
- get settings(): ChromeDocumentSettings;
108
114
  get editing(): U[];
115
+ set dataSource(value);
109
116
  get dataSource(): DataSource[];
110
117
  get elements(): XmlTagNode[];
118
+ get settings(): ChromeDocumentSettings;
111
119
  }
112
120
 
113
121
  export interface ChromeDocumentConstructor<T extends IFileManager<U>, U extends DocumentAsset = DocumentAsset> extends DocumentConstructor<T, U> {
@@ -29,6 +29,7 @@ export interface DocumentOutput {
29
29
  productionIncremental?: boolean;
30
30
  useOriginalHtmlPage?: boolean | string;
31
31
  useUnsafeReplace?: ArrayOf<"html" | "css"> | boolean;
32
+ useSessionCache?: boolean;
32
33
  stripCommentsAndCDATA?: boolean | string;
33
34
  normalizeHtmlOutput?: boolean | string;
34
35
  escapeReservedCharacters?: boolean;