docs-index-keeper 1.0.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.
- package/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oleg Koval
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# docs-index-keeper
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/docs-index-keeper)
|
|
4
|
+
[](https://www.npmjs.com/package/docs-index-keeper)
|
|
5
|
+
[](https://github.com/oleg-koval/docs-index-keeper/actions/workflows/ci.yml)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
|
|
9
|
+
**Keep your docs index in sync automatically.** When you add or change Markdown files under `docs/`, a pre-commit hook (or CI step) updates the index table—no manual edits, no forgotten entries.
|
|
10
|
+
|
|
11
|
+
- **Zero config for common setups:** `docs/README.md` index, exclude `archive/`, optional warning for root-level `.md`
|
|
12
|
+
- **Composable:** Use with [Husky](https://typicode.github.io/husky/) or plain `.git/hooks/pre-commit`
|
|
13
|
+
- **CI-friendly:** `docs-index-keeper check` exits 1 if the index would change (enforce “index must be up to date”)
|
|
14
|
+
- **Portable:** Node 18+, no runtime dependencies, works with npm / pnpm / yarn / bun
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Why use it?
|
|
19
|
+
|
|
20
|
+
| Problem | What docs-index-keeper does |
|
|
21
|
+
|--------|-----------------------------|
|
|
22
|
+
| New runbooks or guides get added under `docs/` but nobody updates the index | Pre-commit (or CI) adds a row to `docs/README.md` automatically |
|
|
23
|
+
| Contributors forget to touch the index | Hook runs on staged `.md` files; index is updated and re-staged in the same commit |
|
|
24
|
+
| “Is this doc listed?” is a recurring review comment | Index stays in sync by construction |
|
|
25
|
+
| Onboarding: “Where do I find X?” | Single table in `docs/README.md` is always up to date |
|
|
26
|
+
|
|
27
|
+
**ROI:** A few minutes to run `npx docs-index-keeper init` once. After that, you avoid repeated manual index edits and review back-and-forth every time someone adds a doc. The index becomes a reliable map of your docs without extra process.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick start
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# In your repo root (with a docs/ folder and docs/README.md index table)
|
|
35
|
+
npm install -D docs-index-keeper
|
|
36
|
+
npx docs-index-keeper init
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then, when you `git add docs/my-new-guide.md` and commit, the hook will run `docs-index-keeper update` and add the new row to `docs/README.md` (and stage it).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Commands
|
|
44
|
+
|
|
45
|
+
| Command | Purpose |
|
|
46
|
+
|--------|---------|
|
|
47
|
+
| `docs-index-keeper init` | Add a pre-commit hook (Husky or `.git/hooks/pre-commit`) that runs `update` and stages the index file |
|
|
48
|
+
| `docs-index-keeper update` | Update the index from **staged** `.md` files (used by the hook) |
|
|
49
|
+
| `docs-index-keeper check` | Dry run; exit 1 if the index would change (use in CI to require an up-to-date index) |
|
|
50
|
+
| `docs-index-keeper add <path>` | Add a single file to the index (e.g. `docs-index-keeper add docs/runbook.md`) |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Config
|
|
55
|
+
|
|
56
|
+
Put config in `package.json` or in `.docs-index-keeper.json` at the repo root.
|
|
57
|
+
|
|
58
|
+
**Example (package.json):**
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"docsIndexKeeper": {
|
|
63
|
+
"indexFile": "docs/README.md",
|
|
64
|
+
"docsDir": "docs",
|
|
65
|
+
"exclude": ["README.md", "archive/"],
|
|
66
|
+
"allowedRootMd": ["README.md", "AGENTS.md", "CONTRIBUTING.md"],
|
|
67
|
+
"warnRootMd": true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- **indexFile** — Path to the Markdown file that contains the index table (default: `docs/README.md`).
|
|
73
|
+
- **docsDir** — Directory treated as “docs” (default: `docs`).
|
|
74
|
+
- **exclude** — Paths under `docsDir` that are not added (e.g. `README.md`, `archive/`).
|
|
75
|
+
- **allowedRootMd** — Root-level `.md` files that do not trigger a warning when changed.
|
|
76
|
+
- **warnRootMd** — If `true`, warn when new/changed `.md` in repo root (or `.github/`) are staged; suggests moving them to `docs/`.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Index format
|
|
81
|
+
|
|
82
|
+
The index file should contain a Markdown table with a header like `| Doc | Purpose |`. New rows are inserted before a “sentinel” row (e.g. `| [archive/](archive/) | … |`) or at the end of the table. The **title** for the link is taken from the filename; the **purpose** column uses the first `#` heading in the file, or a slugified filename.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## CI: require index up to date
|
|
87
|
+
|
|
88
|
+
```yaml
|
|
89
|
+
# .github/workflows/docs-index-check.yml
|
|
90
|
+
- run: npm ci
|
|
91
|
+
- run: npx docs-index-keeper check
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Use `DOCS_INDEX_KEEPER_STAGED` to simulate staged files (e.g. in tests or CI):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
DOCS_INDEX_KEEPER_STAGED="docs/foo.md" npx docs-index-keeper check
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Releases (maintainers)
|
|
103
|
+
|
|
104
|
+
**Publishing is done in CI/CD.** Push to `main` → CI runs tests, then [semantic-release](https://semantic-release.gitbook.io/) bumps the version (SemVer), publishes to npm, and creates a GitHub release when there are releasable commits.
|
|
105
|
+
|
|
106
|
+
**One-shot: create repo, commit, push** (no local npm publish):
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
./publish.sh
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Run from the package root. Requires `git`, `gh` (logged in), and `npm`. Overrides: `PROJECT_DIR`, `REUSE_REMOTE_REPO=true`, `COMMIT_MSG="..."`. After push, CI performs the npm publish.
|
|
113
|
+
|
|
114
|
+
- **Versioning:** Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:` → minor, `fix:` → patch, `BREAKING CHANGE:` (or `feat!:` / `fix!:`) → major.
|
|
115
|
+
- **Secrets:** In the repo’s GitHub Settings → Secrets and variables → Actions, add **NPM_TOKEN** (npm token with **Read and write** for your packages). Paste the token with **no trailing newline or space**. Use `scripts/set-npm-token-secret.sh --from-browser` after creating a token at https://www.npmjs.com/settings/~/tokens (Granular). `GITHUB_TOKEN` is provided by Actions.
|
|
116
|
+
|
|
117
|
+
**Publishing to GitHub Package Registry (instead of npm):** Use a scoped name in `package.json` (e.g. `@oleg-koval/docs-index-keeper`) and add `"publishConfig": { "registry": "https://npm.pkg.github.com" }`. In CI, set the secret to a GitHub PAT with `write:packages` and use it as `NPM_TOKEN` (semantic-release/npm uses `NPM_TOKEN` for any registry). Install from GitHub: `npm install @oleg-koval/docs-index-keeper` with `.npmrc`: `@oleg-koval:registry=https://npm.pkg.github.com`.
|
|
118
|
+
|
|
119
|
+
**Package missing on npm?** CI can create a GitHub Release (tag + notes) while `npm publish` fails. If the package still doesn’t appear on npm: (1) In the release job logs, check for `npm error code EOTP` — then set your npm account 2FA to **“Authorization only”** at https://www.npmjs.com/settings/~/account and re-run the workflow. (2) Or publish the first version once from your machine: `npm run build && npm publish --access public` (you must be logged in and 2FA satisfied). After that, CI can publish subsequent versions.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT © [Oleg Koval](https://github.com/oleg-koval)
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, chmodSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
import { update, check, getFirstHeading, parseTable, insertRows } from './index.js';
|
|
6
|
+
const root = process.cwd();
|
|
7
|
+
function printHelp() {
|
|
8
|
+
console.log(`
|
|
9
|
+
docs-index-keeper — Keep docs index in sync when new .md files are added
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
docs-index-keeper init Add pre-commit hook (husky or plain git)
|
|
13
|
+
docs-index-keeper update Update index from staged .md files (for pre-commit)
|
|
14
|
+
docs-index-keeper check Dry run; exit 1 if index would change (for CI)
|
|
15
|
+
docs-index-keeper add <path> Add a single file to the index
|
|
16
|
+
|
|
17
|
+
Config: package.json "docsIndexKeeper" or .docs-index-keeper.json
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
npx docs-index-keeper init
|
|
21
|
+
DOCS_INDEX_KEEPER_STAGED="docs/foo.md" npx docs-index-keeper check
|
|
22
|
+
`);
|
|
23
|
+
}
|
|
24
|
+
async function initAsync() {
|
|
25
|
+
const config = loadConfig(root);
|
|
26
|
+
const indexPath = config.indexFile;
|
|
27
|
+
const huskyPreCommit = `
|
|
28
|
+
# When new/changed .md under docs/ are staged, add them to ${indexPath}
|
|
29
|
+
staged_md=$(git diff --cached --name-only | grep '\\.md$' || true)
|
|
30
|
+
if [ -n "$staged_md" ]; then
|
|
31
|
+
npx docs-index-keeper update
|
|
32
|
+
git add ${indexPath} 2>/dev/null || true
|
|
33
|
+
fi
|
|
34
|
+
`.trim();
|
|
35
|
+
const huskyDir = join(root, '.husky');
|
|
36
|
+
const huskyPreCommitPath = join(huskyDir, 'pre-commit');
|
|
37
|
+
if (existsSync(huskyDir)) {
|
|
38
|
+
writeFileSync(huskyPreCommitPath, huskyPreCommit);
|
|
39
|
+
console.log('[docs-index-keeper] Updated .husky/pre-commit');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const gitHooks = join(root, '.git', 'hooks');
|
|
43
|
+
const preCommitPath = join(gitHooks, 'pre-commit');
|
|
44
|
+
if (existsSync(join(root, '.git'))) {
|
|
45
|
+
const content = `#!/bin/sh
|
|
46
|
+
${huskyPreCommit}
|
|
47
|
+
`;
|
|
48
|
+
writeFileSync(preCommitPath, content);
|
|
49
|
+
chmodSync(preCommitPath, 0o755);
|
|
50
|
+
console.log('[docs-index-keeper] Added .git/hooks/pre-commit');
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
console.log('[docs-index-keeper] Not a git repo. Run "git init" first, or install husky and re-run init.');
|
|
54
|
+
console.log(' For husky: npm i -D husky && npx husky init');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function main() {
|
|
58
|
+
const args = process.argv.slice(2);
|
|
59
|
+
const cmd = args[0];
|
|
60
|
+
if (!cmd || cmd === '--help' || cmd === '-h') {
|
|
61
|
+
printHelp();
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
const config = loadConfig(root);
|
|
65
|
+
switch (cmd) {
|
|
66
|
+
case 'init': {
|
|
67
|
+
await initAsync();
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case 'update': {
|
|
71
|
+
const result = update(root, config);
|
|
72
|
+
if (result.updated) {
|
|
73
|
+
console.log('[docs-index-keeper] Added to', config.indexFile + ':', result.added.map((r) => r.path).join(', '));
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'check': {
|
|
78
|
+
const ok = check(root, config);
|
|
79
|
+
if (!ok) {
|
|
80
|
+
console.error('[docs-index-keeper] Index is out of date. Stage new docs and run "docs-index-keeper update", or add them manually to', config.indexFile);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case 'add': {
|
|
86
|
+
const pathArg = args[1];
|
|
87
|
+
if (!pathArg) {
|
|
88
|
+
console.error('[docs-index-keeper] add requires a path. Example: docs-index-keeper add docs/my-doc.md');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const indexPath = join(root, config.indexFile);
|
|
92
|
+
if (!existsSync(indexPath)) {
|
|
93
|
+
console.error('[docs-index-keeper] Index file not found:', config.indexFile);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const rel = pathArg.startsWith(config.docsDir + '/') ? pathArg.replace(new RegExp(`^${config.docsDir}/`), '') : pathArg;
|
|
97
|
+
if (config.exclude.some((e) => rel === e || rel.startsWith(e))) {
|
|
98
|
+
console.error('[docs-index-keeper] Path is excluded:', pathArg);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
const fullPath = join(root, pathArg);
|
|
102
|
+
if (!existsSync(fullPath)) {
|
|
103
|
+
console.error('[docs-index-keeper] File not found:', pathArg);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
let readme = readFileSync(indexPath, 'utf-8');
|
|
107
|
+
const existing = parseTable(readme);
|
|
108
|
+
const existingPaths = new Set(existing.map((r) => r.path));
|
|
109
|
+
if (existingPaths.has(rel)) {
|
|
110
|
+
console.log('[docs-index-keeper] Already in index:', rel);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
const title = rel.replace(/\.md$/, '');
|
|
114
|
+
const purpose = getFirstHeading(root, pathArg) || title.replace(/-/g, ' ');
|
|
115
|
+
const toAdd = [{ path: rel, title, purpose }];
|
|
116
|
+
readme = insertRows(readme, toAdd);
|
|
117
|
+
writeFileSync(indexPath, readme);
|
|
118
|
+
console.log('[docs-index-keeper] Added to', config.indexFile + ':', rel);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
default:
|
|
122
|
+
console.error('[docs-index-keeper] Unknown command:', cmd);
|
|
123
|
+
printHelp();
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
main().catch((err) => {
|
|
128
|
+
console.error('[docs-index-keeper]', err);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AACvE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEnF,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;AAE1B,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;CAcb,CAAC,CAAA;AACF,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;IAClC,MAAM,cAAc,GAAG;6DACoC,SAAS;;;;YAI1D,SAAS;;CAEpB,CAAC,IAAI,EAAE,CAAA;IAEN,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IACrC,MAAM,kBAAkB,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;IAEvD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,aAAa,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAA;QACjD,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;QAC5D,OAAM;IACR,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5C,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;IAClD,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG;EAClB,cAAc;CACf,CAAA;QACG,aAAa,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;QACrC,SAAS,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;QAC/B,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAA;IAChE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,6FAA6F,CAAC,CAAA;QAC1G,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;IAC9D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;IAEnB,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC7C,SAAS,EAAE,CAAA;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAE/B,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,SAAS,EAAE,CAAA;YACjB,MAAK;QACP,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YACnC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YACjH,CAAC;YACD,MAAK;QACP,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YAC9B,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,OAAO,CAAC,KAAK,CAAC,sHAAsH,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;gBACvJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAK;QACP,CAAC;QACD,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACvB,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,wFAAwF,CAAC,CAAA;gBACvG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;YAC9C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3B,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;gBAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;YACvH,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,OAAO,CAAC,CAAA;gBAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YACpC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,OAAO,CAAC,CAAA;gBAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,IAAI,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;YAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;YACnC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;YAC1D,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3B,OAAO,CAAC,GAAG,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAA;gBACzD,MAAK;YACP,CAAC;YACD,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;YACtC,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;YAC1E,MAAM,KAAK,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;YAC7C,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;YAClC,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;YAChC,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,CAAC,CAAA;YACxE,MAAK;QACP,CAAC;QACD;YACE,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAA;YAC1D,SAAS,EAAE,CAAA;YACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAA;IACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface DocsIndexKeeperConfig {
|
|
2
|
+
indexFile: string;
|
|
3
|
+
docsDir: string;
|
|
4
|
+
exclude: string[];
|
|
5
|
+
allowedRootMd: string[];
|
|
6
|
+
warnRootMd: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function loadConfig(root: string): DocsIndexKeeperConfig;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,UAAU,EAAE,OAAO,CAAA;CACpB;AAUD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,CA4B9D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
const DEFAULT = {
|
|
4
|
+
indexFile: 'docs/README.md',
|
|
5
|
+
docsDir: 'docs',
|
|
6
|
+
exclude: ['README.md', 'archive/'],
|
|
7
|
+
allowedRootMd: ['README.md', 'AGENTS.md', 'CONTRIBUTING.md', 'RENDER_DEPLOY.md', 'ENV_CHECKLIST.md', 'MIGRATION.md'],
|
|
8
|
+
warnRootMd: true,
|
|
9
|
+
};
|
|
10
|
+
export function loadConfig(root) {
|
|
11
|
+
const pkgPath = join(root, 'package.json');
|
|
12
|
+
if (existsSync(pkgPath)) {
|
|
13
|
+
try {
|
|
14
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
15
|
+
const cfg = pkg.docsIndexKeeper;
|
|
16
|
+
if (cfg && typeof cfg === 'object') {
|
|
17
|
+
return { ...DEFAULT, ...cfg };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// fall through to defaults
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const rcPaths = ['.docs-index-keeper.json', '.docsindexkeeperrc.json'];
|
|
25
|
+
for (const rc of rcPaths) {
|
|
26
|
+
const p = join(root, rc);
|
|
27
|
+
if (existsSync(p)) {
|
|
28
|
+
try {
|
|
29
|
+
const cfg = JSON.parse(readFileSync(p, 'utf-8'));
|
|
30
|
+
return { ...DEFAULT, ...cfg };
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { ...DEFAULT };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAU3B,MAAM,OAAO,GAA0B;IACrC,SAAS,EAAE,gBAAgB;IAC3B,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC;IAClC,aAAa,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,CAAC;IACpH,UAAU,EAAE,IAAI;CACjB,CAAA;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;IAC1C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAA4B,CAAA;YACjF,MAAM,GAAG,GAAG,GAAG,CAAC,eAA6D,CAAA;YAC7E,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACnC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,GAAG,EAAE,CAAA;YAC/B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,yBAAyB,EAAE,yBAAyB,CAAC,CAAA;IACtE,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QACxB,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAmC,CAAA;gBAClF,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,GAAG,EAAE,CAAA;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,MAAK;YACP,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,OAAO,EAAE,CAAA;AACvB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DocsIndexKeeperConfig } from './config.js';
|
|
2
|
+
export interface IndexRow {
|
|
3
|
+
title: string;
|
|
4
|
+
path: string;
|
|
5
|
+
purpose?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function getStagedMdFiles(stagedOverride?: string): string[];
|
|
8
|
+
export declare function getStagedDocs(staged: string[], config: DocsIndexKeeperConfig): string[];
|
|
9
|
+
export declare function getFirstHeading(root: string, filePath: string): string | null;
|
|
10
|
+
export declare function parseTable(readmeContent: string): IndexRow[];
|
|
11
|
+
export declare function warnRootMd(staged: string[], config: DocsIndexKeeperConfig): void;
|
|
12
|
+
export declare function computeNewRows(root: string, stagedDocs: string[], existingPaths: Set<string>, config: DocsIndexKeeperConfig): IndexRow[];
|
|
13
|
+
export declare function insertRows(readme: string, newRows: IndexRow[], sentinelPattern?: string): string;
|
|
14
|
+
export interface UpdateResult {
|
|
15
|
+
updated: boolean;
|
|
16
|
+
added: IndexRow[];
|
|
17
|
+
}
|
|
18
|
+
export declare function update(root: string, config: DocsIndexKeeperConfig, stagedOverride?: string): UpdateResult;
|
|
19
|
+
export declare function check(root: string, config: DocsIndexKeeperConfig, stagedOverride?: string): boolean;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAExD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,gBAAgB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAclE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAQvF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM7E;AAED,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,EAAE,CAc5D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAchF;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAAE,EACpB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,QAAQ,EAAE,CAYZ;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,eAAe,SAAiB,GAAG,MAAM,CAMxG;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,QAAQ,EAAE,CAAA;CAClB;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,qBAAqB,EAC7B,cAAc,CAAC,EAAE,MAAM,GACtB,YAAY,CAsBd;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAenG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
export function getStagedMdFiles(stagedOverride) {
|
|
5
|
+
const envOverride = process.env.DOCS_INDEX_KEEPER_STAGED;
|
|
6
|
+
if (stagedOverride ?? envOverride) {
|
|
7
|
+
const raw = (stagedOverride ?? envOverride);
|
|
8
|
+
return raw
|
|
9
|
+
.split('\n')
|
|
10
|
+
.map((s) => s.trim())
|
|
11
|
+
.filter((s) => s.endsWith('.md'));
|
|
12
|
+
}
|
|
13
|
+
const out = execSync('git diff --cached --name-only', { encoding: 'utf-8' });
|
|
14
|
+
return out
|
|
15
|
+
.split('\n')
|
|
16
|
+
.map((s) => s.trim())
|
|
17
|
+
.filter((s) => s.endsWith('.md'));
|
|
18
|
+
}
|
|
19
|
+
export function getStagedDocs(staged, config) {
|
|
20
|
+
const docsPrefix = config.docsDir + '/';
|
|
21
|
+
return staged.filter((p) => {
|
|
22
|
+
if (!p.startsWith(docsPrefix))
|
|
23
|
+
return false;
|
|
24
|
+
const rel = p.slice(docsPrefix.length);
|
|
25
|
+
if (config.exclude.some((e) => rel === e || rel.startsWith(e)))
|
|
26
|
+
return false;
|
|
27
|
+
return true;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export function getFirstHeading(root, filePath) {
|
|
31
|
+
const full = join(root, filePath);
|
|
32
|
+
if (!existsSync(full))
|
|
33
|
+
return null;
|
|
34
|
+
const content = readFileSync(full, 'utf-8');
|
|
35
|
+
const match = content.match(/^#+\s+(.+)$/m);
|
|
36
|
+
return match ? match[1].trim() : null;
|
|
37
|
+
}
|
|
38
|
+
export function parseTable(readmeContent) {
|
|
39
|
+
const lines = readmeContent.split('\n');
|
|
40
|
+
const rows = [];
|
|
41
|
+
let inTable = false;
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
if (line.startsWith('|') && line.includes('|')) {
|
|
44
|
+
inTable = true;
|
|
45
|
+
const linkMatch = line.match(/\|\s*\[([^\]]+)\]\(([^)]+)\)\s*\|/);
|
|
46
|
+
if (linkMatch)
|
|
47
|
+
rows.push({ title: linkMatch[1], path: linkMatch[2] });
|
|
48
|
+
}
|
|
49
|
+
else if (inTable && !line.trim().startsWith('|')) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return rows;
|
|
54
|
+
}
|
|
55
|
+
export function warnRootMd(staged, config) {
|
|
56
|
+
if (!config.warnRootMd)
|
|
57
|
+
return;
|
|
58
|
+
const rootMd = staged.filter((p) => !p.includes('/') || p.startsWith('.github/'));
|
|
59
|
+
const inRoot = rootMd.filter((p) => {
|
|
60
|
+
const base = p.replace(/^.*\//, '');
|
|
61
|
+
return !config.allowedRootMd.includes(base);
|
|
62
|
+
});
|
|
63
|
+
if (inRoot.length) {
|
|
64
|
+
console.warn('[docs-index-keeper] New/changed .md in root or .github:', inRoot.join(', '), '\nConsider moving to docs/ and they will be added to the index.');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function computeNewRows(root, stagedDocs, existingPaths, config) {
|
|
68
|
+
const toAdd = [];
|
|
69
|
+
for (const p of stagedDocs) {
|
|
70
|
+
const path = p.replace(new RegExp(`^${config.docsDir}/`), '');
|
|
71
|
+
if (existingPaths.has(path))
|
|
72
|
+
continue;
|
|
73
|
+
const titleFromPath = path.replace(/\.md$/, '').replace(/-/g, ' ');
|
|
74
|
+
const purpose = getFirstHeading(root, p) || titleFromPath;
|
|
75
|
+
const title = path.replace(/\.md$/, '');
|
|
76
|
+
toAdd.push({ path, title, purpose });
|
|
77
|
+
existingPaths.add(path);
|
|
78
|
+
}
|
|
79
|
+
return toAdd;
|
|
80
|
+
}
|
|
81
|
+
export function insertRows(readme, newRows, sentinelPattern = '| [archive/]') {
|
|
82
|
+
const newLines = newRows.map(({ path, title, purpose }) => `| [${title}](${path}) | ${purpose ?? title} |`);
|
|
83
|
+
let insertIdx = readme.indexOf(sentinelPattern);
|
|
84
|
+
if (insertIdx === -1)
|
|
85
|
+
insertIdx = readme.indexOf('\n\n', readme.indexOf('| Doc | Purpose |'));
|
|
86
|
+
if (insertIdx === -1)
|
|
87
|
+
insertIdx = readme.length;
|
|
88
|
+
return readme.slice(0, insertIdx) + newLines.join('\n') + '\n' + readme.slice(insertIdx);
|
|
89
|
+
}
|
|
90
|
+
export function update(root, config, stagedOverride) {
|
|
91
|
+
const indexPath = join(root, config.indexFile);
|
|
92
|
+
const staged = getStagedMdFiles(stagedOverride);
|
|
93
|
+
if (!staged.length)
|
|
94
|
+
return { updated: false, added: [] };
|
|
95
|
+
warnRootMd(staged, config);
|
|
96
|
+
const stagedDocs = getStagedDocs(staged, config);
|
|
97
|
+
if (!stagedDocs.length)
|
|
98
|
+
return { updated: false, added: [] };
|
|
99
|
+
if (!existsSync(indexPath))
|
|
100
|
+
return { updated: false, added: [] };
|
|
101
|
+
let readme = readFileSync(indexPath, 'utf-8');
|
|
102
|
+
const existing = parseTable(readme);
|
|
103
|
+
const existingPaths = new Set(existing.map((r) => r.path));
|
|
104
|
+
const toAdd = computeNewRows(root, stagedDocs, existingPaths, config);
|
|
105
|
+
if (!toAdd.length)
|
|
106
|
+
return { updated: false, added: [] };
|
|
107
|
+
readme = insertRows(readme, toAdd);
|
|
108
|
+
writeFileSync(indexPath, readme);
|
|
109
|
+
return { updated: true, added: toAdd };
|
|
110
|
+
}
|
|
111
|
+
export function check(root, config, stagedOverride) {
|
|
112
|
+
const indexPath = join(root, config.indexFile);
|
|
113
|
+
const staged = getStagedMdFiles(stagedOverride);
|
|
114
|
+
const stagedDocs = getStagedDocs(staged, config);
|
|
115
|
+
if (!stagedDocs.length || !existsSync(indexPath))
|
|
116
|
+
return true;
|
|
117
|
+
const readme = readFileSync(indexPath, 'utf-8');
|
|
118
|
+
const existing = parseTable(readme);
|
|
119
|
+
const existingPaths = new Set(existing.map((r) => r.path));
|
|
120
|
+
for (const p of stagedDocs) {
|
|
121
|
+
const path = p.replace(new RegExp(`^${config.docsDir}/`), '');
|
|
122
|
+
if (!existingPaths.has(path))
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "docs-index-keeper",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Keep your docs/README.md index in sync automatically. When you add or change Markdown files under docs/, a pre-commit hook or CI step updates the index table—no manual edits, no forgotten entries.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"docs-index-keeper": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"prepare": "npm run build",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"lint": "eslint src --ext .ts",
|
|
20
|
+
"check": "npm run build && npm run test"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"docs",
|
|
27
|
+
"documentation",
|
|
28
|
+
"markdown",
|
|
29
|
+
"index",
|
|
30
|
+
"readme",
|
|
31
|
+
"pre-commit",
|
|
32
|
+
"husky",
|
|
33
|
+
"git-hooks",
|
|
34
|
+
"cli",
|
|
35
|
+
"automation",
|
|
36
|
+
"docs-index",
|
|
37
|
+
"doc-index",
|
|
38
|
+
"runbook",
|
|
39
|
+
"knowledge-base"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"author": "Oleg Koval <oleg-koval@users.noreply.github.com> (https://github.com/oleg-koval)",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/oleg-koval/docs-index-keeper.git"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/oleg-koval/docs-index-keeper#readme",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/oleg-koval/docs-index-keeper/issues"
|
|
50
|
+
},
|
|
51
|
+
"release": {
|
|
52
|
+
"branches": ["main"],
|
|
53
|
+
"plugins": [
|
|
54
|
+
"@semantic-release/commit-analyzer",
|
|
55
|
+
"@semantic-release/release-notes-generator",
|
|
56
|
+
"@semantic-release/npm",
|
|
57
|
+
"@semantic-release/github"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@semantic-release/github": "^11.0.0",
|
|
62
|
+
"@semantic-release/npm": "^12.0.0",
|
|
63
|
+
"@types/node": "^22.10.0",
|
|
64
|
+
"eslint": "^9.16.0",
|
|
65
|
+
"semantic-release": "^24.0.0",
|
|
66
|
+
"typescript": "^5.7.2",
|
|
67
|
+
"vitest": "^2.1.6"
|
|
68
|
+
}
|
|
69
|
+
}
|