@travetto/doc 8.0.0-alpha.19 → 8.0.0-alpha.20
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/README.md +26 -25
- package/__index__.ts +3 -3
- package/package.json +3 -3
- package/src/jsx.ts +48 -20
- package/src/mapping/library.ts +7 -4
- package/src/mapping/module.ts +170 -58
- package/src/render/code-highlight.ts +3 -5
- package/src/render/context.ts +19 -15
- package/src/render/html.ts +41 -27
- package/src/render/markdown.ts +18 -16
- package/src/render/renderer.ts +23 -21
- package/src/types.ts +7 -8
- package/src/util/file.ts +37 -37
- package/src/util/package.ts +19 -13
- package/src/util/resolve.ts +11 -12
- package/src/util/run.ts +14 -10
- package/src/util/types.ts +1 -1
- package/support/cli.doc.ts +7 -9
- package/support/jsx-runtime.ts +26 -15
package/src/render/markdown.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
|
|
3
|
-
import { CodecUtil, Runtime, RuntimeError, RuntimeIndex } from '@travetto/runtime';
|
|
4
|
-
import { PackageUtil } from '@travetto/manifest';
|
|
5
3
|
import { HELP_FLAG } from '@travetto/cli';
|
|
4
|
+
import { PackageUtil } from '@travetto/manifest';
|
|
5
|
+
import { CodecUtil, Runtime, RuntimeError, RuntimeIndex } from '@travetto/runtime';
|
|
6
6
|
|
|
7
|
-
import type { RenderProvider } from '../types.ts';
|
|
8
7
|
import { c, getComponentName } from '../jsx.ts';
|
|
9
|
-
import { MODULES } from '../mapping/module.ts';
|
|
10
8
|
import { LIBRARIES } from '../mapping/library.ts';
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
9
|
+
import { MODULES } from '../mapping/module.ts';
|
|
10
|
+
import type { RenderProvider } from '../types.ts';
|
|
13
11
|
import { PackageDocUtil } from '../util/package.ts';
|
|
12
|
+
import { DocResolveUtil } from '../util/resolve.ts';
|
|
13
|
+
import type { RenderContext } from './context.ts';
|
|
14
14
|
|
|
15
15
|
export const Markdown: RenderProvider<RenderContext> = {
|
|
16
16
|
ext: 'md',
|
|
17
17
|
finalize: (text, context) => {
|
|
18
18
|
const brand = `<!-- ${context.generatedStamp} -->\n<!-- ${context.rebuildStamp} -->`;
|
|
19
19
|
const cleaned = text
|
|
20
|
-
.replace(/(\[[^\]]+\]\([^)]+\))([A-Za-z0-9$]+)/g, (_, link, value) => value === 's' ? _ : `${link} ${value}`)
|
|
20
|
+
.replace(/(\[[^\]]+\]\([^)]+\))([A-Za-z0-9$]+)/g, (_, link, value) => (value === 's' ? _ : `${link} ${value}`))
|
|
21
21
|
.replace(/(\S)\n(#)/g, (_, left, right) => `${left}\n\n${right}`);
|
|
22
22
|
return `${brand}\n${cleaned}`;
|
|
23
23
|
},
|
|
@@ -30,7 +30,7 @@ export const Markdown: RenderProvider<RenderContext> = {
|
|
|
30
30
|
li: async ({ recurse, stack }) => {
|
|
31
31
|
const parent = stack.toReversed().find(node => node.type === 'ol' || node.type === 'ul');
|
|
32
32
|
const depth = stack.filter(node => node.type === 'ol' || node.type === 'ul').length;
|
|
33
|
-
return `${' '.repeat(depth)}${
|
|
33
|
+
return `${' '.repeat(depth)}${parent && parent.type === 'ol' ? '1.' : '* '} ${await recurse()}\n`;
|
|
34
34
|
},
|
|
35
35
|
table: async ({ recurse }) => `${await recurse()}`,
|
|
36
36
|
tbody: async ({ recurse }) => `${await recurse()}`,
|
|
@@ -45,8 +45,8 @@ export const Markdown: RenderProvider<RenderContext> = {
|
|
|
45
45
|
h4: async ({ recurse }) => `\n#### ${await recurse()}\n\n`,
|
|
46
46
|
Execution: async ({ context, node, props, createState }) => {
|
|
47
47
|
const output = await context.execute(node);
|
|
48
|
-
const displayCmd =
|
|
49
|
-
`${node.props.cmd} ${(node.props.args ?? []).join(' ')}`;
|
|
48
|
+
const displayCmd =
|
|
49
|
+
props.config?.formatCommand?.(props.cmd, props.args ?? []) ?? `${node.props.cmd} ${(node.props.args ?? []).join(' ')}`;
|
|
50
50
|
const state = createState('Terminal', {
|
|
51
51
|
language: 'bash',
|
|
52
52
|
title: node.props.title,
|
|
@@ -56,12 +56,14 @@ export const Markdown: RenderProvider<RenderContext> = {
|
|
|
56
56
|
},
|
|
57
57
|
CliHelpExecution: async ({ context, props, createState }) => {
|
|
58
58
|
const { name: command } = context.resolveCliCommandFromClass(props.commandClass);
|
|
59
|
-
return await Markdown.Execution(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
return await Markdown.Execution(
|
|
60
|
+
createState('Execution', {
|
|
61
|
+
title: `Help for ${command}`,
|
|
62
|
+
cmd: 'trv',
|
|
63
|
+
args: [command, HELP_FLAG],
|
|
64
|
+
config: { ...props.config }
|
|
65
|
+
})
|
|
66
|
+
);
|
|
65
67
|
},
|
|
66
68
|
CliHelpDescription: async ({ context, props }) => {
|
|
67
69
|
const { description = '' } = context.resolveCliCommandFromClass(props.commandClass);
|
package/src/render/renderer.ts
CHANGED
|
@@ -1,30 +1,28 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
3
|
import { type ManifestContext, PackageUtil } from '@travetto/manifest';
|
|
4
|
-
import {
|
|
4
|
+
import { type Class, castTo, Runtime, RuntimeError } from '@travetto/runtime';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { isJSXElement, type JSXElement, JSXFragmentType } from '../../support/jsx-runtime.ts';
|
|
7
|
+
import { type c, EMPTY_ELEMENT, getComponentName, type JSXElementByFn } from '../jsx.ts';
|
|
7
8
|
import type { DocumentShape, RenderProvider, RenderState } from '../types.ts';
|
|
8
9
|
import { DocFileUtil } from '../util/file.ts';
|
|
9
|
-
|
|
10
10
|
import { RenderContext } from './context.ts';
|
|
11
11
|
import { Html } from './html.ts';
|
|
12
12
|
import { Markdown } from './markdown.ts';
|
|
13
13
|
|
|
14
|
-
import { isJSXElement, type JSXElement, JSXFragmentType } from '../../support/jsx-runtime.ts';
|
|
15
|
-
|
|
16
14
|
const providers = { [Html.ext]: Html, [Markdown.ext]: Markdown };
|
|
17
15
|
|
|
18
16
|
/**
|
|
19
17
|
* Doc Renderer
|
|
20
18
|
*/
|
|
21
19
|
export class DocRenderer {
|
|
22
|
-
|
|
23
20
|
static async get(file: string, manifest: Pick<ManifestContext, 'workspace'>): Promise<DocRenderer> {
|
|
24
21
|
const document = await Runtime.importFrom<DocumentShape>(file);
|
|
25
22
|
const pkg = PackageUtil.readPackage(manifest.workspace.path);
|
|
26
23
|
const repoBaseUrl = pkg.travetto?.doc?.baseUrl ?? manifest.workspace.path;
|
|
27
|
-
return new DocRenderer(
|
|
24
|
+
return new DocRenderer(
|
|
25
|
+
document,
|
|
28
26
|
new RenderContext(file, repoBaseUrl, path.resolve(pkg.travetto?.doc?.root ?? manifest.workspace.path))
|
|
29
27
|
);
|
|
30
28
|
}
|
|
@@ -38,11 +36,7 @@ export class DocRenderer {
|
|
|
38
36
|
this.#support = support;
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
async #buildLink(
|
|
42
|
-
renderer: RenderProvider<RenderContext>,
|
|
43
|
-
cls: Class,
|
|
44
|
-
title?: string
|
|
45
|
-
) {
|
|
39
|
+
async #buildLink(renderer: RenderProvider<RenderContext>, cls: Class, title?: string) {
|
|
46
40
|
const source = DocFileUtil.readSource(cls);
|
|
47
41
|
if (source) {
|
|
48
42
|
title = DocFileUtil.isDecorator(cls.name, source.file) ? `@${title ?? cls.name}` : (title ?? cls.name);
|
|
@@ -53,7 +47,11 @@ export class DocRenderer {
|
|
|
53
47
|
});
|
|
54
48
|
// @ts-expect-error
|
|
55
49
|
const state: RenderState<JSXElementByFn<'CodeLink'>, RenderContext> = {
|
|
56
|
-
node,
|
|
50
|
+
node,
|
|
51
|
+
props: node.props,
|
|
52
|
+
recurse: async () => '',
|
|
53
|
+
context: this.#support,
|
|
54
|
+
stack: []
|
|
57
55
|
};
|
|
58
56
|
// @ts-expect-error
|
|
59
57
|
state.createState = (key, props) => this.createState(state, key, props);
|
|
@@ -66,7 +64,6 @@ export class DocRenderer {
|
|
|
66
64
|
input: JSXElement[] | JSXElement | string | bigint | object | number | boolean | null | undefined,
|
|
67
65
|
stack: JSXElement[] = []
|
|
68
66
|
): Promise<string | undefined> {
|
|
69
|
-
|
|
70
67
|
if (input === null || input === undefined) {
|
|
71
68
|
return '';
|
|
72
69
|
} else if (Array.isArray(input)) {
|
|
@@ -99,7 +96,11 @@ export class DocRenderer {
|
|
|
99
96
|
const recurse = () => this.#render(renderer, final.props.children ?? [], [...stack, final]);
|
|
100
97
|
// @ts-expect-error
|
|
101
98
|
const state: RenderState<JSXElement, RenderContext> = {
|
|
102
|
-
node: final,
|
|
99
|
+
node: final,
|
|
100
|
+
props: final.props,
|
|
101
|
+
recurse,
|
|
102
|
+
stack,
|
|
103
|
+
context: this.#support
|
|
103
104
|
};
|
|
104
105
|
state.createState = (key, props) => this.createState(state, key, props);
|
|
105
106
|
// @ts-expect-error
|
|
@@ -110,10 +111,12 @@ export class DocRenderer {
|
|
|
110
111
|
}
|
|
111
112
|
} else {
|
|
112
113
|
switch (typeof input) {
|
|
113
|
-
case 'string':
|
|
114
|
+
case 'string':
|
|
115
|
+
return input.replace(/ /g, ' ');
|
|
114
116
|
case 'number':
|
|
115
117
|
case 'bigint':
|
|
116
|
-
case 'boolean':
|
|
118
|
+
case 'boolean':
|
|
119
|
+
return `${input}`;
|
|
117
120
|
case 'object': {
|
|
118
121
|
if (input) {
|
|
119
122
|
return await this.#buildLink(renderer, castTo(input.constructor), input.constructor.name.replace(/^[$]/, ''));
|
|
@@ -147,15 +150,14 @@ export class DocRenderer {
|
|
|
147
150
|
throw new RuntimeError(`Unknown renderer with format: ${format}`);
|
|
148
151
|
}
|
|
149
152
|
if (!this.#rootNode) {
|
|
150
|
-
this.#rootNode =
|
|
151
|
-
this.#root.text : await (this.#root.text());
|
|
153
|
+
this.#rootNode = Array.isArray(this.#root.text) || isJSXElement(this.#root.text) ? this.#root.text : await this.#root.text();
|
|
152
154
|
}
|
|
153
155
|
|
|
154
156
|
const text = await this.#render(providers[format], this.#rootNode);
|
|
155
|
-
let cleaned = `${text?.replace(/\n{3,100}/
|
|
157
|
+
let cleaned = `${text?.replace(/\n{3,100}/gms, '\n\n').trim()}\n`;
|
|
156
158
|
if (this.#root.wrap?.[format]) {
|
|
157
159
|
cleaned = this.#root.wrap[format](cleaned);
|
|
158
160
|
}
|
|
159
161
|
return providers[format].finalize(cleaned, this.#support);
|
|
160
162
|
}
|
|
161
|
-
}
|
|
163
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { JSXElementByFn, c } from './jsx.ts';
|
|
2
1
|
import type { JSXElement, ValidHtmlTags } from '../support/jsx-runtime.ts';
|
|
2
|
+
import type { c, JSXElementByFn } from './jsx.ts';
|
|
3
3
|
|
|
4
4
|
export type Wrapper = Record<string, (cnt: string) => string>;
|
|
5
5
|
|
|
@@ -25,11 +25,10 @@ export type RenderState<T extends JSXElement, C> = {
|
|
|
25
25
|
/**
|
|
26
26
|
* Renderer
|
|
27
27
|
*/
|
|
28
|
-
export type RenderProvider<C> =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} &
|
|
33
|
-
{ [K in ValidHtmlTags]: (state: RenderState<JSXElement<K>, C>) => Promise<string>; } &
|
|
28
|
+
export type RenderProvider<C> = {
|
|
29
|
+
ext: string;
|
|
30
|
+
finalize: (text: string, ctx: C) => string;
|
|
31
|
+
} & { [K in ValidHtmlTags]: (state: RenderState<JSXElement<K>, C>) => Promise<string> } & {
|
|
34
32
|
// @ts-expect-error
|
|
35
|
-
|
|
33
|
+
[K in keyof typeof c]: (state: RenderState<JSXElementByFn<K>, C>) => Promise<string>;
|
|
34
|
+
};
|
package/src/util/file.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import { RuntimeError, Runtime, RuntimeIndex } from '@travetto/runtime';
|
|
5
4
|
import { type ManifestModuleFileType, ManifestModuleUtil } from '@travetto/manifest';
|
|
5
|
+
import { Runtime, RuntimeError, RuntimeIndex } from '@travetto/runtime';
|
|
6
6
|
|
|
7
7
|
import type { CodeSourceInput } from './types.ts';
|
|
8
8
|
|
|
@@ -23,21 +23,20 @@ const MOD_FILE_TO_LANG: Record<ManifestModuleFileType, string | undefined> = {
|
|
|
23
23
|
const EXT_TO_LANG: Record<string, string> = {
|
|
24
24
|
'.yaml': 'yaml',
|
|
25
25
|
'.yml': 'yaml',
|
|
26
|
-
'.sh': 'bash'
|
|
26
|
+
'.sh': 'bash'
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
type SourceOutput = { content: string
|
|
30
|
-
type SnippetOutput = { file: string
|
|
29
|
+
type SourceOutput = { content: string; language: string; file: string };
|
|
30
|
+
type SnippetOutput = { file: string; startIdx: number; lines: string[]; language: string };
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Standard file utilities
|
|
34
34
|
*/
|
|
35
35
|
export class DocFileUtil {
|
|
36
|
-
|
|
37
36
|
static #decCache: Record<string, boolean> = {};
|
|
38
37
|
|
|
39
38
|
static isFile(file: string): boolean {
|
|
40
|
-
return /^[@:A-Za-z0-9
|
|
39
|
+
return /^[@:A-Za-z0-9/\\_.-]+[.]([a-z]{2,10})$/.test(file);
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
static readSource(input: Exclude<CodeSourceInput, Promise<string>>): SourceOutput {
|
|
@@ -66,16 +65,14 @@ export class DocFileUtil {
|
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
if (content) {
|
|
69
|
-
content = content
|
|
70
|
-
.
|
|
71
|
-
|
|
72
|
-
.replace(ENV_KEY, (_, key) => `'${key}'`)
|
|
73
|
-
)
|
|
68
|
+
content = content
|
|
69
|
+
.split(/\n/)
|
|
70
|
+
.map(line => line.replace(ESLINT_PATTERN, '').replace(ENV_KEY, (_, key) => `'${key}'`))
|
|
74
71
|
.join('\n')
|
|
75
|
-
.replace(/^\/\/# sourceMap.*$/
|
|
76
|
-
.replace(/[ ]*[/][/][ ]*@ts-expect-error[^\n]*\n/
|
|
77
|
-
.replace(/^[ ]*[/][/][ ]*[{][{][^\n]*\n/
|
|
78
|
-
.replace(/[ ]*[/][/][ ]*[{][{][^\n]*/
|
|
72
|
+
.replace(/^\/\/# sourceMap.*$/gms, '')
|
|
73
|
+
.replace(/[ ]*[/][/][ ]*@ts-expect-error[^\n]*\n/gms, '') // Excluding errors
|
|
74
|
+
.replace(/^[ ]*[/][/][ ]*[{][{][^\n]*\n/gms, '') // Excluding conditional comments, full-line
|
|
75
|
+
.replace(/[ ]*[/][/][ ]*[{][{][^\n]*/gms, ''); // Excluding conditional comments
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
if (file !== undefined) {
|
|
@@ -102,7 +99,6 @@ export class DocFileUtil {
|
|
|
102
99
|
* Determine if a file is a decorator
|
|
103
100
|
*/
|
|
104
101
|
static isDecorator(name: string, file: string): boolean {
|
|
105
|
-
|
|
106
102
|
const key = `${name}:${file}`;
|
|
107
103
|
if (key in this.#decCache) {
|
|
108
104
|
return this.#decCache[key];
|
|
@@ -131,32 +127,36 @@ export class DocFileUtil {
|
|
|
131
127
|
*/
|
|
132
128
|
static buildOutline(code: string): string {
|
|
133
129
|
let methodPrefix = '';
|
|
134
|
-
code = code
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
130
|
+
code = code
|
|
131
|
+
.split(/\n/)
|
|
132
|
+
.map(line => {
|
|
133
|
+
if (!methodPrefix) {
|
|
134
|
+
const info = line.match(
|
|
135
|
+
/^(\s{0,50})(?:(private|public)\s{1,10})?(?:static\s{1,10})?(?:async\s{1,10})?(?:[*]\s{0,10})?(?:(?:get|set)\s{1,10})?(\S{1,200})[<(](.{0,500})/
|
|
136
|
+
);
|
|
137
|
+
if (info) {
|
|
138
|
+
const [, space, __name, rest] = info;
|
|
139
|
+
if (!rest.endsWith(';')) {
|
|
140
|
+
if (/\s{0,50}[{]\s{0,50}return.{0,200}$/.test(line)) {
|
|
141
|
+
return line.replace(/\s{0,50}[{]\s{0,50}return.{0,200}$/, ';');
|
|
142
|
+
} else {
|
|
143
|
+
methodPrefix = space;
|
|
144
|
+
return line.replace(/\s{0,50}[{]\s{0,50}$/, ';');
|
|
145
|
+
}
|
|
145
146
|
}
|
|
146
147
|
}
|
|
148
|
+
return line;
|
|
149
|
+
} else {
|
|
150
|
+
if (line.startsWith(`${methodPrefix}}`)) {
|
|
151
|
+
methodPrefix = '';
|
|
152
|
+
}
|
|
153
|
+
return '';
|
|
147
154
|
}
|
|
148
|
-
|
|
149
|
-
} else {
|
|
150
|
-
if (line.startsWith(`${methodPrefix}}`)) {
|
|
151
|
-
methodPrefix = '';
|
|
152
|
-
}
|
|
153
|
-
return '';
|
|
154
|
-
}
|
|
155
|
-
})
|
|
155
|
+
})
|
|
156
156
|
.filter(line => !/#|(\b(private|protected)\b)/.test(line))
|
|
157
157
|
.filter(line => !!line)
|
|
158
158
|
.join('\n');
|
|
159
159
|
|
|
160
160
|
return code;
|
|
161
161
|
}
|
|
162
|
-
}
|
|
162
|
+
}
|
package/src/util/package.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type NodePackageManager, PACKAGE_MANAGERS } from '@travetto/manifest';
|
|
2
2
|
import { Runtime } from '@travetto/runtime';
|
|
3
3
|
|
|
4
4
|
export class PackageDocUtil {
|
|
@@ -8,8 +8,10 @@ export class PackageDocUtil {
|
|
|
8
8
|
static getPackageCommand(pkg: string, args: string[] = [], manager?: NodePackageManager): string {
|
|
9
9
|
switch (manager ?? Runtime.workspace.manager) {
|
|
10
10
|
case 'npm':
|
|
11
|
-
case 'yarn':
|
|
12
|
-
|
|
11
|
+
case 'yarn':
|
|
12
|
+
return `npx ${pkg} ${args.join(' ')}`.trim();
|
|
13
|
+
case 'pnpm':
|
|
14
|
+
return `pnpm ${pkg} ${args.join(' ')}`.trim();
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -18,9 +20,12 @@ export class PackageDocUtil {
|
|
|
18
20
|
*/
|
|
19
21
|
static getWorkspaceInitCommand(manager?: NodePackageManager): string {
|
|
20
22
|
switch (manager ?? Runtime.workspace.manager) {
|
|
21
|
-
case 'npm':
|
|
22
|
-
|
|
23
|
-
case '
|
|
23
|
+
case 'npm':
|
|
24
|
+
return 'npm init -f';
|
|
25
|
+
case 'yarn':
|
|
26
|
+
return 'yarn init -y';
|
|
27
|
+
case 'pnpm':
|
|
28
|
+
return 'pnpm init -y';
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -29,9 +34,12 @@ export class PackageDocUtil {
|
|
|
29
34
|
*/
|
|
30
35
|
static getInstallCommand(pkg: string, production = false, manager?: NodePackageManager): string {
|
|
31
36
|
switch (manager ?? Runtime.workspace.manager) {
|
|
32
|
-
case 'npm':
|
|
33
|
-
|
|
34
|
-
case '
|
|
37
|
+
case 'npm':
|
|
38
|
+
return `npm install ${production ? '' : '--save-dev '}${pkg}`;
|
|
39
|
+
case 'yarn':
|
|
40
|
+
return `yarn add ${production ? '' : '--dev '}${pkg}`;
|
|
41
|
+
case 'pnpm':
|
|
42
|
+
return `pnpm add ${production ? '' : '--dev '}${pkg}`;
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
45
|
|
|
@@ -39,8 +47,6 @@ export class PackageDocUtil {
|
|
|
39
47
|
* Get install example for a given package
|
|
40
48
|
*/
|
|
41
49
|
static getInstallInstructions(pkg: string, production = false): string {
|
|
42
|
-
return PACKAGE_MANAGERS
|
|
43
|
-
.map(manager => this.getInstallCommand(pkg, production, manager.type))
|
|
44
|
-
.join('\n\n# or\n\n');
|
|
50
|
+
return PACKAGE_MANAGERS.map(manager => this.getInstallCommand(pkg, production, manager.type)).join('\n\n# or\n\n');
|
|
45
51
|
}
|
|
46
|
-
}
|
|
52
|
+
}
|
package/src/util/resolve.ts
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { DocFileUtil } from './file.ts';
|
|
2
2
|
import type { CodeProps, CodeSourceInput } from './types.ts';
|
|
3
3
|
|
|
4
|
-
export type ResolvedRef = { title: string
|
|
5
|
-
export type ResolvedCode = { text: string
|
|
6
|
-
export type ResolvedSnippet = { text: string
|
|
7
|
-
export type ResolvedSnippetLink = { file: string
|
|
4
|
+
export type ResolvedRef = { title: string; file: string; line: number };
|
|
5
|
+
export type ResolvedCode = { text: string; language: string; file?: string };
|
|
6
|
+
export type ResolvedSnippet = { text: string; language: string; file: string; line: number };
|
|
7
|
+
export type ResolvedSnippetLink = { file: string; line: number };
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Resolve utilities
|
|
11
11
|
*/
|
|
12
12
|
export class DocResolveUtil {
|
|
13
|
-
|
|
14
13
|
static async resolveRef(title: string, file: string): Promise<ResolvedRef> {
|
|
15
|
-
|
|
16
14
|
let line = 0;
|
|
17
15
|
const result = DocFileUtil.readSource(file);
|
|
18
16
|
file = result.file;
|
|
19
17
|
|
|
20
18
|
if (result.content) {
|
|
21
|
-
line = result.content
|
|
19
|
+
line = result.content
|
|
20
|
+
.split(/\n/g)
|
|
22
21
|
.findIndex(lineText => new RegExp(`(class|interface|function)[ ]+${RegExp.escape(title)}`).test(lineText));
|
|
23
22
|
if (line < 0) {
|
|
24
23
|
line = 0;
|
|
@@ -67,9 +66,9 @@ export class DocResolveUtil {
|
|
|
67
66
|
|
|
68
67
|
static applyCodePropDefaults(props: CodeProps): void {
|
|
69
68
|
const type = typeof props.src === 'function' ? props.src : undefined;
|
|
70
|
-
props.startRe ??=
|
|
71
|
-
props.language ??=
|
|
72
|
-
props.endRe ??=
|
|
73
|
-
props.title ??= typeof props.src
|
|
69
|
+
props.startRe ??= type ? new RegExp(`^(export)?\\s*(interface|class)\\s+${RegExp.escape(type.name)}\\b`) : undefined;
|
|
70
|
+
props.language ??= type ? 'typescript' : undefined;
|
|
71
|
+
props.endRe ??= type ? /^[}]/ : undefined;
|
|
72
|
+
props.title ??= typeof props.src === 'function' ? props.src.name.replace(/^[$]/, '') : undefined;
|
|
74
73
|
}
|
|
75
|
-
}
|
|
74
|
+
}
|
package/src/util/run.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
|
-
import util from 'node:util';
|
|
3
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import os from 'node:os';
|
|
4
3
|
import path from 'node:path';
|
|
4
|
+
import util from 'node:util';
|
|
5
5
|
|
|
6
6
|
import { Env, ExecUtil, Runtime, RuntimeIndex } from '@travetto/runtime';
|
|
7
|
+
|
|
7
8
|
import type { RunConfig } from './types.ts';
|
|
8
9
|
|
|
9
10
|
export const COMMON_DATE = new Date('2029-03-14T00:00:00.000-0400').getTime();
|
|
@@ -25,7 +26,8 @@ class DocState {
|
|
|
25
26
|
|
|
26
27
|
getId(id: string): string {
|
|
27
28
|
if (!this.ids[id]) {
|
|
28
|
-
this.ids[id] = ' '
|
|
29
|
+
this.ids[id] = ' '
|
|
30
|
+
.repeat(id.length)
|
|
29
31
|
.split('')
|
|
30
32
|
.map(_ => Math.trunc(this.rng() * 16).toString(16))
|
|
31
33
|
.join('');
|
|
@@ -42,7 +44,7 @@ export class DocRunUtil {
|
|
|
42
44
|
|
|
43
45
|
/** Build working directory from config */
|
|
44
46
|
static workingDirectory(config: RunConfig): string {
|
|
45
|
-
return path.resolve(config.module ? RuntimeIndex.getModule(config.module)?.sourcePath! : Runtime.mainSourcePath);
|
|
47
|
+
return path.resolve(config.module ? (RuntimeIndex.getModule(config.module)?.sourcePath ?? undefined!) : Runtime.mainSourcePath);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
/**
|
|
@@ -50,20 +52,22 @@ export class DocRunUtil {
|
|
|
50
52
|
*/
|
|
51
53
|
static cleanRunOutput(text: string, config: RunConfig): string {
|
|
52
54
|
const rootPath = this.workingDirectory(config);
|
|
53
|
-
text = util
|
|
55
|
+
text = util
|
|
56
|
+
.stripVTControlCharacters(text.trim())
|
|
54
57
|
.replaceAll(rootPath, '.')
|
|
55
58
|
.replaceAll(os.tmpdir(), '/tmp')
|
|
56
59
|
.replaceAll(Runtime.workspace.path, '<workspace-root>')
|
|
57
|
-
.replace(/[/]tmp[/][a-z_A-Z0-9
|
|
60
|
+
.replace(/[/]tmp[/][a-z_A-Z0-9/-]+/g, '/tmp/<temp-folder>')
|
|
58
61
|
.replace(/^(\s*framework:\s*')(\d+[.]\d+)[^']*('[,]?\s*)$/gm, (_, pre, ver, post) => `${pre}${ver}.x${post}`)
|
|
59
62
|
.replace(/^(\s*nodeVersion:\s*'v)(\d+)[^']*('[,]?\s*)$/gm, (_, pre, ver, post) => `${pre}${ver}.x.x${post}`)
|
|
60
63
|
.replace(/^(.{1,4})?Compiling[.]*/, '') // Compiling message, remove
|
|
61
|
-
.replace(/[A-Za-z0-9_
|
|
64
|
+
.replace(/[A-Za-z0-9_./\\-]+\/travetto\/module\//g, '@travetto/')
|
|
62
65
|
.replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}([.]\d{3})?Z?/g, this.#docState.getDate.bind(this.#docState))
|
|
63
|
-
.replace(/\b[0-9a-f]{4}[0-9a-f
|
|
66
|
+
.replace(/\b[0-9a-f]{4}[0-9a-f-]{8,40}\b/gi, this.#docState.getId.bind(this.#docState))
|
|
64
67
|
.replace(/(\d+[.]\d+[.]\d+)-(alpha|rc)[.]\d+/g, (all, value) => value);
|
|
65
68
|
if (config.filter || config.rewrite) {
|
|
66
|
-
text = text
|
|
69
|
+
text = text
|
|
70
|
+
.split(/\n/g)
|
|
67
71
|
.filter(line => config.filter?.(line) ?? true)
|
|
68
72
|
.map(line => config.rewrite?.(line) ?? line)
|
|
69
73
|
.join('\n');
|
|
@@ -108,4 +112,4 @@ export class DocRunUtil {
|
|
|
108
112
|
|
|
109
113
|
return this.cleanRunOutput(final, config);
|
|
110
114
|
}
|
|
111
|
-
}
|
|
115
|
+
}
|
package/src/util/types.ts
CHANGED
|
@@ -11,4 +11,4 @@ export type RunConfig = {
|
|
|
11
11
|
|
|
12
12
|
export type CodeSourceInput = string | Promise<string> | Function;
|
|
13
13
|
|
|
14
|
-
export type CodeProps = { title?: string
|
|
14
|
+
export type CodeProps = { title?: string; src: CodeSourceInput; language?: string; outline?: boolean; startRe?: RegExp; endRe?: RegExp };
|
package/support/cli.doc.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { type CliCommandShape, CliCommand } from '@travetto/cli';
|
|
6
|
-
import { MinLength, Validator } from '@travetto/schema';
|
|
4
|
+
import { CliCommand, type CliCommandShape } from '@travetto/cli';
|
|
7
5
|
import { PackageUtil } from '@travetto/manifest';
|
|
6
|
+
import { Env, ExecUtil, Runtime, WatchUtil } from '@travetto/runtime';
|
|
7
|
+
import { MinLength, Validator } from '@travetto/schema';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Generate documentation outputs from a module `DOC.tsx` entry file.
|
|
@@ -13,14 +13,13 @@ import { PackageUtil } from '@travetto/manifest';
|
|
|
13
13
|
* iterative documentation authoring.
|
|
14
14
|
*/
|
|
15
15
|
@CliCommand()
|
|
16
|
-
@Validator(async
|
|
16
|
+
@Validator(async cmd => {
|
|
17
17
|
const docFile = path.resolve(cmd.input);
|
|
18
18
|
if (!(await fs.stat(docFile, { throwIfNoEntry: false }))) {
|
|
19
19
|
return { message: `input: ${cmd.input} does not exist`, path: 'input', source: 'flag', kind: 'invalid' };
|
|
20
20
|
}
|
|
21
21
|
})
|
|
22
22
|
export class DocCommand implements CliCommandShape {
|
|
23
|
-
|
|
24
23
|
/** Input File */
|
|
25
24
|
input = 'DOC.tsx';
|
|
26
25
|
|
|
@@ -36,7 +35,7 @@ export class DocCommand implements CliCommandShape {
|
|
|
36
35
|
Env.TRV_ROLE.set('doc');
|
|
37
36
|
Env.TRV_CLI_IPC.clear();
|
|
38
37
|
Env.TRV_LOG_PLAIN.set(true);
|
|
39
|
-
Env.FORCE_COLOR.set(false)
|
|
38
|
+
Env.FORCE_COLOR.set(false); // Prevent restarting
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
async runWatch(): Promise<void> {
|
|
@@ -57,8 +56,7 @@ export class DocCommand implements CliCommandShape {
|
|
|
57
56
|
const { DocRenderer } = await import('../src/render/renderer.ts');
|
|
58
57
|
const ctx = await DocRenderer.get(this.input, Runtime);
|
|
59
58
|
const outputs = this.outputs.map(output =>
|
|
60
|
-
output.includes('.') ? [path.extname(output).replace('.', ''), path.resolve(output)] :
|
|
61
|
-
[output, null] as const
|
|
59
|
+
output.includes('.') ? [path.extname(output).replace('.', ''), path.resolve(output)] : ([output, null] as const)
|
|
62
60
|
);
|
|
63
61
|
|
|
64
62
|
for (const [format, out] of outputs) {
|
|
@@ -78,4 +76,4 @@ export class DocCommand implements CliCommandShape {
|
|
|
78
76
|
|
|
79
77
|
return this.watch ? this.runWatch() : this.render();
|
|
80
78
|
}
|
|
81
|
-
}
|
|
79
|
+
}
|
package/support/jsx-runtime.ts
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type Class, castTo } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
type JSXChild = JSXElement | number | bigint | boolean | object | string;
|
|
4
4
|
type JSXProps = { children?: JSXChild | JSXChild[] | null };
|
|
5
5
|
|
|
6
|
-
export type JSXComponentFunction<P extends {} = {}> = (props: P & JSXProps, ...args: unknown[]) =>
|
|
6
|
+
export type JSXComponentFunction<P extends {} = {}> = (props: P & JSXProps, ...args: unknown[]) => JSXElement | null;
|
|
7
7
|
|
|
8
8
|
export const JSXRuntimeTag = Symbol.for('@travetto/doc:jsx-runtime');
|
|
9
|
-
export class JSXFragmentType {
|
|
9
|
+
export class JSXFragmentType {}
|
|
10
10
|
|
|
11
11
|
let id = 0;
|
|
12
12
|
|
|
13
13
|
/** Simple JSX Element */
|
|
14
|
-
export interface JSXElement<
|
|
15
|
-
T extends string | Class | JSXComponentFunction<P> = string | Class | JSXComponentFunction,
|
|
16
|
-
P extends {} = {},
|
|
17
|
-
> {
|
|
14
|
+
export interface JSXElement<T extends string | Class | JSXComponentFunction<P> = string | Class | JSXComponentFunction, P extends {} = {}> {
|
|
18
15
|
[JSXRuntimeTag]?: { id: number };
|
|
19
16
|
type: T;
|
|
20
17
|
key: string;
|
|
21
18
|
props: P & JSXProps;
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
export type ValidHtmlTags =
|
|
25
|
-
|
|
21
|
+
export type ValidHtmlTags =
|
|
22
|
+
| 'strong'
|
|
23
|
+
| 'em'
|
|
24
|
+
| 'br'
|
|
25
|
+
| 'hr'
|
|
26
|
+
| 'li'
|
|
27
|
+
| 'ul'
|
|
28
|
+
| 'ol'
|
|
29
|
+
| 'h2'
|
|
30
|
+
| 'h3'
|
|
31
|
+
| 'h4'
|
|
32
|
+
| 'td'
|
|
33
|
+
| 'tr'
|
|
34
|
+
| 'table'
|
|
35
|
+
| 'thead'
|
|
36
|
+
| 'tbody';
|
|
26
37
|
|
|
27
|
-
let createFrag: Function | undefined
|
|
38
|
+
let createFrag: Function | undefined;
|
|
28
39
|
|
|
29
40
|
export function createElement<T extends string | Class | JSXComponentFunction<P>, P extends {}>(
|
|
30
|
-
type: T,
|
|
41
|
+
type: T,
|
|
42
|
+
props: P & JSXProps
|
|
31
43
|
): JSXElement<T, P> {
|
|
32
44
|
type = castTo(type === createFrag ? JSXFragmentType : type);
|
|
33
45
|
return { [JSXRuntimeTag]: { id: (id += 1) }, type, key: '', props };
|
|
@@ -46,10 +58,9 @@ export function isJSXElement(value: unknown): value is JSXElement {
|
|
|
46
58
|
return value !== undefined && value !== null && typeof value === 'object' && JSXRuntimeTag in value;
|
|
47
59
|
}
|
|
48
60
|
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
50
61
|
export namespace JSX {
|
|
51
|
-
export interface Element extends JSXElement {
|
|
52
|
-
export interface IntrinsicAttributes extends JSXProps {
|
|
62
|
+
export interface Element extends JSXElement {}
|
|
63
|
+
export interface IntrinsicAttributes extends JSXProps {}
|
|
53
64
|
type BasicElements = { [K in ValidHtmlTags]: IntrinsicAttributes };
|
|
54
|
-
export interface IntrinsicElements extends BasicElements {
|
|
65
|
+
export interface IntrinsicElements extends BasicElements {}
|
|
55
66
|
}
|