Skip to content

Commit

Permalink
fix: ensure that sub keys can only be consumed by a single type (the …
Browse files Browse the repository at this point in the history
…first one) (#10)

This ensures that types like Object | String don't both try to enumerate
the sub keys.
  • Loading branch information
MarshallOfSound authored Aug 1, 2019
1 parent 6fcb117 commit d4d62e1
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 47 deletions.
5 changes: 2 additions & 3 deletions src/DocsParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
findContentInsideHeader,
headingsAndContent,
findConstructorHeader,
consumeTypedKeysList,
} from './markdown-helpers';
import { WEBSITE_BASE_DOCS_URL, REPO_BASE_DOCS_URL } from './constants';
import { extendError } from './helpers';
Expand Down Expand Up @@ -245,12 +246,10 @@ export class DocsParser {

expect(list).to.not.equal(null, `Structure file ${filePath} has no property list`);

const typedKeys = convertListToTypedKeys(list!);

return {
type: 'Structure',
...baseInfos[0].container,
properties: typedKeys.map(typedKey => ({
properties: consumeTypedKeysList(convertListToTypedKeys(list!)).map(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
Expand Down
6 changes: 3 additions & 3 deletions src/block-parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
extractReturnType,
findContentAfterHeadingClose,
StripReturnTypeBehavior,
consumeTypedKeysList,
} from './markdown-helpers';
import {
MethodDocumentationBlock,
Expand Down Expand Up @@ -97,7 +98,7 @@ export const _headingToMethodBlock = (
null,
`Method ${heading.heading} has at least one parameter but no parameter type list`,
);
parameters = convertListToTypedKeys(list).map(typedKey => ({
parameters = consumeTypedKeysList(convertListToTypedKeys(list)).map(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
Expand Down Expand Up @@ -183,8 +184,7 @@ export const _headingToEventBlock = (heading: HeadingContent): EventDocumentatio
) {
const list = findNextList(heading.content);
if (list) {
const typedKeys = convertListToTypedKeys(list);
parameters = typedKeys.map(typedKey => ({
parameters = consumeTypedKeysList(convertListToTypedKeys(list)).map(typedKey => ({
name: typedKey.key,
description: typedKey.description,
...typedKey.type,
Expand Down
113 changes: 72 additions & 41 deletions src/markdown-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export const getTopLevelGenericType = (typeString: string) => {
export const rawTypeToTypeInformation = (
rawType: string,
relatedDescription: string,
subTypedKeys: TypedKey[] | null,
subTypedKeys: TypedKeyList | null,
): TypeInformation => {
// Handle the edge case of "null"
if (rawType === 'null' || rawType === '`null`') {
Expand Down Expand Up @@ -254,42 +254,45 @@ export const rawTypeToTypeInformation = (
return {
collection,
type: 'Function',
parameters: subTypedKeys
? subTypedKeys.map<MethodParameterDocumentation>(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
...typedKey.type,
}))
: [],
parameters:
subTypedKeys && !subTypedKeys.consumed
? consumeTypedKeysList(subTypedKeys).map<MethodParameterDocumentation>(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
...typedKey.type,
}))
: [],
returns: null,
};
} else if (typeString === 'Object') {
return {
collection,
type: 'Object',
properties: subTypedKeys
? subTypedKeys.map<PropertyDocumentationBlock>(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
additionalTags: typedKey.additionalTags,
...typedKey.type,
}))
: [],
properties:
subTypedKeys && !subTypedKeys.consumed
? consumeTypedKeysList(subTypedKeys).map<PropertyDocumentationBlock>(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
additionalTags: typedKey.additionalTags,
...typedKey.type,
}))
: [],
};
} else if (typeString === 'String') {
return {
collection,
type: 'String',
possibleValues: subTypedKeys
? subTypedKeys.map<PossibleStringValue>(typedKey => ({
value: typedKey.key,
description: typedKey.description,
}))
: relatedDescription
? extractStringEnum(relatedDescription)
: null,
possibleValues:
subTypedKeys && !subTypedKeys.consumed
? consumeTypedKeysList(subTypedKeys).map<PossibleStringValue>(typedKey => ({
value: typedKey.key,
description: typedKey.description,
}))
: relatedDescription
? extractStringEnum(relatedDescription)
: null,
};
}

Expand All @@ -303,15 +306,16 @@ export const rawTypeToTypeInformation = (
return {
...info,
type: 'Object',
properties: subTypedKeys
? subTypedKeys.map<PropertyDocumentationBlock>(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
additionalTags: typedKey.additionalTags,
...typedKey.type,
}))
: [],
properties:
subTypedKeys && !subTypedKeys.consumed
? consumeTypedKeysList(subTypedKeys).map<PropertyDocumentationBlock>(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
additionalTags: typedKey.additionalTags,
...typedKey.type,
}))
: [],
};
}
return info;
Expand All @@ -328,8 +332,8 @@ export const rawTypeToTypeInformation = (
parameters:
// If no param types are provided in the <A, B, C> syntax then we should fallback to the normal one
genericProvidedParams.length === 0
? subTypedKeys
? subTypedKeys.map<MethodParameterDocumentation>(typedKey => ({
? subTypedKeys && !subTypedKeys.consumed
? consumeTypedKeysList(subTypedKeys).map<MethodParameterDocumentation>(typedKey => ({
name: typedKey.key,
description: typedKey.description,
required: typedKey.required,
Expand Down Expand Up @@ -428,7 +432,7 @@ export const extractReturnType = (
}

const list = findNextList(tokens);
let typedKeys: null | TypedKey[] = null;
let typedKeys: null | TypedKeyList = null;
if (list) {
try {
typedKeys = convertListToTypedKeys(tokens);
Expand Down Expand Up @@ -555,6 +559,11 @@ type TypedKey = {
additionalTags: DocumentationTag[];
};

type TypedKeyList = {
keys: TypedKey[];
consumed: boolean;
};

type List = { items: ListItem[] };
type ListItem = { tokens: Token[]; nestedList: List | null };

Expand Down Expand Up @@ -592,6 +601,24 @@ const getNestedList = (rawTokens: Token[]): List => {
return rootList;
};

const unconsumedTypedKeyList = <T extends TypedKey[] | null>(
keys: T,
): T extends null ? null : TypedKeyList => {
return keys
? {
consumed: false,
keys,
}
: (null as any);
};

export const consumeTypedKeysList = (list: TypedKeyList) => {
if (list.consumed)
throw new Error('Attempted to consume a typed keys list that has already been consumed');
list.consumed = true;
return list.keys;
};

const convertNestedListToTypedKeys = (list: List): TypedKey[] => {
const keys: TypedKey[] = [];

Expand Down Expand Up @@ -651,7 +678,11 @@ const convertNestedListToTypedKeys = (list: List): TypedKey[] => {
const tagMatch = tagMatcher.exec(rawType);
const cleanedType = rawType.replace(/ ?\(optional\) ?/i, '').replace(/_.+?_/g, '');
const subTypedKeys = item.nestedList ? convertNestedListToTypedKeys(item.nestedList) : null;
const type = rawTypeToTypeInformation(cleanedType.trim(), rawDescription, subTypedKeys);
const type = rawTypeToTypeInformation(
cleanedType.trim(),
rawDescription,
unconsumedTypedKeyList(subTypedKeys),
);

keys.push({
type,
Expand All @@ -665,8 +696,8 @@ const convertNestedListToTypedKeys = (list: List): TypedKey[] => {
return keys;
};

export const convertListToTypedKeys = (listTokens: Token[]): TypedKey[] => {
export const convertListToTypedKeys = (listTokens: Token[]): TypedKeyList => {
const list = getNestedList(listTokens);

return convertNestedListToTypedKeys(list);
return unconsumedTypedKeyList(convertNestedListToTypedKeys(list));
};

0 comments on commit d4d62e1

Please sign in to comment.