Skip to content

Commit

Permalink
chore: increase test coverage, fix build
Browse files Browse the repository at this point in the history
  • Loading branch information
MarshallOfSound committed Dec 1, 2019
1 parent 77e13d0 commit b1d3cf6
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
dist
*api.json
tsconfig.tsbuildinfo
coverage
6 changes: 3 additions & 3 deletions src/DocsParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
export class DocsParser {
constructor(
private baseElectronDir: string,
private electronVersion: string,
private moduleVersion: string,
private apiFiles: string[],
private structureFiles: string[],
) {}
Expand Down Expand Up @@ -105,8 +105,8 @@ export class DocsParser {
description,
slug: path.basename(filePath, '.md'),
websiteUrl: `${WEBSITE_BASE_DOCS_URL}/${relativeDocsPath}`,
repoUrl: `${REPO_BASE_DOCS_URL(this.electronVersion)}/${relativeDocsPath}.md`,
version: this.electronVersion,
repoUrl: `${REPO_BASE_DOCS_URL(this.moduleVersion)}/${relativeDocsPath}.md`,
version: this.moduleVersion,
},
});
}
Expand Down
145 changes: 142 additions & 3 deletions src/__tests__/markdown-helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@ import {
extractStringEnum,
rawTypeToTypeInformation,
parseHeadingTags,
findNextList,
getTopLevelGenericType,
findFirstHeading,
consumeTypedKeysList,
} from '../markdown-helpers';
import { DocumentationTag } from '../ParsedDocumentation';

const getTokens = (md: string) => {
const markdown = new MarkdownIt();
return markdown.parse(md, {});
};

