@jackdbd/zod-to-doc
Advanced tools
Comparing version 1.0.1 to 1.0.2
# CHANGELOG | ||
## [1.0.2](https://github.com/jackdbd/zod-to-doc/compare/v1.0.1...v1.0.2) (2024-02-02) | ||
## [1.0.1](https://github.com/jackdbd/zod-to-doc/compare/v1.0.0...v1.0.1) (2024-02-02) | ||
@@ -7,5 +9,4 @@ | ||
### Features | ||
* first release ([575b9b7](https://github.com/jackdbd/zod-to-doc/commit/575b9b7da7fd3f8395ce871e0ecb0b81e3054ed4)) |
#!/usr/bin/env node | ||
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
import makeDebug from 'debug'; | ||
import defDebug from 'debug'; | ||
import yargs from 'yargs/yargs'; | ||
import { markdownTableFromZodSchema } from './lib.js'; | ||
import { CLI_NAME, DEBUG_PREFIX } from './constants.js'; | ||
const debug = makeDebug(`${DEBUG_PREFIX}:cli`); | ||
const debug = defDebug(`${DEBUG_PREFIX}:cli`); | ||
// https://github.com/thi-ng/umbrella/blob/develop/tools/src/readme.ts | ||
@@ -59,4 +59,4 @@ // https://github.com/thi-ng/umbrella/blob/develop/tools/bin/readme.mjs | ||
} | ||
const ts_module = await import(module_filepath); | ||
const schema = ts_module[argv.schema]; | ||
const es_module = await import(module_filepath); | ||
const schema = es_module[argv.schema]; | ||
debug(`import { ${argv.schema} } from '${module_filepath}'`); | ||
@@ -63,0 +63,0 @@ let title = ''; |
@@ -6,6 +6,6 @@ /** | ||
*/ | ||
import makeDebug from 'debug'; | ||
import defDebug from 'debug'; | ||
import { z } from 'zod'; | ||
import { DEBUG_PREFIX } from './constants.js'; | ||
const debug = makeDebug(`${DEBUG_PREFIX}:lib`); | ||
const debug = defDebug(`${DEBUG_PREFIX}:lib`); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -12,0 +12,0 @@ export const defaultZodValue = (value) => { |
{ | ||
"name": "@jackdbd/zod-to-doc", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Inject your [Zod](https://github.com/colinhacks/zod) schemas into your docs.", | ||
@@ -61,5 +61,4 @@ "author": { | ||
"dev": "run-p 'build:ts:watch' 'test:watch'", | ||
"example": "run-s 'example:car' 'example:car_tire'", | ||
"example": "run-s 'example:car'", | ||
"example:car": "./dist/cli.js --module ./fixtures/schemas.mjs --schema car --placeholder car-table --title '#### Car table' --filepath tpl.readme.md", | ||
"example:car_tire": "./dist/cli.js --module ./fixtures/schemas.mjs --schema car_tire --placeholder car-tire-table --title '#### Car tire table' --filepath tpl.readme.md", | ||
"docs": "run-s 'docs:ae' 'docs:ad' 'docs:typedoc' 'docs:readme' --print-label", | ||
@@ -66,0 +65,0 @@ "docs:ae": "api-extractor run --config ./config/api-extractor.json --verbose", |
# Zod to Doc | ||
[![npm version](https://badge.fury.io/js/@jackdbd%2Fzod-to-doc.svg)](https://badge.fury.io/js/@jackdbd%2Fzod-to-doc) | ||
[![npm version](https://badge.fury.io/js/@jackdbd%2Fzod-to-doc.svg)](https://www.npmjs.com/package/@jackdbd/zod-to-doc) | ||
[![install size](https://packagephobia.com/badge?p=@jackdbd/zod-to-doc)](https://packagephobia.com/result?p=@jackdbd/zod-to-doc) | ||
[![CodeCov badge](https://codecov.io/gh/jackdbd/zod-to-doc/graph/badge.svg?token=9jddzo5Dt3)](https://codecov.io/gh/jackdbd/zod-to-doc) | ||
[![CI](https://github.com/jackdbd/zod-to-doc/actions/workflows/ci.yaml/badge.svg)](https://github.com/jackdbd/zod-to-doc/actions/workflows/ci.yaml) | ||
[![Release to npmjs.com](https://github.com/jackdbd/zod-to-doc/actions/workflows/release-to-npmjs.yaml/badge.svg)](https://github.com/jackdbd/zod-to-doc/actions/workflows/release-to-npmjs.yaml) | ||
[![codecov](https://codecov.io/gh/jackdbd/zod-to-doc/graph/badge.svg?token=9jddzo5Dt3)](https://codecov.io/gh/jackdbd/zod-to-doc) | ||
[![Socket Badge](https://socket.dev/api/badge/npm/package/@jackdbd/zod-to-doc)](https://socket.dev/npm/package/@jackdbd/zod-to-doc) | ||
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org) | ||
[![install size](https://packagephobia.com/badge?p=@jackdbd/zod-to-doc)](https://packagephobia.com/result?p=@jackdbd/zod-to-doc) | ||
[![Socket Badge](https://socket.dev/api/badge/npm/package/@jackdbd/zod-to-doc)](https://socket.dev/npm/package/@jackdbd/zod-to-doc) | ||
- [About](#about) | ||
Inject your [Zod](https://github.com/colinhacks/zod) schemas into your docs. | ||
- [Installation](#installation) | ||
- [Docs](#docs) | ||
- [Examples](#examples) | ||
- [Car](#car) | ||
- [Usage as a CLI](#usage-as-a-cli) | ||
- [Car table](#car-table) | ||
- [Car tire](#car-tire) | ||
- [Usage as a library](#usage-as-a-library) | ||
- [Car tire table](#car-tire-table) | ||
@@ -22,8 +23,3 @@ - [Troubleshooting](#troubleshooting) | ||
- [License](#license) | ||
- [Development](#development) | ||
## About | ||
Inject your [Zod](https://github.com/colinhacks/zod) schemas into your docs. | ||
## Installation | ||
@@ -37,3 +33,3 @@ | ||
[Docs generated by TypeDoc](https://@jackdbd.github.io/zod-to-doc/index.html) | ||
[Docs generated by TypeDoc](https://jackdbd.github.io/zod-to-doc/index.html) | ||
@@ -48,7 +44,7 @@ > :open_book: **API Docs** | ||
Here are some tables generated by running `ztd` against a couple of Zod schemas exported by [fixtures/schemas.mjs](./fixtures/schemas.mjs). | ||
Here are some tables generated using a couple of Zod schemas exported by [fixtures/schemas.mjs](./fixtures/schemas.mjs). | ||
### Car | ||
### Usage as a CLI | ||
Command: | ||
Zod to Doc can be used as a CLI. For example, if you run this command and have the correct placeholder in your document (see this `README.md` in raw mode): | ||
@@ -62,3 +58,3 @@ ```sh | ||
Output: | ||
You get this output: | ||
@@ -80,26 +76,6 @@ <!-- BEGIN car-table --> | ||
<!-- | Key | Default | Description | | ||
|---|---|---| | ||
| `manufacturer` | `undefined` | Car manufacturer | | ||
| `model` | `undefined` | Car model | | ||
| `tires` | `undefined` | Array of 4 elements | | ||
| `year` | `undefined` | Year in which the car was manufactured | | ||
--> | ||
### Usage as a library | ||
### Car tire | ||
Zod to Doc can also be used as a library. For example, the [readme.ts](./readme.ts) file in this repository uses `markdownTableFromZodSchema` to replace a mustache-style placeholder with this markdown table: | ||
Command: | ||
```sh | ||
ztd --module ./fixtures/schemas.mjs \ | ||
--schema car_tire \ | ||
--placeholder car-tire-table \ | ||
--title '#### Car tire table' | ||
``` | ||
Output: | ||
<!-- BEGIN car-tire-table --> | ||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN ztd TO UPDATE --> | ||
#### Car tire table | ||
@@ -109,17 +85,10 @@ | ||
|---|---|---| | ||
| `manufacturer` | `undefined` | Car tire manufacturer | | ||
| `pressure` | `30` | Car tire pressure in PSI | | ||
<!-- END car-tire-table --> | ||
| `manufacturer` | `undefined` | Car manufacturer | | ||
| `model` | `undefined` | Car model | | ||
| `tires` | `undefined` | Array of 4 elements | | ||
| `year` | `undefined` | Year in which the car was manufactured | | ||
<!-- Same example, but using [transclude](https://github.com/thi-ng/umbrella/tree/main/packages/transclude). --> | ||
<!-- | Key | Default | Description | | ||
|---|---|---| | ||
| `manufacturer` | `undefined` | Car tire manufacturer | | ||
| `pressure` | `30` | Car tire pressure in PSI | | ||
--> | ||
## Troubleshooting | ||
This plugin uses the [debug](https://github.com/debug-js/debug) library for logging. | ||
This package uses the [debug](https://github.com/debug-js/debug) library for logging. | ||
You can control what's logged using the `DEBUG` environment variable. | ||
@@ -142,16 +111,2 @@ | ||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) | ||
## Development | ||
Launch both the TypeScript compiler and the [Node.js test runner](https://nodejs.org/api/test.html) in watch mode: | ||
```sh | ||
npm run dev | ||
``` | ||
Whenever you change the public API of this project, you need to run api-extractor with the `--local` flag: | ||
```sh | ||
npx api-extractor run --config ./config/api-extractor.json --verbose --local | ||
``` | ||
[MIT License](https://spdx.org/licenses/MIT.html) |
289
readme.ts
import { readFileSync, writeFileSync } from 'node:fs' | ||
import { execSync } from 'node:child_process' | ||
import { execPath } from 'node:process' | ||
import { join, resolve } from 'node:path' | ||
import { toc, compactEmptyLines, transcludeFile } from '@thi.ng/transclude' | ||
import { join } from 'node:path' | ||
import { z } from 'zod' | ||
import { | ||
licenseLink, | ||
compactEmptyLines, | ||
image, | ||
link, | ||
toc, | ||
transcludeFile, | ||
preincludeFile | ||
} from '@thi.ng/transclude' | ||
import defDebug from 'debug' | ||
import { DEBUG_PREFIX } from './src/constants.js' | ||
// import { markdownTableFromZodSchema } from './src/lib.js' | ||
import { markdownTableFromZodSchema } from './src/lib.js' | ||
import { car, car_tire } from './fixtures/schemas.mjs' | ||
const package_json = JSON.parse(readFileSync('package.json', 'utf-8')) | ||
const debug = defDebug(`${DEBUG_PREFIX}:readme`) | ||
const author = package_json.author | ||
const pkg_name = package_json.name as string | ||
const [npm_scope, unscoped_pkg_name] = pkg_name.split('/') | ||
const github_username = npm_scope as string | ||
const pkg_root = '.' | ||
const lib_js = resolve(pkg_root, 'dist', 'lib.js') | ||
const schemas_mjs = resolve(pkg_root, 'fixtures', 'schemas.mjs') | ||
interface CalloutConfig { | ||
// https://github.com/ikatyang/emoji-cheat-sheet/blob/master/README.md#table-of-contents | ||
// https://github.com/ikatyang/emoji-cheat-sheet | ||
// https://gist.github.com/rxaviers/7360908 | ||
emoji: string | ||
@@ -37,136 +35,161 @@ title: string | ||
const readme = transcludeFile(join(pkg_root, 'tpl.readme.md'), { | ||
user: author, | ||
templates: { | ||
'pkg.deps': () => { | ||
const entries = Object.entries(package_json.dependencies) | ||
const zodToTable = (schema: z.AnyZodObject) => { | ||
const { error, value } = markdownTableFromZodSchema(schema) | ||
if (error) { | ||
return callout({ | ||
emoji: ':warning:', | ||
title: `Could not generate table from Zod schema: ${error.name}`, | ||
message: error.message | ||
}) | ||
} else { | ||
return value | ||
} | ||
} | ||
const links = entries.map( | ||
([name]) => `[${name}](https://www.npmjs.com/package/${name})` | ||
) | ||
const list = links.map((link) => `- ${link}`).join('\n') | ||
const main = async () => { | ||
const pkg_root = '.' | ||
const outdoc = 'README.md' | ||
const pkg = JSON.parse(readFileSync(join(pkg_root, 'package.json'), 'utf-8')) | ||
const rows = entries.map( | ||
([name, version]) => | ||
`| [${name}](https://www.npmjs.com/package/${name}) | \`${version}\` |` | ||
) | ||
const table = [`| Package | Version |`, '|---|---|', rows].join('\n') | ||
const author = pkg.author | ||
const pkg_name = pkg.name as string | ||
const [npm_scope, unscoped_pkg_name] = pkg_name.split('/') | ||
const github_username = npm_scope.replace('@', '') | ||
return [`## Dependencies`, '\n\n', table].join('') | ||
}, | ||
const transcluded = transcludeFile(join(pkg_root, 'tpl.readme.md'), { | ||
pre: [preincludeFile], | ||
post: [toc(), compactEmptyLines], | ||
user: author, | ||
templates: { | ||
badges: () => { | ||
const npm_package = link( | ||
image( | ||
`https://badge.fury.io/js/${npm_scope}%2F${unscoped_pkg_name}.svg`, | ||
'npm version' | ||
), | ||
`https://www.npmjs.com/package/${npm_scope}/${unscoped_pkg_name}` | ||
) | ||
'pkg.about': () => `## About\n\n${package_json.description}`, | ||
const install_size = link( | ||
image( | ||
`https://packagephobia.com/badge?p=${npm_scope}/${unscoped_pkg_name}`, | ||
'install size' | ||
), | ||
`https://packagephobia.com/result?p=${npm_scope}/${unscoped_pkg_name}` | ||
) | ||
'pkg.docs': () => { | ||
const lines = [ | ||
`## Docs`, | ||
'\n\n', | ||
`[Docs generated by TypeDoc](https://${github_username}.github.io/${unscoped_pkg_name}/index.html)`, | ||
'\n\n', | ||
callout({ | ||
emoji: ':open_book:', // open_book, page_facing_up, page_with_curl | ||
title: 'API Docs', | ||
message: `This project uses [API Extractor](https://api-extractor.com/) and [api-documenter markdown](https://api-extractor.com/pages/commands/api-documenter_markdown/) to generate a bunch of markdown files and a \`.d.ts\` rollup file containing all type definitions consolidated into a single file. I don't find this \`.d.ts\` rollup file particularly useful. On the other hand, the markdown files that api-documenter generates are quite handy when reviewing the public API of this project.\n\n*See [Generating API docs](https://api-extractor.com/pages/setup/generating_docs/) if you want to know more*.` | ||
}) | ||
] | ||
return lines.join('') | ||
}, | ||
const socket = link( | ||
image( | ||
`https://socket.dev/api/badge/npm/package/${npm_scope}/${unscoped_pkg_name}`, | ||
'Socket Badge' | ||
), | ||
`https://socket.dev/npm/package/${npm_scope}/${unscoped_pkg_name}` | ||
) | ||
'pkg.installation': () => { | ||
const lines = [ | ||
`## Installation`, | ||
'\n\n', | ||
`\`\`\`sh`, | ||
'\n', | ||
`npm install --save-dev ${pkg_name}`, | ||
'\n', | ||
`\`\`\`` | ||
] | ||
return lines.join('') | ||
}, | ||
const ci_workflow = link( | ||
image( | ||
`https://github.com/${github_username}/${unscoped_pkg_name}/actions/workflows/ci.yaml/badge.svg`, | ||
'CI' | ||
), | ||
`https://github.com/${github_username}/${unscoped_pkg_name}/actions/workflows/ci.yaml` | ||
) | ||
'pkg.license': ({ user }) => { | ||
// https://gist.github.com/lukas-h/2a5d00690736b4c3a7ba | ||
const lines = [`## License`, '\n\n'] | ||
if (package_json.license === 'MIT') { | ||
lines.push( | ||
`[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)` | ||
const release_workflow = link( | ||
image( | ||
`https://github.com/${github_username}/${unscoped_pkg_name}/actions/workflows/release-to-npmjs.yaml/badge.svg`, | ||
'Release to npmjs.com' | ||
), | ||
`https://github.com/${github_username}/${unscoped_pkg_name}/actions/workflows/release-to-npmjs.yaml` | ||
) | ||
} else { | ||
throw new Error(`This license is not yet implemented`) | ||
} | ||
// lines.push(`\n\n`) | ||
// lines.push(`[${user.name}](${user.url})`) | ||
const codecov = link( | ||
image( | ||
`https://codecov.io/gh/${github_username}/${unscoped_pkg_name}/graph/badge.svg?token=9jddzo5Dt3`, | ||
'CodeCov badge' | ||
), | ||
`https://codecov.io/gh/${github_username}/${unscoped_pkg_name}` | ||
) | ||
return lines.join('') | ||
}, | ||
const conventional_commits = link( | ||
image( | ||
`https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white`, | ||
'Conventional Commits' | ||
), | ||
'https://conventionalcommits.org' | ||
) | ||
'table.car': () => { | ||
const schema_name = 'car' | ||
const esm = ` | ||
import { ${schema_name} as schema } from '${schemas_mjs}' | ||
import { markdownTableFromZodSchema } from '${lib_js}' | ||
return [ | ||
npm_package, | ||
install_size, | ||
codecov, | ||
ci_workflow, | ||
release_workflow, | ||
socket, | ||
conventional_commits | ||
].join('\n') | ||
}, | ||
const { error, value: table } = markdownTableFromZodSchema(schema) | ||
console.log(table) // send to stdout | ||
` | ||
'pkg.deps': (ctx) => { | ||
const entries = Object.entries(pkg.dependencies) | ||
try { | ||
const res = execSync(`${execPath} --input-type=module --eval "${esm}"`) | ||
return res.toString() | ||
} catch (err) { | ||
return callout({ | ||
emoji: ':warning:', | ||
title: `Could not generate table from Zod schema \`${schema_name}\``, | ||
message: err.stderr.toString() | ||
}) | ||
} | ||
}, | ||
const rows = entries.map( | ||
([name, version]) => | ||
`| ${link(name, `https://www.npmjs.com/package/${name}`)} | \`${version}\` |` | ||
) | ||
const table = [`| Package | Version |`, '|---|---|', rows].join('\n') | ||
'table.tire': () => { | ||
const schema_name = 'car_tire' | ||
const esm = ` | ||
import { ${schema_name} as schema } from '${schemas_mjs}' | ||
import { markdownTableFromZodSchema } from '${lib_js}' | ||
return [`## Dependencies`, '\n\n', table].join('') | ||
}, | ||
const { error, value: table } = markdownTableFromZodSchema(schema) | ||
console.log(table) // send to stdout | ||
` | ||
'pkg.description': pkg.description, | ||
try { | ||
const res = execSync(`${execPath} --input-type=module --eval "${esm}"`) | ||
return res.toString() | ||
} catch (err) { | ||
return callout({ | ||
emoji: ':warning:', | ||
title: `Could not generate table from Zod schema \`${schema_name}\``, | ||
message: err.stderr.toString() | ||
}) | ||
} | ||
}, | ||
'pkg.docs': () => { | ||
const lines = [ | ||
`## Docs`, | ||
'\n\n', | ||
`[Docs generated by TypeDoc](https://${github_username}.github.io/${unscoped_pkg_name}/index.html)`, | ||
'\n\n', | ||
callout({ | ||
emoji: ':open_book:', // open_book, page_facing_up, page_with_curl | ||
title: 'API Docs', | ||
message: `This project uses [API Extractor](https://api-extractor.com/) and [api-documenter markdown](https://api-extractor.com/pages/commands/api-documenter_markdown/) to generate a bunch of markdown files and a \`.d.ts\` rollup file containing all type definitions consolidated into a single file. I don't find this \`.d.ts\` rollup file particularly useful. On the other hand, the markdown files that api-documenter generates are quite handy when reviewing the public API of this project.\n\n*See [Generating API docs](https://api-extractor.com/pages/setup/generating_docs/) if you want to know more*.` | ||
}) | ||
] | ||
return lines.join('') | ||
}, | ||
troubleshooting: () => { | ||
const lines = [ | ||
`## Troubleshooting`, | ||
'\n\n', | ||
`This plugin uses the [debug](https://github.com/debug-js/debug) library for logging.`, | ||
`You can control what's logged using the \`DEBUG\` environment variable.`, | ||
'\n', | ||
`For example, if you set your environment variables in a \`.envrc\` file, you can do:`, | ||
'\n', | ||
`\`\`\`sh`, | ||
`# print all logging statements`, | ||
`export DEBUG=${DEBUG_PREFIX}:*`, | ||
`\`\`\`` | ||
] | ||
return lines.join('\n') | ||
'pkg.installation': () => { | ||
const lines = [ | ||
`## Installation`, | ||
'\n\n', | ||
`\`\`\`sh`, | ||
'\n', | ||
`npm install --save-dev ${pkg_name}`, | ||
'\n', | ||
`\`\`\`` | ||
] | ||
return lines.join('') | ||
}, | ||
'pkg.license': ({ user }) => { | ||
// © 2022 - 2024 Karsten Schmidt | ||
// https://gist.github.com/lukas-h/2a5d00690736b4c3a7ba | ||
const lines = [`## License`, '\n\n', licenseLink(pkg.license)] | ||
// lines.push(`\n\n`) | ||
// lines.push(`[${user.name}](${user.url})`) | ||
return lines.join('') | ||
}, | ||
'table.car': zodToTable(car), | ||
'table.car_tire': zodToTable(car_tire) | ||
} | ||
}, | ||
post: [toc(), compactEmptyLines] | ||
}) | ||
}) | ||
// console.log('=== README.md BEGIN ===') | ||
// console.log(readme.src) | ||
// console.log('=== README.md END ===') | ||
writeFileSync(join(pkg_root, 'README.md'), readme.src) | ||
// console.log(`=== ${outdoc} BEGIN ===`) | ||
// console.log(transcluded.src) | ||
// console.log(`=== ${outdoc} END ===`) | ||
writeFileSync(join(pkg_root, outdoc), transcluded.src) | ||
debug(`${outdoc} updated`) | ||
} | ||
await main() |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
453
33154
106