Comparing version 7.1.1 to 7.2.0
@@ -9,111 +9,121 @@ "use strict"; | ||
function Attribute(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
} | ||
class Attribute { | ||
constructor(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
} | ||
Attribute.prototype.generate = function () { | ||
let str = ""; | ||
let requires = {}; | ||
generate() { | ||
let str = ""; | ||
const requires = {}; | ||
const configurable = !utils.getExtAttr(this.idl.extAttrs, "Unforgeable"); | ||
const shouldReflect = utils.getExtAttr(this.idl.extAttrs, "Reflect"); | ||
const sameObject = utils.getExtAttr(this.idl.extAttrs, "SameObject"); | ||
const configurable = !utils.getExtAttr(this.idl.extAttrs, "Unforgeable"); | ||
const shouldReflect = utils.getExtAttr(this.idl.extAttrs, "Reflect"); | ||
const sameObject = utils.getExtAttr(this.idl.extAttrs, "SameObject"); | ||
let objName = `this`; | ||
let definedOn = this.obj.name + (this.idl.static ? "" : ".prototype"); | ||
if (utils.isOnInstance(this.idl, this.interface)) { // we're in a setup method | ||
objName = `obj`; | ||
definedOn = `obj`; | ||
} | ||
let getterBody = `return utils.tryWrapperForImpl(${objName}[impl]["${this.idl.name}"]);`; | ||
let setterBody = `${objName}[impl]["${this.idl.name}"] = V;`; | ||
if (conversions[this.idl.idlType.idlType]) { | ||
getterBody = `return ${objName}[impl]["${this.idl.name}"];`; | ||
} | ||
let objName = `this`; | ||
let definedOn = this.obj.name + (this.idl.static ? "" : ".prototype"); | ||
if (utils.isOnInstance(this.idl, this.interface)) { // we're in a setup method | ||
objName = `obj`; | ||
definedOn = `obj`; | ||
} | ||
let getterBody = `return utils.tryWrapperForImpl(${objName}[impl]["${this.idl.name}"]);`; | ||
let setterBody = `${objName}[impl]["${this.idl.name}"] = V;`; | ||
if (conversions[this.idl.idlType.idlType]) { | ||
getterBody = `return ${objName}[impl]["${this.idl.name}"];`; | ||
} | ||
if (this.idl.static) { | ||
getterBody = `return Impl["${this.idl.name}"];`; | ||
setterBody = `Impl["${this.idl.name}"] = V;`; | ||
} else if (shouldReflect) { | ||
if (!reflector[this.idl.idlType.idlType]) { | ||
throw new Error("Unknown reflector type: " + this.idl.idlType.idlType); | ||
if (this.idl.static) { | ||
getterBody = `return Impl["${this.idl.name}"];`; | ||
setterBody = `Impl["${this.idl.name}"] = V;`; | ||
} else if (shouldReflect) { | ||
if (!reflector[this.idl.idlType.idlType]) { | ||
throw new Error("Unknown reflector type: " + this.idl.idlType.idlType); | ||
} | ||
const attrName = shouldReflect.rhs && shouldReflect.rhs.value.replace(/_/g, "-") || this.idl.name; | ||
getterBody = reflector[this.idl.idlType.idlType].get(objName, attrName); | ||
setterBody = reflector[this.idl.idlType.idlType].set(objName, attrName); | ||
} | ||
const attrName = shouldReflect.rhs && shouldReflect.rhs.value.replace(/_/g, '-') || this.idl.name; | ||
getterBody = reflector[this.idl.idlType.idlType].get(objName, attrName); | ||
setterBody = reflector[this.idl.idlType.idlType].set(objName, attrName); | ||
} | ||
if (sameObject) { | ||
getterBody = `return utils.getSameObject(this, "${this.idl.name}", () => { ${getterBody} });`; | ||
} | ||
if (sameObject) { | ||
getterBody = `return utils.getSameObject(this, "${this.idl.name}", () => { ${getterBody} });`; | ||
} | ||
str += `Object.defineProperty(${definedOn}, "${this.idl.name}", { | ||
get() { | ||
${getterBody} | ||
},`; | ||
if (!this.idl.readonly) { | ||
const conv = Types.generateTypeConversion(this.ctx, "V", this.idl.idlType, this.idl.extAttrs, this.interface.name, `"Failed to set the '${this.idl.name}' property on '${this.interface.name}': The provided value"`); | ||
Object.assign(requires, conv.requires); | ||
let conversion = conv.body.replace(/\n/g, "\n "); | ||
str += ` | ||
set(V) {${conversion} | ||
${setterBody} | ||
},`; | ||
} else if (utils.getExtAttr(this.idl.extAttrs, "PutForwards")) { | ||
str += ` | ||
set(V) { | ||
this.${this.idl.name}.${utils.getExtAttr(this.idl.extAttrs, "PutForwards").rhs.value} = V; | ||
},`; | ||
} else if (utils.getExtAttr(this.idl.extAttrs, "Replaceable")) { | ||
str += ` | ||
set(V) { | ||
Object.defineProperty(this, "${this.idl.name}", { | ||
configurable: true, | ||
enumerable: true, | ||
value: V, | ||
writable: true | ||
}); | ||
},`; | ||
} | ||
str += ` | ||
enumerable: true, | ||
configurable: ${JSON.stringify(configurable)} | ||
});\n\n`; | ||
if (this.idl.stringifier) { | ||
const functionExpression = ` | ||
function toString() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
${getterBody}; | ||
} | ||
Object.defineProperty(${definedOn}, "${this.idl.name}", { | ||
get() { | ||
${getterBody} | ||
}, | ||
`; | ||
if (utils.getExtAttr(this.idl.extAttrs, "Unforgeable")) { | ||
if (!this.idl.readonly) { | ||
const conv = Types.generateTypeConversion( | ||
this.ctx, "V", this.idl.idlType, this.idl.extAttrs, this.interface.name, | ||
`"Failed to set the '${this.idl.name}' property on '${this.interface.name}': The provided value"`); | ||
Object.assign(requires, conv.requires); | ||
str += ` | ||
Object.defineProperty(${definedOn}, "toString", { | ||
writable: false, | ||
enumerable: true, | ||
configurable: false, | ||
value: ${functionExpression} | ||
}); | ||
set(V) { | ||
${conv.body} | ||
${setterBody} | ||
}, | ||
`; | ||
} else { | ||
} else if (utils.getExtAttr(this.idl.extAttrs, "PutForwards")) { | ||
str += ` | ||
${definedOn}.toString = ${functionExpression}; | ||
set(V) { | ||
this.${this.idl.name}.${utils.getExtAttr(this.idl.extAttrs, "PutForwards").rhs.value} = V; | ||
}, | ||
`; | ||
} else if (utils.getExtAttr(this.idl.extAttrs, "Replaceable")) { | ||
str += ` | ||
set(V) { | ||
Object.defineProperty(this, "${this.idl.name}", { | ||
configurable: true, | ||
enumerable: true, | ||
value: V, | ||
writable: true | ||
}); | ||
}, | ||
`; | ||
} | ||
str += "\n"; | ||
str += ` | ||
enumerable: true, | ||
configurable: ${JSON.stringify(configurable)} | ||
}); | ||
`; | ||
if (this.idl.stringifier) { | ||
const functionExpression = ` | ||
function toString() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
${getterBody}; | ||
} | ||
`; | ||
if (utils.getExtAttr(this.idl.extAttrs, "Unforgeable")) { | ||
str += ` | ||
Object.defineProperty(${definedOn}, "toString", { | ||
writable: false, | ||
enumerable: true, | ||
configurable: false, | ||
value: ${functionExpression} | ||
}); | ||
`; | ||
} else { | ||
str += ` | ||
${definedOn}.toString = ${functionExpression}; | ||
`; | ||
} | ||
str += "\n"; | ||
} | ||
return { | ||
requires, | ||
body: str | ||
}; | ||
} | ||
} | ||
return { | ||
requires, | ||
body: str | ||
}; | ||
}; | ||
module.exports = Attribute; |
"use strict"; | ||
function Constant(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
class Constant { | ||
constructor(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
this.str = null; | ||
this.str = null; | ||
} | ||
generate() { | ||
const body = ` | ||
Object.defineProperty(${this.obj.name}, "${this.idl.name}", { | ||
value: ${JSON.stringify(this.idl.value.value)}, | ||
enumerable: true | ||
}); | ||
Object.defineProperty(${this.obj.name}.prototype, "${this.idl.name}", { | ||
value: ${JSON.stringify(this.idl.value.value)}, | ||
enumerable: true | ||
}); | ||
`; | ||
return { | ||
requires: {}, | ||
body | ||
}; | ||
} | ||
} | ||
Constant.prototype.generate = function () { | ||
const body = `Object.defineProperty(${this.obj.name}, "${this.idl.name}", { | ||
value: ${JSON.stringify(this.idl.value.value)}, | ||
enumerable: true | ||
}); | ||
Object.defineProperty(${this.obj.name}.prototype, "${this.idl.name}", { | ||
value: ${JSON.stringify(this.idl.value.value)}, | ||
enumerable: true | ||
});\n\n`; | ||
return { | ||
requires: {}, | ||
body | ||
}; | ||
}; | ||
module.exports = Constant; |
@@ -11,9 +11,11 @@ "use strict"; | ||
this.name = idl.name; | ||
this.requires = {}; | ||
} | ||
_generateConversions() { | ||
_prepareFields() { | ||
const fields = []; | ||
const members = this.idl.members; | ||
members.forEach(member => { | ||
if (member.type !== 'field') { | ||
if (member.type !== "field") { | ||
throw new Error("webidl2js doesn't support non-field members in dictionaries"); | ||
@@ -25,39 +27,45 @@ } | ||
fields.sort((a, b) => a.name < b.name ? -1 : 1); | ||
return fields; | ||
} | ||
this.str += ` | ||
let key, value;`; | ||
fields.forEach(field => { | ||
this.str += `\n | ||
key = "${field.name}"; | ||
value = obj === undefined || obj === null ? undefined : obj[key];`; | ||
_generateConversions() { | ||
let str = ""; | ||
for (const field of this._prepareFields()) { | ||
const typeConversion = field.idlType; | ||
this.str += ` | ||
if (value !== undefined) {`; | ||
const argAttrs = field.extAttrs; | ||
const conv = Types.generateTypeConversion( | ||
this.ctx, "value", typeConversion, argAttrs, this.name, `context + " has member ${field.name} that"`); | ||
Object.assign(this.requires, conv.requires); | ||
const conv = Types.generateTypeConversion(this.ctx, "value", typeConversion, argAttrs, this.name, `\`\${context} has member ${field.name} that\``); | ||
for (let key in conv.requires) { | ||
this.str = `const ${key} = ${conv.requires[key]};\n` + this.str; | ||
} | ||
this.str += conv.body; | ||
this.str += ` | ||
ret[key] = value;` | ||
str += ` | ||
{ | ||
const key = "${field.name}"; | ||
let value = obj === undefined || obj === null ? undefined : obj[key]; | ||
if (value !== undefined) { | ||
${conv.body} | ||
ret[key] = value; | ||
} | ||
`; | ||
if (field.required) { | ||
this.str += ` | ||
} else { | ||
throw new TypeError("${field.name} is required in '${this.name}'");`; | ||
str += ` | ||
else { | ||
throw new TypeError("${field.name} is required in '${this.name}'"); | ||
} | ||
`; | ||
} else if (field.default) { | ||
this.str += ` | ||
} else { | ||
ret[key] = `; | ||
if (field.default.type === "null") { | ||
this.str += `null;`; | ||
} else { | ||
this.str += JSON.stringify(field.default.value) + ';'; | ||
str += ` | ||
else { | ||
ret[key] = ${utils.getDefault(field.default)}; | ||
} | ||
`; | ||
} | ||
str += ` | ||
} | ||
} | ||
this.str += ` | ||
}`; | ||
}); | ||
`; | ||
} | ||
return str; | ||
} | ||
@@ -67,23 +75,36 @@ | ||
this.str += ` | ||
module.exports = { | ||
convertInherit(obj, ret, { context = "The provided value" } = {}) {`; | ||
module.exports = { | ||
convertInherit(obj, ret, { context = "The provided value" } = {}) { | ||
`; | ||
if (this.idl.inheritance) { | ||
this.str = `const ${this.idl.inheritance} = require("./${this.idl.inheritance}");\n` + this.str; | ||
this.str += ` | ||
${this.idl.inheritance}.convertInherit(obj, ret, { context });`; | ||
${this.idl.inheritance}.convertInherit(obj, ret, { context }); | ||
`; | ||
} | ||
this._generateConversions(); | ||
this.str += ` | ||
}, | ||
${this._generateConversions()} | ||
}, | ||
convert(obj, { context = "The provided value" } = {}) { | ||
if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") { | ||
throw new TypeError(\`\${context} is not an object.\`); | ||
convert(obj, { context = "The provided value" } = {}) { | ||
if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") { | ||
throw new TypeError(\`\${context} is not an object.\`); | ||
} | ||
const ret = Object.create(null); | ||
module.exports.convertInherit(obj, ret, { context }); | ||
return ret; | ||
} | ||
}; | ||
`; | ||
if (this.idl.inheritance) { | ||
this.requires[this.idl.inheritance] = `require("./${this.idl.inheritance}")`; | ||
} | ||
this.str = ` | ||
${Object.keys(this.requires).map(key => `const ${key} = ${this.requires[key]};`).join("\n")} | ||
const ret = Object.create(null); | ||
module.exports.convertInherit(obj, ret, { context }); | ||
return ret; | ||
} | ||
};`; | ||
${this.str} | ||
`; | ||
@@ -94,3 +115,3 @@ return this.str; | ||
toString() { | ||
this.str = ``; | ||
this.str = ""; | ||
this.generate(); | ||
@@ -97,0 +118,0 @@ return this.str; |
"use strict"; | ||
const path = require("path"); | ||
const utils = require("../utils"); | ||
@@ -14,442 +12,472 @@ const Attribute = require("./attribute"); | ||
function Interface(ctx, idl, opts) { | ||
this.ctx = ctx; | ||
this.idl = idl; | ||
this.name = idl.name; | ||
this.factory = !!utils.getExtAttr(this.idl.extAttrs, "WebIDL2JSFactory"); | ||
class Interface { | ||
constructor(ctx, idl, opts) { | ||
this.ctx = ctx; | ||
this.idl = idl; | ||
this.name = idl.name; | ||
this.factory = Boolean(utils.getExtAttr(this.idl.extAttrs, "WebIDL2JSFactory")); | ||
this.mixins = []; | ||
this.requires = {}; | ||
this.str = null; | ||
this.opts = opts; | ||
this.hasPairIterator = this.idl.members.some(utils.isPairIterable); | ||
} | ||
this.mixins = []; | ||
this.requires = {}; | ||
this.str = null; | ||
this.opts = opts; | ||
} | ||
Interface.prototype.type = "interface"; | ||
get hasPairIterator() { | ||
return this.idl.members.some(utils.isPairIterable); | ||
} | ||
Interface.prototype.implements = function (source) { | ||
this.mixins.push(source); | ||
}; | ||
implements(source) { | ||
this.mixins.push(source); | ||
} | ||
Interface.prototype.generateIterator = function () { | ||
if (this.hasPairIterator) { | ||
this.str += ` | ||
const IteratorPrototype = Object.create(utils.IteratorPrototype, { | ||
next: { | ||
value: function next() { | ||
const internal = this[utils.iterInternalSymbol]; | ||
const { target, kind, index } = internal; | ||
const values = Array.from(target[impl]); | ||
const len = values.length; | ||
if (index >= len) { | ||
return { value: undefined, done: true }; | ||
} | ||
generateIterator() { | ||
if (this.hasPairIterator) { | ||
this.str += ` | ||
const IteratorPrototype = Object.create(utils.IteratorPrototype, { | ||
next: { | ||
value: function next() { | ||
const internal = this[utils.iterInternalSymbol]; | ||
const { target, kind, index } = internal; | ||
const values = Array.from(target[impl]); | ||
const len = values.length; | ||
if (index >= len) { | ||
return { value: undefined, done: true }; | ||
} | ||
const pair = values[index]; | ||
internal.index = index + 1; | ||
const [key, value] = pair.map(utils.tryWrapperForImpl); | ||
const pair = values[index]; | ||
internal.index = index + 1; | ||
const [key, value] = pair.map(utils.tryWrapperForImpl); | ||
let result; | ||
switch (kind) { | ||
case "key": | ||
result = key; | ||
break; | ||
case "value": | ||
result = value; | ||
break; | ||
case "key+value": | ||
result = [key, value]; | ||
break; | ||
} | ||
return { value: result, done: false }; | ||
}, | ||
writable: true, | ||
enumerable: true, | ||
configurable: true | ||
}, | ||
[Symbol.toStringTag]: { | ||
value: "${this.name}Iterator", | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
let result; | ||
switch (kind) { | ||
case "key": | ||
result = key; | ||
break; | ||
case "value": | ||
result = value; | ||
break; | ||
case "key+value": | ||
result = [key, value]; | ||
break; | ||
} | ||
return { value: result, done: false }; | ||
}, | ||
writable: true, | ||
enumerable: true, | ||
configurable: true | ||
}, | ||
[Symbol.toStringTag]: { | ||
value: "${this.name}Iterator", | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
} | ||
}); | ||
`; | ||
} | ||
} | ||
}); | ||
`; | ||
} | ||
}; | ||
generateConstructor() { | ||
const overloads = Overloads.getEffectiveOverloads("constructor", 0, this.idl, null); | ||
Interface.prototype.generateConstructor = function () { | ||
const overloads = Overloads.getEffectiveOverloads("constructor", 0, this.idl, null); | ||
if (overloads.length !== 0) { | ||
let minConstructor = overloads[0]; | ||
if (overloads.length !== 0) { | ||
let minConstructor = overloads[0]; | ||
for (let i = 1; i < overloads.length; ++i) { | ||
if (overloads[i].nameList.length < minConstructor.nameList.length) { | ||
minConstructor = overloads[i]; | ||
} | ||
} | ||
for (let i = 1; i < overloads.length; ++i) { | ||
if (overloads[i].nameList.length < minConstructor.nameList.length) { | ||
minConstructor = overloads[i]; | ||
const conversions = | ||
Parameters.generateOverloadConversions(this.ctx, overloads, this.name, `Failed to construct '${this.name}': `); | ||
Object.assign(this.requires, conversions.requires); | ||
minConstructor.nameList = minConstructor.nameList.map(name => (keywords.has(name) ? "_" : "") + name); | ||
this.str += ` | ||
function ${this.name}(${minConstructor.nameList.join(", ")}) { | ||
`; | ||
if (minConstructor.nameList.length !== 0) { | ||
const plural = minConstructor.nameList.length > 1 ? "s" : ""; | ||
this.str += ` | ||
if (!new.target) { | ||
throw new TypeError("Failed to construct '${this.name}'. Please use the 'new' operator; this constructor " + | ||
"cannot be called as a function."); | ||
} | ||
if (arguments.length < ${minConstructor.nameList.length}) { | ||
throw new TypeError("Failed to construct '${this.name}': ${minConstructor.nameList.length} " + | ||
"argument${plural} required, but only " + arguments.length + " present."); | ||
} | ||
`; | ||
} | ||
this.str += conversions.body + "\n"; | ||
const passArgs = conversions.hasArgs ? ", args" : ""; | ||
this.str += ` | ||
iface.setup(this${passArgs}); | ||
} | ||
`; | ||
} else { | ||
this.str += ` | ||
function ${this.name}() { | ||
throw new TypeError("Illegal constructor"); | ||
} | ||
`; | ||
} | ||
const conversions = Parameters.generateOverloadConversions(this.ctx, overloads, this.name, `Failed to construct '${this.name}': `); | ||
Object.assign(this.requires, conversions.requires); | ||
minConstructor.nameList = minConstructor.nameList.map((name) => (keywords.has(name) ? "_" : "") + name); | ||
this.str += `function ${this.name}(${minConstructor.nameList.join(", ")}) {`; | ||
if (minConstructor.nameList.length !== 0) { | ||
const plural = minConstructor.nameList.length > 1 ? "s" : ""; | ||
if (this.idl.inheritance) { | ||
this.str += ` | ||
if (!new.target) { | ||
throw new TypeError("Failed to construct '${this.name}'. Please use the 'new' operator; this constructor cannot be called as a function."); | ||
} | ||
if (arguments.length < ${minConstructor.nameList.length}) { | ||
throw new TypeError("Failed to construct '${this.name}': ${minConstructor.nameList.length} argument${plural} required, but only " + arguments.length + " present."); | ||
}`; | ||
Object.setPrototypeOf(${this.name}.prototype, ${this.idl.inheritance}.interface.prototype); | ||
Object.setPrototypeOf(${this.name}, ${this.idl.inheritance}.interface); | ||
`; | ||
} | ||
this.str += conversions.body + "\n"; | ||
const passArgs = conversions.hasArgs ? ", args" : ""; | ||
this.str += ` | ||
iface.setup(this${passArgs}); | ||
}\n`; | ||
} else { | ||
this.str += `function ${this.name}() { | ||
throw new TypeError("Illegal constructor"); | ||
}\n`; | ||
Object.defineProperty(${this.name}, "prototype", { | ||
value: ${this.name}.prototype, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
`; | ||
} | ||
if (this.idl.inheritance) { | ||
this.str += `Object.setPrototypeOf(${this.name}.prototype, ${this.idl.inheritance}.interface.prototype); | ||
Object.setPrototypeOf(${this.name}, ${this.idl.inheritance}.interface);\n`; | ||
} | ||
}; | ||
generateRequires() { | ||
this.requires.impl = "utils.implSymbol"; | ||
Interface.prototype.generateRequires = function () { | ||
let requireStr = ``; | ||
if (this.idl.inheritance !== null) { | ||
this.requires[this.idl.inheritance] = `require("./${this.idl.inheritance}.js")`; | ||
} | ||
if (this.idl.inheritance !== null) { | ||
requireStr += `const ${this.idl.inheritance} = require("./${this.idl.inheritance}.js");\n`; | ||
} | ||
if (this.mixins.length !== 0) { | ||
this.requires.mixin = "utils.mixin"; | ||
for (const mixin of this.mixins) { | ||
this.requires[mixin] = `require("./${mixin}.js")`; | ||
} | ||
} | ||
requireStr += `const impl = utils.implSymbol;\n`; | ||
this.str = ` | ||
${Object.keys(this.requires).map(key => `const ${key} = ${this.requires[key]};`).join("\n")} | ||
if (this.mixins.length !== 0) { | ||
requireStr += `const mixin = utils.mixin;\n`; | ||
for (let i = 0; i < this.mixins.length; ++i) { | ||
requireStr += `const ${this.mixins[i]} = require("./${this.mixins[i]}.js");\n`; | ||
} | ||
${this.str} | ||
`; | ||
} | ||
for (let key in this.requires) { | ||
requireStr += `const ${key} = ${this.requires[key]};\n`; | ||
generateMixins() { | ||
for (const mixin of this.mixins) { | ||
this.str += ` | ||
mixin(${this.name}.prototype, ${mixin}.interface.prototype); | ||
${mixin}.mixedInto.push(${this.name}); | ||
`; | ||
} | ||
} | ||
requireStr += `\n`; | ||
this.str = requireStr + this.str; | ||
}; | ||
generateExport() { | ||
this.str += ` | ||
mixedInto: [], | ||
is(obj) { | ||
if (obj) { | ||
if (obj[impl] instanceof Impl.implementation) { | ||
return true; | ||
} | ||
for (let i = 0; i < module.exports.mixedInto.length; ++i) { | ||
if (obj instanceof module.exports.mixedInto[i]) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}, | ||
isImpl(obj) { | ||
if (obj) { | ||
if (obj instanceof Impl.implementation) { | ||
return true; | ||
} | ||
Interface.prototype.generateMixins = function () { | ||
this.str += `\n`; | ||
for (let i = 0; i < this.mixins.length; ++i) { | ||
this.str += `mixin(${this.name}.prototype, ${this.mixins[i]}.interface.prototype); | ||
${this.mixins[i]}.mixedInto.push(${this.name});\n`; | ||
} | ||
}; | ||
Interface.prototype.generateExport = function () { | ||
this.str += ` | ||
mixedInto: [], | ||
is(obj) { | ||
if (obj) { | ||
if (obj[impl] instanceof Impl.implementation) { | ||
return true; | ||
} | ||
for (let i = 0; i < module.exports.mixedInto.length; ++i) { | ||
if (obj instanceof module.exports.mixedInto[i]) { | ||
return true; | ||
const wrapper = utils.wrapperForImpl(obj); | ||
for (let i = 0; i < module.exports.mixedInto.length; ++i) { | ||
if (wrapper instanceof module.exports.mixedInto[i]) { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return false; | ||
}, | ||
isImpl(obj) { | ||
if (obj) { | ||
if (obj instanceof Impl.implementation) { | ||
return true; | ||
} | ||
return false; | ||
}, | ||
convert(obj, { context = "The provided value" } = {}) { | ||
if (module.exports.is(obj)) { | ||
return utils.implForWrapper(obj); | ||
} | ||
throw new TypeError(\`\${context} is not of type '${this.name}'.\`); | ||
}, | ||
`; | ||
const wrapper = utils.wrapperForImpl(obj); | ||
for (let i = 0; i < module.exports.mixedInto.length; ++i) { | ||
if (wrapper instanceof module.exports.mixedInto[i]) { | ||
return true; | ||
} | ||
} | ||
if (this.hasPairIterator) { | ||
this.str += ` | ||
createDefaultIterator(target, kind) { | ||
const iterator = Object.create(IteratorPrototype); | ||
Object.defineProperty(iterator, utils.iterInternalSymbol, { | ||
value: { target, kind, index: 0 }, | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return iterator; | ||
}, | ||
`; | ||
} | ||
return false; | ||
}, | ||
convert(obj, { context = "The provided value" } = {}) { | ||
if (module.exports.is(obj)) { | ||
return utils.implForWrapper(obj); | ||
} | ||
throw new TypeError(\`\${context} is not of type '${this.name}'.\`); | ||
},`; | ||
if (this.hasPairIterator) { | ||
this.str += ` | ||
createDefaultIterator(target, kind) { | ||
const iterator = Object.create(IteratorPrototype); | ||
Object.defineProperty(iterator, utils.iterInternalSymbol, { | ||
value: { target, kind, index: 0 }, | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return iterator; | ||
},`; | ||
} | ||
}; | ||
Interface.prototype.generateIface = function () { | ||
const shouldExposeRoot = !utils.getExtAttr(this.idl.extAttrs, "NoInterfaceObject"); | ||
generateIface() { | ||
const shouldExposeRoot = !utils.getExtAttr(this.idl.extAttrs, "NoInterfaceObject"); | ||
const exposedMap = {}; | ||
if (shouldExposeRoot) { | ||
let exposedOn = ["Window"]; | ||
const exposedAttrs = this.idl.extAttrs | ||
.filter(function (attr) { return attr.name === "Exposed"; }); | ||
if (exposedAttrs.length !== 0) { | ||
if (typeof exposedAttrs[0].rhs.value === "string") { | ||
exposedAttrs[0].rhs.value = [exposedAttrs[0].rhs.value]; | ||
const exposedMap = {}; | ||
if (shouldExposeRoot) { | ||
let exposedOn = ["Window"]; | ||
const exposedAttrs = this.idl.extAttrs | ||
.filter(attr => attr.name === "Exposed"); | ||
if (exposedAttrs.length !== 0) { | ||
if (typeof exposedAttrs[0].rhs.value === "string") { | ||
exposedAttrs[0].rhs.value = [exposedAttrs[0].rhs.value]; | ||
} | ||
exposedOn = exposedAttrs[0].rhs.value; | ||
} | ||
exposedOn = exposedAttrs[0].rhs.value; | ||
} | ||
for (let i = 0; i < exposedOn.length; ++i) { | ||
if (!exposedMap[exposedOn[i]]) { | ||
exposedMap[exposedOn[i]] = []; | ||
for (let i = 0; i < exposedOn.length; ++i) { | ||
if (!exposedMap[exposedOn[i]]) { | ||
exposedMap[exposedOn[i]] = []; | ||
} | ||
exposedMap[exposedOn[i]].push(this.name); | ||
} | ||
exposedMap[exposedOn[i]].push(this.name); | ||
} | ||
} | ||
let exposers = []; | ||
for (let keys = Object.keys(exposedMap), i = 0; i < keys.length; ++i) { | ||
let exposedOnObj = exposedMap[keys[i]].map(function (o) { return o + ": " + o; }); | ||
exposers.push(keys[i] + ": { " + exposedOnObj.join(", ") + " }"); | ||
} | ||
const exposers = []; | ||
for (let keys = Object.keys(exposedMap), i = 0; i < keys.length; ++i) { | ||
exposers.push(keys[i] + ": { " + exposedMap[keys[i]].join(", ") + " }"); | ||
} | ||
// 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); | ||
return obj; | ||
}, | ||
createImpl(constructorArgs, privateData) { | ||
let obj = Object.create(${this.name}.prototype); | ||
this.setup(obj, constructorArgs, privateData); | ||
return utils.implForWrapper(obj); | ||
}, | ||
_internalSetup(obj) {`; | ||
// 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); | ||
return obj; | ||
}, | ||
createImpl(constructorArgs, privateData) { | ||
let obj = Object.create(${this.name}.prototype); | ||
this.setup(obj, constructorArgs, privateData); | ||
return utils.implForWrapper(obj); | ||
}, | ||
_internalSetup(obj) { | ||
`; | ||
if (this.idl.inheritance) { | ||
this.str += ` | ||
${this.idl.inheritance}._internalSetup(obj);\n`; | ||
${this.idl.inheritance}._internalSetup(obj); | ||
`; | ||
} | ||
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; | ||
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"); | ||
} | ||
} | ||
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; | ||
} | ||
this.str += "\n" + member.generate().body; | ||
} | ||
} | ||
this.str += ` | ||
}, | ||
setup(obj, constructorArgs, privateData) { | ||
if (!privateData) privateData = {};`; | ||
if (this.factory) { | ||
this.str += ` | ||
for (var prop in defaultPrivateData) { | ||
if (!(prop in privateData)) { | ||
privateData[prop] = defaultPrivateData[prop]; | ||
} | ||
}`; | ||
} | ||
}, | ||
setup(obj, constructorArgs, privateData) { | ||
if (!privateData) privateData = {}; | ||
`; | ||
this.str += ` | ||
privateData.wrapper = obj; | ||
if (this.factory) { | ||
this.str += ` | ||
for (var prop in defaultPrivateData) { | ||
if (!(prop in privateData)) { | ||
privateData[prop] = defaultPrivateData[prop]; | ||
} | ||
} | ||
`; | ||
} | ||
this._internalSetup(obj);\n`; | ||
this.str += ` | ||
privateData.wrapper = obj; | ||
const implClass = require(this.opts.implDir + "/" + this.name + this.ctx.implSuffix); | ||
this.str += ` | ||
Object.defineProperty(obj, impl, { | ||
value: new Impl.implementation(constructorArgs, privateData), | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
obj[impl][utils.wrapperSymbol] = obj;`; | ||
if (implClass.init) { | ||
this.str += ` | ||
Impl.init(obj[impl], privateData);`; | ||
this._internalSetup(obj); | ||
Object.defineProperty(obj, impl, { | ||
value: new Impl.implementation(constructorArgs, privateData), | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
obj[impl][utils.wrapperSymbol] = obj; | ||
if (Impl.init) { | ||
Impl.init(obj[impl], privateData); | ||
} | ||
}, | ||
interface: ${this.name}, | ||
expose: { | ||
${exposers.join(",\n ")} | ||
} | ||
`; | ||
} | ||
this.str += ` | ||
}, | ||
interface: ${this.name}, | ||
expose: { | ||
${exposers.join(",\n ")} | ||
}`; | ||
}; | ||
Interface.prototype.generateOperations = function () { | ||
const done = {}; | ||
for (let i = 0; i < this.idl.members.length; ++i) { | ||
const memberIdl = this.idl.members[i]; | ||
let member = null; | ||
generateOperations() { | ||
const done = {}; | ||
for (let i = 0; i < this.idl.members.length; ++i) { | ||
const memberIdl = this.idl.members[i]; | ||
let member = null; | ||
switch (memberIdl.type) { | ||
case "operation": | ||
if (utils.isOnInstance(memberIdl, this.idl)) { | ||
switch (memberIdl.type) { | ||
case "operation": | ||
if (utils.isOnInstance(memberIdl, this.idl)) { | ||
break; | ||
} | ||
member = new Operation(this.ctx, this, this.idl, memberIdl); | ||
if (done[member.name]) { | ||
continue; | ||
} | ||
done[member.name] = true; | ||
break; | ||
} | ||
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; | ||
} | ||
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; | ||
if (member !== null) { | ||
const data = member.generate(); | ||
Object.assign(this.requires, data.requires); | ||
this.str += data.body; | ||
} | ||
} | ||
} | ||
}; | ||
Interface.prototype.generateAttributes = function () { | ||
for (let i = 0; i < this.idl.members.length; ++i) { | ||
const memberIdl = this.idl.members[i]; | ||
let member = null; | ||
generateAttributes() { | ||
for (let i = 0; i < this.idl.members.length; ++i) { | ||
const memberIdl = this.idl.members[i]; | ||
let member = null; | ||
switch (memberIdl.type) { | ||
case "attribute": | ||
if (utils.isOnInstance(memberIdl, this.idl)) { | ||
switch (memberIdl.type) { | ||
case "attribute": | ||
if (utils.isOnInstance(memberIdl, this.idl)) { | ||
break; | ||
} | ||
member = new Attribute(this.ctx, this, this.idl, memberIdl); | ||
break; | ||
} | ||
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; | ||
} | ||
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) { | ||
const data = member.generate(); | ||
Object.assign(this.requires, data.requires); | ||
this.str += data.body; | ||
if (member !== null) { | ||
const data = member.generate(); | ||
Object.assign(this.requires, data.requires); | ||
this.str += data.body; | ||
} | ||
} | ||
} | ||
}; | ||
Interface.prototype.generateSymbols = function () { | ||
const unscopables = {}; | ||
for (const member of this.idl.members) { | ||
if (utils.getExtAttr(member.extAttrs, "Unscopeable")) { | ||
unscopables[member.name] = true; | ||
generateSymbols() { | ||
const unscopables = Object.create(null); | ||
for (const member of this.idl.members) { | ||
if (utils.getExtAttr(member.extAttrs, "Unscopeable")) { | ||
unscopables[member.name] = true; | ||
} | ||
} | ||
} | ||
if (Object.keys(unscopables).length) { | ||
if (Object.keys(unscopables).length) { | ||
this.str += ` | ||
Object.defineProperty(${this.name}.prototype, Symbol.unscopables, { | ||
value: ${JSON.stringify(unscopables, null, " ")}, | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
`; | ||
} | ||
this.str += ` | ||
Object.defineProperty(${this.name}.prototype, Symbol.unscopables, { | ||
value: ${JSON.stringify(unscopables, null, ' ')}, | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
});\n`; | ||
Object.defineProperty(${this.name}.prototype, Symbol.toStringTag, { | ||
value: "${this.name}", | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
`; | ||
} | ||
this.str += ` | ||
Object.defineProperty(${this.name}.prototype, Symbol.toStringTag, { | ||
value: "${this.name}", | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
});\n`; | ||
}; | ||
Interface.prototype.generate = function () { | ||
this.generateIterator(); | ||
generate() { | ||
this.generateIterator(); | ||
if (this.factory) { | ||
this.str += ` | ||
module.exports = { | ||
createInterface: function (defaultPrivateData = {}) {\n\n`; | ||
} | ||
if (this.factory) { | ||
this.str += ` | ||
module.exports = { | ||
createInterface: function (defaultPrivateData = {}) { | ||
`; | ||
} | ||
this.generateConstructor(); | ||
this.generateMixins(); | ||
this.generateConstructor(); | ||
this.generateMixins(); | ||
this.generateOperations(); | ||
this.generateAttributes(); | ||
this.generateOperations(); | ||
this.generateAttributes(); | ||
this.generateRequires(); | ||
this.generateRequires(); | ||
this.generateSymbols(); | ||
this.generateSymbols(); | ||
this.str += ` | ||
const iface = {`; | ||
this.str += ` | ||
const iface = { | ||
`; | ||
if (this.factory) { | ||
this.generateIface(); | ||
this.str += ` | ||
}; | ||
return iface; | ||
},`; | ||
this.generateExport(); | ||
this.str += ` | ||
};\n`; | ||
} else { | ||
this.generateExport(); | ||
this.generateIface(); | ||
this.str += ` | ||
}; | ||
module.exports = iface;\n`; | ||
if (this.factory) { | ||
this.generateIface(); | ||
this.str += ` | ||
}; // iface | ||
return iface; | ||
}, // createInterface | ||
`; | ||
this.generateExport(); | ||
this.str += ` | ||
}; // module.exports | ||
`; | ||
} else { | ||
this.generateExport(); | ||
this.generateIface(); | ||
this.str += ` | ||
}; // iface | ||
module.exports = iface; | ||
`; | ||
} | ||
} | ||
}; | ||
Interface.prototype.toString = function () { | ||
this.str = ""; | ||
this.generate(); | ||
return this.str; | ||
}; | ||
toString() { | ||
this.str = ""; | ||
this.generate(); | ||
return this.str; | ||
} | ||
} | ||
Interface.prototype.type = "interface"; | ||
module.exports = Interface; |
"use strict"; | ||
const conversions = require("webidl-conversions"); | ||
const keywords = require("../keywords"); | ||
const utils = require("../utils"); | ||
function Iterable(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
this.name = idl.type; | ||
} | ||
Iterable.prototype.generateFunction = function (key, kind, keyExpr, fnName) { | ||
if (fnName === undefined) { | ||
fnName = typeof key === "symbol" ? "" : (keywords.has(key) ? "_" : key); | ||
class Iterable { | ||
constructor(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
this.name = idl.type; | ||
} | ||
const propExpr = typeof key === "symbol" ? `[${keyExpr}]` : `.${key}`; | ||
generateFunction(key, kind, keyExpr, fnName) { | ||
if (fnName === undefined) { | ||
if (typeof key === "symbol") { | ||
fnName = ""; | ||
} else { | ||
fnName = keywords.has(key) ? "_" : key; | ||
} | ||
} | ||
return `\n${this.obj.name}.prototype${propExpr} = function ${fnName}() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
const propExpr = typeof key === "symbol" ? `[${keyExpr}]` : `.${key}`; | ||
return ` | ||
${this.obj.name}.prototype${propExpr} = function ${fnName}() { | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
return module.exports.createDefaultIterator(this, "${kind}"); | ||
}; | ||
`; | ||
} | ||
return module.exports.createDefaultIterator(this, "${kind}"); | ||
}`; | ||
}; | ||
Iterable.prototype.generate = function () { | ||
const isPairIterator = utils.isPairIterable(this.idl); | ||
let str = ""; | ||
generate() { | ||
const isPairIterator = utils.isPairIterable(this.idl); | ||
let str = ""; | ||
if (isPairIterator) { | ||
str += this.generateFunction(Symbol.iterator, "key+value", "Symbol.iterator", "entries"); | ||
str += `\n${this.obj.name}.prototype.entries = ${this.obj.name}.prototype[Symbol.iterator];`; | ||
str += this.generateFunction("keys", "key"); | ||
str += this.generateFunction("values", "value"); | ||
str += `\n${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 | ||
} | ||
if (isPairIterator) { | ||
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 | ||
} | ||
return { | ||
requires: {}, | ||
body: str | ||
return { | ||
requires: {}, | ||
body: str | ||
}; | ||
} | ||
}; | ||
} | ||
module.exports = Iterable; |
@@ -10,85 +10,89 @@ "use strict"; | ||
function Operation(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
this.name = idl.name; | ||
} | ||
class Operation { | ||
constructor(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
this.interface = I; | ||
this.idl = idl; | ||
this.name = idl.name; | ||
} | ||
Operation.prototype.generate = function () { | ||
let requires = {}; | ||
let str = ""; | ||
generate() { | ||
const requires = {}; | ||
let str = ""; | ||
if (this.idl.name === null) { | ||
return { requires: {}, body: "" }; | ||
} | ||
let name = this.idl.name; | ||
if (!name) { | ||
if (this.idl.stringifier) { | ||
name = "toString"; | ||
} else { | ||
return { requires: {}, body: "" }; | ||
} | ||
} | ||
let name = this.idl.name; | ||
if (this.idl.stringifier && !name) { | ||
name = "toString"; | ||
} | ||
let targetObj = this.obj.name + (this.idl.static ? "" : ".prototype"); | ||
if (utils.isOnInstance(this.idl, this.interface)) { | ||
targetObj = "obj"; | ||
} | ||
let targetObj = this.obj.name + (this.idl.static ? "" : ".prototype"); | ||
if (utils.isOnInstance(this.idl, this.interface)) { | ||
targetObj = "obj"; | ||
} | ||
const overloads = Overloads.getEffectiveOverloads(name, 0, this.interface, null); | ||
let minConstructor = overloads[0]; | ||
const overloads = Overloads.getEffectiveOverloads(name, 0, this.interface, null); | ||
let minConstructor = overloads[0]; | ||
for (let i = 1; i < overloads.length; ++i) { | ||
if (overloads[i].nameList.length < minConstructor.nameList.length) { | ||
minConstructor = overloads[i]; | ||
for (let i = 1; i < overloads.length; ++i) { | ||
if (overloads[i].nameList.length < minConstructor.nameList.length) { | ||
minConstructor = overloads[i]; | ||
} | ||
} | ||
} | ||
const fnName = keywords.has(name) ? "_" : name; | ||
minConstructor.nameList = minConstructor.nameList.map((name) => (keywords.has(name) ? "_" : "") + name); | ||
const fnName = keywords.has(name) ? "_" : name; | ||
minConstructor.nameList = minConstructor.nameList.map(n => (keywords.has(n) ? "_" : "") + n); | ||
str += `\n${targetObj}.${name} = function ${fnName}(${minConstructor.nameList.join(", ")}) {`; | ||
if (!this.idl.static) { | ||
str += ` | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
}`; | ||
} | ||
${targetObj}.${name} = function ${fnName}(${minConstructor.nameList.join(", ")}) { | ||
`; | ||
if (!this.idl.static) { | ||
str += ` | ||
if (!this || !module.exports.is(this)) { | ||
throw new TypeError("Illegal invocation"); | ||
} | ||
`; | ||
} | ||
if (minConstructor.nameList.length !== 0) { | ||
const plural = minConstructor.nameList.length > 1 ? "s" : ""; | ||
str += ` | ||
if (arguments.length < ${minConstructor.nameList.length}) { | ||
throw new TypeError("Failed to execute '${name}' on '${this.obj.name}': ${minConstructor.nameList.length} argument${plural} required, but only " + arguments.length + " present."); | ||
}`; | ||
} | ||
if (minConstructor.nameList.length !== 0) { | ||
const plural = minConstructor.nameList.length > 1 ? "s" : ""; | ||
str += ` | ||
if (arguments.length < ${minConstructor.nameList.length}) { | ||
throw new TypeError("Failed to execute '${name}' on '${this.obj.name}': ${minConstructor.nameList.length} " + | ||
"argument${plural} required, but only " + arguments.length + " present."); | ||
} | ||
`; | ||
} | ||
const callOn = this.idl.static ? "Impl" : "this[impl]"; | ||
const callOn = this.idl.static ? "Impl" : "this[impl]"; | ||
const parameterConversions = Parameters.generateOverloadConversions(this.ctx, overloads, this.interface.name, `Failed to execute '${name}' on '${this.obj.name}': `); | ||
const argsSpread = parameterConversions.hasArgs ? "...args" : ""; | ||
Object.assign(requires, parameterConversions.requires); | ||
str += parameterConversions.body; | ||
if (!this.idl.stringifier && overloads.every((overload) => conversions[overload.operation.idlType.idlType])) { | ||
str += ` | ||
return ${callOn}.${name}(${argsSpread}); | ||
};\n`; | ||
} else { | ||
str += ` | ||
return utils.tryWrapperForImpl(${callOn}.${name}(${argsSpread})); | ||
};\n`; | ||
} | ||
if (this.idl.stringifier && name !== "toString") { | ||
str += `\n${this.name}.prototype.toString(${minConstructor.nameList.join(", ")}) {`; | ||
const parameterConversions = Parameters.generateOverloadConversions( | ||
this.ctx, overloads, this.interface.name, `Failed to execute '${name}' on '${this.obj.name}': `); | ||
const argsSpread = parameterConversions.hasArgs ? "...args" : ""; | ||
Object.assign(requires, parameterConversions.requires); | ||
str += parameterConversions.body; | ||
str += ` | ||
return ${callOn}.${name}.apply(${argsSpread}); | ||
};\n`; | ||
} | ||
return { | ||
requires, | ||
body: str | ||
if (this.idl.stringifier || overloads.every(overload => conversions[overload.operation.idlType.idlType])) { | ||
str += ` | ||
return ${callOn}.${name}(${argsSpread}); | ||
}; | ||
`; | ||
} else { | ||
str += ` | ||
return utils.tryWrapperForImpl(${callOn}.${name}(${argsSpread})); | ||
}; | ||
`; | ||
} | ||
return { | ||
requires, | ||
body: str | ||
}; | ||
} | ||
}; | ||
} | ||
module.exports = Operation; |
@@ -22,4 +22,4 @@ "use strict"; | ||
this.typedefs = new Map(); | ||
this.interfaces = Object.create(null); | ||
this.dictionaries = Object.create(null); | ||
this.interfaces = new Map(); | ||
this.dictionaries = new Map(); | ||
@@ -26,0 +26,0 @@ for (const typedef of builtinTypedefs) { |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
module.exports = new Set([ | ||
@@ -10,2 +12,2 @@ "break", "case", "class", "catch", "const", "continue", "debugger", "default", "delete", | ||
"null", "true", "false"]); | ||
"null", "true", "false"]); |
@@ -16,3 +16,3 @@ "use strict"; | ||
} | ||
return Buffer.from(bufferSource.buffer, bufferSource.byteOffset, bufferSource.byteLength) | ||
return Buffer.from(bufferSource.buffer, bufferSource.byteOffset, bufferSource.byteLength); | ||
} | ||
@@ -48,3 +48,4 @@ | ||
return wrapper[sameObjectCaches][prop] = creator(); | ||
wrapper[sameObjectCaches][prop] = creator(); | ||
return wrapper[sameObjectCaches][prop]; | ||
} | ||
@@ -54,7 +55,7 @@ | ||
return impl ? impl[wrapperSymbol] : null; | ||
}; | ||
} | ||
function implForWrapper(wrapper) { | ||
return wrapper ? wrapper[implSymbol] : null; | ||
}; | ||
} | ||
@@ -64,3 +65,3 @@ function tryWrapperForImpl(impl) { | ||
return wrapper ? wrapper : impl; | ||
}; | ||
} | ||
@@ -70,3 +71,3 @@ function tryImplForWrapper(wrapper) { | ||
return impl ? impl : wrapper; | ||
}; | ||
} | ||
@@ -73,0 +74,0 @@ const iterInternalSymbol = Symbol("internal"); |
"use strict"; | ||
module.exports.getEffectiveOverloads = function (A, N, I, C) { | ||
module.exports.getEffectiveOverloads = function (A, N, I) { // No |C| since we don't support callback function yet. | ||
const S = []; | ||
let F = null; | ||
if (A === 'constructor') { // let's hope no-one specs a member named "constructor" | ||
F = I.extAttrs | ||
.filter(function (a) { return a.name === 'Constructor'; }); | ||
F.forEach(function (c) { if (!c.arguments) { c.arguments = []; }}); | ||
if (A === "constructor") { // let's hope no-one specs a member named "constructor" | ||
F = I.extAttrs.filter(a => a.name === "Constructor"); | ||
for (const c of F) { | ||
if (!c.arguments) { | ||
c.arguments = []; | ||
} | ||
} | ||
} else if (typeof A === "string") { | ||
F = I.members | ||
.filter(function (m) { | ||
return m.name === A || (A === "toString" && m.stringifier); | ||
}); | ||
F.forEach(function (m) { if (m.stringifier) { m.arguments = []; }}); | ||
F = I.members.filter(m => m.name === A || (A === "toString" && m.stringifier)); | ||
for (const m of F) { | ||
if (m.stringifier) { | ||
m.arguments = []; | ||
} | ||
} | ||
} | ||
@@ -29,7 +33,11 @@ | ||
const n = X.arguments.length; | ||
const nameList = X.arguments.map(function (arg) { return arg.name; }); | ||
const typeList = X.arguments.map(function (arg) { return arg.idlType.idlType; }); | ||
const optionalityList = X.arguments.map(function (arg) { | ||
if (arg.optional) return "optional"; | ||
if (arg.variadic) return "variadic"; | ||
const nameList = X.arguments.map(arg => arg.name); | ||
const typeList = X.arguments.map(arg => arg.idlType.idlType); | ||
const optionalityList = X.arguments.map(arg => { | ||
if (arg.optional) { | ||
return "optional"; | ||
} | ||
if (arg.variadic) { | ||
return "variadic"; | ||
} | ||
return "required"; | ||
@@ -40,19 +48,22 @@ }); | ||
operation: X, | ||
nameList: nameList, | ||
typeList: typeList, | ||
optionalityList: optionalityList | ||
nameList, | ||
typeList, | ||
optionalityList | ||
}); | ||
if (optionalityList[optionalityList.length - 1] === "variadic") { | ||
S.push({ | ||
operation: X, | ||
nameList: nameList.slice(0, -1), | ||
typeList: typeList.slice(0, -1), | ||
optionalityList: optionalityList.slice(0, -1) | ||
}); | ||
//TODO: Handle variadic arguments better | ||
for (let i = n; i <= m - 1; i++) { | ||
S.push({ | ||
operation: X, | ||
nameList: nameList.slice(0, i + 1), | ||
typeList: typeList.slice(0, i + 1), | ||
optionalityList: optionalityList.slice(0, i + 1) | ||
}); | ||
} | ||
} | ||
for (let i = n - 1; i >= 0; --i) { | ||
if (optionalityList[i] === "required") break; | ||
if (optionalityList[i] === "required") { | ||
break; | ||
} | ||
S.push({ | ||
@@ -59,0 +70,0 @@ operation: X, |
@@ -8,19 +8,2 @@ "use strict"; | ||
function getDefault(dflt) { | ||
switch (dflt.type) { | ||
case "boolean": | ||
case "number": | ||
case "string": | ||
return JSON.stringify(dflt.value); | ||
case "null": | ||
case "NaN": | ||
return dflt.type; | ||
case "Infinity": | ||
return `${dflt.negative ? "-" : ""}Infinity`; | ||
case "sequence": | ||
return "[]"; | ||
} | ||
throw new Error("Unexpected default type: " + dflt.type); | ||
} | ||
function generateVarConversion(ctx, name, conversion, argAttrs, ...typeArgs) { | ||
@@ -32,5 +15,8 @@ const { customTypes } = ctx; | ||
if (conversion.optional && customTypes.get(idlType.idlType) !== "dictionary") { // always (try to) force-convert dictionaries | ||
// Always (try to) force-convert dictionaries | ||
const optional = conversion.optional && customTypes.get(idlType.idlType) !== "dictionary"; | ||
if (optional) { | ||
str += ` | ||
if (${name} !== undefined) {`; | ||
if (${name} !== undefined) { | ||
`; | ||
} | ||
@@ -42,9 +28,10 @@ | ||
if (conversion.optional && customTypes.get(idlType.idlType) !== "dictionary") { | ||
str += ` | ||
}`; | ||
if (optional) { | ||
str += "}"; | ||
if (conversion.default) { | ||
str += ` else { | ||
${name} = ${getDefault(conversion.default)}; | ||
}`; | ||
str += ` | ||
else { | ||
${name} = ${utils.getDefault(conversion.default)}; | ||
} | ||
`; | ||
} | ||
@@ -57,6 +44,5 @@ } | ||
}; | ||
}; | ||
} | ||
module.exports.generateOverloadConversions = function (ctx, overloads, parentName, errPrefix) { | ||
const { customTypes } = ctx; | ||
const requires = {}; | ||
@@ -85,7 +71,8 @@ let str = ``; | ||
const extraClause = !isVariadic ? ` && i < ${maxArguments}` : ``; | ||
str += `\n | ||
const args = []; | ||
for (let i = 0; i < arguments.length${extraClause}; ++i) { | ||
args[i] = arguments[i]; | ||
}`; | ||
str += ` | ||
const args = []; | ||
for (let i = 0; i < arguments.length${extraClause}; ++i) { | ||
args[i] = arguments[i]; | ||
} | ||
`; | ||
@@ -97,3 +84,5 @@ for (let i = 0; i < typeConversions.length; ++i) { | ||
const conv = generateVarConversion(ctx, `args[${i}]`, typeConversions[i], maxConstructor.operation.arguments[i].extAttrs, parentName, `"${errPrefix}parameter ${i + 1}"`); | ||
const conv = generateVarConversion( | ||
ctx, `args[${i}]`, typeConversions[i], maxConstructor.operation.arguments[i].extAttrs, parentName, | ||
`"${errPrefix}parameter ${i + 1}"`); | ||
Object.assign(requires, conv.requires); | ||
@@ -100,0 +89,0 @@ str += conv.body; |
"use strict"; | ||
module.exports["boolean"] = { | ||
module.exports.boolean = { | ||
get(objName, attrName) { | ||
@@ -8,14 +8,18 @@ return `return this.hasAttribute("${attrName}");`; | ||
set(objName, attrName) { | ||
return `if (V) { | ||
this.setAttribute("${attrName}", ""); | ||
} else { | ||
this.removeAttribute("${attrName}"); | ||
}`; | ||
return ` | ||
if (V) { | ||
this.setAttribute("${attrName}", ""); | ||
} else { | ||
this.removeAttribute("${attrName}"); | ||
} | ||
`; | ||
} | ||
}; | ||
module.exports["DOMString"] = { | ||
module.exports.DOMString = { | ||
get(objName, attrName) { | ||
return `const value = this.getAttribute("${attrName}"); | ||
return value === null ? "" : value;`; | ||
return ` | ||
const value = this.getAttribute("${attrName}"); | ||
return value === null ? "" : value; | ||
`; | ||
}, | ||
@@ -27,6 +31,8 @@ set(objName, attrName) { | ||
module.exports["long"] = { | ||
module.exports.long = { | ||
get(objName, attrName) { | ||
return `const value = parseInt(this.getAttribute("${attrName}")); | ||
return isNaN(value) || value < -2147483648 || value > 2147483647 ? 0 : value`; | ||
return ` | ||
const value = parseInt(this.getAttribute("${attrName}")); | ||
return isNaN(value) || value < -2147483648 || value > 2147483647 ? 0 : value | ||
`; | ||
}, | ||
@@ -40,9 +46,10 @@ set(objName, attrName) { | ||
get(objName, attrName) { | ||
return `const value = parseInt(this.getAttribute("${attrName}")); | ||
return isNaN(value) || value < 0 || value > 2147483647 ? 0 : value`; | ||
return ` | ||
const value = parseInt(this.getAttribute("${attrName}")); | ||
return isNaN(value) || value < 0 || value > 2147483647 ? 0 : value | ||
`; | ||
}, | ||
set(objName, attrName) { | ||
return `V = V > 2147483647 ? 0 : V; | ||
this.setAttribute("${attrName}", String(V));`; | ||
return `this.setAttribute("${attrName}", String(V > 2147483647 ? 0 : V));`; | ||
} | ||
}; |
@@ -38,4 +38,4 @@ "use strict"; | ||
*_collectSources() { | ||
const stats = yield Promise.all(this.sources.map((src) => fs.stat(src.idlPath))); | ||
* _collectSources() { | ||
const stats = yield Promise.all(this.sources.map(src => fs.stat(src.idlPath))); | ||
const files = []; | ||
@@ -63,5 +63,5 @@ for (let i = 0; i < stats.length; ++i) { | ||
*_readFiles(files) { | ||
* _readFiles(files) { | ||
const zipped = []; | ||
const fileContents = yield Promise.all(files.map((f) => fs.readFile(f.idlPath, { encoding: 'utf-8' }))); | ||
const fileContents = yield Promise.all(files.map(f => fs.readFile(f.idlPath, { encoding: "utf-8" }))); | ||
for (let i = 0; i < files.length; ++i) { | ||
@@ -76,4 +76,4 @@ zipped.push({ | ||
*_parse(outputDir, contents) { | ||
const parsed = contents.map((content) => ({ | ||
_parse(outputDir, contents) { | ||
const parsed = contents.map(content => ({ | ||
idl: webidl.parse(content.idlContent), | ||
@@ -99,3 +99,3 @@ impl: content.impl | ||
}); | ||
interfaces[obj.name] = obj; | ||
interfaces.set(obj.name, obj); | ||
customTypes.set(obj.name, "interface"); | ||
@@ -111,3 +111,3 @@ break; | ||
obj = new Dictionary(this.ctx, instruction); | ||
dictionaries[obj.name] = obj; | ||
dictionaries.set(obj.name, obj); | ||
customTypes.set(obj.name, "dictionary"); | ||
@@ -138,9 +138,9 @@ break; | ||
if (this.options.suppressErrors && !interfaces[instruction.name]) { | ||
if (this.options.suppressErrors && !interfaces.has(instruction.name)) { | ||
break; | ||
} | ||
oldMembers = interfaces[instruction.name].idl.members; | ||
oldMembers.push.apply(oldMembers, instruction.members); | ||
extAttrs = interfaces[instruction.name].idl.extAttrs; | ||
extAttrs.push.apply(extAttrs, instruction.extAttrs); | ||
oldMembers = interfaces.get(instruction.name).idl.members; | ||
oldMembers.push(...instruction.members); | ||
extAttrs = interfaces.get(instruction.name).idl.extAttrs; | ||
extAttrs.push(...instruction.extAttrs); | ||
break; | ||
@@ -151,15 +151,15 @@ case "dictionary": | ||
} | ||
if (this.options.suppressErrors && !dictionaries[instruction.name]) { | ||
if (this.options.suppressErrors && !dictionaries.has(instruction.name)) { | ||
break; | ||
} | ||
oldMembers = dictionaries[instruction.name].idl.members; | ||
oldMembers.push.apply(oldMembers, instruction.members); | ||
extAttrs = dictionaries[instruction.name].idl.extAttrs; | ||
extAttrs.push.apply(extAttrs, instruction.extAttrs); | ||
oldMembers = dictionaries.get(instruction.name).idl.members; | ||
oldMembers.push(...instruction.members); | ||
extAttrs = dictionaries.get(instruction.name).idl.extAttrs; | ||
extAttrs.push(...instruction.extAttrs); | ||
break; | ||
case "implements": | ||
if (this.options.suppressErrors && !interfaces[instruction.target]) { | ||
if (this.options.suppressErrors && !interfaces.has(instruction.target)) { | ||
break; | ||
} | ||
interfaces[instruction.target].implements(instruction.implements); | ||
interfaces.get(instruction.target).implements(instruction.implements); | ||
break; | ||
@@ -171,4 +171,4 @@ } | ||
*_writeFiles(outputDir) { | ||
let utilsText = yield fs.readFile(__dirname + "/output/utils.js"); | ||
* _writeFiles(outputDir) { | ||
const utilsText = yield fs.readFile(path.resolve(__dirname, "output/utils.js")); | ||
yield fs.writeFile(this.options.utilPath, utilsText); | ||
@@ -178,15 +178,3 @@ | ||
let interfaceStub = yield fs.readFile(__dirname + "/output/interfaceStub.js"); | ||
let keys = Object.keys(interfaces).concat(Object.keys(dictionaries)); | ||
for (let key of keys) { | ||
if (interfaces[key]) { | ||
yield fs.writeFile(path.join(outputDir, interfaces[key].name + ".js"), interfaceStub); | ||
} else { | ||
yield fs.writeFile(path.join(outputDir, dictionaries[key].name + ".js"), ""); | ||
} | ||
} | ||
keys = Object.keys(interfaces); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const obj = interfaces[keys[i]]; | ||
for (const obj of interfaces.values()) { | ||
let source = obj.toString(); | ||
@@ -200,3 +188,3 @@ | ||
let relativeUtils = path.relative(outputDir, this.options.utilPath).replace(/\\/g, '/'); | ||
let relativeUtils = path.relative(outputDir, this.options.utilPath).replace(/\\/g, "/"); | ||
if (relativeUtils[0] !== ".") { | ||
@@ -206,7 +194,10 @@ relativeUtils = "./" + relativeUtils; | ||
source = `"use strict"; | ||
source = ` | ||
"use strict"; | ||
const conversions = require("webidl-conversions"); | ||
const utils = require("${relativeUtils}");\n${source} | ||
const Impl = require("${implFile}.js");\n`; | ||
const conversions = require("webidl-conversions"); | ||
const utils = require("${relativeUtils}"); | ||
${source} | ||
const Impl = require("${implFile}.js"); | ||
`; | ||
@@ -218,8 +209,6 @@ source = this._prettify(source); | ||
keys = Object.keys(dictionaries); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const obj = dictionaries[keys[i]]; | ||
for (const obj of dictionaries.values()) { | ||
let source = obj.toString(); | ||
let relativeUtils = path.relative(outputDir, this.options.utilPath).replace(/\\/g, '/'); | ||
let relativeUtils = path.relative(outputDir, this.options.utilPath).replace(/\\/g, "/"); | ||
if (relativeUtils[0] !== ".") { | ||
@@ -229,6 +218,9 @@ relativeUtils = "./" + relativeUtils; | ||
source = `"use strict"; | ||
source = ` | ||
"use strict"; | ||
const conversions = require("webidl-conversions"); | ||
const utils = require("${relativeUtils}");\n\n` + source; | ||
const conversions = require("webidl-conversions"); | ||
const utils = require("${relativeUtils}"); | ||
${source} | ||
`; | ||
@@ -243,3 +235,3 @@ source = this._prettify(source); | ||
return prettier.format(source, { | ||
printWidth: 120, | ||
printWidth: 120 | ||
}); | ||
@@ -249,3 +241,5 @@ } | ||
generate(outputDir) { | ||
if (!this.options.utilPath) this.options.utilPath = path.join(outputDir, "utils.js"); | ||
if (!this.options.utilPath) { | ||
this.options.utilPath = path.join(outputDir, "utils.js"); | ||
} | ||
@@ -255,3 +249,3 @@ return co(function* () { | ||
const contents = yield* this._readFiles(sources); | ||
yield* this._parse(outputDir, contents); | ||
this._parse(outputDir, contents); | ||
yield* this._writeFiles(outputDir); | ||
@@ -258,0 +252,0 @@ }.bind(this)); |
224
lib/types.js
@@ -7,2 +7,15 @@ "use strict"; | ||
const arrayBufferViewTypes = new Set([ | ||
"Int8Array", "Int16Array", "Int32Array", "Uint8Array", "Uint16Array", "Uint32Array", | ||
"Uint8ClampedArray", "Float32Array", "Float64Array", "DataView" | ||
]); | ||
const stringTypes = new Set(["DOMString", "ByteString", "USVString"]); | ||
const integerTypes = new Set([ | ||
"byte", "octet", "short", "unsigned short", "long", "unsigned long", | ||
"long long", "unsigned long long" | ||
]); | ||
const numericTypes = new Set([ | ||
...integerTypes, "float", "unrestricted float", "double", "unrestricted double" | ||
]); | ||
function mergeExtAttrs(a = [], b = []) { | ||
@@ -55,6 +68,5 @@ return [...a, ...b]; | ||
return idlType; | ||
} else { | ||
// unknown | ||
return idlType; | ||
} | ||
// unknown | ||
return idlType; | ||
} | ||
@@ -76,5 +88,6 @@ | ||
str += ` | ||
if (${name} === null || ${name} === undefined) { | ||
${name} = null; | ||
} else {`; | ||
if (${name} === null || ${name} === undefined) { | ||
${name} = null; | ||
} else { | ||
`; | ||
} | ||
@@ -115,8 +128,8 @@ | ||
str += ` | ||
${name} = utils.tryImplForWrapper(${name});`; | ||
${name} = utils.tryImplForWrapper(${name}); | ||
`; | ||
} | ||
if (idlType.nullable) { | ||
str += ` | ||
}`; | ||
str += "}"; | ||
} | ||
@@ -140,8 +153,9 @@ | ||
if (!idlType.nullable && union.dictionary) { | ||
let str = `if (${name} === null || ${name} === undefined) {` | ||
const conv = generateTypeConversion(ctx, name, union.dictionary, [], parentName, errPrefix); | ||
Object.assign(requires, conv.requires); | ||
str += conv.body; | ||
str += "}"; | ||
output.push(str); | ||
output.push(` | ||
if (${name} === null || ${name} === undefined) { | ||
${conv.body} | ||
} | ||
`); | ||
} | ||
@@ -165,5 +179,7 @@ | ||
}); | ||
output.push(`if (${exprs.join(" || ")}) { | ||
${name} = utils.implForWrapper(${name}); | ||
}`); | ||
output.push(` | ||
if (${exprs.join(" || ")}) { | ||
${name} = utils.implForWrapper(${name}); | ||
} | ||
`); | ||
} | ||
@@ -195,10 +211,11 @@ | ||
if (union.sequenceLike || union.dictionary || union.record || union.object) { | ||
let str = `if (utils.isObject(${name})) {`; | ||
let code = `if (utils.isObject(${name})) {`; | ||
if (union.sequenceLike) { | ||
str += `if (${name}[Symbol.iterator] !== undefined) {`; | ||
const conv = generateTypeConversion(ctx, name, union.sequenceLike, [], parentName, `${errPrefix} + " sequence"`); | ||
code += `if (${name}[Symbol.iterator] !== undefined) {`; | ||
const conv = generateTypeConversion(ctx, name, union.sequenceLike, [], parentName, | ||
`${errPrefix} + " sequence"`); | ||
Object.assign(requires, conv.requires); | ||
str += conv.body; | ||
str += `} else {`; | ||
code += conv.body; | ||
code += `} else {`; | ||
} | ||
@@ -208,5 +225,6 @@ | ||
const prop = union.dictionary ? "dictionary" : "record"; | ||
const conv = generateTypeConversion(ctx, name, union[prop], [], parentName, `${errPrefix} + " ${prop}"`); | ||
const conv = generateTypeConversion(ctx, name, union[prop], [], parentName, | ||
`${errPrefix} + " ${prop}"`); | ||
Object.assign(requires, conv.requires); | ||
str += conv.body; | ||
code += conv.body; | ||
} else if (union.object) { | ||
@@ -217,32 +235,36 @@ // noop | ||
if (union.sequenceLike) { | ||
str += "}"; | ||
code += "}"; | ||
} | ||
str += "}"; | ||
code += "}"; | ||
output.push(str); | ||
output.push(code); | ||
} | ||
if (union.boolean) { | ||
output.push(`if (typeof ${name} === "boolean") { | ||
${generateTypeConversion(ctx, name, union.boolean, [], parentName, errPrefix).body} | ||
}`); | ||
output.push(` | ||
if (typeof ${name} === "boolean") { | ||
${generateTypeConversion(ctx, name, union.boolean, [], parentName, errPrefix).body} | ||
} | ||
`); | ||
} | ||
if (union.numeric) { | ||
output.push(`if (typeof ${name} === "number") { | ||
${generateTypeConversion(ctx, name, union.numeric, [], parentName, errPrefix).body} | ||
}`); | ||
output.push(` | ||
if (typeof ${name} === "number") { | ||
${generateTypeConversion(ctx, name, union.numeric, [], parentName, errPrefix).body} | ||
} | ||
`); | ||
} | ||
{ | ||
let str = "{"; | ||
let code = "{"; | ||
const type = union.string || union.numeric || union.boolean; | ||
if (type) { | ||
str += generateTypeConversion(ctx, name, type, [], parentName, errPrefix).body; | ||
code += generateTypeConversion(ctx, name, type, [], parentName, errPrefix).body; | ||
} else { | ||
str += `throw new TypeError(${errPrefix} + " is not of any supported type.")`; | ||
code += `throw new TypeError(${errPrefix} + " is not of any supported type.")`; | ||
} | ||
str += "}"; | ||
output.push(str); | ||
code += "}"; | ||
output.push(code); | ||
} | ||
@@ -254,61 +276,68 @@ | ||
function generateSequence() { | ||
str += ` | ||
if (!utils.isObject(${name})) { | ||
throw new TypeError(${errPrefix} + " is not an iterable object."); | ||
} else { | ||
const V = []; | ||
const tmp = ${name}; | ||
for (let nextItem of tmp) {`; | ||
const conv = generateTypeConversion(ctx, "nextItem", idlType.idlType, [], parentName, `${errPrefix} + "'s element"`); | ||
const conv = generateTypeConversion(ctx, "nextItem", idlType.idlType, [], parentName, | ||
`${errPrefix} + "'s element"`); | ||
Object.assign(requires, conv.requires); | ||
str += conv.body; | ||
str += ` | ||
V.push(nextItem); | ||
} | ||
${name} = V; | ||
}`; | ||
if (!utils.isObject(${name})) { | ||
throw new TypeError(${errPrefix} + " is not an iterable object."); | ||
} else { | ||
const V = []; | ||
const tmp = ${name}; | ||
for (let nextItem of tmp) { | ||
${conv.body} | ||
V.push(nextItem); | ||
} | ||
${name} = V; | ||
} | ||
`; | ||
} | ||
function generateRecord() { | ||
str += ` | ||
if (!utils.isObject(${name})) { | ||
throw new TypeError(${errPrefix} + " is not an object."); | ||
} else { | ||
const result = Object.create(null); | ||
for (const key of Reflect.ownKeys(${name})) { | ||
const desc = Object.getOwnPropertyDescriptor(${name}, key); | ||
if (desc && desc.enumerable) { | ||
let typedKey = key; | ||
let typedValue = ${name}[key];`; | ||
const keyConv = generateTypeConversion(ctx, "typedKey", idlType.idlType[0], [], parentName, | ||
`${errPrefix} + "'s key"`); | ||
Object.assign(requires, keyConv.requires); | ||
const valConv = generateTypeConversion(ctx, "typedValue", idlType.idlType[1], [], parentName, | ||
`${errPrefix} + "'s value"`); | ||
Object.assign(requires, valConv.requires); | ||
str += generateTypeConversion(ctx, "typedKey", idlType.idlType[0], [], parentName, `${errPrefix} + "'s key"`).body; | ||
const conv = generateTypeConversion(ctx, "typedValue", idlType.idlType[1], [], parentName, `${errPrefix} + "'s value"`); | ||
Object.assign(requires, conv.requires); | ||
str += conv.body; | ||
str += ` | ||
result[typedKey] = typedValue; | ||
if (!utils.isObject(${name})) { | ||
throw new TypeError(${errPrefix} + " is not an object."); | ||
} else { | ||
const result = Object.create(null); | ||
for (const key of Reflect.ownKeys(${name})) { | ||
const desc = Object.getOwnPropertyDescriptor(${name}, key); | ||
if (desc && desc.enumerable) { | ||
let typedKey = key; | ||
let typedValue = ${name}[key]; | ||
${keyConv.body} | ||
${valConv.body} | ||
result[typedKey] = typedValue; | ||
} | ||
} | ||
${name} = result; | ||
} | ||
} | ||
${name} = result; | ||
}`; | ||
`; | ||
} | ||
function generatePromise() { | ||
str += ` | ||
${name} = Promise.resolve(${name}).then(value => {` | ||
let handler; | ||
if (idlType.idlType.idlType === "void") { | ||
// Do nothing. | ||
handler = ""; | ||
} else { | ||
const conv = generateTypeConversion(ctx, "value", idlType.idlType, [], parentName, `${errPrefix} + " promise value"`); | ||
const conv = generateTypeConversion(ctx, "value", idlType.idlType, [], parentName, | ||
`${errPrefix} + " promise value"`); | ||
Object.assign(requires, conv.requires); | ||
str += conv.body; | ||
str += ` | ||
return value;`; | ||
handler = ` | ||
${conv.body} | ||
return value; | ||
`; | ||
} | ||
str += ` | ||
}, reason => reason);`; | ||
${name} = Promise.resolve(${name}).then(value => { | ||
${handler} | ||
}, reason => reason); | ||
`; | ||
} | ||
@@ -318,4 +347,3 @@ | ||
generateSequence(); | ||
str += ` | ||
${name} = Object.freeze(${name});`; | ||
str += `${name} = Object.freeze(${name});`; | ||
} | ||
@@ -328,21 +356,22 @@ | ||
let optString = `, { context: ${errPrefix}`; | ||
let optString = `context: ${errPrefix},`; | ||
if (clamp) { | ||
optString += ", clamp: true"; | ||
optString += "clamp: true,"; | ||
} | ||
if (enforceRange) { | ||
optString += ", enforceRange: true"; | ||
optString += "enforceRange: true,"; | ||
} | ||
if (treatNullAs && treatNullAs.rhs.value === "EmptyString") { | ||
optString += ", treatNullAsEmptyString: true"; | ||
optString += "treatNullAsEmptyString: true,"; | ||
} | ||
optString += " }"; | ||
if (idlType.array) { | ||
str += ` | ||
for (let i = 0; i < ${name}.length; ++i) { | ||
${name}[i] = ${conversionFn}(${name}[i]${optString}); | ||
}`; | ||
for (let i = 0; i < ${name}.length; ++i) { | ||
${name}[i] = ${conversionFn}(${name}[i], { ${optString} }); | ||
} | ||
`; | ||
} else { | ||
str += ` | ||
${name} = ${conversionFn}(${name}${optString});`; | ||
${name} = ${conversionFn}(${name}, { ${optString} }); | ||
`; | ||
} | ||
@@ -352,15 +381,2 @@ } | ||
const arrayBufferViewTypes = new Set([ | ||
"Int8Array", "Int16Array", "Int32Array", "Uint8Array", "Uint16Array", "Uint32Array", | ||
"Uint8ClampedArray", "Float32Array", "Float64Array", "DataView" | ||
]); | ||
const stringTypes = new Set(["DOMString", "ByteString", "USVString"]); | ||
const integerTypes = new Set([ | ||
"byte", "octet", "short", "unsigned short", "long", "unsigned long", | ||
"long long", "unsigned long long" | ||
]); | ||
const numericTypes = new Set([ | ||
...integerTypes, "float", "unrestricted float", "double", "unrestricted double" | ||
]); | ||
// Condense the member types of a union to a more consumable structured object. At the same time, check for the validity | ||
@@ -485,3 +501,3 @@ // of the union type (no forbidden types, no indistinguishable member types). Duplicated types are allowed for now | ||
} else { | ||
error(`Unknown custom type ${type}`) | ||
error(`Unknown custom type ${type}`); | ||
} | ||
@@ -495,3 +511,3 @@ } else { | ||
function error(msg) { | ||
throw new Error(`${msg}\n When compiling "${eval(errPrefix)}"`); | ||
throw new Error(`${msg}\n When compiling "${eval(errPrefix)}"`); // eslint-disable-line no-eval | ||
} | ||
@@ -498,0 +514,0 @@ } |
"use strict"; | ||
module.exports.getExtAttr = function getExtAttr(attrs, name) { | ||
function getDefault(dflt) { | ||
switch (dflt.type) { | ||
case "boolean": | ||
case "number": | ||
case "string": | ||
return JSON.stringify(dflt.value); | ||
case "null": | ||
case "NaN": | ||
return dflt.type; | ||
case "Infinity": | ||
return `${dflt.negative ? "-" : ""}Infinity`; | ||
case "sequence": | ||
return "[]"; | ||
} | ||
throw new Error("Unexpected default type: " + dflt.type); | ||
} | ||
function getExtAttr(attrs, name) { | ||
for (let i = 0; i < attrs.length; ++i) { | ||
@@ -11,16 +28,23 @@ if (attrs[i].name === name) { | ||
return null; | ||
}; | ||
} | ||
module.exports.isGlobal = function isGlobal(idl) { | ||
const isGlobal = !!module.exports.getExtAttr(idl.extAttrs, "Global") || | ||
!!module.exports.getExtAttr(idl.extAttrs, "PrimaryGlobal"); | ||
return isGlobal; | ||
}; | ||
function isGlobal(idl) { | ||
return Boolean(getExtAttr(idl.extAttrs, "Global")) || | ||
Boolean(getExtAttr(idl.extAttrs, "PrimaryGlobal")); | ||
} | ||
module.exports.isPairIterable = function isPairIterable(idl) { | ||
function isPairIterable(idl) { | ||
return idl.type === "iterable" && Array.isArray(idl.idlType) && idl.idlType.length === 2; | ||
}; | ||
} | ||
module.exports.isOnInstance = (memberIDL, interfaceIDL) => { | ||
return module.exports.getExtAttr(memberIDL.extAttrs, "Unforgeable") || module.exports.isGlobal(interfaceIDL); | ||
function isOnInstance(memberIDL, interfaceIDL) { | ||
return getExtAttr(memberIDL.extAttrs, "Unforgeable") || isGlobal(interfaceIDL); | ||
} | ||
module.exports = { | ||
getDefault, | ||
getExtAttr, | ||
isGlobal, | ||
isPairIterable, | ||
isOnInstance | ||
}; |
{ | ||
"name": "webidl2js", | ||
"version": "7.1.1", | ||
"version": "7.2.0", | ||
"description": "Auto-generates class structures for WebIDL specifications", | ||
@@ -9,7 +9,8 @@ "main": "lib/transformer.js", | ||
"pn": "^1.0.0", | ||
"prettier": "^1.5.2", | ||
"prettier": "^1.5.3", | ||
"webidl-conversions": "^4.0.0", | ||
"webidl2": "^4.0.0" | ||
"webidl2": "^4.1.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^4.3.0", | ||
"jest": "^20.0.4" | ||
@@ -19,3 +20,4 @@ }, | ||
"test": "jest", | ||
"update-snapshots": "jest --updateSnapshot" | ||
"update-snapshots": "jest --updateSnapshot", | ||
"lint": "eslint ." | ||
}, | ||
@@ -22,0 +24,0 @@ "author": "Sebastian Mayr <npm@smayr.name>", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
69797
21
2119
1
2
Updatedprettier@^1.5.3
Updatedwebidl2@^4.1.0