@ankhorage/paradox 0.1.23 → 0.1.25

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.25
4
+
5
+ ### Patch Changes
6
+
7
+ - e377b70: Update docs & add changeset
8
+
9
+ ## 0.1.24
10
+
11
+ ### Patch Changes
12
+
13
+ - 95b08c8: Add opt-in Collaborators README and managed workflow generation through the root-level `collaborators` configuration.
14
+
3
15
  ## 0.1.23
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # @ankhorage/paradox
5
5
 
6
- ![license: MIT](./paradox/badges/license.svg) ![npm: v0.1.22](./paradox/badges/npm.svg) ![runtime: bun](./paradox/badges/runtime.svg) ![typescript: strict](./paradox/badges/typescript.svg) ![eslint: checked](./paradox/badges/eslint.svg) ![prettier: checked](./paradox/badges/prettier.svg) ![build: checked](./paradox/badges/build.svg) ![tests: checked](./paradox/badges/tests.svg) ![docs: paradox](./paradox/badges/docs.svg)
6
+ ![license: MIT](./paradox/badges/license.svg) ![npm: v0.1.24](./paradox/badges/npm.svg) ![runtime: bun](./paradox/badges/runtime.svg) ![typescript: strict](./paradox/badges/typescript.svg) ![eslint: checked](./paradox/badges/eslint.svg) ![prettier: checked](./paradox/badges/prettier.svg) ![build: checked](./paradox/badges/build.svg) ![tests: checked](./paradox/badges/tests.svg) ![docs: paradox](./paradox/badges/docs.svg)
7
7
 
8
8
  Deterministic documentation generator for TypeScript packages.
9
9
 
