@ankhorage/paradox 0.0.2 → 0.0.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/CHANGELOG.md +12 -0
- package/README.md +9 -0
- package/dist/analyze/analyze.d.ts +8 -0
- package/dist/analyze/analyze.js +34 -0
- package/dist/analyze/components.d.ts +5 -0
- package/dist/analyze/components.js +21 -0
- package/dist/analyze/exports.d.ts +16 -0
- package/dist/analyze/exports.js +52 -0
- package/dist/analyze/project.d.ts +5 -0
- package/dist/analyze/project.js +10 -0
- package/dist/analyze/types.d.ts +45 -0
- package/dist/analyze/types.js +1 -0
- package/dist/analyze/usage.d.ts +7 -0
- package/dist/analyze/usage.js +40 -0
- package/dist/analyze/utils/getComponentPropsType.d.ts +5 -0
- package/dist/analyze/utils/getComponentPropsType.js +21 -0
- package/dist/analyze/utils/getParadoxComment.d.ts +5 -0
- package/dist/analyze/utils/getParadoxComment.js +19 -0
- package/dist/analyze/utils/getPropsFromType.d.ts +6 -0
- package/dist/analyze/utils/getPropsFromType.js +19 -0
- package/dist/analyze/utils/isReactComponent.d.ts +5 -0
- package/dist/analyze/utils/isReactComponent.js +30 -0
- package/dist/analyze/utils/parseParadoxComment.d.ts +12 -0
- package/dist/analyze/utils/parseParadoxComment.js +25 -0
- package/{src/analyze/utils/resolveExportSymbol.ts → dist/analyze/utils/resolveExportSymbol.d.ts} +1 -4
- package/dist/analyze/utils/resolveExportSymbol.js +6 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +26 -0
- package/{src/config/defineParadoxConfig.ts → dist/config/defineParadoxConfig.d.ts} +1 -4
- package/dist/config/defineParadoxConfig.js +6 -0
- package/dist/config/types.d.ts +19 -0
- package/dist/config/types.js +1 -0
- package/dist/index.js +1 -0
- package/dist/model/buildModel.d.ts +36 -0
- package/dist/model/buildModel.js +65 -0
- package/dist/model/types.d.ts +42 -0
- package/dist/model/types.js +1 -0
- package/dist/paths/policy.d.ts +23 -0
- package/dist/paths/policy.js +105 -0
- package/dist/render/render.d.ts +6 -0
- package/dist/render/render.js +95 -0
- package/dist/render/types.d.ts +10 -0
- package/dist/render/types.js +1 -0
- package/dist/write/write.d.ts +9 -0
- package/dist/write/write.js +18 -0
- package/package.json +27 -3
- package/.changeset/README.md +0 -5
- package/.changeset/config.json +0 -11
- package/.changeset/stable-usage-model.md +0 -5
- package/.github/workflows/docs.yml +0 -45
- package/.prettierignore +0 -1
- package/.prettierrc.js +0 -5
- package/bun.lock +0 -663
- package/eslint.config.mjs +0 -12
- package/knip.json +0 -8
- package/paradox/components.md +0 -1
- package/paradox/exports.json +0 -12
- package/paradox/exports.md +0 -13
- package/paradox/paradox.json +0 -32
- package/paradox.config.ts +0 -18
- package/src/analyze/analyze.ts +0 -45
- package/src/analyze/components.ts +0 -27
- package/src/analyze/exports.ts +0 -87
- package/src/analyze/project.ts +0 -11
- package/src/analyze/types.ts +0 -53
- package/src/analyze/usage.ts +0 -53
- package/src/analyze/utils/getComponentPropsType.ts +0 -26
- package/src/analyze/utils/getParadoxComment.ts +0 -24
- package/src/analyze/utils/getPropsFromType.ts +0 -24
- package/src/analyze/utils/isReactComponent.ts +0 -35
- package/src/analyze/utils/parseParadoxComment.ts +0 -37
- package/src/cli.ts +0 -30
- package/src/config/types.ts +0 -22
- package/src/model/buildModel.ts +0 -112
- package/src/model/types.ts +0 -49
- package/src/render/render.ts +0 -115
- package/src/render/types.ts +0 -10
- package/src/write/write.ts +0 -25
- package/tests/__snapshots__/basic.components.md +0 -10
- package/tests/__snapshots__/basic.exports.md +0 -19
- package/tests/__snapshots__/basic.readme.md +0 -37
- package/tests/__snapshots__/multi-bin.readme.md +0 -16
- package/tests/analyze.test.ts +0 -153
- package/tests/fixtures/basic/package.json +0 -8
- package/tests/fixtures/basic/src/config.ts +0 -8
- package/tests/fixtures/basic/src/index.ts +0 -3
- package/tests/fixtures/basic/src/internal.ts +0 -6
- package/tests/fixtures/basic/src/ui.ts +0 -29
- package/tests/fixtures/basic/tsconfig.json +0 -11
- package/tests/fixtures/multi-bin/package.json +0 -9
- package/tests/fixtures/multi-bin/src/alpha.ts +0 -1
- package/tests/fixtures/multi-bin/src/beta.ts +0 -1
- package/tests/fixtures/multi-bin/src/index.ts +0 -4
- package/tests/fixtures/multi-bin/tsconfig.json +0 -11
- package/tsconfig.eslint.json +0 -16
- package/tsconfig.json +0 -14
- /package/{src/index.ts → dist/index.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f5b89ce: Stabilize Paradox config discovery and output path resolution so generated artifacts are written under the resolved package output directory.
|
|
8
|
+
|
|
9
|
+
## 0.0.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- d9fb959: Stabilize usage metadata, documentation model serialization, deterministic output ordering, and package entrypoint exports.
|
|
14
|
+
|
|
3
15
|
## 0.0.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -20,6 +20,15 @@ export default defineParadoxConfig({
|
|
|
20
20
|
});
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## Path resolution
|
|
24
|
+
|
|
25
|
+
- Config discovery: searches upward from `process.cwd()` for `paradox.config.ts/js/mjs/cjs` (required; no fallback).
|
|
26
|
+
- Package root: defaults to the directory containing `paradox.config.*`; `package.root` (when relative) resolves relative to that directory.
|
|
27
|
+
- Output directory: defaults to `paradox/`; `output.dir` (when relative) resolves relative to the resolved package root and must stay inside it.
|
|
28
|
+
- Modes:
|
|
29
|
+
- `safe`: writes generated artifacts only under the output directory
|
|
30
|
+
- `write`: additionally updates `<packageRoot>/README.md`
|
|
31
|
+
|
|
23
32
|
## Public API
|
|
24
33
|
|
|
25
34
|
### defineParadoxConfig
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ParadoxConfig } from '../config/types.js';
|
|
2
|
+
import type { AnalysisResult } from './types.js';
|
|
3
|
+
/***
|
|
4
|
+
* Runs the source analysis pipeline for a configured package.
|
|
5
|
+
*/
|
|
6
|
+
export declare function analyze(config: ParadoxConfig, runtime: {
|
|
7
|
+
packageRoot: string;
|
|
8
|
+
}): Promise<AnalysisResult>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { analyzeComponents } from './components.js';
|
|
4
|
+
import { analyzeExports } from './exports.js';
|
|
5
|
+
import { createProject } from './project.js';
|
|
6
|
+
import { createUsageFromPackageJson } from './usage.js';
|
|
7
|
+
/***
|
|
8
|
+
* Runs the source analysis pipeline for a configured package.
|
|
9
|
+
*/
|
|
10
|
+
export async function analyze(config, runtime) {
|
|
11
|
+
const root = runtime.packageRoot;
|
|
12
|
+
const pkg = await readPackageJson(root);
|
|
13
|
+
const usage = createUsageFromPackageJson(pkg);
|
|
14
|
+
const project = createProject(root);
|
|
15
|
+
const entrypoints = config.package?.entrypoints ?? ['src/index.ts'];
|
|
16
|
+
const { config: configMetadata, exports } = analyzeExports(project, {
|
|
17
|
+
root,
|
|
18
|
+
entrypoints,
|
|
19
|
+
});
|
|
20
|
+
const components = analyzeComponents(exports);
|
|
21
|
+
return {
|
|
22
|
+
packageName: config.docs?.title ?? pkg.name,
|
|
23
|
+
packageId: pkg.name,
|
|
24
|
+
description: config.docs?.description ?? pkg.description ?? null,
|
|
25
|
+
exports,
|
|
26
|
+
components,
|
|
27
|
+
usage,
|
|
28
|
+
config: configMetadata,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function readPackageJson(root) {
|
|
32
|
+
const raw = await readFile(join(root, 'package.json'), 'utf-8');
|
|
33
|
+
return JSON.parse(raw);
|
|
34
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getComponentPropsType } from './utils/getComponentPropsType.js';
|
|
2
|
+
import { getPropsFromType } from './utils/getPropsFromType.js';
|
|
3
|
+
import { isReactComponent } from './utils/isReactComponent.js';
|
|
4
|
+
/***
|
|
5
|
+
* Extracts React components and their props from analyzed exports.
|
|
6
|
+
*/
|
|
7
|
+
export function analyzeComponents(exports) {
|
|
8
|
+
const components = [];
|
|
9
|
+
for (const e of exports) {
|
|
10
|
+
if (!isReactComponent(e.node))
|
|
11
|
+
continue;
|
|
12
|
+
const propsType = getComponentPropsType(e.node);
|
|
13
|
+
const props = propsType != null ? getPropsFromType(propsType) : [];
|
|
14
|
+
components.push({
|
|
15
|
+
name: e.name,
|
|
16
|
+
description: e.description,
|
|
17
|
+
props,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return components;
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Project } from 'ts-morph';
|
|
2
|
+
import type { AnalysisExport } from './types.js';
|
|
3
|
+
interface AnalyzeExportsResult {
|
|
4
|
+
exports: AnalysisExport[];
|
|
5
|
+
config: {
|
|
6
|
+
exportName: string;
|
|
7
|
+
} | null;
|
|
8
|
+
}
|
|
9
|
+
/***
|
|
10
|
+
* Collects exported declarations from configured package entrypoints.
|
|
11
|
+
*/
|
|
12
|
+
export declare function analyzeExports(project: Project, options: {
|
|
13
|
+
root: string;
|
|
14
|
+
entrypoints: readonly string[];
|
|
15
|
+
}): AnalyzeExportsResult;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { isAbsolute, join, normalize } from 'node:path';
|
|
2
|
+
import { getParadoxComment } from './utils/getParadoxComment.js';
|
|
3
|
+
import { parseParadoxComment } from './utils/parseParadoxComment.js';
|
|
4
|
+
import { resolveExportSymbol } from './utils/resolveExportSymbol.js';
|
|
5
|
+
/***
|
|
6
|
+
* Collects exported declarations from configured package entrypoints.
|
|
7
|
+
*/
|
|
8
|
+
export function analyzeExports(project, options) {
|
|
9
|
+
const exports = [];
|
|
10
|
+
let config = null;
|
|
11
|
+
for (const sourceFile of getEntryPointSourceFiles(project, options)) {
|
|
12
|
+
const exported = sourceFile.getExportSymbols();
|
|
13
|
+
for (const symbol of exported) {
|
|
14
|
+
const resolved = resolveExportSymbol(symbol);
|
|
15
|
+
const [decl] = resolved.getDeclarations();
|
|
16
|
+
const rawComment = getParadoxComment(decl);
|
|
17
|
+
const parsed = rawComment
|
|
18
|
+
? parseParadoxComment(rawComment)
|
|
19
|
+
: { description: null, isConfig: false };
|
|
20
|
+
if (parsed.isConfig) {
|
|
21
|
+
config = {
|
|
22
|
+
exportName: resolved.getName(),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
exports.push({
|
|
26
|
+
name: resolved.getName(),
|
|
27
|
+
node: decl,
|
|
28
|
+
description: parsed.description,
|
|
29
|
+
kind: inferKind(decl),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
exports,
|
|
35
|
+
config,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function getEntryPointSourceFiles(project, options) {
|
|
39
|
+
return options.entrypoints
|
|
40
|
+
.map((entrypoint) => {
|
|
41
|
+
const absolutePath = normalize(isAbsolute(entrypoint) ? entrypoint : join(options.root, entrypoint));
|
|
42
|
+
return project.getSourceFile((sourceFile) => normalize(sourceFile.getFilePath()) === absolutePath);
|
|
43
|
+
})
|
|
44
|
+
.filter((sourceFile) => sourceFile != null);
|
|
45
|
+
}
|
|
46
|
+
function inferKind(node) {
|
|
47
|
+
if ('getParameters' in node)
|
|
48
|
+
return 'function';
|
|
49
|
+
if ('getProperties' in node || 'getMembers' in node)
|
|
50
|
+
return 'type';
|
|
51
|
+
return 'unknown';
|
|
52
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Node } from 'ts-morph';
|
|
2
|
+
/***
|
|
3
|
+
* Describes one exported declaration discovered in a package.
|
|
4
|
+
*/
|
|
5
|
+
export interface AnalysisExport {
|
|
6
|
+
name: string;
|
|
7
|
+
node: Node;
|
|
8
|
+
description: string | null;
|
|
9
|
+
kind: 'function' | 'type' | 'unknown';
|
|
10
|
+
}
|
|
11
|
+
/***
|
|
12
|
+
* Describes one React component and its extracted props.
|
|
13
|
+
*/
|
|
14
|
+
export interface AnalysisComponent {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string | null;
|
|
17
|
+
props: {
|
|
18
|
+
name: string;
|
|
19
|
+
type: string;
|
|
20
|
+
required: boolean;
|
|
21
|
+
description: string | null;
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
export interface AnalysisUsage {
|
|
25
|
+
packageName: string;
|
|
26
|
+
commands: AnalysisUsageCommand[];
|
|
27
|
+
}
|
|
28
|
+
export interface AnalysisUsageCommand {
|
|
29
|
+
name: string;
|
|
30
|
+
command: string;
|
|
31
|
+
}
|
|
32
|
+
/***
|
|
33
|
+
* Complete analysis output used to build the documentation model.
|
|
34
|
+
*/
|
|
35
|
+
export interface AnalysisResult {
|
|
36
|
+
packageName: string;
|
|
37
|
+
packageId: string;
|
|
38
|
+
description: string | null;
|
|
39
|
+
exports: AnalysisExport[];
|
|
40
|
+
components: AnalysisComponent[];
|
|
41
|
+
usage: AnalysisUsage | null;
|
|
42
|
+
config: {
|
|
43
|
+
exportName: string;
|
|
44
|
+
} | null;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AnalysisUsage } from './types.js';
|
|
2
|
+
export interface PackageJsonModel {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
bin?: string | Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
export declare function createUsageFromPackageJson(pkg: PackageJsonModel): AnalysisUsage | null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function createUsageFromPackageJson(pkg) {
|
|
2
|
+
if (pkg.bin == null)
|
|
3
|
+
return null;
|
|
4
|
+
if (typeof pkg.bin === 'string') {
|
|
5
|
+
return {
|
|
6
|
+
packageName: pkg.name,
|
|
7
|
+
commands: [
|
|
8
|
+
{
|
|
9
|
+
name: getPackageBaseName(pkg.name),
|
|
10
|
+
command: `bunx ${pkg.name}`,
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const entries = Object.keys(pkg.bin).sort((a, b) => a.localeCompare(b));
|
|
16
|
+
if (entries.length === 0)
|
|
17
|
+
return null;
|
|
18
|
+
if (entries.length === 1) {
|
|
19
|
+
const [name] = entries;
|
|
20
|
+
return {
|
|
21
|
+
packageName: pkg.name,
|
|
22
|
+
commands: [
|
|
23
|
+
{
|
|
24
|
+
name,
|
|
25
|
+
command: `bunx ${pkg.name}`,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
packageName: pkg.name,
|
|
32
|
+
commands: entries.map((name) => ({
|
|
33
|
+
name,
|
|
34
|
+
command: `bunx ${pkg.name} ${name}`,
|
|
35
|
+
})),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function getPackageBaseName(packageName) {
|
|
39
|
+
return packageName.split('/').pop() ?? packageName;
|
|
40
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
/***
|
|
3
|
+
* Returns the first parameter type for a React component declaration.
|
|
4
|
+
*/
|
|
5
|
+
export function getComponentPropsType(node) {
|
|
6
|
+
const callSignature = getCallSignature(node);
|
|
7
|
+
const firstParam = callSignature?.getParameters()[0];
|
|
8
|
+
const firstDecl = firstParam?.getDeclarations()[0];
|
|
9
|
+
if (firstDecl)
|
|
10
|
+
return firstParam.getTypeAtLocation(firstDecl);
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function getCallSignature(node) {
|
|
14
|
+
if (Node.isFunctionDeclaration(node)) {
|
|
15
|
+
return node.getType().getCallSignatures()[0] ?? null;
|
|
16
|
+
}
|
|
17
|
+
if (Node.isVariableDeclaration(node)) {
|
|
18
|
+
return node.getType().getCallSignatures()[0] ?? null;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Reads the nearest Paradox doc comment attached to a declaration.
|
|
3
|
+
*/
|
|
4
|
+
export function getParadoxComment(node) {
|
|
5
|
+
const sourceFile = node.getSourceFile();
|
|
6
|
+
const text = sourceFile.getFullText();
|
|
7
|
+
const nodeStart = node.getStart(false);
|
|
8
|
+
const beforeNode = text.slice(0, nodeStart);
|
|
9
|
+
const commentStart = beforeNode.lastIndexOf('/***');
|
|
10
|
+
if (commentStart === -1)
|
|
11
|
+
return null;
|
|
12
|
+
const commentEnd = text.indexOf('*/', commentStart);
|
|
13
|
+
if (commentEnd === -1 || commentEnd > nodeStart)
|
|
14
|
+
return null;
|
|
15
|
+
const between = text.slice(commentEnd + 2, nodeStart);
|
|
16
|
+
if (!/^[\s;]*(export\s+)?(default\s+)?$/.test(between))
|
|
17
|
+
return null;
|
|
18
|
+
return text.slice(commentStart, commentEnd + 2);
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getParadoxComment } from './getParadoxComment.js';
|
|
2
|
+
import { parseParadoxComment } from './parseParadoxComment.js';
|
|
3
|
+
/***
|
|
4
|
+
* Extracts prop names, types, required flags, and descriptions from a type.
|
|
5
|
+
*/
|
|
6
|
+
export function getPropsFromType(type) {
|
|
7
|
+
return type.getProperties().map((property) => {
|
|
8
|
+
const [declaration] = property.getDeclarations();
|
|
9
|
+
const propertyType = property.getTypeAtLocation(declaration);
|
|
10
|
+
const rawComment = getParadoxComment(declaration);
|
|
11
|
+
const parsed = rawComment ? parseParadoxComment(rawComment) : { description: null };
|
|
12
|
+
return {
|
|
13
|
+
name: property.getName(),
|
|
14
|
+
type: propertyType.getText(declaration),
|
|
15
|
+
required: !property.isOptional(),
|
|
16
|
+
description: parsed.description,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
/***
|
|
3
|
+
* Detects simple React component declarations by name and return type.
|
|
4
|
+
*/
|
|
5
|
+
export function isReactComponent(node) {
|
|
6
|
+
const name = getDeclarationName(node);
|
|
7
|
+
if (!name || !/^[A-Z]/.test(name))
|
|
8
|
+
return false;
|
|
9
|
+
const callSignature = getCallSignature(node);
|
|
10
|
+
const returnType = callSignature?.getReturnType().getText() ?? null;
|
|
11
|
+
if (returnType == null)
|
|
12
|
+
return false;
|
|
13
|
+
return /JSX\.Element|ReactElement|ReactNode|Element/.test(returnType);
|
|
14
|
+
}
|
|
15
|
+
function getDeclarationName(node) {
|
|
16
|
+
if (Node.isFunctionDeclaration(node))
|
|
17
|
+
return node.getName() ?? null;
|
|
18
|
+
if (Node.isVariableDeclaration(node))
|
|
19
|
+
return node.getName();
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function getCallSignature(node) {
|
|
23
|
+
if (Node.isFunctionDeclaration(node)) {
|
|
24
|
+
return node.getType().getCallSignatures()[0] ?? null;
|
|
25
|
+
}
|
|
26
|
+
if (Node.isVariableDeclaration(node)) {
|
|
27
|
+
return node.getType().getCallSignatures()[0] ?? null;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Parsed representation of a Paradox doc comment.
|
|
3
|
+
*/
|
|
4
|
+
interface ParsedParadoxComment {
|
|
5
|
+
description: string | null;
|
|
6
|
+
isConfig: boolean;
|
|
7
|
+
}
|
|
8
|
+
/***
|
|
9
|
+
* Parses a Paradox doc comment into structured metadata.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseParadoxComment(rawComment: string): ParsedParadoxComment;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Parses a Paradox doc comment into structured metadata.
|
|
3
|
+
*/
|
|
4
|
+
export function parseParadoxComment(rawComment) {
|
|
5
|
+
const lines = rawComment
|
|
6
|
+
.replace(/^\/\*\*\*/, '')
|
|
7
|
+
.replace(/\*\/$/, '')
|
|
8
|
+
.split('\n')
|
|
9
|
+
.map((line) => line.replace(/^\s*\*\s?/, '').trimEnd());
|
|
10
|
+
let isConfig = false;
|
|
11
|
+
const description = lines
|
|
12
|
+
.filter((line) => {
|
|
13
|
+
if (line.trimStart().startsWith('@config')) {
|
|
14
|
+
isConfig = true;
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
})
|
|
19
|
+
.join('\n')
|
|
20
|
+
.trim();
|
|
21
|
+
return {
|
|
22
|
+
description: description.length > 0 ? description : null,
|
|
23
|
+
isConfig,
|
|
24
|
+
};
|
|
25
|
+
}
|
package/{src/analyze/utils/resolveExportSymbol.ts → dist/analyze/utils/resolveExportSymbol.d.ts}
RENAMED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { Symbol } from 'ts-morph';
|
|
2
|
-
|
|
3
2
|
/***
|
|
4
3
|
* Resolves aliased export symbols to their underlying declarations.
|
|
5
4
|
*/
|
|
6
|
-
export function resolveExportSymbol(symbol: Symbol): Symbol
|
|
7
|
-
return symbol.getAliasedSymbol() ?? symbol;
|
|
8
|
-
}
|
|
5
|
+
export declare function resolveExportSymbol(symbol: Symbol): Symbol;
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { analyze } from './analyze/analyze.js';
|
|
4
|
+
import { buildModel } from './model/buildModel.js';
|
|
5
|
+
import { findParadoxConfigFile, loadParadoxConfig, resolveOutputRoot, resolvePackageRoot, } from './paths/policy.js';
|
|
6
|
+
import { render } from './render/render.js';
|
|
7
|
+
import { write } from './write/write.js';
|
|
8
|
+
async function main() {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
const configFilePath = await findParadoxConfigFile(cwd);
|
|
11
|
+
if (!configFilePath) {
|
|
12
|
+
throw new Error(`Unable to find Paradox config. Looked for paradox.config.{ts,js,mjs,cjs} by searching upward from: ${cwd}`);
|
|
13
|
+
}
|
|
14
|
+
const configDir = dirname(configFilePath);
|
|
15
|
+
const config = await loadParadoxConfig(configFilePath);
|
|
16
|
+
const packageRoot = await resolvePackageRoot(config, configDir);
|
|
17
|
+
const { outputRoot } = resolveOutputRoot(config, packageRoot);
|
|
18
|
+
const analysis = await analyze(config, { packageRoot });
|
|
19
|
+
const model = buildModel(analysis);
|
|
20
|
+
const result = render(model);
|
|
21
|
+
await write(result, config, { packageRoot, outputRoot });
|
|
22
|
+
}
|
|
23
|
+
main().catch((error) => {
|
|
24
|
+
console.error(error);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { ParadoxConfig } from './types.js';
|
|
2
|
-
|
|
3
2
|
/***
|
|
4
3
|
* Defines a Paradox configuration object without changing its shape.
|
|
5
4
|
*/
|
|
6
|
-
export function defineParadoxConfig(config: ParadoxConfig): ParadoxConfig
|
|
7
|
-
return config;
|
|
8
|
-
}
|
|
5
|
+
export declare function defineParadoxConfig(config: ParadoxConfig): ParadoxConfig;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Configuration for running Paradox.
|
|
3
|
+
*
|
|
4
|
+
* @config
|
|
5
|
+
*/
|
|
6
|
+
export interface ParadoxConfig {
|
|
7
|
+
mode?: 'safe' | 'write';
|
|
8
|
+
docs?: {
|
|
9
|
+
title?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
};
|
|
12
|
+
package?: {
|
|
13
|
+
root?: string;
|
|
14
|
+
entrypoints?: string[];
|
|
15
|
+
};
|
|
16
|
+
output?: {
|
|
17
|
+
dir?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { defineParadoxConfig } from './config/defineParadoxConfig.js';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { DocumentationModel, ExportKind } from './types.js';
|
|
2
|
+
interface BuildModelInput {
|
|
3
|
+
packageName: string;
|
|
4
|
+
packageId: string;
|
|
5
|
+
description: string | null;
|
|
6
|
+
exports: {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string | null;
|
|
9
|
+
kind: ExportKind;
|
|
10
|
+
}[];
|
|
11
|
+
components: {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string | null;
|
|
14
|
+
props: {
|
|
15
|
+
name: string;
|
|
16
|
+
type: string;
|
|
17
|
+
required: boolean;
|
|
18
|
+
description: string | null;
|
|
19
|
+
}[];
|
|
20
|
+
}[];
|
|
21
|
+
usage: {
|
|
22
|
+
packageName: string;
|
|
23
|
+
commands: {
|
|
24
|
+
name: string;
|
|
25
|
+
command: string;
|
|
26
|
+
}[];
|
|
27
|
+
} | null;
|
|
28
|
+
config: {
|
|
29
|
+
exportName: string;
|
|
30
|
+
} | null;
|
|
31
|
+
}
|
|
32
|
+
/***
|
|
33
|
+
* Converts analysis output into a serializable documentation model.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildModel(analysis: BuildModelInput): DocumentationModel;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/***
|
|
2
|
+
* Converts analysis output into a serializable documentation model.
|
|
3
|
+
*/
|
|
4
|
+
export function buildModel(analysis) {
|
|
5
|
+
const exportsByName = new Map(analysis.exports.map((item) => [item.name, mapExport(item)]));
|
|
6
|
+
const exports = sortByName([...exportsByName.values()]);
|
|
7
|
+
return {
|
|
8
|
+
packageName: analysis.packageName,
|
|
9
|
+
packageId: analysis.packageId,
|
|
10
|
+
description: analysis.description,
|
|
11
|
+
usage: analysis.usage !== null
|
|
12
|
+
? {
|
|
13
|
+
packageName: analysis.usage.packageName,
|
|
14
|
+
commands: sortByName(analysis.usage.commands.map((command) => ({
|
|
15
|
+
name: command.name,
|
|
16
|
+
command: command.command,
|
|
17
|
+
}))),
|
|
18
|
+
}
|
|
19
|
+
: null,
|
|
20
|
+
config: analysis.config !== null
|
|
21
|
+
? {
|
|
22
|
+
exportName: analysis.config.exportName,
|
|
23
|
+
configFile: getDefaultConfigFileName(analysis.packageId),
|
|
24
|
+
factoryName: findConfigFactoryName(analysis.config.exportName, [
|
|
25
|
+
...exportsByName.keys(),
|
|
26
|
+
]),
|
|
27
|
+
}
|
|
28
|
+
: null,
|
|
29
|
+
exports,
|
|
30
|
+
components: sortByName(analysis.components.map(mapComponent)),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function mapExport(item) {
|
|
34
|
+
return {
|
|
35
|
+
name: item.name,
|
|
36
|
+
description: item.description,
|
|
37
|
+
kind: item.kind,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function mapComponent(component) {
|
|
41
|
+
return {
|
|
42
|
+
name: component.name,
|
|
43
|
+
description: component.description,
|
|
44
|
+
props: sortByName(component.props.map((prop) => ({
|
|
45
|
+
name: prop.name,
|
|
46
|
+
type: prop.type,
|
|
47
|
+
required: prop.required,
|
|
48
|
+
description: prop.description,
|
|
49
|
+
}))),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function findConfigFactoryName(configExportName, exportNames) {
|
|
53
|
+
const prefix = configExportName.endsWith('Config')
|
|
54
|
+
? configExportName.slice(0, -'Config'.length)
|
|
55
|
+
: configExportName;
|
|
56
|
+
const expectedFactoryName = `define${prefix}Config`;
|
|
57
|
+
return exportNames.includes(expectedFactoryName) ? expectedFactoryName : null;
|
|
58
|
+
}
|
|
59
|
+
function getDefaultConfigFileName(packageId) {
|
|
60
|
+
const packageBaseName = packageId.split('/').pop() ?? packageId;
|
|
61
|
+
return `${packageBaseName}.config.ts`;
|
|
62
|
+
}
|
|
63
|
+
function sortByName(items) {
|
|
64
|
+
return [...items].sort((a, b) => a.name.localeCompare(b.name));
|
|
65
|
+
}
|