@jsenv/core 41.5.5 → 41.5.7

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.
@@ -6,7 +6,7 @@ import { jsenvPluginTranspilation, jsenvPluginJsModuleFallback } from "@jsenv/pl
6
6
  import { memoryUsage } from "node:process";
7
7
  import { readFileSync, existsSync, realpathSync, readdirSync, lstatSync, statSync } from "node:fs";
8
8
  import { pathToFileURL } from "node:url";
9
- import { generateSourcemapFileUrl, createMagicSource, composeTwoSourcemaps, generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
9
+ import { generateSourcemapFileUrl, createMagicSource, composeTwoSourcemaps, generateSourcemapDataUrl, SOURCEMAP, applyContentEditsOnSourcemap, composeSourcemaps } from "@jsenv/sourcemap";
10
10
  import { createPluginsController } from "@jsenv/server/src/plugins_controller.js";
11
11
  import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
12
12
  import { WebSocketResponse, pickContentType } from "@jsenv/server";
@@ -2823,6 +2823,84 @@ const createUrlInfoTransformer = ({
2823
2823
  return sourcemap;
2824
2824
  };
2825
2825
 
2826
+ // Sourcemap composition is deferred: each transformation pushes an element
2827
+ // here and "urlInfo.sourcemap" becomes a lazy view resolving the whole
2828
+ // pending chain on first read (with caching, invalidated by a new push or
2829
+ // an assignment). Any reader at any point sees a map matching the current
2830
+ // content — the guarantee is the same as composing at each transformation.
2831
+ //
2832
+ // An element is either a normalized sourcemap, or a magic source edit
2833
+ // record ({ contentEdits, getSourcemap }). Edits applied on top of an
2834
+ // existing map become position shifts on that map — orders of magnitude
2835
+ // cheaper than composing with a generated full-file map, and lossless:
2836
+ // the map keeps its own density instead of being redensified by the edit
2837
+ // map's word boundaries. When the shift cannot apply (no map below, or an
2838
+ // unsupported edit shape), getSourcemap() materializes the generated map
2839
+ // and composition proceeds as usual.
2840
+ const pendingSourcemapsMap = new WeakMap();
2841
+ const resolveSourcemapChain = (urlInfo, base, pendings) => {
2842
+ let current = base;
2843
+ let batch = current ? [current] : [];
2844
+ const composeBatch = () => {
2845
+ if (batch.length > 1) {
2846
+ const composed = composeSourcemaps(batch);
2847
+ current = composed ? normalizeSourcemap(urlInfo, composed) : null;
2848
+ } else {
2849
+ current = batch.length ? batch[0] : null;
2850
+ }
2851
+ };
2852
+ for (const pending of pendings) {
2853
+ if (!pending.contentEdits) {
2854
+ batch.push(pending);
2855
+ continue;
2856
+ }
2857
+ composeBatch();
2858
+ if (current) {
2859
+ const shifted = applyContentEditsOnSourcemap(
2860
+ current,
2861
+ pending.contentEdits,
2862
+ );
2863
+ if (shifted) {
2864
+ current = shifted;
2865
+ batch = [current];
2866
+ continue;
2867
+ }
2868
+ }
2869
+ const materialized = pending.getSourcemap();
2870
+ batch = current ? [current] : [];
2871
+ if (materialized) {
2872
+ batch.push(normalizeSourcemap(urlInfo, materialized));
2873
+ }
2874
+ }
2875
+ composeBatch();
2876
+ return current;
2877
+ };
2878
+ const addSourcemapElement = (urlInfo, element) => {
2879
+ const existingPendings = pendingSourcemapsMap.get(urlInfo);
2880
+ if (existingPendings) {
2881
+ existingPendings.push(element);
2882
+ return;
2883
+ }
2884
+ const pendings = [element];
2885
+ pendingSourcemapsMap.set(urlInfo, pendings);
2886
+ let base = urlInfo.sourcemap;
2887
+ Object.defineProperty(urlInfo, "sourcemap", {
2888
+ configurable: true,
2889
+ enumerable: true,
2890
+ get: () => {
2891
+ if (pendings.length > 0) {
2892
+ base = resolveSourcemapChain(urlInfo, base, pendings);
2893
+ pendings.length = 0;
2894
+ }
2895
+ return base;
2896
+ },
2897
+ set: (value) => {
2898
+ pendings.length = 0;
2899
+ base = value;
2900
+ },
2901
+ });
2902
+ };
2903
+
2826
2904
  const resetContent = (urlInfo) => {
2827
2905
  urlInfo.contentFinalized = false;
2828
2906
  urlInfo.originalContent = undefined;
@@ -2969,33 +3047,35 @@ const createUrlInfoTransformer = ({
2969
3047
  }
2970
3048
  // "sourcemap" is read last, and only when it will be used: a plugin can
2971
3049
  // hand it back as a getter that generates the map on first read, so that
2972
- // nothing is generated for a kitchen that throws sourcemaps away
2973
- const sourcemap =
2974
- mayHaveSourcemap(urlInfo) && shouldHandleSourcemap(urlInfo)
2975
- ? transformations.sourcemap
2976
- : null;
2977
- if (sourcemap) {
2978
- const sourcemapNormalized = normalizeSourcemap(urlInfo, sourcemap);
2979
- let currentSourcemap = urlInfo.sourcemap;
2980
- const finalSourcemap = composeTwoSourcemaps(
2981
- currentSourcemap,
2982
- sourcemapNormalized,
2983
- );
2984
- const finalSourcemapNormalized = normalizeSourcemap(
2985
- urlInfo,
2986
- finalSourcemap,
2987
- );
2988
- urlInfo.sourcemap = finalSourcemapNormalized;
2989
- // A plugin is allowed to modify url content
2990
- // without returning a sourcemap
2991
- // This is the case for preact and react plugins.
2992
- // They are currently generating wrong source mappings
2993
- // when used.
2994
- // Generating the correct sourcemap in this situation
2995
- // is a nightmare no-one could solve in years so
2996
- // jsenv won't emit a warning and use the following strategy:
2997
- // "no sourcemap is better than wrong sourcemap"
2998
- urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
3050
+ // nothing is generated for a kitchen that throws sourcemaps away.
3051
+ // "sourcemapEdits" (magic source results) goes further: the edits are
3052
+ // pushed and the generated map is materialized only if the shift fast
3053
+ // path cannot apply.
3054
+ if (mayHaveSourcemap(urlInfo) && shouldHandleSourcemap(urlInfo)) {
3055
+ const { sourcemapEdits } = transformations;
3056
+ if (sourcemapEdits) {
3057
+ addSourcemapElement(urlInfo, {
3058
+ contentEdits: sourcemapEdits,
3059
+ getSourcemap: () => transformations.sourcemap,
3060
+ });
3061
+ urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
3062
+ } else {
3063
+ const sourcemap = transformations.sourcemap;
3064
+ if (sourcemap) {
3065
+ addSourcemapElement(urlInfo, normalizeSourcemap(urlInfo, sourcemap));
3066
+ // A plugin is allowed to modify url content
3067
+ // without returning a sourcemap
3068
+ // This is the case for preact and react plugins.
3069
+ // They are currently generating wrong source mappings
3070
+ // when used.
3071
+ // Generating the correct sourcemap in this situation
3072
+ // is a nightmare no-one could solve in years so
3073
+ // jsenv won't emit a warning and use the following strategy:
3074
+ // "no sourcemap is better than wrong sourcemap"
3075
+ urlInfo.sourcemapIsWrong =
3076
+ urlInfo.sourcemapIsWrong || sourcemapIsWrong;
3077
+ }
3078
+ }
2999
3079
  }
3000
3080
  if (contentModified && urlInfo.contentFinalized) {
3001
3081
  applyContentEffects(urlInfo);
@@ -6,7 +6,7 @@ import { createPluginsController } from "@jsenv/server/src/plugins_controller.js
6
6
  import { parseHtml, injectJsenvScript, stringifyHtmlAst, parseCssUrls, getHtmlNodeAttribute, getHtmlNodePosition, getHtmlNodeAttributePosition, setHtmlNodeAttributes, parseSrcSet, getUrlForContentInsideHtml, removeHtmlNodeText, setHtmlNodeText, getHtmlNodeText, analyzeScriptNode, visitHtmlNodes, parseJsUrls, getUrlForContentInsideJs, renderCssTemplateLiteral, applyBabelPlugins, visitJsAst, getImportMetaPropertyName, visitJsAstUntil, analyzeLinkNode, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, generateUrlForInlineContent, parseJsWithAcorn } from "@jsenv/ast";
7
7
  import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
8
8
  import { jsenvPluginTranspilation } from "@jsenv/plugin-transpilation";
9
- import { createMagicSource, composeTwoSourcemaps, generateSourcemapFileUrl, generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
9
+ import { createMagicSource, composeTwoSourcemaps, generateSourcemapFileUrl, generateSourcemapDataUrl, SOURCEMAP, applyContentEditsOnSourcemap, composeSourcemaps } from "@jsenv/sourcemap";
10
10
  import { bundleJsModules } from "@jsenv/plugin-bundling";
11
11
  import { randomUUID } from "node:crypto";
12
12
  import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/plugins/filesystem/filesystem_error_to_response.js";
@@ -10151,6 +10151,84 @@ const createUrlInfoTransformer = ({
10151
10151
  return sourcemap;
10152
10152
  };
10153
10153
 
10154
+ // Sourcemap composition is deferred: each transformation pushes an element
10155
+ // here and "urlInfo.sourcemap" becomes a lazy view resolving the whole
10156
+ // pending chain on first read (with caching, invalidated by a new push or
10157
+ // an assignment). Any reader at any point sees a map matching the current
10158
+ // content — the guarantee is the same as composing at each transformation.
10159
+ //
10160
+ // An element is either a normalized sourcemap, or a magic source edit
10161
+ // record ({ contentEdits, getSourcemap }). Edits applied on top of an
10162
+ // existing map become position shifts on that map — orders of magnitude
10163
+ // cheaper than composing with a generated full-file map, and lossless:
10164
+ // the map keeps its own density instead of being redensified by the edit
10165
+ // map's word boundaries. When the shift cannot apply (no map below, or an
10166
+ // unsupported edit shape), getSourcemap() materializes the generated map
10167
+ // and composition proceeds as usual.
10168
+ const pendingSourcemapsMap = new WeakMap();
10169
+ const resolveSourcemapChain = (urlInfo, base, pendings) => {
10170
+ let current = base;
10171
+ let batch = current ? [current] : [];
10172
+ const composeBatch = () => {
10173
+ if (batch.length > 1) {
10174
+ const composed = composeSourcemaps(batch);
10175
+ current = composed ? normalizeSourcemap(urlInfo, composed) : null;
10176
+ } else {
10177
+ current = batch.length ? batch[0] : null;
10178
+ }
10179
+ };
10180
+ for (const pending of pendings) {
10181
+ if (!pending.contentEdits) {
10182
+ batch.push(pending);
10183
+ continue;
10184
+ }
10185
+ composeBatch();
10186
+ if (current) {
10187
+ const shifted = applyContentEditsOnSourcemap(
10188
+ current,
10189
+ pending.contentEdits,
10190
+ );
10191
+ if (shifted) {
10192
+ current = shifted;
10193
+ batch = [current];
10194
+ continue;
10195
+ }
10196
+ }
10197
+ const materialized = pending.getSourcemap();
10198
+ batch = current ? [current] : [];
10199
+ if (materialized) {
10200
+ batch.push(normalizeSourcemap(urlInfo, materialized));
10201
+ }
10202
+ }
10203
+ composeBatch();
10204
+ return current;
10205
+ };
10206
+ const addSourcemapElement = (urlInfo, element) => {
10207
+ const existingPendings = pendingSourcemapsMap.get(urlInfo);
10208
+ if (existingPendings) {
10209
+ existingPendings.push(element);
10210
+ return;
10211
+ }
10212
+ const pendings = [element];
10213
+ pendingSourcemapsMap.set(urlInfo, pendings);
10214
+ let base = urlInfo.sourcemap;
10215
+ Object.defineProperty(urlInfo, "sourcemap", {
10216
+ configurable: true,
10217
+ enumerable: true,
10218
+ get: () => {
10219
+ if (pendings.length > 0) {
10220
+ base = resolveSourcemapChain(urlInfo, base, pendings);
10221
+ pendings.length = 0;
10222
+ }
10223
+ return base;
10224
+ },
10225
+ set: (value) => {
10226
+ pendings.length = 0;
10227
+ base = value;
10228
+ },
10229
+ });
10230
+ };
10231
+
10154
10232
  const resetContent = (urlInfo) => {
10155
10233
  urlInfo.contentFinalized = false;
10156
10234
  urlInfo.originalContent = undefined;
@@ -10297,33 +10375,35 @@ const createUrlInfoTransformer = ({
10297
10375
  }
10298
10376
  // "sourcemap" is read last, and only when it will be used: a plugin can
10299
10377
  // hand it back as a getter that generates the map on first read, so that
10300
- // nothing is generated for a kitchen that throws sourcemaps away
10301
- const sourcemap =
10302
- mayHaveSourcemap(urlInfo) && shouldHandleSourcemap(urlInfo)
10303
- ? transformations.sourcemap
10304
- : null;
10305
- if (sourcemap) {
10306
- const sourcemapNormalized = normalizeSourcemap(urlInfo, sourcemap);
10307
- let currentSourcemap = urlInfo.sourcemap;
10308
- const finalSourcemap = composeTwoSourcemaps(
10309
- currentSourcemap,
10310
- sourcemapNormalized,
10311
- );
10312
- const finalSourcemapNormalized = normalizeSourcemap(
10313
- urlInfo,
10314
- finalSourcemap,
10315
- );
10316
- urlInfo.sourcemap = finalSourcemapNormalized;
10317
- // A plugin is allowed to modify url content
10318
- // without returning a sourcemap
10319
- // This is the case for preact and react plugins.
10320
- // They are currently generating wrong source mappings
10321
- // when used.
10322
- // Generating the correct sourcemap in this situation
10323
- // is a nightmare no-one could solve in years so
10324
- // jsenv won't emit a warning and use the following strategy:
10325
- // "no sourcemap is better than wrong sourcemap"
10326
- urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
10378
+ // nothing is generated for a kitchen that throws sourcemaps away.
10379
+ // "sourcemapEdits" (magic source results) goes further: the edits are
10380
+ // pushed and the generated map is materialized only if the shift fast
10381
+ // path cannot apply.
10382
+ if (mayHaveSourcemap(urlInfo) && shouldHandleSourcemap(urlInfo)) {
10383
+ const { sourcemapEdits } = transformations;
10384
+ if (sourcemapEdits) {
10385
+ addSourcemapElement(urlInfo, {
10386
+ contentEdits: sourcemapEdits,
10387
+ getSourcemap: () => transformations.sourcemap,
10388
+ });
10389
+ urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
10390
+ } else {
10391
+ const sourcemap = transformations.sourcemap;
10392
+ if (sourcemap) {
10393
+ addSourcemapElement(urlInfo, normalizeSourcemap(urlInfo, sourcemap));
10394
+ // A plugin is allowed to modify url content
10395
+ // without returning a sourcemap
10396
+ // This is the case for preact and react plugins.
10397
+ // They are currently generating wrong source mappings
10398
+ // when used.
10399
+ // Generating the correct sourcemap in this situation
10400
+ // is a nightmare no-one could solve in years so
10401
+ // jsenv won't emit a warning and use the following strategy:
10402
+ // "no sourcemap is better than wrong sourcemap"
10403
+ urlInfo.sourcemapIsWrong =
10404
+ urlInfo.sourcemapIsWrong || sourcemapIsWrong;
10405
+ }
10406
+ }
10327
10407
  }
10328
10408
  if (contentModified && urlInfo.contentFinalized) {
10329
10409
  applyContentEffects(urlInfo);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "41.5.5",
3
+ "version": "41.5.7",
4
4
  "type": "module",
5
5
  "description": "Tool to develop, test and build js projects",
6
6
  "repository": {
@@ -74,13 +74,13 @@
74
74
  },
75
75
  "dependencies": {
76
76
  "@jsenv/ast": "6.10.1",
77
- "@jsenv/js-module-fallback": "1.6.2",
78
- "@jsenv/plugin-bundling": "2.10.20",
79
- "@jsenv/plugin-minification": "1.7.15",
80
- "@jsenv/plugin-supervisor": "1.8.17",
81
- "@jsenv/plugin-transpilation": "1.7.2",
77
+ "@jsenv/js-module-fallback": "1.6.4",
78
+ "@jsenv/plugin-bundling": "2.10.22",
79
+ "@jsenv/plugin-minification": "1.7.17",
80
+ "@jsenv/plugin-supervisor": "1.8.19",
81
+ "@jsenv/plugin-transpilation": "1.7.4",
82
82
  "@jsenv/server": "17.6.3",
83
- "@jsenv/sourcemap": "1.4.3",
83
+ "@jsenv/sourcemap": "1.4.5",
84
84
  "react-table": "7.8.0"
85
85
  },
86
86
  "devDependencies": {
@@ -1,6 +1,7 @@
1
1
  import { writeFileSync } from "@jsenv/filesystem";
2
2
  import {
3
- composeTwoSourcemaps,
3
+ applyContentEditsOnSourcemap,
4
+ composeSourcemaps,
4
5
  generateSourcemapDataUrl,
5
6
  SOURCEMAP,
6
7
  } from "@jsenv/sourcemap";
@@ -81,6 +82,84 @@ export const createUrlInfoTransformer = ({
81
82
  return sourcemap;
82
83
  };
83
84
 
85
+ // Sourcemap composition is deferred: each transformation pushes an element
86
+ // here and "urlInfo.sourcemap" becomes a lazy view resolving the whole
87
+ // pending chain on first read (with caching, invalidated by a new push or
88
+ // an assignment). Any reader at any point sees a map matching the current
89
+ // content — the guarantee is the same as composing at each transformation.
90
+ //
91
+ // An element is either a normalized sourcemap, or a magic source edit
92
+ // record ({ contentEdits, getSourcemap }). Edits applied on top of an
93
+ // existing map become position shifts on that map — orders of magnitude
94
+ // cheaper than composing with a generated full-file map, and lossless:
95
+ // the map keeps its own density instead of being redensified by the edit
96
+ // map's word boundaries. When the shift cannot apply (no map below, or an
97
+ // unsupported edit shape), getSourcemap() materializes the generated map
98
+ // and composition proceeds as usual.
99
+ const pendingSourcemapsMap = new WeakMap();
100
+ const resolveSourcemapChain = (urlInfo, base, pendings) => {
101
+ let current = base;
102
+ let batch = current ? [current] : [];
103
+ const composeBatch = () => {
104
+ if (batch.length > 1) {
105
+ const composed = composeSourcemaps(batch);
106
+ current = composed ? normalizeSourcemap(urlInfo, composed) : null;
107
+ } else {
108
+ current = batch.length ? batch[0] : null;
109
+ }
110
+ };
111
+ for (const pending of pendings) {
112
+ if (!pending.contentEdits) {
113
+ batch.push(pending);
114
+ continue;
115
+ }
116
+ composeBatch();
117
+ if (current) {
118
+ const shifted = applyContentEditsOnSourcemap(
119
+ current,
120
+ pending.contentEdits,
121
+ );
122
+ if (shifted) {
123
+ current = shifted;
124
+ batch = [current];
125
+ continue;
126
+ }
127
+ }
128
+ const materialized = pending.getSourcemap();
129
+ batch = current ? [current] : [];
130
+ if (materialized) {
131
+ batch.push(normalizeSourcemap(urlInfo, materialized));
132
+ }
133
+ }
134
+ composeBatch();
135
+ return current;
136
+ };
137
+ const addSourcemapElement = (urlInfo, element) => {
138
+ const existingPendings = pendingSourcemapsMap.get(urlInfo);
139
+ if (existingPendings) {
140
+ existingPendings.push(element);
141
+ return;
142
+ }
143
+ const pendings = [element];
144
+ pendingSourcemapsMap.set(urlInfo, pendings);
145
+ let base = urlInfo.sourcemap;
146
+ Object.defineProperty(urlInfo, "sourcemap", {
147
+ configurable: true,
148
+ enumerable: true,
149
+ get: () => {
150
+ if (pendings.length > 0) {
151
+ base = resolveSourcemapChain(urlInfo, base, pendings);
152
+ pendings.length = 0;
153
+ }
154
+ return base;
155
+ },
156
+ set: (value) => {
157
+ pendings.length = 0;
158
+ base = value;
159
+ },
160
+ });
161
+ };
162
+
84
163
  const resetContent = (urlInfo) => {
85
164
  urlInfo.contentFinalized = false;
86
165
  urlInfo.originalContent = undefined;
@@ -227,33 +306,35 @@ export const createUrlInfoTransformer = ({
227
306
  }
228
307
  // "sourcemap" is read last, and only when it will be used: a plugin can
229
308
  // hand it back as a getter that generates the map on first read, so that
230
- // nothing is generated for a kitchen that throws sourcemaps away
231
- const sourcemap =
232
- mayHaveSourcemap(urlInfo) && shouldHandleSourcemap(urlInfo)
233
- ? transformations.sourcemap
234
- : null;
235
- if (sourcemap) {
236
- const sourcemapNormalized = normalizeSourcemap(urlInfo, sourcemap);
237
- let currentSourcemap = urlInfo.sourcemap;
238
- const finalSourcemap = composeTwoSourcemaps(
239
- currentSourcemap,
240
- sourcemapNormalized,
241
- );
242
- const finalSourcemapNormalized = normalizeSourcemap(
243
- urlInfo,
244
- finalSourcemap,
245
- );
246
- urlInfo.sourcemap = finalSourcemapNormalized;
247
- // A plugin is allowed to modify url content
248
- // without returning a sourcemap
249
- // This is the case for preact and react plugins.
250
- // They are currently generating wrong source mappings
251
- // when used.
252
- // Generating the correct sourcemap in this situation
253
- // is a nightmare no-one could solve in years so
254
- // jsenv won't emit a warning and use the following strategy:
255
- // "no sourcemap is better than wrong sourcemap"
256
- urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
309
+ // nothing is generated for a kitchen that throws sourcemaps away.
310
+ // "sourcemapEdits" (magic source results) goes further: the edits are
311
+ // pushed and the generated map is materialized only if the shift fast
312
+ // path cannot apply.
313
+ if (mayHaveSourcemap(urlInfo) && shouldHandleSourcemap(urlInfo)) {
314
+ const { sourcemapEdits } = transformations;
315
+ if (sourcemapEdits) {
316
+ addSourcemapElement(urlInfo, {
317
+ contentEdits: sourcemapEdits,
318
+ getSourcemap: () => transformations.sourcemap,
319
+ });
320
+ urlInfo.sourcemapIsWrong = urlInfo.sourcemapIsWrong || sourcemapIsWrong;
321
+ } else {
322
+ const sourcemap = transformations.sourcemap;
323
+ if (sourcemap) {
324
+ addSourcemapElement(urlInfo, normalizeSourcemap(urlInfo, sourcemap));
325
+ // A plugin is allowed to modify url content
326
+ // without returning a sourcemap
327
+ // This is the case for preact and react plugins.
328
+ // They are currently generating wrong source mappings
329
+ // when used.
330
+ // Generating the correct sourcemap in this situation
331
+ // is a nightmare no-one could solve in years so
332
+ // jsenv won't emit a warning and use the following strategy:
333
+ // "no sourcemap is better than wrong sourcemap"
334
+ urlInfo.sourcemapIsWrong =
335
+ urlInfo.sourcemapIsWrong || sourcemapIsWrong;
336
+ }
337
+ }
257
338
  }
258
339
  if (contentModified && urlInfo.contentFinalized) {
259
340
  applyContentEffects(urlInfo);