@siteimprove/alfa-dom 0.101.0 → 0.103.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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @siteimprove/alfa-dom
2
2
 
3
+ ## 0.103.0
4
+
5
+ ### Patch Changes
6
+
7
+ - **Fixed:** `Native.fromNode` can now handle `document.adoptedStyleSheets` where `length` property is missing. ([#1786](https://github.com/Siteimprove/alfa/pull/1786))
8
+
9
+ This addresses what is probably incorrect behavior of the `adoptedStyleSheets` in some browser implementations.
10
+
11
+ ## 0.102.0
12
+
13
+ ### Minor Changes
14
+
15
+ - **Added:** `Native.fromNode` returned value now contains a `logs` field, with an array of logs. ([#1781](https://github.com/Siteimprove/alfa/pull/1781))
16
+
17
+ - **Breaking:** The `withCrossOrigin` option of `dom.Native.fromNode` has been renamed `ensureAnonymousCrossOrigin`. ([#1779](https://github.com/Siteimprove/alfa/pull/1779))
18
+
19
+ The old `withCrossOrigin` option is kept as a deprecated legacy alias and will be removed in a later release.
20
+
21
+ The new name better reflects the meaning of the option.
22
+
3
23
  ## 0.101.0
4
24
 
5
25
  ## 0.100.1
package/dist/native.d.ts CHANGED
@@ -1,18 +1,43 @@
1
1
  import type { Attribute, Comment, Document, Element, Node, Text, Type } from "./index.js";
2
+ /**
3
+ * The type of logs.
4
+ *
5
+ * @remarks
6
+ * Each log entry **should** be a JSON stringified object of type
7
+ * \{ level: "debug" | "info" | "warn" | "error", type: string, message: string \}
8
+ * Different types may add more fields to the object.
9
+ *
10
+ * @privateRemarks
11
+ * Given that everything is inlined in one function, it is easier to have a
12
+ * "global" logs array and add to it from any subfunction, rather than merging
13
+ * logs from these.
14
+ */
15
+ type Logs = {
16
+ logs: Array<string>;
17
+ };
2
18
  /**
3
19
  * @internal
4
20
  */
5
21
  export declare namespace Native {
6
- function fromNode(node: globalThis.Element, options?: Options): Promise<Element.JSON>;
7
- function fromNode(node: globalThis.Attr, options?: Options): Promise<Attribute.JSON>;
8
- function fromNode(node: globalThis.Text, options?: Options): Promise<Text.JSON>;
9
- function fromNode(node: globalThis.Comment, options?: Options): Promise<Comment.JSON>;
10
- function fromNode(node?: globalThis.Document, options?: Options): Promise<Document.JSON>;
11
- function fromNode(node: globalThis.DocumentType, options?: Options): Promise<Type.JSON>;
12
- function fromNode(node: globalThis.Node, options?: Options): Promise<Node.JSON>;
22
+ function fromNode(node: globalThis.Element, options?: Options): Promise<Element.JSON & Logs>;
23
+ function fromNode(node: globalThis.Attr, options?: Options): Promise<Attribute.JSON & Logs>;
24
+ function fromNode(node: globalThis.Text, options?: Options): Promise<Text.JSON & Logs>;
25
+ function fromNode(node: globalThis.Comment, options?: Options): Promise<Comment.JSON & Logs>;
26
+ function fromNode(node?: globalThis.Document, options?: Options): Promise<Document.JSON & Logs>;
27
+ function fromNode(node: globalThis.DocumentType, options?: Options): Promise<Type.JSON & Logs>;
28
+ function fromNode(node: globalThis.Node, options?: Options): Promise<Node.JSON & Logs>;
13
29
  interface Options {
14
- /** Whether to enforce anonymous CORS on <link> missing one */
30
+ /**
31
+ * Deprecated, use enforceAnonymousCrossOrigin instead
32
+ *
33
+ * @deprecated
34
+ */
15
35
  withCrossOrigin?: boolean;
36
+ /**
37
+ * Whether to enforce anonymous crossorigin attribute on <link> missing one
38
+ */
39
+ enforceAnonymousCrossOrigin?: boolean;
16
40
  }
17
41
  }
42
+ export {};
18
43
  //# sourceMappingURL=native.d.ts.map
package/dist/native.js CHANGED
@@ -5,9 +5,10 @@
5
5
  export var Native;
6
6
  (function (Native) {
7
7
  async function fromNode(node = globalThis.window.document, options) {
8
- const { withCrossOrigin = false } = options ?? {};
8
+ const logs = [];
9
+ const { withCrossOrigin = false, enforceAnonymousCrossOrigin = withCrossOrigin, } = options ?? {};
9
10
  const range = globalThis.document.createRange(); // Used by toText - the same instance can be reused for each text node.
10
- return toNode(node);
11
+ return { ...(await toNode(node)), logs };
11
12
  async function toNode(node) {
12
13
  switch (node.nodeType) {
13
14
  case node.ELEMENT_NODE:
@@ -72,7 +73,7 @@ export var Native;
72
73
  };
73
74
  }
74
75
  async function toDocument(document) {
75
- if (withCrossOrigin) {
76
+ if (enforceAnonymousCrossOrigin) {
76
77
  await ensureCrossOrigin(document);
77
78
  }
78
79
  return {
@@ -90,7 +91,7 @@ export var Native;
90
91
  };
91
92
  }
92
93
  async function toShadow(shadow) {
93
- if (withCrossOrigin) {
94
+ if (enforceAnonymousCrossOrigin) {
94
95
  await ensureCrossOrigin(document);
95
96
  }
96
97
  return {
@@ -230,14 +231,36 @@ export var Native;
230
231
  };
231
232
  }
232
233
  function toImportRule(rule) {
233
- return {
234
- type: "import",
235
- rules: rule.styleSheet === null ? [] : toSheet(rule.styleSheet).rules,
236
- condition: rule.media.mediaText === "" ? "all" : rule.media.mediaText,
237
- href: rule.href,
238
- supportText: rule.supportsText,
239
- layer: rule.layerName,
240
- };
234
+ try {
235
+ // See https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet#instance_properties
236
+ // While the error may theoretically occur on any style sheet, it seems
237
+ // to be mostly present on @import rules due to CORS policy.
238
+ rule.styleSheet?.cssRules;
239
+ return {
240
+ type: "import",
241
+ rules: rule.styleSheet === null ? [] : toSheet(rule.styleSheet).rules,
242
+ condition: rule.media.mediaText === "" ? "all" : rule.media.mediaText,
243
+ href: rule.href,
244
+ supportText: rule.supportsText,
245
+ layer: rule.layerName,
246
+ };
247
+ }
248
+ catch (e) {
249
+ logs.push(JSON.stringify({
250
+ level: "error",
251
+ type: "import",
252
+ message: `Failed to fetch CSS rules for @import rule at ${rule.href}`,
253
+ originalError: `${e}`,
254
+ }));
255
+ return {
256
+ type: "import",
257
+ rules: [],
258
+ condition: rule.media.mediaText === "" ? "all" : rule.media.mediaText,
259
+ href: rule.href,
260
+ supportText: rule.supportsText,
261
+ layer: rule.layerName,
262
+ };
263
+ }
241
264
  }
242
265
  function toKeyframeRule(rule) {
243
266
  return {
@@ -335,8 +358,8 @@ export var Native;
335
358
  *
336
359
  * {@link https://github.com/Siteimprove/alfa/issues/1563}
337
360
  *
338
- * To circumvent that, we simply return the raw CSS text; and delegate parsing
339
- * to consumers, aka Block.from.
361
+ * To circumvent that, we simply return the raw CSS text; and delegate
362
+ * parsing to consumers, aka Block.from.
340
363
  *
341
364
  * Note that somehow JSDOM behaves differently and correctly associate the
342
365
  * value with the shorthand. This means that the local tests using JSDOM
@@ -355,18 +378,10 @@ export var Native;
355
378
  };
356
379
  }
357
380
  function map(arrayLike, mapper) {
358
- const result = new Array(arrayLike.length);
359
- for (let i = 0, n = arrayLike.length; i < n; i++) {
360
- result[i] = mapper(arrayLike[i]);
361
- }
362
- return result;
381
+ return Array.from(arrayLike, mapper);
363
382
  }
364
383
  async function mapAsync(arrayLike, mapper) {
365
- const result = new Array(arrayLike.length);
366
- for (let i = 0, n = arrayLike.length; i < n; i++) {
367
- result[i] = await mapper(arrayLike[i]);
368
- }
369
- return result;
384
+ return Promise.all(Array.from(arrayLike, mapper));
370
385
  }
371
386
  /**
372
387
  * Ensure that the needed resources for the document or shadow root, such as
@@ -386,8 +401,8 @@ export var Native;
386
401
  for (let i = 0; i < links.length; i++) {
387
402
  const link = links[i];
388
403
  /**
389
- * Skip `<link>` elements for which the `crossorigin` attribute is already
390
- * set to a valid value.
404
+ * Skip `<link>` elements for which the `crossorigin` attribute is
405
+ * already set to a valid value.
391
406
  */
392
407
  if (link.crossOrigin !== null) {
393
408
  continue;
@@ -406,25 +421,25 @@ export var Native;
406
421
  */
407
422
  clone.crossOrigin = "anonymous";
408
423
  /**
409
- * Replace the original `<link>` element with its clone. For style sheets,
410
- * this will unfortunately cause a FOUC while the browser recomputes
411
- * styles.
424
+ * Replace the original `<link>` element with its clone. For style
425
+ * sheets, this will unfortunately cause a FOUC while the browser
426
+ * recomputes styles.
412
427
  *
413
428
  * {@link https://en.wikipedia.org/wiki/Flash_of_unstyled_content}
414
429
  */
415
430
  link.parentNode.replaceChild(clone, link);
416
431
  /**
417
- * While certain resources will load synchronously from cache, others will
418
- * not and we therefore need to await these.
432
+ * While certain resources will load synchronously from cache, others
433
+ * will not and we therefore need to await these.
419
434
  */
420
435
  if (shouldAwait(link)) {
421
436
  /**
422
437
  * Construct a promise that resolves once the `<link>` element either
423
- * loads successfully or fails to load. If the `<link>` element fails to
424
- * load, a request error will be logged to the console which should be
425
- * enough indication that something didn't go quite as expected. Either
426
- * way, we will deliver audit results even in the event of a missing
427
- * resource.
438
+ * loads successfully or fails to load. If the `<link>` element fails
439
+ * to load, a request error will be logged to the console which
440
+ * should be enough indication that something didn't go quite as
441
+ * expected. Either way, we will deliver audit results even in the
442
+ * event of a missing resource.
428
443
  */
429
444
  await new Promise((resolve) => ["load", "error"].forEach((event) => clone.addEventListener(event, () => resolve())));
430
445
  }
@@ -434,8 +449,8 @@ export var Native;
434
449
  */
435
450
  function shouldAwait(link) {
436
451
  /**
437
- * A `<link>` element with an empty `href` will cause the fetch process to
438
- * abort with no events to await.
452
+ * A `<link>` element with an empty `href` will cause the fetch process
453
+ * to abort with no events to await.
439
454
  */
440
455
  if (link.getAttribute("href")?.trim() === "") {
441
456
  return false;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "$schema": "http://json.schemastore.org/package",
3
3
  "name": "@siteimprove/alfa-dom",
4
4
  "homepage": "https://alfa.siteimprove.com",
5
- "version": "0.101.0",
5
+ "version": "0.103.0",
6
6
  "license": "MIT",
7
7
  "description": "Implementations of the core DOM and CSSOM node types",
8
8
  "repository": {
@@ -35,35 +35,35 @@
35
35
  "dist/**/*.d.ts"
36
36
  ],
37
37
  "dependencies": {
38
- "@siteimprove/alfa-array": "^0.101.0",
39
- "@siteimprove/alfa-cache": "^0.101.0",
40
- "@siteimprove/alfa-comparable": "^0.101.0",
41
- "@siteimprove/alfa-css": "^0.101.0",
42
- "@siteimprove/alfa-css-feature": "^0.101.0",
43
- "@siteimprove/alfa-device": "^0.101.0",
44
- "@siteimprove/alfa-earl": "^0.101.0",
45
- "@siteimprove/alfa-equatable": "^0.101.0",
46
- "@siteimprove/alfa-flags": "^0.101.0",
47
- "@siteimprove/alfa-iterable": "^0.101.0",
48
- "@siteimprove/alfa-json": "^0.101.0",
49
- "@siteimprove/alfa-lazy": "^0.101.0",
50
- "@siteimprove/alfa-map": "^0.101.0",
51
- "@siteimprove/alfa-option": "^0.101.0",
52
- "@siteimprove/alfa-parser": "^0.101.0",
53
- "@siteimprove/alfa-predicate": "^0.101.0",
54
- "@siteimprove/alfa-rectangle": "^0.101.0",
55
- "@siteimprove/alfa-refinement": "^0.101.0",
56
- "@siteimprove/alfa-result": "^0.101.0",
57
- "@siteimprove/alfa-sarif": "^0.101.0",
58
- "@siteimprove/alfa-selective": "^0.101.0",
59
- "@siteimprove/alfa-sequence": "^0.101.0",
60
- "@siteimprove/alfa-slice": "^0.101.0",
61
- "@siteimprove/alfa-string": "^0.101.0",
62
- "@siteimprove/alfa-trampoline": "^0.101.0",
63
- "@siteimprove/alfa-tree": "^0.101.0"
38
+ "@siteimprove/alfa-array": "^0.103.0",
39
+ "@siteimprove/alfa-cache": "^0.103.0",
40
+ "@siteimprove/alfa-comparable": "^0.103.0",
41
+ "@siteimprove/alfa-css": "^0.103.0",
42
+ "@siteimprove/alfa-css-feature": "^0.103.0",
43
+ "@siteimprove/alfa-device": "^0.103.0",
44
+ "@siteimprove/alfa-earl": "^0.103.0",
45
+ "@siteimprove/alfa-equatable": "^0.103.0",
46
+ "@siteimprove/alfa-flags": "^0.103.0",
47
+ "@siteimprove/alfa-iterable": "^0.103.0",
48
+ "@siteimprove/alfa-json": "^0.103.0",
49
+ "@siteimprove/alfa-lazy": "^0.103.0",
50
+ "@siteimprove/alfa-map": "^0.103.0",
51
+ "@siteimprove/alfa-option": "^0.103.0",
52
+ "@siteimprove/alfa-parser": "^0.103.0",
53
+ "@siteimprove/alfa-predicate": "^0.103.0",
54
+ "@siteimprove/alfa-rectangle": "^0.103.0",
55
+ "@siteimprove/alfa-refinement": "^0.103.0",
56
+ "@siteimprove/alfa-result": "^0.103.0",
57
+ "@siteimprove/alfa-sarif": "^0.103.0",
58
+ "@siteimprove/alfa-selective": "^0.103.0",
59
+ "@siteimprove/alfa-sequence": "^0.103.0",
60
+ "@siteimprove/alfa-slice": "^0.103.0",
61
+ "@siteimprove/alfa-string": "^0.103.0",
62
+ "@siteimprove/alfa-trampoline": "^0.103.0",
63
+ "@siteimprove/alfa-tree": "^0.103.0"
64
64
  },
65
65
  "devDependencies": {
66
- "@siteimprove/alfa-test": "^0.101.0",
66
+ "@siteimprove/alfa-test": "^0.103.0",
67
67
  "@types/jsdom": "^21.1.6",
68
68
  "jsdom": "^26.0.0"
69
69
  },