describe('markdown-helpers', () => {
describe('parseHeadingTags', () => {
it('should return an empty array for null input', () => {
Expand Down Expand Up @@ -50,10 +59,8 @@ describe('markdown-helpers', () => {
if (!markdownFixture.endsWith('.md')) continue;

it(`should be correct for ${path.basename(markdownFixture, '.md')}`, () => {
const markdown = new MarkdownIt();
const tokens = markdown.parse(
const tokens = getTokens(
fs.readFileSync(path.resolve(fixtureDir, markdownFixture), 'utf8'),
{},
);
expect(safelyJoinTokens(tokens)).toMatchSnapshot();
});
Expand Down Expand Up @@ -248,4 +255,136 @@ describe('markdown-helpers', () => {
).toMatchSnapshot();
});
});

describe('findNextList()', () => {
it('should return null when no list is present in the tokens', () => {
expect(findNextList(getTokens('ABC `123`'))).toEqual(null);
});

it('should return null when the end of the list is not present in the tokens', () => {
const tokens = getTokens(' * 123');
expect(findNextList(tokens.slice(0, tokens.length - 2))).toEqual(null);
});

it('should return the entire list when their is a list present in the blocks', () => {
const list = findNextList(
getTokens(`
what up
* 123
* 456
hey lol
`),
);
expect(list).not.toEqual(null);
expect(safelyJoinTokens(list!)).toMatchInlineSnapshot(`
"* 123
* 456"
`);
});

it('should return the entire list when their is a list present in the blocks with sublists', () => {
const list = findNextList(
getTokens(`
what up
* 123
* deeper
* and
* again
* 456
hey lol
`),
);
expect(list).not.toEqual(null);
expect(safelyJoinTokens(list!)).toMatchInlineSnapshot(`
"* 123
* deeper
* and
* again
* 456"
`);
});
});

describe('findFirstHeading()', () => {
it('should throw if there is no heading', () => {
expect(() => findFirstHeading(getTokens('`abc`'))).toThrowErrorMatchingInlineSnapshot(
`"expected to find a heading token but couldn't: expected -1 to not equal -1"`,
);
});

it('should throw if the heading is does not end', () => {
const tokens = getTokens('# qqq');
expect(() =>
findFirstHeading(tokens.slice(0, tokens.length - 2)),
).toThrowErrorMatchingInlineSnapshot(
`"expected [ Array(1) ] to have a length at least 2 but got 1"`,
);
});

it('should return the heading string token for the first heading', () => {
expect(
safelyJoinTokens([
findFirstHeading(
getTokens(`
hey there
# abc
# def
foo`),
),
]),
).toMatchInlineSnapshot(`"abc"`);
});
});

describe('getTopLevelGenericType()', () => {
it('should return null if there is no generic in the type', () => {
expect(getTopLevelGenericType('Foo')).toEqual(null);
});

it('should return null if something ends like a generic but does not start like one', () => {
expect(getTopLevelGenericType('Foo>')).toEqual(null);
});

it('should extract the generic correctly', () => {
expect(getTopLevelGenericType('Foo<T>')).toStrictEqual({
genericType: 'T',
outerType: 'Foo',
});
});

it('should extract the generic correctly when the generic is itself generic', () => {
expect(getTopLevelGenericType('Foo<T<B>>')).toStrictEqual({
genericType: 'T<B>',
outerType: 'Foo',
});
});
});

describe('consumeTypedKeysList()', () => {
it('should return the keys property if the list is unconsumed', () => {
const list = {
consumed: false,
keys: [],
};
expect(consumeTypedKeysList(list)).toStrictEqual(list.keys);
});

it('should throw an error if the list has already been consumed', () => {
const list = {
consumed: false,
keys: [],
};
consumeTypedKeysList(list);
expect(() => consumeTypedKeysList(list)).toThrowErrorMatchingInlineSnapshot(
`"Attempted to consume a typed keys list that has already been consumed"`,
);
});
});
});
4 changes: 3 additions & 1 deletion src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ if (!fs.pathExistsSync(packageJsonPath)) {
process.exit(1);
}

const pj = require(packageJsonPath);

const resolvedOutDir =
typeof outDir === 'string'
? path.isAbsolute(outDir)
Expand All @@ -55,7 +57,7 @@ const start = Date.now();
fs.mkdirp(resolvedOutDir).then(() =>
parseDocs({
baseDirectory: resolvedDir,
electronVersion: pj.version,
moduleVersion: pj.version,
})
.then(data =>
fs.writeJson(path.resolve(resolvedOutDir, './electron-api.json'), data, {
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { DocsParser } from './DocsParser';

type ParseOptions = {
baseDirectory: string;
electronVersion: string;
moduleVersion: string;
};

export async function parseDocs(options: ParseOptions) {
const electronDocsPath = path.resolve(options.baseDirectory, 'docs', 'api');

const parser = new DocsParser(
options.baseDirectory,
options.electronVersion,
options.moduleVersion,
await getAllMarkdownFiles(electronDocsPath),
await getAllMarkdownFiles(path.resolve(electronDocsPath, 'structures')),
);
Expand Down
15 changes: 15 additions & 0 deletions src/markdown-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const findNextList = (tokens: Token[]) => {
export const findFirstHeading = (tokens: Token[]) => {
const open = tokens.findIndex(token => token.type === 'heading_open');
expect(open).to.not.equal(-1, "expected to find a heading token but couldn't");
expect(tokens).to.have.lengthOf.at.least(open + 2);
expect(tokens[open + 2].type).to.equal('heading_close');
return tokens[open + 1];
};
Expand Down Expand Up @@ -190,6 +191,20 @@ export const getTopLevelOrderedTypes = (typeString: string) => {
return safelySeparateTypeStringOn(typeString, ',');
};

/**
* @param typeString A type as a raw string
*
* @returns Either null or the isolated outer/generic types
*
* This method is used to extract the highest level generic from a type string.
* Examples:
*
* - `Foo` --> `null`
* - `Foo<T>` --> `{Foo, T}`
* - `Foo<T<B, C>>` --> `{Foo, T<B, C>}`
*
* The caller is responsible for recursively parsing the generic
*/
export const getTopLevelGenericType = (typeString: string) => {
if (
typeString[typeString.length - 1] !== '>' &&
Expand Down

0 comments on commit b1d3cf6

Please sign in to comment.