Skip to content

Commit

Permalink
cli: better input handling for adaptor generator
Browse files Browse the repository at this point in the history
  • Loading branch information
josephjclark committed Feb 21, 2024
1 parent b353c8c commit 5529e25
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 268 deletions.
2 changes: 1 addition & 1 deletion packages/cli/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type CommandList =
| 'docgen'
| 'docs'
| 'execute'
| 'generate'
| 'generate-adaptor'
| 'metadata'
| 'pull'
| 'repo-clean'
Expand Down
31 changes: 16 additions & 15 deletions packages/cli/src/generate/adaptor.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
/**
* Handler to generate adaptor code
*/

import { Opts } from '../options';
import { Logger } from '../util';
import mailchimp from './mailchimp-spec.json' assert { type: 'json' };
import loadGenSpec from './adaptor/load-gen-spec';

// TODO: really I just want one domain here
const endpoints = {
signature: 'http://localhost:8001/generate_signature',
code: 'http://localhost:8002/generate_code/',
};

type AdaptorGenOptions = Pick<
export type AdaptorGenOptions = Pick<
Opts,
| 'command'
| 'path' // path to spec - we proably want to override the description
Expand All @@ -21,14 +20,17 @@ type AdaptorGenOptions = Pick<
| 'monorepoPath' // maybe use the monorepo (or use env var)
| 'outputPath' // where to output to. Defaults to monorepo or as sibling of the spec
> & {
adaptor: string;
adaptor?: string;
spec?: string;

// TODO spec overrides
};

// spec.spec is silly, so what is this object?
type Spec = {
spec: any; // OpenAPI spec
export type Spec = {
adaptor?: string; // adaptor name. TOOD rename to name?

spec: any; // OpenAPI spec. TODO rename to api?

instruction: string; // for now... but we'll use endpoints later

Expand All @@ -37,19 +39,16 @@ type Spec = {
model?: string; // TODO not supported yet
};

const generateAdaptor = async (opts: any, logger: Logger) => {
logger.success('** GENERATE ADAPTOR**');
const generateAdaptor = async (opts: AdaptorGenOptions, logger: Logger) => {
// Load the input spec from the cli options
const spec = await loadGenSpec(opts, logger);

// TODO Validate that the spec looks correct

// if we're using the monorepo, and no adaptor with this name exists
// prompt to generate it
// humm is that worth it? it'll create a git diff anyway

// TODO load spec from path
// gonna hard code it right now
const spec = {
spec: mailchimp, // post as open_api_spec
instruction: 'Create an OpenFn function that accesses the /goals endpoint',
};

const sig = await generateSignature(spec, logger);
const code = await generateCode(spec, sig, logger);

Expand Down Expand Up @@ -77,6 +76,8 @@ const convertSpec = (spec: Spec) =>
JSON.stringify({
open_api_spec: spec.spec,
instruction: spec.instruction,

// For now we force this model
model: 'gpt3_turbo',
});

Expand Down
64 changes: 64 additions & 0 deletions packages/cli/src/generate/adaptor/load-gen-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import path from 'node:path';
import fs from 'node:fs/promises';

import type { AdaptorGenOptions, Spec } from '../adaptor';
import { Logger, abort } from '../../util';

// single standalone function to parse all the options and return a spec object
// I can unit test this comprehensively you see
const loadGenSpec = async (opts: AdaptorGenOptions, logger: Logger) => {
let spec: Partial<Spec> = {};

if (opts.path) {
const inputPath = path.resolve(opts.path);
logger.debug(`Loading input spec from ${inputPath}`);

try {
const text = await fs.readFile(inputPath, 'utf8');
spec = JSON.parse(text);
} catch (e) {
return abort(
logger,
'spec load error',
undefined,
`Failed to load a codegen specc from ${inputPath}`
);
}
}

if (opts.spec) {
spec.spec = opts.spec;
}
if (opts.adaptor) {
spec.adaptor = opts.adaptor;
}

if (typeof spec.spec === 'string') {
// TODO if opts.path isn't set I think this will blow up
const specPath = path.resolve(path.dirname(opts.path ?? '.'), spec.spec);
logger.debug(`Loading OpenAPI spec from ${specPath}`);
try {
const text = await fs.readFile(specPath, 'utf8');
spec.spec = JSON.parse(text);
} catch (e) {
return abort(
logger,
'OpenAPI error',
undefined,
`Failed to load openAPI spec from ${specPath}`
);
}
}

// if no name provided, see if we can pull one from the spec
if (!spec.adaptor) {
// TOOD use a lib for this?
spec.adaptor = spec.spec.info?.title?.toLowerCase().replace(/\W/g, '-');
}

logger.debug(`Final spec: ${JSON.stringify(spec, null, 2)}`);

return spec as Required<Spec>;
};

export default loadGenSpec;
3 changes: 1 addition & 2 deletions packages/cli/src/generate/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ options.push({

// Adaptor generation subcommand
const adaptor = {
command: 'adaptor',
command: 'adaptor [path]',
desc: 'Generate adaptor code',
handler: ensure('generate-adaptor', options),
builder: (yargs) =>
Expand All @@ -27,7 +27,6 @@ const adaptor = {
)
.positional('path', {
describe: 'The path spec.json',
demandOption: true,
}),
} as yargs.CommandModule<{}>;

Expand Down
Loading

0 comments on commit 5529e25

Please sign in to comment.