From 9dc3181921ffc021a121f06e740b424578b249de Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sat, 23 Sep 2023 22:19:23 -0400 Subject: [PATCH] fix(bindgen): support for array outputs --- .../demo/output-demo-run-typescript.js | 12 +++- .../typescript/demo/output-demo-typescript.js | 18 ++++-- src/bindgen/typescript/function-module.js | 58 ++++++++++++++++--- src/bindgen/typescript/results-module.js | 6 +- 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/src/bindgen/typescript/demo/output-demo-run-typescript.js b/src/bindgen/typescript/demo/output-demo-run-typescript.js index 9d416331d..fd38837b5 100644 --- a/src/bindgen/typescript/demo/output-demo-run-typescript.js +++ b/src/bindgen/typescript/demo/output-demo-run-typescript.js @@ -12,7 +12,11 @@ function outputDemoRunTypeScript(functionName, prefix, indent, parameter) { result += `${prefix}${indent}${parameterName}OutputDownload.disabled = false\n` result += `${prefix}${indent}const ${parameterName}Output = document.getElementById("${functionName}-${parameter.name}-details")\n` const textDataProp = parameter.type.includes('FILE') ? '.data' : '' - result += `${prefix}${indent}${parameterName}Output.innerHTML = \`
$\{globalThis.escapeHtml(${parameterName}${textDataProp}.substring(0, 1024).toString() + ' ...')}
\`\n` + if (parameter.itemsExpectedMax > 1) { + result += `${prefix}${indent}${parameterName}Output.innerHTML = \`
$\{globalThis.escapeHtml(JSON.stringify(${parameterName}))}
\`\n` + } else { + result += `${prefix}${indent}${parameterName}Output.innerHTML = \`
$\{globalThis.escapeHtml(${parameterName}${textDataProp}.substring(0, 1024).toString() + ' ...')}
\`\n` + } result += `${prefix}${indent}${parameterName}Output.disabled = false\n` } break @@ -23,7 +27,11 @@ function outputDemoRunTypeScript(functionName, prefix, indent, parameter) { result += `${prefix}${indent}${parameterName}OutputDownload.disabled = false\n` result += `${prefix}${indent}const ${parameterName}Output = document.getElementById("${functionName}-${parameter.name}-details")\n` const binaryDataProp = parameter.type.includes('FILE') ? '.data' : '' - result += `${prefix}${indent}${parameterName}Output.innerHTML = \`
$\{globalThis.escapeHtml(${parameterName}${binaryDataProp}.subarray(0, 1024).toString() + ' ...')}
\`\n` + if (parameter.itemsExpectedMax > 1) { + result += `${prefix}${indent}${parameterName}Output.innerHTML = \`
$\{globalThis.escapeHtml(JSON.stringify(${parameterName})}
\`\n` + } else { + result += `${prefix}${indent}${parameterName}Output.innerHTML = \`
$\{globalThis.escapeHtml(${parameterName}${binaryDataProp}.subarray(0, 1024).toString() + ' ...')}
\`\n` + } result += `${prefix}${indent}${parameterName}Output.disabled = false\n` } break diff --git a/src/bindgen/typescript/demo/output-demo-typescript.js b/src/bindgen/typescript/demo/output-demo-typescript.js index 9da9e0bda..c2fbfcb15 100644 --- a/src/bindgen/typescript/demo/output-demo-typescript.js +++ b/src/bindgen/typescript/demo/output-demo-typescript.js @@ -14,8 +14,13 @@ function outputDemoTypeScript(functionName, prefix, indent, parameter) { result += `${prefix}${indent}${indent}event.stopPropagation()\n` result += `${prefix}${indent}${indent}if (model.outputs.has("${parameterName}")) {\n` const textDataProp = parameter.type.includes('FILE') ? '.data' : '' - const downloadFileName = parameter.type.includes('FILE') ? `model.outputs.get("${parameterName}").path`: `"${parameterName}.txt"` - result += `${prefix}${indent}${indent}${indent}globalThis.downloadFile(new TextEncoder().encode(model.outputs.get("${parameterName}")${textDataProp}), ${downloadFileName})\n` + if (parameter.itemsExpectedMax > 1) { + const downloadFileName = parameter.type.includes('FILE') ? `o.path`: `"${parameterName}.txt"` + result += `${prefix}${indent}${indent}${indent}model.outputs.get("${parameterName}").forEach((o) => globalThis.downloadFile(new TextEncoder().encode(o${textDataProp}), ${downloadFileName}))\n` + } else { + const downloadFileName = parameter.type.includes('FILE') ? `model.outputs.get("${parameterName}").path`: `"${parameterName}.txt"` + result += `${prefix}${indent}${indent}${indent}globalThis.downloadFile(new TextEncoder().encode(model.outputs.get("${parameterName}")${textDataProp}), ${downloadFileName})\n` + } result += `${prefix}${indent}${indent}}\n` result += `${prefix}${indent}})\n` } @@ -29,8 +34,13 @@ function outputDemoTypeScript(functionName, prefix, indent, parameter) { result += `${prefix}${indent}${indent}event.stopPropagation()\n` result += `${prefix}${indent}${indent}if (model.outputs.has("${parameterName}")) {\n` const binaryDataProp = parameter.type.includes('FILE') ? '.data' : '' - const downloadFileName = parameter.type.includes('FILE') ? `model.outputs.get("${parameterName}").path`: `"${parameterName}.bin"` - result += `${prefix}${indent}${indent}${indent}globalThis.downloadFile(model.outputs.get("${parameterName}")${binaryDataProp}, ${downloadFileName})\n` + if (parameter.itemsExpectedMax > 1) { + const downloadFileName = parameter.type.includes('FILE') ? `o.path`: `"${parameterName}.bin"` + result += `${prefix}${indent}${indent}${indent}model.outputs.get("${parameterName}").forEach((o) => globalThis.downloadFile(o${binaryDataProp}, ${downloadFileName}))\n` + } else { + const downloadFileName = parameter.type.includes('FILE') ? `model.outputs.get("${parameterName}").path`: `"${parameterName}.bin"` + result += `${prefix}${indent}${indent}${indent}globalThis.downloadFile(model.outputs.get("${parameterName}")${binaryDataProp}, ${downloadFileName})\n` + } result += `${prefix}${indent}${indent}}\n` result += `${prefix}${indent}})\n` } diff --git a/src/bindgen/typescript/function-module.js b/src/bindgen/typescript/function-module.js index 55b0497d7..f497bd6d6 100644 --- a/src/bindgen/typescript/function-module.js +++ b/src/bindgen/typescript/function-module.js @@ -195,6 +195,7 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, } }) } + let haveArray = false functionContent += ' const desiredOutputs: Array = [\n' interfaceJson.outputs.forEach((output) => { if (interfaceJsonTypeToInterfaceType.has(output.type)) { @@ -204,6 +205,7 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, const defaultData = interfaceType === 'BinaryFile' ? 'new Uint8Array()' : "''" const isArray = output.itemsExpectedMax > 1 if (isArray) { + haveArray = true functionContent += ` ...${camel}PipelineOutputs,\n` } else { functionContent += ` { type: InterfaceTypes.${interfaceType}, data: { path: ${camel}Path, data: ${defaultData} }},\n` @@ -214,6 +216,30 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, } }) functionContent += ' ]\n\n' + if (haveArray) { + functionContent += ` let outputIndex = 0\n` + interfaceJson.outputs.forEach((output) => { + if (interfaceJsonTypeToInterfaceType.has(output.type)) { + const interfaceType = interfaceJsonTypeToInterfaceType.get(output.type) + if (!forNode && interfaceType.includes('File')) { + const camel = camelCase(output.name) + const isArray = output.itemsExpectedMax > 1 + if (isArray) { + functionContent += ` const ${camel}Start = outputIndex\n` + functionContent += ` outputIndex += options.${camel}Path ? options.${camel}Path.length : 0\n` + functionContent += ` const ${camel}End = outputIndex\n` + } else { + functionContent += ` const ${camel}Index = outputIndex\n` + functionContent += ` ++outputIndex\n` + } + } else if (!interfaceType.includes('File')) { + functionContent += ` const ${camel}Index = outputIndex\n` + functionContent += ` ++outputIndex\n` + } + } + }) + functionContent += '\n' + } interfaceJson.inputs.forEach((input) => { if (interfaceJsonTypeToInterfaceType.has(input.type)) { const interfaceType = interfaceJsonTypeToInterfaceType.get(input.type) @@ -295,13 +321,12 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, functionContent += name if (isArray) { functionContent += ` options.${camel}Path?.forEach((p) => args.push(p))\n` + if (forNode && interfaceType.includes('File')) { + functionContent += ` options.${camel}Path?.forEach((p) => mountDirs.add(path.dirname(p)))\n` + } } else { functionContent += ` args.push(${camel}Name)\n` - } - if (forNode && interfaceType.includes('File')) { - if (isArray) { - functionContent += ` options.${camel}Path?.forEach((p) => mountDirs.add(path.dirname(p)))\n` - } else { + if (forNode && interfaceType.includes('File')) { functionContent += ` mountDirs.add(path.dirname(${camel}Name))\n` } } @@ -414,12 +439,31 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, interfaceJson.outputs.forEach((output, index) => { const camel = camelCase(output.name) const interfaceType = interfaceJsonTypeToInterfaceType.get(output.type) + const outputIndex = haveArray ? `${camel}Index` : index.toString() if (interfaceType.includes('TextStream') || interfaceType.includes('BinaryStream')) { - functionContent += ` ${camel}: (outputs[${index.toString()}].data as ${interfaceType}).data,\n` + if (haveArray) { + const isArray = output.itemsExpectedMax > 1 + if (isArray) { + functionContent += ` ${camel}: (outputs.slice(${camel}Start, ${camel}End).map(o => (o.data as ${interfaceType}).data)),\n` + } else { + functionContent += ` ${camel}: (outputs[${camel}Index].data as ${interfaceType}).data),\n` + } + } else { + functionContent += ` ${camel}: (outputs[${outputIndex}].data as ${interfaceType}).data,\n` + } } else if (forNode && interfaceType.includes('File')) { // Written to disk } else { - functionContent += ` ${camel}: outputs[${index.toString()}].data as ${interfaceType},\n` + if (haveArray) { + const isArray = output.itemsExpectedMax > 1 + if (isArray) { + functionContent += ` ${camel}: outputs.slice(${camel}Start, ${camel}End).map(o => (o.data as ${interfaceType})),\n` + } else { + functionContent += ` ${camel}: outputs[${camel}Index].data as ${interfaceType},\n` + } + } else { + functionContent += ` ${camel}: outputs[${outputIndex}].data as ${interfaceType},\n` + } } }) functionContent += ' }\n' diff --git a/src/bindgen/typescript/results-module.js b/src/bindgen/typescript/results-module.js index be66416b5..e920a8220 100644 --- a/src/bindgen/typescript/results-module.js +++ b/src/bindgen/typescript/results-module.js @@ -31,16 +31,16 @@ function resultsModule (srcOutputDir, interfaceJson, forNode, modulePascalCase, if (outputType === 'JsonCompatible') { resultsImportTypes.add('JsonCompatible') } + const outputArray = output.itemsExpectedMax > 1 ? '[]' : '' if (forNode && outputType.includes('File')) { // Written to disk } else { if (typesRequireImport.includes(outputType)) { resultsImportTypes.add(outputType) } - resultContent += ` ${camelCase(output.name)}: ${outputType}\n\n` + resultContent += ` ${camelCase(output.name)}: ${outputType}${outputArray}\n\n` } - const readmeOutputArray = output.itemsExpectedMax > 1 ? '[]' : '' - readmeResultTable.push([`\`${camelCase(output.name)}\``, `*${outputType}${readmeOutputArray}*`, output.description]) + readmeResultTable.push([`\`${camelCase(output.name)}\``, `*${outputType}${outputArray}*`, output.description]) }) readmeResult += markdownTable(readmeResultTable, { align: ['c', 'c', 'l'] }) + '\n'