UNPKG

@jsforce/jsforce-node

Version:

Salesforce API Library for JavaScript

355 lines (354 loc) 10.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const node_fs_1 = __importDefault(require("node:fs")); const xml2js_1 = __importDefault(require("xml2js")); const soap_1 = require("../../soap"); const function_1 = require("../../util/function"); /** * */ const WSDLRestrictionSchema = { $: { base: 'string' }, enumeration: [ { $: { value: 'string' }, }, ], 'xsd:enumeration': [ { $: { value: 'string' }, }, ], }; const WSDLSimpleTypeSchema = { $: { name: 'string' }, restriction: WSDLRestrictionSchema, 'xsd:restriction': WSDLRestrictionSchema, }; const WSDLElementSchema = { $: { name: 'string', type: 'string', minOccurs: '?number', maxOccurs: '?string', nillable: '?boolean', }, }; const WSDLSequenceSchema = { element: ['?', WSDLElementSchema], 'xsd:element': ['?', WSDLElementSchema], }; const WSDLExtensionSchema = { $: { base: 'string' }, sequence: { '?': WSDLSequenceSchema }, 'xsd:sequence': { '?': WSDLSequenceSchema }, }; const WSDLComplexContentSchema = { extension: { '?': WSDLExtensionSchema }, 'xsd:extension': { '?': WSDLExtensionSchema }, }; const WSDLComplexTypeSchema = { $: { name: 'string' }, sequence: { '?': WSDLSequenceSchema }, 'xsd:sequence': { '?': WSDLSequenceSchema }, complexContent: { '?': WSDLComplexContentSchema }, 'xsd:complexContent': { '?': WSDLComplexContentSchema }, }; const WSDLSchemaSchema = { $: 'any', complexType: ['?', 'any'], simpleType: ['?', 'any'], 'xsd:complexType': ['?', 'any'], 'xsd:simpleType': ['?', 'any'], }; const WSDLSchema = { definitions: { $: 'any', types: { schema: ['?', WSDLSchemaSchema], 'xsd:schema': ['?', WSDLSchemaSchema], }, message: ['any'], portType: { $: 'any', operation: ['any'], }, binding: { $: 'any', operation: ['any'], }, service: { $: 'any', documentation: 'string', operation: ['any'], }, }, }; /** * */ function toJsType(xsdType, simpleTypes) { switch (xsdType) { case 'xsd:boolean': return 'boolean'; case 'xsd:string': case 'xsd:date': case 'xsd:dateTime': case 'xsd:time': case 'xsd:base64Binary': return 'string'; case 'xsd:int': case 'xsd:long': case 'xsd:double': return 'number'; case 'xsd:anyType': return 'any'; default: { const [ns, type] = xsdType.split(':'); if (simpleTypes[type]) { return simpleTypes[type]; } if (ns) { return type; } return xsdType; } } } /** * */ async function readWSDLFile(filePath) { const xmlData = await node_fs_1.default.promises.readFile(filePath, 'utf8'); const json = await xml2js_1.default.parseStringPromise(xmlData, { explicitArray: false, }); return (0, soap_1.castTypeUsingSchema)(json, WSDLSchema); } /** * */ function getTypeInfo(el, simpleTypes) { const type = toJsType(el.$.type, simpleTypes); const isArray = el.$.maxOccurs === 'unbounded'; const nillable = (!isArray && el.$.minOccurs === 0) || el.$.nillable; return isArray ? nillable ? ['?', type] : [type] : nillable ? `?${type}` : type; } /** * */ function extractComplexTypes(wsdl) { console.log(wsdl.definitions.types['xsd:schema']); const schemas = {}; const simpleTypes = {}; const types = wsdl.definitions.types; for (const sc of types.schema ?? types['xsd:schema'] ?? []) { for (const st of sc.simpleType ?? sc['xsd:simpleType'] ?? []) { const simpleType = (0, soap_1.castTypeUsingSchema)(st, WSDLSimpleTypeSchema); const rs = simpleType.restriction ?? simpleType['xsd:restriction']; const base = rs.$.base.split(':')[1]; simpleTypes[simpleType.$.name] = base; } } console.log({ simpleTypes }); for (const sc of types.schema ?? types['xsd:schema'] ?? []) { for (const ct of sc.complexType ?? sc['xsd:complexType'] ?? []) { const complexType = (0, soap_1.castTypeUsingSchema)(ct, WSDLComplexTypeSchema); const schema = { type: complexType.$.name, props: {}, }; const seq = complexType.sequence ?? complexType['xsd:sequence']; const els = seq?.element ?? seq?.['xsd:element']; for (const el of els ?? []) { schema.props[el.$.name] = getTypeInfo(el, simpleTypes); } const cc = complexType.complexContent ?? complexType['xsd:complexContent']; if (cc) { const extension = cc.extension ?? cc['xsd:extension']; if (extension) { schema.extends = extension.$.base.split(':')[1]; const seq = extension.sequence ?? extension['xsd:sequence']; const els = seq?.element ?? seq?.['xsd:element']; for (const el of els ?? []) { schema.props[el.$.name] = getTypeInfo(el, simpleTypes); } } } schemas[complexType.$.name] = schema; } } return schemas; } /** * */ const GENERATED_MESSAGE_COMMENT = `/** * This file is generated from WSDL file by wsdl2schema.ts. * Do not modify directly. * To generate the file, run "ts-node path/to/wsdl2schema.ts path/to/wsdl.xml path/to/schema.ts" */ `; /** * */ async function dumpSchema(schemas, outFile) { const out = node_fs_1.default.createWriteStream(outFile, 'utf8'); const print = (str, indent = 0) => { for (let i = 0; i < indent; i++) { out.write(' '); } out.write(str); }; const println = (str = '', indent = 0) => { print(str + '\n', indent); }; return new Promise((resolve, reject) => { out.on('error', reject); out.on('finish', () => resolve()); println(GENERATED_MESSAGE_COMMENT); print('export const ApiSchemas = '); writeSchema(schemas); println(' as const;'); println(); writeTypeDefs(schemas); out.end(); }); function writeSchema(o, indent = 0) { if (indent > 20) { print("'any'"); return; } if (Array.isArray(o)) { print('['); let i = 0; for (const co of o) { if (i > 0) { print(', '); } writeSchema(co, indent); i++; } print(']'); } else if ((0, function_1.isMapObject)(o)) { const keys = Object.keys(o); if (keys.length > 0) { println('{'); for (const name of keys) { const co = o[name]; const nameId = /^[\w_$]+$/.test(name) ? name : `'${name}'`; print(`${nameId}: `, indent + 2); writeSchema(co, indent + 2); println(','); } print('}', indent); } else { print('{}'); } } else { print(JSON.stringify(o).replace(/"/g, "'")); } } function writeTypeDef(o, schemas, indent = 0) { if (typeof o === 'string') { print(o); } else if ((0, function_1.isMapObject)(o)) { if ('type' in o && 'props' in o) { if ('extends' in o && typeof o.extends === 'string') { print(`${o.extends} & `); } writeTypeDef(o.props, schemas, indent); return; } const keys = Object.keys(o); if (keys.length > 0) { println('{'); for (const prop of Object.keys(o)) { let value = o[prop]; let nillable = false; let isArray = false; if (Array.isArray(value)) { isArray = true; const len = value.length; if (len === 2 && value[0] === '?') { nillable = true; value = value[1]; } else { value = value[0]; } } else if ((0, function_1.isMapObject)(value)) { if ('?' in value) { nillable = true; value = value['?']; } } if (typeof value === 'string' && value.startsWith('?')) { nillable = true; value = value.substring(1); } print(`${prop}${nillable ? '?' : ''}: `, indent + 2); writeTypeDef(value, schemas, indent + 2); if (isArray) { print('[]'); } if (nillable) { print(' | null | undefined'); } println(';'); } print('}', indent); } else { print('{}'); } } } function writeTypeDefs(schemas) { for (const name of Object.keys(schemas)) { const schema = schemas[name]; print(`export type ${name} = `); writeTypeDef(schema, schemas); println(';'); println(); } println('export type ApiSchemaTypes = {'); for (const name of Object.keys(schemas)) { println(`${name}: ${name};`, 2); } println('};'); } } /** * */ async function main() { const wsdlFilePath = process.argv[2]; if (!wsdlFilePath) { console.error('No input WSDL file is specified.'); return; } const outFilePath = process.argv[3]; if (!wsdlFilePath) { console.error('No output typescript schema file is specified.'); return; } const wsdl = await readWSDLFile(wsdlFilePath); const schemas = extractComplexTypes(wsdl); dumpSchema(schemas, outFilePath); } main();