@rtorcato/js-tooling 2.15.0 โ†’ 2.17.0

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.
@@ -596,6 +596,114 @@ async function checkCodeQL(dir) {
596
596
  hint: 'Run `npx @rtorcato/js-tooling fix codeql` to scaffold CodeQL security scanning',
597
597
  };
598
598
  }
599
+ const TYPEDOC_CONFIGS = [
600
+ 'typedoc.json',
601
+ 'typedoc.config.js',
602
+ 'typedoc.config.mjs',
603
+ 'typedoc.config.cjs',
604
+ 'typedoc.config.ts',
605
+ ];
606
+ async function checkTypedoc(dir, pkg) {
607
+ if (pkg?.private === true) {
608
+ return {
609
+ check: 'TypeDoc',
610
+ status: 'ok',
611
+ detail: 'not applicable (package is private)',
612
+ };
613
+ }
614
+ let configFile = null;
615
+ let configContent = null;
616
+ for (const candidate of TYPEDOC_CONFIGS) {
617
+ const fp = path.join(dir, candidate);
618
+ if (await fs.pathExists(fp)) {
619
+ configFile = candidate;
620
+ try {
621
+ configContent = await fs.readFile(fp, 'utf-8');
622
+ }
623
+ catch {
624
+ configContent = '';
625
+ }
626
+ break;
627
+ }
628
+ }
629
+ const deps = {
630
+ ...(pkg?.dependencies ?? {}),
631
+ ...(pkg?.devDependencies ?? {}),
632
+ };
633
+ const hasDep = !!deps['typedoc'];
634
+ const usesPreset = configContent ? /@rtorcato\/js-tooling\/typedoc/.test(configContent) : false;
635
+ if (configFile && usesPreset) {
636
+ return {
637
+ check: 'TypeDoc',
638
+ status: 'ok',
639
+ detail: `${configFile} extends the preset`,
640
+ };
641
+ }
642
+ if (configFile && !usesPreset) {
643
+ return {
644
+ check: 'TypeDoc',
645
+ status: 'drift',
646
+ detail: `${configFile} found but does not extend @rtorcato/js-tooling/typedoc`,
647
+ hint: 'Add `"extends": ["@rtorcato/js-tooling/typedoc"]` to typedoc.json',
648
+ };
649
+ }
650
+ if (hasDep && !configFile) {
651
+ return {
652
+ check: 'TypeDoc',
653
+ status: 'drift',
654
+ detail: 'typedoc installed but no typedoc.json found',
655
+ hint: 'Run `npx @rtorcato/js-tooling fix typedoc` to scaffold typedoc.json',
656
+ };
657
+ }
658
+ return {
659
+ check: 'TypeDoc',
660
+ status: 'optional-missing',
661
+ detail: 'TypeDoc not configured',
662
+ hint: 'Run `npx @rtorcato/js-tooling fix typedoc` to scaffold API docs generation',
663
+ };
664
+ }
665
+ function isPublishableLibrary(pkg) {
666
+ if (!pkg || pkg.private === true)
667
+ return false;
668
+ return !!(pkg.exports || pkg.main || pkg.module || pkg.files);
669
+ }
670
+ async function checkAreTheTypesWrong(_dir, pkg) {
671
+ if (!isPublishableLibrary(pkg)) {
672
+ return {
673
+ check: 'are-the-types-wrong',
674
+ status: 'ok',
675
+ detail: 'not applicable (private or no published exports)',
676
+ };
677
+ }
678
+ const deps = {
679
+ ...(pkg?.dependencies ?? {}),
680
+ ...(pkg?.devDependencies ?? {}),
681
+ };
682
+ const scripts = pkg?.scripts ?? {};
683
+ const hasDep = !!deps['are-the-types-wrong'];
684
+ const hasScript = Object.values(scripts).some((s) => /\battw\b|are-the-types-wrong/.test(s));
685
+ if (hasDep && hasScript) {
686
+ return {
687
+ check: 'are-the-types-wrong',
688
+ status: 'ok',
689
+ detail: 'are-the-types-wrong installed and wired into a script',
690
+ };
691
+ }
692
+ if (hasDep) {
693
+ return {
694
+ check: 'are-the-types-wrong',
695
+ status: 'drift',
696
+ detail: 'are-the-types-wrong installed but no script runs it',
697
+ hint: 'Add `"attw": "attw --pack"` to package.json scripts and call it from your verify/CI chain',
698
+ };
699
+ }
700
+ return {
701
+ check: 'are-the-types-wrong',
702
+ status: 'optional-missing',
703
+ detail: 'are-the-types-wrong not configured',
704
+ hint: 'Run `pnpm add -D are-the-types-wrong && attw --pack` to validate TypeScript exports before publishing',
705
+ };
706
+ }
599
707
  async function checkTreeshakeSetup(dir, pkg) {
600
708
  const appCheckPath = path.join(dir, 'apps', 'treeshake-check', 'check.mjs');
601
709
  if (await fs.pathExists(appCheckPath)) {
@@ -706,6 +814,8 @@ export async function runDoctor(dir) {
706
814
  results.push(await checkCodeQL(targetDir));
707
815
  results.push(await checkGitLabCI(targetDir));
708
816
  results.push(await checkCodeowners(targetDir));
817
+ results.push(await checkTypedoc(targetDir, pkg));
818
+ results.push(await checkAreTheTypesWrong(targetDir, pkg));
709
819
  results.push(await checkTreeshakeSetup(targetDir, pkg));
710
820
  // Lockfile-driven demotion: if the lock records an intentional opt-out for a
711
821
  // check that's currently optional-missing, demote it to ok with a clear detail.
@@ -24,6 +24,8 @@ export const FIX_TARGETS = {
24
24
  'GitLab CI': 'gitlab-ci',
25
25
  lockfile: 'lockfile',
26
26
  '.js-tooling.json': 'lockfile',
27
+ 'are-the-types-wrong': 'attw',
28
+ TypeDoc: 'typedoc',
27
29
  };
28
30
  export function getFixTargetForCheck(checkName) {
29
31
  return FIX_TARGETS[checkName] ?? null;
@@ -13,6 +13,7 @@ import { composeVerifyScriptFromPkg } from '../generators/package-json.js';
13
13
  import { generateCodeQLWorkflow, generateDependabotConfig, generateRenovateConfig, } from '../generators/security.js';
14
14
  import { generateVitestConfig } from '../generators/testing.js';
15
15
  import { generateTreeshakeCheck, inferSubpathsFromExports } from '../generators/treeshake.js';
16
+ import { generateTypedocConfig, generateTypedocWorkflow } from '../generators/typedoc.js';
16
17
  import { copyPreset } from '../utils/copy-preset.js';
17
18
  import { LOCKFILE_NAME, readLockfile, updateLockfileConfig, writeLockfile, } from '../utils/lockfile.js';
18
19
  import { runDoctor } from './doctor.js';
@@ -359,6 +360,30 @@ const FIXERS = [
359
360
  return { filesWritten: written };
360
361
  },
361
362
  },
363
+ {
364
+ target: 'typedoc',
365
+ description: 'Scaffold typedoc.json extending the preset + .github/workflows/docs.yml (GitHub Pages)',
366
+ appliesTo: ['TypeDoc'],
367
+ outputs: ['typedoc.json', '.github/workflows/docs.yml'],
368
+ riskLevel: 'safe-add',
369
+ canFixDrift: true,
370
+ async run({ targetDir, pkg }) {
371
+ await generateTypedocConfig(pkg, targetDir);
372
+ const workflow = await generateTypedocWorkflow(targetDir);
373
+ const pkgPath = path.join(targetDir, 'package.json');
374
+ const filesWritten = ['typedoc.json', workflow];
375
+ if (await fs.pathExists(pkgPath)) {
376
+ const pkgData = (await fs.readJson(pkgPath));
377
+ const scripts = pkgData.scripts ?? {};
378
+ if (!scripts.docs) {
379
+ pkgData.scripts = { ...scripts, docs: 'typedoc' };
380
+ await fs.writeJson(pkgPath, pkgData, { spaces: 2 });
381
+ filesWritten.push('package.json');
382
+ }
383
+ }
384
+ return { filesWritten };
385
+ },
386
+ },
362
387
  {
363
388
  target: 'package-json',
364
389
  description: 'Add @rtorcato/js-tooling to devDependencies',
@@ -0,0 +1,40 @@
1
+ import path from 'node:path';
2
+ import fs from 'fs-extra';
3
+ const DOCS_WORKFLOW = `name: ๐Ÿ“š Docs
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ jobs:
8
+ docs:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: write
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: pnpm/action-setup@v4
15
+ - uses: actions/setup-node@v4
16
+ with:
17
+ node-version: 22
18
+ cache: pnpm
19
+ - run: pnpm install --frozen-lockfile
20
+ - run: pnpm docs
21
+ - uses: peaceiris/actions-gh-pages@v4
22
+ with:
23
+ github_token: \${{ secrets.GITHUB_TOKEN }}
24
+ publish_dir: ./docs
25
+ `;
26
+ export async function generateTypedocConfig(pkg, targetDir) {
27
+ const name = pkg?.name ?? 'My Library';
28
+ const config = {
29
+ extends: ['@rtorcato/js-tooling/typedoc'],
30
+ entryPoints: ['./src/index.ts'],
31
+ name,
32
+ };
33
+ await fs.writeJson(path.join(targetDir, 'typedoc.json'), config, { spaces: 2 });
34
+ }
35
+ export async function generateTypedocWorkflow(targetDir) {
36
+ const workflowsDir = path.join(targetDir, '.github', 'workflows');
37
+ await fs.ensureDir(workflowsDir);
38
+ await fs.writeFile(path.join(workflowsDir, 'docs.yml'), DOCS_WORKFLOW);
39
+ return '.github/workflows/docs.yml';
40
+ }
package/dist/cli/index.js CHANGED
@@ -148,6 +148,12 @@ const TOOL_CATALOG = [
148
148
  exports: ['@rtorcato/js-tooling/tsup'],
149
149
  fixTarget: null,
150
150
  },
151
+ {
152
+ name: 'TypeDoc',
153
+ description: 'API documentation generation for TypeScript library projects',
154
+ exports: ['@rtorcato/js-tooling/typedoc'],
155
+ fixTarget: 'typedoc',
156
+ },
151
157
  {
152
158
  name: 'esbuild',
153
159
  description: 'Fast JavaScript bundler configuration',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/js-tooling",
3
- "version": "2.15.0",
3
+ "version": "2.17.0",
4
4
  "description": "JavaScript and TypeScript tooling for Node.js, React, Next.js, and Vitest.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -52,6 +52,7 @@
52
52
  "tooling/prettier/index.mjs",
53
53
  "tooling/prettier/index.d.mts",
54
54
  "tooling/typescript/*.json",
55
+ "tooling/typescript/v1/*.json",
55
56
  "tooling/typescript/reset.d.ts",
56
57
  "tooling/vite/vite.config.mjs",
57
58
  "tooling/vite/vite.config.d.mts",
@@ -69,6 +70,7 @@
69
70
  "tooling/tests/ssr-safety.d.mts",
70
71
  "tooling/tsup/index.ts",
71
72
  "tooling/biome/biome.json",
73
+ "tooling/typedoc/typedoc.json",
72
74
  "tooling/semantic-release/*.mjs",
73
75
  "tooling/semantic-release/*.d.mts",
74
76
  "README.md"
@@ -113,6 +115,12 @@
113
115
  "./typescript/react": "./tooling/typescript/tsconfig.react.json",
114
116
  "./typescript/test": "./tooling/typescript/tsconfig.test.json",
115
117
  "./typescript/reset": "./tooling/typescript/reset.d.ts",
118
+ "./typescript/base@1": "./tooling/typescript/v1/tsconfig.base.json",
119
+ "./typescript/next@1": "./tooling/typescript/v1/tsconfig.next.json",
120
+ "./typescript/express@1": "./tooling/typescript/v1/tsconfig.express.json",
121
+ "./typescript/node@1": "./tooling/typescript/v1/tsconfig.node.json",
122
+ "./typescript/react@1": "./tooling/typescript/v1/tsconfig.react.json",
123
+ "./typescript/test@1": "./tooling/typescript/v1/tsconfig.test.json",
116
124
  "./vite": {
117
125
  "types": "./tooling/vite/vite.config.d.mts",
118
126
  "import": "./tooling/vite/vite.config.mjs"
@@ -135,6 +143,7 @@
135
143
  },
136
144
  "./tsup": "./tooling/tsup/index.ts",
137
145
  "./biome": "./tooling/biome/biome.json",
146
+ "./typedoc": "./tooling/typedoc/typedoc.json",
138
147
  "./semantic-release": {
139
148
  "types": "./tooling/semantic-release/index.d.mts",
140
149
  "import": "./tooling/semantic-release/index.mjs"
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "https://typedoc.org/schema.json",
3
+ "excludePrivate": true,
4
+ "excludeExternals": true,
5
+ "includeVersion": true,
6
+ "out": "docs"
7
+ }
@@ -0,0 +1,77 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ // ๐Ÿ”ง Output & Module Resolution
5
+ "moduleResolution": "bundler",
6
+ "module": "esnext",
7
+ "target": "esnext",
8
+ // "module": "esnext", //
9
+ // "moduleResolution": "node", // Prefer "bundler" if you're using Vite, esbuild, etc.
10
+ // "target": "esnext", //
11
+ "lib": ["ES2022"], // Specify library files to be included in the compilation
12
+ "rootDir": "src",
13
+ "outDir": "dist",
14
+
15
+
16
+ // ๐Ÿ” JavaScript Support
17
+ "allowJs": true, // Allow JavaScript files to be compiled
18
+ "checkJs": true, // Enable type checking on JavaScript files
19
+ "resolveJsonModule": true, // Allow importing JSON files
20
+ "isolatedModules": true, // Ensure that each file can be safely transpiled independently
21
+ "esModuleInterop": true, // Enables emit interoperability between CommonJS and ES Modules
22
+ "allowSyntheticDefaultImports": true, // recommend enabling this for smoother interop
23
+
24
+ // โš™๏ธ Module Detection
25
+ "moduleDetection": "force", // Force module detection
26
+
27
+ // ๐Ÿ“ˆ Performance
28
+ "skipLibCheck": true, // Skip type checking of declaration files
29
+ "incremental": true, // Enable incremental compilation
30
+ "disableSourceOfProjectReferenceRedirect": true, // Disable source of project reference redirect
31
+
32
+ // ๐Ÿšจ Strict Type Checking
33
+ "strict": true, // Enable all strict type checking options
34
+ "noUncheckedIndexedAccess": true, // Disallow accessing an index signature with an arbitrary key
35
+ "noImplicitAny": true, // Disallow implicit any type
36
+ "noImplicitReturns": true, // Disallow functions that do not return a value
37
+ "noImplicitOverride": true, // Ensure override keyword is used
38
+ "noImplicitThis": true, // Disallow 'this' with an implicit any type
39
+ "noPropertyAccessFromIndexSignature": true, // Disallow property access from index signature
40
+
41
+ // ๐Ÿงน Lint-Like Settings
42
+ "noUnusedLocals": true, // Disallow unused locals
43
+ "noUnusedParameters": true, // Disallow unused parameters
44
+ "noFallthroughCasesInSwitch": true, // Disallow fallthrough cases in switch statements
45
+
46
+ // ๐Ÿ“ฆ Types & Declarations
47
+ "types": ["node", "vitest"], // Specify type declaration files to be included in the compilation
48
+ "declaration": false, // Do not generate .d.ts files
49
+ "declarationMap": false, // Do not generate sourcemaps for d.ts files
50
+
51
+ // ๐Ÿ›‘ Emit Settings
52
+ "noEmit": true, // Do not emit output files
53
+ "sourceMap": true, // Generate sourcemaps for .ts files
54
+
55
+ "paths": { // Path mapping for module resolution
56
+ "~/*": ["./src/*"],
57
+ "@/*": ["./src/*"]
58
+ }
59
+ },
60
+ "include": ["src/**/*", "index.d.ts"], // Include files in the src directory and index.d.ts
61
+ "exclude": [
62
+ "node_modules",
63
+ "build",
64
+ "dist",
65
+ ".next",
66
+ ".expo",
67
+ "OLD",
68
+ "**/*.test.ts",
69
+ "**/*.test.tsx",
70
+ "**/*.spec.ts",
71
+ "**/*.spec.tsx",
72
+ ".turbo",
73
+ "out",
74
+ "not-used",
75
+ "vitest.config.ts"
76
+ ] // Exclude directories from compilation
77
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2022"], // Only include ES libs, no DOM
5
+ "types": ["node", "express", "vitest"], // Add express types for API development
6
+ },
7
+ "include": ["src", "index.d.ts"],
8
+ "exclude": ["node_modules", "dist", "build", "test", "**/*.test.ts", "**/*.spec.ts"]
9
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "preserve", // Let Next.js handle JSX transformation
5
+ "lib": ["DOM", "DOM.Iterable", "ESNext"], // Include DOM types for browser APIs
6
+ "module": "esnext", // Next.js expects ESNext modules
7
+ "moduleResolution": "bundler", // Modern module resolution for Next.js
8
+ "allowJs": true, // Allow JavaScript files
9
+ "esModuleInterop": true, // Interop for CommonJS/ESM
10
+ "types": ["react", "tailwindcss", "vitest"],
11
+ "plugins": [ { "name": "next" } ], // Next.js plugin for TypeScript
12
+ "paths": {
13
+ "~/*": ["./src/*"],
14
+ "@/*": ["./src/*"]
15
+ }
16
+ },
17
+ "include": ["next-env.d.ts", "src", "pages", "app", "components", "types", "index.d.ts"],
18
+ "exclude": ["node_modules", "dist", ".next", "build", "out"]
19
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2022"],
5
+ "types": ["node", "vitest"]
6
+ },
7
+ "include": ["src", "index.d.ts"],
8
+ "exclude": ["node_modules", "dist", "build", "test", "**/*.test.ts", "**/*.spec.ts"]
9
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx", // Use the new JSX transform for React 17+
5
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],// Include DOM types for browser APIs
6
+ "types": ["react", "react-dom", "tailwindcss", "vitest"],
7
+ "paths": {
8
+ "~/*": ["./src/*"],
9
+ "@/*": ["./src/*"]
10
+ }
11
+ },
12
+ "include": ["src", "index.d.ts", "types"],
13
+ "exclude": ["node_modules", "dist", "build", "out", "**/*.test.ts", "**/*.spec.ts"]
14
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "types": ["node", "vitest"]
6
+ },
7
+ "include": ["src", "tests", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"]
8
+ }