Skip to content

Commit

Permalink
feat(KeyValue): enable labeled KeyValue results
Browse files Browse the repository at this point in the history
  • Loading branch information
simonseyock committed Oct 15, 2021
1 parent d9b9da6 commit c73b0ed
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 8 deletions.
17 changes: 13 additions & 4 deletions src/parslets/TupleParslet.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { assertTerminal } from '../assertTypes'
import { assertPlainKeyValue, assertTerminal } from '../assertTypes'
import { TokenType } from '../lexer/Token'
import { Parser } from '../Parser'
import { PrefixParslet } from './Parslet'
import { Precedence } from '../Precedence'
import { TupleResult } from '../result/TerminalResult'
import { IntermediateResult } from '../result/IntermediateResult'

interface TupleParsletOptions {
allowQuestionMark: boolean
Expand Down Expand Up @@ -37,16 +38,24 @@ export class TupleParslet implements PrefixParslet {

const typeList = parser.parseIntermediateType(Precedence.ALL)
if (typeList.type === 'JsdocTypeParameterList') {
result.elements = typeList.elements.map(assertTerminal)
if (typeList.elements[0].type === 'JsdocTypeKeyValue') {
result.elements = typeList.elements.map(assertPlainKeyValue)
} else {
result.elements = typeList.elements.map(assertTerminal)
}
} else {
result.elements = [assertTerminal(typeList)]
if (typeList.type === 'JsdocTypeKeyValue') {
result.elements = [assertPlainKeyValue(typeList)]
} else {
result.elements = [assertTerminal(typeList)]
}
}

if (!parser.consume(']')) {
throw new Error('Unterminated \'[\'')
}

if (!this.allowQuestionMark && result.elements.some(e => e.type === 'JsdocTypeUnknown')) {
if (!this.allowQuestionMark && result.elements.some((e: IntermediateResult) => e.type === 'JsdocTypeUnknown')) {
throw new Error('Question mark in tuple not allowed')
}

Expand Down
2 changes: 1 addition & 1 deletion src/result/TerminalResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export interface ImportResult {
*/
export interface TupleResult {
type: 'JsdocTypeTuple'
elements: TerminalResult[]
elements: TerminalResult[]|KeyValueResult[]
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/transforms/identityTransformRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export function identityTransformRules (): TransformRules<NonTerminalResult> {

JsdocTypeTuple: (result, transform) => ({
type: 'JsdocTypeTuple',
elements: result.elements.map(transform) as TerminalResult[]
elements: (result.elements as NonTerminalResult[]).map(transform) as TerminalResult[]|KeyValueResult[]
}),

JsdocTypeName: result => result,
Expand Down
2 changes: 1 addition & 1 deletion src/transforms/jtpTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ const jtpRules: TransformRules<JtpResult> = {

JsdocTypeTuple: (result, transform) => ({
type: 'TUPLE',
entries: result.elements.map(transform)
entries: (result.elements as NonTerminalResult[]).map(transform)
}),

JsdocTypeKeyof: (result, transform) => ({
Expand Down
2 changes: 1 addition & 1 deletion src/transforms/stringify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function stringifyRules (): TransformRules<string> {

JsdocTypeName: result => result.value,

JsdocTypeTuple: (result, transform) => `[${result.elements.map(transform).join(', ')}]`,
JsdocTypeTuple: (result, transform) => `[${(result.elements as NonTerminalResult[]).map(transform).join(', ')}]`,

JsdocTypeVariadic: (result, transform) => result.meta.position === undefined
? '...'
Expand Down
73 changes: 73 additions & 0 deletions test/fixtures/typescript/tuple.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,4 +594,77 @@ describe('typescript tuple tests', () => {
}
})
})

describe('labeled tuple with one element', () => {
testFixture({
input: '[a: string]',
modes: ['typescript'],
expected: {
type: 'JsdocTypeTuple',
elements: [
{
type: 'JsdocTypeKeyValue',
key: 'a',
optional: false,
readonly: false,
meta: {
quote: undefined,
hasLeftSideExpression: false
},
right: {
type: 'JsdocTypeName',
value: 'string'
}
}
]
}
})
})

describe('labeled tuple with two elements', () => {
testFixture({
input: '[a: string, b: number]',
modes: ['typescript'],
expected: {
type: 'JsdocTypeTuple',
elements: [
{
type: 'JsdocTypeKeyValue',
key: 'a',
optional: false,
readonly: false,
meta: {
quote: undefined,
hasLeftSideExpression: false
},
right: {
type: 'JsdocTypeName',
value: 'string'
}
},
{
type: 'JsdocTypeKeyValue',
key: 'b',
optional: false,
readonly: false,
meta: {
quote: undefined,
hasLeftSideExpression: false
},
right: {
type: 'JsdocTypeName',
value: 'number'
}
}
]
}
})
})

describe('mixed labeled tuples', () => {
testFixture({
input: '[a: string, b]',
modes: []
})
})
})
81 changes: 81 additions & 0 deletions test/traverse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,85 @@ describe('traverse', () => {
[onLeave, [union, undefined, undefined]]
])
})

it('should traverse a nested expression with function and tuple', () => {
const onEnter = spy()
const onLeave = spy()

const nameA: NameResult = {
type: 'JsdocTypeName',
value: 'number'
}

const nameB: NameResult = {
type: 'JsdocTypeName',
value: 'string'
}

const keyValueA: KeyValueResult = {
type: 'JsdocTypeKeyValue',
key: 'a',
right: nameA,
optional: false,
readonly: false,
meta: {
quote: undefined,
hasLeftSideExpression: false
}
}

const keyValueB: KeyValueResult = {
type: 'JsdocTypeKeyValue',
key: 'b',
right: nameB,
optional: false,
readonly: false,
meta: {
quote: undefined,
hasLeftSideExpression: false
}
}

const tuple: TupleResult = {
type: 'JsdocTypeTuple',
elements: [
keyValueA,
keyValueB
]
}

const parameter: NameResult = {
type: 'JsdocTypeName',
value: 'parameter'
}

const functionResult: FunctionResult = {
type: 'JsdocTypeFunction',
arrow: true,
parenthesis: true,
parameters: [
parameter
],
returnType: tuple
}

traverse(functionResult, onEnter, onLeave)

expectOrder([
[onEnter, [functionResult, undefined, undefined]],
[onEnter, [parameter, functionResult, 'parameters']],
[onLeave, [parameter, functionResult, 'parameters']],
[onEnter, [tuple, functionResult, 'returnType']],
[onEnter, [keyValueA, tuple, 'elements']],
[onEnter, [nameA, keyValueA, 'right']],
[onLeave, [nameA, keyValueA, 'right']],
[onLeave, [keyValueA, tuple, 'elements']],
[onEnter, [keyValueB, tuple, 'elements']],
[onEnter, [nameB, keyValueB, 'right']],
[onLeave, [nameB, keyValueB, 'right']],
[onLeave, [keyValueB, tuple, 'elements']],
[onLeave, [tuple, functionResult, 'returnType']],
[onLeave, [functionResult, undefined, undefined]]
])
})
})

0 comments on commit c73b0ed

Please sign in to comment.