Socket
Socket
Sign inDemoInstall

webidl2js

Package Overview
Dependencies
Maintainers
2
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

webidl2js - npm Package Compare versions

Comparing version 7.2.0 to 7.3.0

README.md

18

lib/constructs/attribute.js

@@ -19,3 +19,3 @@ "use strict";

let str = "";
const requires = {};
const requires = new utils.RequiresMap(this.ctx);

@@ -32,2 +32,7 @@ const configurable = !utils.getExtAttr(this.idl.extAttrs, "Unforgeable");

}
let brandCheck = `
if (!this || !module.exports.is(this)) {
throw new TypeError("Illegal invocation");
}
`;
let getterBody = `return utils.tryWrapperForImpl(${objName}[impl]["${this.idl.name}"]);`;

@@ -40,2 +45,3 @@ let setterBody = `${objName}[impl]["${this.idl.name}"] = V;`;

if (this.idl.static) {
brandCheck = "";
getterBody = `return Impl["${this.idl.name}"];`;

@@ -52,2 +58,6 @@ setterBody = `Impl["${this.idl.name}"] = V;`;

if (utils.getExtAttr(this.idl.extAttrs, "LenientThis")) {
brandCheck = "";
}
if (sameObject) {

@@ -60,2 +70,3 @@ getterBody = `return utils.getSameObject(this, "${this.idl.name}", () => { ${getterBody} });`;

get() {
${brandCheck}
${getterBody}

@@ -68,5 +79,6 @@ },

`"Failed to set the '${this.idl.name}' property on '${this.interface.name}': The provided value"`);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);
str += `
set(V) {
${brandCheck}
${conv.body}

@@ -79,2 +91,3 @@ ${setterBody}

set(V) {
${brandCheck}
this.${this.idl.name}.${utils.getExtAttr(this.idl.extAttrs, "PutForwards").rhs.value} = V;

@@ -86,2 +99,3 @@ },

set(V) {
${brandCheck}
Object.defineProperty(this, "${this.idl.name}", {

@@ -88,0 +102,0 @@ configurable: true,

4

lib/constructs/constant.js
"use strict";
const utils = require("../utils");
class Constant {

@@ -25,3 +27,3 @@ constructor(ctx, obj, I, idl) {

return {
requires: {},
requires: new utils.RequiresMap(this.ctx),
body

@@ -28,0 +30,0 @@ };

@@ -12,3 +12,3 @@ "use strict";

this.requires = {};
this.requires = new utils.RequiresMap(ctx);
}

@@ -38,3 +38,3 @@

this.ctx, "value", typeConversion, argAttrs, this.name, `context + " has member ${field.name} that"`);
Object.assign(this.requires, conv.requires);
this.requires.merge(conv.requires);

@@ -102,6 +102,6 @@ str += `

