@travetto/doc 6.0.0-rc.2 → 6.0.0-rc.3

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/__index__.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { JSXElement as DocJSXElement, isJSXElement as isDocJSXElement } from './jsx-runtime';
2
- export { c, d, JSXElementByFn as DocJSXElementByFn } from './src/jsx';
3
- export { MOD_MAPPING as mod } from './src/mapping/mod-mapping';
4
- export { DocFileUtil } from './src/util/file';
1
+ export { JSXElement as DocJSXElement, isJSXElement as isDocJSXElement } from './jsx-runtime.ts';
2
+ export { c, d, JSXElementByFn as DocJSXElementByFn } from './src/jsx.ts';
3
+ export { MOD_MAPPING as mod } from './src/mapping/mod-mapping.ts';
4
+ export { DocFileUtil } from './src/util/file.ts';
5
+ export { DocRunUtil, COMMON_DATE } from './src/util/run.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/doc",
3
- "version": "6.0.0-rc.2",
3
+ "version": "6.0.0-rc.3",
4
4
  "description": "Documentation support for the Travetto framework",
5
5
  "keywords": [
6
6
  "docs",
@@ -24,12 +24,12 @@
24
24
  "directory": "module/doc"
25
25
  },
26
26
  "dependencies": {
27
- "@travetto/runtime": "^6.0.0-rc.1",
27
+ "@travetto/runtime": "^6.0.0-rc.2",
28
28
  "@types/prismjs": "^1.26.5",
29
- "prismjs": "^1.29.0"
29
+ "prismjs": "^1.30.0"
30
30
  },
31
31
  "peerDependencies": {
32
- "@travetto/cli": "^6.0.0-rc.1"
32
+ "@travetto/cli": "^6.0.0-rc.2"
33
33
  },
