Skip to content

Commit

Permalink
docs: use a processor to transform the operator decision tree data
Browse files Browse the repository at this point in the history
  • Loading branch information
tmair committed Nov 27, 2023
1 parent 04a6a69 commit 0543d3e
Show file tree
Hide file tree
Showing 29 changed files with 111 additions and 154 deletions.
File renamed without changes.
5 changes: 2 additions & 3 deletions apps/rxjs.dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@
"test-pwa-score": "node scripts/test-pwa-score",
"deploy-production": "scripts/deploy-to-firebase.sh",
"payload-size": "scripts/payload.sh",
"docs": "npx ts-node -P tsconfig.docs.json ../../node_modules/dgeni/lib/gen-docs.js ./tools/transforms/angular.io-package && yarn docs-decision-tree",
"docs": "npx ts-node -P tsconfig.docs.json ../../node_modules/dgeni/lib/gen-docs.js ./tools/transforms/angular.io-package",
"docs-watch": "npx ts-node -P tsconfig.docs.json tools/transforms/authors-package/watchr.js",
"docs-lint": "eslint --ignore-path=\"tools/transforms/.eslintignore\" tools/transforms",
"docs-test": "npx ts-node -P tsconfig.docs.json tools/transforms/test.js",
"docs-decision-tree": "ts-node -P tools/decision-tree-generator/tsconfig.json tools/decision-tree-generator/main.ts",
"firebase-utils-test": "jasmine-ts tools/firebase-test-utils/*.spec.ts",
"tools-lint": "tslint -c \"tools/tslint.json\" \"tools/firebase-test-utils/**/*.ts\"",
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn firebase-utils-test",
Expand Down Expand Up @@ -74,7 +73,7 @@
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "^2.0.3",
"@types/lunr": "^2.3.3",
"@types/node": "^12.11.1",
"@types/node": "^20.6.3",
"@types/svgo": "^1.3.3",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
Expand Down
8 changes: 0 additions & 8 deletions apps/rxjs.dev/tools/decision-tree-generator/jest.config.js

This file was deleted.

28 changes: 0 additions & 28 deletions apps/rxjs.dev/tools/decision-tree-generator/main.ts

This file was deleted.

28 changes: 0 additions & 28 deletions apps/rxjs.dev/tools/decision-tree-generator/package.json

This file was deleted.

6 changes: 0 additions & 6 deletions apps/rxjs.dev/tools/decision-tree-generator/tsconfig.json

This file was deleted.

7 changes: 6 additions & 1 deletion apps/rxjs.dev/tools/transforms/angular.io-package/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ const apiPackage = require('../angular-api-package');
const contentPackage = require('../angular-content-package');
const { extname, resolve } = require('canonical-path');
const { existsSync } = require('fs');
const { SRC_PATH } = require('../config');
const { SRC_PATH, DOCS_OUTPUT_PATH, DECISION_TREE_PATH } = require('../config');
// prettier-ignore
module.exports = new Package('angular.io', [gitPackage, apiPackage, contentPackage])

// This processor relies upon the versionInfo. See below...
.processor(require('./processors/processNavigationMap'))
.processor(require('./processors/createOverviewDump'))
.processor(require('./processors/cleanGeneratedFiles'))
.processor(require('../rxjs-decision-tree-generator'))