if (this.idl.inheritance) {
this.requires[this.idl.inheritance] = `require("./${this.idl.inheritance}")`;
this.requires.add(this.idl.inheritance);
}
this.str = `
${Object.keys(this.requires).map(key => `const ${key} = ${this.requires[key]};`).join("\n")}
${this.requires.generate()}

@@ -108,0 +108,0 @@ ${this.str}

@@ -8,2 +8,3 @@ "use strict";

const Operation = require("./operation");
const Types = require("../types");
const Overloads = require("../overloads");

@@ -13,2 +14,12 @@ const Parameters = require("../parameters");

// Used as a sentinel in inheritedMembers to signify that the following members are inherited.
const inherited = Symbol("inherited");
function isNamed(idl) {
return idl.arguments[0].idlType.idlType === "DOMString";
}
function isIndexed(idl) {
return idl.arguments[0].idlType.idlType === "unsigned long";
}
class Interface {

@@ -21,12 +32,182 @@ constructor(ctx, idl, opts) {

this.mixins = [];
this.requires = {};
this.str = null;
this.opts = opts;
this.requires = new utils.RequiresMap(ctx);
this.mixins = [];
this.operations = new Map();
this.attributes = new Map();
this.constants = new Map();
this.indexedGetter = null;
this.indexedSetter = null;
this.namedGetter = null;
this.namedSetter = null;
this.namedDeleter = null;
this.iterable = null;
this._analyzed = false;
}
get hasPairIterator() {
return this.idl.members.some(utils.isPairIterable);
_analyzeMembers() {
let definingInterface = null;
for (const member of this.inheritedMembers()) {
if (member[0] === inherited) {
definingInterface = member[1];
continue;
}
if (!definingInterface) {
switch (member.type) {
case "operation": {
let name = member.name;
if (name === null && member.stringifier) {
name = "toString";
}
if (name !== null && !this.operations.has(name)) {
this.operations.set(name, new Operation(this.ctx, this, this.idl, member));
}
break;
}
case "attribute":
this.attributes.set(member.name, new Attribute(this.ctx, this, this.idl, member));
break;
case "const":
this.constants.set(member.name, new Constant(this.ctx, this, this.idl, member));
break;
case "iterable":
if (this.iterable) {
throw new Error(`Interface ${this.name} has more than one iterable declaration`);
}
this.iterable = new Iterable(this.ctx, this, this.idl, member);
break;
default:
if (!this.ctx.options.suppressErrors) {
throw new Error(`Unknown IDL member type "${member.type}" in interface ${this.name}`);
}
}
} else {
switch (member.type) {
case "iterable":
if (this.iterable) {
throw new Error(`Iterable interface ${this.name} inherits from another iterable interface ` +
`${definingInterface}`);
}
break;
}
}
if (member.type === "operation") {
if (member.getter) {
let msg = `Invalid getter ${member.name ? `"${member.name}" ` : ""}on interface ${this.name}`;
if (definingInterface) {
msg += ` (defined in ${definingInterface})`;
}
msg += ": ";
if (member.arguments.length < 1 ||
(!this.ctx.options.suppressErrors && member.arguments.length !== 1)) {
throw new Error(msg + `1 argument should be present, found ${member.arguments.length}`);
}
if (isIndexed(member)) {
if (!this.ctx.options.suppressErrors && this.indexedGetter) {
throw new Error(msg + "duplicated indexed getter");
}
this.indexedGetter = member;
} else if (isNamed(member)) {
if (!this.ctx.options.suppressErrors && this.namedGetter) {
throw new Error(msg + "duplicated named getter");
}
this.namedGetter = member;
} else {
throw new Error(msg + "getter is neither indexed nor named");
}
}
if (member.setter) {
let msg = `Invalid setter ${member.name ? `"${member.name}" ` : ""}on interface ${this.name}`;
if (definingInterface) {
msg += ` (defined in ${definingInterface})`;
}
msg += ": ";
if (member.arguments.length < 2 ||
(!this.ctx.options.suppressErrors && member.arguments.length !== 2)) {
throw new Error(msg + `2 arguments should be present, found ${member.arguments.length}`);
}
if (isIndexed(member)) {
if (!this.ctx.options.suppressErrors && this.indexedSetter) {
throw new Error(msg + "duplicated indexed setter");
}
this.indexedSetter = member;
} else if (isNamed(member)) {
if (!this.ctx.options.suppressErrors && this.namedSetter) {
throw new Error(msg + "duplicated named setter");
}
this.namedSetter = member;
} else {
throw new Error(msg + "setter is neither indexed nor named");
}
}
if (member.deleter) {
let msg = `Invalid deleter ${member.name ? `"${member.name}" ` : ""}on interface ${this.name}`;
if (definingInterface) {
msg += ` (defined in ${definingInterface})`;
}
msg += ": ";
if (member.arguments.length < 1 ||
(!this.ctx.options.suppressErrors && member.arguments.length !== 1)) {
throw new Error(msg + `1 arguments should be present, found ${member.arguments.length}`);
}
if (isNamed(member)) {
if (!this.ctx.options.suppressErrors && this.namedDeleter) {
throw new Error(msg + "duplicated named deleter");
}
this.namedDeleter = member;
} else {
throw new Error(msg + "deleter is not named");
}
}
}
}
const forbiddenMembers = new Set();
if (this.iterable) {
if (this.iterable.isValue) {
if (!this.supportsIndexedProperties) {
throw new Error(`A value iterator cannot be declared on ${this.name} which does not support indexed ` +
"properties");
}
} else if (this.iterable.isPair && this.supportsIndexedProperties) {
throw new Error(`A pair iterator cannot be declared on ${this.name} which supports indexed properties`);
}
for (const n of ["entries", "forEach", "keys", "values"]) {
forbiddenMembers.add(n);
}
}
definingInterface = null;
for (const member of this.inheritedMembers()) {
if (member[0] === inherited) {
definingInterface = member[1];
continue;
}
if (forbiddenMembers.has(member.name)) {
let msg = `${member.name} is forbidden in interface ${this.name}`;
if (definingInterface) {
msg += ` (defined in ${definingInterface})`;
}
throw new Error(msg);
}
}
}
get supportsIndexedProperties() {
return this.indexedGetter !== null;
}
get supportsNamedProperties() {
return this.namedGetter !== null;
}
get isLegacyPlatformObj() {
return !utils.isGlobal(this.idl) && (this.supportsIndexedProperties || this.supportsNamedProperties);
}
implements(source) {

@@ -37,3 +218,3 @@ this.mixins.push(source);

generateIterator() {
if (this.hasPairIterator) {
if (this.iterable && this.iterable.isPair) {
this.str += `

