Skip to content

Commit

Permalink
fix bug where going to curl tab modifies form values
Browse files Browse the repository at this point in the history
  • Loading branch information
dphuang2 committed Oct 30, 2023
1 parent 399dc01 commit 593eed8
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 47 deletions.
2 changes: 2 additions & 0 deletions generator/konfig-next-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"axios": "^1.4.0",
"camelcase": "^8.0.0",
"chroma-js": "^2.4.2",
"clone": "^2.1.2",
"dayjs": "^1.11.8",
"deepmerge": "^4.3.1",
"eslint": "8.41.0",
Expand Down Expand Up @@ -79,6 +80,7 @@
},
"devDependencies": {
"@types/chroma-js": "^2.4.0",
"@types/clone": "^2.1.3",
"@types/har-format": "^1.2.14",
"@types/jest": "^29.5.5",
"@types/js-yaml": "^4.0.5",
Expand Down
2 changes: 1 addition & 1 deletion generator/konfig-next-app/src/components/CopyButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function CopyButton({ value }: { value: string }) {
{
['bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 shadow dark:shadow-none dark:hover:bg-white/5']:
!copied,
['dark:bg-brand-400/10 bg-brand-600/20 ring-1 ring-inset dark:ring-brand-400/20 ring-brand-600/40']:
['bg-brand-600/20 ring-1 ring-inset dark:ring-brand-400/20 ring-brand-600/40']:
copied,
}
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,41 @@ import { CopyButton } from './CopyButton'
export function OperationFormGeneratedCode(
args: CodeGeneratorConstructorArgs & { language: Language }
) {
const [data, setData] = useState('Loading...') // Initial state
const [data, setData] = useState('Loading...')
const [copyData, setCopyData] = useState('')

console.log(args.formData)

useEffect(() => {
if (args.language === 'typescript') {
new CodeGeneratorTypeScript(args).snippet().then((result) => {
setData(result)
})
new CodeGeneratorTypeScript({ ...args, mode: 'copy' })
.snippet()
.then((result) => {
setCopyData(result)
})
} else if (args.language === 'python') {
new CodeGeneratorPython(args).snippet().then((result) => {
setData(result)
})
new CodeGeneratorPython({ ...args, mode: 'copy' })
.snippet()
.then((result) => {
setCopyData(result)
})
} else if (args.language === 'bash') {
new CodeGeneratorHttpsnippet({ ...args, targetId: 'shell' })
.snippet()
.then((result) => {
setData(result)
})
new CodeGeneratorHttpsnippet({ ...args, targetId: 'shell', mode: 'copy' })
.snippet()
.then((result) => {
setCopyData(result)
})
} else {
throw Error(`Unxpected language: "${args.language}"`)
}
Expand All @@ -50,7 +68,7 @@ export function OperationFormGeneratedCode(
<Prism noCopy withLineNumbers {...styles} language={args.language}>
{data}
</Prism>
<CopyButton value="" />
<CopyButton value={copyData} />
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,6 @@ export function OperationReferenceMain({
}
}

const [language, setLanguage] = useState<Language>('typescript')

const header = operation.operation.summary ?? operation.path
return (
<FormProvider form={form}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ export class CodeGeneratorHttpsnippet extends CodeGenerator {
options: Options
constructor(args: CodeGeneratorHttpSnippetConstructorArgs) {
super(args)

const securities = this.isCopyMode()
? this.nonEmptySecurity()
: this.nonEmptySecurityMasked()
const harRequest = convertToHarRequest(
this.nonEmptyParameters,
this.mode === 'ui' ? this.nonEmptySecurityMasked : this.nonEmptySecurity,
this.requestBodyValue,
this.nonEmptyParameters(),
securities,
this.requestBodyValue(),
// can't use URL because we don't want to encode { and } in path yet
`${this.basePath}${this.configuration.path}`,
this.configuration.httpMethod.toUpperCase(),
Expand Down
10 changes: 5 additions & 5 deletions generator/konfig-next-app/src/utils/code-generator-python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ from ${this.packageName} import ${this.clientName}`

get setupArgs(): string {
const args = []
for (const [name, security] of this.nonEmptySecurity) {
for (const [name, security] of this.nonEmptySecurity()) {
if (security[SECURITY_TYPE_PROPERTY] === 'clientState') {
args.push(`${this.snake_case(name)}="${this.mask(security.value)}"`)
} else if (security[SECURITY_TYPE_PROPERTY] === 'apiKey') {
args.push(
`${
this.hasMultipleApiKeys
this.hasMultipleApiKeys()
? this.snake_case(security[API_KEY_NAME_PROPERTY])
: 'api_key'
}="${this.mask(security.value)}"`
Expand Down Expand Up @@ -118,9 +118,9 @@ from ${this.packageName} import ${this.clientName}`
}

get args(): string {
if (this.isArrayRequestBody) {
if (this.isArrayRequestBody()) {
const arrayValue = this.recursivelyRemoveEmptyValues(
this.requestBodyValue
this.requestBodyValue()
)
if (Array.isArray(arrayValue)) {
return `[${arrayValue
Expand All @@ -130,7 +130,7 @@ from ${this.packageName} import ${this.clientName}`
if (arrayValue === '') return ''
}
const args: string[] = []
for (const [parameter, value] of this.nonEmptyParameters) {
for (const [parameter, value] of this.nonEmptyParameters()) {
args.push(
`${this.snake_case(parameter.name)}=${this.toPythonLiteralString(
value,
Expand Down
42 changes: 18 additions & 24 deletions generator/konfig-next-app/src/utils/code-generator-typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ export class CodeGeneratorTypeScript extends CodeGenerator {
const ${this.clientNameLowercase} = new ${this.client}(${this.setupArgs})
${this.mode === 'ui' ? `const response =` : 'return'} await ${
${this.isUiOrCopyMode() ? `const response =` : 'return'} await ${
this.clientNameLowercase
}.${this.namespace}.${this.methodName}(${this.args})
${this.mode === 'ui' ? `console.log(response.data)` : ''}
${this.isUiOrCopyMode() ? `console.log(response.data)` : ''}
`
}

get importStatement(): string {
if (this.mode === 'ui') {
if (this.isUiOrCopyMode()) {
if (this.args.includes('fs.readFileSync'))
return `import { ${this.clientName} } from '${this.packageName}'\nimport fs from 'fs'`
return `import { ${this.clientName} } from '${this.packageName}'`
Expand All @@ -62,54 +62,48 @@ ${this.mode === 'ui' ? `console.log(response.data)` : ''}
}

get client(): string {
if (this.mode === 'ui') {
if (this.isUiOrCopyMode()) {
return `${this.clientName}`
}
return `client.${this.clientName}`
}

get setupArgs(): string {
return Object.keys(this.nonEmptySecurity).length === 0
return Object.keys(this.nonEmptySecurity()).length === 0
? `{${this.proxySetupArgs}}`
: `{
${this.nonEmptySecurity
${this.nonEmptySecurity()
.map(([_name, value]) => {
if (value.type === 'oauth2-client-credentials') {
// convert value.clientSecret to string of same length with all values replace with char 'X'
const clientSecret =
this.mode === 'execution'
? value.clientSecret
: value.clientSecret.replace(/./g, 'X')
: this.mask(value.clientSecret)
const clientId =
this.mode === 'execution'
? value.clientId
: value.clientId.replace(/./g, 'X')
this.mode === 'execution' ? value.clientId : this.mask(value.clientId)
return ` "oauthClientId": "${clientId}",
"oauthClientSecret": "${clientSecret}",`
}
if (value.type === 'bearer') {
// convert value.value to string of same length with all values replace with char 'X'
const bearer =
this.mode === 'execution' ? value.value : value.value.replace(/./g, 'X')
this.mode === 'execution' ? value.value : this.mask(value.value)
return ` "accessToken": "${bearer}",`
}
const securityValue = value.type === 'apiKey' ? value.value : value.value
const securityKey = this.quoteIfNecessary(
value.type === 'apiKey'
? this.hasMultipleApiKeys
? this.hasMultipleApiKeys()
? value.key
: 'apiKey'
: value.name
)
// convert securityValue to string of same length with all values replace with char 'X'
const securityValueMasked =
this.mode === 'execution'
? securityValue
: securityValue.replace(/./g, 'X')
this.mode === 'execution' ? securityValue : this.mask(securityValue)
return ` ${securityKey}: '${securityValueMasked}',`
})
.join('\n')}${
this.oauthTokenUrl !== null && this.isUsingCustomOAuthTokenUrl
this.oauthTokenUrl !== null && this.isUsingCustomOAuthTokenUrl()
? `oauthTokenUrl: "${this.oauthTokenUrl}",`
: ''
}
Expand All @@ -128,8 +122,8 @@ ${this.nonEmptySecurity
}

get proxySetupArgs(): string {
return this.mode === 'ui'
? this.isUsingCustomBasePath
return this.isUiOrCopyMode()
? this.isUsingCustomBasePath()
? `basePath: "${this.basePath}",`
: ''
: `basePath: "/api/proxy", baseOptions: {headers: {"x-proxy-target": "${this.basePath}"}}`
Expand Down Expand Up @@ -206,8 +200,8 @@ ${this.nonEmptySecurity
}

get args(): string {
if (this.isArrayRequestBody) {
const arrayValue = this.requestBodyValue
if (this.isArrayRequestBody()) {
const arrayValue = this.requestBodyValue()
if (Array.isArray(arrayValue)) {
return `[${arrayValue.map((v) => this.argValue(v)).join(', ')}]`
}
Expand All @@ -219,14 +213,14 @@ ${this.nonEmptySecurity
}
return ''
}
const nonBodyParameters = this.nonEmptyParameters
const nonBodyParameters = this.nonEmptyParameters()
.filter(([{ parameter }]) => {
return parameter.in !== 'body'
})
.map(([{ name }, value]) => {
return [name, value] as [string, SdkArg]
})
const bodyParameters = this.nonEmptyParameters
const bodyParameters = this.nonEmptyParameters()
.filter(([{ parameter }]) => {
return parameter.in === 'body'
})
Expand Down
75 changes: 75 additions & 0 deletions generator/konfig-next-app/src/utils/code-generator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { HttpMethodsEnum } from 'konfig-lib'
import { CodeGenerator, CodeGeneratorConstructorArgs } from './code-generator'
import { SECURITY_FORM_NAME_PREFIX } from './generate-initial-operation-form-values'
import clone from 'clone'

class CodeGeneratorTest extends CodeGenerator {
protected format(code: string): Promise<string> {
throw new Error(
'This class is only used for testing shared functions in CodeGenerator'
)
}
protected gen(): string {
throw new Error(
'This class is only used for testing shared functions in CodeGenerator'
)
}
}

/**
* Creates new instance of CodeGeneratorTest with values used for testing
*/
function testArgs(): CodeGeneratorConstructorArgs {
return {
path: '',
contentType: 'application/json',
httpMethod: HttpMethodsEnum.POST,
securitySchemes: {
apiKey: {
type: 'apiKey',
in: 'header',
name: 'X-Api-Key',
},
},
formData: {
requestBody: '',
parameters: {},
security: {
apiKey: {
type: 'apiKey',
in: 'header',
key: 'X-API-Key',
value: 'my_api_key',
},
},
},
parameters: [],
languageConfigurations: {
typescript: {
clientName: 'Test',
packageName: 'test',
},
python: {
clientName: 'Test',
packageName: 'tet',
},
},
tag: 'Test',
operationId: 'Test_test',
requestBody: null,
basePath: 'https://test.com/api',
requestBodyRequired: true,
servers: ['https://test.com/api'],
oauthTokenUrl: null,
originalOauthTokenUrl: null,
}
}

test('ensure nonEmptySecurityMasked does not modify security values in-place', async () => {
const args: CodeGeneratorConstructorArgs = testArgs()
const test = new CodeGeneratorTest(args)
const before = clone(test.configuration.formData[SECURITY_FORM_NAME_PREFIX])
test.nonEmptySecurityMasked()
const after = test.configuration.formData[SECURITY_FORM_NAME_PREFIX]
expect(before).toStrictEqual(after)
})
Loading

0 comments on commit 593eed8

Please sign in to comment.