From d8c926897e0721961fde1250f8b9051dc86c69cc Mon Sep 17 00:00:00 2001 From: Richard Rodger Date: Wed, 23 Oct 2024 18:04:48 +0100 Subject: [PATCH] transform-control --- bin/run-apidef.js | 188 ++++++++++++++++++ dist-test/apidef.test.js | 1 + dist-test/apidef.test.js.map | 2 +- dist/apidef.d.ts | 9 +- dist/apidef.js | 189 +++++------------- dist/apidef.js.map | 2 +- dist/transform.d.ts | 23 +++ dist/transform.js | 96 ++++++++++ dist/transform.js.map | 1 + dist/transform/entity.d.ts | 5 + dist/transform/entity.js | 33 ++++ dist/transform/entity.js.map | 1 + dist/transform/field.d.ts | 5 + dist/transform/field.js | 138 ++++++++++++++ dist/transform/field.js.map | 1 + dist/transform/fieldTransform.d.ts | 5 + dist/transform/fieldTransform.js | 55 ++++++ dist/transform/fieldTransform.js.map | 1 + dist/transform/manual.d.ts | 5 + dist/transform/manual.js | 11 ++ dist/transform/manual.js.map | 1 + dist/transform/operation.d.ts | 5 + dist/transform/operation.js | 77 ++++++++ dist/transform/operation.js.map | 1 + dist/transform/top.d.ts | 5 + dist/transform/top.js | 11 ++ dist/transform/top.js.map | 1 + model/guide.jsonic | 32 ++++ package-lock.json | 56 +++--- package.json | 13 +- src/apidef.ts | 275 ++++++++------------------- src/transform.ts | 176 +++++++++++++++++ src/transform/entity.ts | 49 +++++ src/transform/field.ts | 179 +++++++++++++++++ src/transform/manual.ts | 22 +++ src/transform/operation.ts | 120 ++++++++++++ src/transform/top.ts | 21 ++ test/apidef.test.ts | 2 + 38 files changed, 1451 insertions(+), 366 deletions(-) create mode 100755 bin/run-apidef.js create mode 100644 dist/transform.d.ts create mode 100644 dist/transform.js create mode 100644 dist/transform.js.map create mode 100644 dist/transform/entity.d.ts create mode 100644 dist/transform/entity.js create mode 100644 dist/transform/entity.js.map create mode 100644 dist/transform/field.d.ts create mode 100644 dist/transform/field.js create mode 100644 dist/transform/field.js.map create mode 100644 dist/transform/fieldTransform.d.ts create mode 100644 dist/transform/fieldTransform.js create mode 100644 dist/transform/fieldTransform.js.map create mode 100644 dist/transform/manual.d.ts create mode 100644 dist/transform/manual.js create mode 100644 dist/transform/manual.js.map create mode 100644 dist/transform/operation.d.ts create mode 100644 dist/transform/operation.js create mode 100644 dist/transform/operation.js.map create mode 100644 dist/transform/top.d.ts create mode 100644 dist/transform/top.js create mode 100644 dist/transform/top.js.map create mode 100644 src/transform.ts create mode 100644 src/transform/entity.ts create mode 100644 src/transform/field.ts create mode 100644 src/transform/manual.ts create mode 100644 src/transform/operation.ts create mode 100644 src/transform/top.ts diff --git a/bin/run-apidef.js b/bin/run-apidef.js new file mode 100755 index 0000000..715eb01 --- /dev/null +++ b/bin/run-apidef.js @@ -0,0 +1,188 @@ +#!/usr/bin/env node + +const Path = require('node:path') +const { statSync } = require('node:fs') +const { parseArgs } = require('node:util') + +const { Gubu, Fault } = require('gubu') +const { Aontu, Context } = require('aontu') + + +const Pkg = require('../package.json') + +const { ApiDef } = require('../dist/apidef.js') + + +let DEBUG = false +let CONSOLE = console + + +try { + let options = resolveOptions() + + if(options.debug) { + DEBUG = true + } + + if(options.version) { + version() + } + + if(options.help) { + help() + } + + if(options.version || options.help) { + exit() + } + + options = validateOptions(options) + + generate(options) + +} +catch(err) { + handleError(err) +} + + + +function exit(err) { + let code = 0 + if(err) { + code = 1 + } + process.exit(code) +} + + +function generate(options) { + const apidef = new ApiDef({ + debug: options.debug + }) + + const spec = { + def: options.def, + kind: 'openapi-3', + model: Path.join(options.folder,'model/api.jsonic'), + meta: { name: options.name }, + } + + if(options.watch) { + apidef.watch(spec) + } + else { + apidef.generate(spec) + } + +} + + + +function resolveOptions() { + + const args = parseArgs({ + allowPositionals: true, + options: { + folder: { + type: 'string', + short: 'f', + default: '', + }, + + def: { + type: 'string', + short: 'd', + default: '', + }, + + watch: { + type: 'boolean', + short: 'w', + }, + + debug: { + type: 'boolean', + short: 'g', + }, + + help: { + type: 'boolean', + short: 'h', + }, + + version: { + type: 'boolean', + short: 'v', + }, + + } + }) + + const options = { + name: args.positionals[0], + folder: '' === args.values.folder ? args.positionals[0] : args.values.folder, + def: args.values.def, + watch: !!args.values.watch, + debug: !!args.values.debug, + help: !!args.values.help, + version: !!args.values.version, + } + + return options +} + + +function validateOptions(rawOptions) { + const optShape = Gubu({ + name: Fault('The first argument should be the project name.', String), + folder: String, + def: '', + watch: Boolean, + debug: Boolean, + help: Boolean, + version: Boolean, + }) + + const err = [] + const options = optShape(rawOptions,{err}) + + if(err[0]) { + throw new Error(err[0].text) + } + + if('' !== options.def) { + options.def = Path.resolve(options.def) + const stat = statSync(options.def, {throwIfNoEntry:false}) + if(null == stat) { + throw new Error('Definition file not found: '+options.def) + } + } + + return options +} + + +function handleError(err) { + CONSOLE.log('Voxgig SDK Generator Error:') + + if(DEBUG) { + CONSOLE.log(err) + } + else { + CONSOLE.log(err.message) + } + + exit(err) +} + + +function version() { + CONSOLE.log(Pkg.version) +} + + +function help() { + const s = 'TODO' + CONSOLE.log(s) +} diff --git a/dist-test/apidef.test.js b/dist-test/apidef.test.js index b92b4ea..dcb516c 100644 --- a/dist-test/apidef.test.js +++ b/dist-test/apidef.test.js @@ -1,4 +1,5 @@ "use strict"; +/* Copyright (c) 2024 Voxgig Ltd, MIT License */ Object.defineProperty(exports, "__esModule", { value: true }); const node_test_1 = require("node:test"); const code_1 = require("@hapi/code"); diff --git a/dist-test/apidef.test.js.map b/dist-test/apidef.test.js.map index 9697221..1d52f30 100644 --- a/dist-test/apidef.test.js.map +++ b/dist-test/apidef.test.js.map @@ -1 +1 @@ -{"version":3,"file":"apidef.test.js","sourceRoot":"","sources":["../test/apidef.test.ts"],"names":[],"mappings":";;AACA,yCAA0C;AAC1C,qCAAmC;AAEnC,iCAA6B;AAG7B,oEAAoE;AAEpE,2BAEY;AAIZ,IAAA,oBAAQ,EAAC,QAAQ,EAAE,GAAG,EAAE;IAEtB,IAAA,gBAAI,EAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QACvB,IAAA,aAAM,EAAC,UAAM,CAAC,CAAC,KAAK,EAAE,CAAA;QAEtB,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,IAAA,aAAK,EAAC;YACxB,gBAAgB,EAAE,IAAI,CAAC,aAAa;YACpC,6BAA6B,EAAE,IAAI,CAAC,0BAA0B;SAC/D,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAA,UAAM,EAAC;YACpB,EAAE;SACH,CAAC,CAAA;QACF,IAAA,aAAM,EAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAA;QAEtB,MAAM,IAAI,GAAG;YACX,GAAG,EAAE,gBAAgB;YACrB,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE,uBAAuB;YAC9B,IAAI,EAAE;gBACJ,IAAI,EAAE,KAAK;aACZ;SACF,CAAA;QAED,MAAM,GAAG,GAAQ,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5C,IAAA,aAAM,EAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAA;QAEnB,kDAAkD;QAElD,oCAAoC;QACpC,wCAAwC;QAExC,6DAA6D;QAC7D,2DAA2D;QAE3D,4EAA4E;QAC5E,4EAA4E;QAE5E,+BAA+B;QAC/B,0CAA0C;QAC1C,0CAA0C;QAC1C,KAAK;IAEP,CAAC,CAAC,CAAA;AAEJ,CAAC,CAAC,CAAA;AAGF,MAAM,IAAI,GAAG;IACX,0BAA0B,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B7B;IACC,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6OhB;IAEC,uBAAuB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6F1B;CAEA,CAAA"} \ No newline at end of file +{"version":3,"file":"apidef.test.js","sourceRoot":"","sources":["../test/apidef.test.ts"],"names":[],"mappings":";AAAA,gDAAgD;;AAGhD,yCAA0C;AAC1C,qCAAmC;AAEnC,iCAA6B;AAG7B,oEAAoE;AAEpE,2BAEY;AAIZ,IAAA,oBAAQ,EAAC,QAAQ,EAAE,GAAG,EAAE;IAEtB,IAAA,gBAAI,EAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QACvB,IAAA,aAAM,EAAC,UAAM,CAAC,CAAC,KAAK,EAAE,CAAA;QAEtB,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,IAAA,aAAK,EAAC;YACxB,gBAAgB,EAAE,IAAI,CAAC,aAAa;YACpC,6BAA6B,EAAE,IAAI,CAAC,0BAA0B;SAC/D,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAA,UAAM,EAAC;YACpB,EAAE;SACH,CAAC,CAAA;QACF,IAAA,aAAM,EAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAA;QAEtB,MAAM,IAAI,GAAG;YACX,GAAG,EAAE,gBAAgB;YACrB,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE,uBAAuB;YAC9B,IAAI,EAAE;gBACJ,IAAI,EAAE,KAAK;aACZ;SACF,CAAA;QAED,MAAM,GAAG,GAAQ,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5C,IAAA,aAAM,EAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAA;QAEnB,kDAAkD;QAElD,oCAAoC;QACpC,wCAAwC;QAExC,6DAA6D;QAC7D,2DAA2D;QAE3D,4EAA4E;QAC5E,4EAA4E;QAE5E,+BAA+B;QAC/B,0CAA0C;QAC1C,0CAA0C;QAC1C,KAAK;IAEP,CAAC,CAAC,CAAA;AAEJ,CAAC,CAAC,CAAA;AAGF,MAAM,IAAI,GAAG;IACX,0BAA0B,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B7B;IACC,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6OhB;IAEC,uBAAuB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6F1B;CAEA,CAAA"} \ No newline at end of file diff --git a/dist/apidef.d.ts b/dist/apidef.d.ts index 1619836..d64b753 100644 --- a/dist/apidef.d.ts +++ b/dist/apidef.d.ts @@ -1,9 +1,16 @@ type ApiDefOptions = { fs?: any; + debug?: boolean; +}; +type ApiDefSpec = { + def: string; + model: string; + kind: string; + meta: Record; }; declare function ApiDef(opts?: ApiDefOptions): { watch: (spec: any) => Promise; - generate: (spec: any) => Promise<{ + generate: (spec: ApiDefSpec) => Promise<{ ok: boolean; model: { main: { diff --git a/dist/apidef.js b/dist/apidef.js index 794640e..19ea7a3 100644 --- a/dist/apidef.js +++ b/dist/apidef.js @@ -1,5 +1,5 @@ "use strict"; -/* Copyright (c) 2024 Richard Rodger, MIT License */ +/* Copyright (c) 2024 Voxgig, MIT License */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); @@ -33,7 +33,7 @@ const node_path_1 = __importDefault(require("node:path")); const openapi_core_1 = require("@redocly/openapi-core"); const chokidar_1 = require("chokidar"); const aontu_1 = require("aontu"); -const jostraca_1 = require("jostraca"); +const transform_1 = require("./transform"); function ApiDef(opts = {}) { const fs = opts.fs || Fs; async function watch(spec) { @@ -49,9 +49,25 @@ function ApiDef(opts = {}) { fsw.add(spec.guide); } async function generate(spec) { - // console.log('APIDEF.generate') + const start = Date.now(); + // TODO: Validate spec + const ctx = { + spec, + guide: {}, + opts, + util: { fixName: transform_1.fixName }, + defpath: node_path_1.default.dirname(spec.def) + }; + if (opts.debug) { + console.log('@voxgig/apidef =============', start, new Date(start)); + console.dir(spec, { depth: null }); + } const guide = await resolveGuide(spec, opts); - const transform = resolveTranform(spec, guide, opts); + console.log('APIDEF.guide'); + console.dir(guide, { depth: null }); + ctx.guide = guide; + const transformSpec = await (0, transform_1.resolveTransforms)(ctx); + console.log('APIDEF.transformSpec', transformSpec); const source = fs.readFileSync(spec.def, 'utf8'); const modelBasePath = node_path_1.default.dirname(spec.model); const config = await (0, openapi_core_1.createConfig)({}); @@ -71,7 +87,10 @@ function ApiDef(opts = {}) { try { const def = bundle.bundle.parsed; // console.dir(def, { depth: null }) - transform(def, model); + const processResult = await (0, transform_1.processTransforms)(ctx, transformSpec, model, def); + console.log('APIDEF.processResult', processResult); + console.log('APIDEF.model'); + console.dir(model, { depth: null }); } catch (err) { console.log('APIDEF ERROR', err); @@ -80,7 +99,14 @@ function ApiDef(opts = {}) { const modelapi = { main: { api: model.main.api } }; let modelSrc = JSON.stringify(modelapi, null, 2); modelSrc = modelSrc.substring(1, modelSrc.length - 1); - fs.writeFileSync(spec.model, modelSrc); + /* + console.log('WRITE', spec.model) + fs.writeFileSync( + spec.model, + modelSrc + ) + */ + writeChanged(spec.model, modelSrc); const defFilePath = node_path_1.default.join(modelBasePath, 'def.jsonic'); const modelDef = { main: { def: model.main.def } }; let modelDefSrc = JSON.stringify(modelDef, null, 2); @@ -100,6 +126,20 @@ function ApiDef(opts = {}) { model, }; } + function writeChanged(path, content) { + let existingContent = ''; + if (fs.existsSync(path)) { + existingContent = fs.readFileSync(path, 'utf8'); + } + let writeFile = existingContent !== content; + if (writeFile) { + console.log('WRITE-CHANGE: YES', path); + fs.writeFileSync(path, content); + } + else { + console.log('WRITE-CHANGE: NO', path); + } + } async function resolveGuide(spec, _opts) { if (null == spec.guide) { spec.guide = spec.def + '-guide.jsonic'; @@ -114,7 +154,7 @@ function ApiDef(opts = {}) { src = ` # API Specification Transform Guide -@"node_modules/@voxgig/apidef/model/guide.jsonic" +@"@voxgig/apidef/model/guide.jsonic" guide: entity: { @@ -123,20 +163,20 @@ guide: entity: { `; fs.writeFileSync(path, src); } + // console.log('GUIDE SRC', src) const aopts = {}; const root = (0, aontu_1.Aontu)(src, aopts); const hasErr = root.err && 0 < root.err.length; // TODO: collect all errors if (hasErr) { - // console.log(root.err) - // throw new Error(root.err[0]) + console.log('RESOLVE-GUIDE PARSE', root.err); throw root.err[0].err; } let genctx = new aontu_1.Context({ root }); const guide = spec.guideModel = root.gen(genctx); // TODO: collect all errors if (genctx.err && 0 < genctx.err.length) { - // console.log(genctx.err) + console.log('RESOLVE-GUIDE GEN', genctx.err); throw new Error(JSON.stringify(genctx.err[0])); } // console.log('GUIDE') @@ -159,133 +199,4 @@ guide: entity: { generate, }; } -function resolveTranform(spec, guide, opts) { - return makeOpenAPITransform(spec, guide, opts); -} -function extractFields(properties) { - const fieldMap = (0, jostraca_1.each)(properties) - .reduce((a, p) => (a[p.key$] = - { name: p.key$, kind: (0, jostraca_1.camelify)(p.type) }, a), {}); - return fieldMap; -} -function fixName(base, name, prop = 'name') { - base[prop.toLowerCase()] = name.toLowerCase(); - base[(0, jostraca_1.camelify)(prop)] = (0, jostraca_1.camelify)(name); - base[prop.toUpperCase()] = name.toUpperCase(); -} -function makeOpenAPITransform(spec, guideModel, opts) { - const paramBuilder = (paramMap, paramDef, entityModel, pathdef, op, path, entity, model) => { - paramMap[paramDef.name] = { - required: paramDef.required - }; - fixName(paramMap[paramDef.name], paramDef.name); - const type = paramDef.schema ? paramDef.schema.type : paramDef.type; - fixName(paramMap[paramDef.name], type, 'type'); - }; - const queryBuilder = (queryMap, queryDef, entityModel, pathdef, op, path, entity, model) => { - queryMap[queryDef.name] = { - required: queryDef.required - }; - fixName(queryMap[queryDef.name], queryDef.name); - const type = queryDef.schema ? queryDef.schema.type : queryDef.type; - fixName(queryMap[queryDef.name], type, 'type'); - }; - const opBuilder = { - any: (entityModel, pathdef, op, path, entity, model) => { - const em = entityModel.op[op.key$] = { - path: path.key$, - method: op.val$, - param: {}, - query: {}, - }; - fixName(em, op.key$); - // Params are in the path - if (0 < path.params.length) { - let params = (0, jostraca_1.getx)(pathdef[op.val$], 'parameters?in=path') || []; - if (Array.isArray(params)) { - params.reduce((a, p) => (paramBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.param); - } - } - // Queries are after the ? - let queries = (0, jostraca_1.getx)(pathdef[op.val$], 'parameters?in!=path') || []; - if (Array.isArray(queries)) { - queries.reduce((a, p) => (queryBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.query); - } - return em; - }, - list: (entityModel, pathdef, op, path, entity, model) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model); - }, - load: (entityModel, pathdef, op, path, entity, model) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model); - }, - create: (entityModel, pathdef, op, path, entity, model) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model); - }, - save: (entityModel, pathdef, op, path, entity, model) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model); - }, - remove: (entityModel, pathdef, op, path, entity, model) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model); - }, - }; - function fieldbuild(entityModel, pathdef, op, path, entity, model) { - // console.log(pathdef) - let fieldSets = (0, jostraca_1.getx)(pathdef.get, 'responses 200 content "application/json" schema'); - if (fieldSets) { - if (Array.isArray(fieldSets.allOf)) { - fieldSets = fieldSets.allOf; - } - else if (fieldSets.properties) { - fieldSets = [fieldSets]; - } - } - (0, jostraca_1.each)(fieldSets, (fieldSet) => { - (0, jostraca_1.each)(fieldSet.properties, (property) => { - // console.log(property) - const field = (entityModel.field[property.key$] = entityModel.field[property.key$] || {}); - field.name = property.key$; - fixName(field, field.name); - field.type = property.type; - fixName(field, field.type, 'type'); - field.short = property.description; - }); - }); - } - return function OpenAPITransform(def, model) { - fixName(model.main.api, spec.meta.name); - // console.log('OpenAPITransform', guideModel) - model.main.def.desc = def.info.description; - (0, jostraca_1.each)(guideModel.guide.entity, (entity) => { - // console.log('ENTITY', entity) - const entityModel = model.main.api.entity[entity.key$] = { - op: {}, - field: {}, - cmd: {}, - }; - fixName(entityModel, entity.key$); - (0, jostraca_1.each)(entity.path, (path) => { - const pathdef = def.paths[path.key$]; - if (null == pathdef) { - throw new Error('APIDEF: path not found in OpenAPI: ' + path.key$ + - ' (entity: ' + entity.name + ')'); - } - path.parts = path.key$.split('/'); - path.params = path.parts - .filter((p) => p.startsWith('{')) - .map((p) => p.substring(1, p.length - 1)); - // console.log('ENTITY-PATH', entity, path) - (0, jostraca_1.each)(path.op, (op) => { - const opbuild = opBuilder[op.key$]; - if (opbuild) { - opbuild(entityModel, pathdef, op, path, entity, model); - } - if ('load' === op.key$) { - fieldbuild(entityModel, pathdef, op, path, entity, model); - } - }); - }); - }); - }; -} //# sourceMappingURL=apidef.js.map \ No newline at end of file diff --git a/dist/apidef.js.map b/dist/apidef.js.map index fed6980..9995a0b 100644 --- a/dist/apidef.js.map +++ b/dist/apidef.js.map @@ -1 +1 @@ -{"version":3,"file":"apidef.js","sourceRoot":"","sources":["../src/apidef.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"apidef.js","sourceRoot":"","sources":["../src/apidef.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/transform.d.ts b/dist/transform.d.ts new file mode 100644 index 0000000..8be1c2a --- /dev/null +++ b/dist/transform.d.ts @@ -0,0 +1,23 @@ +type TransformCtx = { + spec: any; + guide: any; + opts: any; + util: any; + defpath: string; +}; +type TransformSpec = { + transform: Transform[]; +}; +type TransformResult = { + ok: boolean; +}; +type Transform = (ctx: TransformCtx, tspec: TransformSpec, model: any, def: any) => Promise; +type ProcessResult = { + ok: boolean; + results: TransformResult[]; +}; +declare function resolveTransforms(ctx: TransformCtx): Promise; +declare function processTransforms(ctx: TransformCtx, spec: TransformSpec, model: any, def: any): Promise; +declare function fixName(base: any, name: string, prop?: string): void; +export type { TransformCtx, TransformSpec, }; +export { fixName, resolveTransforms, processTransforms, }; diff --git a/dist/transform.js b/dist/transform.js new file mode 100644 index 0000000..e04a292 --- /dev/null +++ b/dist/transform.js @@ -0,0 +1,96 @@ +"use strict"; +/* Copyright (c) 2024 Voxgig, MIT License */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fixName = fixName; +exports.resolveTransforms = resolveTransforms; +exports.processTransforms = processTransforms; +const node_path_1 = __importDefault(require("node:path")); +const jostraca_1 = require("jostraca"); +const top_1 = require("./transform/top"); +const entity_1 = require("./transform/entity"); +const operation_1 = require("./transform/operation"); +const field_1 = require("./transform/field"); +const manual_1 = require("./transform/manual"); +const TRANSFORM = { + top: top_1.topTransform, + entity: entity_1.entityTransform, + operation: operation_1.operationTransform, + field: field_1.fieldTransform, + manual: manual_1.manualTransform, +}; +async function resolveTransforms(ctx) { + const { guide: { guide } } = ctx; + const tspec = { + transform: [] + }; + // TODO: parameterize + const defkind = 'openapi'; + const transformNames = guide.control.transform[defkind].order + .split(/\s*,\s*/) + .map((t) => t.trim()) + .filter((t) => '' != t); + console.log('TRANSFORM-RESOLVE-NAMES', transformNames); + for (const tn of transformNames) { + console.log('TRANSFORM-RESOLVE', tn); + const transform = await resolveTransform(tn, ctx); + tspec.transform.push(transform); + } + //tspec.transform = await Promise.all(transformNames.map(async (tn: string) => + // await resolveTransform(tn, ctx))) + console.log(tspec); + return tspec; +} +async function resolveTransform(tn, ctx) { + const { defpath, guide: { guide } } = ctx; + let transform = TRANSFORM[tn]; + if (transform) { + return transform; + } + const tdef = guide.transform[tn]; + if (null == tdef) { + throw new Error('APIDEF-TRANSFORM: unknown transform: ' + tn); + } + if (!tn.startsWith('custom')) { + throw new Error('APIDEF-TRANSFORM: custom transform name must start with "custom": ' + tn); + } + const customtpath = node_path_1.default.join(defpath, tdef.load); + try { + const transformModule = require(customtpath); + transform = transformModule[tn]; + } + catch (e) { + throw new Error('APIDEF-TRANSFORM: custom transform not found: ' + + customtpath + ': ' + e.message); + } + return transform; +} +async function processTransforms(ctx, spec, model, def) { + const pres = { + ok: true, + results: [] + }; + for (let tI = 0; tI < spec.transform.length; tI++) { + const transform = spec.transform[tI]; + const tres = await transform(ctx, spec, model, def); + pres.ok = pres.ok && tres.ok; + pres.results.push(tres); + } + return pres; +} +/* +function extractFields(properties: any) { + const fieldMap = each(properties) + .reduce((a: any, p: any) => (a[p.key$] = + { name: p.key$, kind: camelify(p.type) }, a), {}) + return fieldMap +} +*/ +function fixName(base, name, prop = 'name') { + base[prop.toLowerCase()] = name.toLowerCase(); + base[(0, jostraca_1.camelify)(prop)] = (0, jostraca_1.camelify)(name); + base[prop.toUpperCase()] = name.toUpperCase(); +} +//# sourceMappingURL=transform.js.map \ No newline at end of file diff --git a/dist/transform.js.map b/dist/transform.js.map new file mode 100644 index 0000000..b25739a --- /dev/null +++ b/dist/transform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"transform.js","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/transform/entity.d.ts b/dist/transform/entity.d.ts new file mode 100644 index 0000000..469a177 --- /dev/null +++ b/dist/transform/entity.d.ts @@ -0,0 +1,5 @@ +import type { TransformCtx, TransformSpec } from '../transform'; +declare function entityTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any): Promise<{ + ok: boolean; +}>; +export { entityTransform }; diff --git a/dist/transform/entity.js b/dist/transform/entity.js new file mode 100644 index 0000000..41437eb --- /dev/null +++ b/dist/transform/entity.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.entityTransform = entityTransform; +const jostraca_1 = require("jostraca"); +const transform_1 = require("../transform"); +async function entityTransform(ctx, tspec, model, def) { + const { guide: { guide } } = ctx; + (0, jostraca_1.each)(guide.entity, (guideEntity) => { + const entityModel = model.main.api.entity[guideEntity.key$] = { + op: {}, + field: {}, + cmd: {}, + id: { + name: 'id', + field: 'id', + } + }; + (0, transform_1.fixName)(entityModel, guideEntity.key$); + (0, jostraca_1.each)(guideEntity.path, (guidePath) => { + const pathdef = def.paths[guidePath.key$]; + if (null == pathdef) { + throw new Error('APIDEF: path not found in OpenAPI: ' + guidePath.key$ + + ' (entity: ' + guideEntity.name + ')'); + } + guidePath.parts$ = guidePath.key$.split('/'); + guidePath.params$ = guidePath.parts$ + .filter((p) => p.startsWith('{')) + .map((p) => p.substring(1, p.length - 1)); + }); + }); + return { ok: true }; +} +//# sourceMappingURL=entity.js.map \ No newline at end of file diff --git a/dist/transform/entity.js.map b/dist/transform/entity.js.map new file mode 100644 index 0000000..a9d93c6 --- /dev/null +++ b/dist/transform/entity.js.map @@ -0,0 +1 @@ +{"version":3,"file":"entity.js","sourceRoot":"","sources":["../../src/transform/entity.ts"],"names":[],"mappings":";;AA+CE,0CAAe;AA7CjB,uCAA+B;AAI/B,4CAAsC;AAItC,KAAK,UAAU,eAAe,CAAC,GAAiB,EAAE,KAAoB,EAAE,KAAU,EAAE,GAAQ;IAC1F,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,GAAG,CAAA;IAEhC,IAAA,eAAI,EAAC,KAAK,CAAC,MAAM,EAAE,CAAC,WAAgB,EAAE,EAAE;QAEtC,MAAM,WAAW,GAAQ,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG;YACjE,EAAE,EAAE,EAAE;YACN,KAAK,EAAE,EAAE;YACT,GAAG,EAAE,EAAE;YACP,EAAE,EAAE;gBACF,IAAI,EAAE,IAAI;gBACV,KAAK,EAAE,IAAI;aACZ;SACF,CAAA;QAED,IAAA,mBAAO,EAAC,WAAW,EAAE,WAAW,CAAC,IAAI,CAAC,CAAA;QAEtC,IAAA,eAAI,EAAC,WAAW,CAAC,IAAI,EAAE,CAAC,SAAc,EAAE,EAAE;YACxC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YAEzC,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,qCAAqC,GAAG,SAAS,CAAC,IAAI;oBACpE,YAAY,GAAG,WAAW,CAAC,IAAI,GAAG,GAAG,CAAC,CAAA;YAC1C,CAAC;YAED,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC5C,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM;iBACjC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;iBACxC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;QACrD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACrB,CAAC"} \ No newline at end of file diff --git a/dist/transform/field.d.ts b/dist/transform/field.d.ts new file mode 100644 index 0000000..7b9fa15 --- /dev/null +++ b/dist/transform/field.d.ts @@ -0,0 +1,5 @@ +import type { TransformCtx, TransformSpec } from '../transform'; +declare function fieldTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any): Promise<{ + ok: boolean; +}>; +export { fieldTransform }; diff --git a/dist/transform/field.js b/dist/transform/field.js new file mode 100644 index 0000000..911c9dc --- /dev/null +++ b/dist/transform/field.js @@ -0,0 +1,138 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fieldTransform = fieldTransform; +const jostraca_1 = require("jostraca"); +const transform_1 = require("../transform"); +async function fieldTransform(ctx, tspec, model, def) { + const { guide: { guide } } = ctx; + (0, jostraca_1.each)(guide.entity, (guideEntity) => { + const entityModel = model.main.api.entity[guideEntity.key$]; + (0, jostraca_1.each)(guideEntity.path, (guidePath) => { + const pathdef = def.paths[guidePath.key$]; + (0, jostraca_1.each)(guidePath.op, (op) => { + if ('load' === op.key$) { + fieldbuild(entityModel, pathdef, op, guidePath, guideEntity, model); + } + }); + }); + }); + return { ok: true }; +} +function fieldbuild(entityModel, pathdef, op, path, entity, model) { + // console.log('FB-A', op, pathdef) + let fieldSets = (0, jostraca_1.getx)(pathdef.get, 'responses 200 content "application/json" schema'); + if (fieldSets) { + if (Array.isArray(fieldSets.allOf)) { + fieldSets = fieldSets.allOf; + } + else if (fieldSets.properties) { + fieldSets = [fieldSets]; + } + } + // console.log('TRANSFORM-FIELDSETS', fieldSets) + (0, jostraca_1.each)(fieldSets, (fieldSet) => { + (0, jostraca_1.each)(fieldSet.properties, (property) => { + // console.log(property) + const field = (entityModel.field[property.key$] = entityModel.field[property.key$] || {}); + field.name = property.key$; + (0, transform_1.fixName)(field, field.name); + field.type = property.type; + (0, transform_1.fixName)(field, field.type, 'type'); + field.short = property.description; + // console.log('FB-ID', field.name, entityModel.param) + }); + }); + // Guess id field name using GET path param + if ('load' === op.key$) { + const getdef = pathdef.get; + const getparams = getdef.parameters || []; + if (1 === getparams.length) { + if (entityModel.op.load.path.match(RegExp('\\{' + getdef.parameters[0].name + '\\}$'))) { + entityModel.id.field = getdef.parameters[0].name; + } + } + } +} +/* + +# API Specification Transform Guide + + +@"@voxgig/apidef/model/guide.jsonic" + + +guide: control: transform: openapi: order: ` + + top, + entity, + operation, + field, + customField, + + ` + +guide: transform: customField: { + load: 'customField.js' +} + + +guide: entity: { + pet: path: { + '/pet/{petId}': { + op:{ load: 'get', create: 'post', save: 'put' } + } + } + pet: test: { + quick: { + active: true, + create: { id: 1, name:'Rex' }, + load: { id: 1 }, + } + } + + # direct custom definition + pet: def: {} +} + + + + +const { each, getx } = require('jostraca') + + +async function customField(ctx, tspec, model, def) { + const { spec, util: {fixName} } = ctx + + const nameField = { + name: 'name', + type: 'string', + short: 'Name of pet' + } + fixName(nameField, nameField.name) + fixName(nameField, nameField.type, 'type') + + const ageField = { + name: 'age', + type: 'number', + short: 'Age of pet' + } + fixName(ageField, ageField.name) + fixName(ageField, ageField.type, 'type') + + + Object.assign(model.main.api.entity.pet.field, { + name: nameField, + age: ageField, + }) + + return { ok: true } +} + + +module.exports = { + customField +} + + + */ +//# sourceMappingURL=field.js.map \ No newline at end of file diff --git a/dist/transform/field.js.map b/dist/transform/field.js.map new file mode 100644 index 0000000..082a33e --- /dev/null +++ b/dist/transform/field.js.map @@ -0,0 +1 @@ +{"version":3,"file":"field.js","sourceRoot":"","sources":["../../src/transform/field.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/transform/fieldTransform.d.ts b/dist/transform/fieldTransform.d.ts new file mode 100644 index 0000000..7b9fa15 --- /dev/null +++ b/dist/transform/fieldTransform.d.ts @@ -0,0 +1,5 @@ +import type { TransformCtx, TransformSpec } from '../transform'; +declare function fieldTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any): Promise<{ + ok: boolean; +}>; +export { fieldTransform }; diff --git a/dist/transform/fieldTransform.js b/dist/transform/fieldTransform.js new file mode 100644 index 0000000..3c4648f --- /dev/null +++ b/dist/transform/fieldTransform.js @@ -0,0 +1,55 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fieldTransform = fieldTransform; +const jostraca_1 = require("jostraca"); +const transform_1 = require("../transform"); +async function fieldTransform(ctx, tspec, model, def) { + const { guide: { guide } } = ctx; + (0, jostraca_1.each)(guide.entity, (guideEntity) => { + const entityModel = model.main.api.entity[guideEntity.key$]; + (0, jostraca_1.each)(guideEntity.path, (guidePath) => { + const pathdef = def.paths[guidePath.key$]; + (0, jostraca_1.each)(guidePath.op, (op) => { + if ('load' === op.key$) { + fieldbuild(entityModel, pathdef, op, guidePath, guideEntity, model); + } + }); + }); + }); + return { ok: true }; +} +function fieldbuild(entityModel, pathdef, op, path, entity, model) { + // console.log('FB-A', op, pathdef) + let fieldSets = (0, jostraca_1.getx)(pathdef.get, 'responses 200 content "application/json" schema'); + if (fieldSets) { + if (Array.isArray(fieldSets.allOf)) { + fieldSets = fieldSets.allOf; + } + else if (fieldSets.properties) { + fieldSets = [fieldSets]; + } + } + (0, jostraca_1.each)(fieldSets, (fieldSet) => { + (0, jostraca_1.each)(fieldSet.properties, (property) => { + // console.log(property) + const field = (entityModel.field[property.key$] = entityModel.field[property.key$] || {}); + field.name = property.key$; + (0, transform_1.fixName)(field, field.name); + field.type = property.type; + (0, transform_1.fixName)(field, field.type, 'type'); + field.short = property.description; + // console.log('FB-ID', field.name, entityModel.param) + }); + }); + // Guess id field name using GET path param + if ('load' === op.key$) { + const getdef = pathdef.get; + const getparams = getdef.parameters || []; + if (1 === getparams.length) { + if (entityModel.op.load.path.match(RegExp('\\{' + getdef.parameters[0].name + '\\}$'))) { + entityModel.id.field = getdef.parameters[0].name; + } + } + } +} +//# sourceMappingURL=fieldTransform.js.map \ No newline at end of file diff --git a/dist/transform/fieldTransform.js.map b/dist/transform/fieldTransform.js.map new file mode 100644 index 0000000..85f5fc3 --- /dev/null +++ b/dist/transform/fieldTransform.js.map @@ -0,0 +1 @@ +{"version":3,"file":"fieldTransform.js","sourceRoot":"","sources":["../../src/transform/fieldTransform.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/transform/manual.d.ts b/dist/transform/manual.d.ts new file mode 100644 index 0000000..64320c8 --- /dev/null +++ b/dist/transform/manual.d.ts @@ -0,0 +1,5 @@ +import type { TransformCtx, TransformSpec } from '../transform'; +declare function manualTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any): Promise<{ + ok: boolean; +}>; +export { manualTransform }; diff --git a/dist/transform/manual.js b/dist/transform/manual.js new file mode 100644 index 0000000..6bbc92b --- /dev/null +++ b/dist/transform/manual.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.manualTransform = manualTransform; +const jsonic_next_1 = require("@jsonic/jsonic-next"); +const { deep } = jsonic_next_1.Jsonic.util; +async function manualTransform(ctx, tspec, model, def) { + const { guide: { guide: { manual } } } = ctx; + deep(model, manual); + return { ok: true }; +} +//# sourceMappingURL=manual.js.map \ No newline at end of file diff --git a/dist/transform/manual.js.map b/dist/transform/manual.js.map new file mode 100644 index 0000000..7d806d0 --- /dev/null +++ b/dist/transform/manual.js.map @@ -0,0 +1 @@ +{"version":3,"file":"manual.js","sourceRoot":"","sources":["../../src/transform/manual.ts"],"names":[],"mappings":";;AAoBE,0CAAe;AAnBjB,qDAA4C;AAO5C,MAAM,EAAE,IAAI,EAAE,GAAG,oBAAM,CAAC,IAAI,CAAA;AAE5B,KAAK,UAAU,eAAe,CAAC,GAAiB,EAAE,KAAoB,EAAE,KAAU,EAAE,GAAQ;IAC1F,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAA;IAE5C,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAEnB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACrB,CAAC"} \ No newline at end of file diff --git a/dist/transform/operation.d.ts b/dist/transform/operation.d.ts new file mode 100644 index 0000000..4197090 --- /dev/null +++ b/dist/transform/operation.d.ts @@ -0,0 +1,5 @@ +import type { TransformCtx, TransformSpec } from '../transform'; +declare function operationTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any): Promise<{ + ok: boolean; +}>; +export { operationTransform }; diff --git a/dist/transform/operation.js b/dist/transform/operation.js new file mode 100644 index 0000000..9728003 --- /dev/null +++ b/dist/transform/operation.js @@ -0,0 +1,77 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.operationTransform = operationTransform; +const jostraca_1 = require("jostraca"); +const transform_1 = require("../transform"); +async function operationTransform(ctx, tspec, model, def) { + const { guide: { guide } } = ctx; + const paramBuilder = (paramMap, paramDef, entityModel, pathdef, op, path, entity, model) => { + paramMap[paramDef.name] = { + required: paramDef.required + }; + (0, transform_1.fixName)(paramMap[paramDef.name], paramDef.name); + const type = paramDef.schema ? paramDef.schema.type : paramDef.type; + (0, transform_1.fixName)(paramMap[paramDef.name], type, 'type'); + }; + const queryBuilder = (queryMap, queryDef, entityModel, pathdef, op, path, entity, model) => { + queryMap[queryDef.name] = { + required: queryDef.required + }; + (0, transform_1.fixName)(queryMap[queryDef.name], queryDef.name); + const type = queryDef.schema ? queryDef.schema.type : queryDef.type; + (0, transform_1.fixName)(queryMap[queryDef.name], type, 'type'); + }; + const opBuilder = { + any: (entityModel, pathdef, op, path, entity, model) => { + const em = entityModel.op[op.key$] = { + path: path.key$, + method: op.val$, + param: {}, + query: {}, + }; + (0, transform_1.fixName)(em, op.key$); + // Params are in the path + if (0 < path.params$.length) { + let params = (0, jostraca_1.getx)(pathdef[op.val$], 'parameters?in=path') || []; + if (Array.isArray(params)) { + params.reduce((a, p) => (paramBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.param); + } + } + // Queries are after the ? + let queries = (0, jostraca_1.getx)(pathdef[op.val$], 'parameters?in!=path') || []; + if (Array.isArray(queries)) { + queries.reduce((a, p) => (queryBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.query); + } + return em; + }, + list: (entityModel, pathdef, op, path, entity, model) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model); + }, + load: (entityModel, pathdef, op, path, entity, model) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model); + }, + create: (entityModel, pathdef, op, path, entity, model) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model); + }, + save: (entityModel, pathdef, op, path, entity, model) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model); + }, + remove: (entityModel, pathdef, op, path, entity, model) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model); + }, + }; + (0, jostraca_1.each)(guide.entity, (guideEntity) => { + const entityModel = model.main.api.entity[guideEntity.key$]; + (0, jostraca_1.each)(guideEntity.path, (guidePath) => { + const pathdef = def.paths[guidePath.key$]; + (0, jostraca_1.each)(guidePath.op, (op) => { + const opbuild = opBuilder[op.key$]; + if (opbuild) { + opbuild(entityModel, pathdef, op, guidePath, guideEntity, model); + } + }); + }); + }); + return { ok: true }; +} +//# sourceMappingURL=operation.js.map \ No newline at end of file diff --git a/dist/transform/operation.js.map b/dist/transform/operation.js.map new file mode 100644 index 0000000..ae3633e --- /dev/null +++ b/dist/transform/operation.js.map @@ -0,0 +1 @@ +{"version":3,"file":"operation.js","sourceRoot":"","sources":["../../src/transform/operation.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/transform/top.d.ts b/dist/transform/top.d.ts new file mode 100644 index 0000000..186c34a --- /dev/null +++ b/dist/transform/top.d.ts @@ -0,0 +1,5 @@ +import type { TransformCtx, TransformSpec } from '../transform'; +declare function topTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any): Promise<{ + ok: boolean; +}>; +export { topTransform }; diff --git a/dist/transform/top.js b/dist/transform/top.js new file mode 100644 index 0000000..b68f74d --- /dev/null +++ b/dist/transform/top.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.topTransform = topTransform; +const transform_1 = require("../transform"); +async function topTransform(ctx, tspec, model, def) { + const { spec } = ctx; + (0, transform_1.fixName)(model.main.api, spec.meta.name); + model.main.def.desc = def.info.description; + return { ok: true }; +} +//# sourceMappingURL=top.js.map \ No newline at end of file diff --git a/dist/transform/top.js.map b/dist/transform/top.js.map new file mode 100644 index 0000000..f781c59 --- /dev/null +++ b/dist/transform/top.js.map @@ -0,0 +1 @@ +{"version":3,"file":"top.js","sourceRoot":"","sources":["../../src/transform/top.ts"],"names":[],"mappings":";;AAmBE,oCAAY;AAdd,4CAAsC;AAGtC,KAAK,UAAU,YAAY,CAAC,GAAiB,EAAE,KAAoB,EAAE,KAAU,EAAE,GAAQ;IACvF,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAA;IAEpB,IAAA,mBAAO,EAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,CAAA;IAE1C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACrB,CAAC"} \ No newline at end of file diff --git a/model/guide.jsonic b/model/guide.jsonic index 7eb1b03..4549c9f 100644 --- a/model/guide.jsonic +++ b/model/guide.jsonic @@ -1,4 +1,35 @@ +guide: control: transform: &: { + order: string +} + +guide: control: transform: openapi: { + order: *` + + top, + entity, + operation, + field, + manual, + + ` | string +} + + +guide: transform: &: { + name: .$KEY + load: string +} + +guide: transform: { + top: {} + entity: {} + operation: {} + field: {} + manual: {} +} + + guide: entity: &: { name: .$KEY path: &: { @@ -7,3 +38,4 @@ guide: entity: &: { } +guide: manual: {} diff --git a/package-lock.json b/package-lock.json index 5b3cb3d..0965030 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,27 @@ { "name": "@voxgig/apidef", - "version": "0.1.4", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@voxgig/apidef", - "version": "0.1.4", + "version": "0.2.0", "license": "MIT", "dependencies": { - "@redocly/openapi-core": "^1.25.7", + "@redocly/openapi-core": "^1.25.8", "chokidar": "^4.0.1", - "jostraca": "^0.7.6" + "gubu": "^8.3.0", + "jostraca": "^0.7.7" + }, + "bin": { + "apidef": "bin/run-apidef.js" }, "devDependencies": { "@hapi/code": "^9.0.3", "@types/js-yaml": "^4.0.9", - "@types/node": "22.7.6", - "aontu": "^0.22.0", + "@types/node": "22.7.8", + "aontu": "^0.23.0", "esbuild": "^0.24.0", "json-schema-to-ts": "^3.1.1", "memfs": "^4.14.0", @@ -462,9 +466,9 @@ } }, "node_modules/@jsonic/multisource": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonic/multisource/-/multisource-1.2.0.tgz", - "integrity": "sha512-Bp6sDAYPLrNsnT4b8jKsS26kTZfHTYdDlKqjkL5WENKsOiNN0r6pOFXr/+808JedodNm5UINLUdKKqRCDJ17WQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonic/multisource/-/multisource-1.3.0.tgz", + "integrity": "sha512-+Lm99ovlUsDarJh3PkHEH9jcmsR5smTdm4dpLPa5NtMQqv1WSAiL5TkPaSSeG14SShyKwIA+0iBrG2FE464VYw==", "dev": true, "peerDependencies": { "@jsonic/directive": ">=0.11.4", @@ -555,9 +559,9 @@ "integrity": "sha512-RW3rSirfsPdr0uvATijRDU3f55SuZV3m7/ppdTDvGw4IB0cmeZRkFmqTrchxMqWP50Gfg1tpHnjdxUCNo0E2qg==" }, "node_modules/@redocly/openapi-core": { - "version": "1.25.7", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.7.tgz", - "integrity": "sha512-qidGKk4Bq0Ud0O8gRuXnDSLwVopwrf5+roNvpkvdQPVIHFSYJ5dscJkThdsn7OW8bNqahumQPWWczEh9l93FZw==", + "version": "1.25.8", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.8.tgz", + "integrity": "sha512-eKKRqo2RYo7UIoDvIgcUB9ynhOjIWJnILXFz+VDevYeOBKd/CxvC0KbNRnuOrFqG3ip6363R/ONal2MyvuVrjg==", "dependencies": { "@redocly/ajv": "^8.11.2", "@redocly/config": "^0.12.1", @@ -583,9 +587,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", - "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", + "version": "22.7.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.8.tgz", + "integrity": "sha512-a922jJy31vqR5sk+kAdIENJjHblqcZ4RmERviFsER4WJcEONqxKcjNOlk0q7OUfrF5sddT+vng070cdfMlrPLg==", "dev": true, "dependencies": { "undici-types": "~6.19.2" @@ -603,15 +607,15 @@ } }, "node_modules/aontu": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/aontu/-/aontu-0.22.0.tgz", - "integrity": "sha512-Vd2IkAZu0Xlpwx9H5ICIqVK6oMSXi8vuGT2mhwvotzXBY5O7dPPfZ3Z5BdvBgyBfBJCqJXMHnERnq8QB52yNfQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/aontu/-/aontu-0.23.0.tgz", + "integrity": "sha512-zmc3GgkMi9xEygk7pxjRwBgW321Qfh0wL/sYPaaicuPcPGwbXKDB6iDzkyfpWZQRt38LaurepZL4b4kIcCFFeA==", "dev": true, "dependencies": { "@jsonic/directive": "^0.11.4", "@jsonic/expr": "^0.8.3", "@jsonic/jsonic-next": "^2.12.1", - "@jsonic/multisource": "^1.2.0", + "@jsonic/multisource": "^1.3.0", "@jsonic/path": "^0.7.0" }, "engines": { @@ -715,6 +719,14 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/gubu": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/gubu/-/gubu-8.3.0.tgz", + "integrity": "sha512-v/CrDWq3VSGDuUxeVjvgeDfDas2w4pi8KHTO2r+AJ2qoIULxCUHXZ+OOFIBRmm2xp3SHOynJtx6VabtYPBYUbQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", @@ -737,9 +749,9 @@ } }, "node_modules/jostraca": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/jostraca/-/jostraca-0.7.6.tgz", - "integrity": "sha512-OqNeTFJwnmHLFogUAZUvGlX4RwRfTuKepo7cXTBO3tmlrZW0ZkIhcZtazAXDeWEI8omXgoFmbrLl6kKJMqqjVQ==", + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/jostraca/-/jostraca-0.7.7.tgz", + "integrity": "sha512-II9yzfSqvtMER7GuX1vJXY9Rg87tA3Nk+sOb1ZypZV0I/b54R+O5P1Nzmmpp2WnHS1m+xfIM35AanrfIY4I5Xg==", "dependencies": { "@jsonic/jsonic-next": "^2.12.1" } diff --git a/package.json b/package.json index c776c18..abaf1e0 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,9 @@ "type": "git", "url": "git://github.com/voxgig/apidef.git" }, + "bin": { + "apidef": "bin/run-apidef.js" + }, "scripts": { "test": "node --enable-source-maps --test dist-test", "test22": "node --enable-source-maps --test \"dist-test/*.test.js\"", @@ -32,21 +35,23 @@ "model", "src", "dist", + "bin", "LICENSE" ], "devDependencies": { "@hapi/code": "^9.0.3", "@types/js-yaml": "^4.0.9", - "@types/node": "22.7.6", - "aontu": "^0.22.0", + "@types/node": "22.7.8", + "aontu": "^0.23.0", "esbuild": "^0.24.0", "json-schema-to-ts": "^3.1.1", "memfs": "^4.14.0", "typescript": "^5.6.3" }, "dependencies": { - "@redocly/openapi-core": "^1.25.7", + "@redocly/openapi-core": "^1.25.8", "chokidar": "^4.0.1", - "jostraca": "^0.7.6" + "gubu": "^8.3.0", + "jostraca": "^0.7.7" } } diff --git a/src/apidef.ts b/src/apidef.ts index 734a23d..b98e919 100644 --- a/src/apidef.ts +++ b/src/apidef.ts @@ -1,4 +1,4 @@ -/* Copyright (c) 2024 Richard Rodger, MIT License */ +/* Copyright (c) 2024 Voxgig, MIT License */ import * as Fs from 'node:fs' @@ -14,11 +14,25 @@ import { Aontu, Context } from 'aontu' import { getx, each, camelify } from 'jostraca' +import { + resolveTransforms, + processTransforms, + fixName, +} from './transform' + + type ApiDefOptions = { fs?: any + debug?: boolean } +type ApiDefSpec = { + def: string + model: string, + kind: string, + meta: Record, +} function ApiDef(opts: ApiDefOptions = {}) { @@ -43,11 +57,33 @@ function ApiDef(opts: ApiDefOptions = {}) { } - async function generate(spec: any) { - // console.log('APIDEF.generate') + async function generate(spec: ApiDefSpec) { + const start = Date.now() + + // TODO: Validate spec + const ctx = { + spec, + guide: {}, + opts, + util: { fixName }, + defpath: Path.dirname(spec.def) + } + + if (opts.debug) { + console.log('@voxgig/apidef =============', start, new Date(start)) + console.dir(spec, { depth: null }) + } const guide = await resolveGuide(spec, opts) - const transform = resolveTranform(spec, guide, opts) + console.log('APIDEF.guide') + console.dir(guide, { depth: null }) + + + + ctx.guide = guide + const transformSpec = await resolveTransforms(ctx) + console.log('APIDEF.transformSpec', transformSpec) + const source = fs.readFileSync(spec.def, 'utf8') @@ -72,7 +108,12 @@ function ApiDef(opts: ApiDefOptions = {}) { try { const def = bundle.bundle.parsed // console.dir(def, { depth: null }) - transform(def, model) + + const processResult = await processTransforms(ctx, transformSpec, model, def) + console.log('APIDEF.processResult', processResult) + + console.log('APIDEF.model') + console.dir(model, { depth: null }) } catch (err: any) { console.log('APIDEF ERROR', err) @@ -83,11 +124,15 @@ function ApiDef(opts: ApiDefOptions = {}) { let modelSrc = JSON.stringify(modelapi, null, 2) modelSrc = modelSrc.substring(1, modelSrc.length - 1) + /* + console.log('WRITE', spec.model) fs.writeFileSync( spec.model, modelSrc ) + */ + writeChanged(spec.model, modelSrc) const defFilePath = Path.join(modelBasePath, 'def.jsonic') @@ -119,6 +164,27 @@ function ApiDef(opts: ApiDefOptions = {}) { } + + function writeChanged(path: string, content: string) { + let existingContent: string = '' + + if (fs.existsSync(path)) { + existingContent = fs.readFileSync(path, 'utf8') + } + + let writeFile = existingContent !== content + + if (writeFile) { + console.log('WRITE-CHANGE: YES', path) + fs.writeFileSync(path, content) + } + else { + console.log('WRITE-CHANGE: NO', path) + } + } + + + async function resolveGuide(spec: any, _opts: any) { if (null == spec.guide) { spec.guide = spec.def + '-guide.jsonic' @@ -136,7 +202,7 @@ function ApiDef(opts: ApiDefOptions = {}) { src = ` # API Specification Transform Guide -@"node_modules/@voxgig/apidef/model/guide.jsonic" +@"@voxgig/apidef/model/guide.jsonic" guide: entity: { @@ -146,14 +212,16 @@ guide: entity: { fs.writeFileSync(path, src) } + + // console.log('GUIDE SRC', src) + const aopts = {} const root = Aontu(src, aopts) const hasErr = root.err && 0 < root.err.length // TODO: collect all errors if (hasErr) { - // console.log(root.err) - // throw new Error(root.err[0]) + console.log('RESOLVE-GUIDE PARSE', root.err) throw root.err[0].err } @@ -162,7 +230,7 @@ guide: entity: { // TODO: collect all errors if (genctx.err && 0 < genctx.err.length) { - // console.log(genctx.err) + console.log('RESOLVE-GUIDE GEN', genctx.err) throw new Error(JSON.stringify(genctx.err[0])) } @@ -197,195 +265,6 @@ guide: entity: { - -function resolveTranform(spec: any, guide: any, opts: any) { - return makeOpenAPITransform(spec, guide, opts) -} - - -function extractFields(properties: any) { - const fieldMap = each(properties) - .reduce((a: any, p: any) => (a[p.key$] = - { name: p.key$, kind: camelify(p.type) }, a), {}) - return fieldMap -} - - -function fixName(base: any, name: string, prop = 'name') { - base[prop.toLowerCase()] = name.toLowerCase() - base[camelify(prop)] = camelify(name) - base[prop.toUpperCase()] = name.toUpperCase() -} - - -function makeOpenAPITransform(spec: any, guideModel: any, opts: any) { - - const paramBuilder = (paramMap: any, paramDef: any, - entityModel: any, pathdef: any, - op: any, path: any, entity: any, model: any) => { - - paramMap[paramDef.name] = { - required: paramDef.required - } - fixName(paramMap[paramDef.name], paramDef.name) - - const type = paramDef.schema ? paramDef.schema.type : paramDef.type - fixName(paramMap[paramDef.name], type, 'type') - } - - - const queryBuilder = (queryMap: any, queryDef: any, - entityModel: any, pathdef: any, - op: any, path: any, entity: any, model: any) => { - queryMap[queryDef.name] = { - required: queryDef.required - } - fixName(queryMap[queryDef.name], queryDef.name) - - const type = queryDef.schema ? queryDef.schema.type : queryDef.type - fixName(queryMap[queryDef.name], type, 'type') - } - - - const opBuilder: any = { - any: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { - const em = entityModel.op[op.key$] = { - path: path.key$, - method: op.val$, - param: {}, - query: {}, - } - fixName(em, op.key$) - - // Params are in the path - if (0 < path.params.length) { - let params = getx(pathdef[op.val$], 'parameters?in=path') || [] - if (Array.isArray(params)) { - params.reduce((a: any, p: any) => - (paramBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.param) - } - } - - // Queries are after the ? - let queries = getx(pathdef[op.val$], 'parameters?in!=path') || [] - if (Array.isArray(queries)) { - queries.reduce((a: any, p: any) => - (queryBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.query) - } - - return em - }, - - - list: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model) - }, - - load: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model) - }, - - create: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model) - }, - - save: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model) - }, - - remove: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { - return opBuilder.any(entityModel, pathdef, op, path, entity, model) - }, - - } - - - function fieldbuild( - entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any - ) { - // console.log(pathdef) - - let fieldSets = getx(pathdef.get, 'responses 200 content "application/json" schema') - - if (fieldSets) { - if (Array.isArray(fieldSets.allOf)) { - fieldSets = fieldSets.allOf - } - else if (fieldSets.properties) { - fieldSets = [fieldSets] - } - } - - each(fieldSets, (fieldSet: any) => { - each(fieldSet.properties, (property: any) => { - // console.log(property) - - const field = - (entityModel.field[property.key$] = entityModel.field[property.key$] || {}) - - field.name = property.key$ - fixName(field, field.name) - - field.type = property.type - fixName(field, field.type, 'type') - - field.short = property.description - }) - }) - } - - - return function OpenAPITransform(def: any, model: any) { - fixName(model.main.api, spec.meta.name) - - // console.log('OpenAPITransform', guideModel) - - model.main.def.desc = def.info.description - - - each(guideModel.guide.entity, (entity: any) => { - // console.log('ENTITY', entity) - - const entityModel: any = model.main.api.entity[entity.key$] = { - op: {}, - field: {}, - cmd: {}, - } - - fixName(entityModel, entity.key$) - - each(entity.path, (path: any) => { - const pathdef = def.paths[path.key$] - - if (null == pathdef) { - throw new Error('APIDEF: path not found in OpenAPI: ' + path.key$ + - ' (entity: ' + entity.name + ')') - } - - path.parts = path.key$.split('/') - path.params = path.parts - .filter((p: string) => p.startsWith('{')) - .map((p: string) => p.substring(1, p.length - 1)) - - // console.log('ENTITY-PATH', entity, path) - - each(path.op, (op: any) => { - const opbuild = opBuilder[op.key$] - - if (opbuild) { - opbuild(entityModel, pathdef, op, path, entity, model) - } - - if ('load' === op.key$) { - fieldbuild(entityModel, pathdef, op, path, entity, model) - } - }) - }) - }) - } -} - - export type { ApiDefOptions, } diff --git a/src/transform.ts b/src/transform.ts new file mode 100644 index 0000000..84c2439 --- /dev/null +++ b/src/transform.ts @@ -0,0 +1,176 @@ +/* Copyright (c) 2024 Voxgig, MIT License */ + + +import Path from 'node:path' + +import { getx, each, camelify } from 'jostraca' + + +import { topTransform } from './transform/top' +import { entityTransform } from './transform/entity' +import { operationTransform } from './transform/operation' +import { fieldTransform } from './transform/field' +import { manualTransform } from './transform/manual' + + + +type TransformCtx = { + spec: any, + guide: any, + opts: any, + util: any, + defpath: string, +} + +type TransformSpec = { + transform: Transform[] +} + +type TransformResult = { + ok: boolean +} + +type Transform = ( + ctx: TransformCtx, + tspec: TransformSpec, + model: any, + def: any, +) => Promise + +type ProcessResult = { + ok: boolean + results: TransformResult[] +} + + + +const TRANSFORM: Record = { + top: topTransform, + entity: entityTransform, + operation: operationTransform, + field: fieldTransform, + manual: manualTransform, +} + + + + +async function resolveTransforms(ctx: TransformCtx): Promise { + const { guide: { guide } } = ctx + + const tspec: TransformSpec = { + transform: [] + } + + // TODO: parameterize + const defkind = 'openapi' + const transformNames = guide.control.transform[defkind].order + .split(/\s*,\s*/) + .map((t: string) => t.trim()) + .filter((t: string) => '' != t) + + console.log('TRANSFORM-RESOLVE-NAMES', transformNames) + + for (const tn of transformNames) { + console.log('TRANSFORM-RESOLVE', tn) + const transform = await resolveTransform(tn, ctx) + tspec.transform.push(transform) + } + + //tspec.transform = await Promise.all(transformNames.map(async (tn: string) => + // await resolveTransform(tn, ctx))) + + console.log(tspec) + + return tspec +} + + +async function resolveTransform(tn: string, ctx: TransformCtx) { + const { defpath, guide: { guide } } = ctx + + let transform = TRANSFORM[tn] + if (transform) { + return transform + } + + const tdef = guide.transform[tn] + if (null == tdef) { + throw new Error('APIDEF-TRANSFORM: unknown transform: ' + tn) + } + + if (!tn.startsWith('custom')) { + throw new Error('APIDEF-TRANSFORM: custom transform name must start with "custom": ' + tn) + } + + const customtpath = Path.join(defpath, tdef.load) + try { + const transformModule = require(customtpath) + transform = transformModule[tn] + } + catch (e: any) { + throw new Error('APIDEF-TRANSFORM: custom transform not found: ' + + customtpath + ': ' + e.message) + } + + return transform +} + + + +async function processTransforms( + ctx: TransformCtx, + spec: TransformSpec, + model: any, + def: any +): Promise { + const pres: ProcessResult = { + ok: true, + results: [] + } + + for (let tI = 0; tI < spec.transform.length; tI++) { + const transform = spec.transform[tI] + const tres = await transform(ctx, spec, model, def) + pres.ok = pres.ok && tres.ok + pres.results.push(tres) + } + + return pres +} + + + + + +/* +function extractFields(properties: any) { + const fieldMap = each(properties) + .reduce((a: any, p: any) => (a[p.key$] = + { name: p.key$, kind: camelify(p.type) }, a), {}) + return fieldMap +} +*/ + + +function fixName(base: any, name: string, prop = 'name') { + base[prop.toLowerCase()] = name.toLowerCase() + base[camelify(prop)] = camelify(name) + base[prop.toUpperCase()] = name.toUpperCase() +} + + + + + +export type { + TransformCtx, + TransformSpec, +} + + +export { + fixName, + resolveTransforms, + processTransforms, +} diff --git a/src/transform/entity.ts b/src/transform/entity.ts new file mode 100644 index 0000000..e220fce --- /dev/null +++ b/src/transform/entity.ts @@ -0,0 +1,49 @@ + + +import { each } from 'jostraca' + +import type { TransformCtx, TransformSpec } from '../transform' + +import { fixName } from '../transform' + + + +async function entityTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any) { + const { guide: { guide } } = ctx + + each(guide.entity, (guideEntity: any) => { + + const entityModel: any = model.main.api.entity[guideEntity.key$] = { + op: {}, + field: {}, + cmd: {}, + id: { + name: 'id', + field: 'id', + } + } + + fixName(entityModel, guideEntity.key$) + + each(guideEntity.path, (guidePath: any) => { + const pathdef = def.paths[guidePath.key$] + + if (null == pathdef) { + throw new Error('APIDEF: path not found in OpenAPI: ' + guidePath.key$ + + ' (entity: ' + guideEntity.name + ')') + } + + guidePath.parts$ = guidePath.key$.split('/') + guidePath.params$ = guidePath.parts$ + .filter((p: string) => p.startsWith('{')) + .map((p: string) => p.substring(1, p.length - 1)) + }) + }) + + return { ok: true } +} + + +export { + entityTransform +} diff --git a/src/transform/field.ts b/src/transform/field.ts new file mode 100644 index 0000000..8012a03 --- /dev/null +++ b/src/transform/field.ts @@ -0,0 +1,179 @@ + + +import { each, getx } from 'jostraca' + +import type { TransformCtx, TransformSpec } from '../transform' + +import { fixName } from '../transform' + + + +async function fieldTransform( + ctx: TransformCtx, + tspec: TransformSpec, + model: any, + def: any +) { + const { guide: { guide } } = ctx + + each(guide.entity, (guideEntity: any) => { + + const entityModel = model.main.api.entity[guideEntity.key$] + each(guideEntity.path, (guidePath: any) => { + const pathdef = def.paths[guidePath.key$] + + each(guidePath.op, (op: any) => { + + if ('load' === op.key$) { + fieldbuild(entityModel, pathdef, op, guidePath, guideEntity, model) + } + + }) + }) + }) + + return { ok: true } +} + + +function fieldbuild( + entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any +) { + // console.log('FB-A', op, pathdef) + + let fieldSets = getx(pathdef.get, 'responses 200 content "application/json" schema') + + if (fieldSets) { + if (Array.isArray(fieldSets.allOf)) { + fieldSets = fieldSets.allOf + } + else if (fieldSets.properties) { + fieldSets = [fieldSets] + } + } + + // console.log('TRANSFORM-FIELDSETS', fieldSets) + + each(fieldSets, (fieldSet: any) => { + each(fieldSet.properties, (property: any) => { + // console.log(property) + + const field = + (entityModel.field[property.key$] = entityModel.field[property.key$] || {}) + + field.name = property.key$ + fixName(field, field.name) + + field.type = property.type + fixName(field, field.type, 'type') + + field.short = property.description + + // console.log('FB-ID', field.name, entityModel.param) + }) + }) + + // Guess id field name using GET path param + if ('load' === op.key$) { + const getdef = pathdef.get + const getparams = getdef.parameters || [] + if (1 === getparams.length) { + if (entityModel.op.load.path.match(RegExp('\\{' + getdef.parameters[0].name + '\\}$'))) { + entityModel.id.field = getdef.parameters[0].name + } + } + } + +} + + + +export { + fieldTransform +} + + + + +/* + +# API Specification Transform Guide + + +@"@voxgig/apidef/model/guide.jsonic" + + +guide: control: transform: openapi: order: ` + + top, + entity, + operation, + field, + customField, + + ` + +guide: transform: customField: { + load: 'customField.js' +} + + +guide: entity: { + pet: path: { + '/pet/{petId}': { + op:{ load: 'get', create: 'post', save: 'put' } + } + } + pet: test: { + quick: { + active: true, + create: { id: 1, name:'Rex' }, + load: { id: 1 }, + } + } + + # direct custom definition + pet: def: {} +} + + + + +const { each, getx } = require('jostraca') + + +async function customField(ctx, tspec, model, def) { + const { spec, util: {fixName} } = ctx + + const nameField = { + name: 'name', + type: 'string', + short: 'Name of pet' + } + fixName(nameField, nameField.name) + fixName(nameField, nameField.type, 'type') + + const ageField = { + name: 'age', + type: 'number', + short: 'Age of pet' + } + fixName(ageField, ageField.name) + fixName(ageField, ageField.type, 'type') + + + Object.assign(model.main.api.entity.pet.field, { + name: nameField, + age: ageField, + }) + + return { ok: true } +} + + +module.exports = { + customField +} + + + */ diff --git a/src/transform/manual.ts b/src/transform/manual.ts new file mode 100644 index 0000000..56ceb7f --- /dev/null +++ b/src/transform/manual.ts @@ -0,0 +1,22 @@ + +import { Jsonic } from '@jsonic/jsonic-next' + +import { each, getx } from 'jostraca' + +import type { TransformCtx, TransformSpec } from '../transform' + + +const { deep } = Jsonic.util + +async function manualTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any) { + const { guide: { guide: { manual } } } = ctx + + deep(model, manual) + + return { ok: true } +} + + +export { + manualTransform +} diff --git a/src/transform/operation.ts b/src/transform/operation.ts new file mode 100644 index 0000000..3f99a85 --- /dev/null +++ b/src/transform/operation.ts @@ -0,0 +1,120 @@ + + +import { each, getx } from 'jostraca' + +import type { TransformCtx, TransformSpec } from '../transform' + +import { fixName } from '../transform' + + + +async function operationTransform( + ctx: TransformCtx, + tspec: TransformSpec, + model: any, + def: any +) { + const { guide: { guide } } = ctx + + const paramBuilder = (paramMap: any, paramDef: any, + entityModel: any, pathdef: any, + op: any, path: any, entity: any, model: any) => { + + paramMap[paramDef.name] = { + required: paramDef.required + } + fixName(paramMap[paramDef.name], paramDef.name) + + const type = paramDef.schema ? paramDef.schema.type : paramDef.type + fixName(paramMap[paramDef.name], type, 'type') + } + + + const queryBuilder = (queryMap: any, queryDef: any, + entityModel: any, pathdef: any, + op: any, path: any, entity: any, model: any) => { + queryMap[queryDef.name] = { + required: queryDef.required + } + fixName(queryMap[queryDef.name], queryDef.name) + + const type = queryDef.schema ? queryDef.schema.type : queryDef.type + fixName(queryMap[queryDef.name], type, 'type') + } + + const opBuilder: any = { + any: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { + const em = entityModel.op[op.key$] = { + path: path.key$, + method: op.val$, + param: {}, + query: {}, + } + fixName(em, op.key$) + + // Params are in the path + if (0 < path.params$.length) { + let params = getx(pathdef[op.val$], 'parameters?in=path') || [] + if (Array.isArray(params)) { + params.reduce((a: any, p: any) => + (paramBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.param) + } + } + + // Queries are after the ? + let queries = getx(pathdef[op.val$], 'parameters?in!=path') || [] + if (Array.isArray(queries)) { + queries.reduce((a: any, p: any) => + (queryBuilder(a, p, entityModel, pathdef, op, path, entity, model), a), em.query) + } + + return em + }, + + + list: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model) + }, + + load: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model) + }, + + create: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model) + }, + + save: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model) + }, + + remove: (entityModel: any, pathdef: any, op: any, path: any, entity: any, model: any) => { + return opBuilder.any(entityModel, pathdef, op, path, entity, model) + }, + + } + + + each(guide.entity, (guideEntity: any) => { + + const entityModel = model.main.api.entity[guideEntity.key$] + each(guideEntity.path, (guidePath: any) => { + const pathdef = def.paths[guidePath.key$] + + each(guidePath.op, (op: any) => { + const opbuild = opBuilder[op.key$] + + if (opbuild) { + opbuild(entityModel, pathdef, op, guidePath, guideEntity, model) + } + }) + }) + }) + + return { ok: true } +} + + +export { + operationTransform +} diff --git a/src/transform/top.ts b/src/transform/top.ts new file mode 100644 index 0000000..2ca7f6a --- /dev/null +++ b/src/transform/top.ts @@ -0,0 +1,21 @@ + +import { each, getx } from 'jostraca' + +import type { TransformCtx, TransformSpec } from '../transform' + +import { fixName } from '../transform' + + +async function topTransform(ctx: TransformCtx, tspec: TransformSpec, model: any, def: any) { + const { spec } = ctx + + fixName(model.main.api, spec.meta.name) + model.main.def.desc = def.info.description + + return { ok: true } +} + + +export { + topTransform +} diff --git a/test/apidef.test.ts b/test/apidef.test.ts index aa05c3e..504bcca 100644 --- a/test/apidef.test.ts +++ b/test/apidef.test.ts @@ -1,3 +1,5 @@ +/* Copyright (c) 2024 Voxgig Ltd, MIT License */ + import { test, describe } from 'node:test' import { expect } from '@hapi/code'