@@ -98,3 +279,3 @@ const IteratorPrototype = Object.create(utils.IteratorPrototype, {

Parameters.generateOverloadConversions(this.ctx, overloads, this.name, `Failed to construct '${this.name}': `);
Object.assign(this.requires, conversions.requires);
this.requires.merge(conversions.requires);

@@ -138,2 +319,6 @@ minConstructor.nameList = minConstructor.nameList.map(name => (keywords.has(name) ? "_" : "") + name);

`;
} else if (utils.getExtAttr(this.idl.extAttrs, "LegacyArrayClass")) {
this.str += `
Object.setPrototypeOf(${this.name}.prototype, Array.prototype);
`;
}

@@ -151,13 +336,23 @@

* inheritedMembers() {
yield* this.idl.members;
for (const iface of [...this.mixins, this.idl.inheritance]) {
if (this.ctx.interfaces.has(iface)) {
yield [inherited, iface];
yield* this.ctx.interfaces.get(iface).inheritedMembers();
}
}
}
generateRequires() {
this.requires.impl = "utils.implSymbol";
this.requires.addRaw("impl", "utils.implSymbol");
if (this.idl.inheritance !== null) {
this.requires[this.idl.inheritance] = `require("./${this.idl.inheritance}.js")`;
this.requires.add(this.idl.inheritance);
}
if (this.mixins.length !== 0) {
this.requires.mixin = "utils.mixin";
this.requires.addRaw("mixin", "utils.mixin");
for (const mixin of this.mixins) {
this.requires[mixin] = `require("./${mixin}.js")`;
this.requires.add(mixin);
}

@@ -167,3 +362,3 @@ }

this.str = `
${Object.keys(this.requires).map(key => `const ${key} = ${this.requires[key]};`).join("\n")}
${this.requires.generate()}

@@ -222,3 +417,3 @@ ${this.str}

if (this.hasPairIterator) {
if (this.iterable && this.iterable.isPair) {
this.str += `

@@ -239,2 +434,523 @@ createDefaultIterator(target, kind) {

generateLegacyProxy() {
const hasIndexedSetter = this.indexedSetter !== null;
const hasNamedSetter = this.namedSetter !== null;
const hasNamedDeleter = this.namedDeleter !== null;
const overrideBuiltins = Boolean(utils.getExtAttr(this.idl.extAttrs, "OverrideBuiltins"));
const supportsPropertyIndex = (O, index, indexedValue) => {
let unsupportedValue = utils.getExtAttr(this.indexedGetter.extAttrs, "WebIDL2JSValueAsUnsupported");
if (unsupportedValue) {
unsupportedValue = unsupportedValue.rhs.value;
}
if (unsupportedValue) {
const func = this.indexedGetter.name !== null ? `.${this.indexedGetter.name}` : "[utils.indexedGet]";
const value = indexedValue || `${O}[impl]${func}(${index})`;
return `${value} !== ${unsupportedValue}`;
}
return `${O}[impl][utils.supportsPropertyIndex](${index})`;
};
const supportsPropertyName = (O, P, namedValue) => {
let unsupportedValue = utils.getExtAttr(this.namedGetter.extAttrs, "WebIDL2JSValueAsUnsupported");
if (unsupportedValue) {
unsupportedValue = unsupportedValue.rhs.value;
}
if (unsupportedValue) {
const func = this.namedGetter.name !== null ? `.${this.namedGetter.name}` : "[utils.namedGet]";
const value = namedValue || `${O}[impl]${func}(${P})`;
return `${value} !== ${unsupportedValue}`;
}
return `${O}[impl][utils.supportsPropertyName](${P})`;
};
// "named property visibility algorithm"
// If `supports` is true then skip the supportsPropertyName check.
function namedPropertyVisible(P, O, supports = false) {
const conditions = [];
if (!supports) {
conditions.push(supportsPropertyName(O, P));
}
if (overrideBuiltins) {
conditions.push(`!Object.prototype.hasOwnProperty.call(${O}, ${P})`);
} else {
// TODO: create a named properties object.
conditions.push(`!(${P} in ${O})`);
}
return conditions.join(" && ");
}
// "invoke an indexed property setter"
const invokeIndexedSetter = (O, P, V) => {
const arg = this.indexedSetter.arguments[1];
const conv = Types.generateTypeConversion(
this.ctx, "indexedValue", arg.idlType, arg.extAttrs, this.name,
`"Failed to set the " + index + " property on '${this.name}': The provided value"`);
this.requires.merge(conv.requires);
let str = `
const index = ${P} >>> 0;
let indexedValue = ${V};
${conv.body}
`;
if (this.indexedSetter.name === null) {
str += `
const creating = !(${supportsPropertyIndex(O, "index")});
if (creating) {
${O}[impl][utils.indexedSetNew](index, indexedValue);
} else {
${O}[impl][utils.indexedSetExisting](index, indexedValue);
}
`;
} else {
str += `
${O}[impl].${this.indexedSetter.name}(index, indexedValue);
`;
}
return str;
};
// "invoke a named property setter"
const invokeNamedSetter = (O, P, V) => {
const arg = this.namedSetter.arguments[1];
const conv = Types.generateTypeConversion(
this.ctx, "namedValue", arg.idlType, arg.extAttrs, this.name,
`"Failed to set the '" + ${P} + "' property on '${this.name}': The provided value"`);
this.requires.merge(conv.requires);
let str = `
let namedValue = ${V};
${conv.body}
`;
if (this.namedSetter.name === null) {
str += `
const creating = !(${supportsPropertyName(O, P)});
if (creating) {
${O}[impl][utils.namedSetNew](${P}, namedValue);
} else {
${O}[impl][utils.namedSetExisting](${P}, namedValue);
}
`;
} else {
str += `
${O}[impl].${this.namedSetter.name}(${P}, namedValue);
`;
}
return str;
};
this.str += `
obj = new Proxy(obj, {
`;
// [[Get]] (necessary because of proxy semantics)
this.str += `
get(target, P, receiver) {
if (typeof P === "symbol") {
return Reflect.get(target, P, receiver);
}
const desc = this.getOwnPropertyDescriptor(target, P);
if (desc === undefined) {
const parent = Object.getPrototypeOf(target);
if (parent === null) {
return undefined;
}
return Reflect.get(target, P, receiver);
}
if (!desc.get && !desc.set) {
return desc.value;
}
const getter = desc.get;
if (getter === undefined) {
return undefined;
}
return Reflect.apply(getter, receiver, []);
},
`;
// [[HasProperty]] (necessary because of proxy semantics)
this.str += `
has(target, P) {
if (typeof P === "symbol") {
return Reflect.has(target, P);
}
const desc = this.getOwnPropertyDescriptor(target, P);
if (desc !== undefined) {
return true;
}
const parent = Object.getPrototypeOf(target);
if (parent !== null) {
return Reflect.has(parent, P);
}
return false;
},
`;
// [[OwnPropertyKeys]]
// Loosely defined by https://heycam.github.io/webidl/#legacy-platform-object-property-enumeration, but with finer
// points tuned according to Firefox until https://github.com/heycam/webidl/issues/400 is resolved.
this.str += `
ownKeys(target) {
const keys = new Set();
`;
if (this.supportsIndexedProperties) {
this.str += `
for (const key of target[impl][utils.supportedPropertyIndices]) {
keys.add(\`\${key}\`);
}
`;
}
if (this.supportsNamedProperties) {
this.str += `
for (const key of target[impl][utils.supportedPropertyNames]) {
if (${namedPropertyVisible("key", "target", true)}) {
keys.add(\`\${key}\`);
}
}
`;
}
this.str += `
for (const key of Reflect.ownKeys(target)) {
keys.add(key);
}
return [...keys];
},
`;
// [[GetOwnProperty]]
this.str += `
getOwnPropertyDescriptor(target, P) {
if (typeof P === "symbol") {
return Reflect.getOwnPropertyDescriptor(target, P);
}
let ignoreNamedProps = false;
`;
if (this.supportsIndexedProperties) {
this.str += `
if (utils.isArrayIndexPropName(P)) {
const index = P >>> 0;
`;
const func = this.indexedGetter.name !== null ? `.${this.indexedGetter.name}` : "[utils.indexedGet]";
let preamble = "";
let condition;
if (utils.getExtAttr(this.indexedGetter.extAttrs, "WebIDL2JSValueAsUnsupported")) {
this.str += `const indexedValue = target[impl]${func}(index);`;
condition = supportsPropertyIndex("target", "index", "indexedValue");
} else {
preamble = `const indexedValue = target[impl]${func}(index);`;
condition = supportsPropertyIndex("target", "index");
}
this.str += `
if (${condition}) {
${preamble}
return {
writable: ${hasIndexedSetter},
enumerable: true,
configurable: true,
value: utils.tryWrapperForImpl(indexedValue)
};
}
ignoreNamedProps = true;
}
`;
}
if (this.supportsNamedProperties) {
const func = this.namedGetter.name !== null ? `.${this.namedGetter.name}` : "[utils.namedGet]";
const enumerable = !utils.getExtAttr(this.idl.extAttrs, "LegacyUnenumerableNamedProperties");
let preamble = "";
const conditions = [];
if (utils.getExtAttr(this.namedGetter.extAttrs, "WebIDL2JSValueAsUnsupported")) {
this.str += `
const namedValue = target[impl]${func}(P);
`;
conditions.push(supportsPropertyName("target", "index", "namedValue"));
conditions.push(namedPropertyVisible("P", "target", true));
} else {
preamble = `
const namedValue = target[impl]${func}(P);
`;
conditions.push(namedPropertyVisible("P", "target", false));
}
conditions.push("!ignoreNamedProps");
this.str += `
if (${conditions.join(" && ")}) {
${preamble}
return {
writable: ${hasNamedSetter},
enumerable: ${enumerable},
configurable: true,
value: utils.tryWrapperForImpl(namedValue)
};
}
`;
}
this.str += `
return Reflect.getOwnPropertyDescriptor(target, P);
},
`;
// [[Set]]
this.str += `
set(target, P, V, receiver) {
if (typeof P === "symbol") {
return Reflect.set(target, P, V, receiver);
}
if (target === receiver) {
`;
if (this.supportsIndexedProperties) {
if (hasIndexedSetter) {
this.str += `
if (utils.isArrayIndexPropName(P)) {
${invokeIndexedSetter("target", "P", "V")}
return true;
}
`;
} else {
// Side-effects
this.str += `
utils.isArrayIndexPropName(P);
`;
}
}
if (this.supportsNamedProperties) {
if (hasNamedSetter) {
this.str += `
if (typeof P === "string" && !utils.isArrayIndexPropName(P)) {
${invokeNamedSetter("target", "P", "V")}
return true;
}
`;
} else {
// Side-effects
this.str += `
typeof P === "string" && !utils.isArrayIndexPropName(P);
`;
}
}
this.str += `
}
let ownDesc;
`;
if (this.supportsIndexedProperties) {
this.str += `
if (utils.isArrayIndexPropName(P)) {
const index = P >>> 0;
`;
const func = this.indexedGetter.name !== null ? `.${this.indexedGetter.name}` : "[utils.indexedGet]";
let preamble = "";
let condition;
if (utils.getExtAttr(this.indexedGetter.extAttrs, "WebIDL2JSValueAsUnsupported")) {
this.str += `const indexedValue = target[impl]${func}(index);`;
condition = supportsPropertyIndex("target", "index", "indexedValue");
} else {
preamble = `const indexedValue = target[impl]${func}(index);`;
condition = supportsPropertyIndex("target", "index");
}
this.str += `
if (${condition}) {
${preamble}
ownDesc = {
writable: ${hasIndexedSetter},
enumerable: true,
configurable: true,
value: utils.tryWrapperForImpl(indexedValue)
};
}
}
`;
}
this.str += `
if (ownDesc === undefined) {
ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
}
if (ownDesc === undefined) {
const parent = Reflect.getPrototypeOf(target);
if (parent !== null) {
return Reflect.set(parent, P, V, receiver);
}
ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
}
if (!ownDesc.writable) {
return false;
}
if (!utils.isObject(receiver)) {
return false;
}
const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
let valueDesc;
if (existingDesc !== undefined) {
if (existingDesc.get || existingDesc.set) {
return false;
}
if (!existingDesc.writable) {
return false;
}
valueDesc = { value: V };
} else {
valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
}
return Reflect.defineProperty(receiver, P, valueDesc);
},
`;
// [[DefineOwnProperty]]
this.str += `
defineProperty(target, P, desc) {
if (typeof P === "symbol") {
return Reflect.defineProperty(target, P, desc);
}
`;
if (this.supportsIndexedProperties) {
this.str += `
if (utils.isArrayIndexPropName(P)) {
`;
if (hasIndexedSetter) {
this.str += `
if (desc.get || desc.set) {
return false;
}
${invokeIndexedSetter("target", "P", "desc.value")}
return true;
`;
} else {
this.str += `
return false;
`;
}
this.str += `
}
`;
}
let needFallback = false;
if (this.supportsNamedProperties && !utils.isGlobal(this.idl)) {
const unforgeable = new Set();
for (const m of this.inheritedMembers()) {
if (m[0] === inherited) {
continue;
}
if ((m.type === "attribute" || m.type === "operation") && !m.static &&
utils.getExtAttr(m.extAttrs, "Unforgeable")) {
unforgeable.add(m.name);
}
}
if (unforgeable.size > 0) {
needFallback = true;
this.str += `if (!${JSON.stringify([...unforgeable])}.includes(P)) {`;
}
if (!overrideBuiltins) {
needFallback = true;
this.str += "if (!Object.prototype.hasOwnProperty.call(target, P)) {";
}
if (!hasNamedSetter) {
needFallback = true;
this.str += `
const creating = !(${supportsPropertyName("target", "P")});
if (!creating) {
return false;
}
`;
} else {
this.str += `
if (desc.get || desc.set) {
return false;
}
${invokeNamedSetter("target", "P", "desc.value")}
return true;
`;
}
if (!overrideBuiltins) {
this.str += "}";
}
if (unforgeable.size > 0) {
this.str += "}";
}
} else {
needFallback = true;
}
if (needFallback) {
// Spec says to set configurable to true, but doing so will make Proxy's trap throw and also fail WPT.
// if (!utils.isGlobal(this.idl)) {
// this.str += `
// desc.configurable = true;
// `;
// }
this.str += `
return Reflect.defineProperty(target, P, desc);
`;
}
this.str += `
},
`;
// [[Delete]]
this.str += `
deleteProperty(target, P) {
if (typeof P === "symbol") {
return Reflect.deleteProperty(target, P);
}
`;
if (this.supportsIndexedProperties) {
this.str += `
if (utils.isArrayIndexPropName(P)) {
const index = P >>> 0;
return !(${supportsPropertyIndex("target", "index")});
}
`;
}
if (this.supportsNamedProperties && !utils.isGlobal(this.idl)) {
this.str += `
if (${namedPropertyVisible("P", "target")}) {
`;
if (!hasNamedDeleter) {
this.str += `
return false;
`;
} else {
const func = this.namedDeleter.name !== null ? `.${this.namedDeleter.name}` : "[utils.namedDelete]";
if (this.namedDeleter.idlType.idlType === "bool") {
this.str += `
return target[impl]${func}(P);
`;
} else {
this.str += `
target[impl]${func}(P);
return true;
`;
}
}
this.str += `
}
`;
}
this.str += `
return Reflect.deleteProperty(target, P);
},
`;
// TODO: Implement [[Call]] / legacycallers.
// [[PreventExtensions]]
this.str += `
preventExtensions() {
return false;
}
`;
this.str += `
});
`;
}
generateIface() {

@@ -267,8 +983,6 @@ const shouldExposeRoot = !utils.getExtAttr(this.idl.extAttrs, "NoInterfaceObject");

// since we don't have spread arg calls, we can't do new Interface(...arguments) yet
// add initialized symbol as to not destroy the object shape and cause deopts
this.str += `
create(constructorArgs, privateData) {
let obj = Object.create(${this.name}.prototype);
this.setup(obj, constructorArgs, privateData);
obj = this.setup(obj, constructorArgs, privateData);
return obj;

@@ -278,3 +992,3 @@ },

let obj = Object.create(${this.name}.prototype);
this.setup(obj, constructorArgs, privateData);
obj = this.setup(obj, constructorArgs, privateData);
return utils.implForWrapper(obj);

@@ -291,21 +1005,7 @@ },

for (let i = 0; i < this.idl.members.length; ++i) {
const memberIdl = this.idl.members[i];
if (utils.isOnInstance(memberIdl, this.idl)) {
let member;
switch (memberIdl.type) {
case "operation": {
member = new Operation(this.ctx, this, this.idl, memberIdl);
break;
}
case "attribute": {
member = new Attribute(this.ctx, this, this.idl, memberIdl);
break;
}
default: {
throw new Error("Cannot handle on-instance members that are not operations or attributes");
}
}
this.str += member.generate().body;
for (const member of [...this.operations.values(), ...this.attributes.values()]) {
if (utils.isOnInstance(member.idl, this.idl)) {
const data = member.generate();
this.requires.merge(data.requires);
this.str += data.body;
}

@@ -340,2 +1040,9 @@ }

});
`;
if (this.isLegacyPlatformObj) {
this.generateLegacyProxy();
}
this.str += `
obj[impl][utils.wrapperSymbol] = obj;

@@ -345,2 +1052,3 @@ if (Impl.init) {

}
return obj;
},

@@ -355,62 +1063,91 @@ interface: ${this.name},

generateOperations() {
const done = {};
for (let i = 0; i < this.idl.members.length; ++i) {
const memberIdl = this.idl.members[i];
let member = null;
// TODO maplike setlike
// Don't bother checking "length" attribute as interfaces that support indexed properties must implement one.
// "Has value iterator" implies "supports indexed properties".
if (this.supportsIndexedProperties || this.iterable && this.iterable.isPair) {
let expr;
switch (memberIdl.type) {
case "operation":
if (utils.isOnInstance(memberIdl, this.idl)) {
break;
if (this.supportsIndexedProperties) {
expr = "Array.prototype[Symbol.iterator]";
} else {
expr = `
function entries() {
if (!this || !module.exports.is(this)) {
throw new TypeError("Illegal invocation");
}
return module.exports.createDefaultIterator(this, "key+value");
}
member = new Operation(this.ctx, this, this.idl, memberIdl);
if (done[member.name]) {
continue;
}
done[member.name] = true;
break;
case "iterable":
member = new Iterable(this.ctx, this, this.idl, memberIdl);
break;
default:
// throw new Error("Can't handle member of type '" + memberIdl.type + "'");
break;
`;
}
if (member !== null) {
const data = member.generate();
Object.assign(this.requires, data.requires);
this.str += data.body;
}
this.str += `
Object.defineProperty(${this.name}.prototype, Symbol.iterator, {
writable: true,
enumerable: false,
configurable: true,
value: ${expr}
});
`;
}
}
generateAttributes() {
for (let i = 0; i < this.idl.members.length; ++i) {
const memberIdl = this.idl.members[i];
let member = null;
if (this.iterable) {
let expr;
switch (memberIdl.type) {
case "attribute":
if (utils.isOnInstance(memberIdl, this.idl)) {
break;
if (this.iterable.isValue) {
expr = "Array.prototype.forEach";
} else {
expr = `
function forEach(callback) {
if (!this || !module.exports.is(this)) {
throw new TypeError("Illegal invocation");
}
if (arguments.length < 1) {
throw new TypeError("Failed to execute 'forEach' on '${this.name}': 1 argument required, " +
"but only 0 present.");
}
if (typeof callback !== "function") {
throw new TypeError("Failed to execute 'forEach' on '${this.name}': The callback provided " +
"as parameter 1 is not a function.");
}
const thisArg = arguments[1];
let pairs = Array.from(this[impl]);
let i = 0;
while (i < pairs.length) {
const [key, value] = pairs[i].map(utils.tryWrapperForImpl);
callback.call(thisArg, value, key, this);
pairs = Array.from(this[impl]);
i++;
}
}
member = new Attribute(this.ctx, this, this.idl, memberIdl);
break;
case "const":
member = new Constant(this.ctx, this, this.idl, memberIdl);
break;
default:
// throw new Error("Can't handle member of type '" + memberIdl.type + "'");
break;
`;
}
if (member !== null) {
this.str += `${this.name}.prototype.forEach = ${expr};`;
}
for (const member of this.operations.values()) {
if (!utils.isOnInstance(member.idl, this.idl)) {
const data = member.generate();
Object.assign(this.requires, data.requires);
this.requires.merge(data.requires);
this.str += data.body;
}
}
if (this.iterable) {
const data = this.iterable.generate();
this.requires.merge(data.requires);
this.str += data.body;
}
}
generateAttributes() {
for (const member of [...this.attributes.values(), ...this.constants.values()]) {
if (member instanceof Attribute && utils.isOnInstance(member.idl, this.idl)) {
continue;
}
const data = member.generate();
this.requires.merge(data.requires);
this.str += data.body;
}
}
generateSymbols() {

@@ -460,4 +1197,2 @@ const unscopables = Object.create(null);

this.generateRequires();
this.generateSymbols();

@@ -488,2 +1223,4 @@

}
this.generateRequires();
}

@@ -493,2 +1230,6 @@

this.str = "";
if (!this._analyzed) {
this._analyzed = true;
this._analyzeMembers();
}
this.generate();

@@ -495,0 +1236,0 @@ return this.str;

@@ -15,2 +15,10 @@ "use strict";

get isValue() {
return !Array.isArray(this.idl.idlType);
}
get isPair() {
return Array.isArray(this.idl.idlType) && this.idl.idlType.length === 2;
}
generateFunction(key, kind, keyExpr, fnName) {

@@ -38,40 +46,20 @@ if (fnName === undefined) {

generate() {
const isPairIterator = utils.isPairIterable(this.idl);
let str = "";
if (isPairIterator) {
if (this.isPair) {
str += `
${this.generateFunction(Symbol.iterator, "key+value", "Symbol.iterator", "entries")}
${this.obj.name}.prototype.entries = ${this.obj.name}.prototype[Symbol.iterator];
${this.generateFunction("keys", "key")}
${this.generateFunction("values", "value")}
${this.obj.name}.prototype.forEach = function forEach(callback) {
if (!this || !module.exports.is(this)) {
throw new TypeError("Illegal invocation");
}
if (arguments.length < 1) {
throw new TypeError("Failed to execute 'forEach' on '${this.obj.name}': 1 argument required, " +
"but only 0 present.");
}
if (typeof callback !== "function") {
throw new TypeError("Failed to execute 'forEach' on '${this.obj.name}': The callback provided " +
"as parameter 1 is not a function.");
}
const thisArg = arguments[1];
let pairs = Array.from(this[impl]);
let i = 0;
while (i < pairs.length) {
const [key, value] = pairs[i].map(utils.tryWrapperForImpl);
callback.call(thisArg, value, key, this);
pairs = Array.from(this[impl]);
i++;
}
};
`;
} else {
// value iterator; WIP
str += `
${this.obj.name}.prototype.entries = Array.prototype.entries;
${this.obj.name}.prototype.keys = Array.prototype.keys;
${this.obj.name}.prototype.values = Array.prototype.values;
`;
}
return {
requires: {},
requires: new utils.RequiresMap(this.ctx),
body: str

@@ -78,0 +66,0 @@ };

@@ -20,3 +20,3 @@ "use strict";

generate() {
const requires = {};
const requires = new utils.RequiresMap(this.ctx);
let str = "";

@@ -29,3 +29,3 @@

} else {
return { requires: {}, body: "" };
return { requires, body: "" };
}

@@ -77,3 +77,3 @@ }

const argsSpread = parameterConversions.hasArgs ? "...args" : "";
Object.assign(requires, parameterConversions.requires);
requires.merge(parameterConversions.requires);
str += parameterConversions.body;

@@ -80,0 +80,0 @@

@@ -14,4 +14,5 @@ "use strict";

class Context {
constructor({ implSuffix = "" } = {}) {
constructor({ implSuffix = "", options } = {}) {
this.implSuffix = implSuffix;
this.options = options;
this.initialize();

@@ -18,0 +19,0 @@ }

@@ -72,2 +72,29 @@ "use strict";

function isArrayIndexPropName(P) {
if (typeof P !== "string") {
return false;
}
const i = P >>> 0;
if (i === Math.pow(2, 32) - 1) {
return false;
}
const s = `${i}`;
if (P !== s) {
return false;
}
return true;
}
const supportsPropertyIndex = Symbol("supports property index");
const supportedPropertyIndices = Symbol("supported property indices");
const supportsPropertyName = Symbol("supports property name");
const supportedPropertyNames = Symbol("supported property names");
const indexedGet = Symbol("indexed property get");
const indexedSetNew = Symbol("indexed property set new");
const indexedSetExisting = Symbol("indexed property set existing");
const namedGet = Symbol("named property get");
const namedSetNew = Symbol("named property set new");
const namedSetExisting = Symbol("named property set existing");
const namedDelete = Symbol("named property delete");
module.exports = exports = {

@@ -86,3 +113,15 @@ isObject,

iterInternalSymbol,
IteratorPrototype
IteratorPrototype,
isArrayIndexPropName,
supportsPropertyIndex,
supportedPropertyIndices,
supportsPropertyName,
supportedPropertyNames,
indexedGet,
indexedSetNew,
indexedSetExisting,
namedGet,
namedSetNew,
namedSetExisting,
namedDelete
};

@@ -10,3 +10,3 @@ "use strict";

const { customTypes } = ctx;
const requires = {};
const requires = new utils.RequiresMap(ctx);
let str = "";

@@ -24,3 +24,3 @@ const idlType = conversion.type;

const conv = Types.generateTypeConversion(ctx, name, idlType, argAttrs, ...typeArgs);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);
str += conv.body;

@@ -46,3 +46,3 @@

module.exports.generateOverloadConversions = function (ctx, overloads, parentName, errPrefix) {
const requires = {};
const requires = new utils.RequiresMap(ctx);
let str = ``;

@@ -85,3 +85,3 @@ let maxConstructor = overloads[0];

`"${errPrefix}parameter ${i + 1}"`);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);
str += conv.body;

@@ -88,0 +88,0 @@ }

@@ -18,9 +18,10 @@ "use strict";

this.ctx = new Context({
implSuffix: opts.implSuffix
implSuffix: opts.implSuffix,
options: {
suppressErrors: Boolean(opts.suppressErrors)
}
});
this.options = Object.assign({
suppressErrors: false
}, opts);
this.sources = [];
this.utilPath = null;
}

@@ -116,3 +117,3 @@

default:
if (!this.options.suppressErrors) {
if (!this.ctx.options.suppressErrors) {
throw new Error("Can't convert type '" + instruction.type + "'");

@@ -135,3 +136,3 @@ }

if (this.options.suppressErrors && !interfaces.has(instruction.name)) {
if (this.ctx.options.suppressErrors && !interfaces.has(instruction.name)) {
break;

@@ -148,3 +149,3 @@ }

}
if (this.options.suppressErrors && !dictionaries.has(instruction.name)) {
if (this.ctx.options.suppressErrors && !dictionaries.has(instruction.name)) {
break;

@@ -158,3 +159,3 @@ }

case "implements":
if (this.options.suppressErrors && !interfaces.has(instruction.target)) {
if (this.ctx.options.suppressErrors && !interfaces.has(instruction.target)) {
break;

@@ -171,3 +172,3 @@ }

const utilsText = yield fs.readFile(path.resolve(__dirname, "output/utils.js"));
yield fs.writeFile(this.options.utilPath, utilsText);
yield fs.writeFile(this.utilPath, utilsText);

@@ -185,3 +186,3 @@ const { interfaces, dictionaries } = this.ctx;

let relativeUtils = path.relative(outputDir, this.options.utilPath).replace(/\\/g, "/");
let relativeUtils = path.relative(outputDir, this.utilPath).replace(/\\/g, "/");
if (relativeUtils[0] !== ".") {

@@ -208,3 +209,3 @@ relativeUtils = "./" + relativeUtils;

let relativeUtils = path.relative(outputDir, this.options.utilPath).replace(/\\/g, "/");
let relativeUtils = path.relative(outputDir, this.utilPath).replace(/\\/g, "/");
if (relativeUtils[0] !== ".") {

@@ -235,4 +236,4 @@ relativeUtils = "./" + relativeUtils;

generate(outputDir) {
if (!this.options.utilPath) {
this.options.utilPath = path.join(outputDir, "utils.js");
if (!this.utilPath) {
this.utilPath = path.join(outputDir, "utils.js");
}

@@ -239,0 +240,0 @@

@@ -78,3 +78,3 @@ "use strict";

const { customTypes } = ctx;
const requires = {};
const requires = new utils.RequiresMap(ctx);
let str = "";

@@ -117,3 +117,3 @@

fn = `convert${idlType.idlType}`;
requires[fn] = `require("./${idlType.idlType}").convert`;
requires.add(idlType.idlType, "convert");
} else {

@@ -152,3 +152,3 @@ fn = `module.exports.convert`;

const conv = generateTypeConversion(ctx, name, union.dictionary, [], parentName, errPrefix);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);
output.push(`

@@ -171,3 +171,3 @@ if (${name} === null || ${name} === undefined) {

fn = `is${iface}`;
requires[fn] = `require("./${iface}").is`;
requires.add(iface, "is");
} else {

@@ -215,3 +215,3 @@ fn = "module.exports.is";

`${errPrefix} + " sequence"`);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);
code += conv.body;

@@ -225,3 +225,3 @@ code += `} else {`;

`${errPrefix} + " ${prop}"`);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);
code += conv.body;

@@ -275,3 +275,3 @@ } else if (union.object) {

`${errPrefix} + "'s element"`);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);

@@ -296,6 +296,6 @@ str += `

`${errPrefix} + "'s key"`);
Object.assign(requires, keyConv.requires);
requires.merge(keyConv.requires);
const valConv = generateTypeConversion(ctx, "typedValue", idlType.idlType[1], [], parentName,
`${errPrefix} + "'s value"`);
Object.assign(requires, valConv.requires);
requires.merge(valConv.requires);

@@ -330,3 +330,3 @@ str += `

`${errPrefix} + " promise value"`);
Object.assign(requires, conv.requires);
requires.merge(conv.requires);
handler = `

@@ -333,0 +333,0 @@ ${conv.body}

@@ -35,6 +35,2 @@ "use strict";

function isPairIterable(idl) {
return idl.type === "iterable" && Array.isArray(idl.idlType) && idl.idlType.length === 2;
}
function isOnInstance(memberIDL, interfaceIDL) {

@@ -44,2 +40,38 @@ return getExtAttr(memberIDL.extAttrs, "Unforgeable") || isGlobal(interfaceIDL);

class RequiresMap extends Map {
constructor(ctx) {
super();
this.ctx = ctx;
}
add(type, func = "") {
const key = func + type;
let req = `require("./${type}.js")`;
if (func) {
req += `.${func}`;
}
this.addRaw(key, req);
}
addRaw(key, expr) {
if (this.has(key) && this.get(key) !== expr) {
throw new Error(`Internal error: Variable name clash: ${key}; was ${this.get(key)}, adding: ${expr}`);
}
super.set(key, expr);
}
merge(src) {
if (!src || !(src instanceof RequiresMap)) {
return;
}
for (const [key, val] of src) {
this.addRaw(key, val);
}
}
generate() {
return [...this.keys()].map(key => `const ${key} = ${this.get(key)};`).join("\n");
}
}
module.exports = {

@@ -49,4 +81,4 @@ getDefault,

isGlobal,
isPairIterable,
isOnInstance
isOnInstance,
RequiresMap
};
{
"name": "webidl2js",
"version": "7.2.0",
"version": "7.3.0",
"description": "Auto-generates class structures for WebIDL specifications",

@@ -5,0 +5,0 @@ "main": "lib/transformer.js",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc