UNPKG

@thi.ng/wasm-api-bindgen

Version:

Polyglot bindings code generators (TS/JS, Zig, C11) for hybrid WebAssembly projects

77 lines (76 loc) 3.23 kB
import { isArray } from "@thi.ng/checks/is-array"; import { isPlainObject } from "@thi.ng/checks/is-plain-object"; import { isString } from "@thi.ng/checks/is-string"; import { split } from "@thi.ng/strings/split"; import { wordWrapLine, wordWrapLines } from "@thi.ng/strings/word-wrap"; const isNumeric = (x) => /^(([iu](8|16|32))|(f(32|64)))$/.test(x); const isBigNumeric = (x) => /^[iu]64$/.test(x); const isSizeT = (x) => /^[iu]size$/.test(x); const isWasmPrim = (x) => isNumeric(x) || isBigNumeric(x); const isWasmString = (x) => x === "string"; const isPadding = (f) => f.pad != null && f.pad > 0; const isPointer = (x) => x === "ptr"; const isFuncPointer = (type, coll) => coll[type]?.type === "funcptr"; const isEnum = (type, coll) => coll[type]?.type === "enum"; const isExternal = (type, coll) => coll[type]?.type === "ext"; const isSlice = (x) => x === "slice"; const isOpaque = (x) => x === "opaque"; const isPointerLike = (f, coll) => isPointer(f.tag) || isSlice(f.tag) || isWasmString(f.type) || isOpaque(f.type) || isFuncPointer(f.type, coll); const isStringSlice = (type) => type === "slice"; const isStruct = (x) => x.type === "struct"; const isUnion = (x) => x.type === "union"; const hasStringFields = (x) => { if (!isStruct(x) || isUnion(x)) return false; return x.fields.some((f) => f.type === "string"); }; const usesStrings = (coll) => Object.values(coll).some(hasStringFields); const pointerFields = (fields) => fields.filter((f) => isPointer(f.tag)); const stringFields = (fields) => fields.filter((f) => isWasmString(f.type) && f.tag !== "ptr"); const sliceTypes = (coll) => new Set( Object.values(coll).flatMap((x) => isStruct(x) || isUnion(x) ? x.fields : []).map((x) => x.tag === "slice" ? x.type : null).filter((x) => !!x) ); const enumName = (opts, name) => opts.uppercaseEnums ? name.toUpperCase() : name; const defaultValue = (f, lang) => f.default !== void 0 ? isPlainObject(f.default) ? f.default[lang] : f.default : void 0; const prefixLines = (prefix, str, width) => (isString(str) ? wordWrapLines(str, { width: width - prefix.length }) : str.flatMap((x) => wordWrapLine(x, { width: width - prefix.length }))).map((line) => prefix + line); const ensureLines = (src, key) => isString(src) ? split(src) : isArray(src) ? src : key ? src[key] ? ensureLines(src[key], key) : [] : []; const ensureStringArray = (src) => isString(src) ? [src] : src; function* withIndentation(lines, indent, scopeStart, scopeEnd, level = 0) { const stack = new Array(level).fill(indent); for (let l of lines) { scopeEnd.test(l) && stack.pop(); const curr = stack.length ? stack[stack.length - 1] : ""; yield curr + l; scopeStart.test(l) && stack.push(curr + indent); } } const injectBody = (acc, body, key = "impl") => body && acc.push("", ...ensureLines(body, key), ""); export { defaultValue, ensureLines, ensureStringArray, enumName, hasStringFields, injectBody, isBigNumeric, isEnum, isExternal, isFuncPointer, isNumeric, isOpaque, isPadding, isPointer, isPointerLike, isSizeT, isSlice, isStringSlice, isStruct, isUnion, isWasmPrim, isWasmString, pointerFields, prefixLines, sliceTypes, stringFields, usesStrings, withIndentation };