// We don't include this in the angular-base package because the `versionInfo` stuff
// accesses the file system and git, which is slow.
Expand Down Expand Up @@ -54,4 +55,8 @@ module.exports = new Package('angular.io', [gitPackage, apiPackage, contentPacka

.config(function(renderLinkInfo, postProcessHtml) {
renderLinkInfo.docTypes = postProcessHtml.docTypes;
})
.config(function(decisionTreeGenerator) {
decisionTreeGenerator.outputFolder = DOCS_OUTPUT_PATH + '/app';
decisionTreeGenerator.decisionTreeFile = DECISION_TREE_PATH;
});
2 changes: 2 additions & 0 deletions apps/rxjs.dev/tools/transforms/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const DOCS_OUTPUT_PATH = resolve(OUTPUT_PATH, 'docs');
const API_SOURCE_PATH = resolve(PROJECT_ROOT, 'packages/rxjs/src');
const MARBLE_IMAGES_PATH = resolve(SRC_PATH, 'assets/images/marble-diagrams');
const MARBLE_IMAGES_WEB_PATH = 'assets/images/marble-diagrams';
const DECISION_TREE_PATH = resolve(CONTENTS_PATH, 'tree.yml');

function requireFolder(dirname, folderPath) {
const absolutePath = resolve(dirname, folderPath);
Expand All @@ -32,5 +33,6 @@ module.exports = {
API_SOURCE_PATH,
MARBLE_IMAGES_PATH,
MARBLE_IMAGES_WEB_PATH,
DECISION_TREE_PATH,
requireFolder,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { readFile } from 'fs/promises';
import { parse } from 'yamljs';

import { TreeNodeRaw, build, flattenApiList } from './src/lib';

module.exports = function decisionTreeGenerator(log: { warn: (message: string) => void }) {
return {
$runBefore: ['rendering-docs'],
$runAfter: ['generateApiListDoc'],
$validate: {
decisionTreeFile: { presence: true },
outputFolder: { presence: true },
},
$process: async function (this: any, docs: any[]) {
const apiListDoc = docs.find((doc) => doc.docType === 'api-list-data');

if (!apiListDoc) {
throw new Error('Can not find api-list-data for decision tree generation');
}

const yamlContent = await readFile(this.decisionTreeFile, { encoding: 'utf8' });
const decisionTreeJson: TreeNodeRaw[] = parse(yamlContent);

const flattenedApiList = flattenApiList(apiListDoc.data);
const jsonContent = build(flattenedApiList, decisionTreeJson, log);

docs.push({
docType: 'decision-tree-data',
template: 'json-doc.template.json',
path: this.outputFolder + '/decision-tree-data.json',
outputPath: this.outputFolder + '/decision-tree-data.json',
data: jsonContent,
});
return docs;
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,34 @@ import { mockRawTreeNodes } from './fixtures';
describe('addUniqueId', () => {
describe('when called with three raw nodes', () => {
let tree: TreeNode[];
let baseProperties: jest.Expect;
const baseProperties = jasmine.objectContaining({
id: jasmine.any(String),
label: jasmine.any(String),
depth: jasmine.any(Number),
});

beforeEach(() => {
tree = addUniqueId(mockRawTreeNodes);
baseProperties = expect.objectContaining({
id: expect.any(String),
label: expect.any(String),
depth: expect.any(Number),
});
});

describe('and one of the nodes is a child of another', () => {
it('should not flatten the tree and return the same number of top level nodes', () => {
expect(tree).toHaveLength(mockRawTreeNodes.length);
expect(tree.length).toBe(mockRawTreeNodes.length);
});
it('should return an array of tree nodes that have unique ids', () => {
tree.forEach(node => {
tree.forEach((node) => {
expect(node).toEqual(baseProperties);

if (!node.children) {
expect(node).not.toHaveProperty('options');
expect(node.options).toBeUndefined();
} else {
expect(node).toEqual(expect.objectContaining({
children: expect.any(Array),
options: expect.any(Array),
}));
node.children.forEach(child => {
expect(node).toEqual(
jasmine.objectContaining({
children: jasmine.any(Array),
options: jasmine.any(Array),
})
);
node.children.forEach((child) => {
expect(child).toEqual(baseProperties);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { mockFlatApiList, mockRawTreeNodes } from './fixtures';
import { treeNodeCount } from './helpers';

describe('build', () => {
const tree = build(mockFlatApiList, mockRawTreeNodes);
const tree = build(mockFlatApiList, mockRawTreeNodes, {warn: () => {}});
it('should return a flat map of all nodes and one additional initial node', () => {
expect(tree).toHaveProperty('initial');
expect(tree.initial).toBeDefined()
expect(Object.keys(tree).length).toBe(treeNodeCount(mockRawTreeNodes) + 1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import { decisionTreeReducer } from './decisionTreeReducer';
* @requires decisionTreeReducer
* @returns {DecisionTree}
*/
export function build(apiList: FlattenedApiList, tree: TreeNodeRaw[]): DecisionTree {
export function build(apiList: FlattenedApiList, tree: TreeNodeRaw[], log: { warn: (message: string) => void }): DecisionTree {
const nodesWithUniqueIds = addUniqueId(tree);
const initialOption = extractInitialSequence(nodesWithUniqueIds);

return {
...decisionTreeReducer(nodesWithUniqueIds, apiList),
[initialOption.id]: { ...initialOption }
...decisionTreeReducer(nodesWithUniqueIds, apiList, log),
[initialOption.id]: { ...initialOption },
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { addUniqueId } from './addUniqueId';
import { rawNodesWithMethodCount } from './helpers';

describe('decisionTreeReducer', () => {
const tree = decisionTreeReducer(addUniqueId(mockRawTreeNodes), mockFlatApiList);
const tree = decisionTreeReducer(addUniqueId(mockRawTreeNodes), mockFlatApiList, { warn: jasmine.createSpy() });
describe('all nodes', () => {
const baseProperties = expect.objectContaining({
id: expect.any(String),
label: expect.any(String)
const baseProperties = jasmine.objectContaining({
id: jasmine.any(String),
label: jasmine.any(String),
});

it('should have base properties', () => {
Expand All @@ -22,11 +22,8 @@ describe('decisionTreeReducer', () => {
describe('that have options', () => {
it('should have an options property that is an array of strings', () => {
for (const key in tree) {
if (
tree.hasOwnProperty(key) &&
tree[key].options
) {
tree[key].options.forEach(option => {
if (tree.hasOwnProperty(key) && tree[key].options) {
tree[key].options?.forEach((option) => {
expect(typeof option).toBe('string');
});
}
Expand All @@ -37,22 +34,16 @@ describe('decisionTreeReducer', () => {
describe('when a node does not have options', () => {
it('should not have an options property', () => {
for (const key in tree) {
if (
tree.hasOwnProperty(key) &&
!tree[key].options
) {
expect(tree[key]).not.toHaveProperty('options');
if (tree.hasOwnProperty(key) && !tree[key].options) {
expect(tree[key].options).toBeUndefined();
}
}
});
it('should have a docType and a path', () => {
for (const key in tree) {
if (
tree.hasOwnProperty(key) &&
!tree[key].options
) {
expect(tree[key]).toHaveProperty('docType');
expect(tree[key]).toHaveProperty('path');
if (tree.hasOwnProperty(key) && !tree[key].options) {
expect(tree[key].docType).toBeDefined();
expect(tree[key].path).toBeDefined();
}
}
});
Expand All @@ -61,12 +52,12 @@ describe('decisionTreeReducer', () => {
const treeNodesMissingInApiList = [
...mockRawTreeNodes,
{
label: 'foo'
}
label: 'foo',
},
];
it('should call a console.log', () => {
const spy = jest.spyOn(console, 'log');
decisionTreeReducer(addUniqueId(treeNodesMissingInApiList), mockFlatApiList);
const spy = jasmine.createSpy('warn');
decisionTreeReducer(addUniqueId(treeNodesMissingInApiList), mockFlatApiList, { warn: spy });
expect(spy).toHaveBeenCalled();
});
});
Expand All @@ -77,10 +68,7 @@ describe('decisionTreeReducer', () => {
it('should have a method property', () => {
let count = 0;
for (const key in tree) {
if (
tree.hasOwnProperty(key) &&
tree[key].method
) {
if (tree.hasOwnProperty(key) && tree[key].method) {
count++;
}
}
Expand Down
Loading

0 comments on commit 0543d3e

Please sign in to comment.