Skip to content

Commit 133383e

Browse files
authored
feat(validator): no EnforceRange for readonly attributes (#740)
* feat(validator): no EnforceRange for readonly attributes * full sentence * fmt * apply feedback
1 parent f5cb0e0 commit 133383e

File tree

4 files changed

+84
-30
lines changed

4 files changed

+84
-30
lines changed

lib/productions/attribute.js

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { validationError } from "../error.js";
2-
import { idlTypeIncludesDictionary } from "../validators/helpers.js";
2+
import {
3+
idlTypeIncludesDictionary,
4+
idlTypeIncludesEnforceRange,
5+
} from "../validators/helpers.js";
36
import { Base } from "./base.js";
47
import {
58
type_with_extended_attributes,
@@ -72,32 +75,32 @@ export class Attribute extends Base {
7275
yield* this.extAttrs.validate(defs);
7376
yield* this.idlType.validate(defs);
7477

75-
switch (this.idlType.generic) {
76-
case "sequence":
77-
case "record": {
78-
const message = `Attributes cannot accept ${this.idlType.generic} types.`;
79-
yield validationError(
80-
this.tokens.name,
81-
this,
82-
"attr-invalid-type",
83-
message
84-
);
85-
break;
78+
if (["sequence", "record"].includes(this.idlType.generic)) {
79+
const message = `Attributes cannot accept ${this.idlType.generic} types.`;
80+
yield validationError(
81+
this.tokens.name,
82+
this,
83+
"attr-invalid-type",
84+
message
85+
);
86+
}
87+
88+
{
89+
const { reference } = idlTypeIncludesDictionary(this.idlType, defs) || {};
90+
if (reference) {
91+
const targetToken = (this.idlType.union ? reference : this.idlType)
92+
.tokens.base;
93+
const message = "Attributes cannot accept dictionary types.";
94+
yield validationError(targetToken, this, "attr-invalid-type", message);
8695
}
87-
default: {
88-
const { reference } =
89-
idlTypeIncludesDictionary(this.idlType, defs) || {};
90-
if (reference) {
91-
const targetToken = (this.idlType.union ? reference : this.idlType)
92-
.tokens.base;
93-
const message = "Attributes cannot accept dictionary types.";
94-
yield validationError(
95-
targetToken,
96-
this,
97-
"attr-invalid-type",
98-
message
99-
);
100-
}
96+
}
97+
98+
if (this.readonly) {
99+
if (idlTypeIncludesEnforceRange(this.idlType, defs)) {
100+
const targetToken = this.idlType.tokens.base;
101+
const message =
102+
"Readonly attributes cannot accept [EnforceRange] extended attribute.";
103+
yield validationError(targetToken, this, "attr-invalid-type", message);
101104
}
102105
}
103106
}

lib/validators/helpers.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/**
2+
* @typedef {import("../validator.js").Definitions} Definitions
23
* @typedef {import("../productions/dictionary.js").Dictionary} Dictionary
4+
* @typedef {import("../../lib/productions/type").Type} Type
35
*
4-
* @param {*} idlType
5-
* @param {import("../validator.js").Definitions} defs
6+
* @param {Type} idlType
7+
* @param {Definitions} defs
68
* @param {object} [options]
79
* @param {boolean} [options.useNullableInner] use when the input idlType is nullable and you want to use its inner type
810
* @return {{ reference: *, dictionary: Dictionary }} the type reference that ultimately includes dictionary.
@@ -56,8 +58,8 @@ export function idlTypeIncludesDictionary(
5658
}
5759

5860
/**
59-
* @param {*} dict dictionary type
60-
* @param {import("../validator.js").Definitions} defs
61+
* @param {Dictionary} dict dictionary type
62+
* @param {Definitions} defs
6163
* @return {boolean}
6264
*/
6365
export function dictionaryIncludesRequiredField(dict, defs) {
@@ -80,3 +82,31 @@ export function dictionaryIncludesRequiredField(dict, defs) {
8082
defs.cache.dictionaryIncludesRequiredField.set(dict, result);
8183
return result;
8284
}
85+
86+
/**
87+
* For now this only checks the most frequent cases:
88+
* 1. direct inclusion of [EnforceRange]
89+
* 2. typedef of that
90+
*
91+
* More complex cases with dictionaries and records are not covered yet.
92+
*
93+
* @param {Type} idlType
94+
* @param {Definitions} defs
95+
*/
96+
export function idlTypeIncludesEnforceRange(idlType, defs) {
97+
if (idlType.union) {
98+
// TODO: This should ideally be checked too
99+
return false;
100+
}
101+
102+
if (idlType.extAttrs.some((e) => e.name === "EnforceRange")) {
103+
return true;
104+
}
105+
106+
const def = defs.unique.get(idlType.idlType);
107+
if (def?.type !== "typedef") {
108+
return false;
109+
}
110+
111+
return def.idlType.extAttrs.some((e) => e.name === "EnforceRange");
112+
}

test/invalid/baseline/invalid-attribute.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@
1010
(attr-invalid-type) Validation error at line 18 in invalid-attribute.webidl, inside `interface dictionaryAsAttribute -> attribute dictUnion`:
1111
attribute (Dict or boolean) dictUnion
1212
^ Attributes cannot accept dictionary types.
13+
(attr-invalid-type) Validation error at line 28 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr1`:
14+
readonly attribute [EnforceRange] long readOnlyAttr1;
15+
^ Readonly attributes cannot accept [EnforceRange] extended attribute.
16+
(attr-invalid-type) Validation error at line 29 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr2`:
17+
readonly attribute [EnforceRange] GPUInt32In readOnlyAttr2;
18+
^ Readonly attributes cannot accept [EnforceRange] extended attribute.
19+
(attr-invalid-type) Validation error at line 30 in invalid-attribute.webidl, inside `interface EnforceRangeInReadonlyAttribute -> attribute readOnlyAttr2`:
20+
readonly attribute GPUInt32 readOnlyAttr2;
21+
^ Readonly attributes cannot accept [EnforceRange] extended attribute.

test/invalid/idl/invalid-attribute.webidl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,15 @@ interface dictionaryAsAttribute {
1717
attribute Dict dict;
1818
attribute (Dict or boolean) dictUnion;
1919
};
20+
21+
typedef [EnforceRange] long GPUInt32;
22+
typedef long GPUInt32In;
23+
24+
[Exposed=Window]
25+
interface EnforceRangeInReadonlyAttribute {
26+
attribute [EnforceRange] long noProblem;
27+
28+
readonly attribute [EnforceRange] long readOnlyAttr1;
29+
readonly attribute [EnforceRange] GPUInt32In readOnlyAttr2;
30+
readonly attribute GPUInt32 readOnlyAttr2;
31+
};

0 commit comments

Comments
 (0)