@@ -70,6 +70,8 @@ import { defineParadoxConfig } from './src/config/defineParadoxConfig.js';
70
70
  export default defineParadoxConfig({
71
71
  mode: 'write',
72
72
 
73
+ collaborators: true,
74
+
73
75
  donation: {
74
76
  account: 'ankhorage',
75
77
  },
@@ -92,13 +94,14 @@ export default defineParadoxConfig({
92
94
  <details>
93
95
  <summary>Configuration options</summary>
94
96
 
95
- | Field | Type | Required | Default | Description |
96
- | -------- | ------------------------------------------------------------------------------------------------------------------- | -------- | ------- | ----------- |
97
- | mode | `'safe' \| 'write' \| undefined` | no | — | |
98
- | donation | `{ account: string; } \| undefined` | no | — | |
99
- | docs | `{ title?: string; description?: string; usage?: { description?: string; entrypoints?: string[]; }; } \| undefined` | no | — | |
100
- | package | `{ root?: string; entrypoints?: string[]; } \| undefined` | no | — | |
101
- | output | `{ dir?: string; } \| undefined` | no | — | |
97
+ | Field | Type | Required | Default | Description |
98
+ | ------------- | ------------------------------------------------------------------------------------------------------------------- | -------- | ------- | ----------- |
99
+ | mode | `'safe' \| 'write' \| undefined` | no | — | |
100
+ | collaborators | `true \| undefined` | no | — | |
101
+ | donation | `{ account: string; } \| undefined` | no | — | |
102
+ | docs | `{ title?: string; description?: string; usage?: { description?: string; entrypoints?: string[]; }; } \| undefined` | no | — | |
103
+ | package | `{ root?: string; entrypoints?: string[]; } \| undefined` | no | — | |
104
+ | output | `{ dir?: string; } \| undefined` | no | — | |
102
105
 
103
106
  </details>
104
107
 
@@ -142,6 +145,11 @@ Source: `src/config/types.ts:7:1`
142
145
 
143
146
  </details>
144
147
 
148
+ ## Collaborators
149
+
150
+ <!-- readme: collaborators -start -->
151
+ <!-- readme: collaborators -end -->
152
+
145
153
  ## Donation
146
154
 
147
155
  If this project is useful to you, you can support its continued development.
@@ -1,5 +1,6 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
+ import { validateCollaborators } from '../config/utils/validateCollaborators.js';
3
4
  import { validateDonationAccount } from '../config/utils/validateDonationAccount.js';
4
5
  import { analyzeBadges } from './badges.js';
5
6
  import { analyzeComponents } from './components.js';
@@ -21,6 +22,7 @@ import { createUsageFromPackageJson } from './usage.js';
21
22
  export async function analyze(config, runtime) {
22
23
  const root = runtime.packageRoot;
23
24
  const pkg = await readPackageJson(root);
25
+ const collaborators = validateCollaborators(config.collaborators);
24
26
  const donation = config.donation === undefined
25
27
  ? null
26
28
  : { account: validateDonationAccount(config.donation.account) };
@@ -71,6 +73,7 @@ export async function analyze(config, runtime) {
71
73
  packageName: config.docs?.title ?? pkg.name,
72
74
  packageId: pkg.name,
73
75
  description: config.docs?.description ?? pkg.description ?? null,
76
+ collaborators,
74
77
  donation,
75
78
  exports,
76
79
  components,
@@ -168,6 +168,7 @@ export interface AnalysisResult {
168
168
  packageName: string;
169
169
  packageId: string;
170
170
  description: string | null;
171
+ collaborators: true | null;
171
172
  donation: AnalysisDonation | null;
172
173
  exports: AnalysisExport[];
173
174
  components: AnalysisComponent[];
@@ -6,6 +6,8 @@
6
6
  */
7
7
  export interface ParadoxConfig {
8
8
  mode?: 'safe' | 'write';
9
+ /** Enables canonical direct-collaborator documentation and workflow integration. */
10
+ collaborators?: true;
9
11
  /** Enables canonical GitHub Sponsors integration for generated repository documentation. */
10
12
  donation?: {
11
13
  /** GitHub Sponsors account login used for the Sponsor button and Donation chapter. */
@@ -0,0 +1 @@
1
+ export declare function validateCollaborators(value: unknown): true | null;
@@ -0,0 +1,7 @@
1
+ export function validateCollaborators(value) {
2
+ if (value === undefined)
3
+ return null;
4
+ if (value === true)
5
+ return true;
6
+ throw new Error('Invalid collaborators config. Expected literal true or omission.');
7
+ }
@@ -27,6 +27,7 @@ interface BuildModelInput {
27
27
  packageName: string;
28
28
  packageId: string;
29
29
  description: string | null;
30
+ collaborators: true | null;
30
31
  donation: {
31
32
  account: string;
32
33
  } | null;
@@ -9,6 +9,7 @@ export function buildModel(analysis) {
9
9
  packageName: analysis.packageName,
10
10
  packageId: analysis.packageId,
11
11
  description: analysis.description,
12
+ collaborators: analysis.collaborators,
12
13
  donation: analysis.donation === null ? null : { account: analysis.donation.account },
13
14
  badges: analysis.badges.map((badge) => ({
14
15
  id: badge.id,
@@ -5,6 +5,7 @@ export interface DocumentationModel {
5
5
  packageName: string;
6
6
  packageId: string;
7
7
  description: string | null;
8
+ collaborators: true | null;
8
9
  donation: DonationModel | null;
9
10
  badges: GeneratedBadge[];
10
11
  usage: UsageModel | null;
@@ -1,4 +1,5 @@
1
1
  import { renderBadgeArtifacts } from './renderers/badges.js';
2
+ import { renderCollaborators } from './renderers/collaborators.js';
2
3
  import { renderDiagramArtifacts } from './renderers/diagrams.js';
3
4
  import { renderDonation } from './renderers/donation.js';
4
5
  import { renderFundingYaml } from './renderers/funding.js';
@@ -18,6 +19,7 @@ export function render(model, options = {}) {
18
19
  exportsJson: `${JSON.stringify(model.exports, null, 2)}\n`,
19
20
  paradoxJson: `${JSON.stringify(model, null, 2)}\n`,
20
21
  indexHtml: '',
22
+ collaboratorsWorkflowYaml: null,
21
23
  fundingYaml: renderFundingYaml(model),
22
24
  badges,
23
25
  diagrams,
@@ -32,6 +34,7 @@ export function render(model, options = {}) {
32
34
  for (const renderer of [renderMarkdown, renderHtml]) {
33
35
  Object.assign(result, renderer(context));
34
36
  }
37
+ Object.assign(result, renderCollaborators(context));
35
38
  Object.assign(result, renderDonation(context));
36
39
  return result;
37
40
  }
@@ -0,0 +1,2 @@
1
+ import type { RenderContext } from '../types.js';
2
+ export declare function renderCollaborators(context: RenderContext): Pick<RenderContext['result'], 'collaboratorsWorkflowYaml' | 'readme'>;
@@ -0,0 +1,51 @@
1
+ export function renderCollaborators(context) {
2
+ if (context.model.collaborators === null) {
3
+ return {
4
+ collaboratorsWorkflowYaml: null,
5
+ readme: context.result.readme,
6
+ };
7
+ }
8
+ return {
9
+ collaboratorsWorkflowYaml: renderCollaboratorsWorkflowYaml(),
10
+ readme: renderCollaboratorsReadme(context.result.readme),
11
+ };
12
+ }
13
+ // Upgrade both values together only after verifying the Marketplace release and immutable tag SHA.
14
+ const actionCommit = '83ea0b4f1ac928fbfe88b9e8460a932a528eb79f';
15
+ const actionVersion = 'v2.3.11';
16
+ const collaboratorsMarkers = [
17
+ '<!-- readme: collaborators -start -->',
18
+ '<!-- readme: collaborators -end -->',
19
+ ].join('\n');
20
+ function renderCollaboratorsReadme(readme) {
21
+ return `${readme.trimEnd()}\n\n## Collaborators\n\n${collaboratorsMarkers}\n`;
22
+ }
23
+ function renderCollaboratorsWorkflowYaml() {
24
+ return [
25
+ '# Generated by Paradox. Do not edit manually.',
26
+ 'name: Update collaborators',
27
+ '',
28
+ 'on:',
29
+ ' schedule:',
30
+ " - cron: '17 3 * * 1'",
31
+ ' workflow_dispatch:',
32
+ '',
33
+ 'permissions:',
34
+ ' contents: write',
35
+ ' pull-requests: write',
36
+ '',
37
+ 'jobs:',
38
+ ' collaborators:',
39
+ ' name: Update collaborators',
40
+ ' runs-on: ubuntu-latest',
41
+ ' steps:',
42
+ ' - name: Update collaborators',
43
+ ` uses: akhilmhdh/contributors-readme-action@${actionCommit} # ${actionVersion}`,
44
+ ' with:',
45
+ ' readme_path: README.md',
46
+ ' collaborators: direct',
47
+ ' env:',
48
+ ' GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}',
49
+ '',
50
+ ].join('\n');
51
+ }
@@ -18,6 +18,7 @@ export interface RenderResult {
18
18
  exportsJson: string;
19
19
  paradoxJson: string;
20
20
  indexHtml: string;
21
+ collaboratorsWorkflowYaml: string | null;
21
22
  fundingYaml: string | null;
22
23
  diagrams: DiagramArtifact[];
23
24
  badges: BadgeArtifact[];
@@ -0,0 +1,3 @@
1
+ export declare function syncCollaboratorsWorkflowAsync(packageRoot: string, workflowYaml: string | null, options?: {
2
+ mode?: 'check' | 'write';
3
+ }): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ export async function syncCollaboratorsWorkflowAsync(packageRoot, workflowYaml, options = {}) {
4
+ const workflowPath = join(packageRoot, '.github', 'workflows', 'collaborators.yml');
5
+ const existing = await readCollaboratorsWorkflowAsync(workflowPath);
6
+ const mode = options.mode ?? 'write';
7
+ if (workflowYaml === null) {
8
+ if (mode === 'write' && existing !== null && isParadoxOwnedCollaboratorsWorkflow(existing)) {
9
+ await unlink(workflowPath);
10
+ }
11
+ return;
12
+ }
13
+ if (existing !== null && !isParadoxOwnedCollaboratorsWorkflow(existing)) {
14
+ throw new Error('Refusing to overwrite existing non-Paradox .github/workflows/collaborators.yml.');
15
+ }
16
+ if (mode === 'check')
17
+ return;
18
+ await mkdir(dirname(workflowPath), { recursive: true });
19
+ await writeFile(workflowPath, workflowYaml);
20
+ }
21
+ const generatedWorkflowMarker = '# Generated by Paradox. Do not edit manually.';
22
+ function isParadoxOwnedCollaboratorsWorkflow(content) {
23
+ return content.split(/\r?\n/, 1)[0] === generatedWorkflowMarker;
24
+ }
25
+ async function readCollaboratorsWorkflowAsync(path) {
26
+ try {
27
+ return await readFile(path, 'utf-8');
28
+ }
29
+ catch (error) {
30
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
31
+ return null;
32
+ throw error;
33
+ }
34
+ }
@@ -1,5 +1,6 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import { dirname, join } from 'node:path';
3
+ import { syncCollaboratorsWorkflowAsync } from './utils/syncCollaboratorsWorkflowAsync.js';
3
4
  import { syncFundingFileAsync } from './utils/syncFundingFileAsync.js';
4
5
  /***
5
6
  * Writes generated documentation artifacts to the configured output paths.
@@ -8,6 +9,11 @@ export async function write(result, config, runtime) {
8
9
  const root = runtime.packageRoot;
9
10
  const { outputRoot } = runtime;
10
11
  const mode = config.mode ?? 'safe';
12
+ if (mode === 'write') {
13
+ await syncCollaboratorsWorkflowAsync(root, result.collaboratorsWorkflowYaml, {
14
+ mode: 'check',
15
+ });
16
+ }
11
17
  await mkdir(outputRoot, { recursive: true });
12
18
  await writeFile(join(outputRoot, 'exports.md'), result.exportsMarkdown);
13
19
  await writeFile(join(outputRoot, 'components.md'), result.components);
@@ -26,6 +32,7 @@ export async function write(result, config, runtime) {
26
32
  }
27
33
  if (mode === 'write') {
28
34
  await writeFile(join(root, 'README.md'), result.readme);
35
+ await syncCollaboratorsWorkflowAsync(root, result.collaboratorsWorkflowYaml);
29
36
  await syncFundingFileAsync(root, result.fundingYaml);
30
37
  }
31
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/paradox",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "Deterministic documentation generator for TypeScript packages.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -54,29 +54,28 @@
54
54
  },
55
55
  "scripts": {
56
56
  "build": "tsc -p tsconfig.build.json",
57
- "changeset": "changeset",
58
- "changeset:status": "changeset status --since=origin/main",
57
+ "changeset": "ankhorage-changeset",
58
+ "changeset:status": "ankhorage-changeset status --since=origin/main",
59
59
  "docs": "bun src/cli/standalone.ts",
60
60
  "docs:bunx": "bunx @ankhorage/paradox",
61
61
  "format": "ankhorage-prettier --write .",
62
62
  "format:check": "ankhorage-prettier --check .",
63
- "knip": "ankhorage-knip",
64
63
  "lint": "ankhorage-eslint . --max-warnings=0",
65
64
  "lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
66
65
  "prepack": "bun run build",
67
66
  "test": "bun test",
68
67
  "typecheck": "bun x tsc --noEmit -p tsconfig.json",
69
- "version-packages": "changeset version"
68
+ "version-packages": "ankhorage-changeset version",
69
+ "knip:check": "ankhorage-knip"
70
70
  },
71
71
  "dependencies": {
72
72
  "ts-morph": "^28.0.0"
73
73
  },
74
74
  "devDependencies": {
75
- "@ankhorage/devtools": "^1.6.0",
76
- "@changesets/cli": "^2.31.0",
77
- "@types/bun": "^1.3.14",
75
+ "@ankhorage/devtools": "^1.14.0",
76
+ "@types/bun": "^1.4.1",
78
77
  "@types/node": "^24.13.3",
79
78
  "typescript": "^5.9.3"
80
79
  },
81
- "packageManager": "bun@1.3.14"
80
+ "packageManager": "bun@1.4.2"
82
81
  }