@pi-r/chrome 0.3.0 → 0.6.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,38 +12,53 @@ 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;
20
+ const [PATTERN_STRING_SOME, PATTERN_STRING_MANY] = (function () {
21
+ 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}`)';
22
+ return [grouping + '*', grouping + '+'];
23
+ })();
24
+ const [REGEXP_NTHCHILD, REGEXP_NTHCHILD_UNSAFE] = (function () {
25
+ const parenthesis = '(?:,[^()]+(?=\\))|[^()]|\\([^()]*\\(+|\\([^()]*\\)|(?:\\)[^()]+)?\\)*?)+';
26
+ return [
27
+ new RegExp(`\\(${PATTERN_STRING_SOME}([+-])?(?:(\\d*)[nN]|(0))?${PATTERN_STRING_SOME}([+-])?${PATTERN_STRING_SOME}(\\d*)(?:${PATTERN_STRING_MANY}[oO][fF]${PATTERN_STRING_MANY}(${parenthesis})${PATTERN_STRING_SOME}\\)|${PATTERN_STRING_SOME}\\))`, 'g'),
28
+ new RegExp(`\\(\\s*([+-])?(?:(\\d*)[nN]|(0))?\\s*([+-])?\\s*(\\d*)(?:\\s+[oO][fF]\\s+(${parenthesis})\\s*\\)|\\s*\\))`, 'g')
29
+ ];
30
+ })();
18
31
  const REGEXP_SRCSETSIZE = /~\s*([\d.]+)\s*([wx])/i;
19
32
  const REGEXP_TEMPLATECONDITIONAL = /(\n\s+)?\{\{if\s+((?:[^}]|}(?!}))+?)\}\}(\s*)([\S\s]*?)(?:\s*\{\{else(?:\s+if\s+((?:[^}]|}(?!}))+?))?\}\}(\s*)([\S\s]*?)\s*)?\s*\{\{end\}\}/g;
20
- const REGEXP_TEMPLATECOMPARISON = /\s*\(\s*(?:(eq|ne|lt|le|gt|ge)\s+)?("[^"]+"|'[^']+'|[^\s)]+)(?:\s+("[^"]+"|'[^']+'|[^\s)]+))?\s*\)/g;
21
- 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;
33
+ const REGEXP_TEMPLATECOMPARISON = /\s*\(\s*(?:\b(eq|ne|lt|le|gt|ge)\s+)?("[^"]+"|'[^']+'|[^\s)]+)(?:\s+("[^"]+"|'[^']+'|[^\s)]+))?\s*\)/g;
34
+ const REGEXP_TEMPLATEMATCH = new RegExp(`^(?:\\b(and|or|not)\\s+)?((?:${REGEXP_TEMPLATECOMPARISON.source})+)|(!|not\\s+)?([^\\s][\\S\\s]*)$`);
35
+ const REGEXP_IMPORTMODULE = /(?:(?:^|[\n;]+)\s*import\s+(?:("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')|.+?from\s+("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(?:[ \t]+assert[ \t]+\{((?:"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+'|`(?:[^`]|(?<=\\)`)+`|{[^{]*{|{[^}]*}|}[^}]*}|[^"'`]+)+)\})?)|\bimport\(\s*("(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')\s*(?:,\s*\{((?:"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+'|`(?:[^`]|(?<=\\)`)+`|{[^{]*{|{[^}]*}|}[^}]*}|[^"'`]+)+)\}\s*)?\))/g;
23
36
  const REGEXP_BLOCKEXCLUDE = new RegExp(`(\\s*)<!--\\s*exclude\\s*:\\s*(?:start|end)\\s*-->` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi');
24
- 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
- })();
28
37
  const REGEXP_COMMENT = new RegExp(dom_1.DomWriter.PATTERN_COMMENT, 'g');
29
- const REGEXP_CONTENT = new RegExp(`\\bcontent${PATTERN_STRING_SOME}:${PATTERN_STRING_SOME}(?:"[^"]*"|'[^']*')`, 'gi');
38
+ const REGEXP_QUOTEDVALUE = new RegExp(`\\b(?:@import${PATTERN_STRING_MANY}|content${PATTERN_STRING_SOME}:${PATTERN_STRING_SOME})(?:"[^"]*"|'[^']*')`, 'gi');
30
39
  const REGEXP_STYLE = new RegExp(`(<style${dom_1.DomWriter.PATTERN_TAGOPEN}*>)([\\S\\s]*?)(<\\/style\\s*>)`, 'gi');
31
- const REGEXP_VARIABLES = new RegExp(`(\\s*)(--[^\\s:]*)${PATTERN_STRING_SOME}:[^;}]*([;}])` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'g');
40
+ const REGEXP_VARIABLES = new RegExp(`(?<!style\\()(\\s*)(--[^\\s:]*)${PATTERN_STRING_SOME}:[^;}]*([;}])` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'g');
32
41
  const REGEXP_FONTFACE = new RegExp(`(\\s*)@font-face${PATTERN_STRING_SOME}{([^}]+)}` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi');
33
- const REGEXP_FONTFAMILY = new RegExp(`font-family${PATTERN_STRING_SOME}:([^;}]+)`, 'i');
42
+ const REGEXP_FONTFAMILY = new RegExp(`\\bfont-family${PATTERN_STRING_SOME}:([^;}]+)`, 'i');
34
43
  const REGEXP_KEYFRAMES = new RegExp(`(\\s*)@keyframes${PATTERN_STRING_MANY}([^{]+){`, 'gi');
35
- const REGEXP_NTHCHILD = new RegExp(`\\(${PATTERN_STRING_SOME}([+-])?(?:(\\d*)[nN]|(0))${PATTERN_STRING_SOME}([+-])?${PATTERN_STRING_SOME}(\\d*)${PATTERN_STRING_SOME}\\)`, 'g');
36
- const REGEXP_VARIABLES_UNSAFE = new RegExp(`(\\s*)(--[^\\s:]*)\\s*:[^;}]*([;}])` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'g');
44
+ const REGEXP_PROPERTY = new RegExp(`(\\s*)@property${PATTERN_STRING_MANY}(--[^\\s]+)${PATTERN_STRING_SOME}{`, 'gi');
45
+ const REGEXP_VARIABLES_UNSAFE = new RegExp(`(?<!style\\()(\\s*)(--[^\\s:]*)\\s*:[^;}]*([;}])` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'g');
37
46
  const REGEXP_FONTFACE_UNSAFE = new RegExp(`(\\s*)@font-face\\s*{([^}]+)}` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi');
38
- const REGEXP_FONTFAMILY_UNSAFE = /font-family\s*:([^;}]+)/i;
47
+ const REGEXP_FONTFAMILY_UNSAFE = /\bfont-family\s*:([^;}]+)/i;
39
48
  const REGEXP_KEYFRAMES_UNSAFE = /(\s*)@keyframes\s+([^{]+){/gi;
40
- const REGEXP_NTHCHILD_UNSAFE = /\(\s*([+-])?(?:(\d*)[nN]|(0))\s*([+-])?\s*(\d*)\s*\)/g;
49
+ const REGEXP_PROPERTY_UNSAFE = /(\s*)@property\s+(--[^\s]+)\s*{/gi;
41
50
  const REGEXP_OBJECT_NAME = /([^[.\s]+)((?:\s*\[[^\]]+\]\s*)+)?\s*\.?\s*/g;
42
51
  const REGEXP_OBJECT_SUBSCRIPT = /\[\s*(["'])?(.+?)\1\s*\]/g;
43
52
  const REGEXP_TEMPLATE_LEADING = /\s*\{\{- \s*((?:[^}]|}(?!}))+?)\}\}/g;
44
53
  const REGEXP_TEMPLATE_TRAILING = /\{\{((?:[^}]|}(?!}))+?)\s*? -\}\}\s*/g;
54
+ const REGEXP_URL = /(?:\b[Uu][Rr][Ll]\(|@import\s+(["'])|\b([Hh][Rr][Ee][Ff])\s*=)/g;
55
+ const REGEXP_URL_JS = /\bimport\(/g;
56
+ const REGEXP_URL_SVG = /(?:\b[Uu][Rr][Ll]\(|@import\s+(["'])|\b([Hh][Rr][Ee][Ff])\s*=)/g;
57
+ const REGEXP_IMAGESET = /\b(?:-webkit-)?image-set\(/gi;
58
+ const REGEXP_IMAGESET_URL = /(?:^|[^(])\s*("(\s*[^)][^"]*)"|'(\s*[^)][^"]*)')\s*(?:,|$|[^)][^,]*,?)/g;
59
+ const REGEXP_REPLACECSS = /^@import\s+(?:url\((?:[^)]|(?<=\\)\))+\)|"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(\s*layer(?:\(([^)]*)\)|\b))?(?:\s*supports\(((?:\([^(]+\(|\([^)]+\)|\)[^)]+\)|(?:(?!\))[^(])+|(?:(?!\()[^)])+)+)\))?(.*?);?$/;
45
60
  function removeNamespace(name, source, newline, comments) {
46
- if (source.indexOf('-' + name) !== -1) {
61
+ if (source.includes('-' + name)) {
47
62
  const [a, b, c, d, e] = CACHE_DATASET[name] || (CACHE_DATASET[name] = [
48
63
  new RegExp(`(\\s*)<(script|style)(${dom_1.DomWriter.PATTERN_TAGOPEN}+)>[\\S\\s]*?<\\/\\2\\s*>` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi'),
49
64
  new RegExp(`(\\s*)<link(${dom_1.DomWriter.PATTERN_TAGOPEN}+)>` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'gi'),
@@ -106,15 +121,18 @@ function trimQuote(value) {
106
121
  const last = value[value.length - 1];
107
122
  return first === last && (first === '"' || first === "'") ? value.substring(1, value.length - 1).trim() : value;
108
123
  }
109
- function findClosingIndex(source, lastIndex) {
110
- const pattern = /[{}]/g;
124
+ function findClosingIndex(source, lastIndex, char) {
125
+ const pattern = char === '{' ? /[{}]/g : /[()]/g;
111
126
  pattern.lastIndex = lastIndex;
112
127
  let opened = 1, closed = 0, endIndex = -1, trailing = '', match;
113
128
  while (match = pattern.exec(source)) {
114
- if (match[0] === '{') {
129
+ if (match[0] === char) {
115
130
  ++opened;
116
131
  }
117
132
  else if (++closed === opened) {
133
+ if (char === '(') {
134
+ return match.index;
135
+ }
118
136
  endIndex = match.index + 1;
119
137
  let ch;
120
138
  while (isSpace(ch = source[endIndex])) {
@@ -261,27 +279,26 @@ function isTruthy(data, attr, falsey) {
261
279
  }
262
280
  function hasSameOrigin(value, ...other) {
263
281
  for (let url of other) {
264
- if (!url) {
265
- continue;
266
- }
267
- try {
268
- if (typeof value === 'string') {
269
- value = new URL(value);
270
- }
271
- if (typeof url === 'string') {
272
- url = new URL(url);
282
+ if (url) {
283
+ try {
284
+ if (typeof value === 'string') {
285
+ value = new URL(value);
286
+ }
287
+ if (typeof url === 'string') {
288
+ url = new URL(url);
289
+ }
290
+ if (value.origin === url.origin) {
291
+ return true;
292
+ }
273
293
  }
274
- if (value.origin === url.origin) {
275
- return true;
294
+ catch {
276
295
  }
277
296
  }
278
- catch {
279
- }
280
297
  }
281
298
  return false;
282
299
  }
283
300
  function restoreSearchParams(value, prefix = '__sqd') {
284
- if (value?.indexOf(prefix) !== -1) {
301
+ if (value?.includes(prefix)) {
285
302
  const params = new URLSearchParams(value);
286
303
  params.forEach((_, key) => key.startsWith(prefix) && params.delete(key));
287
304
  if (value = params.toString()) {
@@ -316,14 +333,10 @@ function getBaseURLs(asset, baseUrl) {
316
333
  }
317
334
  return result;
318
335
  }
319
- function createHash(host, file, bufferMap) {
320
- const hash = file.hash;
321
- if (!hash) {
322
- return;
323
- }
336
+ function createHash(host, file, hash, bufferMap) {
324
337
  const { filename, localUri } = file;
325
338
  try {
326
- const buffer = localUri && bufferMap[localUri] || getBuffer(file);
339
+ const buffer = localUri && bufferMap[localUri] || getBuffer(file, localUri);
327
340
  if (buffer) {
328
341
  const [algorithm, length] = (0, util_1.getHashData)(hash);
329
342
  let value;
@@ -377,8 +390,29 @@ function transformURL(host, parent, type, source, importFile) {
377
390
  const baseHref = getBaseURLs(importFile || parent, this.baseUrl);
378
391
  const isHtml = type === 'html';
379
392
  const isJs = type === 'js';
380
- 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;
393
+ const pattern = isJs ? REGEXP_URL_JS : type === 'svg' ? REGEXP_URL_SVG : REGEXP_URL;
394
+ pattern.lastIndex = 0;
395
+ REGEXP_IMAGESET.lastIndex = 0;
381
396
  let length = source.length, modified, match;
397
+ while (match = REGEXP_IMAGESET.exec(source)) {
398
+ const startIndex = match.index + match[0].length;
399
+ const endIndex = findClosingIndex(source, startIndex, '(');
400
+ if (endIndex === -1) {
401
+ continue;
402
+ }
403
+ REGEXP_IMAGESET_URL.lastIndex = 0;
404
+ const original = source.substring(startIndex, endIndex);
405
+ let content = original, url;
406
+ while (url = REGEXP_IMAGESET_URL.exec(original)) {
407
+ const quote = url[2] ? '"' : "'";
408
+ content = content.replace(url[1], `url(${quote + (url[2] || url[3]).trim() + quote})`);
409
+ modified = true;
410
+ }
411
+ if (modified) {
412
+ source = spliceString(source, startIndex, REGEXP_IMAGESET.lastIndex = endIndex, content);
413
+ modified = false;
414
+ }
415
+ }
382
416
  while (match = pattern.exec(source)) {
383
417
  const isText = !!match[1];
384
418
  const isHref = !!match[2];
@@ -484,10 +518,10 @@ function transformURL(host, parent, type, source, importFile) {
484
518
  related.push(asset);
485
519
  }
486
520
  if (!quote && !isHtml && !isJs) {
487
- if (value.indexOf('"') === -1) {
521
+ if (!value.includes('"')) {
488
522
  quote = '"';
489
523
  }
490
- else if (value.indexOf("'") === -1) {
524
+ else if (!value.includes("'")) {
491
525
  quote = "'";
492
526
  }
493
527
  }
@@ -735,7 +769,7 @@ function transformJs(host, file, output) {
735
769
  });
736
770
  }
737
771
  else {
738
- this.writeFail(['Unable to create element entry point', path.basename(chunkUri)], (0, types_1.errorMessage)('js', 'Element not found', chunkUri), 4 /* LOG_TYPE.PROCESS */);
772
+ this.writeFail(['Unable to create script entry point', path.basename(chunkUri)], (0, types_1.errorMessage)('js', 'Element not found', chunkUri), 4 /* LOG_TYPE.PROCESS */);
739
773
  }
740
774
  }
741
775
  }
@@ -766,11 +800,16 @@ function replaceCss(file) {
766
800
  }
767
801
  }
768
802
  function replaceHtml(source, { productionRelease, contentMap }, cssMap) {
769
- for (const data of [cssMap, contentMap]) {
803
+ const finalize = (value, data) => {
770
804
  for (const id in data) {
771
- source = source.replace(new RegExp((0, types_1.escapePattern)(id), 'g'), data[id]);
805
+ value = value.replace(new RegExp((0, types_1.escapePattern)(id), 'g'), data[id]);
772
806
  }
807
+ return value;
808
+ };
809
+ if (cssMap) {
810
+ source = finalize(source, cssMap);
773
811
  }
812
+ source = finalize(source, contentMap);
774
813
  return productionRelease ? this.removeServerRoot(source) : source;
775
814
  }
776
815
  function isWatched(file) {
@@ -839,10 +878,6 @@ async function checkData(item, name, result, validate) {
839
878
  }
840
879
  }
841
880
  }
842
- function getBuffer(item) {
843
- let localUri;
844
- return item.sourceUTF8 || item.buffer || ((localUri = item.localUri) && isPath(localUri) ? fs.readFileSync(localUri, item.encoding) : null);
845
- }
846
881
  const getNewlineString = dom_1.DomWriter.getNewlineString.bind(dom_1.DomWriter);
847
882
  const isSpace = dom_1.DomWriter.isSpace.bind(dom_1.DomWriter);
848
883
  const replaceMatch = dom_1.DomWriter.replaceMatch.bind(dom_1.DomWriter);
@@ -853,6 +888,7 @@ const asString = Document.asString.bind(Document);
853
888
  const resolvePath = Document.resolvePath.bind(Document);
854
889
  const toPosix = Document.toPosix.bind(Document);
855
890
  const isDir = Document.isDir.bind(Document);
891
+ const getBuffer = (item, localUri) => item.sourceUTF8 || item.buffer || ((localUri || (localUri = item.localUri)) && isPath(localUri) ? fs.readFileSync(localUri, item.encoding) : null);
856
892
  const hasSourceMap = (metadata, value) => (0, types_1.isObject)(metadata) && metadata.__sourcemap__ === value;
857
893
  const isBundled = (value, main) => typeof value === 'number' && (value > 0 || main && value === 0);
858
894
  const isFont = (value) => value === 'truetype' || value === 'opentype' || value === 'woff' || value === 'woff2';
@@ -882,6 +918,7 @@ class ChromeDocument extends Document {
882
918
  useOriginalHtmlPage: undefined,
883
919
  useUnsafeHtmlReplace: undefined,
884
920
  useUnsafeCssReplace: undefined,
921
+ useSessionCache: undefined,
885
922
  stripCommentsAndCDATA: undefined,
886
923
  normalizeHtmlOutput: undefined,
887
924
  escapeReservedCharacters: undefined,
@@ -904,7 +941,8 @@ class ChromeDocument extends Document {
904
941
  this._elements = null;
905
942
  this._idMap = Object.create(null);
906
943
  this._editing = [];
907
- this._selectorMap = {};
944
+ this._queryMap = new Map();
945
+ this._selectorMap = new Map();
908
946
  }
909
947
  static async purgeMemory(percent = 1, limit = 0, parent) {
910
948
  if (typeof limit === 'boolean') {
@@ -912,14 +950,14 @@ class ChromeDocument extends Document {
912
950
  limit = 0;
913
951
  }
914
952
  let result = 0;
915
- if (limit === 0 || CACHE_TOTAL >= limit) {
953
+ if ((limit === 0 || CACHE_TOTAL >= limit) && percent > 0) {
916
954
  if (percent >= 1) {
917
955
  result += CACHE_DBRESULT.size + CACHE_LOCALFILE.size;
918
956
  CACHE_DBRESULT.clear();
919
957
  CACHE_LOCALFILE.clear();
920
958
  CACHE_TOTAL = 0;
921
959
  }
922
- else if (percent > 0) {
960
+ else {
923
961
  const stored = [];
924
962
  for (const map of [CACHE_DBRESULT, CACHE_LOCALFILE]) {
925
963
  for (const [key, value] of map) {
@@ -934,6 +972,8 @@ class ChromeDocument extends Document {
934
972
  }
935
973
  CACHE_TOTAL = stored.length - result;
936
974
  }
975
+ CACHE_QUERY.clear();
976
+ CACHE_SELECTOR.clear();
937
977
  }
938
978
  return result + (parent && result > 0 ? await super.purgeMemory(typeof parent === 'number' && parent > 0 ? parent : percent, limit, true) : 0);
939
979
  }
@@ -1027,16 +1067,15 @@ class ChromeDocument extends Document {
1027
1067
  const items = new Set((asset.watch.assets || []));
1028
1068
  (function recurse(children) {
1029
1069
  for (const item of children) {
1030
- if (items.has(item)) {
1031
- continue;
1032
- }
1033
- if (isWatched.call(instance, item)) {
1034
- item.flags |= 8 /* ASSET_FLAG.WATCH */;
1035
- }
1036
- items.add(item);
1037
- const next = related.get(item);
1038
- if (next) {
1039
- recurse(next);
1070
+ if (!items.has(item)) {
1071
+ if (isWatched.call(instance, item)) {
1072
+ item.flags |= 8 /* ASSET_FLAG.WATCH */;
1073
+ }
1074
+ items.add(item);
1075
+ const next = related.get(item);
1076
+ if (next) {
1077
+ recurse(next);
1078
+ }
1040
1079
  }
1041
1080
  }
1042
1081
  })(includes);
@@ -1052,20 +1091,18 @@ class ChromeDocument extends Document {
1052
1091
  if (this.canWrite(productionRelease)) {
1053
1092
  const serverRoot = ChromeDocument.INTERNAL_SERVERROOT;
1054
1093
  const srcDir = path.join(this.baseDirectory, serverRoot);
1055
- if (!isDir(srcDir)) {
1056
- return;
1057
- }
1058
- const result = await Document.copyDir(srcDir, productionRelease, this.incremental !== 'staging');
1059
- const failed = result.failed.map(value => this.removeCwd(value));
1060
- for (const value of this.files) {
1061
- if (!value.startsWith(serverRoot)) {
1062
- continue;
1063
- }
1064
- if (!failed.includes(value)) {
1065
- this.delete(value);
1066
- }
1067
- else {
1068
- instance.writeFail(["Unable to move file" /* ERR_MESSAGE.MOVE_FILE */, instance.moduleName], (0, types_1.errorMessage)('production', path.join(this.baseDirectory, value)), { fatal: true });
1094
+ if (isDir(srcDir)) {
1095
+ const result = await Document.copyDir(srcDir, productionRelease, this.incremental !== 'staging');
1096
+ const failed = result.failed.map(value => this.removeCwd(value));
1097
+ for (const value of this.files) {
1098
+ if (value.startsWith(serverRoot)) {
1099
+ if (!failed.includes(value)) {
1100
+ this.delete(value);
1101
+ }
1102
+ else {
1103
+ instance.writeFail(["Unable to move file" /* ERR_MESSAGE.MOVE_FILE */, instance.moduleName], (0, types_1.errorMessage)('production', path.join(this.baseDirectory, value)), { fatal: true });
1104
+ }
1105
+ }
1069
1106
  }
1070
1107
  }
1071
1108
  }
@@ -1566,12 +1603,14 @@ class ChromeDocument extends Document {
1566
1603
  }
1567
1604
  for (const placeholder in importMap) {
1568
1605
  const items = importMap[placeholder];
1606
+ let found;
1569
1607
  for (let i = 0, length = items.length; i < length; ++i) {
1570
1608
  const index = code.indexOf(placeholder);
1571
1609
  if (index !== -1) {
1572
1610
  const { uri, original, type, dynamic } = items[i];
1611
+ const hosted = type === 'css';
1573
1612
  let value;
1574
- if (type === 'css') {
1613
+ if (hosted) {
1575
1614
  const asset = this.host?.findAsset(uri);
1576
1615
  if (asset) {
1577
1616
  const [relativeUrl, sameDir] = getSrcURL.call(this, bundleMain || file, asset);
@@ -1583,11 +1622,12 @@ class ChromeDocument extends Document {
1583
1622
  else if (!(dynamic && file.imported !== false)) {
1584
1623
  value = this.findSourceRoot(uri);
1585
1624
  }
1586
- if (!value) {
1625
+ if (!value || !hosted && !Document.isPath(value)) {
1587
1626
  if (i < length - 1) {
1627
+ found || (found = value);
1588
1628
  continue;
1589
1629
  }
1590
- value = original;
1630
+ value = found || original;
1591
1631
  }
1592
1632
  code = spliceString(code, index, index + placeholder.length, value);
1593
1633
  modified = true;
@@ -1602,7 +1642,7 @@ class ChromeDocument extends Document {
1602
1642
  replaceContent(source, statement, mimeType) {
1603
1643
  switch (mimeType) {
1604
1644
  case 'text/css': {
1605
- const match = /^@import\s+(?:url\((?:[^)]|(?<=\\)\))+\)|"(?:[^"]|(?<=\\)")+"|'(?:[^']|(?<=\\)')+')(\s*layer(?:\(([^)]*)\)|\b))?(?:\s*supports\(((?:\([^(]+\(|\([^)]+\)|\)[^)]+\)|(?:(?!\))[^(])+|(?:(?!\()[^)])+)+)\))?(.*?);?$/.exec((typeof statement === 'string' ? statement : statement[0]).trim());
1645
+ const match = REGEXP_REPLACECSS.exec((typeof statement === 'string' ? statement : statement[0]).trim());
1606
1646
  if (match) {
1607
1647
  const layer = match[1];
1608
1648
  const supports = match[3]?.trim();
@@ -1671,7 +1711,7 @@ class ChromeDocument extends Document {
1671
1711
  }
1672
1712
  return this.editing.includes(file);
1673
1713
  }
1674
- cloudUpload({ host }, file, url, active) {
1714
+ async cloudUpload({ host }, file, url, active) {
1675
1715
  if (active) {
1676
1716
  const endpoint = this._cloudEndpoint;
1677
1717
  const inlineUrlCloud = file.inlineUrlCloud;
@@ -1683,7 +1723,7 @@ class ChromeDocument extends Document {
1683
1723
  for (const item of this.editing) {
1684
1724
  if (item.inlineUrlCloudMap?.[inlineUrlCloud]) {
1685
1725
  const source = host.getUTF8String(item);
1686
- const output = source.replace(pattern, endpoint && item !== htmlFile && cloudUrl.indexOf('/') !== -1 ? url : cloudUrl);
1726
+ const output = source.replace(pattern, endpoint && item !== htmlFile && cloudUrl.includes('/') ? url : cloudUrl);
1687
1727
  if (source !== output) {
1688
1728
  item.sourceUTF8 = output;
1689
1729
  item.modified = true;
@@ -1693,7 +1733,7 @@ class ChromeDocument extends Document {
1693
1733
  this._cloudUploaded.add(inlineUrlCloud);
1694
1734
  }
1695
1735
  }
1696
- return Promise.resolve(false);
1736
+ return false;
1697
1737
  }
1698
1738
  async cloudFinalize(state) {
1699
1739
  if (this.aborted) {
@@ -1801,7 +1841,7 @@ class ChromeDocument extends Document {
1801
1841
  }
1802
1842
  else if (current = watch.assets.find(item => (0, asset_1.isEqual)(item, asset))) {
1803
1843
  const { inlineUrlCloud: inlineUrlCloud, initialValue = {} } = current;
1804
- if (inlineUrlCloud && inlineUrlCloudMap[inlineUrlCloud] || path.join(initialValue.pathname || asset.pathname, initialValue.filename || asset.filename).indexOf(ChromeDocument.INTERNAL_ASSIGNUUID) !== -1) {
1844
+ if (inlineUrlCloud && inlineUrlCloudMap[inlineUrlCloud] || path.join(initialValue.pathname || asset.pathname, initialValue.filename || asset.filename).includes(ChromeDocument.INTERNAL_ASSIGNUUID)) {
1805
1845
  using.push(asset);
1806
1846
  }
1807
1847
  }
@@ -1890,7 +1930,7 @@ class ChromeDocument extends Document {
1890
1930
  for (const url of items) {
1891
1931
  const resolve = sameOrigin && !Document.isURL(url);
1892
1932
  const pathname = url.split(/[\\/]/).map(seg => (0, types_1.escapePattern)(seg)).join('[\\\\/]');
1893
- const pattern = new RegExp(`(,?\\s*)(${(resolve && url[0] !== '.' ? `(?:\\.\\.[\\\\/])*\\.\\.${pathname}|` : '') + pathname})(` + (url.indexOf('?') === -1 ? '(?:(?!,)(?:[^?]|$)[^,]*)|(?!\\?)[^,]*)' : '[^,]*)'), 'g');
1933
+ const pattern = new RegExp(`(,?\\s*)(${(resolve && !url.startsWith('.') ? `(?:\\.\\.[\\\\/])*\\.\\.${pathname}|` : '') + pathname})(` + (!url.includes('?') ? '(?:(?!,)(?:[^?]|$)[^,]*)|(?!\\?)[^,]*)' : '[^,]*)'), 'g');
1894
1934
  while (match = pattern.exec(current)) {
1895
1935
  const partial = match[2];
1896
1936
  if (!resolve || baseHref.some(baseUri => uri === resolvePath(partial, baseUri))) {
@@ -1937,12 +1977,12 @@ class ChromeDocument extends Document {
1937
1977
  }
1938
1978
  }
1939
1979
  if (productionRelease) {
1940
- const { imported, inlineUrl: inlineUrl, inlineUrlCloud: inlineUrlCloud } = item;
1980
+ const { inlineUrl, inlineUrlCloud, imported, hash } = item;
1941
1981
  if (inlineUrl || inlineUrlCloud) {
1942
- const filename = createHash(host, item, bufferMap);
1982
+ const filename = hash && createHash(host, item, hash, bufferMap);
1943
1983
  if (filename) {
1944
- for (const hash of this.assets) {
1945
- const url = inlineUrl ? hash.inlineUrlMap?.[inlineUrl] : hash.inlineUrlCloudMap?.[inlineUrlCloud];
1984
+ for (const asset of this.assets) {
1985
+ const url = inlineUrl ? asset.inlineUrlMap?.[inlineUrl] : asset.inlineUrlCloudMap?.[inlineUrlCloud];
1946
1986
  if (url) {
1947
1987
  const search = url.indexOf('?');
1948
1988
  const index = (search !== -1 ? url.substring(0, search) : url).lastIndexOf('/');
@@ -1955,17 +1995,17 @@ class ChromeDocument extends Document {
1955
1995
  result += url.substring(search);
1956
1996
  }
1957
1997
  if (inlineUrl) {
1958
- hash.inlineUrlMap[inlineUrl] = result;
1998
+ asset.inlineUrlMap[inlineUrl] = result;
1959
1999
  }
1960
2000
  else {
1961
- hash.inlineUrlCloudMap[inlineUrlCloud] = result;
2001
+ asset.inlineUrlCloudMap[inlineUrlCloud] = result;
1962
2002
  }
1963
2003
  }
1964
2004
  }
1965
2005
  }
1966
2006
  hashed.add(item);
1967
2007
  }
1968
- else if ((!item.editing || imported) && createHash(host, item, bufferMap)) {
2008
+ else if (hash && (!item.editing || imported) && createHash(host, item, hash, bufferMap)) {
1969
2009
  hashed.add(item);
1970
2010
  }
1971
2011
  }
@@ -2021,7 +2061,7 @@ class ChromeDocument extends Document {
2021
2061
  }
2022
2062
  }
2023
2063
  item.sourceUTF8 = source;
2024
- if (productionRelease && !hashed.has(item) && createHash(host, item, bufferMap)) {
2064
+ if (productionRelease && item.hash && !hashed.has(item) && createHash(host, item, item.hash, bufferMap)) {
2025
2065
  hashed.add(item);
2026
2066
  }
2027
2067
  }
@@ -2347,7 +2387,7 @@ class ChromeDocument extends Document {
2347
2387
  }
2348
2388
  if (data) {
2349
2389
  if ((0, types_1.isString)(query) && item.source !== 'mongodb') {
2350
- const pkg = query[0] === '$' ? 'jsonpath' : 'jmespath';
2390
+ const pkg = query.startsWith('$') ? 'jsonpath' : 'jmespath';
2351
2391
  try {
2352
2392
  if (pkg === 'jsonpath') {
2353
2393
  data = require(pkg).query(data, query);
@@ -2422,7 +2462,7 @@ class ChromeDocument extends Document {
2422
2462
  for (const key in batchMap) {
2423
2463
  batchGroup.push(batchMap[key]);
2424
2464
  }
2425
- return this.allSettled(batchGroup.map(batch => {
2465
+ return this.allSettled(batchGroup.map(async (batch) => {
2426
2466
  return new Promise(async (resolve, reject) => {
2427
2467
  const errorRemove = (item, reason) => {
2428
2468
  removeElement(item);
@@ -2438,13 +2478,13 @@ class ChromeDocument extends Document {
2438
2478
  const length = batch.length;
2439
2479
  const current = batch[0];
2440
2480
  const type = current.source;
2441
- let result = new Array(length);
2481
+ let result = new Array(length), errors;
2442
2482
  switch (type) {
2443
2483
  case 'cloud':
2444
2484
  result = await cloud.getDatabaseBatchRows(batch, true, sessionKey).catch(err => {
2445
2485
  this.abort(type);
2446
2486
  if (err instanceof Error) {
2447
- cloud.addLog(this.aborted ? types_1.STATUS_TYPE.ERROR : types_1.STATUS_TYPE.WARN, err);
2487
+ cloud.addLog(this.aborted ? types_1.STATUS_TYPE.ERROR : types_1.STATUS_TYPE.WARN, errors = err);
2448
2488
  }
2449
2489
  return [];
2450
2490
  });
@@ -2610,9 +2650,7 @@ class ChromeDocument extends Document {
2610
2650
  }
2611
2651
  if (!getData) {
2612
2652
  const { settings, encoding, persist = true } = current;
2613
- if (!target) {
2614
- target = settings && this.settings.export?.[settings] || pathname;
2615
- }
2653
+ target || (target = settings && this.settings.export?.[settings] || pathname);
2616
2654
  if (typeof target === 'function') {
2617
2655
  getData = target;
2618
2656
  hint = target.name;
@@ -2700,7 +2738,7 @@ class ChromeDocument extends Document {
2700
2738
  search.schema = loadLocalFile.call(this, current, pathname, cacheData, cmd.encoding);
2701
2739
  }
2702
2740
  catch (err) {
2703
- this.writeFail(['Unable to parse document', path.basename(pathname)], err, { startTime });
2741
+ this.writeFail(['Unable to parse document', path.basename(pathname)], err instanceof Error ? errors = err : err, { startTime });
2704
2742
  search.schema = undefined;
2705
2743
  }
2706
2744
  }
@@ -2780,13 +2818,13 @@ class ChromeDocument extends Document {
2780
2818
  }
2781
2819
  }
2782
2820
  if (data.willAbort) {
2783
- this.abort();
2821
+ this.abort(undefined, err);
2784
2822
  }
2785
2823
  else if (aborting) {
2786
- this.abort(type);
2824
+ this.abort(type, err);
2787
2825
  }
2788
2826
  if (err) {
2789
- this.writeFail(["Unable to execute query" /* ERR_DB.EXEC_QUERY */, message || "Unknown" /* ERR_MESSAGE.UNKNOWN */], err, { type: 65536 /* LOG_TYPE.DB */, startTime });
2827
+ 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 });
2790
2828
  }
2791
2829
  return this.aborted;
2792
2830
  };
@@ -2839,7 +2877,7 @@ class ChromeDocument extends Document {
2839
2877
  if (items.length && !item.transactionFail) {
2840
2878
  const { element, preRender } = item;
2841
2879
  const domElement = new dom_1.HtmlElement(moduleName, element);
2842
- let errors, value = '';
2880
+ let value = '';
2843
2881
  const checkValue = async (name) => {
2844
2882
  const data = await checkData.call(this, item, name, value, row => typeof row === 'string');
2845
2883
  if (data) {
@@ -2901,21 +2939,21 @@ class ChromeDocument extends Document {
2901
2939
  let segment = template;
2902
2940
  while (match = REGEXP_TEMPLATECONDITIONAL.exec(segment)) {
2903
2941
  const col = hasCondition(row, match[2]) ? 4 : hasCondition(row, match[5]) ? 7 : -1;
2904
- segment = replaceMatch(match, segment, match[col] ? (!match[1] || match[col - 1].indexOf('\n') !== -1 ? '' : match[1]) + match[col - 1] + match[col] : '', REGEXP_TEMPLATECONDITIONAL);
2942
+ segment = replaceMatch(match, segment, match[col] ? (!match[1] || match[col - 1].includes('\n') ? '' : match[1]) + match[col - 1] + match[col] : '', REGEXP_TEMPLATECONDITIONAL);
2905
2943
  }
2906
2944
  REGEXP_TEMPLATECONDITIONAL.lastIndex = 0;
2907
2945
  const literal = segment.trim();
2908
- if (literal[0] === '`' && literal[literal.length - 1] === '`') {
2946
+ if (literal.startsWith('`') && literal.endsWith('`')) {
2909
2947
  if (!this.hasEval('function')) {
2910
2948
  errors = (0, types_1.errorMessage)('eval', "Unsupported access" /* ERR_MESSAGE.UNSUPPORTED_ACCESS */, 'function');
2911
2949
  continue;
2912
2950
  }
2913
2951
  try {
2914
2952
  let content = new Function('return ' + literal + ';').call(row);
2915
- if (segment[0] !== '`') {
2953
+ if (!segment.startsWith('`')) {
2916
2954
  content = segment.substring(0, segment.indexOf('`')) + content;
2917
2955
  }
2918
- if (segment[segment.length - 1] !== '`') {
2956
+ if (!segment.endsWith('`')) {
2919
2957
  content += segment.substring(segment.lastIndexOf('`') + 1);
2920
2958
  }
2921
2959
  segment = content;
@@ -2928,7 +2966,7 @@ class ChromeDocument extends Document {
2928
2966
  else {
2929
2967
  const pattern = /\$\{\s*([^\s}]+)\s*\}/g;
2930
2968
  while (match = pattern.exec(segment)) {
2931
- segment = replaceMatch(match, segment, match[1] === '__index__' && !(0, types_1.isObject)(row) ? (j + 1).toString() : valueAsString(getObjectValue(row, match[1]), ', '), pattern);
2969
+ segment = replaceMatch(match, segment, match[1] === "__index__" /* PROPERTIES.INDEX */ && !(0, types_1.isObject)(row) ? (j + 1).toString() : valueAsString(getObjectValue(row, match[1]), ', '), pattern);
2932
2970
  }
2933
2971
  }
2934
2972
  value += trimTemplate(segment);
@@ -2975,7 +3013,7 @@ class ChromeDocument extends Document {
2975
3013
  for (const row of items) {
2976
3014
  for (let seg of segment) {
2977
3015
  seg = seg.trim();
2978
- if (seg[0] === ':' && (match = /^:join\(([\S\s]*)\)$/i.exec(seg))) {
3016
+ if (seg.startsWith(':') && (match = /^:join\(([\S\s]*)\)$/i.exec(seg))) {
2979
3017
  joinString = match[1];
2980
3018
  continue;
2981
3019
  }
@@ -3135,7 +3173,10 @@ class ChromeDocument extends Document {
3135
3173
  }
3136
3174
  else {
3137
3175
  if (!empty && item.type !== 'display' || item.transactionFail) {
3138
- const emptyResponse = (value, service = item.source) => errorDataSource(service + ' -> Empty', value || "Unknown" /* ERR_MESSAGE.UNKNOWN */);
3176
+ const emptyResponse = (value, service = item.source) => {
3177
+ value || (value = "Unknown" /* ERR_MESSAGE.UNKNOWN */);
3178
+ return errors instanceof Error ? (0, types_1.errorMessage)(service, value, errors.message) : errorDataSource(service + ' -> Empty', value);
3179
+ };
3139
3180
  switch (item.source) {
3140
3181
  case 'cloud': {
3141
3182
  const { service, table, id, query } = item;
@@ -3183,8 +3224,8 @@ class ChromeDocument extends Document {
3183
3224
  if (isIgnored(item, true)) {
3184
3225
  continue;
3185
3226
  }
3186
- if (!hashed.has(item)) {
3187
- createHash(host, item, bufferMap);
3227
+ if (item.hash && !hashed.has(item)) {
3228
+ createHash(host, item, item.hash, bufferMap);
3188
3229
  }
3189
3230
  switch (item.element?.tagName.toLowerCase()) {
3190
3231
  case 'style':
@@ -3225,12 +3266,13 @@ class ChromeDocument extends Document {
3225
3266
  }
3226
3267
  }
3227
3268
  }
3228
- removeUnusedStyles(source, { useUnsafeCssReplace, usedVariables, usedFontFace, usedKeyframes, unusedStyles, unusedMedia, unusedContainer, unusedSupports } = this.config) {
3269
+ removeUnusedStyles(source, { useUnsafeCssReplace, usedVariables, usedFontFace, usedKeyframes, unusedStyles, unusedMedia, unusedContainer, unusedSupports, useSessionCache } = this.config) {
3229
3270
  var _a;
3230
3271
  if (!usedVariables && !usedFontFace && !usedKeyframes && !unusedStyles && !unusedMedia && !unusedContainer && !unusedSupports) {
3231
3272
  return;
3232
3273
  }
3233
- const selectorMap = this._selectorMap;
3274
+ const queryMap = useSessionCache ? CACHE_QUERY : this._queryMap;
3275
+ const selectorMap = useSessionCache ? CACHE_SELECTOR : this._selectorMap;
3234
3276
  const replaceMap = [];
3235
3277
  const getStringSome = () => useUnsafeCssReplace ? '\\s*' : PATTERN_STRING_SOME;
3236
3278
  const getStringMany = () => useUnsafeCssReplace ? '\\s+' : PATTERN_STRING_MANY;
@@ -3238,7 +3280,7 @@ class ChromeDocument extends Document {
3238
3280
  const parseSelector = (value) => {
3239
3281
  const items = [];
3240
3282
  const revised = value.replace(useUnsafeCssReplace ? REGEXP_NTHCHILD_UNSAFE : REGEXP_NTHCHILD, (...capture) => {
3241
- return '`%' + (items.push('\\(' + getStringSome() + (capture[1] === '-' ? '\\x2d' : '\\x2b?') + (capture[2] || '[01]?') + (capture[3] === '0' ? !capture[1] && !capture[2] && !capture[4] && !capture[5] ? '[+-]?0[nN]?' : '0' : '[nN]') + getStringSome() + (capture[5] ? (capture[4] === '-' ? '\\x2d' : '\\x2b') + getStringSome() + capture[5] : `(?:[+-]${getStringSome()}0)?`) + getStringSome() + '\\)') - 1) + '`';
3283
+ return '`%' + (items.push('\\(' + getStringSome() + (capture[1] === '-' ? '\\x2d' : '\\x2b?') + (capture[2] || '[01]?') + (capture[3] === '0' ? !capture[1] && !capture[2] && !capture[4] && !capture[5] ? '[+-]?0[nN]?' : '0' : '[nN]') + getStringSome() + (capture[5] ? (capture[4] === '-' ? '\\x2d' : '\\x2b') + getStringSome() + capture[5] : `(?:[+-]${getStringSome()}0)?`) + (capture[6] ? getStringMany() + '[oO][fF]' + getStringMany() + capture[6].trim() : '') + getStringSome() + '\\)') - 1) + '`';
3242
3284
  });
3243
3285
  let selector = '';
3244
3286
  for (let i = 0, length = revised.length, casing = false, attr = false, quote = false; i < length; i++) {
@@ -3327,17 +3369,17 @@ class ChromeDocument extends Document {
3327
3369
  return `[${capture[1]}]`;
3328
3370
  }
3329
3371
  });
3330
- for (let i = 0; i < items.length; ++i) {
3372
+ for (let i = 0, length = revised.length; i < length; ++i) {
3331
3373
  selector = selector.replace('`%' + i + '`', items[i]);
3332
3374
  }
3333
- return selector.replace(/[ ]+/g, getStringMany()) + getStringSome();
3375
+ return selector.replace(/ +/g, getStringMany()) + getStringSome();
3334
3376
  };
3335
3377
  const replaceUnunsed = (name, items) => {
3336
3378
  for (let value of items) {
3337
3379
  const key = name + '_' + (value = value.trim()) + (useUnsafeCssReplace ? '_1' : '');
3338
- let [pattern] = selectorMap[key] || [], selector = '', rule;
3380
+ let pattern = queryMap.get(key), rule;
3339
3381
  if (!pattern) {
3340
- let flags = 'gi', revised;
3382
+ let flags = 'gi', selector = '', revised;
3341
3383
  if (name === 'container') {
3342
3384
  for (let i = 0, length = value.length, casing = true; i < length; i++) {
3343
3385
  let ch = value[i];
@@ -3373,27 +3415,25 @@ class ChromeDocument extends Document {
3373
3415
  .replace(/\s*(\\[()])\s*/g, (...capture) => getStringSome() + capture[1] + getStringSome())
3374
3416
  .replace(/:\s+/g, getStringSome() + ':' + getStringSome())
3375
3417
  .replace(/\s+([<>/]|<=|>=|\\\*)\s+/g, (...capture) => getStringSome() + capture[1] + getStringSome())
3376
- .replace(/[ ]+/g, getStringMany());
3418
+ .replace(/ +/g, getStringMany());
3377
3419
  if (flags === 'g') {
3378
3420
  selector = selector.replace(/`([a-z][A-Z])`/g, (...capture) => `[${capture[1]}]`);
3379
3421
  }
3380
3422
  }
3381
3423
  pattern = new RegExp('(\\s*)@' + (flags === 'g' ? name.split('').map(ch => `[${ch + ch.toUpperCase()}]`).join('') : name) + getStringMany() + selector + getStringSome() + '{', flags);
3424
+ queryMap.set(key, pattern);
3382
3425
  }
3383
3426
  else {
3384
3427
  pattern.lastIndex = 0;
3385
3428
  }
3386
3429
  while (rule = pattern.exec(current)) {
3387
- const [endIndex, trailing] = findClosingIndex(current, getEndIndex(rule));
3430
+ const [endIndex, trailing] = findClosingIndex(current, getEndIndex(rule), '{');
3388
3431
  if (endIndex !== -1) {
3389
3432
  current = spliceSource(current, rule.index, endIndex, pattern, rule[1], trailing);
3390
3433
  (checkEmpty || (checkEmpty = {}))[name] = true;
3391
3434
  modified = true;
3392
3435
  }
3393
3436
  }
3394
- if (selector) {
3395
- selectorMap[key] = [pattern];
3396
- }
3397
3437
  }
3398
3438
  };
3399
3439
  if (!useUnsafeCssReplace) {
@@ -3410,7 +3450,7 @@ class ChromeDocument extends Document {
3410
3450
  pattern.lastIndex = 0;
3411
3451
  };
3412
3452
  replaceBracket(REGEXP_COMMENT);
3413
- replaceBracket(REGEXP_CONTENT);
3453
+ replaceBracket(REGEXP_QUOTEDVALUE);
3414
3454
  const values = (0, util_1.splitEnclosing)(current, /\burl/gi);
3415
3455
  for (let i = 0, length = values.length; i < length; ++i) {
3416
3456
  const seg = values[i];
@@ -3432,41 +3472,110 @@ class ChromeDocument extends Document {
3432
3472
  replaceUnunsed('container', unusedContainer);
3433
3473
  }
3434
3474
  if (unusedStyles) {
3435
- for (const value of unusedStyles) {
3436
- const key = value + (useUnsafeCssReplace ? '_1' : '');
3437
- let [single, group] = selectorMap[key] || [], selector;
3438
- if (!single || !group) {
3439
- single = new RegExp(`(}|^)(${getStringSome()})(?<!@[^}]*)${selector = parseSelector(value)}\\{([^}]*)\\}` + dom_1.DomWriter.PATTERN_TRAILINGSPACE, 'g');
3440
- group = new RegExp(`((?:}|^)[^{]*?)((?:,${getStringSome()}|(?<!@[^}]*))${selector})(,[^{]*)?\\{`, 'g');
3441
- }
3442
- else {
3443
- single.lastIndex = 0;
3444
- group.lastIndex = 0;
3445
- }
3446
- while ((match = single.exec(current)) && match[3].indexOf('{') === -1) {
3447
- current = spliceSource(current, match.index, getEndIndex(match), single, match[2], match[4], match[1] || '');
3448
- modified = true;
3449
- }
3450
- while (match = group.exec(current)) {
3451
- const opening = match.index + match[0].length;
3452
- const closing = current.indexOf('}', opening);
3453
- if (closing !== -1 && current.substring(opening, closing).indexOf('{') === -1) {
3454
- const middle = match[2][0] === ',';
3455
- const leading = middle ? match[1].trimEnd() : match[1];
3456
- const trailing = match[3];
3457
- const segment = trailing ? (!middle ? (!isSpace(leading[leading.length - 1]) ? ' ' : '') + trailing.substring(1).trimStart() : trailing).trimEnd() : '';
3458
- current = replaceMatch(match, current, leading + segment + ' {');
3459
- group.lastIndex = match.index;
3460
- modified = true;
3475
+ current = (function recurse(target, child) {
3476
+ let output = '', index = 0, pendingStart = 0, pendingEnd = 0, found = -1;
3477
+ while ((found = target.indexOf('{', index)) !== -1) {
3478
+ ++found;
3479
+ const closing = findClosingIndex(target, found, '{')[0];
3480
+ if (closing === -1) {
3481
+ break;
3482
+ }
3483
+ let header = target.substring(index, found), invalid = 0, content;
3484
+ for (const value of unusedStyles) {
3485
+ const key = value + (child ? '_1' : '') + (useUnsafeCssReplace ? '_2' : '');
3486
+ const pattern = selectorMap.get(key);
3487
+ let single, group;
3488
+ if (!pattern) {
3489
+ const selector = parseSelector(value) + (child ? `(?:${getStringSome()}&${getStringSome()})*` : '');
3490
+ single = new RegExp(`(^|;)(${getStringSome()})(?<!${child ? '&|' : ''}@[^};]*)${selector}\\{$`);
3491
+ group = new RegExp(`((?:^|;)[^{]*?${getStringSome()}(,${getStringSome()}|(?<!@[^};]*)))(${(child ? '(?:&\\s+|(?<!&))' : '') + selector})(,[^{]*)?\\{$`, 'g');
3492
+ selectorMap.set(key, [single, group]);
3493
+ }
3494
+ else {
3495
+ [single, group] = pattern;
3496
+ }
3497
+ if (match = single.exec(header)) {
3498
+ content = match[1] === ';' ? header.substring(0, match.index + 1) + match[2].replace(/[^\n]+$/, '') : undefined;
3499
+ invalid = 1;
3500
+ break;
3501
+ }
3502
+ let leading = -1, first = true;
3503
+ while (match = group.exec(header)) {
3504
+ const start = match.index + match[1].length;
3505
+ if (!child && first) {
3506
+ if (match[1].trimEnd().endsWith(';')) {
3507
+ leading = start;
3508
+ }
3509
+ first = false;
3510
+ }
3511
+ const sibling = match[2].startsWith(',');
3512
+ const trailing = match[4];
3513
+ const offset = trailing && !sibling ? /^,\s*/.exec(trailing)[0].length : 1;
3514
+ 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));
3515
+ group.lastIndex = match.index;
3516
+ invalid = 2;
3517
+ }
3518
+ if (invalid) {
3519
+ group.lastIndex = 0;
3520
+ const empty = /(.)\s*{$/.exec(header);
3521
+ if (empty) {
3522
+ if (header.trim() === '{') {
3523
+ content = undefined;
3524
+ invalid = 1;
3525
+ break;
3526
+ }
3527
+ else if (leading !== -1 && empty[1] === ';') {
3528
+ content = target.substring(index, found).substring(0, leading).replace(/[^\n;]+$/, '');
3529
+ invalid = 1;
3530
+ break;
3531
+ }
3532
+ }
3533
+ }
3534
+ }
3535
+ if (invalid === 0 || invalid === 2) {
3536
+ const trailing = target.substring(found, closing);
3537
+ if (content = recurse(trailing, true)) {
3538
+ content = header + content;
3539
+ }
3540
+ else if (invalid === 2) {
3541
+ content = header + trailing;
3542
+ }
3543
+ }
3544
+ if (content) {
3545
+ if (pendingEnd) {
3546
+ output = target.substring(pendingStart, pendingEnd) + content;
3547
+ pendingEnd = 0;
3548
+ }
3549
+ else {
3550
+ output += content;
3551
+ }
3552
+ }
3553
+ else if (!invalid) {
3554
+ if (output) {
3555
+ output += target.substring(index, closing);
3556
+ }
3557
+ else {
3558
+ pendingEnd = closing;
3559
+ }
3560
+ }
3561
+ else if (pendingEnd) {
3562
+ output = target.substring(pendingStart, pendingEnd);
3563
+ pendingEnd = 0;
3564
+ }
3565
+ else {
3566
+ pendingStart = closing;
3461
3567
  }
3568
+ index = closing;
3462
3569
  }
3463
- if (selector) {
3464
- selectorMap[key] = [single, group];
3570
+ if (output) {
3571
+ modified = true;
3572
+ return output + target.substring(index);
3465
3573
  }
3466
- }
3574
+ return !child ? target : '';
3575
+ })(current, false);
3467
3576
  }
3468
3577
  if (usedVariables) {
3469
- const pattern = useUnsafeCssReplace ? REGEXP_VARIABLES_UNSAFE : REGEXP_VARIABLES;
3578
+ let pattern = useUnsafeCssReplace ? REGEXP_VARIABLES_UNSAFE : REGEXP_VARIABLES;
3470
3579
  while (match = pattern.exec(current)) {
3471
3580
  if (!usedVariables.includes(match[2])) {
3472
3581
  current = replaceMatch(match, current, match[3] === ';' ? getNewlineString(match[1], match[4]) : '', pattern);
@@ -3474,24 +3583,35 @@ class ChromeDocument extends Document {
3474
3583
  }
3475
3584
  }
3476
3585
  pattern.lastIndex = 0;
3586
+ pattern = useUnsafeCssReplace ? REGEXP_PROPERTY_UNSAFE : REGEXP_PROPERTY;
3587
+ while (match = pattern.exec(current)) {
3588
+ if (!usedVariables.includes(match[2])) {
3589
+ const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match), '{');
3590
+ if (endIndex !== -1) {
3591
+ current = spliceSource(current, match.index, endIndex, pattern, match[1], trailing);
3592
+ modified = true;
3593
+ }
3594
+ }
3595
+ }
3596
+ pattern.lastIndex = 0;
3477
3597
  }
3478
3598
  if (usedFontFace) {
3479
- const fontFace = useUnsafeCssReplace ? REGEXP_FONTFACE_UNSAFE : REGEXP_FONTFACE;
3599
+ const pattern = useUnsafeCssReplace ? REGEXP_FONTFACE_UNSAFE : REGEXP_FONTFACE;
3480
3600
  const fontFamily = useUnsafeCssReplace ? REGEXP_FONTFAMILY_UNSAFE : REGEXP_FONTFAMILY;
3481
- while (match = fontFace.exec(current)) {
3601
+ while (match = pattern.exec(current)) {
3482
3602
  const font = fontFamily.exec(match[0]);
3483
3603
  if (font && !usedFontFace.includes(font[1].trim().replace(/^(["'])([\S\s]+)\1$/, (...content) => content[2]))) {
3484
- current = spliceSource(current, match.index, getEndIndex(match), fontFace, match[1], match[3]);
3604
+ current = spliceSource(current, match.index, getEndIndex(match), pattern, match[1], match[3]);
3485
3605
  modified = true;
3486
3606
  }
3487
3607
  }
3488
- fontFace.lastIndex = 0;
3608
+ pattern.lastIndex = 0;
3489
3609
  }
3490
3610
  if (usedKeyframes) {
3491
3611
  const pattern = useUnsafeCssReplace ? REGEXP_KEYFRAMES_UNSAFE : REGEXP_KEYFRAMES;
3492
3612
  while (match = pattern.exec(current)) {
3493
3613
  if (!usedKeyframes.includes(match[2].trim())) {
3494
- const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match));
3614
+ const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match), '{');
3495
3615
  if (endIndex !== -1) {
3496
3616
  current = spliceSource(current, match.index, endIndex, pattern, match[1], trailing);
3497
3617
  modified = true;
@@ -3546,7 +3666,9 @@ class ChromeDocument extends Document {
3546
3666
  return this._editing;
3547
3667
  }
3548
3668
  set dataSource(value) {
3549
- this._dataSource = value;
3669
+ if (Array.isArray(value)) {
3670
+ this._dataSource = value;
3671
+ }
3550
3672
  }
3551
3673
  get dataSource() {
3552
3674
  const result = this._dataSource;
@@ -3569,7 +3691,7 @@ class ChromeDocument extends Document {
3569
3691
  return (_a = this.module).settings || (_a.settings = {});
3570
3692
  }
3571
3693
  }
3572
- ChromeDocument.INTERNAL_ASSIGNUUID = '__assign__';
3573
- ChromeDocument.INTERNAL_SERVERROOT = '__serverroot__';
3694
+ ChromeDocument.INTERNAL_ASSIGNUUID = "__assign__" /* PROPERTIES.ASSIGN */;
3695
+ ChromeDocument.INTERNAL_SERVERROOT = "__serverroot__" /* PROPERTIES.SERVERROOT */;
3574
3696
 
3575
3697
  module.exports = ChromeDocument;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/chrome",
3
- "version": "0.3.0",
3
+ "version": "0.6.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.6.0",
24
- "@e-mc/core": "^0.6.0",
25
- "@e-mc/document": "^0.6.0",
26
- "@e-mc/types": "^0.6.0"
23
+ "@e-mc/cloud": "^0.8.0",
24
+ "@e-mc/core": "^0.8.0",
25
+ "@e-mc/document": "^0.8.0",
26
+ "@e-mc/types": "^0.8.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;
@@ -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;