@versatiles/release-tool 1.2.7 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,24 @@
1
- MIT License
1
+ This is free and unencumbered software released into the public domain.
2
2
 
3
- Copyright (c) 2024 VersaTiles
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
4
7
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
11
15
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
14
23
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
24
+ For more information, please refer to [unlicense.org](https://unlicense.org/)
package/README.md CHANGED
@@ -3,13 +3,14 @@
3
3
 
4
4
  # VersaTiles Release Tools
5
5
 
6
- Tools used internally for:
6
+ Tools used for:
7
7
 
8
- * creating Markdown documentation of TypeScript libraries: [`vrt ts2md`](#subcommand-vrt-ts2md)
9
- * creating Markdown documentation of executables: [`vrt cmd2md`](#subcommand-vrt-cmd2md)
10
- * inserting Markdown into documents: [`vrt insertmd`](#subcommand-vrt-insertmd)
11
- * updating "Table of Content" in Markdown files: [`vrt inserttoc`](#subcommand-vrt-inserttoc)
12
- * releasing the current version as npm package: [`vrt release-npm`](#subcommand-vrt-release-npm)
8
+ * creating a graph of the source code as mermaid: [`vrt deps-graph`](#subcommand-vrt-deps-graph)
9
+ * upgrading all package dependencies: [`vrt deps-upgrade`](#subcommand-vrt-deps-upgrade)
10
+ * creating Markdown documentation of executables: [`vrt doc-command`](#subcommand-vrt-doc-command)
11
+ * inserting Markdown into documents: [`vrt doc-insert`](#subcommand-vrt-doc-insert)
12
+ * updating "Table of Content" in Markdown files: [`vrt doc-toc`](#subcommand-vrt-doc-toc)
13
+ * releasing the project as npm package: [`vrt release-npm`](#subcommand-vrt-release-npm)
13
14
 
14
15
  # Installation
15
16
 
@@ -37,8 +38,6 @@ You need to configure the scripts in the package.json:
37
38
  * `scripts.prepack` is **recommended** to ensure that all files are up-to-date before releasing. Here you can build code and documentation.
38
39
  * `scripts.release` is **recommended** to make it easy to release a new version.
39
40
 
40
- Have a look at this [package.json](https://github.com/versatiles-org/node-release-tool/blob/main/package.json) as an example.
41
-
42
41
  # Command `vrt`
43
42
 
44
43
  <!--- This chapter is generated automatically --->
@@ -47,95 +46,186 @@ Have a look at this [package.json](https://github.com/versatiles-org/node-releas
47
46
  $ vrt
48
47
  Usage: vrt [options] [command]
49
48
 
50
- versatiles release and documentaion tool
49
+ CLI tool for releasing packages and generating documentation for
50
+ Node.js/TypeScript projects.
51
51
 
52
52
  Options:
53
- -h, --help display help for command
53
+ -h, --help display help for command
54
54
 
55
55
  Commands:
56
- ts2md <typescript> <tsconfig> documents a TypeScript file and outputs it to stdout
57
- cmd2md <command> documents a runnable command and outputs it to stdout
58
- insertmd <readme> [heading] [foldable] takes Markdown from stdin and insert it into a Markdown file
59
- inserttoc <readme> [heading] updates the TOC in a Markdown file
60
- release-npm [path] release a npm package
61
- help [command] display help for command
56
+ check-package Check package.json for required scripts and other metadata.
57
+ deps-graph Analyze project files and output a dependency graph as Mermaid markup.
58
+ deps-upgrade Upgrade all dependencies in the current project to their latest versions.
59
+ doc-command <command> Generate Markdown documentation for a specified command and output the result.
60
+ doc-insert <readme> [heading] [foldable] Insert Markdown from stdin into a specified section of a Markdown file.
61
+ doc-toc <readme> [heading] Generate a Table of Contents (TOC) in a Markdown file.
62
+ doc-typescript [options] Generate documentation for a TypeScript project.
63
+ help [command] display help for command
64
+ release-npm [path] Publish an npm package from the specified path to the npm registry.
62
65
  ```
63
66
 
64
- ## Subcommand: `vrt ts2md`
67
+ ## Subcommand: `vrt check-package`
65
68
 
66
69
  ```console
67
- $ vrt ts2md
68
- Usage: vrt ts2md [options] <typescript> <tsconfig>
70
+ $ vrt check-package
71
+ Usage: vrt check-package [options]
69
72
 
70
- documents a TypeScript file and outputs it to stdout
73
+ Check package.json for required scripts and other metadata.
71
74
 
72
- Arguments:
73
- typescript Filename of the TypeScript file
74
- tsconfig Filename of tsconfig.json
75
+ Options:
76
+ -h, --help display help for command
77
+ ```
78
+
79
+ ## Subcommand: `vrt deps-graph`
80
+
81
+ ```console
82
+ $ vrt deps-graph
83
+ Usage: vrt deps-graph [options]
84
+
85
+ Analyze project files and output a dependency graph as Mermaid markup.
86
+
87
+ Options:
88
+ -h, --help display help for command
89
+ ```
90
+
91
+ ## Subcommand: `vrt deps-upgrade`
92
+
93
+ ```console
94
+ $ vrt deps-upgrade
95
+ Usage: vrt deps-upgrade [options]
96
+
97
+ Upgrade all dependencies in the current project to their latest versions.
75
98
 
76
99
  Options:
77
100
  -h, --help display help for command
78
101
  ```
79
102
 
80
- ## Subcommand: `vrt cmd2md`
103
+ ## Subcommand: `vrt doc-command`
81
104
 
82
105
  ```console
83
- $ vrt cmd2md
84
- Usage: vrt cmd2md [options] <command>
106
+ $ vrt doc-command
107
+ Usage: vrt doc-command [options] <command>
85
108
 
86
- documents a runnable command and outputs it to stdout
109
+ Generate Markdown documentation for a specified command and output the result.
87
110
 
88
111
  Arguments:
89
- command command to run
112
+ command Command to document (e.g., "npm run build").
90
113
 
91
114
  Options:
92
115
  -h, --help display help for command
93
116
  ```
94
117
 
95
- ## Subcommand: `vrt insertmd`
118
+ ## Subcommand: `vrt doc-insert`
96
119
 
97
120
  ```console
98
- $ vrt insertmd
99
- Usage: vrt insertmd [options] <readme> [heading] [foldable]
121
+ $ vrt doc-insert
122
+ Usage: vrt doc-insert [options] <readme> [heading] [foldable]
100
123
 
101
- takes Markdown from stdin and insert it into a Markdown file
124
+ Insert Markdown from stdin into a specified section of a Markdown file.
102
125
 
103
126
  Arguments:
104
- readme Markdown file, like a readme.md
105
- heading Heading in the Markdown file (default: "# API")
106
- foldable Make content foldable (default: false)
127
+ readme Path to the target Markdown file (e.g., README.md).
128
+ heading Heading in the Markdown file where content should be placed.
129
+ Default is "# API". (default: "# API")
130
+ foldable Whether to wrap the inserted content in a foldable section.
131
+ (default: false)
107
132
 
108
133
  Options:
109
134
  -h, --help display help for command
110
135
  ```
111
136
 
112
- ## Subcommand: `vrt inserttoc`
137
+ ## Subcommand: `vrt doc-toc`
113
138
 
114
139
  ```console
115
- $ vrt inserttoc
116
- Usage: vrt inserttoc [options] <readme> [heading]
140
+ $ vrt doc-toc
141
+ Usage: vrt doc-toc [options] <readme> [heading]
117
142
 
118
- updates the TOC in a Markdown file
143
+ Generate a Table of Contents (TOC) in a Markdown file.
119
144
 
120
145
  Arguments:
121
- readme Markdown file, like a readme.md
122
- heading Heading in the Markdown file (default: "# Table of Content")
146
+ readme Path to the Markdown file (e.g., README.md).
147
+ heading Heading in the Markdown file where TOC should be inserted. Default
148
+ is "# Table of Content". (default: "# Table of Content")
123
149
 
124
150
  Options:
125
151
  -h, --help display help for command
126
152
  ```
127
153
 
154
+ ## Subcommand: `vrt doc-typescript`
155
+
156
+ ```console
157
+ $ vrt doc-typescript
158
+ Usage: vrt doc-typescript [options]
159
+
160
+ Generate documentation for a TypeScript project.
161
+
162
+ Options:
163
+ -h, --help display help for command
164
+ -i <entryPoint> Entry point of the TypeScript project. Default is
165
+ "./src/index.ts".
166
+ -o <outputPath> Output path for the generated documentation. Default is
167
+ "./docs".
168
+ ```
169
+
128
170
  ## Subcommand: `vrt release-npm`
129
171
 
130
172
  ```console
131
173
  $ vrt release-npm
132
174
  Usage: vrt release-npm [options] [path]
133
175
 
134
- release a npm package
176
+ Publish an npm package from the specified path to the npm registry.
135
177
 
136
178
  Arguments:
137
- path root path of the Node.js project
179
+ path Root path of the Node.js project. Defaults to the current
180
+ directory.
138
181
 
139
182
  Options:
140
183
  -h, --help display help for command
141
184
  ```
185
+
186
+ # Development
187
+
188
+ ## Dependency Graph
189
+
190
+ <!--- This chapter is generated automatically --->
191
+
192
+ ```mermaid
193
+ flowchart TB
194
+
195
+ subgraph 0["src"]
196
+ subgraph 1["commands"]
197
+ 2["check-package.ts"]
198
+ 5["deps-graph.ts"]
199
+ 6["deps-upgrade.ts"]
200
+ 8["doc-command.ts"]
201
+ A["doc-typescript.ts"]
202
+ B["markdown.ts"]
203
+ C["release-npm.ts"]
204
+ end
205
+ subgraph 3["lib"]
206
+ 4["log.ts"]
207
+ 7["shell.ts"]
208
+ 9["utils.ts"]
209
+ D["git.ts"]
210
+ end
211
+ E["index.ts"]
212
+ end
213
+ 2-->4
214
+ 5-->4
215
+ 6-->4
216
+ 6-->7
217
+ 8-->9
218
+ A-->4
219
+ B-->9
220
+ C-->D
221
+ C-->4
222
+ C-->7
223
+ D-->7
224
+ E-->2
225
+ E-->5
226
+ E-->6
227
+ E-->8
228
+ E-->A
229
+ E-->B
230
+ E-->C
231
+ ```
@@ -0,0 +1 @@
1
+ export declare function checkPackage(directory: string): void;
@@ -0,0 +1,53 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { panic, info, warn } from '../lib/log.js';
3
+ import { resolve } from 'node:path';
4
+ export function checkPackage(directory) {
5
+ const pack = JSON.parse(readFileSync(resolve(directory, 'package.json'), 'utf8'));
6
+ const { scripts } = pack;
7
+ if (!scripts)
8
+ panic('scripts not found');
9
+ if (!scripts.test)
10
+ info('scripts.test is recommended');
11
+ if (!scripts.doc)
12
+ info('scripts.doc is recommended');
13
+ if (!scripts.build)
14
+ panic('scripts.build is required');
15
+ if (!scripts.check)
16
+ panic('scripts.check is required');
17
+ if (!scripts.check.includes('npm run build')) {
18
+ warn(`scripts.check should include "npm run build", but is "${scripts.check}"`);
19
+ }
20
+ if (!scripts.prepack)
21
+ panic('scripts.prepack is required');
22
+ if (scripts.prepack !== 'npm run build') {
23
+ warn(`scripts.prepack should be "npm run build", but is "${scripts.prepack}"`);
24
+ }
25
+ if (!scripts.release)
26
+ panic('scripts.release is required');
27
+ if (scripts.release !== 'vrt release-npm') {
28
+ warn(`scripts.release should be "vrt release-npm", but is "${scripts.release}"`);
29
+ }
30
+ if (!scripts.upgrade) {
31
+ warn('scripts.upgrade is recommended');
32
+ }
33
+ else if (scripts.upgrade !== 'vrt deps-upgrade') {
34
+ info(`scripts.upgrade should be "vrt deps-upgrade", but is "${scripts.upgrade}"`);
35
+ }
36
+ if (!scripts['doc-graph']) {
37
+ info(`scripts.doc-graph could be: "vrt deps-graph | vrt doc-insert README.md '## Dependency Graph'"`);
38
+ }
39
+ else {
40
+ if (scripts.doc && !scripts.doc.includes('npm run doc-graph')) {
41
+ info('scripts.doc should include "npm run doc-graph"');
42
+ }
43
+ }
44
+ ['npm-check-updates'].forEach((dep) => {
45
+ if (pack.dependencies?.[dep]) {
46
+ info(`dependencies "${dep}" is probably not needed`);
47
+ }
48
+ if (pack.devDependencies?.[dep]) {
49
+ info(`devDependencies "${dep}" is probably not needed`);
50
+ }
51
+ });
52
+ }
53
+ //# sourceMappingURL=check-package.js.map
@@ -0,0 +1 @@
1
+ export declare function generateDependencyGraph(directory: string): Promise<void>;
@@ -0,0 +1,21 @@
1
+ import { cruise } from 'dependency-cruiser';
2
+ import { panic } from '../lib/log.js';
3
+ export async function generateDependencyGraph(directory) {
4
+ let cruiseResult;
5
+ try {
6
+ cruiseResult = await cruise([directory], {
7
+ includeOnly: '^src',
8
+ outputType: 'mermaid',
9
+ exclude: ["\\.(test|d)\\.ts$", "node_modules"],
10
+ });
11
+ }
12
+ catch (pError) {
13
+ panic(String(pError));
14
+ }
15
+ let { output } = cruiseResult;
16
+ if (typeof output !== 'string')
17
+ panic('no output');
18
+ output = output.replace('flowchart LR', 'flowchart TB');
19
+ process.stdout.write(Buffer.from('```mermaid\n' + output + '```\n'));
20
+ }
21
+ //# sourceMappingURL=deps-graph.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Upgrades the dependencies in a package.json file to their latest versions, removes existing
3
+ * installed modules, and reinstalls them in the specified directory.
4
+ *
5
+ * This function performs the following steps:
6
+ * 1. Checks for outdated dependencies by running `npm outdated --all --json`.
7
+ * 2. Reads the project's package.json file and updates any existing dependencies to their latest versions.
8
+ * 3. Removes all installed modules (`node_modules`) and the lock file (`package-lock.json`).
9
+ * 4. Reinstalls and updates all dependencies.
10
+ * 5. Logs a message indicating that all dependencies are up to date.
11
+ *
12
+ * @param directory - The path to the directory containing the Node.js project.
13
+ * @returns A promise that resolves when the process is complete.
14
+ */
15
+ export declare function upgradeDependencies(directory: string): Promise<void>;
@@ -0,0 +1,97 @@
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import { check, info } from '../lib/log.js';
3
+ import { getShell } from '../lib/shell.js';
4
+ /**
5
+ * Upgrades the dependencies in a package.json file to their latest versions, removes existing
6
+ * installed modules, and reinstalls them in the specified directory.
7
+ *
8
+ * This function performs the following steps:
9
+ * 1. Checks for outdated dependencies by running `npm outdated --all --json`.
10
+ * 2. Reads the project's package.json file and updates any existing dependencies to their latest versions.
11
+ * 3. Removes all installed modules (`node_modules`) and the lock file (`package-lock.json`).
12
+ * 4. Reinstalls and updates all dependencies.
13
+ * 5. Logs a message indicating that all dependencies are up to date.
14
+ *
15
+ * @param directory - The path to the directory containing the Node.js project.
16
+ * @returns A promise that resolves when the process is complete.
17
+ */
18
+ export async function upgradeDependencies(directory) {
19
+ const shell = getShell(directory);
20
+ // Step 1: Check and upgrade all versions
21
+ await check('Upgrade all versions', async () => {
22
+ const { stdout } = await shell.run('npm outdated --all --json', false);
23
+ const outdated = JSON.parse(stdout);
24
+ const latestVersion = new Map();
25
+ // Collect the latest version for each dependency
26
+ for (const [name, entry] of Object.entries(outdated)) {
27
+ let version = '0.0.0';
28
+ if (Array.isArray(entry)) {
29
+ for (const item of entry) {
30
+ if (isGreaterSemver(item.latest, version))
31
+ version = item.latest;
32
+ }
33
+ }
34
+ else {
35
+ version = entry.latest;
36
+ }
37
+ latestVersion.set(name, version);
38
+ }
39
+ // Load package.json
40
+ const pack = JSON.parse(readFileSync('package.json', 'utf8'));
41
+ // Update dependencies to their latest versions
42
+ patch(pack.dependencies);
43
+ patch(pack.devDependencies);
44
+ patch(pack.optionalDependencies);
45
+ patch(pack.peerDependencies);
46
+ // Write the updated package.json
47
+ writeFileSync('package.json', JSON.stringify(pack, null, 2) + '\n');
48
+ /**
49
+ * Mutates the provided dependency object by updating
50
+ * each dependency to the latest known version (if available).
51
+ *
52
+ * @param dependencies - A mapping of dependency names to their currently specified versions.
53
+ */
54
+ function patch(dependencies) {
55
+ if (!dependencies)
56
+ return;
57
+ for (const name of Object.keys(dependencies)) {
58
+ dependencies[name] = latestVersion.get(name) ?? dependencies[name];
59
+ }
60
+ }
61
+ });
62
+ // Step 2: Remove existing dependencies and lock file
63
+ await check('Remove all dependencies', async () => {
64
+ await shell.run('rm -rf node_modules');
65
+ await shell.run('rm -f package-lock.json');
66
+ });
67
+ // Step 3: Reinstall/upgrade all dependencies
68
+ await check('Upgrade all dependencies', shell.stdout('npm update --save'));
69
+ // Final log message
70
+ info('All dependencies are up to date');
71
+ }
72
+ /**
73
+ * Compares two semantic version strings (major.minor.patch) and checks if `a` is greater than `b`.
74
+ *
75
+ * @param a - A semantic version string (e.g., "1.2.3").
76
+ * @param b - Another semantic version string (e.g., "1.2.4").
77
+ * @returns `true` if `a` is greater than `b`, otherwise `false`.
78
+ * @throws If either version string is invalid (i.e., not in "x.x.x" format).
79
+ */
80
+ function isGreaterSemver(a, b) {
81
+ const pa = a.split('.');
82
+ const pb = b.split('.');
83
+ for (let i = 0; i < 3; i++) {
84
+ const na = Number(pa[i]);
85
+ const nb = Number(pb[i]);
86
+ if (isNaN(na))
87
+ throw new Error('Invalid version number: ' + a);
88
+ if (isNaN(nb))
89
+ throw new Error('Invalid version number: ' + b);
90
+ if (na > nb)
91
+ return true;
92
+ if (na < nb)
93
+ return false;
94
+ }
95
+ return false;
96
+ }
97
+ //# sourceMappingURL=deps-upgrade.js.map
@@ -31,7 +31,13 @@ export async function generateCommandDocumentation(command) {
31
31
  */
32
32
  async function getCommandResults(command) {
33
33
  return new Promise((resolve, reject) => {
34
- const env = { ...process.env, NODE_ENV: undefined };
34
+ const env = {
35
+ ...process.env,
36
+ NODE_ENV: undefined,
37
+ NODE_DISABLE_COLORS: '1',
38
+ NO_COLORS: '1',
39
+ FORCE_COLOR: '0'
40
+ };
35
41
  // Spawn a child process to run the command with the '--help' flag.
36
42
  const childProcess = cp.spawn('npx', [...command.split(' '), '--help'], { env });
37
43
  let output = '';
@@ -81,4 +87,4 @@ function extractSubcommands(result) {
81
87
  return [subcommand];
82
88
  });
83
89
  }
84
- //# sourceMappingURL=command.js.map
90
+ //# sourceMappingURL=doc-command.js.map
@@ -0,0 +1,4 @@
1
+ export declare function generateTypescriptDocs(options: {
2
+ entryPoint?: string;
3
+ outputPath?: string;
4
+ }): Promise<void>;
@@ -0,0 +1,43 @@
1
+ import * as td from 'typedoc';
2
+ import * as tdMarkdown from 'typedoc-plugin-markdown';
3
+ import * as tdTheme from 'typedoc-github-wiki-theme';
4
+ import { panic, warn } from '../lib/log.js';
5
+ export async function generateTypescriptDocs(options) {
6
+ const app = await td.Application.bootstrapWithPlugins({
7
+ entryPoints: [options.entryPoint ?? './src/index.ts'],
8
+ gitRevision: 'main',
9
+ outputs: [{ name: 'markdown', path: options.outputPath ?? './docs' }],
10
+ }, [
11
+ new td.ArgumentsReader(0),
12
+ new td.TypeDocReader(),
13
+ new td.PackageJsonReader(),
14
+ new td.TSConfigReader(),
15
+ new td.ArgumentsReader(300),
16
+ ]);
17
+ tdMarkdown.load(app);
18
+ tdTheme.load(app);
19
+ app.options.setValue('readme', 'none');
20
+ app.options.setValue('hidePageHeader', true);
21
+ app.options.setValue('classPropertiesFormat', 'table');
22
+ app.options.setValue('enumMembersFormat', 'table');
23
+ app.options.setValue('indexFormat', 'table');
24
+ app.options.setValue('interfacePropertiesFormat', 'table');
25
+ app.options.setValue('parametersFormat', 'table');
26
+ app.options.setValue('propertiesFormat', 'table');
27
+ app.options.setValue('propertyMembersFormat', 'table');
28
+ app.options.setValue('typeDeclarationFormat', 'table');
29
+ const project = await app.convert();
30
+ if (!project)
31
+ panic('Failed to convert project');
32
+ app.validate(project);
33
+ if (app.logger.hasWarnings())
34
+ warn('Warnings found during validation');
35
+ if (app.logger.hasErrors())
36
+ panic('Errors found during validation');
37
+ await app.generateOutputs(project);
38
+ if (app.logger.hasWarnings())
39
+ warn('Warnings found during validation');
40
+ if (app.logger.hasErrors())
41
+ panic('Errors found during validation');
42
+ }
43
+ //# sourceMappingURL=doc-typescript.js.map
@@ -126,4 +126,4 @@ export async function release(directory, branch = 'main') {
126
126
  }
127
127
  }
128
128
  }
129
- //# sourceMappingURL=release.js.map
129
+ //# sourceMappingURL=release-npm.js.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  #!/usr/bin/env -S node --enable-source-maps
2
2
  import { Command } from 'commander';
3
+ /**
4
+ * Main CLI program, configured with custom text styling for titles, commands, options, etc.
5
+ */
3
6
  export declare const program: Command;
package/dist/index.js CHANGED
@@ -1,67 +1,140 @@
1
1
  #!/usr/bin/env -S node --enable-source-maps
2
2
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
- import { generateTsMarkdownDoc } from './commands/typedoc.js';
4
+ import { styleText } from 'node:util';
5
5
  import { injectMarkdown, updateTOC } from './commands/markdown.js';
6
6
  import { Command, InvalidArgumentError } from 'commander';
7
7
  import { cwd } from 'node:process';
8
- import { generateCommandDocumentation } from './commands/command.js';
9
- import { release } from './commands/release.js';
8
+ import { generateCommandDocumentation } from './commands/doc-command.js';
9
+ import { release } from './commands/release-npm.js';
10
+ import { upgradeDependencies } from './commands/deps-upgrade.js';
11
+ import { generateDependencyGraph } from './commands/deps-graph.js';
12
+ import { checkPackage } from './commands/check-package.js';
13
+ import { generateTypescriptDocs } from './commands/doc-typescript.js';
14
+ /**
15
+ * Main CLI program, configured with custom text styling for titles, commands, options, etc.
16
+ */
10
17
  export const program = new Command();
18
+ program.configureHelp({
19
+ styleTitle: (str) => styleText('bold', str),
20
+ styleCommandText: (str) => styleText('bold', str),
21
+ styleOptionText: (str) => styleText('cyan', str),
22
+ styleArgumentText: (str) => styleText('green', str),
23
+ styleSubcommandText: (str) => styleText('yellow', str),
24
+ sortOptions: true,
25
+ sortSubcommands: true,
26
+ });
11
27
  program
12
28
  .name('vrt')
13
- .description('versatiles release and documentaion tool');
14
- program.command('ts2md')
15
- .description('documents a TypeScript file and outputs it to stdout')
16
- .argument('<typescript>', 'Filename of the TypeScript file', checkFilename)
17
- .argument('<tsconfig>', 'Filename of tsconfig.json', checkFilename)
18
- .action(async (tsFilename, tsConfig) => {
19
- const mdDocumentation = await generateTsMarkdownDoc([tsFilename], tsConfig);
20
- process.stdout.write(mdDocumentation);
29
+ .description('CLI tool for releasing packages and generating documentation for Node.js/TypeScript projects.');
30
+ /**
31
+ * Command: check-package
32
+ * Checks that the project's package.json includes certain required scripts/fields.
33
+ */
34
+ program.command('check-package')
35
+ .description('Check package.json for required scripts and other metadata.')
36
+ .action(() => {
37
+ void checkPackage(process.cwd());
38
+ });
39
+ /**
40
+ * Command: deps-graph
41
+ * Analyzes the project’s files to produce a dependency graph (in Mermaid format).
42
+ */
43
+ program.command('deps-graph')
44
+ .description('Analyze project files and output a dependency graph as Mermaid markup.')
45
+ .action(() => {
46
+ void generateDependencyGraph(process.cwd());
21
47
  });
22
- program.command('cmd2md')
23
- .description('documents a runnable command and outputs it to stdout')
24
- .argument('<command>', 'command to run')
48
+ /**
49
+ * Command: deps-upgrade
50
+ * Upgrades project dependencies in package.json to their latest versions and reinstalls them.
51
+ */
52
+ program.command('deps-upgrade')
53
+ .description('Upgrade all dependencies in the current project to their latest versions.')
54
+ .action(() => {
55
+ void upgradeDependencies(process.cwd());
56
+ });
57
+ /**
58
+ * Command: doc-command
59
+ * Generates Markdown documentation for a given CLI command.
60
+ */
61
+ program.command('doc-command')
62
+ .description('Generate Markdown documentation for a specified command and output the result.')
63
+ .argument('<command>', 'Command to document (e.g., "npm run build").')
25
64
  .action(async (command) => {
26
65
  const mdDocumentation = await generateCommandDocumentation(command);
27
66
  process.stdout.write(mdDocumentation);
28
67
  });
29
- program.command('insertmd')
30
- .description('takes Markdown from stdin and insert it into a Markdown file')
31
- .argument('<readme>', 'Markdown file, like a readme.md', checkFilename)
32
- .argument('[heading]', 'Heading in the Markdown file', '# API')
33
- .argument('[foldable]', 'Make content foldable', false)
68
+ /**
69
+ * Command: doc-insert
70
+ * Inserts Markdown content from stdin into a specified Markdown file under a given heading.
71
+ * Optionally makes the inserted content foldable.
72
+ */
73
+ program.command('doc-insert')
74
+ .description('Insert Markdown from stdin into a specified section of a Markdown file.')
75
+ .argument('<readme>', 'Path to the target Markdown file (e.g., README.md).', checkFilename)
76
+ .argument('[heading]', 'Heading in the Markdown file where content should be placed. Default is "# API".', '# API')
77
+ .argument('[foldable]', 'Whether to wrap the inserted content in a foldable section.', false)
34
78
  .action(async (mdFilename, heading, foldable) => {
35
79
  const buffers = [];
36
- for await (const data of process.stdin)
80
+ for await (const data of process.stdin) {
37
81
  buffers.push(data);
38
- const mdContent = '<!--- This chapter is generated automatically --->\n' + Buffer.concat(buffers).toString();
82
+ }
83
+ const mdContent = '<!--- This chapter is generated automatically --->\n'
84
+ + Buffer.concat(buffers).toString();
39
85
  let mdFile = readFileSync(mdFilename, 'utf8');
40
86
  mdFile = injectMarkdown(mdFile, mdContent, heading, foldable);
41
87
  writeFileSync(mdFilename, mdFile);
42
88
  });
43
- program.command('inserttoc')
44
- .description('updates the TOC in a Markdown file')
45
- .argument('<readme>', 'Markdown file, like a readme.md', checkFilename)
46
- .argument('[heading]', 'Heading in the Markdown file', '# Table of Content')
89
+ /**
90
+ * Command: doc-toc
91
+ * Updates or generates a Table of Contents in a Markdown file under a specified heading.
92
+ */
93
+ program.command('doc-toc')
94
+ .description('Generate a Table of Contents (TOC) in a Markdown file.')
95
+ .argument('<readme>', 'Path to the Markdown file (e.g., README.md).', checkFilename)
96
+ .argument('[heading]', 'Heading in the Markdown file where TOC should be inserted. Default is "# Table of Content".', '# Table of Content')
47
97
  .action((mdFilename, heading) => {
48
98
  let mdFile = readFileSync(mdFilename, 'utf8');
49
99
  mdFile = updateTOC(mdFile, heading);
50
100
  writeFileSync(mdFilename, mdFile);
51
101
  });
102
+ /**
103
+ * Command: doc-typescript
104
+ * Generates documentation for a TypeScript project.
105
+ * Allows specifying entry point and output location.
106
+ */
107
+ program.command('doc-typescript')
108
+ .description('Generate documentation for a TypeScript project.')
109
+ .option('-i <entryPoint>', 'Entry point of the TypeScript project. Default is "./src/index.ts".')
110
+ .option('-o <outputPath>', 'Output path for the generated documentation. Default is "./docs".')
111
+ .action(async (options) => {
112
+ await generateTypescriptDocs(options);
113
+ });
114
+ /**
115
+ * Command: release-npm
116
+ * Releases/publishes an npm package from a specified project path to the npm registry.
117
+ */
52
118
  program.command('release-npm')
53
- .description('release a npm package')
54
- .argument('[path]', 'root path of the Node.js project')
119
+ .description('Publish an npm package from the specified path to the npm registry.')
120
+ .argument('[path]', 'Root path of the Node.js project. Defaults to the current directory.')
55
121
  .action((path) => {
56
- void release(resolve(path ?? ',', process.cwd()), 'main');
122
+ void release(resolve(path ?? '.', process.cwd()), 'main');
57
123
  });
58
124
  if (process.env.NODE_ENV !== 'test') {
59
125
  await program.parseAsync();
60
126
  }
127
+ /**
128
+ * Validates that the given filename exists.
129
+ * Throws an InvalidArgumentError if the file cannot be found.
130
+ *
131
+ * @param filename - The filename to check.
132
+ * @returns The resolved full path if the file exists.
133
+ */
61
134
  function checkFilename(filename) {
62
135
  const fullname = resolve(cwd(), filename);
63
136
  if (!existsSync(fullname)) {
64
- throw new InvalidArgumentError('file not found');
137
+ throw new InvalidArgumentError(`File not found: ${filename}`);
65
138
  }
66
139
  return fullname;
67
140
  }
package/dist/lib/log.d.ts CHANGED
@@ -2,4 +2,4 @@ export declare function panic(text: string): never;
2
2
  export declare function warn(text: string): void;
3
3
  export declare function info(text: string): void;
4
4
  export declare function abort(): never;
5
- export declare function check<T>(message: string, promise: Promise<T>): Promise<T>;
5
+ export declare function check<T>(message: string, promise: (Promise<T>) | (() => Promise<T>)): Promise<T>;
package/dist/lib/log.js CHANGED
@@ -15,14 +15,14 @@ export function abort() {
15
15
  export async function check(message, promise) {
16
16
  process.stderr.write(`\x1b[0;90m\u2B95 ${message}\x1b[0m`);
17
17
  try {
18
- const result = await promise;
18
+ const result = await (typeof promise === 'function' ? promise() : promise);
19
19
  process.stderr.write(`\r\x1b[0;92m\u2714 ${message}\x1b[0m\n`);
20
20
  return result;
21
21
  }
22
22
  catch (error) {
23
23
  process.stderr.write(`\r\x1b[0;91m\u2718 ${message}\x1b[0m\n`);
24
24
  panic(error.message);
25
- throw Error();
25
+ throw error;
26
26
  }
27
27
  }
28
28
  //# sourceMappingURL=log.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versatiles/release-tool",
3
- "version": "1.2.7",
3
+ "version": "2.1.0",
4
4
  "description": "VersaTiles release and documentation tools",
5
5
  "bin": {
6
6
  "vrt": "./dist/index.js"
@@ -10,44 +10,49 @@
10
10
  "dist/**/*.d.ts"
11
11
  ],
12
12
  "scripts": {
13
- "build": "rm -rf dist && tsc -p tsconfig.build.json && chmod +x dist/index.js",
13
+ "build": "npm run build-node && npm run doc",
14
+ "build-node": "rm -rf dist && tsc -p tsconfig.build.json && chmod +x dist/index.js",
14
15
  "check": "npm run lint && npm run build && npm run test",
15
- "doc": "npx vrt cmd2md vrt | npx vrt insertmd README.md '# Command'",
16
+ "dev": "tsx src/index.ts",
17
+ "doc": "npm run doc-command && npm run doc-graph",
18
+ "doc-command": "tsx src/index.ts doc-command vrt | tsx src/index.ts doc-insert README.md '# Command'",
19
+ "doc-graph": "tsx src/index.ts deps-graph | tsx src/index.ts doc-insert README.md '## Dependency Graph'",
16
20
  "lint": "eslint . --color",
17
- "prepack": "npm run build && npm run doc",
18
- "release": "npm run build && npx vrt release-npm",
21
+ "prepack": "npm run build",
22
+ "release": "tsx src/index.ts release-npm",
19
23
  "test-coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
20
24
  "test": "NODE_OPTIONS=--experimental-vm-modules jest",
21
- "upgrade": "npm-check-updates -u && rm -f package-lock.json; rm -rf node_modules; npm i && npm update"
25
+ "upgrade": "tsx src/index.ts deps-upgrade"
22
26
  },
23
- "author": "yetzt <node@yetzt.me>, Michael Kreil <versatiles@michael-kreil.de>",
27
+ "author": "Michael Kreil <versatiles@michael-kreil.de>",
24
28
  "license": "Unlicense",
25
29
  "type": "module",
26
30
  "repository": {
27
31
  "type": "git",
28
- "url": "git+https://github.com/versatiles-org/node-versatiles.git"
32
+ "url": "git+https://github.com/versatiles-org/node-release-tool.git"
29
33
  },
30
- "homepage": "https://github.com/versatiles-org/node-versatiles/blob/main/versatiles-release-tool/README.md",
34
+ "homepage": "https://github.com/versatiles-org/node-release-tool",
31
35
  "devDependencies": {
32
- "@types/inquirer": "^9.0.7",
36
+ "@schemastore/package": "^0.0.10",
33
37
  "@types/jest": "^29.5.14",
34
- "@types/node": "^22.13.0",
38
+ "@types/node": "^22.13.5",
35
39
  "@typescript-eslint/eslint-plugin": "^8.22.0",
36
40
  "@typescript-eslint/parser": "^8.22.0",
37
- "eslint": "^9.19.0",
41
+ "eslint": "^9.21.0",
38
42
  "jest": "^29.7.0",
39
- "npm-check-updates": "^17.1.14",
40
43
  "ts-jest": "^29.2.5",
41
- "ts-node": "^10.9.2",
42
- "tsx": "^4.19.2",
44
+ "tsx": "^4.19.3",
43
45
  "typescript": "^5.7.3",
44
- "typescript-eslint": "^8.22.0"
46
+ "typescript-eslint": "^8.24.1"
45
47
  },
46
48
  "dependencies": {
47
- "@inquirer/select": "^4.0.7",
49
+ "@inquirer/select": "^4.0.9",
48
50
  "commander": "^13.1.0",
51
+ "dependency-cruiser": "^16.10.0",
49
52
  "remark": "^15.0.1",
50
- "remark-gfm": "^4.0.0",
51
- "typedoc": "^0.27.6"
53
+ "remark-gfm": "^4.0.1",
54
+ "typedoc": "^0.27.8",
55
+ "typedoc-github-wiki-theme": "^2.1.0",
56
+ "typedoc-plugin-markdown": "^4.4.2"
52
57
  }
53
58
  }
package/LICENSE.md DELETED
@@ -1,24 +0,0 @@
1
- This is free and unencumbered software released into the public domain.
2
-
3
- Anyone is free to copy, modify, publish, use, compile, sell, or
4
- distribute this software, either in source code form or as a compiled
5
- binary, for any purpose, commercial or non-commercial, and by any
6
- means.
7
-
8
- In jurisdictions that recognize copyright laws, the author or authors
9
- of this software dedicate any and all copyright interest in the
10
- software to the public domain. We make this dedication for the benefit
11
- of the public at large and to the detriment of our heirs and
12
- successors. We intend this dedication to be an overt act of
13
- relinquishment in perpetuity of all present and future rights to this
14
- software under copyright law.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
- IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
- OTHER DEALINGS IN THE SOFTWARE.
23
-
24
- For more information, please refer to [unlicense.org](https://unlicense.org/)
@@ -1,6 +0,0 @@
1
- /**
2
- * Generate markdown documentation from TypeScript files.
3
- * @param sourceFilePaths - Array of absolute TypeScript file paths.
4
- * @param tsConfigPath - Absolute file path of tsconfig.json.
5
- */
6
- export declare function generateTsMarkdownDoc(sourceFilePaths: string[], tsConfigPath: string): Promise<string>;
@@ -1,282 +0,0 @@
1
- import { Application, ReflectionKind, } from 'typedoc';
2
- /**
3
- * Generate markdown documentation from TypeScript files.
4
- * @param sourceFilePaths - Array of absolute TypeScript file paths.
5
- * @param tsConfigPath - Absolute file path of tsconfig.json.
6
- */
7
- export async function generateTsMarkdownDoc(sourceFilePaths, tsConfigPath) {
8
- const app = await Application.bootstrap({ entryPoints: sourceFilePaths, tsconfig: tsConfigPath });
9
- const project = await app.convert();
10
- if (!project) {
11
- throw new Error('Failed to convert TypeScript project.');
12
- }
13
- return Array.from(documentProject(project)).join('\n');
14
- }
15
- function* documentProject(project) {
16
- if (!project.groups) {
17
- throw new Error('No TypeScript code to document found! Is this a lib?');
18
- }
19
- for (const group of project.groups) {
20
- yield '\n# ' + group.title;
21
- for (const d of group.children) {
22
- const declaration = d;
23
- switch (declaration.kind) {
24
- case ReflectionKind.Class:
25
- yield* documentClass(declaration);
26
- break;
27
- case ReflectionKind.Function:
28
- yield* documentMethod(declaration, 2);
29
- break;
30
- case ReflectionKind.Interface:
31
- yield* documentInterface(declaration);
32
- break;
33
- case ReflectionKind.TypeAlias:
34
- yield* documentType(declaration);
35
- break;
36
- case ReflectionKind.Variable:
37
- yield* documentVariable(declaration);
38
- break;
39
- default:
40
- throw new Error('implement ' + declaration.kind);
41
- }
42
- }
43
- }
44
- }
45
- function* documentInterface(declaration) {
46
- yield `\n## Interface: \`${declaration.name}\`<a id="${createAnchorId(declaration)}"></a>`;
47
- yield '\n```typescript';
48
- yield 'interface {';
49
- for (const child of declaration.children ?? []) {
50
- if (child.kind !== ReflectionKind.Property)
51
- throw Error('should be a property inside an interface');
52
- if (child.type == null)
53
- throw Error('should have a type');
54
- const name = child.name + (child.flags.isOptional ? '?' : '');
55
- yield ` ${name}: ${formatTypeDeclaration(child.type)};`;
56
- }
57
- yield '}';
58
- yield '```';
59
- }
60
- function* documentType(declaration) {
61
- yield `\n## Type: \`${declaration.name}\`<a id="${createAnchorId(declaration)}"></a>`;
62
- if (declaration.type) {
63
- yield `\n**Type:** <code>${formatTypeDeclaration(declaration.type)}</code>`;
64
- }
65
- }
66
- function* documentClass(declaration) {
67
- yield `\n## Class: \`${declaration.name}\`<a id="${createAnchorId(declaration)}"></a>`;
68
- yield* documentSummaryBlock(declaration);
69
- for (const group of declaration.groups ?? []) {
70
- const publicMembers = group.children.filter(member => !member.flags.isPrivate && !member.flags.isProtected);
71
- if (publicMembers.length === 0)
72
- continue;
73
- // Sort by order in code
74
- publicMembers.sort((a, b) => a.id - b.id);
75
- switch (group.title) {
76
- case 'Constructors':
77
- if (publicMembers.length !== 1)
78
- throw Error('publicMembers.length !== 1');
79
- yield* documentMethod(publicMembers[0], 3, true);
80
- continue;
81
- case 'Accessors':
82
- yield '\n### Accessors';
83
- for (const member of publicMembers)
84
- yield documentAccessor(member);
85
- continue;
86
- case 'Properties':
87
- yield '\n### Properties';
88
- for (const member of publicMembers)
89
- yield documentProperty(member);
90
- continue;
91
- case 'Methods':
92
- for (const member of publicMembers)
93
- yield* documentMethod(member, 3);
94
- continue;
95
- default:
96
- console.log(group);
97
- throw Error('Unknown group title');
98
- }
99
- }
100
- }
101
- function* documentMethod(method, depth, isConstructor = false) {
102
- if (method.signatures?.length !== 1)
103
- throw Error('should be 1');
104
- const [signature] = method.signatures;
105
- const parameters = formatMethodParameters(signature.parameters ?? []);
106
- if (isConstructor) {
107
- yield `\n${'#'.repeat(depth)} Constructor: \`new ${signature.name}(${parameters})\``;
108
- }
109
- else {
110
- yield `\n${'#'.repeat(depth)} Method: \`${signature.name}(${parameters})\``;
111
- }
112
- yield* documentSummaryBlock(signature);
113
- if (signature.parameters && signature.parameters.length > 0) {
114
- yield '';
115
- yield '**Parameters:**';
116
- for (const parameter of signature.parameters) {
117
- yield documentProperty(parameter);
118
- }
119
- }
120
- if (signature.type && !isConstructor) {
121
- yield `\n**Returns:** <code>${formatTypeDeclaration(signature.type)}</code>`;
122
- }
123
- }
124
- function formatMethodParameters(parameters) {
125
- return parameters.map(param => param.name).join(', ');
126
- }
127
- // Helper Functions
128
- function getDeclarationKindName(kind) {
129
- switch (kind) {
130
- case ReflectionKind.Class: return 'Class';
131
- case ReflectionKind.Function: return 'Function';
132
- case ReflectionKind.Interface: return 'Interface';
133
- case ReflectionKind.TypeAlias: return 'Type';
134
- case ReflectionKind.Variable: return 'Variable';
135
- default: throw new Error(`Unknown reflection kind: ${kind}`);
136
- }
137
- }
138
- function documentProperty(ref) {
139
- let line = ` - <code>${ref.name}${resolveTypeDeclaration(ref.type)}</code>`;
140
- if (ref.flags.isOptional)
141
- line += ' (optional)';
142
- const summary = extractSummary(ref.comment);
143
- if (summary != null)
144
- line += ' \n ' + summary;
145
- return line;
146
- }
147
- function* documentVariable(ref) {
148
- const prefix = ref.flags.isConst ? 'const' : 'let';
149
- yield `\n## \`${prefix} ${ref.name}\``;
150
- const summary = extractSummary(ref.comment);
151
- if (summary != null)
152
- yield summary;
153
- }
154
- function documentAccessor(ref) {
155
- let line = ` - <code>${ref.name}${resolveTypeDeclaration(ref.type)}</code>`;
156
- const summary = extractSummary(ref.comment);
157
- if (summary != null)
158
- line += ' \n ' + summary;
159
- return line;
160
- }
161
- function extractSummary(comment) {
162
- if (!comment)
163
- return null;
164
- return comment.summary.map(line => line.text).join('');
165
- }
166
- function* documentSummaryBlock(ref) {
167
- yield '';
168
- if (ref.comment) {
169
- yield formatComment(ref.comment);
170
- return;
171
- }
172
- const { type } = ref;
173
- if (type?.type === 'reflection') {
174
- if (type.declaration.signatures?.length !== 1)
175
- throw Error('type.declaration.signatures?.length !== 1');
176
- const [signature] = type.declaration.signatures;
177
- if (signature.comment) {
178
- yield formatComment(signature.comment);
179
- return;
180
- }
181
- }
182
- const sourceLink = createSourceLink(ref);
183
- if (sourceLink != null)
184
- yield sourceLink;
185
- return;
186
- function formatComment(comment) {
187
- let summary = extractSummary(comment) ?? '';
188
- const link = createSourceLink(ref);
189
- if (link != null)
190
- summary += ' ' + link;
191
- return summary.replace(/\n/mg, ' \n') + '\n';
192
- }
193
- }
194
- function resolveTypeDeclaration(someType) {
195
- if (!someType)
196
- return '';
197
- return `: ${formatTypeDeclaration(someType)}`;
198
- }
199
- function formatTypeDeclaration(someType) {
200
- return getTypeRec(someType);
201
- function getTypeRec(some) {
202
- switch (some.type) {
203
- case 'intrinsic':
204
- return some.name;
205
- case 'literal':
206
- return JSON.stringify(some.value);
207
- case 'reference': {
208
- let result = some.name;
209
- if (some.reflection)
210
- result = `[${result}](#${createAnchorId(some.reflection)})`;
211
- if (some.typeArguments?.length ?? 0)
212
- result += '&lt;'
213
- + (some.typeArguments ?? [])
214
- .map(getTypeRec).join(',')
215
- + '&gt;';
216
- return result;
217
- }
218
- case 'reflection':
219
- switch (some.declaration.kind) {
220
- case ReflectionKind.TypeLiteral: return decodeReflectionTypeLiteral(some.declaration);
221
- default:
222
- console.log('declarationKindName', getDeclarationKindName(some.declaration.kind));
223
- console.dir(some, { depth: 4 });
224
- throw Error();
225
- }
226
- case 'tuple':
227
- return `[${some.elements.map(getTypeRec).join(', ')}]`;
228
- case 'union':
229
- return some.types.map(getTypeRec).join(' | ');
230
- case 'array':
231
- return getTypeRec(some.elementType) + '[]';
232
- default:
233
- console.log(some);
234
- throw Error(some.type);
235
- }
236
- function decodeReflectionTypeLiteral(ref) {
237
- try {
238
- if (ref.variant !== 'declaration')
239
- throw Error();
240
- if (ref.groups && !ref.signatures) {
241
- if (!Array.isArray(ref.groups))
242
- throw Error();
243
- if (ref.groups.length !== 1)
244
- throw Error();
245
- const [group] = ref.groups;
246
- if (group.title !== 'Properties')
247
- throw Error();
248
- const properties = group.children.map(r => r.escapedName + ':?');
249
- return `{${properties.join(', ')}}`;
250
- }
251
- if (!ref.groups && ref.signatures) {
252
- if (ref.signatures.length !== 1)
253
- throw Error('ref.signatures.length !== 1');
254
- const [signature] = ref.signatures;
255
- const returnType = signature.type ? getTypeRec(signature.type) : 'void';
256
- const parameters = (signature.parameters ?? [])
257
- .map(p => {
258
- return p.name + (p.type ? ': ' + getTypeRec(p.type) : '');
259
- }).join(', ');
260
- return `(${parameters}) => ${returnType}`;
261
- }
262
- throw Error();
263
- }
264
- catch (error) {
265
- console.dir(ref, { depth: 3 });
266
- throw error;
267
- }
268
- }
269
- }
270
- }
271
- function createSourceLink(reference) {
272
- if (!reference.sources || reference.sources.length < 1)
273
- return null;
274
- if (reference.sources.length > 1)
275
- throw Error('ref.sources.length > 1');
276
- const [source] = reference.sources;
277
- return `<sup><a href="${source.url}">[src]</a></sup>`;
278
- }
279
- function createAnchorId(reference) {
280
- return `${getDeclarationKindName(reference.kind)}_${reference.name}`.toLowerCase();
281
- }
282
- //# sourceMappingURL=typedoc.js.map