UNPKG

webidl2js

Version:

Auto-generates class structures for WebIDL specifications

181 lines (151 loc) 4.41 kB
"use strict"; const { extname } = require("path"); const keywords = require("./keywords.js"); function getDefault(dflt) { switch (dflt.type) { case "boolean": case "string": return JSON.stringify(dflt.value); case "number": return 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) { if (attrs[i].name === name) { return attrs[i]; } } return null; } function isGlobal(idl) { return Boolean(getExtAttr(idl.extAttrs, "Global")); } function hasCEReactions(idl) { return Boolean(getExtAttr(idl.extAttrs, "CEReactions")); } function isOnInstance(memberIDL, interfaceIDL) { return memberIDL.special !== "static" && isGlobal(interfaceIDL); } function symbolName(symbol) { const desc = String(symbol).replace(/^Symbol\((.*)\)$/, "$1"); if (!desc.startsWith("Symbol.")) { throw new Error(`Internal error: Unsupported property name ${String(symbol)}`); } return desc; } function propertyName(name) { // All Web IDL identifiers are valid JavaScript PropertyNames, other than those with '-'. const isJSIdentifier = !name.includes("-"); if (isJSIdentifier) { return name; } return JSON.stringify(name); } function stringifyPropertyKey(prop) { return typeof prop === "symbol" ? `[${symbolName(prop)}]` : propertyName(prop); } function stringifyPropertyName(prop) { return typeof prop === "symbol" ? symbolName(prop) : JSON.stringify(propertyName(prop)); } // type can be "accessor" or "regular" function getPropertyDescriptorModifier(currentDesc, targetDesc, type, value = undefined) { const changes = []; if (value !== undefined) { changes.push(`value: ${value}`); } if (currentDesc.configurable !== targetDesc.configurable) { changes.push(`configurable: ${targetDesc.configurable}`); } if (currentDesc.enumerable !== targetDesc.enumerable) { changes.push(`enumerable: ${targetDesc.enumerable}`); } if (type !== "accessor" && currentDesc.writable !== targetDesc.writable) { changes.push(`writable: ${targetDesc.writable}`); } if (changes.length === 0) { return undefined; } return `{ ${changes.join(", ")} }`; } const defaultDefinePropertyDescriptor = { configurable: false, enumerable: false, writable: false }; function formatArgs(args) { return args .filter(name => name !== null && name !== undefined && name !== "") .map(name => name + (keywords.has(name) ? "_" : "")) .join(", "); } function toKey(type, func = "") { return String(func + type).replace(/[./-]+/g, " ").trim().replace(/ /g, "_"); } const PACKAGE_NAME_REGEX = /^(?:@([^/]+?)[/])?([^/]+?)$/u; class RequiresMap extends Map { constructor(ctx) { super(); this.ctx = ctx; } add(name, func = "") { const key = toKey(name, func); // If `name` is a package name or has a file extension, then use it as-is, // otherwise append the `.js` file extension: const importPath = PACKAGE_NAME_REGEX.test(name) || extname(name) ? name : `${name}.js`; let req = `require(${JSON.stringify(importPath)})`; if (func) { req += `.${func}`; } this.addRaw(key, req); return key; } addRelative(type, func = "") { const key = toKey(type, func); const path = type.startsWith(".") ? type : `./${type}`; let req = `require("${path}.js")`; if (func) { req += `.${func}`; } this.addRaw(key, req); return key; } addRaw(key, expr) { if (this.has(key) && this.get(key) !== expr) { throw new Error(`Internal error: Variable name clash: ${key}; was ${this.get(key)}, adding: ${expr}`); } super.set(key, expr); } merge(src) { if (!src || !(src instanceof RequiresMap)) { return; } for (const [key, val] of src) { this.addRaw(key, val); } } generate() { return [...this.keys()].map(key => `const ${key} = ${this.get(key)};`).join("\n"); } } module.exports = { getDefault, getExtAttr, isGlobal, hasCEReactions, isOnInstance, stringifyPropertyKey, stringifyPropertyName, getPropertyDescriptorModifier, defaultDefinePropertyDescriptor, formatArgs, RequiresMap };