aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2023-02-01 22:33:15 +0100
committerGitHub <[email protected]>2023-02-01 22:33:15 +0100
commit9c3618d66550b7a72cade402b035ecdbcb485625 (patch)
tree0f6792026c965c745f6763b9ba1b14a3d26f828e /scripts
parentde7ed2e3b823131345995da6ec52c2b0c40c8d6e (diff)
downloadfaker-9c3618d66550b7a72cade402b035ecdbcb485625.tar.xz
faker-9c3618d66550b7a72cade402b035ecdbcb485625.zip
infra(docs): add docs diff script (#1755)
Diffstat (limited to 'scripts')
-rw-r--r--scripts/apidoc/apiDocsWriter.ts8
-rw-r--r--scripts/apidoc/diff.ts98
-rw-r--r--scripts/apidoc/generate.ts11
-rw-r--r--scripts/apidoc/moduleMethods.ts33
-rw-r--r--scripts/apidoc/utils.ts39
-rw-r--r--scripts/diff.ts30
6 files changed, 204 insertions, 15 deletions
diff --git a/scripts/apidoc/apiDocsWriter.ts b/scripts/apidoc/apiDocsWriter.ts
index f18b7cd9..d40dec34 100644
--- a/scripts/apidoc/apiDocsWriter.ts
+++ b/scripts/apidoc/apiDocsWriter.ts
@@ -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(
@@ -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[] = [];
diff --git a/scripts/apidoc/diff.ts b/scripts/apidoc/diff.ts
new file mode 100644
index 00000000..913062c8
--- /dev/null
+++ b/scripts/apidoc/diff.ts
@@ -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;
+}
diff --git a/scripts/apidoc/generate.ts b/scripts/apidoc/generate.ts
index 1f7c0016..6aa3ae0c 100644
--- a/scripts/apidoc/generate.ts
+++ b/scripts/apidoc/generate.ts
@@ -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';
@@ -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);
}
diff --git a/scripts/apidoc/moduleMethods.ts b/scripts/apidoc/moduleMethods.ts
index b52d4780..bf7b93f9 100644
--- a/scripts/apidoc/moduleMethods.ts
+++ b/scripts/apidoc/moduleMethods.ts
@@ -8,7 +8,8 @@ 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()`.
@@ -16,8 +17,10 @@ import type { PageIndex } from './utils';
* @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)) {
@@ -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[] = [];
@@ -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,
+ }),
+ }
+ ),
},
];
}
diff --git a/scripts/apidoc/utils.ts b/scripts/apidoc/utils.ts
index f480c0b1..5de80cc3 100644
--- a/scripts/apidoc/utils.ts
+++ b/scripts/apidoc/utils.ts
@@ -1,3 +1,4 @@
+import { createHash } from 'node:crypto';
import { resolve } from 'node:path';
// Types
@@ -5,10 +6,39 @@ import { resolve } from 'node:path';
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
@@ -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');
+}
diff --git a/scripts/diff.ts b/scripts/diff.ts
new file mode 100644
index 00000000..09a07046
--- /dev/null
+++ b/scripts/diff.ts
@@ -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);