From a6d4d8ca372952906cece1fe9ef0054df5bf7073 Mon Sep 17 00:00:00 2001
From: Kevin Scott <151596+thekevinscott@users.noreply.github.com>
Date: Tue, 17 Oct 2023 07:13:06 -0400
Subject: [PATCH] Update documentation to leverage new @internals/scripts
(#1236)
* Add docs scripts
---
docs/package.json | 33 ++-
internals/scripts/package.json | 37 ++-
.../scripts/src/bin/write/docs/api/index.ts | 27 ++
.../write/docs/api/lib/_templates/index.md.t | 9 +
.../write/docs/api/lib/_templates/source.md.t | 1 +
.../src/bin/write/docs/api/lib/constants.ts | 68 +++++
.../get-all-declaration-reflections.test.ts | 36 +++
.../get-all-declaration-reflections.ts | 16 +
...laration-reflections-from-packages.test.ts | 45 +++
...t-declaration-reflections-from-packages.ts | 22 ++
.../get-definitions/get-definitions.test.ts | 103 +++++++
.../lib/get-definitions/get-definitions.ts | 41 +++
.../get-package-as-tree.test.ts | 61 ++++
.../get-definitions/get-package-as-tree.ts | 20 ++
...m-platform-specific-upscaler-files.test.ts | 134 +++++++++
...s-from-platform-specific-upscaler-files.ts | 94 ++++++
.../docs/api/lib/get-definitions/index.ts | 1 +
.../get-sorted-methods-for-writing.test.ts | 48 +++
.../api/lib/get-sorted-methods-for-writing.ts | 24 ++
.../lib/sort-children-by-line-number.test.ts | 46 +++
.../api/lib/sort-children-by-line-number.ts | 13 +
.../src/bin/write/docs/api/lib/types.ts | 49 +++
.../bin/write/docs/api/lib/write-api-docs.ts | 15 +
.../get-content-for-method.ts | 85 ++++++
.../get-matching-type.test.ts | 189 ++++++++++++
.../get-matching-type.ts | 64 ++++
.../get-reference-type-of-parameter.ts | 157 ++++++++++
.../get-return-type.ts | 80 +++++
.../get-source.ts | 20 ++
.../get-text-summary.test.ts | 47 +++
.../get-text-summary.ts | 25 ++
.../get-url-from-sources.test.ts | 53 ++++
.../get-url-from-sources.ts | 30 ++
.../write-api-documentation-files/index.ts | 1 +
.../write-api-documentation-files.test.ts | 51 ++++
.../write-api-documentation-files.ts | 22 ++
.../write-parameter.ts | 90 ++++++
.../write-platform-specific-parameter.ts | 18 ++
.../docs/api/lib/write-index-file.test.ts | 27 ++
.../write/docs/api/lib/write-index-file.ts | 12 +
.../scripts/src/bin/write/docs/check-tense.ts | 106 +++++++
.../src/bin/write/docs/guides/index.ts | 26 ++
.../bin/write/docs/guides/write-guide-docs.ts | 278 ++++++++++++++++++
.../src/bin/write/docs/models/index.ts | 27 ++
.../write/docs/models/write-model-readmes.ts | 214 ++++++++++++++
.../docs/shared/clear-out-markdown-files.ts | 18 ++
.../bin/write/docs/shared/get-shared-args.ts | 18 ++
pnpm-lock.yaml | 4 +
scripts/package.json | 5 -
49 files changed, 2587 insertions(+), 23 deletions(-)
create mode 100644 internals/scripts/src/bin/write/docs/api/index.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/_templates/index.md.t
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/_templates/source.md.t
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/constants.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-definitions/index.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/types.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-docs.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-content-for-method.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-reference-type-of-parameter.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-return-type.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-source.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/index.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-parameter.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-platform-specific-parameter.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-index-file.test.ts
create mode 100644 internals/scripts/src/bin/write/docs/api/lib/write-index-file.ts
create mode 100644 internals/scripts/src/bin/write/docs/check-tense.ts
create mode 100644 internals/scripts/src/bin/write/docs/guides/index.ts
create mode 100644 internals/scripts/src/bin/write/docs/guides/write-guide-docs.ts
create mode 100644 internals/scripts/src/bin/write/docs/models/index.ts
create mode 100644 internals/scripts/src/bin/write/docs/models/write-model-readmes.ts
create mode 100644 internals/scripts/src/bin/write/docs/shared/clear-out-markdown-files.ts
create mode 100644 internals/scripts/src/bin/write/docs/shared/get-shared-args.ts
diff --git a/docs/package.json b/docs/package.json
index a26bc859d..d0c2970fd 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -3,7 +3,6 @@
"version": "1.0.0-beta.10",
"private": true,
"scripts": {
- "build:dependencies": "wireit",
"build-api": "wireit",
"build-api:watch": "wireit",
"build-guides": "wireit",
@@ -123,32 +122,32 @@
"node": ">=16.14"
},
"wireit": {
- "build:dependencies": {
- "command": "pnpm --filter upscaler build",
- "dependencies": [
- "../models/esrgan-medium:build"
- ]
- },
"build-api": {
- "command": "pnpm --filter @upscalerjs/scripts docs:build-api",
+ "command": "pnpm --filter @internals/scripts write:docs:api",
"dependencies": [
- "../internals/common:build"
+ "../internals/scripts:build"
]
},
"build-api:watch": {
- "command": "nodemon -e ts --ignore '../packages/upscalerjs/**/*.generated.ts' --watch '../packages/core/**/*' --watch '../packages/upscalerjs/**/*' --watch '../scripts/package-scripts/docs/build-api.ts' -x \"pnpm run build-api\""
+ "command": "nodemon -e ts --ignore '../packages/upscalerjs/**/*.generated.ts' --watch '../packages/upscalerjs/**/*' --watch '../internals/scripts/src/write/docs/shared/**' --watch '../internals/scripts/src/write/docs/api/**' -x \"pnpm run build-api\""
},
"build-guides": {
- "command": "pnpm --filter @upscalerjs/scripts docs:build-guides"
+ "command": "pnpm --filter @internals/scripts write:docs:guides",
+ "dependencies": [
+ "../internals/scripts:build"
+ ]
},
"build-guides:watch": {
- "command": "nodemon -e md --watch '../examples/**/*' --watch '../scripts/package-scripts/docs/build-guides.ts' -x \"pnpm run build-guides\""
+ "command": "nodemon -e md --watch '../examples/**/*' --watch '../internals/scripts/src/write/docs/shared/**' --watch '../internals/scripts/src/write/docs/guides/**' -x \"pnpm run build-guides\""
},
"link-model-readmes": {
- "command": "pnpm --filter @upscalerjs/scripts docs:link-model-readmes"
+ "command": "pnpm --filter @internals/scripts write:docs:models",
+ "dependencies": [
+ "../internals/scripts:build"
+ ]
},
"link-model-readmes:watch": {
- "command": "nodemon -e md -e mdx --watch '../models/**/*' --watch '../scripts/package-scripts/docs/link-model-readmes.ts' -x \"pnpm run link-model-readmes\""
+ "command": "nodemon -e md -e mdx --watch '../models/**/*' --watch '../internals/scripts/src/write/docs/shared/**' --watch '../internals/scripts/src/write/docs/models/**' -x \"pnpm run link-model-readmes\""
},
"docusaurus": {
"command": "docusaurus"
@@ -166,7 +165,11 @@
"command": "docusaurus build"
},
"build": {
- "command": "concurrently \"pnpm build-guides -- --shouldClearMarkdown\" \"pnpm build-api -- --shouldClearMarkdown\" \"pnpm link-model-readmes -- --shouldClearMarkdown\" && pnpm tense-checks && pnpm build:dependencies && pnpm build:only"
+ "command": "concurrently \"pnpm build-guides -- --shouldClearMarkdown\" \"pnpm build-api -- --shouldClearMarkdown\" \"pnpm link-model-readmes -- --shouldClearMarkdown\" && pnpm tense-checks && pnpm build:only",
+ "dependencies": [
+ "../models/esrgan-medium:build",
+ "../packages/upscalerjs:build"
+ ]
},
"swizzle": {
"command": "docusaurus swizzle"
diff --git a/internals/scripts/package.json b/internals/scripts/package.json
index b93a87b29..33004634c 100644
--- a/internals/scripts/package.json
+++ b/internals/scripts/package.json
@@ -10,9 +10,14 @@
"author": "Kevin Scott",
"license": "MIT",
"dependencies": {
- "@internals/common": "workspace:*"
+ "@internals/common": "workspace:*",
+ "typedoc": "^0.24.8"
},
"scripts": {
+ "write:docs:check-tense": "wireit",
+ "write:docs:guides": "wireit",
+ "write:docs:models": "wireit",
+ "write:docs:api": "wireit",
"start:guide": "wireit",
"update:npm-dependencies": "wireit",
"build": "wireit",
@@ -20,6 +25,32 @@
"test": "wireit"
},
"wireit": {
+ "write:docs:check-tense": {
+ "command": "node ./dist/bin/write/docs/check-tense.js",
+ "dependencies": [
+ "build"
+ ]
+ },
+ "write:docs:guides": {
+ "command": "node ./dist/bin/write/docs/guides/index.js",
+ "dependencies": [
+ "build"
+ ]
+ },
+ "write:docs:models": {
+ "command": "node ./dist/bin/write/docs/models/index.js",
+ "dependencies": [
+ "build"
+ ]
+ },
+ "write:docs:api": {
+ "command": "node ./dist/bin/write/docs/api/index.js",
+ "dependencies": [
+ "../../packages/upscalerjs:build:browser:esm",
+ "../../packages/upscalerjs:build:node",
+ "build"
+ ]
+ },
"start:guide": {
"command": "node ./dist/bin/start/guide.js",
"dependencies": [
@@ -67,7 +98,7 @@
"node": ">=20.0.0"
},
"devDependencies": {
- "wireit": "latest",
- "vitest": "^0.34.2"
+ "vitest": "^0.34.2",
+ "wireit": "latest"
}
}
diff --git a/internals/scripts/src/bin/write/docs/api/index.ts b/internals/scripts/src/bin/write/docs/api/index.ts
new file mode 100644
index 000000000..79c7c0664
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/index.ts
@@ -0,0 +1,27 @@
+import path from 'path';
+import { DOCS_DIR, } from '@internals/common/constants';
+import { mkdirp } from '@internals/common/fs';
+import { writeAPIDocs } from './lib/write-api-docs.js';
+import { info, verbose } from '@internals/common/logger';
+import { getSharedArgs } from '../shared/get-shared-args.js';
+import { clearOutMarkdownFiles } from '../shared/clear-out-markdown-files.js';
+
+const EXAMPLES_DOCS_DEST = path.resolve(DOCS_DIR, 'docs/documentation/api');
+
+const writeAPIDocumentation = async ({ shouldClearMarkdown }: { shouldClearMarkdown: boolean }) => {
+ info('Writing API documentation');
+ await mkdirp(EXAMPLES_DOCS_DEST);
+ if (shouldClearMarkdown) {
+ verbose(`Clearing out markdown files in ${EXAMPLES_DOCS_DEST}`)
+ await clearOutMarkdownFiles(EXAMPLES_DOCS_DEST);
+ }
+
+ return writeAPIDocs(EXAMPLES_DOCS_DEST);
+};
+
+
+const main = async () => {
+ return writeAPIDocumentation(getSharedArgs());
+};
+
+main();
diff --git a/internals/scripts/src/bin/write/docs/api/lib/_templates/index.md.t b/internals/scripts/src/bin/write/docs/api/lib/_templates/index.md.t
new file mode 100644
index 000000000..8034b8bf0
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/_templates/index.md.t
@@ -0,0 +1,9 @@
+# API
+
+API Documentation for UpscalerJS.
+
+Available methods:
+
+<% for (const method of methods) { %>
+- [`<%- method.name %>`](./<%- method.name %>)
+<% } %>
diff --git a/internals/scripts/src/bin/write/docs/api/lib/_templates/source.md.t b/internals/scripts/src/bin/write/docs/api/lib/_templates/source.md.t
new file mode 100644
index 000000000..aace97a79
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/_templates/source.md.t
@@ -0,0 +1 @@
+Defined in <%- prettyFileName %>:<%- line %>
diff --git a/internals/scripts/src/bin/write/docs/api/lib/constants.ts b/internals/scripts/src/bin/write/docs/api/lib/constants.ts
new file mode 100644
index 000000000..5bc3ebc5d
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/constants.ts
@@ -0,0 +1,68 @@
+import { UPSCALER_DIR } from "@internals/common/constants";
+import path from 'path';
+import { DeclarationReflection, ReflectionKind, TypeParameterReflection } from "typedoc";
+import * as url from 'url';
+import { Definitions } from "./types.js";
+import { writePlatformSpecificDefinitions } from "./write-api-documentation-files/write-parameter.js";
+
+const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
+
+export const REPO_ROOT = 'https://github.com/thekevinscott/UpscalerJS';
+export const UPSCALER_TSCONFIG_PATH = path.resolve(UPSCALER_DIR, 'tsconfig.esm.json');
+export const UPSCALER_SRC_PATH = path.resolve(UPSCALER_DIR, 'src');
+export const VALID_EXPORTS_FOR_WRITING_DOCS = ['default'];
+export const VALID_METHODS_FOR_WRITING_DOCS = [
+ 'constructor',
+ 'upscale',
+ 'execute',
+ 'warmup',
+ 'abort',
+ 'dispose',
+ 'getModel',
+];
+export const INTRINSIC_TYPES = [
+ 'string',
+ 'number',
+ 'boolean',
+];
+export const TYPES_TO_EXPAND: Record = {
+ 'upscale': ['Input', 'Progress'],
+ 'warmup': ['WarmupSizes'],
+};
+export const TEMPLATES_DIR = path.resolve(__dirname, '_templates');
+
+export const makeNewExternalType = (name: string, _url: string): DeclarationReflection => {
+ const type = new DeclarationReflection(name, ReflectionKind['SomeType']);
+ type.sources = [];
+ return type;
+};
+
+export const EXTERNALLY_DEFINED_TYPES: Record = {
+ 'AbortSignal': makeNewExternalType(
+ 'AbortSignal',
+ 'https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal'
+ ),
+ 'SerializableConstructor': makeNewExternalType(
+ 'SerializableConstructor',
+ 'https://github.com/tensorflow/tfjs/blob/38f8462fe642011ff1b7bcbb52e018f3451be58b/tfjs-core/src/serialization.ts#L54',
+ ),
+}
+
+export const EXPANDED_TYPE_CONTENT: Record) => string> = {
+ 'Input': (definitions) => writePlatformSpecificDefinitions(definitions),
+ 'WarmupSizes': () => ([
+ '- `number` - a number representing both the size (width and height) of the patch.',
+ '- `{patchSize: number; padding?: number}` - an object with the `patchSize` and optional `padding` properties.',
+ '- `number[]` - an array of numbers representing the size (width and height) of the patch.',
+ '- `{patchSize: number; padding?: number}[]` - an array of objects with the `patchSize` and optional `padding` properties.',
+ ].join('\n')),
+ 'Progress': () => ([
+ 'The progress callback function has the following four parameters:',
+ '- `progress` - a number between 0 and 1 representing the progress of the upscale.',
+ '- `slice` - a string or 3D tensor representing the current slice of the image being processed. The type returned is specified by the `progressOutput` option, or if not present, the `output` option, or if not present, string for the browser and tensor for node.',
+ '- `row` - the row of the image being processed.',
+ '- `col` - the column of the image being processed.',
+ '',
+ '[See the guide on progress for more information.](/documentation/guides/browser/usage/progress)',
+ ].join('\n')),
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.test.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.test.ts
new file mode 100644
index 000000000..2e8afae52
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.test.ts
@@ -0,0 +1,36 @@
+import { PlatformSpecificFileDeclarationReflection } from "../types.js";
+import { getAllDeclarationReflections } from "./get-all-declaration-reflections.js";
+import { getDeclarationReflectionsFromPackages } from "./get-declaration-reflections-from-packages.js";
+import { getTypesFromPlatformSpecificUpscalerFiles } from "./get-types-from-platform-specific-upscaler-files.js";
+import { DeclarationReflection } from "typedoc";
+
+vi.mock('./get-declaration-reflections-from-packages.js', () => ({
+ getDeclarationReflectionsFromPackages: vi.fn(),
+}));
+
+vi.mock('./get-types-from-platform-specific-upscaler-files.js', () => ({
+ getTypesFromPlatformSpecificUpscalerFiles: vi.fn(),
+}));
+
+describe('getAllDeclarationReflections()', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+ it('gets merged declaration reflections', async () => {
+ vi.mocked(getDeclarationReflectionsFromPackages).mockImplementation(() => {
+ return [
+ 'foo',
+ ] as unknown as DeclarationReflection[];
+ });
+
+ vi.mocked(getTypesFromPlatformSpecificUpscalerFiles).mockImplementation(() => {
+ return Promise.resolve([
+ 'bar',
+ ] as unknown as PlatformSpecificFileDeclarationReflection[]);
+ });
+
+ const results = await getAllDeclarationReflections();
+ expect(results).toEqual(['foo', 'bar']);
+
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.ts
new file mode 100644
index 000000000..0c5b9347d
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-all-declaration-reflections.ts
@@ -0,0 +1,16 @@
+import { UPSCALER_DIR } from "@internals/common/constants";
+import { UPSCALER_TSCONFIG_PATH } from "../constants.js";
+import { DeclarationReflection } from "typedoc";
+import { getDeclarationReflectionsFromPackages } from "./get-declaration-reflections-from-packages.js";
+import { getTypesFromPlatformSpecificUpscalerFiles } from "./get-types-from-platform-specific-upscaler-files.js";
+import { PlatformSpecificFileDeclarationReflection } from "../types.js";
+
+const DECLARATION_REFLECTION_FILE_DEFINITIONS = [{
+ tsconfigPath: UPSCALER_TSCONFIG_PATH,
+ projectRoot: UPSCALER_DIR,
+}];
+
+export const getAllDeclarationReflections = async (): Promise<(DeclarationReflection | PlatformSpecificFileDeclarationReflection)[]> => ([
+ ...(await getTypesFromPlatformSpecificUpscalerFiles([{ fileName: 'image', typeName: 'Input' }])),
+ ...getDeclarationReflectionsFromPackages(DECLARATION_REFLECTION_FILE_DEFINITIONS),
+]);
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.test.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.test.ts
new file mode 100644
index 000000000..3c6e0fe9b
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.test.ts
@@ -0,0 +1,45 @@
+import { ProjectReflection } from "typedoc";
+import { getDeclarationReflectionsFromPackages } from "./get-declaration-reflections-from-packages.js";
+import { getPackageAsTree } from "./get-package-as-tree.js";
+
+vi.mock('./get-package-as-tree.js', () => {
+ return {
+ getPackageAsTree: vi.fn(),
+ }
+});
+
+describe('getDeclarationReflectionsFromPackages', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+ it('returns an array of DeclarationReflections', () => {
+ vi.mocked(getPackageAsTree).mockImplementation(() => {
+ return {
+ children: [
+ 'foo',
+ 'bar',
+ ],
+ } as unknown as ProjectReflection;
+ });
+ expect(getDeclarationReflectionsFromPackages([
+ {
+ tsconfigPath: 'tsconfig',
+ projectRoot: 'projectRoot',
+ },
+ ])).toEqual(['foo', 'bar']);
+ });
+
+ it('throws if receiving an empty children array', () => {
+ vi.mocked(getPackageAsTree).mockImplementation(() => {
+ return {
+ children: [],
+ } as unknown as ProjectReflection;
+ });
+ expect(() => getDeclarationReflectionsFromPackages([
+ {
+ tsconfigPath: 'tsconfig',
+ projectRoot: 'projectRoot',
+ },
+ ])).toThrow();
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.ts
new file mode 100644
index 000000000..6322c23b3
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-declaration-reflections-from-packages.ts
@@ -0,0 +1,22 @@
+import { getPackageAsTree } from "./get-package-as-tree.js";
+import { DeclarationReflection } from "typedoc";
+import path from "path";
+
+export interface ProjectDefinition {
+ tsconfigPath: string;
+ projectRoot: string;
+}
+
+export const getDeclarationReflectionsFromPackages = (projectDefinitions: ProjectDefinition[]): DeclarationReflection[] => [
+ ...projectDefinitions,
+].reduce((arr, { tsconfigPath, projectRoot }) => {
+ const { children } = getPackageAsTree(
+ path.join(projectRoot, 'src'),
+ tsconfigPath,
+ projectRoot,
+ );
+ if (children === undefined || children.length === 0) {
+ throw new Error(`No children were found for ${projectRoot}. Indicates an error in the returned structure from getPackageAsTree`);
+ }
+ return arr.concat(children);
+}, []);
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.test.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.test.ts
new file mode 100644
index 000000000..09940877a
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.test.ts
@@ -0,0 +1,103 @@
+import { getDefinitions } from "./get-definitions.js";
+import { getAllDeclarationReflections } from "./get-all-declaration-reflections.js";
+import { DeclarationReflection, ReflectionKind } from "typedoc";
+import { PlatformSpecificFileDeclarationReflection } from "../types.js";
+
+vi.mock('./get-all-declaration-reflections.js', () => ({
+ getAllDeclarationReflections: vi.fn(),
+}));
+
+describe('getDefinitions()', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('throws if given a bad "kind"', async () => {
+ vi.mocked(getAllDeclarationReflections).mockImplementation(() => {
+ return Promise.resolve([
+ {
+ kind: 'foo',
+ }
+ ] as unknown as (DeclarationReflection | PlatformSpecificFileDeclarationReflection)[]);
+ });
+
+ await expect(() => getDefinitions()).rejects.toThrow();
+ });
+
+ it('gets definitions', async () => {
+ const Constructor = {
+ name: 'Constructor',
+ kind: ReflectionKind.Constructor,
+ };
+ const Method = {
+ name: 'Method',
+ kind: ReflectionKind.Method,
+ };
+ const Interface = {
+ name: 'Interface',
+ kind: ReflectionKind.Interface,
+ };
+ const TypeAlias = {
+ name: 'TypeAlias',
+ kind: ReflectionKind.TypeAlias,
+ };
+ const Class = {
+ name: 'Class',
+ kind: ReflectionKind.Class,
+ };
+ const Function = {
+ name: 'Function',
+ kind: ReflectionKind.Function,
+ };
+ const Enum = {
+ name: 'Enum',
+ kind: ReflectionKind.Enum,
+ };
+ const PlatformSpecific = {
+ declarationReflection: {
+ name: 'PlatformSpecific',
+ kind: ReflectionKind.Constructor,
+ },
+ browser: {},
+ node: {},
+ };
+ vi.mocked(getAllDeclarationReflections).mockImplementation(() => {
+ return Promise.resolve([
+ PlatformSpecific,
+ Constructor,
+ Method,
+ Interface,
+ TypeAlias,
+ Class,
+ Function,
+ Enum,
+ ] as (DeclarationReflection | PlatformSpecificFileDeclarationReflection)[]);
+ });
+
+ const result = await getDefinitions();
+ expect(result).toEqual({
+ methods: {
+ Method,
+ },
+ constructors: {
+ Constructor,
+ PlatformSpecific,
+ },
+ functions: {
+ Function,
+ },
+ types: {
+ TypeAlias,
+ },
+ interfaces: {
+ Interface,
+ },
+ classes: {
+ Class,
+ },
+ enums: {
+ Enum,
+ },
+ });
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.ts
new file mode 100644
index 000000000..550d1f7f3
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-definitions.ts
@@ -0,0 +1,41 @@
+import { ReflectionKind } from "typedoc";
+import { Definitions, isPlatformSpecificFileDeclarationReflection } from "../types.js";
+import { getAllDeclarationReflections } from "./get-all-declaration-reflections.js";
+import { } from "./get-types-from-platform-specific-upscaler-files.js";
+
+export const KindStringKey: Partial> = {
+ [ReflectionKind.Constructor]: 'constructors',
+ [ReflectionKind.Method]: 'methods',
+ [ReflectionKind.Interface]: 'interfaces',
+ [ReflectionKind.TypeAlias]: 'types',
+ [ReflectionKind.Class]: 'classes',
+ [ReflectionKind.Function]: 'functions',
+ [ReflectionKind.Enum]: 'enums',
+}
+
+const getKindStringKey = (kindString: ReflectionKind): keyof Definitions => {
+ const nameOfKind = KindStringKey[kindString];
+ if (!nameOfKind) {
+ throw new Error(`Unexpected kind string: ${kindString}`);
+ }
+ return nameOfKind;
+};
+
+export const getDefinitions = async (): Promise => {
+ const children = await getAllDeclarationReflections();
+ const definitions: Definitions = {
+ constructors: {},
+ methods: {},
+ functions: {},
+ interfaces: {},
+ types: {},
+ classes: {},
+ enums: {},
+ };
+ for (const child of children) {
+ const { name, kind } = isPlatformSpecificFileDeclarationReflection(child) ? child.declarationReflection : child;
+ definitions[getKindStringKey(kind)][name] = child;
+ }
+ return definitions;
+}
+
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.test.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.test.ts
new file mode 100644
index 000000000..be060da5e
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.test.ts
@@ -0,0 +1,61 @@
+import * as typedoc from 'typedoc';
+import { vi } from 'vitest';
+import { getPackageAsTree } from './get-package-as-tree.js';
+
+vi.mock('typedoc', async () => {
+ const actual = await vi.importActual('typedoc') as typeof typedoc;
+ return {
+ ...actual,
+ Application: vi.fn().mockImplementation(() => ({
+ options: {
+ addReader: vi.fn(),
+ },
+ bootstrap: vi.fn(),
+ convert: vi.fn(),
+ serializer: {
+ projectToObject: vi.fn(),
+ },
+ })),
+ TSConfigReader: vi.fn(),
+ TypeDocReader: vi.fn(),
+ }
+});
+
+describe('getPackageAsTree', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+ it('throws if project is not converted', async () => {
+ vi.mocked(typedoc.Application).mockImplementation(() => {
+ return {
+ options: {
+ addReader: vi.fn(),
+ },
+ bootstrap: vi.fn(),
+ convert: vi.fn(),
+ } as unknown as typedoc.Application;
+ });
+ await expect(async () => {
+ await getPackageAsTree('entryPoint', 'tsconfig', 'projectRoot')
+ }).rejects.toThrow();
+ });
+
+ it('returns project if it is converted', async () => {
+ const projectToObject = vi.fn().mockImplementation(() => 'projectToObject');
+ vi.mocked(typedoc.Application).mockImplementation(() => {
+ return {
+ options: {
+ addReader: vi.fn(),
+ },
+ bootstrap: vi.fn(),
+ convert: vi.fn().mockImplementation(() => 'foo'),
+ serializer: {
+ projectToObject,
+ }
+ } as unknown as typedoc.Application;
+ });
+ const result = await getPackageAsTree('entryPoint', 'tsconfig', 'projectRoot');
+ expect(result).toEqual('projectToObject');
+ expect(projectToObject).toHaveBeenCalledWith('foo', 'projectRoot');
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.ts
new file mode 100644
index 000000000..a44867593
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-package-as-tree.ts
@@ -0,0 +1,20 @@
+import { Application, ProjectReflection, TSConfigReader, TypeDocReader } from "typedoc";
+
+export const getPackageAsTree = (entryPoint: string, tsconfig: string, projectRoot: string): ProjectReflection => {
+ const app = new Application();
+
+ app.options.addReader(new TSConfigReader());
+ app.options.addReader(new TypeDocReader());
+
+ app.bootstrap({
+ entryPoints: [entryPoint],
+ tsconfig,
+ });
+
+ const project = app.convert();
+
+ if (!project) {
+ throw new Error('No project was converted.')
+ }
+ return app.serializer.projectToObject(project, projectRoot) as unknown as ProjectReflection;
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.test.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.test.ts
new file mode 100644
index 000000000..742b3e8d1
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.test.ts
@@ -0,0 +1,134 @@
+import { DeclarationReflection, ProjectReflection, ReflectionKind, SomeType } from "typedoc";
+import {
+ getPlatformSpecificUpscalerDeclarationReflections,
+ getTypesFromPlatformSpecificUpscalerFile,
+ getTypesFromPlatformSpecificUpscalerFiles,
+ makeDeclarationReflection,
+} from "./get-types-from-platform-specific-upscaler-files.js";
+import { getPackageAsTree } from "./get-package-as-tree.js";
+
+vi.mock('./get-package-as-tree.js', () => {
+ return {
+ getPackageAsTree: vi.fn(),
+ };
+});
+
+describe('makeDeclarationReflection', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+ it('gets a declaration reflection', () => {
+ const decRef = makeDeclarationReflection('foo', {
+ type: 'functions',
+ } as unknown as SomeType);
+ expect(decRef.name).toEqual('foo');
+ expect(decRef.kind).toEqual(ReflectionKind.Function);
+ expect(decRef.type).toEqual({
+ type: 'functions',
+ });
+ })
+});
+
+describe('getPlatformSpecificUpscalerDeclarationReflections', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+ it('throws if it cannot find a matching type', () => {
+ vi.mocked(getPackageAsTree).mockImplementation(() => {
+ return {
+ children: [
+ 'foo',
+ 'bar',
+ ],
+ } as unknown as ProjectReflection;
+ });
+
+ expect(() => getPlatformSpecificUpscalerDeclarationReflections('browser', {
+ fileName: 'fileName',
+ typeName: 'typeName',
+ })).toThrow();
+ });
+
+ it('throws if it cannot find a matching type', () => {
+ const child = {
+ name: 'foo',
+ };
+ vi.mocked(getPackageAsTree).mockImplementation(() => {
+ return {
+ children: [child],
+ } as unknown as ProjectReflection;
+ });
+
+ expect(getPlatformSpecificUpscalerDeclarationReflections('browser', {
+ fileName: 'fileName',
+ typeName: child.name,
+ })).toEqual(child);
+ });
+});
+
+describe('getTypesFromPlatformSpecificUpscalerFile', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+ it('gets types from platform specific upscaler file', () => {
+ const typeName = 'typeName';
+ const child = {
+ name: typeName,
+ type: {
+ type: 'functions',
+ },
+ };
+ vi.mocked(getPackageAsTree).mockImplementation(() => {
+ return {
+ children: [child],
+ } as unknown as ProjectReflection;
+ });
+ const result = getTypesFromPlatformSpecificUpscalerFile({
+ fileName: 'fileName',
+ typeName,
+ });
+ expect(result.declarationReflection.name).toEqual(typeName);
+ expect(result.browser).toEqual(child);
+ expect(result.node).toEqual(child);
+ });
+});
+
+describe('getTypesFromPlatformSpecificFiles', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+ it('iterates through files array', async () => {
+ const typeName = 'typeName';
+ const child = {
+ name: typeName,
+ type: {
+ type: 'functions',
+ },
+ };
+ vi.mocked(getPackageAsTree).mockImplementation(() => {
+ return {
+ children: [child],
+ } as unknown as ProjectReflection;
+ });
+ const result = await getTypesFromPlatformSpecificUpscalerFiles([{
+ fileName: 'file1',
+ typeName,
+ }, {
+ fileName: 'file2',
+ typeName,
+ }]);
+
+ expect(result).toEqual([
+ expect.objectContaining({
+ declarationReflection: expect.any(DeclarationReflection),
+ browser: child,
+ node: child,
+ }),
+ expect.objectContaining({
+ declarationReflection: expect.any(DeclarationReflection),
+ browser: child,
+ node: child,
+ }),
+ ]);
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.ts
new file mode 100644
index 000000000..030972be1
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/get-types-from-platform-specific-upscaler-files.ts
@@ -0,0 +1,94 @@
+import { TFJSLibrary } from "@internals/common/tfjs-library";
+import { DeclarationReflection, ReflectionKind, SomeType } from "typedoc";
+import { getPackageAsTree } from "./get-package-as-tree.js";
+import { UPSCALER_DIR } from "@internals/common/constants";
+import path from "path";
+import { PlatformSpecificFileDeclarationReflection } from "../types.js";
+
+export interface PlatformSpecificFileDefinition {
+ fileName: string;
+ typeName: string;
+}
+
+const tfjsLibraries: TFJSLibrary[] = ['browser', 'node'];
+
+const reverseKindStringKey: Record = {
+ constructors: ReflectionKind.Constructor,
+ methods: ReflectionKind.Method,
+ interfaces: ReflectionKind.Interface,
+ types: ReflectionKind.TypeAlias,
+ classes: ReflectionKind.Class,
+ functions: ReflectionKind.Function,
+ enums: ReflectionKind.Enum,
+};
+
+export const makeDeclarationReflection = (typeName: string, type: SomeType): DeclarationReflection => {
+ if (type.type === 'union') {
+ // const childType = type.types?.[0];
+ // console.log(typeName, type.types);
+ // if (!childType) {
+ // throw new Error('No child type for union');
+ // }
+ // return makeDeclarationReflection(typeName, childType);
+ const declarationReflection = new DeclarationReflection(typeName, ReflectionKind.Interface);
+ declarationReflection.type = type;
+ return declarationReflection;
+ }
+ const kind = reverseKindStringKey[type.type];
+ if (kind === undefined) {
+ throw new Error(`Kind is undefined for type ${type.type}`);
+ }
+ const declarationReflection = new DeclarationReflection(typeName, kind);
+ declarationReflection.type = type;
+ return declarationReflection;
+};
+
+export const getPlatformSpecificUpscalerDeclarationReflections = (
+ tfjsLibrary: TFJSLibrary, {
+ fileName,
+ typeName,
+ }: PlatformSpecificFileDefinition
+): DeclarationReflection => {
+ // await scaffoldUpscaler(tfjsLibrary);
+ const { children } = getPackageAsTree(
+ path.resolve(UPSCALER_DIR, 'src', `${fileName}.${tfjsLibrary}.ts`),
+ path.resolve(UPSCALER_DIR, `tsconfig.docs.${tfjsLibrary}.json`),
+ UPSCALER_DIR,
+ );
+ const matchingType = children?.filter(child => child.name === typeName).pop();
+ if (!matchingType) {
+ throw new Error(`Could not find input from ${fileName}.${tfjsLibrary}.ts`);
+ }
+ return matchingType;
+};
+
+export const getTypesFromPlatformSpecificUpscalerFile = ({ fileName, typeName }: PlatformSpecificFileDefinition) => {
+ const [browser, node] = tfjsLibraries.map(tfjsLibrary => getPlatformSpecificUpscalerDeclarationReflections(tfjsLibrary, { fileName, typeName }));
+ if (browser.type?.type !== node.type?.type) {
+ throw new Error([
+ 'Some mismatch for file name',
+ fileName,
+ 'and type name',
+ typeName,
+ 'between browser type:',
+ `\n\n${JSON.stringify(browser.type)}\n\n`,
+ 'and node type:',
+ `\n\n${JSON.stringify(node.type)}`,
+ ].join(' '));
+ }
+
+ const type = browser.type;
+ if (!type) {
+ throw new Error('No type defined on browser type');
+ }
+
+ return {
+ declarationReflection: makeDeclarationReflection(typeName, type),
+ browser,
+ node,
+ };
+};
+
+export const getTypesFromPlatformSpecificUpscalerFiles = (
+ fileNames: PlatformSpecificFileDefinition[]
+): Promise => Promise.all(fileNames.map(getTypesFromPlatformSpecificUpscalerFile));
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-definitions/index.ts b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/index.ts
new file mode 100644
index 000000000..f2d6815bf
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-definitions/index.ts
@@ -0,0 +1 @@
+export { getDefinitions } from "./get-definitions.js";
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.test.ts b/internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.test.ts
new file mode 100644
index 000000000..d8cb2216a
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.test.ts
@@ -0,0 +1,48 @@
+import { ReflectionKind } from "typedoc";
+import { getSortedMethodsForWriting } from "./get-sorted-methods-for-writing.js";
+import { DecRef, Definitions } from "./types.js";
+
+describe('getSortedMethodsForWriting()', () => {
+ it('ignores a non-default class', () => {
+ const Class = {
+ name: 'class',
+ kind: ReflectionKind.Class,
+ children: [],
+ } as unknown as DecRef;
+ const definitions = {
+ classes: {
+ Class,
+ },
+ } as unknown as Definitions;
+ expect(getSortedMethodsForWriting(definitions)).toEqual([ ])
+ });
+
+ it('sorts children by line number', () => {
+ const srcLine1 = {
+ name: 'upscale',
+ sources: {
+ line: 1,
+ }
+ };
+ const srcLine0 = {
+ name: 'constructor',
+ sources: {
+ line: 0,
+ }
+ };
+ const Class = {
+ name: 'default',
+ kind: ReflectionKind.Class,
+ children: [srcLine1, srcLine0],
+ } as unknown as DecRef;
+ const definitions = {
+ classes: {
+ Class,
+ },
+ } as unknown as Definitions;
+ expect(getSortedMethodsForWriting(definitions)).toEqual([
+ srcLine1,
+ srcLine0,
+ ])
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.ts b/internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.ts
new file mode 100644
index 000000000..8c18652f8
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/get-sorted-methods-for-writing.ts
@@ -0,0 +1,24 @@
+import { DeclarationReflection } from "typedoc";
+import { DecRef, Definitions, isPlatformSpecificFileDeclarationReflection } from "./types.js";
+import { VALID_EXPORTS_FOR_WRITING_DOCS, VALID_METHODS_FOR_WRITING_DOCS } from "./constants.js";
+import { info } from "@internals/common/logger";
+import { sortChildrenByLineNumber } from "./sort-children-by-line-number.js";
+
+const getDecRef = (decRef: DecRef) => isPlatformSpecificFileDeclarationReflection(decRef) ? decRef.declarationReflection : decRef;
+
+export const getSortedMethodsForWriting = (definitions: Definitions): DeclarationReflection[] => {
+ const decRefs = Object.values(definitions.classes);
+ const methods: DeclarationReflection[] = [];
+ for (const { name, children = [] } of decRefs.map(getDecRef)) {
+ if (VALID_EXPORTS_FOR_WRITING_DOCS.includes(name)) {
+ sortChildrenByLineNumber(children).forEach(method => {
+ if (VALID_METHODS_FOR_WRITING_DOCS.includes(method.name)) {
+ methods.push(method);
+ } else {
+ info(`** Ignoring method ${method.name}`);
+ }
+ });
+ }
+ }
+ return methods;
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.test.ts b/internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.test.ts
new file mode 100644
index 000000000..2efcffc71
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.test.ts
@@ -0,0 +1,46 @@
+import { vi, } from 'vitest';
+import { DeclarationReflection, SourceReference } from "typedoc";
+import { sortChildrenByLineNumber } from "./sort-children-by-line-number.js";
+
+const getMockDeclarationReflection = (...sources: Partial[]): DeclarationReflection => {
+ return {
+ sources,
+ } as unknown as DeclarationReflection;
+};
+
+describe('sortChildrenByLineNumber', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('sorts children', () => {
+ const line1 = getMockDeclarationReflection({
+ line: 1,
+ });
+ const line0 = getMockDeclarationReflection({
+ line: 0,
+ });
+ const line2 = getMockDeclarationReflection({
+ line: 2,
+ });
+ expect(sortChildrenByLineNumber([
+ line1,
+ line2,
+ line0,
+ ])).toEqual([line0, line1, line2]);
+ });
+
+ it('returns sources before no sources', () => {
+ const linefoo = getMockDeclarationReflection();
+ const linebar = getMockDeclarationReflection();
+ const line2 = getMockDeclarationReflection({
+ line: 2,
+ });
+ expect(sortChildrenByLineNumber([
+ linefoo,
+ line2,
+ linebar,
+ ])).toEqual([line2, linefoo, linebar]);
+ });
+});
+
diff --git a/internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.ts b/internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.ts
new file mode 100644
index 000000000..ba35a5a0a
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/sort-children-by-line-number.ts
@@ -0,0 +1,13 @@
+import { DeclarationReflection } from "typedoc";
+
+export function sortChildrenByLineNumber(children: DeclarationReflection[]) {
+ return children.sort(({ sources: aSrc }, { sources: bSrc }) => {
+ if (!aSrc?.length) {
+ return 1;
+ }
+ if (!bSrc?.length) {
+ return -1;
+ }
+ return aSrc[0].line - bSrc[0].line;
+ });
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/types.ts b/internals/scripts/src/bin/write/docs/api/lib/types.ts
new file mode 100644
index 000000000..f88beaafa
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/types.ts
@@ -0,0 +1,49 @@
+import {
+ ArrayType,
+ DeclarationReflection,
+ IntersectionType,
+ IntrinsicType,
+ LiteralType,
+ ReferenceType,
+ SomeType,
+ UnionType,
+} from "typedoc";
+
+export interface PlatformSpecificFileDeclarationReflection {
+ declarationReflection: DeclarationReflection;
+ browser: DeclarationReflection;
+ node: DeclarationReflection;
+}
+
+export type DecRef = DeclarationReflection | PlatformSpecificFileDeclarationReflection;
+export interface Definitions {
+ constructors: Record;
+ methods: Record;
+ interfaces: Record;
+ types: Record;
+ classes: Record;
+ functions: Record;
+ enums: Record;
+}
+
+export const isPlatformSpecificFileDeclarationReflection = (
+ child: DeclarationReflection | PlatformSpecificFileDeclarationReflection
+): child is PlatformSpecificFileDeclarationReflection => 'browser' in child;
+
+export const isDeclarationReflection = (reflection?: DecRef): reflection is DeclarationReflection => reflection !== undefined && !isPlatformSpecificFileDeclarationReflection(reflection);
+export const isArrayType = (type: SomeType): type is ArrayType => type.type === 'array';
+export const isReferenceType = (type: SomeType): type is ReferenceType => type.type === 'reference';
+export const isLiteralType = (type: SomeType): type is LiteralType => type.type === 'literal';
+export const isInstrinsicType = (type: SomeType): type is IntrinsicType => type.type === 'intrinsic';
+export const isUnionType = (type: SomeType): type is UnionType => type.type === 'union';
+export const isIntersectionType = (type: SomeType): type is IntersectionType => type.type === 'intersection';
+export const getLiteralTypeValue = (type: LiteralType): string => {
+ const { value } = type;
+ if (typeof value === 'number') {
+ return `${value}`;
+ } else if (typeof value === 'string') {
+ return value;
+ }
+
+ throw new Error('Not yet implemented for literal');
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-docs.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-docs.ts
new file mode 100644
index 000000000..4e9febe51
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-docs.ts
@@ -0,0 +1,15 @@
+import { getDefinitions } from './get-definitions/index.js';
+import { getSortedMethodsForWriting } from './get-sorted-methods-for-writing.js';
+import { writeIndexFile } from './write-index-file.js';
+import { writeAPIDocumentationFiles } from './write-api-documentation-files/index.js';
+
+export async function writeAPIDocs(dest: string) {
+ return;
+ const definitions = await getDefinitions();
+ const methods = getSortedMethodsForWriting(definitions);
+
+ await Promise.all([
+ writeAPIDocumentationFiles(dest, methods, definitions),
+ writeIndexFile(dest, methods),
+ ]);
+}
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-content-for-method.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-content-for-method.ts
new file mode 100644
index 000000000..56cdc75ce
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-content-for-method.ts
@@ -0,0 +1,85 @@
+import { DeclarationReflection, SignatureReflection, TypeParameterReflection } from 'typedoc';
+import { getSource } from './get-source.js';
+import { getTextSummary } from './get-text-summary.js';
+import { getParameters } from './write-parameter.js';
+import { getReturnType } from './get-return-type.js';
+import { EXPANDED_TYPE_CONTENT, TYPES_TO_EXPAND } from '../constants.js';
+import { Definitions } from '../types.js';
+
+function getAsObj (arr: T[], getKey: (item: T) => string) {
+ return arr.reduce((obj, item) => ({
+ ...obj,
+ [getKey(item)]: item,
+ }), {} as Record);
+}
+
+const writeExpandedTypeDefinitions = (methodName: string, definitions: Definitions, typeParameters: Record = {}): string => {
+ // this method is for writing out additional information on the types, below the parameters
+ const typesToExpand: string[] = TYPES_TO_EXPAND[methodName === 'constructor' ? '_constructor' : methodName] || [];
+ return typesToExpand.map(type => [
+ `### \`${type}\``,
+ EXPANDED_TYPE_CONTENT[type](definitions, typeParameters),
+ ].join('\n')).join('\n');
+}
+
+export const getContentForMethod = async (method: DeclarationReflection, definitions: Definitions, i: number) => {
+ const {
+ name,
+ signatures,
+ sources,
+ } = method;
+
+ if (name === 'upscale') {
+ return [
+ [
+ '---',
+ `title: ${name}`,
+ `sidebar_position: ${i}`,
+ `sidebar_label: ${name}`,
+ '---',
+ ].join('\n'),
+
+ `# ${name}`,
+ 'Alias for [`execute`](execute)',
+ ].filter(Boolean).join('\n\n');
+
+ }
+
+ if (!sources?.length) {
+ throw new Error(`No sources found for ${name}`);
+ }
+ if (!signatures?.length) {
+ const { type: _type } = method;
+ throw new Error(`No signatures found in ${name}`);
+ }
+ const signature = signatures[0] as SignatureReflection & { typeParameter?: TypeParameterReflection[] };
+ const { comment, parameters, typeParameter: typeParameters } = signature;
+
+ const { description, codeSnippet, blockTags } = getTextSummary(name, comment);
+ const source = await getSource(sources);
+
+ const content = [
+ [
+ '---',
+ `title: ${name}`,
+ `sidebar_position: ${i}`,
+ `sidebar_label: ${name}`,
+ '---',
+ ].join('\n'),
+`# \`${name}\``,
+ description,
+ ...(codeSnippet ? [
+ '## Example',
+ codeSnippet,
+ ] : []),
+ source,
+ ...(parameters ? [
+ '## Parameters',
+ getParameters(name, parameters, definitions, getAsObj(typeParameters || [], t => t.name)),
+ ] : []),
+ writeExpandedTypeDefinitions(name, definitions, getAsObj(typeParameters || [], t => t.name)),
+ '## Returns',
+ getReturnType(signatures, blockTags),
+ ].filter(Boolean).join('\n\n');
+ return content;
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.test.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.test.ts
new file mode 100644
index 000000000..80851162a
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.test.ts
@@ -0,0 +1,189 @@
+import { ArrayType, DeclarationReflection, ReflectionKind } from "typedoc";
+import { getMatchingType } from "./get-matching-type.js";
+import { getReferenceTypeOfParameter } from "./get-reference-type-of-parameter.js";
+import * as constants from "../constants.js";
+import { Definitions, isLiteralType } from "../types.js";
+
+vi.mock('../types.js', async () => {
+ const actualTypes = await import('../types.js');
+ return {
+ ...actualTypes,
+ isLiteralType: vi.fn().mockImplementation(() => false),
+ }
+});
+
+vi.mock('../constants.js', () => ({
+ INTRINSIC_TYPES: [],
+ EXTERNALLY_DEFINED_TYPES: [],
+}));
+
+vi.mock('./get-reference-type-of-parameter.js', () => ({
+ getReferenceTypeOfParameter: vi.fn(),
+}));
+
+const makeNewExternalType = (name: string, _url: string): DeclarationReflection => {
+ const type = new DeclarationReflection(name, ReflectionKind['SomeType']);
+ type.sources = [];
+ return type;
+};
+
+const Interface = {
+ name: 'Interface',
+ kind: ReflectionKind.Interface,
+};
+const TypeAlias = {
+ name: 'TypeAlias',
+ kind: ReflectionKind.TypeAlias,
+};
+const mockDefinitions = (): Definitions => {
+ const Constructor = {
+ name: 'Constructor',
+ kind: ReflectionKind.Constructor,
+ };
+ const Method = {
+ name: 'Method',
+ kind: ReflectionKind.Method,
+ };
+ const Class = {
+ name: 'Class',
+ kind: ReflectionKind.Class,
+ };
+ const Function = {
+ name: 'Function',
+ kind: ReflectionKind.Function,
+ };
+ const Enum = {
+ name: 'Enum',
+ kind: ReflectionKind.Enum,
+ };
+ const PlatformSpecific = {
+ declarationReflection: {
+ name: 'PlatformSpecific',
+ kind: ReflectionKind.Constructor,
+ },
+ browser: {},
+ node: {},
+ };
+ return {
+ methods: {
+ Method,
+ },
+ constructors: {
+ Constructor,
+ PlatformSpecific,
+ },
+ functions: {
+ Function,
+ },
+ types: {
+ TypeAlias,
+ },
+ interfaces: {
+ Interface,
+ },
+ classes: {
+ Class,
+ },
+ enums: {
+ Enum,
+ },
+ } as unknown as Definitions;
+}
+
+describe('getMatchingType', () => {
+ beforeEach(() => {
+ vi.spyOn(constants, 'INTRINSIC_TYPES', 'get').mockReturnValue([]);
+ vi.spyOn(constants, 'EXTERNALLY_DEFINED_TYPES', 'get').mockReturnValue({});
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('returns undefined if intrinsic types includes the name of the type definition', () => {
+ const definitions = mockDefinitions();
+ const parameter = new DeclarationReflection('foo', ReflectionKind.Parameter);
+ constants.INTRINSIC_TYPES.push('foo');
+ vi.mocked(getReferenceTypeOfParameter).mockImplementation(() => ({
+ name: 'foo',
+ type: 'literal',
+ }) as ReturnType);
+ expect(getMatchingType(parameter, definitions, {})).toEqual(undefined);
+ });
+
+ it('returns undefined if parameter type is undefined', () => {
+ const definitions = mockDefinitions();
+ const parameter = new DeclarationReflection('foo', ReflectionKind.Parameter);
+ parameter.type = undefined;
+ vi.mocked(getReferenceTypeOfParameter).mockImplementation(() => ({
+ name: 'foo',
+ type: 'literal'
+ }) as ReturnType);
+ expect(getMatchingType(parameter, definitions, {})).toEqual(undefined);
+ });
+
+ it('returns undefined if it is a literal type', () => {
+ const definitions = mockDefinitions();
+ const parameter = new DeclarationReflection('foo', ReflectionKind.Parameter);
+ parameter.type = { type: 'array' } as ArrayType;
+ vi.mocked(getReferenceTypeOfParameter).mockImplementation(() => ({
+ name: 'foo',
+ type: 'literal'
+ }) as ReturnType);
+ vi.mocked(isLiteralType).mockImplementation(() => true)
+ expect(getMatchingType(parameter, definitions, {})).toEqual(undefined);
+ });
+
+ it('returns an externally defined type if defined', () => {
+ const definitions = mockDefinitions();
+ const parameter = new DeclarationReflection('foo', ReflectionKind.Parameter);
+ parameter.type = { type: 'array' } as ArrayType;
+ const externalType = makeNewExternalType('Foo', 'https://foo.com');
+ vi.spyOn(constants, 'EXTERNALLY_DEFINED_TYPES', 'get').mockReturnValue({
+ Foo: externalType,
+ });
+ vi.mocked(getReferenceTypeOfParameter).mockImplementation(() => ({
+ name: 'Foo',
+ type: 'literal'
+ }) as ReturnType);
+ expect(getMatchingType(parameter, definitions, {})).toEqual(externalType);
+ });
+
+ it('returns a type defined on an interface', () => {
+ const definitions = mockDefinitions();
+ const parameter = new DeclarationReflection('foo', ReflectionKind.Parameter);
+ parameter.type = { type: 'array' } as ArrayType;
+ vi.mocked(getReferenceTypeOfParameter).mockImplementation(() => ({
+ name: Interface.name,
+ type: 'literal'
+ }) as ReturnType);
+ expect(getMatchingType(parameter, definitions, {})).toEqual(Interface);
+ });
+
+ it('returns a type defined on a types', () => {
+ const definitions = mockDefinitions();
+ const parameter = new DeclarationReflection('foo', ReflectionKind.Parameter);
+ parameter.type = { type: 'array' } as ArrayType;
+ vi.mocked(getReferenceTypeOfParameter).mockImplementation(() => ({
+ name: TypeAlias.name,
+ type: 'literal'
+ }) as ReturnType);
+ expect(getMatchingType(parameter, definitions, {})).toEqual(TypeAlias);
+ });
+
+ // it('returns a type parameter if defined', () => {
+ // const definitions = mockDefinitions();
+ // const parameter = new DeclarationReflection('parameter', ReflectionKind.Parameter);
+ // // parameter.type = 'foo';
+ // vi.mocked(getReferenceTypeOfParameter).mockImplementation(() => ({
+ // name: 'foo',
+ // type: 'literal' as 'literal',
+ // }));
+ // const reflection = new DeclarationReflection('bar', ReflectionKind.Class);
+ // const typeReflection = new TypeParameterReflection('foo', reflection, undefined);
+ // expect(getMatchingType(parameter, definitions, {
+ // foo: typeReflection,
+ // })).toEqual();
+ // });
+});
+
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.ts
new file mode 100644
index 000000000..c632dd74a
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-matching-type.ts
@@ -0,0 +1,64 @@
+import { DeclarationReflection, ParameterReflection, TypeParameterReflection } from "typedoc";
+import { DecRef, Definitions, isLiteralType, isPlatformSpecificFileDeclarationReflection, isUnionType } from "../types.js";
+import { EXTERNALLY_DEFINED_TYPES, INTRINSIC_TYPES } from "../constants.js";
+import { warn } from "@internals/common/logger";
+import { getReferenceTypeOfParameter } from "./get-reference-type-of-parameter.js";
+
+/**
+ * getMatchingType returns the matching type for a given parameter.
+ *
+ * It looks through the definitions tree, along with externally defined types
+ */
+
+export const getMatchingType = (
+ parameter: ParameterReflection | DeclarationReflection,
+ definitions: Definitions,
+ typeParameters: Record = {}
+): undefined | DecRef => {
+ const { classes, interfaces, types } = definitions;
+ let { name: nameOfTypeDefinition } = getReferenceTypeOfParameter(parameter.type, definitions);
+ if (INTRINSIC_TYPES.includes(nameOfTypeDefinition)) {
+ return undefined;
+ }
+ if (parameter.type === undefined) {
+ return undefined;
+ }
+ if (isLiteralType(parameter.type)) {
+ return undefined;
+ }
+ // first, check if it is a specially defined external type
+ const externallyDefinedType = EXTERNALLY_DEFINED_TYPES[nameOfTypeDefinition] || interfaces[nameOfTypeDefinition] || types[nameOfTypeDefinition];
+ if (externallyDefinedType) {
+ return externallyDefinedType;
+ }
+
+ // it's possible that this type is a generic type; in which case, replace the generic with the actual type it's extending
+ // this is _UGLY_
+ const typeParameterType = typeParameters[nameOfTypeDefinition];
+ if (typeParameterType && typeParameterType.type !== undefined && 'name' in typeParameterType.type) {
+ nameOfTypeDefinition = typeParameterType.type.name;
+ const matchingType = interfaces[nameOfTypeDefinition] || types[nameOfTypeDefinition];
+ parameter.type = isPlatformSpecificFileDeclarationReflection(matchingType) ? matchingType.declarationReflection.type : matchingType.type;
+ return matchingType;
+ }
+ if (!isUnionType(parameter.type)) {
+ let matchingDefKey: string | undefined;
+ for (const [definitionKey, defs] of Object.entries(definitions)) {
+ for (const key of Object.keys(defs)) {
+ if (key === nameOfTypeDefinition) {
+ matchingDefKey = definitionKey;
+ }
+ }
+ }
+ warn([
+ `No matching type could be found for ${nameOfTypeDefinition} in interfaces, types, or classes.`,
+ matchingDefKey ? `However, it was found in ${matchingDefKey}.` : undefined,
+ `- Available interfaces: ${Object.keys(interfaces).join(', ')}`,
+ `- Available types: ${Object.keys(types).join(', ')}`,
+ `- Available classes: ${Object.keys(classes).join(', ')}`,
+ 'Parameter type:',
+ JSON.stringify(parameter.type),
+ ].join('\n'));
+ }
+ return undefined;
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-reference-type-of-parameter.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-reference-type-of-parameter.ts
new file mode 100644
index 000000000..bdb892b2a
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-reference-type-of-parameter.ts
@@ -0,0 +1,157 @@
+import { SomeType, UnionType } from "typedoc";
+import { Definitions, getLiteralTypeValue, isArrayType, isDeclarationReflection, isInstrinsicType, isIntersectionType, isLiteralType, isReferenceType, isUnionType } from "../types.js";
+import { info, warn } from "@internals/common/logger";
+
+export const getReferenceTypeOfParameter = (_type?: SomeType, definitions?: Definitions): {
+ type: 'reference' | 'array' | 'literal' | 'intrinsic' | 'union',
+ name: string;
+ includeURL?: boolean;
+} => {
+ if (!_type) {
+ throw new Error('Define a type');
+ }
+ if (isArrayType(_type)) {
+ const { elementType } = _type;
+ if (isReferenceType(elementType)) {
+ return {
+ type: _type.type,
+ name: elementType.name,
+ }
+ } else if (isUnionType(elementType)) {
+ return {
+ type: 'union',
+ name: elementType.types.map(t => {
+ if ('name' in t) {
+ return t.name;
+ }
+ throw new Error('unimplemented');
+ }).join(' | '),
+ };
+ }
+
+ throw new Error('Not yet implemented');
+ }
+
+ if (isReferenceType(_type)) {
+ const { name } = _type;
+ if (name === 'ModelDefinitionObjectOrFn') {
+ return {
+ type: _type.type,
+ name: "ModelDefinition",
+ };
+ }
+ return {
+ type: _type.type,
+ name,
+ };
+ }
+
+ if (isLiteralType(_type)) {
+ return {
+ type: 'literal',
+ name: getLiteralTypeValue(_type),
+ };
+ }
+
+ if (isInstrinsicType(_type)) {
+ return {
+ type: 'intrinsic',
+ name: _type.name,
+ }
+ }
+
+ if (isIntersectionType(_type)) {
+ const refType = _type.types.filter(t => t.type === 'reference').pop();
+ if (!refType || !isReferenceType(refType)) {
+ throw new Error('No reference type found on intersection type.');
+ }
+ // if (definitions === undefined) {
+ // throw new Error('Intersection type was provided and a reference type was found in the union, but no definitions are present.')
+ // }
+ const intersectionType = refType.typeArguments?.filter(t => t.type === 'reference').pop();
+ if (!intersectionType || !('name' in intersectionType)) {
+ throw new Error('No type arguments found on intersection type.');
+ }
+ return {
+ type: 'literal',
+ name: intersectionType.name,
+ };
+ }
+
+ if (isUnionType(_type)) {
+ let includeURL = true;
+
+ const getNameFromUnionType = (type: UnionType): string => type.types.map(t => {
+ if (isReferenceType(t)) {
+ if (definitions === undefined) {
+ warn('Union type was provided and a reference type was found in the union, but no definitions are present.');
+ return t.name;
+ }
+ const { interfaces, types } = definitions;
+ const matchingType = interfaces[t.name] || types[t.name];
+ if (!isDeclarationReflection(matchingType)) {
+ throw new Error('Is a platform specific type');
+ }
+ if (!matchingType?.type) {
+ return t.name;
+ // throw new Error(`No matching type found for literal ${t.name} in union`);
+ }
+ const matchingTypeType = matchingType.type;
+ if (isLiteralType(matchingTypeType)) {
+ // if any literal types are included, don't include the URL
+ includeURL = false;
+ return JSON.stringify(matchingTypeType.value);
+ }
+ if (matchingTypeType.type === 'reflection') {
+ // Ignore reflection types
+ return t.name;
+ }
+ if (matchingTypeType.type === 'union') {
+ return getNameFromUnionType(matchingTypeType);
+ }
+ if (matchingTypeType.type === 'tuple') {
+ info('matchingTypeType tuple', matchingTypeType);
+ return `[${matchingTypeType.elements?.map(e => {
+ if ('name' in e) {
+ return e.name;
+ }
+ throw new Error('Array type not yet implemented');
+ }).join(',')}]`;
+ }
+ throw new Error(`Unsupported type of matching type ${matchingTypeType.type} in reference type of union type ${t.name}.`);
+ } else if (isInstrinsicType(t)) {
+ if (t.name === 'undefined') {
+ // ignore an explicit undefined type; this should be better represented to the user as an optional flag.
+ return undefined;
+ }
+ return t.name;
+ } else if (isLiteralType(t)) {
+ return `${t.value}`;
+ } else if (t.type === 'indexedAccess') {
+ const objectType = t.objectType;
+ if ('name' in objectType) {
+ return objectType.name;
+ }
+ return '';
+ } else if (t.type === 'array') {
+ if ('name' in t.elementType) {
+ return `${t.elementType.name}[]`;
+ }
+ warn('Unknown element type', t);
+ // throw new Error('Unknown element type');
+ return '';
+ }
+ throw new Error(`Unsupported type in union type: ${t.type}`);
+ }).filter(Boolean).join(' | ');
+
+ const name = getNameFromUnionType(_type);
+
+ return {
+ type: 'literal',
+ includeURL,
+ name,
+ };
+ }
+
+ throw new Error(`Unsupported type: ${_type.type}`)
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-return-type.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-return-type.ts
new file mode 100644
index 000000000..9c75fcb5f
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-return-type.ts
@@ -0,0 +1,80 @@
+import { CommentTag, SignatureReflection, TypeParameterReflection } from "typedoc";
+import { isInstrinsicType, isReferenceType, isUnionType } from "../types.js";
+import { getReferenceTypeOfParameter } from "./get-reference-type-of-parameter.js";
+
+export const getReturnType = (signatures: (SignatureReflection & { typeParameter?: TypeParameterReflection[] })[], blockTags?: Record) => {
+ if (signatures.length === 1) {
+ const { type } = signatures[0];
+ if (type === undefined) {
+ return 'void';
+ }
+
+ if (isReferenceType(type)) {
+ const { name, typeArguments } = type;
+ let nameOfType = name;
+ if (typeArguments?.length) {
+ nameOfType = `${nameOfType}<${typeArguments.map(t => getReferenceTypeOfParameter(t)).map(({ name }) => name).join(', ')}>`;
+ }
+ const returnDescription = blockTags?.['@returns']?.map(({ text }) => text).join('');
+ return `\`${nameOfType}\`${returnDescription ? ` - ${returnDescription}` : ''}`;
+ }
+
+ if (isInstrinsicType(type)) {
+ const nameOfType = type.name;
+ const returnDescription = blockTags?.['@returns']?.map(({ text }) => text).join('');
+ return `\`${nameOfType}\`${returnDescription ? ` - ${returnDescription}` : ''}`;
+ }
+
+ throw new Error(`Return Type function not yet implemented for type ${type.type}`)
+ }
+
+ // let comment: Comment;
+ let commentSeen = false;
+ const validReturnTypes = new Set();
+ let returnType = '';
+ signatures.forEach(signature => {
+ if (signature.comment) {
+ if (commentSeen) {
+ throw new Error('Multiple comments defined for return signatures');
+ }
+ commentSeen = true;
+ // comment = signature.comment;
+ }
+ const { type } = signature;
+ if (type === undefined) {
+ throw new Error('No type defined for signature');
+ }
+ if (!isReferenceType(type)) {
+ throw new Error(`Unsupported type: ${type.type}`);
+ }
+ if (returnType !== '' && returnType !== type.name) {
+ throw new Error(`Conflicting return types in signatures: ${returnType} vs ${type.name}}`)
+ }
+ returnType = type.name;
+ if (!('typeArguments' in type)) {
+ throw new Error('No type arguments defined for type');
+ }
+ const { typeArguments } = type;
+ typeArguments?.forEach(type => {
+ if (isUnionType(type)) {
+ type.types.forEach(t => {
+ if (isInstrinsicType(t) || isReferenceType(t)) {
+ validReturnTypes.add(t.name);
+ } else {
+ throw new Error(`Unsupported type when trying to handle union type while collecting valid signatures: ${type.type} ${t.type}`);
+ }
+ });
+ } else if (isInstrinsicType(type)) {
+ validReturnTypes.add(type.name);
+ } else if (isReferenceType(type)) {
+ validReturnTypes.add(type.name);
+ } else {
+ throw new Error(`Unsupported type when trying to collect valid signatures: ${type.type}`);
+ }
+ });
+ })
+
+ const nameOfType = `${returnType}<${Array.from(validReturnTypes).join(' | ')}>`;
+ const returnDescription = blockTags?.['@returns']?.map(({ text }) => text).join('');
+ return `\`${nameOfType}\`${returnDescription ? ` - ${returnDescription}` : ''}`;
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-source.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-source.ts
new file mode 100644
index 000000000..16b8ab26c
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-source.ts
@@ -0,0 +1,20 @@
+import { SourceReference } from "typedoc";
+import { REPO_ROOT, TEMPLATES_DIR } from "../constants.js";
+import { getTemplate } from "@internals/common/get-template";
+import { rewriteURL } from "./get-url-from-sources.js";
+import path from "path";
+
+export const getSource = ([source]: SourceReference[]) => {
+ let {
+ fileName,
+ line,
+ url,
+ } = source;
+ url = `${REPO_ROOT}/blob/main/${fileName}#L${line}`;
+ const prettyFileName = fileName.split('packages/upscalerjs/src/').pop();
+ return getTemplate(path.resolve(TEMPLATES_DIR, 'source.md.t'), {
+ prettyFileName,
+ line,
+ url: rewriteURL(url),
+ });
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.test.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.test.ts
new file mode 100644
index 000000000..5dc3606d0
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.test.ts
@@ -0,0 +1,47 @@
+import { Comment } from "typedoc";
+import { getTextSummary } from "./get-text-summary.js";
+
+describe('getTextSummary', () => {
+ it('returns an empty object for an undefined comment', () => {
+ expect(getTextSummary('foo')).toEqual({});
+ });
+
+ it('throws an error if receiving an empty summary', () => {
+ expect(() => getTextSummary('foo', {
+ summary: [],
+ blockTags: [],
+ } as unknown as Comment)).toThrow('Expected code snippet not found for foo');
+ });
+
+ it('throws an error if receiving a summary with kind not code', () => {
+ expect(() => getTextSummary('foo', {
+ summary: [{
+ kind: 'foo',
+ }],
+ blockTags: [],
+ } as unknown as Comment)).toThrow('Expected code snippet not found for foo');
+ });
+
+ it('returns a text summary', () => {
+ expect(getTextSummary('foo', {
+ summary: [{
+ kind: 'code',
+ text: 'foo',
+ }, {
+ kind: 'code',
+ text: 'bar',
+ }],
+ blockTags: [{
+ tag: 'baz',
+ content: 'qux',
+ }],
+ } as unknown as Comment)).toEqual({
+ blockTags: {
+ baz: 'qux',
+ },
+ description: 'foo',
+ codeSnippet: 'bar',
+
+ });
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.ts
new file mode 100644
index 000000000..db7835354
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-text-summary.ts
@@ -0,0 +1,25 @@
+import { Comment, CommentDisplayPart } from "typedoc";
+
+export const getTextSummary = (name: string, comment?: Comment): {
+ codeSnippet?: string;
+ description?: string;
+ blockTags?: Record;
+} => {
+ if (comment === undefined) {
+ return {};
+ }
+ const { summary, blockTags } = comment;
+ const expectedCodeSnippet = summary.pop();
+ if (expectedCodeSnippet?.kind !== 'code') {
+ throw new Error(`Expected code snippet not found for ${name}`);
+ }
+ const text = summary.map(({ text }) => text).join('');
+ return {
+ blockTags: blockTags?.reduce>((obj, { tag, content }) => ({
+ ...obj,
+ [tag]: content,
+ }), {}),
+ description: text.trim(),
+ codeSnippet: expectedCodeSnippet.text.trim(),
+ }
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.test.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.test.ts
new file mode 100644
index 000000000..97d765b4e
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.test.ts
@@ -0,0 +1,53 @@
+import { DeclarationReflection, SourceReference } from "typedoc";
+import { DecRef } from "../types.js";
+import { getURLFromSources, rewriteURL } from "./get-url-from-sources.js";
+
+describe('rewriteURL', () => {
+ it('rewrites the URL', () => {
+ const URL = 'https://github.com/thekevinscott/UpscalerJS/blob/foobabaz/packages/upscalerjs/foo.setup.ts';
+ expect(rewriteURL(URL)).toEqual([
+ "https://github.com/thekevinscott/UpscalerJS/",
+ "tree/main",
+ "/packages/upscalerjs/foo.setup.ts",
+ ].join(''));
+ });
+
+ it('throws if given a non-matching url', () => {
+ const URL = 'https://github.com/thekevinscott/UpscalerJS/foobabaz/packages/upscalerjs/foo.setup.ts';
+ expect(() => rewriteURL(URL)).toThrow();
+ });
+});
+
+describe('getURLFromSources', () => {
+ it('returns undefined if no matching type is provided', () => {
+ expect(getURLFromSources(undefined)).toEqual(undefined);
+ });
+
+ it('returns undefined if sources is not available', () => {
+ expect(getURLFromSources({} as DecRef)).toEqual(undefined);
+ });
+
+ it('returns undefined if sources is empty', () => {
+ expect(getURLFromSources({
+ sources: [] as SourceReference[],
+ } as DeclarationReflection)).toEqual(undefined);
+ });
+
+ it('returns rewritten URL if beginning with repo root', () => {
+ const url = 'https://github.com/thekevinscott/UpscalerJS/blob/foobabaz/packages/upscalerjs/foo.setup.ts';
+ expect(getURLFromSources({
+ sources: [{
+ url,
+ }] as SourceReference[],
+ } as DecRef)).toEqual(rewriteURL(url));
+ });
+
+ it('returns unrewritten URL if not beginning with repo root', () => {
+ const url = 'foo.com';
+ expect(getURLFromSources({
+ sources: [{
+ url,
+ }] as SourceReference[],
+ } as DecRef)).toEqual(url);
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.ts
new file mode 100644
index 000000000..3e83e6344
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/get-url-from-sources.ts
@@ -0,0 +1,30 @@
+import { TypeParameterReflection } from "typedoc";
+import { DecRef } from "../types.js";
+import { REPO_ROOT } from "../constants.js";
+
+export const rewriteURL = (url: string) => {
+ const parts = url.split(/blob\/(?[^/]+)/)
+ if (parts.length !== 3) {
+ throw new Error(`Error with the regex: ${url}`);
+ }
+ return [
+ parts[0],
+ 'tree/main',
+ parts[2],
+ ].join('');
+};
+
+export const getURLFromSources = (matchingType: undefined | DecRef | TypeParameterReflection) => {
+ if (!matchingType) {
+ return undefined;
+ }
+ if ('sources' in matchingType) {
+ const sources = matchingType.sources;
+ if (sources?.length) {
+ const { url } = sources[0];
+ return url?.startsWith(REPO_ROOT) ? rewriteURL(url) : url;
+ }
+ }
+
+ return undefined;
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/index.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/index.ts
new file mode 100644
index 000000000..bcc7c0983
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/index.ts
@@ -0,0 +1 @@
+export { writeAPIDocumentationFiles } from "./write-api-documentation-files.js";
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.test.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.test.ts
new file mode 100644
index 000000000..090a8e599
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.test.ts
@@ -0,0 +1,51 @@
+import { writeAPIDocumentationFiles } from "./write-api-documentation-files.js";
+import { mkdirp, writeFile } from "@internals/common/fs";
+import { getContentForMethod } from './get-content-for-method.js';
+import { Definitions } from "../types.js";
+import { DeclarationReflection } from "typedoc";
+
+vi.mock('@internals/common/fs', () => ({
+ writeFile: vi.fn(),
+ mkdirp: vi.fn(),
+}));
+
+vi.mock('./get-content-for-method.js', () => ({
+ getContentForMethod: vi.fn(),
+}));
+
+describe('writeAPIDocumentationFiles', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('it to write API documentation files', async () => {
+ vi.mocked(getContentForMethod).mockResolvedValue('foobarbaz');
+ await writeAPIDocumentationFiles('/out', [{
+ name: 'foo'
+ } as DeclarationReflection], {} as unknown as Definitions);
+ expect(getContentForMethod).toHaveBeenCalled();
+ expect(mkdirp).toHaveBeenCalledWith('/out');
+ expect(writeFile).toHaveBeenCalledWith('/out/foo.md', 'foobarbaz');
+ });
+
+ it('it to write API documentation files for multiple methods', async () => {
+ vi.mocked(getContentForMethod).mockResolvedValue('foobarbaz');
+ await writeAPIDocumentationFiles('/out', [{
+ name: 'foo'
+ }, {
+ name: 'bar',
+ }] as DeclarationReflection[], {} as unknown as Definitions);
+ expect(getContentForMethod).toHaveBeenCalledTimes(2);
+ expect(writeFile).toHaveBeenCalledWith('/out/foo.md', 'foobarbaz');
+ expect(writeFile).toHaveBeenCalledWith('/out/bar.md', 'foobarbaz');
+ });
+
+ it('it to throw if no content is returned', async () => {
+ vi.mocked(getContentForMethod).mockResolvedValue('');
+ await expect(() => writeAPIDocumentationFiles('/out', [{
+ name: 'foo'
+ }, {
+ name: 'bar',
+ }] as DeclarationReflection[], {} as unknown as Definitions)).rejects.toThrow();
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.ts
new file mode 100644
index 000000000..c9183e8af
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-api-documentation-files.ts
@@ -0,0 +1,22 @@
+import path from 'path';
+import { mkdirp, writeFile } from '@internals/common/fs';
+import { getContentForMethod } from './get-content-for-method.js';
+import { Definitions } from '../types.js';
+import { DeclarationReflection } from 'typedoc';
+import { verbose } from '@internals/common/logger';
+
+export const writeAPIDocumentationFiles = async (dest: string, methods: DeclarationReflection[], definitions: Definitions) => {
+ await Promise.all(methods.map(async (method, i) => {
+ verbose('Getting content for method', method.name);
+ const content = await getContentForMethod(method, definitions, i);
+ verbose('Content for method', method.name, 'measures', content.length);
+ if (!content) {
+ throw new Error(`No content for method ${method.name}`);
+ }
+ const target = path.resolve(dest, `${method.name}.md`);
+ await mkdirp(path.dirname(target));
+ await writeFile(target, content.trim());
+ verbose('Wrote content for method', method.name, 'to', target);
+ }));
+};
+
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-parameter.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-parameter.ts
new file mode 100644
index 000000000..6bc3732aa
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-parameter.ts
@@ -0,0 +1,90 @@
+import { Comment, DeclarationReflection, ParameterReflection, TypeParameterReflection } from "typedoc";
+import { DecRef, Definitions, PlatformSpecificFileDeclarationReflection, isDeclarationReflection, isPlatformSpecificFileDeclarationReflection } from "../types.js";
+import { getReferenceTypeOfParameter } from "./get-reference-type-of-parameter.js";
+import { getURLFromSources } from "./get-url-from-sources.js";
+import { sortChildrenByLineNumber } from "../sort-children-by-line-number.js";
+import { getMatchingType } from "./get-matching-type.js";
+import { TYPES_TO_EXPAND } from "../constants.js";
+
+export const getSummary = (comment?: Comment) => comment?.summary.map(({ text }) => text).join('');
+
+type MatchingType = undefined | DecRef | TypeParameterReflection;
+type Parameter = ParameterReflection | DeclarationReflection;
+
+const writeParameter = (
+ methodName: string,
+ parameter: Parameter,
+ matchingType: MatchingType,
+ definitions: Definitions,
+ childParameters: string
+) => {
+ const comment = getSummary(parameter.comment);
+ const { type, name, includeURL = true } = getReferenceTypeOfParameter(parameter.type, definitions);
+ const parsedName = `${name}${type === 'array' ? '[]' : ''}`;
+
+ let url: string | undefined;
+ const typesToExpand = TYPES_TO_EXPAND[methodName === 'constructor' ? '_constructor' : methodName] || [];
+ if (typesToExpand.includes(name)) {
+ url = `#${name.toLowerCase()}`;
+ } else if (includeURL) {
+ url = getURLFromSources(matchingType);
+ }
+ const linkedName = url ? `[\`${parsedName}\`](${url})` : `\`${parsedName}\``;
+ return [
+ '-',
+ `**${parameter.name}${parameter.flags?.isOptional ? '?' : ''}**:`,
+ childParameters === '' ? linkedName : undefined, // only show the type information if we're not expanding it
+ comment ? ` - ${comment.split('\n').join(" ")}` : undefined,
+ ].filter(Boolean).join(' ');
+};
+
+const writePlatformSpecificParameter = (platform: string, parameter: DeclarationReflection, definitions: Definitions) => {
+ const comment = getSummary(parameter.comment);
+ const { type, name } = getReferenceTypeOfParameter(parameter.type, definitions);
+ const url = getURLFromSources(parameter);
+ const parsedName = `${name}${type === 'array' ? '[]' : ''}`;
+ return [
+ '-',
+ `**[${platform}](${url})**:`,
+ `\`${parsedName}\``,
+ comment ? ` - ${comment}` : undefined,
+ ].filter(Boolean).join(' ');
+};
+
+
+export const writePlatformSpecificDefinitions = (definitions: Definitions): string => {
+ const platformSpecificTypes: PlatformSpecificFileDeclarationReflection[] = [];
+ for (const type of Object.values(definitions.types)) {
+ if (!isDeclarationReflection(type)) {
+ platformSpecificTypes.push(type);
+ }
+ }
+ return platformSpecificTypes.map(parameter => [
+ writePlatformSpecificParameter('Browser', parameter.browser, definitions),
+ writePlatformSpecificParameter('Node', parameter.node, definitions),
+ ].join('\n')).join('\n');
+};
+
+export const getParameters = (
+ methodName: string,
+ parameters: Parameter[],
+ definitions: Definitions,
+ typeParameters: Record = {},
+ depth = 0
+): string => {
+ if (depth > 5) {
+ throw new Error('Too many levels of depth');
+ }
+ return parameters.map((parameter) => {
+ const matchingType = getMatchingType(parameter, definitions, typeParameters);
+ if (matchingType) {
+ const { children } = isPlatformSpecificFileDeclarationReflection(matchingType) ? matchingType.declarationReflection : matchingType;
+ const childParameters = children ? getParameters(methodName, sortChildrenByLineNumber(children), definitions, typeParameters, depth + 1) : '';
+ return [
+ writeParameter(methodName, parameter, matchingType, definitions, childParameters),
+ childParameters,
+ ].filter(Boolean).map(line => Array(depth * 2).fill(' ').join('') + line).join('\n');
+ }
+ return undefined;
+ }).filter(Boolean).join('\n');
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-platform-specific-parameter.ts b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-platform-specific-parameter.ts
new file mode 100644
index 000000000..e77fe420e
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-api-documentation-files/write-platform-specific-parameter.ts
@@ -0,0 +1,18 @@
+import { DeclarationReflection } from "typedoc";
+import { Definitions } from "../types.js";
+import { getReferenceTypeOfParameter } from "./get-reference-type-of-parameter.js";
+import { getURLFromSources } from "./get-url-from-sources.js";
+import { getSummary } from "./write-parameter.js";
+
+export const writePlatformSpecificParameter = (platform: string, parameter: DeclarationReflection, definitions: Definitions) => {
+ const comment = getSummary(parameter.comment);
+ const { type, name } = getReferenceTypeOfParameter(parameter.type, definitions);
+ const url = getURLFromSources(parameter);
+ const parsedName = `${name}${type === 'array' ? '[]' : ''}`;
+ return [
+ '-',
+ `**[${platform}](${url})**:`,
+ `\`${parsedName}\``,
+ comment ? ` - ${comment}` : undefined,
+ ].filter(Boolean).join(' ');
+};
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-index-file.test.ts b/internals/scripts/src/bin/write/docs/api/lib/write-index-file.test.ts
new file mode 100644
index 000000000..3174fa25e
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-index-file.test.ts
@@ -0,0 +1,27 @@
+import { DeclarationReflection } from "typedoc";
+import { writeIndexFile } from "./write-index-file.js";
+import { getTemplate } from "@internals/common/get-template";
+import { writeFile } from "@internals/common/fs";
+
+vi.mock('@internals/common/fs', () => ({
+ writeFile: vi.fn(),
+}));
+
+vi.mock('@internals/common/get-template', () => ({
+ getTemplate: vi.fn(),
+}));
+
+describe('writeIndexFile', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('writes an index file', async () => {
+ vi.mocked(getTemplate).mockResolvedValue('foobarbaz');
+ await writeIndexFile('/out', [{
+ name: 'foo',
+ }] as unknown as DeclarationReflection[]);
+ expect(getTemplate).toHaveBeenCalled();
+ expect(writeFile).toHaveBeenCalledWith('/out/index.md', 'foobarbaz');
+ });
+});
diff --git a/internals/scripts/src/bin/write/docs/api/lib/write-index-file.ts b/internals/scripts/src/bin/write/docs/api/lib/write-index-file.ts
new file mode 100644
index 000000000..901e2ec34
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/api/lib/write-index-file.ts
@@ -0,0 +1,12 @@
+import { writeFile } from "@internals/common/fs";
+import { getTemplate } from "@internals/common/get-template";
+import path from "path";
+import { DeclarationReflection } from "typedoc";
+import { TEMPLATES_DIR } from "./constants.js";
+
+export const writeIndexFile = async (dest: string, methods: DeclarationReflection[]) => {
+ const contents = await getTemplate(path.resolve(TEMPLATES_DIR, 'index.md.t'), {
+ methods,
+ });
+ await writeFile(path.resolve(dest, 'index.md'), contents);
+}
diff --git a/internals/scripts/src/bin/write/docs/check-tense.ts b/internals/scripts/src/bin/write/docs/check-tense.ts
new file mode 100644
index 000000000..094f2141d
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/check-tense.ts
@@ -0,0 +1,106 @@
+
+/*****
+ * Script for checking tense in docs markdown files
+ */
+import { sync } from 'glob';
+import path from 'path';
+import { readFile } from '@internals/common/fs';
+import { DOCS_DIR } from '@internals/common/constants';
+
+/****
+ * Constants
+ */
+
+const EXCLUDED_DIRECTORIES = [
+ 'node_modules',
+ 'blog',
+];
+
+/****
+ * Utility functions
+ */
+
+const getDocumentationFiles = (): string[] => {
+ return sync(path.resolve(DOCS_DIR, '**/*.{md,mdx}')).filter(file => {
+ return EXCLUDED_DIRECTORIES.reduce((include, dir) => {
+ return !include ? false : !file.includes(dir);
+ }, true);
+ });
+};
+
+// split a markdown file's contents into two concatenated strings,
+// one containing the main content of the file, the other containing
+// just the asides
+const splitFileContents = (contents: string): [string, string] => {
+ const nonAsides = [];
+ const asides = [];
+ let isAside = false;
+ for (const line of contents.split('\n')) {
+ if (line.startsWith(':::')) {
+ isAside = !isAside;
+ } else {
+ if (isAside) {
+ asides.push(line);
+ } else {
+ nonAsides.push(line);
+ }
+ }
+ }
+ return [nonAsides.join('\n'), asides.join('\n')];
+};
+
+// check that a chunk of text matches a specific tense
+const checkTense = (contents: string, expectedTense: 'third' | 'second') => {
+ if (expectedTense === 'third') {
+ // const matches = contents.match(/(Y|y)ou|(Y|y)our|(M|m)ine|(M|m)y/g);
+ return contents.match(/\b(I |I'm|me|my|mine|you|your|yours|yourself|yourselves)\b/g);
+ } else if (expectedTense === 'second') {
+ return contents.match(/\b(I |I'm|me|my|mine|we|us|our|ours|ourselves)\b/g);
+ }
+ throw new Error(`Unexpected tense: ${expectedTense}`);
+}
+
+const checkFileForTense = async (file: string) => {
+ const contents = await readFile(file);
+ if (file.includes('documentation/api') || file.includes('troubleshooting')) {
+ const matches = checkTense(contents, 'second');
+ if (matches !== null) {
+ return [
+ `Found inconsistent tenses in file ${file}:`,
+ '',
+ `Main content should be second person, found following keywords: ${matches.join('|')}`,
+ ].join('\n');
+ }
+ } else {
+ const [mainContents, asides] = splitFileContents(contents);
+ const mainMatches = checkTense(mainContents, 'third');
+ const asidesMatches = checkTense(asides, 'second');
+ if (mainMatches !== null || asidesMatches !== null) {
+ return [
+ `Found inconsistent tenses in file ${file}:`,
+ '',
+ ...(mainMatches !== null ? [
+ `Main content should be third person, found following keywords: ${mainMatches.join('|')}`,
+ ] : []),
+ ...(asidesMatches !== null ? [
+ `Asides content should be second person, found following keywords: ${asidesMatches.join('|')}`,
+ ] : []),
+ ].join('\n');
+ }
+ }
+ return undefined;
+}
+
+/****
+ * Main function
+ */
+export const main = async () => {
+ const files = getDocumentationFiles();
+ const errors = (await Promise.all(files.map(checkFileForTense))).filter(Boolean);
+
+ if (errors.length) {
+ throw new Error(errors.join('\n\n\n'));
+ }
+}
+
+main();
diff --git a/internals/scripts/src/bin/write/docs/guides/index.ts b/internals/scripts/src/bin/write/docs/guides/index.ts
new file mode 100644
index 000000000..7eba7f4d2
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/guides/index.ts
@@ -0,0 +1,26 @@
+import path from 'path';
+import { DOCS_DIR } from '@internals/common/constants';
+import { mkdirp } from '@internals/common/fs';
+import { writeGuideDocs } from './write-guide-docs.js';
+import { info, verbose } from '@internals/common/logger';
+import { getSharedArgs } from '../shared/get-shared-args.js';
+import { clearOutMarkdownFiles } from '../shared/clear-out-markdown-files.js';
+
+const EXAMPLES_DOCS_DEST = path.resolve(DOCS_DIR, 'docs/documentation/guides');
+
+const writeGuideDocumentation = async ({ shouldClearMarkdown }: { shouldClearMarkdown: boolean }) => {
+ info('Writing guides documentation');
+ await mkdirp(EXAMPLES_DOCS_DEST);
+ if (shouldClearMarkdown) {
+ verbose(`Clearing out markdown files in ${EXAMPLES_DOCS_DEST}`)
+ await clearOutMarkdownFiles(EXAMPLES_DOCS_DEST);
+ }
+
+ return writeGuideDocs(EXAMPLES_DOCS_DEST);
+};
+
+const main = async () => {
+ return writeGuideDocumentation(getSharedArgs());
+};
+
+main();
diff --git a/internals/scripts/src/bin/write/docs/guides/write-guide-docs.ts b/internals/scripts/src/bin/write/docs/guides/write-guide-docs.ts
new file mode 100644
index 000000000..8e140acdb
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/guides/write-guide-docs.ts
@@ -0,0 +1,278 @@
+import { EXAMPLES_DIR } from "@internals/common/constants";
+import { copyFile, exists, mkdirp, readFile, readdir, stat, writeFile } from "@internals/common/fs";
+import { getPackageJSON } from "@internals/common/package-json";
+import path from "path";
+
+/****
+ * Types
+ */
+interface FrontMatter {
+ [index: string]: string | number | FrontMatter;
+}
+interface ExampleContent {
+ title: string;
+ frontmatter: FrontMatter;
+}
+type Category = 'browser' | 'node' | 'other';
+
+/****
+ * Utility functions
+ */
+const DEFAULT_EMBED_FOR_NODE = 'codesandbox';
+const DEFAULT_EMBED_FOR_BROWSER = 'codesandbox';
+const isCategory = (category: unknown): category is Category => typeof category === 'string' && ['browser', 'node', 'other'].includes(category);
+const getGuideFolders = async (root: string): Promise => {
+ const files = await readdir(root);
+ const includedFiles: string[] = [];
+ await Promise.all(files.map(async file => {
+ const isDirectory = (await stat(path.resolve(root, file))).isDirectory();
+ if (isDirectory) {
+ includedFiles.push(file);
+ }
+ }));
+ if (includedFiles.length === 0) {
+ throw new Error('No guides found')
+ }
+ return includedFiles;
+};
+
+const getBody = (contents: string) => contents.split('---').pop() ?? '';
+
+const getDefaultCodeEmbedParameters = (category: Category, params: Record = {}) => {
+ if (category === 'node') {
+ return 'view=split,preview&module=index.js&hidenavigation=1';
+ };
+ return Object.entries({
+ embed: 1,
+ file: 'index.js',
+ hideExplorer: 1,
+ ...params,
+ }).map(([key, val]) => `${key}=${val}`).join('&');
+}
+
+const getFrontmatter = async (key: string): Promise => {
+ const packageJSON = await getPackageJSON(path.resolve(EXAMPLES_DIR, key, 'package.json'));
+ const readmePath = path.resolve(EXAMPLES_DIR, key, 'README.md');
+ const readmeContents = await readFile(readmePath);
+ const body = getBody(readmeContents);
+ const bodyParts = body.split('\n');
+ let title: undefined | string;
+ for (const line of bodyParts) {
+ if (line.startsWith('#')) {
+ title = line.split('#')?.pop()?.trim() ?? '';
+ break;
+ }
+ }
+
+ if (!title) {
+ throw new Error(`No title found in file ${readmePath}`);
+ }
+
+ const {
+ category = 'browser',
+ code_embed,
+ ...frontmatter
+ } = packageJSON['@upscalerjs']?.guide?.frontmatter || {};
+
+ const codeEmbed = code_embed !== false ? {
+ params: getDefaultCodeEmbedParameters(category, frontmatter.params),
+ type: category ? DEFAULT_EMBED_FOR_NODE : DEFAULT_EMBED_FOR_BROWSER,
+ url: `/examples/${key}`,
+ ...code_embed,
+ } : {};
+
+ return {
+ frontmatter: {
+ category,
+ hide_table_of_contents: true,
+ ...frontmatter,
+ code_embed: codeEmbed,
+ },
+ title,
+ }
+};
+
+const getGuidesWithFrontmatter = async (): Promise<({ key: string; } & ExampleContent)[]> => {
+ const folders = await getGuideFolders(EXAMPLES_DIR);
+ const includedFolders: string[] = [];
+ await Promise.all(folders.map(async folder => {
+ const readmePath = path.resolve(EXAMPLES_DIR, folder, 'README.md');
+ if (await exists(readmePath)) {
+ includedFolders.push(folder);
+ }
+ }))
+ if (includedFolders.length === 0) {
+ throw new Error('No guides found including a readme')
+ }
+
+ return Promise.all(includedFolders.map(async key => ({
+ key,
+ ...(await getFrontmatter(key)),
+ })));
+};
+
+const getExampleOrder = (examples: ({ key: string; } & ExampleContent)[]) => {
+ return examples.sort((a, b) => {
+ const aPos = Number(a.frontmatter.sidebar_position);
+ const bPos = Number(b.frontmatter.sidebar_position);
+ if (Number.isNaN(aPos)) {
+ return 1;
+ }
+ if (Number.isNaN(bPos)) {
+ return -1;
+ }
+ return aPos - bPos;
+ }).map(({ key }) => key);
+}
+
+const getExamplesByName = async () => {
+ const examplesWithFrontmatter = await getGuidesWithFrontmatter();
+ const exampleOrder = getExampleOrder(examplesWithFrontmatter);
+
+ return {
+ examplesByName: examplesWithFrontmatter.reduce((obj, { key, ...rest }) => {
+ if (obj[key]) {
+ throw new Error(`Example already exists for key ${key}`);
+ }
+ return {
+ ...obj,
+ [key]: rest,
+ };
+ }, {} as Record),
+ exampleOrder,
+ };
+}
+
+const indent = (str: string, depth = 0) => [...Array(depth * 2).fill(''), str].join(' ');
+const uppercase = (str: string) => str[0].toUpperCase() + str.slice(1);
+
+const buildFrontmatter = (frontmatter: FrontMatter = {}, depth = 0): string[] => Object.entries(frontmatter).reduce((arr, [key, val]) => {
+ if (typeof val === 'object') {
+ return arr.concat(...[
+ `${key}:`,
+ ...buildFrontmatter(val, depth + 1),
+ ].map(str => indent(str, depth)));
+ }
+ return arr.concat(indent(`${key}: ${val}`, depth));
+}, [] as string[]);
+
+const parseContents = async (key: string, frontmatter: FrontMatter = {}) => {
+ const readmePath = path.resolve(EXAMPLES_DIR, key, 'README.md');
+ const contents = await readFile(readmePath);
+ const frontmatterContents = [
+ ...buildFrontmatter(frontmatter),
+ ];
+ return [
+ '---',
+ ...frontmatterContents,
+ '---',
+ '',
+ contents,
+ ].filter(Boolean).join('\n');
+}
+
+const copyAssets = async (targetDir: string, key: string) => {
+ const srcAssetsDir = path.resolve(EXAMPLES_DIR, key, 'assets');
+ if (await exists(srcAssetsDir)) {
+ const targetAssetsDir = path.resolve(targetDir, 'assets');
+ await mkdirp(targetAssetsDir);
+ const assets = await readdir(srcAssetsDir);
+ await Promise.all(assets.map(async asset => {
+ const assetPath = path.resolve(srcAssetsDir, asset);
+ await copyFile(assetPath, path.resolve(targetAssetsDir, asset));
+ }));
+ }
+}
+
+const copyReadmesToDocs = async (exampleOrder: string[], examplesByName: Record, dest: string) => {
+ await Promise.all(exampleOrder.map(async (key) => {
+ const example = examplesByName[key];
+ if (!example) {
+ throw new Error(`No example found for key ${key}`);
+ }
+ const {
+ frontmatter,
+ } = example;
+
+ const {
+ parent,
+ category,
+ } = frontmatter;
+ if (!isCategory(category)) {
+ throw new Error(`Category is not valid: ${category}, for key ${key}`);
+ }
+ if (parent !== undefined && typeof parent !== 'string') {
+ throw new Error(`Parent is not of type string: ${parent}`);
+ }
+ const targetDir = path.resolve(...[dest, category, parent].filter(Boolean));
+
+ // copy assets
+ await copyAssets(targetDir, key);
+
+ // write readme
+ const targetPath = path.resolve(targetDir, `${key}.md`);
+ await mkdirp(path.dirname(targetPath));
+ const fileContents = await parseContents(key, frontmatter);
+ await writeFile(targetPath, fileContents);
+ }));
+}
+
+const writeIndexFile = async (exampleOrder: string[], examplesByName: Record, dest: string) => {
+ const examplesByCategory = exampleOrder.reduce((obj, example) => {
+ const { frontmatter: { parent, category } } = examplesByName[example];
+ if (!isCategory(category)) {
+ throw new Error(`Category is not valid: ${category}, for key ${example}`);
+ }
+ if (parent !== undefined && typeof parent !== 'string') {
+ throw new Error(`Parent is not of type string: ${parent}`);
+ }
+ return {
+ ...obj,
+ [category]: (obj[category] || []).concat([[parent ? uppercase(parent) : undefined, example]]),
+ }
+ }, {} as Record>);
+
+ const content = [
+ '---',
+ 'hide_table_of_contents: true',
+ '---',
+ '# Guides',
+ 'This page contains a list of guides and examples for using various features of UpscalerJS.',
+ '',
+ 'The first two guides discuss the basics of UpscalerJS and how to use it in a project. The [Models](browser/models) and [Working with Tensors](browser/tensors) guides discuss useful configuration options of UpscalerJS.',
+ '',
+ 'There are also guides on [improving the performance](#performance) of UpscalerJS, [specific examples of implementations](#implementations), and [Node.js-specific](#node) guides.',
+ '',
+ ...Object.entries(examplesByCategory).map(([category, examples]) => {
+ let activeParent: undefined | string;
+ return `\n## ${uppercase(category)}\n\n${examples.map(([parent, example]) => {
+ const { title } = examplesByName[example];
+ const url = [
+ '/documentation',
+ 'guides',
+ category,
+ parent,
+ example
+ ].filter(Boolean).join('/');
+ const strings: string[] = [];
+ if (activeParent !== parent) {
+ activeParent = parent;
+ strings.push(`- ### ${parent}`);
+ }
+ strings.push(indent(`- [${title}](${url})`, activeParent ? 1 : 0));
+ return strings.join('\n');
+ }).join('\n')}`;
+ }),
+ ].join('\n');
+
+ await writeFile(path.resolve(dest, 'index.md'), content);
+}
+
+export const writeGuideDocs = async (dest: string) => {
+ const { exampleOrder, examplesByName } = await getExamplesByName();
+
+ await Promise.all([
+ copyReadmesToDocs(exampleOrder, examplesByName, dest),
+ writeIndexFile(exampleOrder, examplesByName, dest),
+ ]);
+}
diff --git a/internals/scripts/src/bin/write/docs/models/index.ts b/internals/scripts/src/bin/write/docs/models/index.ts
new file mode 100644
index 000000000..55c68e068
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/models/index.ts
@@ -0,0 +1,27 @@
+import path from 'path';
+import { DOCS_DIR } from '@internals/common/constants';
+import { mkdirp } from '@internals/common/fs';
+import { writeModelReadmes } from './write-model-readmes.js';
+import { verbose } from '@internals/common/logger';
+import { info } from 'console';
+import { getSharedArgs } from '../shared/get-shared-args.js';
+import { clearOutMarkdownFiles } from '../shared/clear-out-markdown-files.js';
+
+const targetDocDir = path.resolve(DOCS_DIR, 'docs/models/available');
+
+const writeModelsDocumentation = async ({ shouldClearMarkdown }: { shouldClearMarkdown: boolean }) => {
+ info('Writing models documentation');
+ await mkdirp(targetDocDir);
+ if (shouldClearMarkdown) {
+ verbose(`Clearing out markdown files in ${targetDocDir}`)
+ await clearOutMarkdownFiles(targetDocDir);
+ }
+
+ return writeModelReadmes(targetDocDir);
+};
+
+const main = async () => {
+ return writeModelsDocumentation(getSharedArgs());
+};
+
+main();
diff --git a/internals/scripts/src/bin/write/docs/models/write-model-readmes.ts b/internals/scripts/src/bin/write/docs/models/write-model-readmes.ts
new file mode 100644
index 000000000..457107426
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/models/write-model-readmes.ts
@@ -0,0 +1,214 @@
+/*****
+ * Script for linking model readmes locally in docs folder
+ */
+import path from 'path';
+import { verbose } from '@internals/common/logger';
+import { DOCS_DIR, MODELS_DIR } from '@internals/common/constants';
+import { copy, exists, mkdirp, readFile, writeFile } from '@internals/common/fs';
+import { ALL_MODEL_PACKAGE_DIRECTORY_NAMES, PRIVATE_MODEL_PACKAGE_NAMES } from '@internals/common/models';
+
+/****
+ * Types
+ */
+
+interface PackageWithMetadata {
+ description: string;
+ sidebarPosition: number;
+ enhancedSrc: string;
+ unenhancedSrc: string;
+ category: string;
+ packageName: string;
+}
+
+/****
+ * Utility functions
+ */
+
+const copyAssets = async (packageName: string, targetDir: string) => {
+ const packagePath = path.resolve(MODELS_DIR, packageName, 'assets');
+ const targetPath = path.resolve(targetDir, packageName);
+ await copy(packagePath, targetPath);
+};
+
+const createMarkdown = (contents: string, targetPath: string) => writeFile(targetPath, contents);
+
+const getCategory = (packageName: string, readmeContents: string) => {
+ const lines = readmeContents.split('\n');
+ for (const line of lines) {
+ if (line.startsWith('category: ')) {
+ return line.split('category: ').pop() ?? '';
+ }
+ }
+
+ throw new Error(`Could not find category for package name ${packageName}`);
+};
+
+const linkAllModelReadmes = async (packages: string[], targetAssetDir: string, targetDocDir: string) => {
+ for (const packageName of packages) {
+ const packagePath = path.resolve(MODELS_DIR, packageName);
+ const docMdxPath = path.resolve(packagePath, 'DOC.mdx');
+
+ if (await exists(docMdxPath)) {
+ const docMdxContents = await readFile(docMdxPath);
+ const category = getCategory(packageName, docMdxContents);
+
+ const targetPath = path.resolve(targetDocDir, category, `${packageName}.mdx`);
+ await mkdirp(path.dirname(targetPath));
+ // try {
+ // unlinkSync(targetPath);
+ // } catch (err) { }
+ await copyAssets(packageName, targetAssetDir);
+ await createMarkdown(await readFile(docMdxPath), targetPath);
+ verbose(`** Linked: ${packageName}`);
+ } else {
+ verbose(`** Does not have a DOC.mdx file: ${packageName}`)
+ }
+ }
+};
+
+const getDescription = (readmeContents: string) => {
+ const lines = readmeContents.split('\n');
+ let description = '';
+ let startedDescription = false;
+ for (const line of lines) {
+ if (line.startsWith('# ')) {
+ startedDescription = true;
+ } else if (line.startsWith('## ')) {
+ startedDescription = false;
+ break;
+ } else if (!line.startsWith(' `${part[0].toUpperCase()}${part.slice(1)}`;
+
+const getSidebarPosition = (packageName: string, readmeContents: string) => {
+ const lines = readmeContents.split('\n');
+ for (const line of lines) {
+ if (line.startsWith('sidebar_position: ')) {
+ const pos = line.split('sidebar_position: ').pop() ?? '';
+ return parseInt(pos, 10);
+ }
+ }
+ throw new Error(`Could not find sidebar position for package name ${packageName}`);
+};
+
+const getEnhancedSrc = (packageName: string, readmeContents: string) => {
+ const lines = readmeContents.split('\n');
+ for (const line of lines) {
+ if (line.startsWith('enhanced_src: ')) {
+ return line.split('enhanced_src: ').pop() ?? '';
+ }
+ }
+
+ throw new Error(`Could not find enhanced_src for package name ${packageName}`);
+};
+
+const getPackageMetadata = async (packageName: string) => {
+ const packagePath = path.resolve(MODELS_DIR, packageName);
+ const docMdxPath = path.resolve(packagePath, 'DOC.mdx');
+ const docMdxContents = await readFile(docMdxPath);
+ return {
+ description: getDescription(docMdxContents),
+ sidebarPosition: getSidebarPosition(packageName, docMdxContents),
+ enhancedSrc: getEnhancedSrc(packageName, docMdxContents),
+ unenhancedSrc: `${packageName}/fixture.png`,
+ category: getCategory(packageName, docMdxContents),
+ };
+};
+
+const getAllPackagesWithMetadata = async (packageNames: string[]): Promise => {
+ const packagesWithValidReadme = packageNames.filter(packageName => {
+ const packagePath = path.resolve(MODELS_DIR, packageName);
+ const readmePath = path.resolve(packagePath, 'DOC.mdx');
+ return exists(readmePath);
+ });
+ const packagesWithMetadata = await Promise.all(packagesWithValidReadme.map(async (packageName) => ({
+ packageName,
+ ...(await getPackageMetadata(packageName)),
+ })));
+
+ return packagesWithMetadata;
+};
+
+const getAllPackagesOrganizedByCategory = async (packageNames: string[]): Promise<{ category: string, packages: PackageWithMetadata[] }[]> => {
+ const packages = await getAllPackagesWithMetadata(packageNames);
+
+ const packagesByCategory = packages.reduce>>((obj, pkg) => {
+ const { category, sidebarPosition } = pkg;
+ if (!obj[category]) {
+ obj[category] = {};
+ }
+ obj[category][sidebarPosition] = pkg;
+ return obj;
+ }, {});
+
+ return Object.keys(packagesByCategory).map(category => {
+ const packageSidebarPositions = Object.keys(packagesByCategory[category]).sort();
+ const packages = packagesByCategory[category];
+
+ return {
+ category,
+ packages: packageSidebarPositions.map(position => packages[position]),
+ }
+ });
+};
+
+const writeModelIndexFile = async (packageNames: string[], _targetAssetDir: string) => {
+ const packagesByCategory = getAllPackagesOrganizedByCategory(packageNames);
+ const contents = `
+---
+title: Models
+description: An overview of available UpscalerJS Models
+sidebar_position: 1
+sidebar_label: Overview
+pagination_next: null
+pagination_prev: null
+hide_title: true
+---
+View this page on the UpscalerJS website
+
+# Models
+
+UpscalerJS offers a number of available models. With the exception of \`default-model\`, these models must be explicitly installed alongside UpscalerJS.
+
+import ModelCard from '@site/src/components/modelCards/modelCard/modelCard';
+import ModelCards from '@site/src/components/modelCards/modelCards';
+
+${(await packagesByCategory).map(({ category, packages }) => `
+## ${category.split('-').map(uppercase)}
+
+
+ ${packages.map(({ packageName, description, unenhancedSrc, enhancedSrc } ) => `
+
+ `).join('\n')}
+
+`).join('\n')}
+
+ `;
+ await writeFile(path.resolve(DOCS_DIR, 'docs', 'models', 'index.md'), contents.trim());
+};
+
+const isExcluded = (folder: string) => !PRIVATE_MODEL_PACKAGE_NAMES.includes(folder);
+
+export const writeModelReadmes = async (targetDocDir: string) => {
+ const packages = (await ALL_MODEL_PACKAGE_DIRECTORY_NAMES).filter(isExcluded);
+ const targetAssetDir = path.resolve(DOCS_DIR, 'assets/assets/sample-images');
+
+ await writeModelIndexFile(packages, targetAssetDir);
+ verbose('Wrote model index file');
+ await linkAllModelReadmes(packages, targetAssetDir, targetDocDir);
+ verbose(`Linked ${packages.length} model readmes`)
+};
diff --git a/internals/scripts/src/bin/write/docs/shared/clear-out-markdown-files.ts b/internals/scripts/src/bin/write/docs/shared/clear-out-markdown-files.ts
new file mode 100644
index 000000000..a06ab704a
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/shared/clear-out-markdown-files.ts
@@ -0,0 +1,18 @@
+import { unlink } from '@internals/common/fs';
+import { glob } from 'glob';
+
+const getAllMarkdownFiles = (target: string) => glob(`${target}/**/*.md?(x)`);
+
+export const clearOutMarkdownFiles = async (target: string, verbose?: boolean) => {
+ const files = await getAllMarkdownFiles(target);
+ if (files.length > 0) {
+ await Promise.all(files.map(file => unlink(file)));
+ if (verbose) {
+ console.log([
+ `Cleared out ${files.length} markdown files, including:`,
+ ...files.map(file => file.split(/docs\/documentation\//gi).pop()).map(file => `- ${file}`),
+ ].join('\n'));
+ }
+ }
+};
+
diff --git a/internals/scripts/src/bin/write/docs/shared/get-shared-args.ts b/internals/scripts/src/bin/write/docs/shared/get-shared-args.ts
new file mode 100644
index 000000000..32dd3a1c3
--- /dev/null
+++ b/internals/scripts/src/bin/write/docs/shared/get-shared-args.ts
@@ -0,0 +1,18 @@
+import { parseArgs } from "node:util";
+
+export const getSharedArgs = () => {
+ const {
+ values: {
+ ['should-clear-markdown']: shouldClearMarkdown = false,
+ },
+ } = parseArgs({
+ options: {
+ 'should-clear-markdown': {
+ type: "boolean",
+ short: "c",
+ },
+ },
+ });
+
+ return { shouldClearMarkdown };
+};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 42d139ed3..e21be3fab 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -665,6 +665,9 @@ importers:
'@internals/common':
specifier: workspace:*
version: link:../common
+ typedoc:
+ specifier: ^0.24.8
+ version: 0.24.8(typescript@5.1.6)
devDependencies:
vitest:
specifier: ^0.34.2
@@ -12089,6 +12092,7 @@ packages:
/marked@4.3.0:
resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==}
engines: {node: '>= 12'}
+ hasBin: true
/matchit@1.1.0:
resolution: {integrity: sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==}
diff --git a/scripts/package.json b/scripts/package.json
index e642887a7..d891cb79f 100644
--- a/scripts/package.json
+++ b/scripts/package.json
@@ -6,11 +6,6 @@
},
"scripts": {
"__run_command": "ts-node --esm --project ./tsconfig.json",
- "docs:build-api": "pnpm __run_command ./package-scripts/docs/build-api.ts",
- "docs:build-guides": "pnpm __run_command ./package-scripts/docs/build-guides.ts",
- "docs:link-model-readmes": "pnpm __run_command ./package-scripts/docs/link-model-readmes.ts",
- "docs:tense-checks": "pnpm __run_command ./package-scripts/docs/tense-checks.ts",
- "model:write-docs": "pnpm __run_command ./package-scripts/write-model-docs.ts",
"test:integration:browserstack": "pnpm __run_command ./test.ts --kind integration --platform browser --runner browserstack",
"test:integration:clientside": "pnpm __run_command ./test.ts --kind integration --platform browser",
"test:integration:serverside": "pnpm __run_command ./test.ts --kind integration --platform node",