nx/scripts/documentation/builders.ts
2019-04-16 13:10:49 -04:00

126 lines
3.9 KiB
TypeScript

import * as fs from 'fs-extra';
import * as path from 'path';
import { parseJsonSchemaToOptions } from '@angular/cli/utilities/json-schema';
import { dedent } from 'tslint/lib/utils';
import { Schematic } from '@angular-devkit/schematics/collection-schema';
import { CoreSchemaRegistry } from '@angular-devkit/core/src/json/schema';
import {
htmlSelectorFormat,
pathFormat
} from '@angular-devkit/schematics/src/formats';
import { sortAlphabeticallyFunction } from './utils';
/**
* @WhatItDoes: Generates default documentation from the builders' schema.
* We need to construct an Array of objects containing all the information
* of the builders and their associates schema info. It should be easily
* parsable in order to be used in a rendering process using template. This
* in order to generate a markdown file for each available schematic.
*/
interface DocConfig {
source: string;
output: string;
}
const buildersConfig = {
source: path.join(__dirname, '../../packages/builders/src'),
output: path.join(__dirname, '../../docs/api-builders')
};
const jestConfig = {
source: path.join(__dirname, '../../packages/jest'),
output: path.join(__dirname, '../../docs/api-jest/builders')
};
const docConfigs: DocConfig[] = [buildersConfig, jestConfig];
const registry = new CoreSchemaRegistry();
registry.addFormat(pathFormat);
registry.addFormat(htmlSelectorFormat);
function generateSchematicList(
config: DocConfig,
registry: CoreSchemaRegistry
): Promise<Schematic>[] {
const builderCollectionFile = path.join(config.source, 'builders.json');
fs.removeSync(config.output);
const builderCollection = fs.readJsonSync(builderCollectionFile).builders;
return Object.keys(builderCollection).map(builderName => {
const builder = {
name: builderName,
...builderCollection[builderName],
rawSchema: fs.readJsonSync(
path.join(config.source, builderCollection[builderName]['schema'])
)
};
return parseJsonSchemaToOptions(registry, builder.rawSchema)
.then(options => ({ ...builder, options }))
.catch(error =>
console.error(`Can't parse schema option of ${builder.name}:\n${error}`)
);
});
}
function generateTemplate(builder): { name: string; template: string } {
let template = dedent`
# ${builder.name}
${builder.description}
\n`;
if (Array.isArray(builder.options) && !!builder.options.length) {
template += '## Properties';
builder.options
.sort((a, b) => sortAlphabeticallyFunction(a.name, b.name))
.forEach(
option =>
(template += dedent`
### ${option.name} ${option.required ? '(*__required__*)' : ''} ${
option.hidden ? '(__hidden__)' : ''
}
${
!!option.aliases.length
? `Alias(es): ${option.aliases.join(',')}\n`
: ''
}
${
option.default === undefined || option.default === ''
? ''
: `Default: \`${option.default}\`\n`
}
Type: \`${option.type}\` \n
${option.description}
`)
);
}
return { name: builder.name, template };
}
function generateFile(
outputDirectory: string,
templateObject: { name: string; template: string }
): void {
fs.outputFileSync(
path.join(outputDirectory, `${templateObject.name}.md`),
templateObject.template
);
}
Promise.all(
docConfigs.map(config => {
Promise.all(generateSchematicList(config, registry))
.then(builderList => builderList.map(generateTemplate))
.then(markdownList =>
markdownList.forEach(template => generateFile(config.output, template))
)
.then(() =>
console.log(
`Generated documentation for ${config.source} to ${config.output}`
)
);
})
).then(() => {
console.log('Done generating Builders Documentation');
});