@merkur/integration 0.37.0 → 0.38.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/lib/index.es9.cjs CHANGED
@@ -36,87 +36,138 @@ const exported = {
36
36
  isES13Supported,
37
37
  test
38
38
  };
39
- function _loadScript(asset, root) {
40
- return new Promise((resolve, reject) => {
41
- const scriptElement = root.querySelector(`script[src='${asset.source}']`);
42
- if (scriptElement) {
43
- if (!asset.test || exported.test(asset.test)) {
44
- resolve();
45
- }
46
- scriptElement.addEventListener('load', resolve);
47
- scriptElement.addEventListener('error', asset.optional ? resolve : reject);
48
- return;
39
+ const isLoadedSymbol = Symbol.for('isLoaded');
40
+ const loadingPromiseSymbol = Symbol.for('loadingPromise');
41
+ function _attachElementToAsset(asset, element) {
42
+ return {
43
+ ...asset,
44
+ element
45
+ };
46
+ }
47
+ function _handleAssetError({
48
+ asset,
49
+ message = `Error loading asset ${asset.source}.`
50
+ }) {
51
+ if (asset.optional) {
52
+ console.warn(message);
53
+ return _attachElementToAsset(asset, null);
54
+ }
55
+ const error = new Error(message);
56
+ error.asset = asset;
57
+ throw error;
58
+ }
59
+ function _addListenersToAssetElement(asset, element, resolve, reject) {
60
+ element.addEventListener('load', () => {
61
+ resolve(_attachElementToAsset(asset, element));
62
+ element[isLoadedSymbol] = true;
63
+ delete element[loadingPromiseSymbol];
64
+ });
65
+ element.addEventListener('error', () => {
66
+ if (element.parentNode) {
67
+ element.remove();
49
68
  }
50
- const script = document.createElement('script');
51
- if (asset.type === 'script') {
52
- script.defer = true;
53
- script.onload = resolve;
54
- script.onerror = error => {
55
- script.remove();
56
- asset.optional ? resolve(error) : reject(error);
57
- };
58
- script.src = asset.source;
59
- const {
60
- attr
61
- } = asset;
62
- if (attr && Object.keys(attr).length) {
63
- for (const name in attr) {
64
- const value = attr[name];
65
- if (typeof value === 'boolean') {
66
- if (value) {
67
- script.setAttribute(name, '');
68
- } else {
69
- script.removeAttribute(name);
70
- }
71
- } else {
72
- script.setAttribute(name, value);
73
- }
74
- }
75
- }
76
- } else {
77
- script.text = asset.source;
78
- resolve();
69
+ try {
70
+ resolve(_handleAssetError({
71
+ asset
72
+ }));
73
+ } catch (error) {
74
+ reject(error);
79
75
  }
80
- root.appendChild(script);
81
76
  });
82
77
  }
83
78
  function _loadStyle(asset, root) {
84
- return new Promise((resolve, reject) => {
79
+ if (asset.type === 'inlineStyle') {
80
+ const style = document.createElement('style');
81
+ style.innerHTML = asset.source;
82
+ root.appendChild(style);
83
+ return _attachElementToAsset(asset, style);
84
+ }
85
+ const link = document.createElement('link');
86
+ link[loadingPromiseSymbol] = new Promise((resolve, reject) => {
87
+ _addListenersToAssetElement(asset, link, resolve, reject);
88
+ link.rel = 'stylesheet';
89
+ link.href = asset.source;
90
+ root.appendChild(link);
91
+ });
92
+ return link[loadingPromiseSymbol];
93
+ }
94
+ async function loadStyleAssets(assets, root = document.head) {
95
+ const styleElements = Array.from(root.querySelectorAll('style'));
96
+ return Promise.all(assets.map(asset => {
97
+ if (!['stylesheet', 'inlineStyle'].includes(asset.type) || !asset.source) {
98
+ return _attachElementToAsset(asset, null);
99
+ }
85
100
  if (asset.type === 'stylesheet') {
86
- const link = document.createElement('link');
87
- link.onload = resolve;
88
- link.onerror = reject;
89
- link.rel = 'stylesheet';
90
- link.href = asset.source;
91
- root.appendChild(link);
92
- } else {
93
- const style = document.createElement('style');
94
- style.innerHTML = asset.source;
95
- root.appendChild(style);
96
- resolve();
101
+ const link = root.querySelector(`link[href='${asset.source}']`);
102
+ if (link) {
103
+ if (link[loadingPromiseSymbol]) {
104
+ return link[loadingPromiseSymbol];
105
+ }
106
+ return _attachElementToAsset(asset, link);
107
+ }
97
108
  }
98
- });
109
+ if (asset.type === 'inlineStyle') {
110
+ const inlineStyle = styleElements.find(element => element.innerHTML === asset.source);
111
+ if (inlineStyle) {
112
+ return _attachElementToAsset(asset, inlineStyle);
113
+ }
114
+ }
115
+ return _loadStyle(asset, root);
116
+ }));
99
117
  }
100
- function loadStyleAssets(assets, root = document.head) {
101
- const styleElements = root.querySelectorAll('style');
102
- const stylesToRender = assets.filter(asset => asset.source && (asset.type === 'stylesheet' && !root.querySelector(`link[href='${asset.source}']`) || asset.type === 'inlineStyle' && Array.from(styleElements).reduce((acc, cur) => {
103
- if (cur.innerHTML === asset.source) {
104
- return false;
118
+ function _findScriptElement(scriptElements, asset) {
119
+ if (asset.type === 'json') {
120
+ return scriptElements.find(element => element.dataset.src === asset.source);
121
+ }
122
+ if (!['script', 'inlineScript', 'inlineJson'].includes(asset.type)) {
123
+ return null;
124
+ }
125
+ const attributeKey = asset.type === 'script' ? 'src' : 'textContent';
126
+ const source = asset.type === 'inlineJson' ? JSON.stringify(asset.source) : asset.source;
127
+ return scriptElements.find(element => element[attributeKey] === source) || null;
128
+ }
129
+ function _loadScript(asset, root) {
130
+ const script = document.createElement('script');
131
+ if (asset.type === 'inlineScript') {
132
+ script.textContent = asset.source;
133
+ root.appendChild(script);
134
+ return _attachElementToAsset(asset, script);
135
+ }
136
+ script[loadingPromiseSymbol] = new Promise((resolve, reject) => {
137
+ script.defer = true;
138
+ _addListenersToAssetElement(asset, script, resolve, reject);
139
+ script.src = asset.source;
140
+ const {
141
+ attr
142
+ } = asset;
143
+ if (attr && Object.keys(attr).length) {
144
+ for (const name in attr) {
145
+ const value = attr[name];
146
+ if (typeof value === 'boolean') {
147
+ if (value) {
148
+ script.setAttribute(name, '');
149
+ } else {
150
+ script.removeAttribute(name);
151
+ }
152
+ } else {
153
+ script.setAttribute(name, value);
154
+ }
155
+ }
105
156
  }
106
- return acc;
107
- }, true)));
108
- return Promise.all(stylesToRender.map(asset => _loadStyle(asset, root)));
157
+ root.appendChild(script);
158
+ });
159
+ return script[loadingPromiseSymbol];
109
160
  }
110
161
  async function loadScriptAssets(assets, root = document.head) {
111
- const scriptElements = root.querySelectorAll('script');
112
- const scriptsToRender = assets.reduce((scripts, asset) => {
162
+ const scriptElements = Array.from(root.querySelectorAll('script'));
163
+ return Promise.all(assets.map(asset => {
164
+ if (!['script', 'inlineScript'].includes(asset.type) || !asset.source) {
165
+ return _attachElementToAsset(asset, null);
166
+ }
113
167
  const {
114
168
  source
115
169
  } = asset;
116
170
  const _asset = Object.assign({}, asset);
117
- if (_asset.type !== 'script' && _asset.type !== 'inlineScript') {
118
- return scripts;
119
- }
120
171
  if (source === Object(source)) {
121
172
  if (source.es13 && exported.isES13Supported()) {
122
173
  _asset.source = source.es13;
@@ -128,33 +179,122 @@ async function loadScriptAssets(assets, root = document.head) {
128
179
  _asset.source = null;
129
180
  }
130
181
  if (!_asset.source) {
131
- const message = `Asset '${_asset.name}' is missing ES variant and could not be loaded.`;
132
- if (!_asset.optional) {
133
- const error = new Error(message);
134
- error.asset = _asset;
135
- throw error;
182
+ return _handleAssetError({
183
+ asset: _asset,
184
+ message: `Asset '${_asset.name}' is missing ES variant and could not be loaded.`
185
+ });
186
+ }
187
+ }
188
+ if (_asset.test && exported.test(_asset.test)) {
189
+ return _attachElementToAsset(_asset, _findScriptElement(scriptElements, _asset));
190
+ }
191
+ const script = _findScriptElement(scriptElements, _asset);
192
+ if (script && _asset.type === 'script') {
193
+ if (script[loadingPromiseSymbol]) {
194
+ return script[loadingPromiseSymbol];
195
+ }
196
+ if (script[isLoadedSymbol]) {
197
+ return _attachElementToAsset(_asset, script);
198
+ }
199
+ return new Promise((resolve, reject) => _addListenersToAssetElement(_asset, script, resolve, reject));
200
+ } else if (script && _asset.type === 'inlineScript') {
201
+ return _attachElementToAsset(_asset, script);
202
+ }
203
+ return _loadScript(_asset, root);
204
+ }));
205
+ }
206
+ async function _fetchData(source) {
207
+ const response = await fetch(source);
208
+ if (!response.ok) {
209
+ throw new Error(`Failed to fetch from '${source}' with status ${response.status} ${response.statusText}.`);
210
+ }
211
+ return response.text();
212
+ }
213
+ function _removeElementAfterTimeout(element, timeout) {
214
+ if (timeout) {
215
+ setTimeout(() => {
216
+ if (element.parentNode) {
217
+ element.remove();
218
+ }
219
+ }, timeout);
220
+ }
221
+ }
222
+ function _loadJsonAsset(asset, root) {
223
+ const script = document.createElement('script');
224
+ script.type = 'application/json';
225
+ if (asset.type === 'inlineJson') {
226
+ script.textContent = JSON.stringify(asset.source);
227
+ root.appendChild(script);
228
+ _removeElementAfterTimeout(script, asset.ttl);
229
+ return _attachElementToAsset(asset, script);
230
+ }
231
+ script[loadingPromiseSymbol] = new Promise((resolve, reject) => {
232
+ script.dataset.src = asset.source;
233
+ root.appendChild(script);
234
+ (async () => {
235
+ try {
236
+ const textContent = await _fetchData(asset.source);
237
+ script.textContent = textContent;
238
+ delete script[loadingPromiseSymbol];
239
+ _removeElementAfterTimeout(script, asset.ttl);
240
+ resolve(_attachElementToAsset(asset, script));
241
+ } catch (error) {
242
+ script.remove();
243
+ try {
244
+ resolve(_handleAssetError({
245
+ asset,
246
+ message: `Error loading JSON asset '${asset.name}': ${error.message}`
247
+ }));
248
+ } catch (error) {
249
+ reject(error);
136
250
  }
137
- console.warn(message);
138
- return scripts;
139
251
  }
252
+ })();
253
+ });
254
+ return script[loadingPromiseSymbol];
255
+ }
256
+ async function loadJsonAssets(assets, root = document.head) {
257
+ const scriptElements = Array.from(root.querySelectorAll('script[type="application/json"]'));
258
+ return Promise.all(assets.map(asset => {
259
+ if (!['json', 'inlineJson'].includes(asset.type) || !asset.source) {
260
+ return _attachElementToAsset(asset, null);
140
261
  }
141
- if (Array.from(scriptElements).reduce((acc, cur) => {
142
- if (cur.text === _asset.source) {
143
- return true;
262
+ const script = _findScriptElement(scriptElements, asset);
263
+ if (script) {
264
+ if (script[loadingPromiseSymbol]) {
265
+ return script[loadingPromiseSymbol];
266
+ }
267
+ if (script.textContent) {
268
+ return _attachElementToAsset(asset, script);
144
269
  }
145
- return acc;
146
- }, false) || (_asset.test ? exported.test(_asset.test) : false)) {
147
- return scripts;
270
+ return _handleAssetError({
271
+ asset,
272
+ message: `JSON asset '${asset.name}' is missing textContent and could not be loaded.`
273
+ });
148
274
  }
149
- scripts.push(_asset);
150
- return scripts;
275
+ return _loadJsonAsset(asset, root);
276
+ }));
277
+ }
278
+ function _mergeResults(results) {
279
+ return results.reduce((acc, results) => {
280
+ results.forEach((result, index) => {
281
+ if (!acc[index]) {
282
+ acc[index] = result;
283
+ } else if (result.element) {
284
+ acc[index] = result;
285
+ }
286
+ });
287
+ return acc;
151
288
  }, []);
152
- return Promise.all(scriptsToRender.map(asset => _loadScript(asset, root)));
153
289
  }
154
- function loadAssets(assets, root) {
155
- return Promise.all([loadScriptAssets(assets, root), loadStyleAssets(assets, root)]);
290
+ async function loadAssets(assets, root) {
291
+ const results = await Promise.all([loadScriptAssets(assets, root), loadStyleAssets(assets, root), loadJsonAssets(assets, root)]);
292
+ return _mergeResults(results);
156
293
  }
294
+ exports.isLoadedSymbol = isLoadedSymbol;
157
295
  exports.loadAssets = loadAssets;
296
+ exports.loadJsonAssets = loadJsonAssets;
158
297
  exports.loadScriptAssets = loadScriptAssets;
159
298
  exports.loadStyleAssets = loadStyleAssets;
299
+ exports.loadingPromiseSymbol = loadingPromiseSymbol;
160
300
  exports.testScript = exported;
package/lib/index.es9.mjs CHANGED
@@ -34,87 +34,138 @@ const exported = {
34
34
  isES13Supported,
35
35
  test
36
36
  };
37
- function _loadScript(asset, root) {
38
- return new Promise((resolve, reject) => {
39
- const scriptElement = root.querySelector(`script[src='${asset.source}']`);
40
- if (scriptElement) {
41
- if (!asset.test || exported.test(asset.test)) {
42
- resolve();
43
- }
44
- scriptElement.addEventListener('load', resolve);
45
- scriptElement.addEventListener('error', asset.optional ? resolve : reject);
46
- return;
37
+ const isLoadedSymbol = Symbol.for('isLoaded');
38
+ const loadingPromiseSymbol = Symbol.for('loadingPromise');
39
+ function _attachElementToAsset(asset, element) {
40
+ return {
41
+ ...asset,
42
+ element
43
+ };
44
+ }
45
+ function _handleAssetError({
46
+ asset,
47
+ message = `Error loading asset ${asset.source}.`
48
+ }) {
49
+ if (asset.optional) {
50
+ console.warn(message);
51
+ return _attachElementToAsset(asset, null);
52
+ }
53
+ const error = new Error(message);
54
+ error.asset = asset;
55
+ throw error;
56
+ }
57
+ function _addListenersToAssetElement(asset, element, resolve, reject) {
58
+ element.addEventListener('load', () => {
59
+ resolve(_attachElementToAsset(asset, element));
60
+ element[isLoadedSymbol] = true;
61
+ delete element[loadingPromiseSymbol];
62
+ });
63
+ element.addEventListener('error', () => {
64
+ if (element.parentNode) {
65
+ element.remove();
47
66
  }
48
- const script = document.createElement('script');
49
- if (asset.type === 'script') {
50
- script.defer = true;
51
- script.onload = resolve;
52
- script.onerror = error => {
53
- script.remove();
54
- asset.optional ? resolve(error) : reject(error);
55
- };
56
- script.src = asset.source;
57
- const {
58
- attr
59
- } = asset;
60
- if (attr && Object.keys(attr).length) {
61
- for (const name in attr) {
62
- const value = attr[name];
63
- if (typeof value === 'boolean') {
64
- if (value) {
65
- script.setAttribute(name, '');
66
- } else {
67
- script.removeAttribute(name);
68
- }
69
- } else {
70
- script.setAttribute(name, value);
71
- }
72
- }
73
- }
74
- } else {
75
- script.text = asset.source;
76
- resolve();
67
+ try {
68
+ resolve(_handleAssetError({
69
+ asset
70
+ }));
71
+ } catch (error) {
72
+ reject(error);
77
73
  }
78
- root.appendChild(script);
79
74
  });
80
75
  }
81
76
  function _loadStyle(asset, root) {
82
- return new Promise((resolve, reject) => {
77
+ if (asset.type === 'inlineStyle') {
78
+ const style = document.createElement('style');
79
+ style.innerHTML = asset.source;
80
+ root.appendChild(style);
81
+ return _attachElementToAsset(asset, style);
82
+ }
83
+ const link = document.createElement('link');
84
+ link[loadingPromiseSymbol] = new Promise((resolve, reject) => {
85
+ _addListenersToAssetElement(asset, link, resolve, reject);
86
+ link.rel = 'stylesheet';
87
+ link.href = asset.source;
88
+ root.appendChild(link);
89
+ });
90
+ return link[loadingPromiseSymbol];
91
+ }
92
+ async function loadStyleAssets(assets, root = document.head) {
93
+ const styleElements = Array.from(root.querySelectorAll('style'));
94
+ return Promise.all(assets.map(asset => {
95
+ if (!['stylesheet', 'inlineStyle'].includes(asset.type) || !asset.source) {
96
+ return _attachElementToAsset(asset, null);
97
+ }
83
98
  if (asset.type === 'stylesheet') {
84
- const link = document.createElement('link');
85
- link.onload = resolve;
86
- link.onerror = reject;
87
- link.rel = 'stylesheet';
88
- link.href = asset.source;
89
- root.appendChild(link);
90
- } else {
91
- const style = document.createElement('style');
92
- style.innerHTML = asset.source;
93
- root.appendChild(style);
94
- resolve();
99
+ const link = root.querySelector(`link[href='${asset.source}']`);
100
+ if (link) {
101
+ if (link[loadingPromiseSymbol]) {
102
+ return link[loadingPromiseSymbol];
103
+ }
104
+ return _attachElementToAsset(asset, link);
105
+ }
95
106
  }
96
- });
107
+ if (asset.type === 'inlineStyle') {
108
+ const inlineStyle = styleElements.find(element => element.innerHTML === asset.source);
109
+ if (inlineStyle) {
110
+ return _attachElementToAsset(asset, inlineStyle);
111
+ }
112
+ }
113
+ return _loadStyle(asset, root);
114
+ }));
97
115
  }
98
- function loadStyleAssets(assets, root = document.head) {
99
- const styleElements = root.querySelectorAll('style');
100
- const stylesToRender = assets.filter(asset => asset.source && (asset.type === 'stylesheet' && !root.querySelector(`link[href='${asset.source}']`) || asset.type === 'inlineStyle' && Array.from(styleElements).reduce((acc, cur) => {
101
- if (cur.innerHTML === asset.source) {
102
- return false;
116
+ function _findScriptElement(scriptElements, asset) {
117
+ if (asset.type === 'json') {
118
+ return scriptElements.find(element => element.dataset.src === asset.source);
119
+ }
120
+ if (!['script', 'inlineScript', 'inlineJson'].includes(asset.type)) {
121
+ return null;
122
+ }
123
+ const attributeKey = asset.type === 'script' ? 'src' : 'textContent';
124
+ const source = asset.type === 'inlineJson' ? JSON.stringify(asset.source) : asset.source;
125
+ return scriptElements.find(element => element[attributeKey] === source) || null;
126
+ }
127
+ function _loadScript(asset, root) {
128
+ const script = document.createElement('script');
129
+ if (asset.type === 'inlineScript') {
130
+ script.textContent = asset.source;
131
+ root.appendChild(script);
132
+ return _attachElementToAsset(asset, script);
133
+ }
134
+ script[loadingPromiseSymbol] = new Promise((resolve, reject) => {
135
+ script.defer = true;
136
+ _addListenersToAssetElement(asset, script, resolve, reject);
137
+ script.src = asset.source;
138
+ const {
139
+ attr
140
+ } = asset;
141
+ if (attr && Object.keys(attr).length) {
142
+ for (const name in attr) {
143
+ const value = attr[name];
144
+ if (typeof value === 'boolean') {
145
+ if (value) {
146
+ script.setAttribute(name, '');
147
+ } else {
148
+ script.removeAttribute(name);
149
+ }
150
+ } else {
151
+ script.setAttribute(name, value);
152
+ }
153
+ }
103
154
  }
104
- return acc;
105
- }, true)));
106
- return Promise.all(stylesToRender.map(asset => _loadStyle(asset, root)));
155
+ root.appendChild(script);
156
+ });
157
+ return script[loadingPromiseSymbol];
107
158
  }
108
159
  async function loadScriptAssets(assets, root = document.head) {
109
- const scriptElements = root.querySelectorAll('script');
110
- const scriptsToRender = assets.reduce((scripts, asset) => {
160
+ const scriptElements = Array.from(root.querySelectorAll('script'));
161
+ return Promise.all(assets.map(asset => {
162
+ if (!['script', 'inlineScript'].includes(asset.type) || !asset.source) {
163
+ return _attachElementToAsset(asset, null);
164
+ }
111
165
  const {
112
166
  source
113
167
  } = asset;
114
168
  const _asset = Object.assign({}, asset);
115
- if (_asset.type !== 'script' && _asset.type !== 'inlineScript') {
116
- return scripts;
117
- }
118
169
  if (source === Object(source)) {
119
170
  if (source.es13 && exported.isES13Supported()) {
120
171
  _asset.source = source.es13;
@@ -126,30 +177,116 @@ async function loadScriptAssets(assets, root = document.head) {
126
177
  _asset.source = null;
127
178
  }
128
179
  if (!_asset.source) {
129
- const message = `Asset '${_asset.name}' is missing ES variant and could not be loaded.`;
130
- if (!_asset.optional) {
131
- const error = new Error(message);
132
- error.asset = _asset;
133
- throw error;
180
+ return _handleAssetError({
181
+ asset: _asset,
182
+ message: `Asset '${_asset.name}' is missing ES variant and could not be loaded.`
183
+ });
184
+ }
185
+ }
186
+ if (_asset.test && exported.test(_asset.test)) {
187
+ return _attachElementToAsset(_asset, _findScriptElement(scriptElements, _asset));
188
+ }
189
+ const script = _findScriptElement(scriptElements, _asset);
190
+ if (script && _asset.type === 'script') {
191
+ if (script[loadingPromiseSymbol]) {
192
+ return script[loadingPromiseSymbol];
193
+ }
194
+ if (script[isLoadedSymbol]) {
195
+ return _attachElementToAsset(_asset, script);
196
+ }
197
+ return new Promise((resolve, reject) => _addListenersToAssetElement(_asset, script, resolve, reject));
198
+ } else if (script && _asset.type === 'inlineScript') {
199
+ return _attachElementToAsset(_asset, script);
200
+ }
201
+ return _loadScript(_asset, root);
202
+ }));
203
+ }
204
+ async function _fetchData(source) {
205
+ const response = await fetch(source);
206
+ if (!response.ok) {
207
+ throw new Error(`Failed to fetch from '${source}' with status ${response.status} ${response.statusText}.`);
208
+ }
209
+ return response.text();
210
+ }
211
+ function _removeElementAfterTimeout(element, timeout) {
212
+ if (timeout) {
213
+ setTimeout(() => {
214
+ if (element.parentNode) {
215
+ element.remove();
216
+ }
217
+ }, timeout);
218
+ }
219
+ }
220
+ function _loadJsonAsset(asset, root) {
221
+ const script = document.createElement('script');
222
+ script.type = 'application/json';
223
+ if (asset.type === 'inlineJson') {
224
+ script.textContent = JSON.stringify(asset.source);
225
+ root.appendChild(script);
226
+ _removeElementAfterTimeout(script, asset.ttl);
227
+ return _attachElementToAsset(asset, script);
228
+ }
229
+ script[loadingPromiseSymbol] = new Promise((resolve, reject) => {
230
+ script.dataset.src = asset.source;
231
+ root.appendChild(script);
232
+ (async () => {
233
+ try {
234
+ const textContent = await _fetchData(asset.source);
235
+ script.textContent = textContent;
236
+ delete script[loadingPromiseSymbol];
237
+ _removeElementAfterTimeout(script, asset.ttl);
238
+ resolve(_attachElementToAsset(asset, script));
239
+ } catch (error) {
240
+ script.remove();
241
+ try {
242
+ resolve(_handleAssetError({
243
+ asset,
244
+ message: `Error loading JSON asset '${asset.name}': ${error.message}`
245
+ }));
246
+ } catch (error) {
247
+ reject(error);
134
248
  }
135
- console.warn(message);
136
- return scripts;
137
249
  }
250
+ })();
251
+ });
252
+ return script[loadingPromiseSymbol];
253
+ }
254
+ async function loadJsonAssets(assets, root = document.head) {
255
+ const scriptElements = Array.from(root.querySelectorAll('script[type="application/json"]'));
256
+ return Promise.all(assets.map(asset => {
257
+ if (!['json', 'inlineJson'].includes(asset.type) || !asset.source) {
258
+ return _attachElementToAsset(asset, null);
138
259
  }
139
- if (Array.from(scriptElements).reduce((acc, cur) => {
140
- if (cur.text === _asset.source) {
141
- return true;
260
+ const script = _findScriptElement(scriptElements, asset);
261
+ if (script) {
262
+ if (script[loadingPromiseSymbol]) {
263
+ return script[loadingPromiseSymbol];
264
+ }
265
+ if (script.textContent) {
266
+ return _attachElementToAsset(asset, script);
142
267
  }
143
- return acc;
144
- }, false) || (_asset.test ? exported.test(_asset.test) : false)) {
145
- return scripts;
268
+ return _handleAssetError({
269
+ asset,
270
+ message: `JSON asset '${asset.name}' is missing textContent and could not be loaded.`
271
+ });
146
272
  }
147
- scripts.push(_asset);
148
- return scripts;
273
+ return _loadJsonAsset(asset, root);
274
+ }));
275
+ }
276
+ function _mergeResults(results) {
277
+ return results.reduce((acc, results) => {
278
+ results.forEach((result, index) => {
279
+ if (!acc[index]) {
280
+ acc[index] = result;
281
+ } else if (result.element) {
282
+ acc[index] = result;
283
+ }
284
+ });
285
+ return acc;
149
286
  }, []);
150
- return Promise.all(scriptsToRender.map(asset => _loadScript(asset, root)));
151
287
  }
152
- function loadAssets(assets, root) {
153
- return Promise.all([loadScriptAssets(assets, root), loadStyleAssets(assets, root)]);
288
+ async function loadAssets(assets, root) {
289
+ const results = await Promise.all([loadScriptAssets(assets, root), loadStyleAssets(assets, root), loadJsonAssets(assets, root)]);
290
+ return _mergeResults(results);
154
291
  }
155
- export { loadAssets, loadScriptAssets, loadStyleAssets, exported as testScript };
292
+ export { isLoadedSymbol, loadAssets, loadJsonAssets, loadScriptAssets, loadStyleAssets, loadingPromiseSymbol, exported as testScript };