Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

webidl2js

Package Overview
Dependencies
Maintainers
2
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

webidl2js - npm Package Compare versions

Comparing version 7.0.1 to 7.1.0

lib/constructs/typedef.js

15

lib/context.js
"use strict";
const webidl = require("webidl2");
const Typedef = require("./constructs/typedef");
const builtinTypedefs = webidl.parse(`
typedef (Int8Array or Int16Array or Int32Array or
Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or
Float32Array or Float64Array or DataView) ArrayBufferView;
typedef (ArrayBufferView or ArrayBuffer) BufferSource;
typedef unsigned long long DOMTimeStamp;
`);
class Context {

@@ -11,4 +21,9 @@ constructor({ implSuffix = "" } = {}) {

this.customTypes = new Map();
this.typedefs = new Map();
this.interfaces = Object.create(null);
this.dictionaries = Object.create(null);
for (const typedef of builtinTypedefs) {
this.typedefs.set(typedef.name, new Typedef(this, typedef));
}
}

@@ -15,0 +30,0 @@ }

48

lib/output/utils.js
"use strict";
module.exports.mixin = function mixin(target, source) {
// Returns "Type(value) is Object" in ES terminology.
function isObject(value) {
return typeof value === "object" && value !== null || typeof value === "function";
}
function getReferenceToBytes(bufferSource) {
// Node.js' Buffer does not allow subclassing for now, so we can get away with a prototype object check for perf.
if (Object.getPrototypeOf(bufferSource) === Buffer.prototype) {
return bufferSource;
}
if (bufferSource instanceof ArrayBuffer) {
return Buffer.from(bufferSource);
}
return Buffer.from(bufferSource.buffer, bufferSource.byteOffset, bufferSource.byteLength)
}
function getCopyToBytes(bufferSource) {
return Buffer.from(getReferenceToBytes(bufferSource));
}
function mixin(target, source) {
const keys = Object.getOwnPropertyNames(source);

@@ -12,3 +32,3 @@ for (let i = 0; i < keys.length; ++i) {

}
};
}

@@ -52,10 +72,16 @@ const wrapperSymbol = Symbol("wrapper");

module.exports.wrapperSymbol = wrapperSymbol;
module.exports.implSymbol = implSymbol;
module.exports.getSameObject = getSameObject;
module.exports.wrapperForImpl = wrapperForImpl;
module.exports.implForWrapper = implForWrapper;
module.exports.tryWrapperForImpl = tryWrapperForImpl;
module.exports.tryImplForWrapper = tryImplForWrapper;
module.exports.iterInternalSymbol = iterInternalSymbol;
module.exports.IteratorPrototype = IteratorPrototype;
module.exports = exports = {
isObject,
getReferenceToBytes,
getCopyToBytes,
mixin,
wrapperSymbol,
implSymbol,
getSameObject,
wrapperForImpl,
implForWrapper,
tryWrapperForImpl,
tryImplForWrapper,
iterInternalSymbol,
IteratorPrototype
};

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

const Context = require("./context");
const Typedef = require("./constructs/typedef");
const Interface = require("./constructs/interface");

@@ -81,3 +82,3 @@ const Dictionary = require("./constructs/dictionary");

this.ctx.initialize();
const { interfaces, dictionaries, customTypes } = this.ctx;
const { interfaces, dictionaries, typedefs, customTypes } = this.ctx;

@@ -111,2 +112,6 @@ // first we're gathering all full interfaces and ignore partial ones

break;
case "typedef":
obj = new Typedef(this.ctx, instruction);
typedefs.set(obj.name, obj);
break;
default:

