@ps-aux/api-client-gen 0.0.6-rc1 → 0.0.6-rc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@ps-aux/api-client-gen",
3
- "version": "0.0.6-rc1",
3
+ "version": "0.0.6-rc3",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.esm.js",
6
- "type": "module",
7
6
  "types": "dist/index.d.ts",
8
7
  "bin": {
9
8
  "gen-api-client": "dist/bin.js"
@@ -1,22 +0,0 @@
1
- import axios from 'axios'
2
- import fs from 'fs/promises'
3
-
4
- export const downloadSpec = async (path: string, url: string) => {
5
- const res = await axios({
6
- url,
7
- method: 'GET',
8
- responseType: 'arraybuffer',
9
- }).catch(err => {
10
- throw err.toString()
11
- })
12
-
13
- const content = res.data.toString()
14
-
15
- await fs.writeFile(path, format(content))
16
- }
17
-
18
- const format = (content: string): string =>
19
- JSON.stringify(
20
- JSON.parse(content), null, 4,
21
- )
22
-
@@ -1,76 +0,0 @@
1
- import Path from 'path'
2
- import * as fs from 'fs'
3
- import { downloadSpec } from './downloadSpec'
4
- import { generateOpenApiModel } from './generateOpenApiModel'
5
- import { generateSchemas, GenerateSchemasOptions } from './generateSchemas'
6
-
7
- export type Params = {
8
- srcSpec: string, // path or http(s) URL
9
- dstDir: string
10
- apiName: string
11
- env: 'browser' | 'node'
12
- responseWrapper?: {
13
- symbol: string
14
- import?: string
15
- },
16
- zodSchemas?: GenerateSchemasOptions & {
17
- enabled?: boolean
18
- }
19
- }
20
-
21
- export const generateApiClient = async ({
22
- dstDir,
23
- apiName,
24
- env,
25
- srcSpec,
26
- responseWrapper,
27
- zodSchemas,
28
- }: Params, log: (msg: string) => void = console.log): Promise<void> => {
29
- if (!srcSpec) throw new Error(`Url or path ('srcSpec' not specified`)
30
- if (!apiName) throw new Error('apiName not specified')
31
- if (!dstDir) throw new Error('dstDir not specified')
32
- if (!env) throw new Error('env not specified')
33
-
34
- const dir = Path.resolve(dstDir, apiName)
35
- if (!fs.existsSync(dir)) {
36
- log(`Creating dir ${dir}`)
37
- fs.mkdirSync(dir, {
38
- recursive: true,
39
- })
40
- }
41
- const clientDir = Path.resolve(dir, 'client')
42
-
43
- const specPath = await getSpecPath(srcSpec, dir, log)
44
-
45
- const clientFile = await generateOpenApiModel(
46
- {
47
- name: apiName,
48
- input: specPath,
49
- outputDir: clientDir,
50
- isNode: env === 'node',
51
- responseWrapper,
52
- },
53
- log,
54
- )
55
-
56
- if (zodSchemas?.enabled === false)
57
- return
58
-
59
-
60
- log('Generating Zod schemas')
61
- generateSchemas(Path.resolve(dir, clientFile), Path.resolve(dir, './zod.ts'), zodSchemas)
62
- }
63
-
64
- const getSpecPath = async (urlOrPath: string, dir: string, log: (str: string) => void): Promise<string> => {
65
- if (!urlOrPath.startsWith('http')) {
66
- if (!fs.existsSync(urlOrPath))
67
- throw new Error(`Spec file ${urlOrPath} does not exists`)
68
- return urlOrPath
69
- }
70
- const specPath = Path.resolve(dir, `spec.json`)
71
-
72
- log(`Will download the API spec from ${urlOrPath} to ${specPath}`)
73
- await downloadSpec(specPath, urlOrPath)
74
-
75
- return specPath
76
- }
@@ -1,114 +0,0 @@
1
- import { generateApi } from 'swagger-typescript-api'
2
- import Path from 'path'
3
- import fs from 'fs/promises'
4
-
5
- export type GenerateOpenApiModelCmd = {
6
- name: string,
7
- input: string,
8
- outputDir: string,
9
- isNode?: boolean
10
- responseWrapper?: {
11
- symbol: string
12
- import?: string
13
- },
14
- }
15
-
16
- export const generateOpenApiModel = async ({ input, isNode, responseWrapper, name, outputDir }: GenerateOpenApiModelCmd,
17
- log: (msg: string) => void,
18
- ): Promise<string> => {
19
-
20
- log(`Will generate API client name=${name} to ${outputDir}, node=${isNode}`)
21
- const specialMapping = isNode
22
- ? {
23
- File: '{file: Buffer | stream.Readable, name: string}',
24
- }
25
- : {}
26
-
27
- const fileName = 'index'
28
- const dstFile = Path.join(outputDir, `${fileName}.ts`)
29
-
30
- await generateApi({
31
- name: 'index',
32
- output: outputDir,
33
- input: input,
34
- // modular: true,
35
- httpClientType: 'axios',
36
- templates: Path.resolve(getThisScriptDirname(), '../templates'),
37
- defaultResponseAsSuccess: true,
38
- // generateRouteTypes: true,
39
- singleHttpClient: true,
40
- // extractRequestBody: true,
41
- cleanOutput: true,
42
- moduleNameFirstTag: true,
43
- apiClassName: capitalize(name) + 'Api',
44
- // @ts-ignore
45
- codeGenConstructs: (struct) => ({
46
- // @ts-ignore
47
- Keyword: specialMapping,
48
- }),
49
- // extractRequestParams: true,
50
- })
51
-
52
- const addImports: string[] = []
53
- const replaces: [string, string][] = []
54
-
55
- if (isNode) {
56
- addImports.push('import stream from \'node:stream\'')
57
- }
58
-
59
-
60
- if (responseWrapper) {
61
- log(`Will use response wrapper '${JSON.stringify(responseWrapper)}'`)
62
- if (responseWrapper.import)
63
- addImports.push(responseWrapper.import)
64
-
65
- replaces.push(['Promise', responseWrapper.symbol])
66
- }
67
-
68
-
69
- // Remove unnecessary generics
70
- replaces.push(['<SecurityDataType extends unknown>', ''])
71
- replaces.push(['<SecurityDataType>', ''])
72
-
73
-
74
- log(`Will modify the outputs ${JSON.stringify({
75
- addImports,
76
- replaces,
77
- })}`)
78
- await modifyOutput(dstFile, {
79
- addImports,
80
- replaces,
81
- })
82
-
83
- return dstFile
84
- }
85
-
86
- const modifyOutput = async (path: string, cmd: {
87
- addImports: string[]
88
- replaces: [string, string][]
89
- }) => {
90
-
91
-
92
- let content = await fs.readFile(path).then((r) => r.toString())
93
-
94
- if (cmd.addImports.length) {
95
- content = cmd.addImports.join('\n') + '\n' + content
96
- }
97
-
98
- cmd.replaces.forEach(([from, to]) => {
99
- content = content.replaceAll(from, to)
100
- })
101
-
102
-
103
- await fs.writeFile(path, content)
104
- }
105
-
106
- const getThisScriptDirname = (): string => {
107
- // Might be problem in ESM mode
108
- return __dirname
109
- }
110
-
111
-
112
- const capitalize = (str: string): string => {
113
- return str[0].toUpperCase() + str.substring(1)
114
- }
@@ -1,40 +0,0 @@
1
- import fs from 'fs'
2
- import { generate } from 'ts-to-zod'
3
- import Path from 'path'
4
-
5
- // TODO needed?
6
- const removeGenericTypes = (code: string): string => {
7
- const regex = /export (interface|enum|type) [^<]* \{\n(.*\n)*?}/mg
8
- const matches = code.matchAll(regex)
9
- const types = Array.from(matches).map(m => m[0])
10
-
11
- return types.join('\n')
12
- }
13
-
14
- export type GenerateSchemasOptions = {
15
- localDateTimes?: boolean
16
- }
17
-
18
- export const generateSchemas = (inputFile: string, outputFile: string, opts: GenerateSchemasOptions = {}) => {
19
- const code = fs.readFileSync(inputFile).toString()
20
-
21
- const { getZodSchemasFile } = generate({
22
- sourceText: removeGenericTypes(code),
23
- customJSDocFormatTypes: {
24
- // Custom mapping
25
- // 'date-time': 'blablaj' - regex
26
- },
27
- })
28
-
29
- const fileName = Path.basename(inputFile)
30
-
31
- let f = getZodSchemasFile(`./${fileName.replace('.ts', '')}`)
32
-
33
- // Backend sends nulls not undefined - should be properly set in the OpenAPI TS types generation!
34
- f = f.replaceAll('.optional()', '.nullable()')
35
- if (opts.localDateTimes) {
36
- f = f.replaceAll('z.string().datetime()', 'z.string().datetime({local: true})')
37
- }
38
- fs.writeFileSync(outputFile, f)
39
-
40
- }
package/src/go.ts DELETED
@@ -1,23 +0,0 @@
1
- #!/bin/env node
2
- import { generateApiClient } from './generateApiClient'
3
- import { cosmiconfigSync } from 'cosmiconfig'
4
-
5
- const profile = process.argv[2]
6
-
7
- if (!profile)
8
- throw new Error(`No profile specified`)
9
-
10
- const conf = cosmiconfigSync('api-client-gen')
11
- .search()
12
-
13
- // TODO validate config
14
- if (!conf)
15
- throw new Error(`No config provided`)
16
-
17
-
18
- const profileConf = conf.config[profile]
19
-
20
- if (!profile)
21
- throw new Error(`Profile ${profile} not present in the configuration`)
22
-
23
- generateApiClient(profileConf).catch(console.error)
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export { generateApiClient } from "./generateApiClient";
2
-
3
-
package/test/go.spec.ts DELETED
@@ -1,16 +0,0 @@
1
- import { generateApiClient } from '../src'
2
- import * as Path from 'path'
3
- import { test } from 'vitest'
4
-
5
-
6
- test('generate', async () => {
7
- await generateApiClient({
8
- srcSpec: Path.resolve(__dirname, 'schema.json'),
9
- dstDir: Path.resolve(__dirname, 'out'),
10
- env: 'browser',
11
- apiName: 'test',
12
- zodSchemas: {
13
- localDateTimes: true,
14
- },
15
- })
16
- })
package/test/schema.json DELETED
@@ -1,118 +0,0 @@
1
- {
2
- "openapi": "3.0.0",
3
- "info": {
4
- "title": "Simple API",
5
- "description": "A basic API example",
6
- "version": "1.0.0"
7
- },
8
- "servers": [
9
- {
10
- "url": "https://api.example.com/v1",
11
- "description": "Main production server"
12
- }
13
- ],
14
- "paths": {
15
- "/users": {
16
- "get": {
17
- "summary": "Get list of users",
18
- "responses": {
19
- "200": {
20
- "description": "Successful response",
21
- "content": {
22
- "application/json": {
23
- "schema": {
24
- "type": "array",
25
- "items": {
26
- "$ref": "#/components/schemas/User"
27
- }
28
- }
29
- }
30
- }
31
- }
32
- }
33
- },
34
- "post": {
35
- "summary": "Create a new user",
36
- "requestBody": {
37
- "required": true,
38
- "content": {
39
- "application/json": {
40
- "schema": {
41
- "$ref": "#/components/schemas/User"
42
- }
43
- }
44
- }
45
- },
46
- "responses": {
47
- "201": {
48
- "description": "User created successfully",
49
- "content": {
50
- "application/json": {
51
- "schema": {
52
- "$ref": "#/components/schemas/User"
53
- }
54
- }
55
- }
56
- }
57
- }
58
- }
59
- },
60
- "/users/{id}": {
61
- "get": {
62
- "summary": "Get user by ID",
63
- "parameters": [
64
- {
65
- "name": "id",
66
- "in": "path",
67
- "required": true,
68
- "schema": {
69
- "type": "string"
70
- }
71
- }
72
- ],
73
- "responses": {
74
- "200": {
75
- "description": "Successful response",
76
- "content": {
77
- "application/json": {
78
- "schema": {
79
- "$ref": "#/components/schemas/User"
80
- }
81
- }
82
- }
83
- }
84
- }
85
- }
86
- }
87
- },
88
- "components": {
89
- "schemas": {
90
- "User": {
91
- "type": "object",
92
- "required": [
93
- "id",
94
- "name"
95
- ],
96
- "properties": {
97
- "id": {
98
- "type": "string",
99
- "example": "123"
100
- },
101
- "name": {
102
- "type": "string",
103
- "example": "John Doe"
104
- },
105
- "email": {
106
- "type": "string",
107
- "format": "email",
108
- "example": "john@example.com"
109
- },
110
- "createdAt": {
111
- "type": "string",
112
- "format": "date-time"
113
- }
114
- }
115
- }
116
- }
117
- }
118
- }