Comparing version 6.1.0 to 7.0.0
@@ -7,5 +7,6 @@ "use strict"; | ||
const reflector = require("../reflector"); | ||
const Parameters = require("../parameters"); | ||
const Types = require("../types"); | ||
function Attribute(obj, I, idl) { | ||
function Attribute(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
@@ -31,6 +32,5 @@ this.interface = I; | ||
let getterBody = `return utils.tryWrapperForImpl(${objName}[impl].${this.idl.name});`; | ||
let setterBody = `${objName}[impl].${this.idl.name} = utils.tryImplForWrapper(V);`; | ||
let setterBody = `${objName}[impl].${this.idl.name} = V;`; | ||
if (conversions[this.idl.idlType.idlType]) { | ||
getterBody = `return ${objName}[impl].${this.idl.name};`; | ||
setterBody = `${objName}[impl].${this.idl.name} = V;`; | ||
} | ||
@@ -59,3 +59,3 @@ | ||
if (!this.idl.readonly) { | ||
const conv = Parameters.generateVarConversion("V", { type: this.idl.idlType, optional: false }, this.idl.extAttrs, new Set()); | ||
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); | ||
@@ -62,0 +62,0 @@ let conversion = conv.body.replace(/\n/g, "\n "); |
"use strict"; | ||
function Constant(obj, I, idl) { | ||
function Constant(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
@@ -5,0 +6,0 @@ this.interface = I; |
"use strict"; | ||
const conversions = require("webidl-conversions"); | ||
const Types = require("../types"); | ||
const utils = require("../utils"); | ||
class Dictionary { | ||
constructor(idl, opts) { | ||
constructor(ctx, idl) { | ||
this.ctx = ctx; | ||
this.idl = idl; | ||
this.name = idl.name; | ||
this.opts = opts; | ||
} | ||
@@ -35,30 +35,11 @@ | ||
const argAttrs = field.extAttrs; | ||
const enforceRange = utils.getExtAttr(argAttrs, "EnforceRange"); | ||
const clamp = utils.getExtAttr(argAttrs, "Clamp"); | ||
let optString = ""; | ||
if (clamp) { | ||
optString = `, { clamp: true }`; | ||
} else if (enforceRange) { | ||
optString = `, { enforceRange: true }`; | ||
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;` | ||
let conversionFn = ""; | ||
if (conversions[typeConversion.idlType]) { | ||
conversionFn = `conversions["${typeConversion.idlType}"]`; | ||
} else if (this.opts.customTypes.has(typeConversion.idlType)) { | ||
this.str = `const convert${typeConversion.idlType} = require("./${typeConversion.idlType}");\n` + this.str; | ||
conversionFn = `convert${typeConversion.idlType}`; | ||
} | ||
if (typeConversion.array) { | ||
this.str += ` | ||
ret[key] = []; | ||
for (let i = 0; i < value.length; ++i) { | ||
ret[key][i] = ${conversionFn}(value[i]${optString}); | ||
}`; | ||
} else { | ||
this.str += ` | ||
ret[key] = ${conversionFn}(value${optString});`; | ||
} | ||
if (field.required) { | ||
@@ -86,7 +67,7 @@ this.str += ` | ||
module.exports = { | ||
convertInherit(obj, ret) {`; | ||
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);`; | ||
${this.idl.inheritance}.convertInherit(obj, ret, { context });`; | ||
} | ||
@@ -97,12 +78,9 @@ this._generateConversions(); | ||
convert(obj) { | ||
if (obj !== undefined && typeof obj !== "object") { | ||
throw new TypeError("Dictionary has to be 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.\`); | ||
} | ||
if (obj instanceof Date || obj instanceof RegExp) { | ||
throw new TypeError("Dictionary may not be a Date or RegExp object"); | ||
} | ||
const ret = Object.create(null); | ||
module.exports.convertInherit(obj, ret); | ||
module.exports.convertInherit(obj, ret, { context }); | ||
return ret; | ||
@@ -109,0 +87,0 @@ } |
@@ -14,3 +14,4 @@ "use strict"; | ||
function Interface(idl, opts) { | ||
function Interface(ctx, idl, opts) { | ||
this.ctx = ctx; | ||
this.idl = idl; | ||
@@ -24,3 +25,3 @@ this.name = idl.name; | ||
this.opts = opts; | ||
this.iterable = this.idl.members.some(member => member.type === "iterable"); | ||
this.hasPairIterator = this.idl.members.some(utils.isPairIterable); | ||
} | ||
@@ -35,3 +36,3 @@ | ||
Interface.prototype.generateIterator = function () { | ||
if (this.iterable) { | ||
if (this.hasPairIterator) { | ||
this.str += ` | ||
@@ -42,5 +43,3 @@ const IteratorPrototype = Object.create(utils.IteratorPrototype, { | ||
const internal = this[utils.iterInternalSymbol]; | ||
const target = internal.target; | ||
const kind = internal.kind; | ||
const index = internal.index; | ||
const { target, kind, index } = internal; | ||
const values = Array.from(target[impl]); | ||
@@ -54,2 +53,3 @@ const len = values.length; | ||
internal.index = index + 1; | ||
const [key, value] = pair.map(utils.tryWrapperForImpl); | ||
@@ -59,9 +59,9 @@ let result; | ||
case "key": | ||
result = pair[0]; | ||
result = key; | ||
break; | ||
case "value": | ||
result = pair[1]; | ||
result = value; | ||
break; | ||
case "key+value": | ||
result = [pair[0], pair[1]]; | ||
result = [key, value]; | ||
break; | ||
@@ -99,3 +99,3 @@ } | ||
const conversions = Parameters.generateOverloadConversions(overloads, this.opts.customTypes); | ||
const conversions = Parameters.generateOverloadConversions(this.ctx, overloads, this.name, `Failed to construct '${this.name}': `); | ||
Object.assign(this.requires, conversions.requires); | ||
@@ -195,13 +195,20 @@ | ||
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.iterable) { | ||
if (this.hasPairIterator) { | ||
this.str += ` | ||
createDefaultIterator(target, kind) { | ||
const iterator = Object.create(IteratorPrototype); | ||
iterator[utils.iterInternalSymbol] = { | ||
target, | ||
kind, | ||
index: 0 | ||
}; | ||
Object.defineProperty(iterator, utils.iterInternalSymbol, { | ||
value: { target, kind, index: 0 }, | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return iterator; | ||
@@ -263,3 +270,3 @@ },`; | ||
if (memberIdl.type === "attribute" && (utils.getExtAttr(memberIdl.extAttrs, "Unforgeable") || utils.isGlobal(this.idl))) { | ||
const member = new Attribute(this, this.idl, memberIdl); | ||
const member = new Attribute(this.ctx, this, this.idl, memberIdl); | ||
this.str += "\n " + member.generate().body.replace(/\n/g, '\n '); | ||
@@ -296,5 +303,10 @@ } | ||
const implClass = require(this.opts.implDir + "/" + this.name + this.opts.implSuffix); | ||
const implClass = require(this.opts.implDir + "/" + this.name + this.ctx.implSuffix); | ||
this.str += ` | ||
obj[impl] = new Impl.implementation(constructorArgs, privateData); | ||
Object.defineProperty(obj, impl, { | ||
value: new Impl.implementation(constructorArgs, privateData), | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
obj[impl][utils.wrapperSymbol] = obj;`; | ||
@@ -321,3 +333,3 @@ if (implClass.init) { | ||
case "operation": | ||
member = new Operation(this, this.idl, memberIdl, { customTypes: this.opts.customTypes }); | ||
member = new Operation(this.ctx, this, this.idl, memberIdl); | ||
if (done[member.name]) { | ||
@@ -329,3 +341,3 @@ continue; | ||
case "iterable": | ||
member = new Iterable(this, this.idl, memberIdl, { customTypes: this.opts.customTypes }); | ||
member = new Iterable(this.ctx, this, this.idl, memberIdl); | ||
break; | ||
@@ -355,6 +367,6 @@ default: | ||
} | ||
member = new Attribute(this, this.idl, memberIdl); | ||
member = new Attribute(this.ctx, this, this.idl, memberIdl); | ||
break; | ||
case "const": | ||
member = new Constant(this, this.idl, memberIdl); | ||
member = new Constant(this.ctx, this, this.idl, memberIdl); | ||
break; | ||
@@ -384,5 +396,16 @@ default: | ||
this.str += ` | ||
${this.name}.prototype[Symbol.unscopables] = ${JSON.stringify(unscopables, null, ' ')};\n`; | ||
Object.defineProperty(${this.name}.prototype, Symbol.unscopables, { | ||
value: ${JSON.stringify(unscopables, null, ' ')}, | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
});\n`; | ||
} | ||
this.str += `\n${this.name}.prototype[Symbol.toStringTag] = ${JSON.stringify(this.name)};\n`; | ||
this.str += ` | ||
Object.defineProperty(${this.name}.prototype, Symbol.toStringTag, { | ||
value: "${this.name}", | ||
writable: false, | ||
enumerable: false, | ||
configurable: true | ||
});\n`; | ||
}; | ||
@@ -389,0 +412,0 @@ |
@@ -5,4 +5,6 @@ "use strict"; | ||
const keywords = require("../keywords"); | ||
const utils = require("../utils"); | ||
function Iterable(obj, I, idl, opts) { | ||
function Iterable(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
@@ -12,3 +14,2 @@ this.interface = I; | ||
this.name = idl.type; | ||
this.opts = opts; | ||
} | ||
@@ -32,3 +33,3 @@ | ||
Iterable.prototype.generate = function () { | ||
const isPairIterator = Array.isArray(this.idl.idlType) && this.idl.idlType.length === 2; | ||
const isPairIterator = utils.isPairIterable(this.idl); | ||
let str = ""; | ||
@@ -55,3 +56,3 @@ | ||
while (i < pairs.length) { | ||
const [key, value] = pairs[i]; | ||
const [key, value] = pairs[i].map(utils.tryWrapperForImpl); | ||
callback.call(thisArg, value, key, this); | ||
@@ -62,5 +63,6 @@ pairs = Array.from(this[impl]); | ||
};`; | ||
} else { | ||
// value iterator; WIP | ||
} | ||
return { | ||
@@ -67,0 +69,0 @@ requires: {}, |
@@ -8,3 +8,4 @@ "use strict"; | ||
function Operation(obj, I, idl) { | ||
function Operation(ctx, obj, I, idl) { | ||
this.ctx = ctx; | ||
this.obj = obj; | ||
@@ -56,3 +57,3 @@ this.interface = I; | ||
const parameterConversions = Parameters.generateOverloadConversions(overloads, this.obj.opts.customTypes); | ||
const parameterConversions = Parameters.generateOverloadConversions(this.ctx, overloads, this.interface.name, `Failed to execute '${name}' on '${this.obj.name}': `); | ||
const argsSpread = parameterConversions.hasArgs ? "...args" : ""; | ||
@@ -59,0 +60,0 @@ Object.assign(requires, parameterConversions.requires); |
@@ -68,3 +68,3 @@ "use strict"; | ||
module.exports.proveSimiliarity = function (overloads) { | ||
module.exports.proveSimiliarity = function (ctx, overloads) { | ||
let maxArguments = overloads[0].nameList.length; | ||
@@ -97,2 +97,3 @@ for (let i = 1; i < overloads.length; ++i) { | ||
maybeType = null; | ||
break; | ||
} | ||
@@ -105,2 +106,2 @@ } | ||
return typeConversions; | ||
}; | ||
}; |
"use strict"; | ||
const conversions = require("webidl-conversions"); | ||
const Overloads = require("./overloads"); | ||
const Types = require("./types"); | ||
const utils = require("./utils"); | ||
module.exports.generateVarConversion = function (name, conversion, argAttrs, customTypes) { | ||
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) { | ||
const { customTypes } = ctx; | ||
const requires = {}; | ||
@@ -13,56 +31,19 @@ let str = ""; | ||
if (idlType.nullable) { | ||
if (conversion.optional && customTypes.get(idlType.idlType) !== "dictionary") { // always (try to) force-convert dictionaries | ||
str += ` | ||
if (${name} === null || ${name} === undefined) { | ||
${name} = null; | ||
} else {`; | ||
if (${name} !== undefined) {`; | ||
} | ||
if (conversions[idlType.idlType] || customTypes.has(idlType.idlType)) { | ||
const enforceRange = utils.getExtAttr(argAttrs, "EnforceRange"); | ||
const clamp = utils.getExtAttr(argAttrs, "Clamp"); | ||
const treatNullAs = utils.getExtAttr(argAttrs, "TreatNullAs"); | ||
let optString = ""; | ||
if (clamp) { | ||
optString = `, { clamp: true }`; | ||
} else if (enforceRange) { | ||
optString = `, { enforceRange: true }`; | ||
} else if (treatNullAs && treatNullAs.rhs.value === "EmptyString") { | ||
optString = `, { treatNullAsEmptyString: true }`; | ||
} | ||
let conversionFn = null; | ||
if (conversions[idlType.idlType]) { | ||
conversionFn = `conversions["${idlType.idlType}"]`; | ||
} else { | ||
requires[`convert${idlType.idlType}`] = `require("./${idlType.idlType}").convert`; | ||
conversionFn = `convert${idlType.idlType}`; | ||
} | ||
if (conversion.optional && !customTypes.has(idlType.idlType)) { // always (try to) force-convert dictionaries | ||
str += ` | ||
if (${name} !== undefined) {`; | ||
} | ||
if (idlType.array) { | ||
str += ` | ||
for (let i = 0; i < ${name}.length; ++i) { | ||
${name}[i] = ${conversionFn}(${name}[i]${optString}); | ||
}`; | ||
} else { | ||
str += ` | ||
${name} = ${conversionFn}(${name}${optString});`; | ||
} | ||
if (conversion.optional && !customTypes.has(idlType.idlType)) { | ||
str += ` | ||
}`; | ||
if (conversion.default) { | ||
str += ` else { | ||
${name} = ${JSON.stringify(conversion.default.value)}; | ||
}`; | ||
} | ||
} | ||
} | ||
const conv = Types.generateTypeConversion(ctx, name, idlType, argAttrs, ...typeArgs); | ||
Object.assign(requires, conv.requires); | ||
str += conv.body; | ||
if (idlType.nullable) { | ||
if (conversion.optional && customTypes.get(idlType.idlType) !== "dictionary") { | ||
str += ` | ||
}`; | ||
}`; | ||
if (conversion.default) { | ||
str += ` else { | ||
${name} = ${getDefault(conversion.default)}; | ||
}`; | ||
} | ||
} | ||
@@ -76,3 +57,4 @@ | ||
module.exports.generateOverloadConversions = function (overloads, customTypes) { | ||
module.exports.generateOverloadConversions = function (ctx, overloads, parentName, errPrefix) { | ||
const { customTypes } = ctx; | ||
const requires = {}; | ||
@@ -96,3 +78,3 @@ let str = ``; | ||
const typeConversions = Overloads.proveSimiliarity(overloads); | ||
const typeConversions = Overloads.proveSimiliarity(ctx, overloads); | ||
@@ -105,3 +87,3 @@ const isAlwaysZeroArgs = !isVariadic && maxArguments === 0; | ||
for (let i = 0; i < arguments.length${extraClause}; ++i) { | ||
args[i] = utils.tryImplForWrapper(arguments[i]); | ||
args[i] = arguments[i]; | ||
}`; | ||
@@ -114,3 +96,3 @@ | ||
const conv = module.exports.generateVarConversion(`args[${i}]`, typeConversions[i], maxConstructor.operation.arguments[i].extAttrs, customTypes); | ||
const conv = generateVarConversion(ctx, `args[${i}]`, typeConversions[i], maxConstructor.operation.arguments[i].extAttrs, parentName, `"${errPrefix}parameter ${i + 1}"`); | ||
Object.assign(requires, conv.requires); | ||
@@ -117,0 +99,0 @@ str += conv.body; |
@@ -8,3 +8,5 @@ "use strict"; | ||
const webidl = require("webidl2"); | ||
const prettier = require("prettier"); | ||
const Context = require("./context"); | ||
const Interface = require("./constructs/interface"); | ||
@@ -14,12 +16,11 @@ const Dictionary = require("./constructs/dictionary"); | ||
class Transformer { | ||
constructor(opts) { | ||
constructor(opts = {}) { | ||
this.ctx = new Context({ | ||
implSuffix: opts.implSuffix | ||
}); | ||
this.options = Object.assign({ | ||
implSuffix: "", | ||
suppressErrors: false | ||
}, opts); | ||
this.sources = []; | ||
this._interfaces = null; | ||
this._dictionaries = null; | ||
this._customTypes = null; | ||
} | ||
@@ -80,5 +81,4 @@ | ||
const interfaces = this._interfaces = Object.create(null); | ||
const dictionaries = this._dictionaries = Object.create(null); | ||
const customTypes = this._customTypes = new Set(); | ||
this.ctx.initialize(); | ||
const { interfaces, dictionaries, customTypes } = this.ctx; | ||
@@ -95,8 +95,7 @@ // first we're gathering all full interfaces and ignore partial ones | ||
obj = new Interface(instruction, { | ||
implDir: path.resolve(outputDir, file.impl), | ||
implSuffix: this.options.implSuffix, | ||
customTypes | ||
obj = new Interface(this.ctx, instruction, { | ||
implDir: path.resolve(outputDir, file.impl) | ||
}); | ||
interfaces[obj.name] = obj; | ||
customTypes.set(obj.name, "interface"); | ||
break; | ||
@@ -110,5 +109,5 @@ case "implements": | ||
obj = new Dictionary(instruction, { customTypes }); | ||
obj = new Dictionary(this.ctx, instruction); | ||
dictionaries[obj.name] = obj; | ||
customTypes.add(instruction.name); | ||
customTypes.set(obj.name, "dictionary"); | ||
break; | ||
@@ -169,19 +168,21 @@ default: | ||
const { interfaces, dictionaries } = this.ctx; | ||
let interfaceStub = yield fs.readFile(__dirname + "/output/interfaceStub.js"); | ||
let keys = Object.keys(this._interfaces).concat(Object.keys(this._dictionaries)); | ||
let keys = Object.keys(interfaces).concat(Object.keys(dictionaries)); | ||
for (let key of keys) { | ||
if (this._interfaces[key]) { | ||
yield fs.writeFile(path.join(outputDir, this._interfaces[key].name + ".js"), interfaceStub); | ||
if (interfaces[key]) { | ||
yield fs.writeFile(path.join(outputDir, interfaces[key].name + ".js"), interfaceStub); | ||
} else { | ||
yield fs.writeFile(path.join(outputDir, this._dictionaries[key].name + ".js"), ""); | ||
yield fs.writeFile(path.join(outputDir, dictionaries[key].name + ".js"), ""); | ||
} | ||
} | ||
keys = Object.keys(this._interfaces); | ||
keys = Object.keys(interfaces); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const obj = this._interfaces[keys[i]]; | ||
const obj = interfaces[keys[i]]; | ||
let source = obj.toString(); | ||
const implDir = path.relative(outputDir, obj.opts.implDir).replace(/\\/g, "/"); // fix windows file paths | ||
let implFile = implDir + "/" + obj.name + this.options.implSuffix; | ||
let implFile = implDir + "/" + obj.name + this.ctx.implSuffix; | ||
if (implFile[0] !== ".") { | ||
@@ -202,8 +203,10 @@ implFile = "./" + implFile; | ||
source = this._prettify(source); | ||
yield fs.writeFile(path.join(outputDir, obj.name + ".js"), source); | ||
} | ||
keys = Object.keys(this._dictionaries); | ||
keys = Object.keys(dictionaries); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const obj = this._dictionaries[keys[i]]; | ||
const obj = dictionaries[keys[i]]; | ||
let source = obj.toString(); | ||
@@ -221,2 +224,4 @@ | ||
source = this._prettify(source); | ||
yield fs.writeFile(path.join(outputDir, obj.name + ".js"), source); | ||
@@ -226,2 +231,8 @@ } | ||
_prettify(source) { | ||
return prettier.format(source, { | ||
printWidth: 120, | ||
}); | ||
} | ||
generate(outputDir) { | ||
@@ -228,0 +239,0 @@ if (!this.options.utilPath) this.options.utilPath = path.join(outputDir, "utils.js"); |
@@ -18,1 +18,5 @@ "use strict"; | ||
}; | ||
module.exports.isPairIterable = function isPairIterable(idl) { | ||
return idl.type === "iterable" && Array.isArray(idl.idlType) && idl.idlType.length === 2; | ||
}; |
{ | ||
"name": "webidl2js", | ||
"version": "6.1.0", | ||
"version": "7.0.0", | ||
"description": "Auto-generates class structures for WebIDL specifications", | ||
@@ -9,8 +9,12 @@ "main": "lib/transformer.js", | ||
"pn": "^1.0.0", | ||
"prettier": "^1.3.1", | ||
"webidl-conversions": "^4.0.0", | ||
"webidl2": "^2.0.11" | ||
"webidl2": "^2.2.2" | ||
}, | ||
"devDependencies": {}, | ||
"devDependencies": { | ||
"jest": "^20.0.0" | ||
}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "jest", | ||
"update-snapshots": "jest --updateSnapshot" | ||
}, | ||
@@ -17,0 +21,0 @@ "author": "Sebastian Mayr <npm@smayr.name>", |
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
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
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
46094
19
1363
1
5
1
+ Addedprettier@^1.3.1
+ Addedprettier@1.19.1(transitive)
Updatedwebidl2@^2.2.2