34
34
  "peerDependenciesMeta": {
35
35
  "@travetto/cli": {
package/src/jsx.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import { createElement, JSXElement, JSXComponentFunction as CompFn } from '@travetto/doc/jsx-runtime';
2
2
  import { castTo, TypedObject } from '@travetto/runtime';
3
3
 
4
- import { LIB_MAPPING } from './mapping/lib-mapping';
5
- import { MOD_MAPPING } from './mapping/mod-mapping';
6
- import { RunConfig } from './util/run';
4
+ import { LIB_MAPPING } from './mapping/lib-mapping.ts';
5
+ import { MOD_MAPPING } from './mapping/mod-mapping.ts';
6
+ import { CodeProps, RunConfig } from './util/types.ts';
7
7
 
8
- type CodeProps = { title: string, src: string | Function, language?: string, outline?: boolean, startRe?: RegExp, endRe?: RegExp };
9
8
  type InstallProps = { title: string, pkg: string };
10
9
  type ExecProps = { title: string, cmd: string, args?: string[], config?: RunConfig & { formatCommand?(cmd: string, args: string[]): string } };
11
10
  type StdHeaderProps = { mod?: string, install?: boolean };
@@ -82,8 +81,9 @@ function CodeLinker(titleOrNode: string | JSXElement, src?: string, startRe?: Re
82
81
  props = { title: titleOrNode, src: src!, startRe: startRe! };
83
82
  } else if (titleOrNode.type === Code) {
84
83
  const node: JSXElementByFn<'Code'> = castTo(titleOrNode);
84
+ const srcName = typeof node.props.src === 'string' ? node.props.src : node.props.src.name;
85
85
  props = {
86
- title: node.props.title,
86
+ title: node.props.title ?? srcName,
87
87
  src: node.props.src,
88
88
  startRe: node.props.startRe!
89
89
  };
@@ -39,17 +39,22 @@ export const LIB_MAPPING = {
39
39
  UUID: { title: 'UUID', href: 'https://en.wikipedia.org/wiki/Universally_unique_identifier' },
40
40
 
41
41
  // Node
42
- Process: { title: 'process', href: 'https://nodejs.org/api/process.html' },
43
- ChildProcess: { title: 'child_process', href: 'https://nodejs.org/api/child_process.html' },
44
- AsyncHooks: { title: 'async_hooks', href: 'https://nodejs.org/api/async_hooks.html' },
45
- Http: { title: 'http', href: 'https://nodejs.org/api/http.html' },
46
- Path: { title: 'http', href: 'https://nodejs.org/api/path.html' },
47
- Https: { title: 'https', href: 'https://nodejs.org/api/https.html' },
48
- Console: { title: 'console', href: 'https://nodejs.org/api/console.html' },
49
- Assert: { title: 'assert', href: 'https://nodejs.org/api/assert.html' },
42
+ NodeProcess: { title: 'process', href: 'https://nodejs.org/api/process.html' },
43
+ NodeChildProcess: { title: 'child_process', href: 'https://nodejs.org/api/child_process.html' },
44
+ NodeAsyncHooks: { title: 'async_hooks', href: 'https://nodejs.org/api/async_hooks.html' },
45
+ NodeHttp: { title: 'http', href: 'https://nodejs.org/api/http.html' },
46
+ NodePath: { title: 'path', href: 'https://nodejs.org/api/path.html' },
47
+ NodeHttps: { title: 'https', href: 'https://nodejs.org/api/https.html' },
48
+ NodeConsole: { title: 'console', href: 'https://nodejs.org/api/console.html' },
49
+ NodeAssert: { title: 'assert', href: 'https://nodejs.org/api/assert.html' },
50
+ NodeEventEmitter: { title: 'EventEmitter', href: 'https://nodejs.org/api/events.html#class-eventemitter' },
51
+ NodeBuffer: { title: 'Buffer', href: 'https://nodejs.org/api/buffer.html' },
52
+ NodeZlib: { title: 'Buffer', href: 'https://nodejs.org/api/zlib.html' },
53
+ NodeFile: { title: 'Buffer', href: 'https://nodejs.org/api/buffer.html#class-file' },
50
54
 
51
55
  // Cloud
52
56
  AwsCloudwatch: { title: 'AWS Cloudwatch', href: 'https://aws.amazon.com/cloudwatch/' },
57
+ AwsLambda: { title: 'AWS Lambda', href: 'https://aws.amazon.com/lambda/' },
53
58
 
54
59
  // Utils
55
60
  Lodash: { title: 'lodash', href: 'https://lodash.com' },
@@ -97,7 +102,8 @@ export const LIB_MAPPING = {
97
102
  Firestore: { title: 'Firestore', href: 'https://firebase.google.com/docs/firestore' },
98
103
  SQLite: { title: 'SQLite', href: 'https://www.sqlite.org/' },
99
104
 
100
- // Rest
105
+ // Web
106
+ Connect: { title: 'connect', href: 'https://github.com/senchalabs/connect' },
101
107
  Express: { title: 'express', href: 'https://expressjs.com' },
102
108
  Passport: { title: 'passport', href: 'http://passportjs.org' },
103
109
  Busboy: { title: '@fastify/busboy', href: 'https://github.com/fastify/busboy' },
@@ -7,22 +7,22 @@ export const MOD_MAPPING = {
7
7
  name: '@travetto/auth-model', folder: '@travetto/auth-model', displayName: 'Authentication Model',
8
8
  description: 'Authentication model support for the Travetto framework'
9
9
  },
10
- AuthRest: {
11
- name: '@travetto/auth-rest', folder: '@travetto/auth-rest', displayName: 'Rest Auth',
12
- description: 'Rest authentication integration support for the Travetto framework'
13
- },
14
- AuthRestPassport: {
15
- name: '@travetto/auth-rest-passport', folder: '@travetto/auth-rest-passport', displayName: 'Rest Auth Passport',
16
- description: 'Rest authentication integration support for the Travetto framework'
17
- },
18
- AuthRestSession: {
19
- name: '@travetto/auth-rest-session', folder: '@travetto/auth-rest-session', displayName: 'Rest Auth Session',
20
- description: 'Rest authentication session integration support for the Travetto framework'
21
- },
22
10
  AuthSession: {
23
11
  name: '@travetto/auth-session', folder: '@travetto/auth-session', displayName: 'Auth Session',
24
12
  description: 'Session provider for the travetto auth module.'
25
13
  },
14
+ AuthWeb: {
15
+ name: '@travetto/auth-web', folder: '@travetto/auth-web', displayName: 'Web Auth',
16
+ description: 'Web authentication integration support for the Travetto framework'
17
+ },
18
+ AuthWebPassport: {
19
+ name: '@travetto/auth-web-passport', folder: '@travetto/auth-web-passport', displayName: 'Web Auth Passport',
20
+ description: 'Web authentication integration support for the Travetto framework'
21
+ },
22
+ AuthWebSession: {
23
+ name: '@travetto/auth-web-session', folder: '@travetto/auth-web-session', displayName: 'Web Auth Session',
24
+ description: 'Web authentication session integration support for the Travetto framework'
25
+ },
26
26
  Cache: {
27
27
  name: '@travetto/cache', folder: '@travetto/cache', displayName: 'Caching',
28
28
  description: 'Caching functionality with decorators for declarative use.'
@@ -159,50 +159,6 @@ export const MOD_MAPPING = {
159
159
  name: '@travetto/repo', folder: '@travetto/repo', displayName: 'Repo',
160
160
  description: 'Monorepo utilities'
161
161
  },
162
- Rest: {
163
- name: '@travetto/rest', folder: '@travetto/rest', displayName: 'RESTful API',
164
- description: 'Declarative api for RESTful APIs with support for the dependency injection module.'
165
- },
166
- RestAwsLambda: {
167
- name: '@travetto/rest-aws-lambda', folder: '@travetto/rest-aws-lambda', displayName: 'RESTful AWS Lambda',
168
- description: 'RESTful APIs entry point support for AWS Lambdas.'
169
- },
170
- RestClient: {
171
- name: '@travetto/rest-client', folder: '@travetto/rest-client', displayName: 'RESTful Client Support',
172
- description: 'RESTful support for generating clients for controller endpoints'
173
- },
174
- RestExpress: {
175
- name: '@travetto/rest-express', folder: '@travetto/rest-express', displayName: 'Express REST Source',
176
- description: 'Express provider for the travetto rest module.'
177
- },
178
- RestExpressLambda: {
179
- name: '@travetto/rest-express-lambda', folder: '@travetto/rest-express-lambda', displayName: 'Express REST AWS Lambda Source',
180
- description: 'Express AWS Lambda provider for the travetto rest module.'
181
- },
182
- RestFastify: {
183
- name: '@travetto/rest-fastify', folder: '@travetto/rest-fastify', displayName: 'Fastify REST Source',
184
- description: 'Fastify provider for the travetto rest module.'
185
- },
186
- RestFastifyLambda: {
187
- name: '@travetto/rest-fastify-lambda', folder: '@travetto/rest-fastify-lambda', displayName: 'Fastify REST AWS Lambda Source',
188
- description: 'Fastify AWS Lambda provider for the travetto rest module.'
189
- },
190
- RestKoa: {
191
- name: '@travetto/rest-koa', folder: '@travetto/rest-koa', displayName: 'Koa REST Source',
192
- description: 'Koa provider for the travetto rest module.'
193
- },
194
- RestKoaLambda: {
195
- name: '@travetto/rest-koa-lambda', folder: '@travetto/rest-koa-lambda', displayName: 'Koa REST AWS Lambda Source',
196
- description: 'Koa provider for the travetto rest module.'
197
- },
198
- RestRpc: {
199
- name: '@travetto/rest-rpc', folder: '@travetto/rest-rpc', displayName: 'RESTful RPC Support',
200
- description: 'RESTful RPC support for a module'
201
- },
202
- RestUpload: {
203
- name: '@travetto/rest-upload', folder: '@travetto/rest-upload', displayName: 'Rest Upload Support',
204
- description: 'Provides integration between the travetto asset and rest module.'
205
- },
206
162
  Runtime: {
207
163
  name: '@travetto/runtime', folder: '@travetto/runtime', displayName: 'Runtime',
208
164
  description: 'Runtime for travetto applications.'
@@ -235,6 +191,34 @@ export const MOD_MAPPING = {
235
191
  name: '@travetto/transformer', folder: '@travetto/transformer', displayName: 'Transformation',
236
192
  description: 'Functionality for AST transformations, with transformer registration, and general utils'
237
193
  },
194
+ Web: {
195
+ name: '@travetto/web', folder: '@travetto/web', displayName: 'Web API',
196
+ description: 'Declarative api for Web Applications with support for the dependency injection.'
197
+ },
198
+ WebAwsLambda: {
199
+ name: '@travetto/web-aws-lambda', folder: '@travetto/web-aws-lambda', displayName: 'Web AWS Lambda',
200
+ description: 'Web APIs entry point support for AWS Lambdas.'
201
+ },
202
+ WebConnect: {
203
+ name: '@travetto/web-connect', folder: '@travetto/web-connect', displayName: 'Web Connect Support',
204
+ description: 'Web integration for Connect-Like Resources'
205
+ },
206
+ WebHttp: {
207
+ name: '@travetto/web-http', folder: '@travetto/web-http', displayName: 'Web HTTP Server Support',
208
+ description: 'Web HTTP Server Support'
209
+ },
210
+ WebNode: {
211
+ name: '@travetto/web-node', folder: '@travetto/web-node', displayName: 'Node Web Server',
212
+ description: 'Node provider for the travetto web module.'
213
+ },
214
+ WebRpc: {
215
+ name: '@travetto/web-rpc', folder: '@travetto/web-rpc', displayName: 'Web RPC Support',
216
+ description: 'RPC support for a Web Application'
217
+ },
218
+ WebUpload: {
219
+ name: '@travetto/web-upload', folder: '@travetto/web-upload', displayName: 'Web Upload Support',
220
+ description: 'Provides integration between the travetto asset and web module.'
221
+ },
238
222
  Worker: {
239
223
  name: '@travetto/worker', folder: '@travetto/worker', displayName: 'Worker',
240
224
  description: 'Process management utilities, with a focus on inter-process communication'
@@ -5,9 +5,9 @@ import { createElement, JSXRuntimeTag } from '@travetto/doc/jsx-runtime';
5
5
  import { PackageUtil } from '@travetto/manifest';
6
6
  import { castTo, RuntimeIndex } from '@travetto/runtime';
7
7
 
8
- import { JSXElementByFn, c } from '../jsx';
9
- import { DocResolveUtil, ResolvedCode, ResolvedRef, ResolvedSnippetLink } from '../util/resolve';
10
- import { DocRunUtil } from '../util/run';
8
+ import { JSXElementByFn, c } from '../jsx.ts';
9
+ import { DocResolveUtil, ResolvedCode, ResolvedRef, ResolvedSnippetLink } from '../util/resolve.ts';
10
+ import { DocRunUtil } from '../util/run.ts';
11
11
 
12
12
  /**
13
13
  * Render Context
@@ -66,7 +66,7 @@ export class RenderContext {
66
66
  link(text: string, line?: number | { [key: string]: unknown, line?: number }): string {
67
67
  const num = typeof line === 'number' ? line : line?.line;
68
68
  return `${text.replace(this.repoRoot, this.baseUrl)
69
- .replace(/.*@travetto\//, `${this.travettoBaseUrl}/module/`)}${num ? `#L${num}` : ''}`;
69
+ .replace(/.*@travetto\//, `${this.travettoBaseUrl}/module/`)}${num && num > 1 ? `#L${num}` : ''}`;
70
70
  }
71
71
 
72
72
  /**
@@ -4,13 +4,13 @@ import { JSXElement } from '@travetto/doc/jsx-runtime';
4
4
  import { Runtime, RuntimeIndex } from '@travetto/runtime';
5
5
  import { PackageUtil } from '@travetto/manifest';
6
6
 
7
- import { highlight } from './code-highlight';
8
- import { RenderProvider, RenderState } from '../types';
9
- import { c, getComponentName } from '../jsx';
10
- import { MOD_MAPPING } from '../mapping/mod-mapping';
11
- import { LIB_MAPPING } from '../mapping/lib-mapping';
12
- import { RenderContext } from './context';
13
- import { DocResolveUtil } from '../util/resolve';
7
+ import { highlight } from './code-highlight.ts';
8
+ import { RenderProvider, RenderState } from '../types.ts';
9
+ import { c, getComponentName } from '../jsx.ts';
10
+ import { MOD_MAPPING } from '../mapping/mod-mapping.ts';
11
+ import { LIB_MAPPING } from '../mapping/lib-mapping.ts';
12
+ import { RenderContext } from './context.ts';
13
+ import { DocResolveUtil } from '../util/resolve.ts';
14
14
 
15
15
  const ESCAPE_ENTITIES: Record<string, string> = { '<': '&lt;', '>': '&gt;', '&': '&amp;', '{': "{{'{'}}", '}': "{{'}'}}" };
16
16
  const ENTITY_RE = new RegExp(`[${Object.keys(ESCAPE_ENTITIES).join('')}]`, 'gm');
@@ -71,6 +71,8 @@ yarn add ${el.props.pkg}
71
71
  Terminal: state => Html.Code(state),
72
72
  Config: state => Html.Code(state),
73
73
  Code: async ({ context, el, props }) => {
74
+ DocResolveUtil.applyCodePropDefaults(el.props);
75
+
74
76
  const cls = getComponentName(el.type).replace(/^[A-Z]/g, v => v.toLowerCase());
75
77
  const content = await context.resolveCode(el);
76
78
  let link: string = '';
@@ -3,11 +3,12 @@ import fs from 'node:fs/promises';
3
3
  import { Runtime, RuntimeIndex } from '@travetto/runtime';
4
4
  import { PackageUtil } from '@travetto/manifest';
5
5
 
6
- import { RenderProvider } from '../types';
7
- import { c, getComponentName } from '../jsx';
8
- import { MOD_MAPPING } from '../mapping/mod-mapping';
9
- import { LIB_MAPPING } from '../mapping/lib-mapping';
10
- import { RenderContext } from './context';
6
+ import { RenderProvider } from '../types.ts';
7
+ import { c, getComponentName } from '../jsx.ts';
8
+ import { MOD_MAPPING } from '../mapping/mod-mapping.ts';
9
+ import { LIB_MAPPING } from '../mapping/lib-mapping.ts';
10
+ import { RenderContext } from './context.ts';
11
+ import { DocResolveUtil } from '../util/resolve.ts';
11
12
 
12
13
  export const Markdown: RenderProvider<RenderContext> = {
13
14
  ext: 'md',
@@ -25,17 +26,17 @@ export const Markdown: RenderProvider<RenderContext> = {
25
26
  ul: async ({ recurse }) => `\n${await recurse()}`,
26
27
  ol: async ({ recurse }) => `\n${await recurse()}`,
27
28
  li: async ({ recurse, stack }) => {
28
- const parent = stack.reverse().find(x => x.type === 'ol' || x.type === 'ul');
29
+ const parent = stack.toReversed().find(x => x.type === 'ol' || x.type === 'ul');
29
30
  const depth = stack.filter(x => x.type === 'ol' || x.type === 'ul').length;
30
31
  return `${' '.repeat(depth)}${(parent && parent.type === 'ol') ? '1.' : '* '} ${await recurse()}\n`;
31
32
  },
32
- table: async ({ recurse }) => recurse(),
33
- tbody: async ({ recurse }) => recurse(),
33
+ table: async ({ recurse }) => `${await recurse()}`,
34
+ tbody: async ({ recurse }) => `${await recurse()}`,
34
35
  td: async ({ recurse }) => `|${await recurse()}`,
35
36
  tr: async ({ recurse }) => `${await recurse()}|\n`,
36
37
  thead: async ({ recurse }) => {
37
38
  const row = await recurse();
38
- return `${row}${row.replace(/[^|\n]/g, '-')}`;
39
+ return `${row}${row?.replace(/[^|\n]/g, '-')}`;
39
40
  },
40
41
  h2: async ({ recurse }) => `\n## ${await recurse()}\n\n`,
41
42
  h3: async ({ recurse }) => `\n### ${await recurse()}\n\n`,
@@ -61,10 +62,12 @@ npm install ${el.props.pkg}
61
62
  yarn add ${el.props.pkg}
62
63
  \`\`\`
63
64
  `,
64
- Code: async ({ context, el }) => {
65
+ Code: async ({ context, el, props }) => {
66
+ DocResolveUtil.applyCodePropDefaults(el.props);
67
+
65
68
  const name = getComponentName(el.type);
66
69
  const content = await context.resolveCode(el);
67
- let lang = el.props.language ?? content.language;
70
+ let lang = props.language ?? content.language;
68
71
  if (!lang) {
69
72
  if (el.type === c.Terminal) {
70
73
  lang = 'bash';
@@ -72,7 +75,7 @@ yarn add ${el.props.pkg}
72
75
  lang = 'typescript';
73
76
  }
74
77
  }
75
- return `\n\n**${name}: ${el.props.title}**
78
+ return `\n\n**${name}: ${props.title}**
76
79
  \`\`\`${lang}
77
80
  ${context.cleanText(content.text)}
78
81
  \`\`\`\n\n`;
@@ -2,15 +2,15 @@ import path from 'node:path';
2
2
 
3
3
  import { type ManifestContext, PackageUtil } from '@travetto/manifest';
4
4
  import { isJSXElement, JSXElement, JSXFragmentType } from '@travetto/doc/jsx-runtime';
5
- import { castTo, Runtime } from '@travetto/runtime';
5
+ import { castTo, Class, Runtime } from '@travetto/runtime';
6
6
 
7
- import { EMPTY_ELEMENT, getComponentName, JSXElementByFn, c } from '../jsx';
8
- import { DocumentShape, RenderProvider, RenderState } from '../types';
9
- import { DocFileUtil } from '../util/file';
7
+ import { EMPTY_ELEMENT, getComponentName, JSXElementByFn, c } from '../jsx.ts';
8
+ import { DocumentShape, RenderProvider, RenderState } from '../types.ts';
9
+ import { DocFileUtil } from '../util/file.ts';
10
10
 
11
- import { RenderContext } from './context';
12
- import { Html } from './html';
13
- import { Markdown } from './markdown';
11
+ import { RenderContext } from './context.ts';
12
+ import { Html } from './html.ts';
13
+ import { Markdown } from './markdown.ts';
14
14
 
15
15
  const providers = { [Html.ext]: Html, [Markdown.ext]: Markdown };
16
16
 
@@ -37,18 +37,44 @@ export class DocRenderer {
37
37
  this.#support = support;
38
38
  }
39
39
 
40
+ async #buildLink(
41
+ renderer: RenderProvider<RenderContext>,
42
+ cls: Class,
43
+ title?: string
44
+ ) {
45
+ const source = DocFileUtil.readSource(cls);
46
+ if (source) {
47
+ title = (await DocFileUtil.isDecorator(cls.name, source.file)) ? `@${title ?? cls.name}` : (title ?? cls.name);
48
+ const el = this.#support.createElement('CodeLink', {
49
+ src: source.file,
50
+ startRe: new RegExp(`(class|function|interface)\\s+(${cls.name.replaceAll('$', '\\$')})`),
51
+ title
52
+ });
53
+ // @ts-expect-error
54
+ const state: RenderState<JSXElementByFn<'CodeLink'>, RenderContext> = {
55
+ el, props: el.props, recurse: async () => '', context: this.#support, stack: []
56
+ };
57
+ // @ts-expect-error
58
+ state.createState = (key, props) => this.createState(state, key, props);
59
+ return renderer.CodeLink(state);
60
+ }
61
+ }
62
+
40
63
  async #render(
41
64
  renderer: RenderProvider<RenderContext>,
42
65
  node: JSXElement[] | JSXElement | string | bigint | object | number | boolean | null | undefined,
43
66
  stack: JSXElement[] = []
44
- ): Promise<string> {
67
+ ): Promise<string | undefined> {
45
68
 
46
69
  if (node === null || node === undefined) {
47
70
  return '';
48
71
  } else if (Array.isArray(node)) {
49
72
  const out: string[] = [];
50
73
  for (const el of node) {
51
- out.push(await this.#render(renderer, el, stack));
74
+ const sub = await this.#render(renderer, el, stack);
75
+ if (sub) {
76
+ out.push(sub);
77
+ }
52
78
  }
53
79
  return out.join('');
54
80
  } else if (isJSXElement(node)) {
@@ -87,25 +113,15 @@ export class DocRenderer {
87
113
  case 'number':
88
114
  case 'bigint':
89
115
  case 'boolean': return `${node}`;
90
- case 'function': {
91
- const source = DocFileUtil.readSource(node);
92
- if (source.file) {
93
- const title = (await DocFileUtil.isDecorator(node.name, source.file)) ? `@${node.name}` : node.name;
94
- const el = this.#support.createElement('CodeLink', {
95
- src: source.file,
96
- startRe: new RegExp(`(class|function)\\s+(${node.name})`),
97
- title
98
- });
99
- // @ts-expect-error
100
- const state: RenderState<JSXElementByFn<'CodeLink'>, RenderContext> = {
101
- el, props: el.props, recurse: async () => '', context: this.#support, stack: []
102
- };
103
- // @ts-expect-error
104
- state.createState = (key, props) => this.createState(state, key, props);
105
- return await renderer.CodeLink(state);
116
+ case 'object': {
117
+ if (node) {
118
+ return await this.#buildLink(renderer, castTo(node.constructor), node.constructor.name.replace(/^[$]/, ''));
106
119
  }
107
120
  break;
108
121
  }
122
+ case 'function': {
123
+ return await this.#buildLink(renderer, castTo(node));
124
+ }
109
125
  }
110
126
  throw new Error(`Unknown object type: ${typeof node}`);
111
127
  }
@@ -135,7 +151,7 @@ export class DocRenderer {
135
151
  }
136
152
 
137
153
  const text = await this.#render(providers[fmt], this.#rootNode);
138
- let cleaned = `${text.replace(/\n{3,100}/msg, '\n\n').trim()}\n`;
154
+ let cleaned = `${text?.replace(/\n{3,100}/msg, '\n\n').trim()}\n`;
139
155
  if (this.#root.wrap?.[fmt]) {
140
156
  cleaned = this.#root.wrap[fmt](cleaned);
141
157
  }
package/src/types.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { JSXElement, ValidHtmlTags } from '@travetto/doc/jsx-runtime';
2
- import { JSXElementByFn, c } from './jsx';
2
+ import { JSXElementByFn, c } from './jsx.ts';
3
3
 
4
4
  export type Wrapper = Record<string, (cnt: string) => string>;
5
5
 
6
6
  /**
7
7
  * Document file shape
8
+ * @concrete
8
9
  */
9
10
  export interface DocumentShape {
10
11
  text: JSXElement | JSXElement[] | (() => Promise<JSXElement | JSXElement[]>);
@@ -14,7 +15,7 @@ export interface DocumentShape {
14
15
  export type RenderState<T extends JSXElement, C> = {
15
16
  el: T;
16
17
  props: T['props'];
17
- recurse: () => Promise<string>;
18
+ recurse: () => Promise<string | undefined>;
18
19
  stack: JSXElement[];
19
20
  // @ts-expect-error
20
21
  createState: <K extends keyof typeof c>(key: K, props: JSXElementByFn<K>['props']) => RenderState<JSXElementByFn<K>, C>;
package/src/util/file.ts CHANGED
@@ -2,6 +2,7 @@ import { readFileSync, existsSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
4
  import { AppError, Runtime, RuntimeIndex } from '@travetto/runtime';
5
+ import { ManifestModuleFileType, ManifestModuleUtil } from '@travetto/manifest';
5
6
 
6
7
  const ESLINT_PATTERN = /\s{0,10}\/\/ eslint.{0,300}$/g;
7
8
  const ENV_KEY = /Env.([^.]{1,100})[.]key/g;
@@ -12,10 +13,18 @@ const ENV_KEY = /Env.([^.]{1,100})[.]key/g;
12
13
  export class DocFileUtil {
13
14
 
14
15
  static #decCache: Record<string, boolean> = {};
16
+ static #modFileTypeToLang: Record<ManifestModuleFileType, string | undefined> = {
17
+ ts: 'typescript',
18
+ js: 'javascript',
19
+ md: 'markdown',
20
+ json: 'json',
21
+ typings: 'typescript',
22
+ 'package-json': 'json',
23
+ fixture: undefined,
24
+ unknown: undefined
25
+ };
15
26
  static #extToLang: Record<string, string> = {
16
- '.ts': 'typescript',
17
- '.tsx': 'typescript',
18
- '.js': 'javascript',
27
+ '.yaml': 'yaml',
19
28
  '.yml': 'yaml',
20
29
  '.sh': 'bash',
21
30
  };
@@ -64,7 +73,8 @@ export class DocFileUtil {
64
73
 
65
74
  if (file !== undefined) {
66
75
  const ext = path.extname(file);
67
- const language = this.#extToLang[ext] ?? ext.replace('.', '');
76
+ const type = ManifestModuleUtil.getFileType(file);
77
+ const language = this.#modFileTypeToLang[type] ?? this.#extToLang[ext] ?? ext.replace('.', '');
68
78
  return { content, file, language };
69
79
  } else {
70
80
  return { content, file: '', language: '' };
@@ -72,13 +82,13 @@ export class DocFileUtil {
72
82
  }
73
83
 
74
84
  static async readCodeSnippet(src: string | Function, startPattern: RegExp): Promise<{ file: string, startIdx: number, lines: string[], language: string }> {
75
- const res = this.readSource(src);
76
- const lines = res.content.split(/\n/);
85
+ const result = this.readSource(src);
86
+ const lines = result.content.split(/\n/);
77
87
  const startIdx = lines.findIndex(l => startPattern.test(l));
78
88
  if (startIdx < 0) {
79
89
  throw new Error(`Pattern ${startPattern.source} not found in ${src}`);
80
90
  }
81
- return { file: res.file, startIdx, lines, language: res.language };
91
+ return { file: result.file, startIdx, lines, language: result.language };
82
92
  }
83
93
 
84
94
  /**
@@ -91,21 +101,21 @@ export class DocFileUtil {
91
101
  return this.#decCache[key];
92
102
  }
93
103
 
94
- const res = await this.readSource(file);
95
- const text = res.content.split(/\n/g);
104
+ const text = await this.readSource(file);
105
+ const lines = text.content.split(/\n/g);
96
106
 
97
- const start = text.findIndex(x => new RegExp(`function ${name}\\b`).test(x));
98
- let ret = false;
107
+ const start = lines.findIndex(x => new RegExp(`function ${name}\\b`).test(x));
108
+ let found = false;
99
109
  if (start > 0) {
100
110
  for (let i = start - 1; i > start - 3; i--) {
101
- if (text[i].includes('@augments')) {
102
- ret = true;
111
+ if (lines[i].includes('@augments')) {
112
+ found = true;
103
113
  break;
104
114
  }
105
115
  }
106
116
  }
107
- this.#decCache[key] = ret;
108
- return ret;
117
+ this.#decCache[key] = found;
118
+ return found;
109
119
  }
110
120
 
111
121
  /**
@@ -1,4 +1,5 @@
1
- import { DocFileUtil } from './file';
1
+ import { DocFileUtil } from './file.ts';
2
+ import { CodeProps } from './types.ts';
2
3
 
3
4
  export type ResolvedRef = { title: string, file: string, line: number };
4
5
  export type ResolvedCode = { text: string, language: string, file?: string };
@@ -13,12 +14,12 @@ export class DocResolveUtil {
13
14
  static async resolveRef(title: string, file: string): Promise<ResolvedRef> {
14
15
 
15
16
  let line = 0;
16
- const res = await DocFileUtil.readSource(file);
17
- file = res.file;
17
+ const result = await DocFileUtil.readSource(file);
18
+ file = result.file;
18
19
 
19
- if (res.content) {
20
- line = res.content.split(/\n/g)
21
- .findIndex(x => new RegExp(`(class|function)[ ]+${title}`).test(x));
20
+ if (result.content) {
21
+ line = result.content.split(/\n/g)
22
+ .findIndex(x => new RegExp(`(class|interface|function)[ ]+${title.replaceAll('$', '\\$')}`).test(x));
22
23
  if (line < 0) {
23
24
  line = 0;
24
25
  } else {
@@ -32,13 +33,13 @@ export class DocResolveUtil {
32
33
  }
33
34
 
34
35
  static async resolveCode(content: string | Function, language?: string, outline = false): Promise<ResolvedCode> {
35
- const res = DocFileUtil.readSource(content);
36
- let text = res.content;
36
+ const result = DocFileUtil.readSource(content);
37
+ let text = result.content;
37
38
 
38
39
  let file: string | undefined;
39
- if (res.file) {
40
- language = res.language;
41
- file = res.file;
40
+ if (result.file) {
41
+ language = result.language;
42
+ file = result.file;
42
43
  if (outline) {
43
44
  text = DocFileUtil.buildOutline(text);
44
45
  }
@@ -63,4 +64,12 @@ export class DocResolveUtil {
63
64
  const { startIdx, file: resolvedFile } = await DocFileUtil.readCodeSnippet(file, startPattern);
64
65
  return { file: resolvedFile, line: startIdx + 1 };
65
66
  }
67
+
68
+ static applyCodePropDefaults(props: CodeProps) {
69
+ const type = typeof props.src === 'function' ? props.src : undefined;
70
+ props.startRe ??= (type ? new RegExp(`^(export)?\\s*(interface|class)\\s+${type.name.replaceAll('$', '\\$')}\\b`) : undefined);
71
+ props.language ??= (type ? 'typescript' : undefined);
72
+ props.endRe ??= (type ? /^[}]/ : undefined);
73
+ props.title ??= typeof props.src == 'function' ? props.src.name.replace(/^[$]/, '') : undefined;
74
+ }
66
75
  }
package/src/util/run.ts CHANGED
@@ -4,18 +4,10 @@ import { spawn, ChildProcess } from 'node:child_process';
4
4
  import path from 'node:path';
5
5
 
6
6
  import { Env, ExecUtil, Runtime, RuntimeIndex } from '@travetto/runtime';
7
+ import { RunConfig } from './types.ts';
7
8
 
8
9
  export const COMMON_DATE = new Date('2029-03-14T00:00:00.000').getTime();
9
10
 
10
- export type RunConfig = {
11
- filter?: (line: string) => boolean;
12
- rewrite?: (text: string) => string;
13
- module?: string;
14
- env?: Record<string, string>;
15
- envName?: string;
16
- cwd?: string;
17
- };
18
-
19
11
  class DocState {
20
12
  baseline = COMMON_DATE;
21
13
  _s = 37;
@@ -105,11 +97,11 @@ export class DocRunUtil {
105
97
  let final: string;
106
98
  try {
107
99
  const proc = this.spawn(cmd, args, config);
108
- const res = await ExecUtil.getResult(proc, { catch: true });
109
- if (!res.valid) {
110
- throw new Error(res.stderr);
100
+ const result = await ExecUtil.getResult(proc, { catch: true });
101
+ if (!result.valid) {
102
+ throw new Error(result.stderr);
111
103
  }
112
- final = util.stripVTControlCharacters(res.stdout).trim() || util.stripVTControlCharacters(res.stderr).trim();
104
+ final = util.stripVTControlCharacters(result.stdout).trim() || util.stripVTControlCharacters(result.stderr).trim();
113
105
  } catch (err) {
114
106
  if (err instanceof Error) {
115
107
  final = err.message;
@@ -0,0 +1,10 @@
1
+ export type RunConfig = {
2
+ filter?: (line: string) => boolean;
3
+ rewrite?: (text: string) => string;
4
+ module?: string;
5
+ env?: Record<string, string>;
6
+ envName?: string;
7
+ cwd?: string;
8
+ };
9
+
10
+ export type CodeProps = { title?: string, src: string | Function, language?: string, outline?: boolean, startRe?: RegExp, endRe?: RegExp };
@@ -67,7 +67,7 @@ export class DocCommand implements CliCommandShape {
67
67
  }
68
68
 
69
69
  async render(): Promise<void> {
70
- const { DocRenderer } = await import('../src/render/renderer');
70
+ const { DocRenderer } = await import('../src/render/renderer.ts');
71
71
  const ctx = await DocRenderer.get(this.input, Runtime);
72
72
  const outputs = this.outputs.map(output =>
73
73
  output.includes('.') ? [path.extname(output).replace('.', ''), path.resolve(output)] :