Skip to content

Commit

Permalink
feat(bindgen): Check for positional input of an array of files
Browse files Browse the repository at this point in the history
Still todo: dynamic input indexing with multiple arguments.

Also, cli11 currently does not distinguish between the end of a input
array set of arguments and a positional output.
  • Loading branch information
thewtex committed Sep 28, 2023
1 parent 2cf3c7e commit 4b07cda
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 8 deletions.
12 changes: 12 additions & 0 deletions src/bindgen/input-array-check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function inputArrayCheck(interfaceJson) {
interfaceJson.inputs.forEach((input) => {
const isArray = input.itemsExpectedMax > 1
if (isArray) {
console.error('Positional multi-value inputs are currently not supported -- please use an option instead')
console.error(`Violating option: ${input.name}`)
process.exit(1)
}
})
}

export default inputArrayCheck
44 changes: 36 additions & 8 deletions src/bindgen/typescript/function-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ import writeIfOverrideNotPresent from '../write-if-override-not-present.js'
function readFileIfNotInterfaceType(forNode, interfaceType, varName, indent, isArray) {
if (forNode) {
if (isArray) {
return `${indent}value.forEach((p) => mountDirs.add(path.dirname(p) as string))\n`
return `${indent}${varName}.forEach((p) => mountDirs.add(path.dirname(p) as string))\n`
} else {
return `${indent}mountDirs.add(path.dirname(${varName} as string))\n`
}

} else {
if (interfaceType === 'TextFile') {
if (isArray) {
return `${indent}${varName}.map((v) => {\n${indent}${indent}let vFile = v\n${indent}${indent}if (v instanceof File) {\n${indent}${indent} const vBuffer = await v.arrayBuffer()\n${indent}${indent} vFile = { path: v.name, data: new TextDecoder().decode(vBuffer) }\n${indent}${indent}}\n${indent}})\n`
return `${indent}const ${varName}File = await Promise.all(${varName}.map(async (v) => {\n${indent}${indent}let vFile = v\n${indent}${indent}if (v instanceof File) {\n${indent}${indent} const vBuffer = await v.arrayBuffer()\n${indent}${indent} vFile = { path: v.name, data: new TextDecoder().decode(vBuffer) }\n${indent}${indent}}\n${indent}${indent}return vFile\n${indent}}))\n`
} else {
return `${indent}let ${varName}File = ${varName}\n${indent}if (${varName} instanceof File) {\n${indent} const ${varName}Buffer = await ${varName}.arrayBuffer()\n${indent} ${varName}File = { path: ${varName}.name, data: new TextDecoder().decode(${varName}Buffer) }\n${indent}}\n`
}
} else {
if (isArray) {
return `${indent}${varName}.map((v) => {\n${indent}let vFile = v\n${indent}${indent}if (v instanceof File) {\n${indent}${indent} const vBuffer = await v.arrayBuffer()\n${indent}${indent} vFile = { path: v.name, data: new Uint8Array(vBuffer) }\n${indent}${indent}}\n${indent}})\n`
return `${indent}const ${varName}File = await Promise.all(${varName}.map(async (v) => {\n${indent}let vFile = v\n${indent}${indent}if (v instanceof File) {\n${indent}${indent} const vBuffer = await v.arrayBuffer()\n${indent}${indent} vFile = { path: v.name, data: new Uint8Array(vBuffer) }\n${indent}${indent}}${indent}${indent}\nreturn vFile\n${indent}}))\n`
} else {
return `${indent}let ${varName}File = ${varName}\n${indent}if (${varName} instanceof File) {\n${indent} const ${varName}Buffer = await ${varName}.arrayBuffer()\n${indent} ${varName}File = { path: ${varName}.name, data: new Uint8Array(${varName}Buffer) }\n${indent}}\n`

Expand Down Expand Up @@ -251,6 +251,9 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase,
const camel = camelCase(input.name)
const isArray = input.itemsExpectedMax > 1
functionContent += readFileIfNotInterfaceType(forNode, interfaceType, camel, ' ', isArray)
if (!forNode && isArray) {
functionContent += ` const ${camel}PipelineInputs = ${camel}File.map(i => { return { type: InterfaceTypes.${interfaceType}, data: i as ${interfaceType} }})\n`
}
}
}
})
Expand All @@ -259,9 +262,14 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase,
if (interfaceJsonTypeToInterfaceType.has(input.type)) {
const interfaceType = interfaceJsonTypeToInterfaceType.get(input.type)
const camel = camelCase(input.name)
const isArray = input.itemsExpectedMax > 1
if (interfaceType.includes('File')) {
if (!forNode) {
functionContent += ` { type: InterfaceTypes.${interfaceType}, data: ${camel}File as ${interfaceType} },\n`
if (isArray) {
functionContent += ` ...${camel}PipelineInputs,\n`
} else {
functionContent += ` { type: InterfaceTypes.${interfaceType}, data: ${camel}File as ${interfaceType} },\n`
}
}
} else {
let data = camel
Expand All @@ -283,16 +291,36 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase,
const camel = camelCase(input.name)
if (interfaceJsonTypeToInterfaceType.has(input.type)) {
const interfaceType = interfaceJsonTypeToInterfaceType.get(input.type)
const isArray = input.itemsExpectedMax > 1
let name = ` const ${camel}Name = '${inputCount.toString()}'\n`
if (interfaceType.includes('File')) {
if (forNode) {
name = ` const ${camel}Name = ${camel}\n`
if (isArray) {
name = ''
} else {
name = ` const ${camel}Name = (${camel}File as ${interfaceType}).path\n`
if (forNode) {
name = ` const ${camel}Name = ${camel}\n`
} else {
name = ` const ${camel}Name = (${camel}File as ${interfaceType}).path\n`
}
}
}
functionContent += name
functionContent += ` args.push(${camel}Name as string)\n\n`
if (isArray) {
if (forNode) {
functionContent += ` ${camel}.forEach((p) => args.push(p))\n`
} else {
functionContent += ` ${camel}File.forEach((p) => args.push((p as ${interfaceType}).path))\n`
}
if (forNode && interfaceType.includes('File')) {
functionContent += ` ${camel}.forEach((p) => mountDirs.add(path.dirname(p)))\n`
}
} else {
functionContent += ` args.push(${camel}Name)\n`
if (forNode && interfaceType.includes('File')) {
functionContent += ` mountDirs.add(path.dirname(${camel}Name))\n`
}
}
functionContent += '\n'
inputCount++
} else {
functionContent += ` args.push(${camel}.toString())\n\n`
Expand Down
2 changes: 2 additions & 0 deletions src/bindgen/typescript/typescript-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import resultsModule from './results-module.js'
import optionsModule from './options-module.js'
import functionModule from './function-module.js'
import outputOptionsCheck from '../output-options-check.js'
import inputArrayCheck from '../input-array-check.js'

// Array of types that will require an import from itk-wasm
function bindgenResource(filePath) {
Expand Down Expand Up @@ -98,6 +99,7 @@ function typescriptBindings (outputDir, buildDir, wasmBinaries, options, forNode
const { interfaceJson, parsedPath } = wasmBinaryInterfaceJson(outputDir, buildDir, wasmBinaryName)

outputOptionsCheck(interfaceJson)
inputArrayCheck(interfaceJson)

const moduleKebabCase = parsedPath.name
const moduleCamelCase = camelCase(parsedPath.name)
Expand Down

0 comments on commit 4b07cda

Please sign in to comment.