Skip to content

Commit

Permalink
Merge pull request #505 from kubb-project/feat/inputData
Browse files Browse the repository at this point in the history
feat: `input.data` for oasParser
  • Loading branch information
stijnvanhulle authored Oct 18, 2023
2 parents f2faef5 + f82ab73 commit abab7bf
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 30 deletions.
25 changes: 25 additions & 0 deletions docs/configuration/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export default defineConfig({
:::

## input
You can use `input.path` or `input.data` depending on the needs you have.

### path
Path to be used as the input. Can be an absolute path, or a path relative from the defined root option.

Expand All @@ -55,6 +57,29 @@ export default defineConfig({
})
```

### data
String or object containing the data that you would normally import.

Type: `string | unknown` <br/>
Required: `true`

::: code-group

```typescript [kubb.config.js]
import { defineConfig } from '@kubb/core'

import petStore from "./petStore.yaml"

export default defineConfig({
input: {
data: petStore,
},
output: {
path: './src/gen',
}
})
```

:::

## output
Expand Down
12 changes: 7 additions & 5 deletions packages/cli/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,20 @@ export default async function generate({ input, config, CLIOptions, logger }: Ge
try {
const { root: _root, ...userConfig } = config
const logLevel = CLIOptions.logLevel ?? LogLevel.silent
const inputPath = input ?? userConfig.input.path
const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)

spinner.start(`🚀 Building ${logLevel !== 'silent' ? pc.dim(inputPath) : ''}`)

const output = await build({
config: {
root: process.cwd(),
...userConfig,
input: {
...userConfig.input,
path: inputPath,
},
input: inputPath
? {
...userConfig.input,
path: inputPath,
}
: userConfig.input,
output: {
write: true,
...userConfig.output,
Expand Down
6 changes: 2 additions & 4 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,16 @@ async function generateAction(input: string, CLIOptions: CLIOptions) {
const result = await getCosmiConfig(moduleName, CLIOptions.config)
spinner.succeed(`💾 Config loaded(${pc.dim(pathParser.relative(process.cwd(), result.filepath))})`)

if (CLIOptions.watch) {
const config = await getConfig(result, CLIOptions)
const config = await getConfig(result, CLIOptions)

if (CLIOptions.watch && 'path' in config.input) {
return startWatcher([input || config.input.path], async (paths) => {
await generate({ config, CLIOptions, logger })
spinner.spinner = 'simpleDotsScrolling'
spinner.start(pc.yellow(pc.bold(`Watching for changes in ${paths.join(' and ')}`)))
})
}

const config = await getConfig(result, CLIOptions)

await generate({ input, config, CLIOptions, logger })
}

Expand Down
16 changes: 9 additions & 7 deletions packages/core/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@ export async function build(options: BuildOptions): Promise<BuildOutput> {
const { config, logLevel, logger = createLogger() } = options

try {
if (!URLPath.isURL(config.input.path)) {
if ('path' in config.input && !URLPath.isURL(config.input.path)) {
await read(config.input.path)
}
} catch (e) {
throw new Error(
'Cannot read file/URL defined in `input.path` or set with `kubb generate PATH` in the CLI of your Kubb config ' + pc.dim(config.input.path),
{
cause: e,
},
)
if ('path' in config.input) {
throw new Error(
'Cannot read file/URL defined in `input.path` or set with `kubb generate PATH` in the CLI of your Kubb config ' + pc.dim(config.input.path),
{
cause: e,
},
)
}
}

if (config.output.clean) {
Expand Down
21 changes: 14 additions & 7 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,20 @@ export type KubbConfig = {
* @default process.cwd()
*/
root: string
input: {
/**
* Path to be used as the input. Can be an absolute path, or a path relative from
* the defined root option.
*/
path: string
}
input:
| {
/**
* Path to be used as the input. Can be an absolute path, or a path relative from
* the defined root option.
*/
path: string
}
| {
/**
* String or object containing the data that you would normally import.
*/
data: string | unknown
}
output: {
/**
* Path to be used to export all generated files. Can be an absolute path, or a path relative based of the defined root option.
Expand Down
2 changes: 2 additions & 0 deletions packages/swagger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@kubb/core": "workspace:*",
"@kubb/react": "workspace:*",
"change-case": "^4.1.2",
"js-yaml": "^4.1.0",
"oas": "23.0.0",
"oas-normalize": "^11.0.1",
"swagger2openapi": "^7.0.8"
Expand All @@ -61,6 +62,7 @@
"@kubb/eslint-config": "workspace:*",
"@kubb/ts-config": "workspace:*",
"@kubb/tsup-config": "workspace:*",
"@types/js-yaml": "^4.0.8",
"@types/react": "^18.2.28",
"@types/swagger2openapi": "^7.0.2",
"eslint": "^8.51.0",
Expand Down
97 changes: 96 additions & 1 deletion packages/swagger/src/parsers/oasParser.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,60 @@
import pathParser from 'node:path'

import { oasPathParser } from './oasParser.ts'
import yaml from 'js-yaml'

import { oasParser, oasPathParser } from './oasParser.ts'

import type { KubbConfig } from '@kubb/core'

describe('oasParser', () => {
const petStoreV3 = pathParser.resolve(__dirname, '../../mocks/petStore.yaml')
const petStoreV2 = pathParser.resolve(__dirname, '../../mocks/petStoreV2.json')

const yamlPetStoreString = `
openapi: '3.0.0'
info:
title: Swagger Petstore
version: 1.0.0
paths:
/users/{userId}:
get:
tags:
- Users
summary: Get public user details
operationId: getUser
parameters:
- $ref: "#/components/parameters/userId"
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: User details retrieved successfully
user:
type: object
properties:
userId:
type: string
example: 1234343434343
components:
parameters:
userId:
name: userId
in: path
description: Executes the action in the context of the specified user.
required: true
schema:
type: string
example: 1234343434343
`

const petStoreObject = yaml.load(yamlPetStoreString)

test('check if oas and title is defined based on a Swagger(v3) file', async () => {
const oas = await oasPathParser(petStoreV3)

Expand All @@ -19,4 +68,50 @@ describe('oasParser', () => {
expect(oas).toBeDefined()
expect(oas.api?.info.title).toBe('Swagger Petstore')
})

test('check if oas and title is defined based on a Swagger(v3) JSON import', async () => {
const data = await import(petStoreV2)

const oas = await oasParser({
input: {
data,
},
} as KubbConfig)

expect(oas).toBeDefined()
expect(oas.api?.info.title).toBe('Swagger Petstore')
})

test('check if oas and title is defined based on a Swagger(v3) JSON string', async () => {
const oas = await oasParser({
input: {
data: JSON.stringify(petStoreObject),
},
} as KubbConfig)

expect(oas).toBeDefined()
expect(oas.api?.info.title).toBe('Swagger Petstore')
})

test('check if oas and title is defined based on a Swagger(v3) JSON object', async () => {
const oas = await oasParser({
input: {
data: petStoreObject,
},
} as KubbConfig)

expect(oas).toBeDefined()
expect(oas.api?.info.title).toBe('Swagger Petstore')
})

test('check if oas and title is defined based on a Swagger(v3) YAML', async () => {
const oas = await oasParser({
input: {
data: yamlPetStoreString,
},
} as KubbConfig)

expect(oas).toBeDefined()
expect(oas.api?.info.title).toBe('Swagger Petstore')
})
})
29 changes: 23 additions & 6 deletions packages/swagger/src/parsers/oasParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import pathParser from 'node:path'
import { URLPath } from '@kubb/core'

import SwaggerParser from '@apidevtools/swagger-parser'
import yaml from 'js-yaml'
import Oas from 'oas'
import OASNormalize from 'oas-normalize'
import swagger2openapi from 'swagger2openapi'
Expand Down Expand Up @@ -31,7 +32,7 @@ function convertSwagger2ToOpenApi(document: OASDocument): Promise<OASDocument> {
})
}

export async function oasPathParser(pathOrApi: string, { validate }: OasOptions = {}): Promise<oas> {
export async function oasPathParser(pathOrApi: string | OASDocument, { validate }: OasOptions = {}): Promise<oas> {
if (validate) {
await new OASNormalize(pathOrApi, { enablePaths: true, colorizeErrors: true }).validate()
}
Expand All @@ -46,12 +47,28 @@ export async function oasPathParser(pathOrApi: string, { validate }: OasOptions
}

export async function oasParser(config: KubbConfig, options: OasOptions = {}): Promise<oas> {
let pathOrApi = ''
if ('data' in config.input) {
if (typeof config.input.data === 'object') {
const api: OASDocument = JSON.parse(JSON.stringify(config.input.data)) as OASDocument
return oasPathParser(api, options)
}

try {
const api: string = yaml.load(config.input.data as string) as string

return oasPathParser(api, options)
} catch (e) {
/* empty */
}

const api: OASDocument = JSON.parse(JSON.stringify(config.input.data)) as OASDocument

return oasPathParser(api, options)
}

if (URLPath.isURL(config.input.path)) {
pathOrApi = config.input.path
} else {
pathOrApi = pathParser.resolve(config.root, config.input.path)
return oasPathParser(config.input.path, options)
}

return oasPathParser(pathOrApi, options)
return oasPathParser(pathParser.resolve(config.root, config.input.path), options)
}
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 comment on commit abab7bf

@vercel
Copy link

@vercel vercel bot commented on abab7bf Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

kubb – ./

kubb-git-main-kubb.vercel.app
www.kubb.dev
kubb-kubb.vercel.app
kubb.dev

Please sign in to comment.