Skip to content

Commit

Permalink
Merge branch 'next' into chore/fullname-name-patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
ST-DDT authored Feb 2, 2023
2 parents c3ccd26 + 9c3618d commit cea078e
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ versions.json
/docs/.vitepress/cache
/docs/.vitepress/dist
/docs/api/typedoc.json
/docs/public/api-diff-index.json
/lib
/locale

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"docs:dev": "run-s docs:prepare docs:dev:run",
"docs:dev:run": "vitepress dev docs",
"docs:serve": "vitepress serve docs --port 5173",
"docs:diff": "tsx ./scripts/diff.ts",
"format": "prettier --write .",
"lint": "eslint --cache --cache-strategy content .",
"ts-check:scripts": "tsc --project tsconfig.check-scripts.json",
Expand Down
8 changes: 6 additions & 2 deletions scripts/apidoc/apiDocsWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
selectApiMethods,
selectApiModules,
} from './typedoc';
import type { PageIndex } from './utils';
import { pathDocsDir, pathOutputDir } from './utils';
import type { DocsApiDiffIndex, PageIndex } from './utils';
import { pathDocsDiffIndexFile, pathDocsDir, pathOutputDir } from './utils';

const pathDocsApiPages = resolve(pathDocsDir, '.vitepress', 'api-pages.ts');
const pathDocsApiSearchIndex = resolve(
Expand Down Expand Up @@ -120,6 +120,10 @@ export function writeApiPagesIndex(pages: PageIndex): void {
writeFileSync(pathDocsApiPages, apiPagesContent);
}

export function writeApiDiffIndex(diffIndex: DocsApiDiffIndex): void {
writeFileSync(pathDocsDiffIndexFile, JSON.stringify(diffIndex));
}

export function writeApiSearchIndex(project: ProjectReflection): void {
const apiIndex: APIGroup[] = [];

Expand Down
98 changes: 98 additions & 0 deletions scripts/apidoc/diff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import type { DocsApiDiffIndex } from './utils';
import { nameDocsDiffIndexFile, pathDocsDiffIndexFile } from './utils';

/**
* Loads the diff index from the given source url.
*
* @param url The url to load the diff index from.
*/
async function loadRemote(url: string): Promise<DocsApiDiffIndex> {
return fetch(url).then((res) => {
if (!res.ok) {
throw new Error(
`Failed to load remote diff index from ${url}: ${res.statusText}`
);
} else {
return res.json() as Promise<DocsApiDiffIndex>;
}
});
}

/**
* Loads the diff index from the given local path.
*
* @param path The path to load the diff index from. Should start with `file://` for cross platform compatibility.
*/
async function loadLocal(path: string): Promise<DocsApiDiffIndex> {
return import(path).then((imp) => imp.default as DocsApiDiffIndex);
}

/**
* Loads the diff index from the given source.
* If the source starts with `https://` it will be loaded from the remote url.
* Otherwise it will be loaded from the local path.
*
* @param source The source to load the diff index from.
*/
async function load(source: string): Promise<DocsApiDiffIndex> {
if (source.startsWith('https://')) {
return loadRemote(source);
} else {
return loadLocal(source);
}
}

/**
* Returns a set of all keys from the given entries.
*
* @param entries The entries to get the keys from.
*/
function allKeys(
...entries: ReadonlyArray<Record<string, unknown>>
): Set<string> {
return new Set(entries.map(Object.keys).flat());
}

/**
* Compares the target (reference) and source (changed) diff index and returns the differences.
* The returned object contains the module names as keys and the method names as values.
* If the module name is `ADDED` or `REMOVED` it means that the module was added or removed in the local diff index.
*
* @param targetDiffIndex The url to the target (reference) diff index. Defaults to the next.fakerjs.dev diff index.
* @param sourceDiffIndex The path to the source (changed) index. Defaults to the local diff index.
*/
export async function diff(
targetDiffIndex = `https://next.fakerjs.dev/${nameDocsDiffIndexFile}`,
sourceDiffIndex = `file://${pathDocsDiffIndexFile}`
): Promise<Record<string, ['ADDED'] | ['REMOVED'] | string[]>> {
const target = await load(targetDiffIndex);
const source = await load(sourceDiffIndex);

const diff: Record<string, string[]> = {};

for (const moduleName of allKeys(target, source)) {
const remoteModule = target[moduleName];
const localModule = source[moduleName];

if (!remoteModule) {
diff[moduleName] = ['ADDED'];
continue;
}

if (!localModule) {
diff[moduleName] = ['REMOVED'];
continue;
}

for (const methodName of allKeys(remoteModule, localModule)) {
const remoteMethod = remoteModule[methodName];
const localMethod = localModule[methodName];

if (remoteMethod !== localMethod) {
(diff[moduleName] ??= []).push(methodName);
}
}
}

return diff;
}
11 changes: 9 additions & 2 deletions scripts/apidoc/generate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { resolve } from 'path';
import { writeApiPagesIndex, writeApiSearchIndex } from './apiDocsWriter';
import {
writeApiDiffIndex,
writeApiPagesIndex,
writeApiSearchIndex,
} from './apiDocsWriter';
import { processModuleMethods } from './moduleMethods';
import { loadProject } from './typedoc';
import { pathOutputDir } from './utils';
Expand All @@ -16,7 +20,10 @@ export async function generate(): Promise<void> {
await app.generateJson(project, pathOutputJson);

const modules = processModuleMethods(project);
writeApiPagesIndex(modules);
writeApiPagesIndex(modules.map(({ text, link }) => ({ text, link })));
writeApiDiffIndex(
modules.reduce((data, { text, diff }) => ({ ...data, [text]: diff }), {})
);

writeApiSearchIndex(project);
}
33 changes: 22 additions & 11 deletions scripts/apidoc/moduleMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ import {
selectApiMethodSignatures,
selectApiModules,
} from './typedoc';
import type { PageIndex } from './utils';
import type { PageAndDiffIndex } from './utils';
import { diffHash } from './utils';

/**
* Analyzes and writes the documentation for modules and their methods such as `faker.animal.cat()`.
*
* @param project The project used to extract the modules.
* @returns The generated pages.
*/
export function processModuleMethods(project: ProjectReflection): PageIndex {
const pages: PageIndex = [];
export function processModuleMethods(
project: ProjectReflection
): PageAndDiffIndex {
const pages: PageAndDiffIndex = [];

// Generate module files
for (const module of selectApiModules(project)) {
Expand All @@ -33,10 +36,11 @@ export function processModuleMethods(project: ProjectReflection): PageIndex {
* @param module The module to process.
* @returns The generated pages.
*/
function processModuleMethod(module: DeclarationReflection): PageIndex {
function processModuleMethod(module: DeclarationReflection): PageAndDiffIndex {
const moduleName = extractModuleName(module);
const moduleFieldName = extractModuleFieldName(module);
console.log(`Processing Module ${moduleName}`);
const comment = toBlock(module.comment);

const methods: Method[] = [];

Expand All @@ -45,22 +49,29 @@ function processModuleMethod(module: DeclarationReflection): PageIndex {
selectApiMethodSignatures(module)
)) {
console.debug(`- ${methodName}`);

methods.push(analyzeSignature(signature, moduleFieldName, methodName));
}

writeApiDocsModulePage(
moduleName,
moduleFieldName,
toBlock(module.comment),
methods
);
writeApiDocsModulePage(moduleName, moduleFieldName, comment, methods);
writeApiDocsData(moduleFieldName, methods);

return [
{
text: moduleName,
link: `/api/${moduleFieldName}.html`,
diff: methods.reduce(
(data, method) => ({
...data,
[method.name]: diffHash(method),
}),
{
moduleHash: diffHash({
name: moduleName,
field: moduleFieldName,
comment,
}),
}
),
},
];
}
39 changes: 39 additions & 0 deletions scripts/apidoc/utils.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
import { createHash } from 'node:crypto';
import { resolve } from 'node:path';

// Types

export type Page = { text: string; link: string };
export type PageIndex = Page[];

export type PageAndDiff = Page & {
diff: DocsApiDiff;
};
export type PageAndDiffIndex = PageAndDiff[];

export interface DocsApiDiffIndex {
/**
* The methods in the module by name.
*/
[module: string]: DocsApiDiff;
}

export interface DocsApiDiff {
/**
* The checksum of the entire module.
*/
moduleHash: string;
/**
* The checksum of the method by name.
*/
[method: string]: string;
}

// Paths

const pathRoot = resolve(__dirname, '..', '..');
export const pathDocsDir = resolve(pathRoot, 'docs');
const pathPublicDir = resolve(pathDocsDir, 'public');
export const nameDocsDiffIndexFile = 'api-diff-index.json';
export const pathDocsDiffIndexFile = resolve(
pathPublicDir,
nameDocsDiffIndexFile
);
export const pathOutputDir = resolve(pathDocsDir, 'api');

// Functions
Expand All @@ -22,3 +52,12 @@ export function mapByName<T extends { name: string }, V>(
{}
);
}

/**
* Creates a diff hash for the given object.
*
* @param object The object to create a hash for.
*/
export function diffHash(object: unknown): string {
return createHash('md5').update(JSON.stringify(object)).digest('hex');
}
30 changes: 30 additions & 0 deletions scripts/diff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { existsSync } from 'node:fs';
import { argv } from 'node:process';
import { diff } from './apidoc/diff';
import { pathDocsDiffIndexFile } from './apidoc/utils';

const [target, source] = argv.slice(2);

if (!source && !existsSync(pathDocsDiffIndexFile)) {
throw new Error(
`Unable to find local diff index file at: ${pathDocsDiffIndexFile}\n
You can run \`pnpm run generate:api-docs\` to generate it.`
);
}

diff(target, source)
.then((delta) => {
if (Object.keys(delta).length === 0) {
console.log('No documentation changes detected');
return;
}

console.log('Documentation changes detected:');
for (const [module, methods] of Object.entries(delta)) {
console.log(`- ${module}`);
for (const method of methods) {
console.log(` - ${method}`);
}
}
})
.catch(console.error);

0 comments on commit cea078e

Please sign in to comment.