/ utils / genUpdateInfoHtml.js
genUpdateInfoHtml.js
 1  /**
 2   * @file generates release notes for auto-updates
 3   *
 4   * Usage:
 5   *
 6   * 1. generate changelog during bump:
 7   *      node ./utils/genUpdateInfoHtml.js
 8   *
 9   * 2. generate changelog for a specific version:
10   *      node ./utils/genUpdateInfoHtml.js -v 0.1.26 --range v0.1.25..v0.1.26
11   */
12  
13  // @ts-check
14  
15  import fs from 'node:fs/promises';
16  import path from 'node:path';
17  import { fileURLToPath } from 'node:url';
18  import { parseArgs } from 'node:util';
19  import { codeToANSI } from '@shikijs/cli';
20  import { runGitCliff } from 'git-cliff';
21  import { toHtml } from 'hast-util-to-html';
22  import { h } from 'hastscript';
23  import { fromMarkdown } from 'mdast-util-from-markdown';
24  import { toHast } from 'mdast-util-to-hast';
25  import rehypeMinifyWhitespace from 'rehype-minify-whitespace';
26  import { remove } from 'unist-util-remove';
27  
28  import pkg from '../package.json' with { type: 'json' };
29  
30  const ROOT_PATH = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
31  const RELEASE_NOTES_DIR = path.join(ROOT_PATH, 'docs', 'release-notes');
32  
33  const {
34  	values: { version, range },
35  } = parseArgs({
36  	options: {
37  		version: {
38  			type: 'string',
39  			short: 'v',
40  			default: pkg.version,
41  		},
42  		range: {
43  			type: 'string',
44  		},
45  	},
46  });
47  
48  if (!version) {
49  	throw new RangeError(`\`--version\` is required, got \`${JSON.stringify(version)}\``);
50  }
51  
52  const newVersionMarkdown = (
53  	await runGitCliff(range ? [range] : ['--unreleased'], {
54  		stdio: ['ignore', 'pipe', 'inherit'],
55  	})
56  ).stdout;
57  
58  const mdTree = fromMarkdown(newVersionMarkdown);
59  
60  remove(mdTree, [
61  	{ type: 'heading', depth: 1 },
62  	{ type: 'heading', depth: 2 },
63  ]);
64  
65  const htmlTree = h(null, [
66  	{ type: 'doctype' },
67  	h('html', { lang: 'en' }, [
68  		h('head', [h('meta', { charSet: 'UTF-8' }), h('title', [`v${version} release notes`])]),
69  		h('body', toHast(mdTree)),
70  	]),
71  ]);
72  
73  rehypeMinifyWhitespace()(htmlTree);
74  
75  const html = toHtml(htmlTree);
76  
77  const htmlPath = path.join(RELEASE_NOTES_DIR, `${version}.html`);
78  
79  console.log('Writing to', path.relative(ROOT_PATH, htmlPath));
80  console.log();
81  console.log(await codeToANSI(html, 'html', 'ayu-dark'));
82  
83  await fs.mkdir(RELEASE_NOTES_DIR, { recursive: true });
84  await fs.writeFile(htmlPath, `${html}\n`, { encoding: 'utf8' });