Skip to content

Commit

Permalink
templating client generation
Browse files Browse the repository at this point in the history
  • Loading branch information
battis committed Sep 18, 2024
1 parent 5dab8ea commit 18dcd7e
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 91 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
**/vendor/
**/var/*
!**/var/README.md
!**/var/*.example.*
/coverage/
/examples/**/composer.lock
/packages/**/composer.lock
Expand Down
120 changes: 109 additions & 11 deletions bin/schema.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,114 @@
import cli from '@battis/qui-cli';
import { glob } from 'glob';
import fs from 'node:fs';
import path from 'node:path';
import prettier from 'prettier';

const map = {
'var/afe-rostr.json': 'packages/oneroster/src',
'var/school.json': 'packages/school/src'
type Map = {
schema: string;
path: string;
namespace: string;
package: string;
};

cli.init();
const CWD = process.cwd();

for (const schema in map) {
cli.shell.exec(
`npx openapi-typescript ${schema} -o ${
map[schema as keyof typeof map]
}/schema.ts`
);
}
(async () => {
let {
values: { mapPath, templatePath, prettierConfig }
} = cli.init({
args: {
options: {
mapPath: {
short: 'm',
description: `Path to the schema map JSON file (refer to README.md)`,
default: './var/schema-map.json'
},
templatePath: {
short: 't',
description: `Path to the template package (refer to README.md)`,
default: './packages/typescript-template'
},
prettierConfig: {
short: 'p',
description: `Path to Prettier configuration file`,
default: './package.json'
}
}
}
});

const spinner = cli.spinner();

spinner.start('Parsing schema map');
mapPath = path.resolve(CWD, mapPath!);
const maps = JSON.parse(fs.readFileSync(mapPath).toString()) as Map[];
spinner.succeed(`Schema map: ${cli.colors.url(mapPath)}`);

spinner.start('Parsing template');
templatePath = path.join(CWD, templatePath!);
const templateFilePaths = await glob(path.join(templatePath, './**/*'), {
ignore: '**/node_modules/**'
});
spinner.succeed(`Template: ${cli.colors.url(templatePath)}`);

spinner.start('Finding Prettier configuration');
prettierConfig = path.resolve(CWD, prettierConfig!);
const prettierOptions = await prettier.resolveConfig(prettierConfig);
spinner.succeed(`Pretter config: ${cli.colors.url(prettierConfig)}`);

for (const map of maps) {
map.schema = path.resolve(path.dirname(mapPath), map.schema);
spinner.start(cli.colors.url(map.schema));
map.path = path.resolve(path.dirname(mapPath), map.path);
const schema = JSON.parse(fs.readFileSync(map.schema).toString());
for (const templateFilePath of templateFilePaths) {
const targetPath = path.join(
map.path,
templateFilePath.replace(templatePath, '.')
);
spinner.start(cli.colors.url(targetPath));
if (fs.statSync(templateFilePath).isDirectory()) {
if (!fs.existsSync(targetPath)) {
fs.mkdirSync(targetPath);
}
} else {
const contents = fs
.readFileSync(templateFilePath)
.toString()
.replace(/__NAMESPACE__/g, map.namespace)
.replace(/__PACKAGE__/g, map.package)
.replace(/__BASE_URL__/g, schema.servers[0].url);
if (path.basename(templateFilePath) == 'package.json') {
const pkg = JSON.parse(fs.readFileSync(targetPath).toString());
fs.writeFileSync(
targetPath,
await prettier.format(
JSON.stringify({
...pkg,
...JSON.parse(contents)
}),
{
...prettierOptions,
filepath: targetPath
}
)
);
} else {
fs.writeFileSync(
targetPath,
await prettier.format(contents, {
...prettierOptions,
filepath: targetPath
})
);
}
}
spinner.succeed(cli.colors.url(targetPath));
}
cli.shell.exec(
`npx openapi-typescript ${map.schema} -o ${path.join(map.path, 'src/schema.ts')}`
);
spinner.succeed(cli.colors.value(map.package));
}
})();
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@changesets/cli": "^2.27.8",
"@groton/sky-api.tsconfig": "workspace:*",
"@tsconfig/recommended": "^1.0.7",
"glob": "^11.0.0",
"lerna": "^8.1.8",
"monorepo-package-paths": "^0.3.1",
"npm-run-all": "^4.1.5",
Expand Down
19 changes: 10 additions & 9 deletions packages/oneroster/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import Authorization from '@groton/sky-api.auth-middleware';
import createClient from 'openapi-fetch';
import type { components, paths } from './schema.js';

namespace SKY {
export type OneRoster = components['schemas'];
export namespace School {
export function client(getCredentials: Authorization.CredentialsPromise) {
const client = createClient<paths>();
client.use(Authorization.middleware(getCredentials));
return client;
}
type OneRoster = components['schemas'];

namespace OneRoster {
export function Client(getCredentials: Authorization.CredentialsPromise) {
const client = createClient<paths>({
baseUrl: 'https://api.sky.blackbaud.com/afe-rostr/ims/oneroster/v1p1'
});
client.use(Authorization.middleware(getCredentials));
return client;
}
}

export default SKY;
export default OneRoster;
19 changes: 10 additions & 9 deletions packages/school/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import Authorization from '@groton/sky-api.auth-middleware';
import createClient from 'openapi-fetch';
import type { components, paths } from './schema.js';

namespace SKY {
export type School = components['schemas'];
export namespace School {
export function client(getCredentials: Authorization.CredentialsPromise) {
const client = createClient<paths>();
client.use(Authorization.middleware(getCredentials));
return client;
}
type School = components['schemas'];

namespace School {
export function Client(getCredentials: Authorization.CredentialsPromise) {
const client = createClient<paths>({
baseUrl: 'https://api.sky.blackbaud.com/school'
});
client.use(Authorization.middleware(getCredentials));
return client;
}
}

export default SKY;
export default School;
27 changes: 27 additions & 0 deletions packages/typescript-template/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "__PACKAGE__",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"./dist/*",
"./README.md"
],
"scripts": {
"clean": "del ./dist/*",
"build": "run-s build:*",
"build:clean": "run-s clean",
"build:compile": "tsc"
},
"dependencies": {
"@groton/sky-api.auth-middleware": "workspace:*",
"openapi-fetch": "^0.12.0"
},
"devDependencies": {
"del-cli": "^5.1.0",
"npm-run-all": "^4.1.5"
},
"peerDependencies": {
"@groton/sky-api.tsconfig": "workspace:*"
}
}
15 changes: 15 additions & 0 deletions packages/typescript-template/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Authorization from '@groton/sky-api.auth-middleware';
import createClient from 'openapi-fetch';
import type { components, paths } from './schema.js';

type __NAMESPACE__ = components['schemas'];

namespace __NAMESPACE__ {
export function Client(getCredentials: Authorization.CredentialsPromise) {
const client = createClient<paths>({ baseUrl: '__BASE_URL__' });
client.use(Authorization.middleware(getCredentials));
return client;
}
}

export default __NAMESPACE__;
Loading

0 comments on commit 18dcd7e

Please sign in to comment.