@@ -113,0 +118,0 @@ if (!this.options.suppressErrors) {

@@ -7,3 +7,60 @@ "use strict";

function generateTypeConversion(ctx, name, idlType, argAttrs, parentName, errPrefix = '"The provided value"') {
function mergeExtAttrs(a = [], b = []) {
return [...a, ...b];
}
function resolveType(ctx, idlType, stack = []) {
idlType = deepClone(idlType);
const { customTypes, typedefs } = ctx;
if (idlType.union) {
const types = [];
for (let type of idlType.idlType) {
type = resolveType(ctx, type, stack);
idlType.nullable = idlType.nullable || type.nullable;
// Only the outermost union is nullable
type.nullable = false;
if (type.union) {
types.push(...type.idlType);
} else {
types.push(type);
}
}
for (const type of types) {
type.extAttrs = deepClone(mergeExtAttrs(type.extAttrs, idlType.extAttrs));
}
idlType.idlType = types;
return idlType;
} else if (idlType.generic === "sequence" || idlType.generic === "FrozenArray" || idlType.generic === "Promise") {
idlType.idlType = resolveType(ctx, idlType.idlType, stack);
return idlType;
} else if (idlType.generic === "record") {
idlType.idlType = idlType.idlType.map(t => resolveType(ctx, t, stack));
return idlType;
} else if (customTypes.has(idlType.idlType)) {
// already resolved
return idlType;
} else if (typedefs.has(idlType.idlType)) {
const out = deepClone(typedefs.get(idlType.idlType).resolve(stack));
out.nullable = out.nullable || idlType.nullable;
out.extAttrs = deepClone(mergeExtAttrs(out.extAttrs, idlType.extAttrs));
if (out.union) {
for (const type of out.idlType) {
type.extAttrs = deepClone(mergeExtAttrs(type.extAttrs, idlType.extAttrs));
}
}
return out;
} else if (conversions[idlType.idlType]) {
// already resolved
return idlType;
} else {
// unknown
return idlType;
}
}
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
function generateTypeConversion(ctx, name, idlType, argAttrs = [], parentName, errPrefix = '"The provided value"') {
const { customTypes } = ctx;

@@ -13,2 +70,5 @@ const requires = {};

idlType = resolveType(ctx, idlType);
const extAttrs = idlType.extAttrs !== undefined ? [...idlType.extAttrs, ...argAttrs] : argAttrs;
if (idlType.nullable) {

@@ -21,3 +81,6 @@ str += `

if (idlType.generic === "sequence") {
if (idlType.union) {
// union type
generateUnion();
} else if (idlType.generic === "sequence") {
// sequence type

@@ -65,5 +128,124 @@ generateSequence();

function generateUnion() {
const union = extractUnionInfo(ctx, idlType, errPrefix);
const output = [];
if (union.unknown) {
// Oh well, what do we know...
str += `${name} = utils.tryImplForWrapper(${name});`;
return;
}
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);
}
if (union.object) {
output.push(`if (utils.isObject(${name}) && ${name}[utils.implSymbol]) {
${name} = utils.implForWrapper(${name});
}`);
} else if (union.interfaces.size > 0) {
const exprs = [...union.interfaces].map(iface => {
let fn;
// Avoid requiring the interface itself
if (iface !== parentName) {
fn = `is${iface}`;
requires[fn] = `require("./${iface}").is`;
} else {
fn = "module.exports.is";
}
return `${fn}(${name})`;
});
output.push(`if (${exprs.join(" || ")}) {
${name} = utils.implForWrapper(${name});
}`);
}
// Handle Error and DOMException the same way
if (union.exception || union.object) {
output.push(`if (${name} instanceof Error) {}`);
}
// Do not convert buffer source types as the impl code can either "get a reference" or "get a copy" to the bytes.
if (union.ArrayBuffer || union.object) {
output.push(`if (${name} instanceof ArrayBuffer) {}`);
}
if (union.ArrayBufferViews.size > 0 || union.object) {
let condition = `ArrayBuffer.isView(${name})`;
// Skip specific type check if all ArrayBufferView member types are allowed.
if (union.ArrayBufferViews.size !== arrayBufferViewTypes.size) {
const exprs = [...union.ArrayBufferViews].map(a => `${name} instanceof ${a}`);
condition += ` && (${exprs.join(" || ")})`;
}
output.push(`if (${condition}) {}`);
}
if (union.callback || union.object) {
output.push(`if (typeof ${name} === "function") {}`);
}
if (union.sequenceLike || union.dictionary || union.record || union.object) {
let str = `if (utils.isObject(${name})) {`;
if (union.sequenceLike) {
str += `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 {`;
}
if (union.dictionary || union.record) {
const prop = union.dictionary ? "dictionary" : "record";
const conv = generateTypeConversion(ctx, name, union[prop], [], parentName, `${errPrefix} + " ${prop}"`);
Object.assign(requires, conv.requires);
str += conv.body;
} else if (union.object) {
// noop
}
if (union.sequenceLike) {
str += "}";
}
str += "}";
output.push(str);
}
if (union.boolean) {
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}
}`);
}
{
let str = "{";
const type = union.string || union.numeric || union.boolean;
if (type) {
str += generateTypeConversion(ctx, name, type, [], parentName, errPrefix).body;
} else {
str += `throw new TypeError(${errPrefix} + " is not of any supported type.")`;
}
str += "}";
output.push(str);
}
str += output.join(" else ");
}
function generateSequence() {
str += `
if (${name} === null || typeof ${name} !== "object" && typeof ${name} !== "function") {
if (!utils.isObject(${name})) {
throw new TypeError(${errPrefix} + " is not an iterable object.");

@@ -88,3 +270,3 @@ } else {

str += `
if (${name} === null || typeof ${name} !== "object" && typeof ${name} !== "function") {
if (!utils.isObject(${name})) {
throw new TypeError(${errPrefix} + " is not an object.");

@@ -136,5 +318,5 @@ } else {

function generateGeneric(conversionFn) {
const enforceRange = utils.getExtAttr(argAttrs, "EnforceRange");
const clamp = utils.getExtAttr(argAttrs, "Clamp");
const treatNullAs = utils.getExtAttr(argAttrs, "TreatNullAs");
const enforceRange = utils.getExtAttr(extAttrs, "EnforceRange");
const clamp = utils.getExtAttr(extAttrs, "Clamp");
const treatNullAs = utils.getExtAttr(extAttrs, "TreatNullAs");

@@ -144,5 +326,7 @@ let optString = `, { context: ${errPrefix}`;

optString += ", clamp: true";
} else if (enforceRange) {
}
if (enforceRange) {
optString += ", enforceRange: true";
} else if (treatNullAs && treatNullAs.rhs.value === "EmptyString") {
}
if (treatNullAs && treatNullAs.rhs.value === "EmptyString") {
optString += ", treatNullAsEmptyString: true";

@@ -163,4 +347,150 @@ }

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
// of the union type (no forbidden types, no indistinguishable member types). Duplicated types are allowed for now
// though.
function extractUnionInfo(ctx, idlType, errPrefix) {
const { customTypes } = ctx;
const seen = {
sequenceLike: null,
record: null,
get dictionaryLike() {
return this.dictionary !== null || this.record !== null;
},
ArrayBuffer: false,
ArrayBufferViews: new Set(),
get BufferSource() {
return this.ArrayBuffer || this.ArrayBufferViews.size > 0;
},
object: false,
exception: null,
string: null,
numeric: null,
boolean: null,
// Callback function, not interface
callback: false,
dictionary: null,
interfaces: new Set(),
get interfaceLike() {
return this.interfaces.size > 0 || this.exception !== null || this.BufferSource;
},
unknown: false
};
for (const item of idlType.idlType) {
if (item.generic === "sequence" || item.generic === "FrozenArray") {
if (seen.sequenceLike) {
error("There can only be one sequence-like type in a union type");
}
seen.sequenceLike = item;
} else if (item.generic === "record") {
if (seen.record || seen.dictionary) {
error("There can only be one dictionary-like type in a union type");
}
seen.record = item;
} else if (item.generic === "Promise") {
error("Promise types are not supported in union types");
} else if (item.generic) {
error(`Unknown generic type ${item.generic}`);
} else if (item.idlType === "any") {
error("any type is not allowed in a union type");
} else if (item.idlType === "ArrayBuffer") {
if (seen.object) {
error("ArrayBuffer is not distinguishable with object type");
}
seen.ArrayBuffer = true;
} else if (arrayBufferViewTypes.has(item.idlType)) {
if (seen.object) {
error(`${item.idlType} is not distinguishable with object type`);
}
seen.ArrayBufferViews.add(item.idlType);
} else if (stringTypes.has(item.idlType)) {
if (seen.string) {
error("There can only be one string type in a union type");
}
seen.string = item;
} else if (numericTypes.has(item.idlType)) {
if (seen.numeric) {
error("There can only be one numeric type in a union type");
}
seen.numeric = item;
} else if (item.idlType === "object") {
if (seen.interfaceLike) {
error("Object type is not distinguishable with interface-like types");
}
if (seen.callback) {
error("Object type is not distinguishable with callback functions");
}
if (seen.dictionaryLike) {
error("Object type is not distinguishable with dictionary-like types");
}
if (seen.sequenceLike) {
error("Object type is not distinguishable with sequence-like types");
}
seen.object = true;
} else if (item.idlType === "DOMException" || item.idlType === "Error") {
if (seen.object) {
error("Exception types are not distinguishable with object type");
}
if (seen.exception && seen.exception.idlType !== item.idlType) {
error("DOMException is not distinguishable with Error type");
}
seen.exception = item;
} else if (item.idlType === "boolean") {
seen.boolean = item;
} else if (item.idlType === "Function") {
// TODO: add full support for callback functions
if (seen.object) {
error("Callback functions are not distinguishable with object type");
}
if (seen.dictionaryLike) {
error("Callback functions are not distinguishable with dictionary-like types");
}
seen.callback = true;
} else if (customTypes.has(item.idlType)) {
const type = customTypes.get(item.idlType);
if (type === "dictionary") {
if (seen.object) {
error("Dictionary-like types are not distinguishable with object type");
}
if (seen.callback) {
error("Dictionary-like types are not distinguishable with callback functions");
}
if (seen.dictionaryLike) {
error("There can only be one dictionary-like type in a union type");
}
seen.dictionary = item;
} else if (type === "interface") {
if (seen.object) {
error("Interface types are not distinguishable with object type");
}
seen.interfaces.add(item.idlType);
} else {
error(`Unknown custom type ${type}`)
}
} else {
seen.unknown = true;
}
}
return seen;
function error(msg) {
throw new Error(`${msg}\n When compiling "${eval(errPrefix)}"`);
}
}
module.exports = {
generateTypeConversion
generateTypeConversion,
resolveType
};
{
"name": "webidl2js",
"version": "7.0.1",
"version": "7.1.0",
"description": "Auto-generates class structures for WebIDL specifications",

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

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc