Skip to content

Commit

Permalink
feat(Typescript factory functions): Only first required prop is unnamed
Browse files Browse the repository at this point in the history
This change attempts to balance the convienience of unnamed arguments, with the robustness of named arguments (aka keyword arguments in Python and other langs), particularly to changes in the number and order of required properties. It should mean that consumers of these factory functions do not need to change their code as often, when/if there are changes to type schemas.
  • Loading branch information
nokome authored and alex-ketch committed Jan 20, 2020
1 parent 44e2ed5 commit 02b3483
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 22 deletions.
6 changes: 3 additions & 3 deletions ts/bindings/__file_snapshots__/Person.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ export interface Person extends Thing {

/**
* Create a `Person` node
* @param options Optional properties
* @param other Other properties
* @returns {Person}
*/
export const person = (
options: OptionalProps<Person> = {}
props: OptionalProps<Person> = {}
): Person => ({
...(compact(options)),
...compact(props),
type: 'Person'
})

24 changes: 17 additions & 7 deletions ts/bindings/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,27 @@ export const typeGenerator = (schema: Schema): string => {
({ name, schema }) =>
`@param ${name} {${schemaToType(schema)}} ${schema.description}`
),
`@param options Optional properties`,
`@param other Other properties`,
`@returns {${title}}`
])
code += `export const ${funcName(title)} = (\n`
code += required
.map(({ name, schema }) => ` ${name}: ${schemaToType(schema)},\n`)
.join('')
code += ` options: OptionalProps<${title}> = {}\n`
const firstRequired = required[0]
if (firstRequired !== undefined)
code += ` ${firstRequired.name}: ${schemaToType(firstRequired.schema)},\n`
const propsType =
(required.length > 1
? '{' +
required
.slice(1)
.map(({ name, schema }) => `${name}: ${schemaToType(schema)}`)
.join('; ') +
'} &'
: '') + `OptionalProps<${title}>`
const propsDefault = required.length < 2 ? ' = {}' : ''
code += ` props: ${propsType}${propsDefault}\n`
code += `): ${title} => ({\n`
code += required.map(({ name }) => ` ${name},\n`).join('')
code += ` ...(compact(options)),\n`
if (firstRequired !== undefined) code += ` ${firstRequired.name},\n`
code += ` ...compact(props),\n`
code += ` type: '${title}'\n`
code += '})\n\n'

Expand Down
26 changes: 14 additions & 12 deletions ts/types.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { article, organization, person } from './types'
import { person, paragraph, link } from './types'

describe('Schema factory functions', () => {
test('it creates a valid Person node', () => {
test('no required properties', () => {
expect(person()).toMatchObject({ type: 'Person' })
})

test('it creates a valid Article node', () => {
test('one required property', () => {
expect(paragraph(['The content of the paragraph'])).toMatchObject({
type: 'Paragraph',
content: ['The content of the paragraph']
})
})

test('more than one required property', () => {
expect(
article([organization({ name: 'Stencila' })], 'Testing')
link(['The content of the link'], { target: 'https://example.org' })
).toMatchObject({
type: 'Article',
title: 'Testing',
authors: [
{
name: 'Stencila',
type: 'Organization'
}
]
type: 'Link',
content: ['The content of the link'],
target: 'https://example.org'
})
})

Expand Down

0 comments on commit 02b3483

Please sign in to comment.