@travetto/doc 5.0.0-rc.3 → 5.0.0-rc.4

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,3 +1,4 @@
1
1
  export { JSXElement as DocJSXElement, isJSXElement as isDocJSXElement } from './jsx-runtime';
2
2
  export { c, d, JSXElementByFn as DocJSXElementByFn } from './src/jsx';
3
- export { MOD_MAPPING as mod } from './src/mapping/mod-mapping';
3
+ export { MOD_MAPPING as mod } from './src/mapping/mod-mapping';
4
+ export { DocFileUtil } from './src/util/file';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/doc",
3
- "version": "5.0.0-rc.3",
3
+ "version": "5.0.0-rc.4",
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": "^5.0.0-rc.3",
27
+ "@travetto/runtime": "^5.0.0-rc.4",
28
28
  "@types/prismjs": "^1.26.4",
29
29
  "prismjs": "^1.29.0"
30
30
  },
31
31
  "peerDependencies": {
32
- "@travetto/cli": "^5.0.0-rc.3"
32
+ "@travetto/cli": "^5.0.0-rc.4"
33
33
  },
34
34
  "peerDependenciesMeta": {
35
35
  "@travetto/cli": {
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import { createElement, JSXRuntimeTag } from '@travetto/doc/jsx-runtime';
4
4
 
5
5
  import { PackageUtil } from '@travetto/manifest';
6
- import { Runtime, RuntimeIndex } from '@travetto/runtime';
6
+ import { RuntimeIndex } from '@travetto/runtime';
7
7
 
8
8
  import { JSXElementByFn, c } from '../jsx';
9
9
  import { DocResolveUtil, ResolvedCode, ResolvedRef, ResolvedSnippetLink } from '../util/resolve';
@@ -108,18 +108,16 @@ export class RenderContext {
108
108
  * Resolve code link
109
109
  */
110
110
  async resolveCodeLink(node: JSXElementByFn<'CodeLink'>): Promise<ResolvedSnippetLink> {
111
- const src = typeof node.props.src === 'string' ? node.props.src : Runtime.getSource(node.props.src);
112
- return DocResolveUtil.resolveCodeLink(src, node.props.startRe);
111
+ return DocResolveUtil.resolveCodeLink(node.props.src, node.props.startRe);
113
112
  }
114
113
 
115
114
  /**
116
115
  * Resolve code/config
117
116
  */
118
117
  async resolveCode(node: JSXElementByFn<'Code' | 'Config'>): Promise<ResolvedCode> {
119
- const src = typeof node.props.src === 'string' ? node.props.src : Runtime.getSource(node.props.src);
120
118
  return node.props.startRe ?
121
- DocResolveUtil.resolveSnippet(src, node.props.startRe, node.props.endRe, node.props.outline) :
122
- DocResolveUtil.resolveCode(src, node.props.language, node.props.outline);
119
+ DocResolveUtil.resolveSnippet(node.props.src, node.props.startRe, node.props.endRe, node.props.outline) :
120
+ DocResolveUtil.resolveCode(node.props.src, node.props.language, node.props.outline);
123
121
  }
124
122
 
125
123
  /**
@@ -2,7 +2,7 @@ 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 { Runtime, RuntimeIndex } from '@travetto/runtime';
5
+ import { RuntimeIndex } from '@travetto/runtime';
6
6
 
7
7
  import { EMPTY_ELEMENT, getComponentName, JSXElementByFn, c } from '../jsx';
8
8
  import { DocumentShape, RenderProvider, RenderState } from '../types';
@@ -93,12 +93,12 @@ export class DocRenderer {
93
93
  case 'number':
94
94
  case 'bigint':
95
95
  case 'boolean': return `${node}`;
96
- default: {
97
- const source = typeof node === 'function' ? Runtime.getSource(node) : undefined;
98
- if (source && typeof node === 'function') {
99
- const title = (await DocFileUtil.isDecorator(node.name, source)) ? `@${node.name}` : node.name;
96
+ case 'function': {
97
+ const source = DocFileUtil.readSource(node);
98
+ if (source.file) {
99
+ const title = (await DocFileUtil.isDecorator(node.name, source.file)) ? `@${node.name}` : node.name;
100
100
  const el = this.#support.createElement('CodeLink', {
101
- src: source,
101
+ src: source.file,
102
102
  startRe: new RegExp(`(class|function)\\s+(${node.name})`),
103
103
  title
104
104
  });
@@ -110,9 +110,10 @@ export class DocRenderer {
110
110
  state.createState = (key, props) => this.createState(state, key, props);
111
111
  return await renderer.CodeLink(state);
112
112
  }
113
- throw new Error(`Unknown object type: ${typeof node}`);
113
+ break;
114
114
  }
115
115
  }
116
+ throw new Error(`Unknown object type: ${typeof node}`);
116
117
  }
117
118
  }
118
119
 
package/src/util/file.ts CHANGED
@@ -1,8 +1,7 @@
1
- import fs from 'node:fs/promises';
1
+ import { readFileSync, existsSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
- import { ManifestModuleUtil } from '@travetto/manifest';
5
- import { RuntimeIndex } from '@travetto/runtime';
4
+ import { Runtime, RuntimeIndex } from '@travetto/runtime';
6
5
 
7
6
  const ESLINT_PATTERN = /\s*\/\/ eslint.*$/g;
8
7
  const ENV_KEY = /Env.([^.]+)[.]key/g;
@@ -25,58 +24,56 @@ export class DocFileUtil {
25
24
  return /^[@:A-Za-z0-9\/\\\-_.]+[.]([a-z]{2,10})$/.test(src);
26
25
  }
27
26
 
28
- /**
29
- * Resolve file
30
- * @param file
31
- * @returns
32
- */
33
- static async resolveFile(file: string): Promise<string> {
34
- let resolved = path.resolve(file);
35
- if (!(await fs.stat(resolved).catch(() => false))) {
36
- if (ManifestModuleUtil.getFileType(file) === 'ts') {
37
- resolved = RuntimeIndex.getSourceFile(file);
38
- }
39
- if (!(await fs.stat(resolved).catch(() => false))) {
40
- throw new Error(`Unknown file to resolve: ${file}`);
27
+ static readSource(src: string | Function): { content: string, language: string, file: string } {
28
+ let file: string | undefined;
29
+ let content: string | undefined;
30
+
31
+ if (typeof src === 'string') {
32
+ if (src.includes('\n') || src.includes(' ')) {
33
+ content = src;
34
+ } else {
35
+ const resolved = path.resolve(src);
36
+ if (existsSync(resolved)) {
37
+ content = readFileSync(resolved, 'utf8');
38
+ file = resolved;
39
+ } else {
40
+ file = RuntimeIndex.getSourceFile(src);
41
+ content = readFileSync(file, 'utf8');
42
+ }
41
43
  }
44
+ } else {
45
+ file = Runtime.getSourceFile(src);
46
+ content = readFileSync(file, 'utf8');
42
47
  }
43
- return resolved;
44
- }
45
48
 
46
- /**
47
- * Read file
48
- *
49
- * @param file
50
- * @returns
51
- */
52
- static async read(file: string): Promise<{ content: string, language: string, file: string }> {
53
- file = await this.resolveFile(file);
54
-
55
- const ext = path.extname(file);
56
- const language = this.#extToLang[ext] ?? ext.replace('.', '');
57
-
58
- let text: string | undefined;
59
- if (language) {
60
- text = await fs.readFile(file, 'utf8');
61
-
62
- text = text.split(/\n/)
49
+ if (content) {
50
+ content = content.split(/\n/)
63
51
  .map(x => x
64
52
  .replace(ESLINT_PATTERN, '')
65
53
  .replace(ENV_KEY, (_, k) => `'${k}'`)
66
54
  )
67
- .filter(x => !x.includes('@doc-exclude'))
68
- .join('\n');
55
+ .join('\n')
56
+ .replace(/^\/\/# sourceMap.*$/gsm, '')
57
+ .replace(/[ ]*[/][/][ ]*@ts-expect-error[^\n]*\n/gsm, '') // Excluding errors
58
+ .replace(/^[ ]*[/][/][ ]*[{][{][^\n]*\n/gsm, '') // Excluding conditional comments, full-line
59
+ .replace(/[ ]*[/][/][ ]*[{][{][^\n]*/gsm, ''); // Excluding conditional comments
69
60
  }
70
61
 
71
- return { content: text ?? '', language, file };
62
+ if (file !== undefined) {
63
+ const ext = path.extname(file);
64
+ const language = this.#extToLang[ext] ?? ext.replace('.', '');
65
+ return { content, file, language };
66
+ } else {
67
+ return { content, file: '', language: '' };
68
+ }
72
69
  }
73
70
 
74
- static async readCodeSnippet(file: string, startPattern: RegExp): Promise<{ file: string, startIdx: number, lines: string[], language: string }> {
75
- const res = await this.read(file);
76
- const lines = res.content.split(/\n/g);
71
+ static async readCodeSnippet(src: string | Function, startPattern: RegExp): Promise<{ file: string, startIdx: number, lines: string[], language: string }> {
72
+ const res = this.readSource(src);
73
+ const lines = res.content.split(/\n/);
77
74
  const startIdx = lines.findIndex(l => startPattern.test(l));
78
75
  if (startIdx < 0) {
79
- throw new Error(`Pattern ${startPattern.source} not found in ${file}`);
76
+ throw new Error(`Pattern ${startPattern.source} not found in ${src}`);
80
77
  }
81
78
  return { file: res.file, startIdx, lines, language: res.language };
82
79
  }
@@ -85,15 +82,14 @@ export class DocFileUtil {
85
82
  * Determine if a file is a decorator
86
83
  */
87
84
  static async isDecorator(name: string, file: string): Promise<boolean> {
88
- file = await this.resolveFile(file);
89
85
 
90
86
  const key = `${name}:${file}`;
91
87
  if (key in this.#decCache) {
92
88
  return this.#decCache[key];
93
89
  }
94
90
 
95
- const text = (await fs.readFile(file, 'utf8'))
96
- .split(/\n/g);
91
+ const res = await this.readSource(file);
92
+ const text = res.content.split(/\n/g);
97
93
 
98
94
  const start = text.findIndex(x => new RegExp(`function ${name}\\b`).test(x));
99
95
  let ret = false;
@@ -13,7 +13,7 @@ export class DocResolveUtil {
13
13
  static async resolveRef(title: string, file: string): Promise<ResolvedRef> {
14
14
 
15
15
  let line = 0;
16
- const res = await DocFileUtil.read(file);
16
+ const res = await DocFileUtil.readSource(file);
17
17
  file = res.file;
18
18
 
19
19
  if (res.content) {
@@ -31,22 +31,22 @@ export class DocResolveUtil {
31
31
  return { title, file, line };
32
32
  }
33
33
 
34
- static async resolveCode(content: string, language?: string, outline = false): Promise<ResolvedCode> {
34
+ static async resolveCode(content: string | Function, language?: string, outline = false): Promise<ResolvedCode> {
35
+ const res = DocFileUtil.readSource(content);
36
+ let text = res.content;
37
+
35
38
  let file: string | undefined;
36
- if (DocFileUtil.isFile(content)) {
37
- const res = await DocFileUtil.read(content);
39
+ if (res.file) {
38
40
  language = res.language;
39
41
  file = res.file;
40
- content = res.content;
41
42
  if (outline) {
42
- content = DocFileUtil.buildOutline(content);
43
+ text = DocFileUtil.buildOutline(text);
43
44
  }
44
45
  }
45
- content = content.replace(/^\/\/# sourceMap.*$/gm, '');
46
- return { text: content, language: language!, file };
46
+ return { text, language: language!, file };
47
47
  }
48
48
 
49
- static async resolveSnippet(file: string, startPattern: RegExp, endPattern?: RegExp, outline = false): Promise<ResolvedSnippet> {
49
+ static async resolveSnippet(file: Function | string, startPattern: RegExp, endPattern?: RegExp, outline = false): Promise<ResolvedSnippet> {
50
50
  const { lines, startIdx, language, file: resolvedFile } = await DocFileUtil.readCodeSnippet(file, startPattern);
51
51
 
52
52
  const endIdx = endPattern ? lines.findIndex((l, i) => i > startIdx && endPattern.test(l)) : lines.length;
@@ -59,7 +59,7 @@ export class DocResolveUtil {
59
59
  return { text, language, line: startIdx + 1, file: resolvedFile };
60
60
  }
61
61
 
62
- static async resolveCodeLink(file: string, startPattern: RegExp): Promise<ResolvedSnippetLink> {
62
+ static async resolveCodeLink(file: Function | string, startPattern: RegExp): Promise<ResolvedSnippetLink> {
63
63
  const { startIdx, file: resolvedFile } = await DocFileUtil.readCodeSnippet(file, startPattern);
64
64
  return { file: resolvedFile, line: startIdx + 1 };
65
65
  }