pterodoc 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,126 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ ### Changed
6
+
7
+ - Split into an npm workspace of four packages: `@pterodoc/core` (rendering, the site
8
+ model, the target contract, configuration and the reconciler), `@pterodoc/docusaurus`
9
+ (the site loader and its readers), `@pterodoc/wordpress` (the REST target) and
10
+ `pterodoc` (the command line, the Docusaurus build plugin and the public barrel).
11
+ The dependency graph points inwards and npm enforces it. The public surface of
12
+ `pterodoc` is unchanged, `pterodoc/plugin` still resolves, and the goldens still match
13
+ byte for byte.
14
+ - The site model, the page tree, the `SourceReader` contract and model capture moved out
15
+ of the Docusaurus layer: they describe what a source produces, not how Docusaurus
16
+ produces it. `pterodoc --model` and every fixture-driven test now resolve without
17
+ Docusaurus in the graph at all.
18
+ - The command line and the Docusaurus plugin build the target through one
19
+ `resolveTarget`, rather than each spelling out the same options. The plugin also
20
+ accepts a `target` of its own.
21
+ - The version is stamped into the build instead of found by walking up the tree looking
22
+ for a manifest, which under a workspace would have found the wrong one and silently
23
+ reported `0.0.0`.
24
+ - Installing from a git URL is no longer supported; install `pterodoc` from npm.
25
+
26
+ ### Added
27
+
28
+ - A WordPress plugin, in `packages/wordpress/plugin`, that turns the pages
29
+ pterodoc publishes into a documentation experience: a full-width layout with
30
+ prose kept to a comfortable measure while code and tables run to the column
31
+ edge, syntax highlighting and a copy button, a sidebar that collapses to the
32
+ section being read and scrolls on its own, a bottom sheet or drawer on small
33
+ screens, and tables that scroll inside their own keyboard-reachable region.
34
+
35
+ It registers no block types. Everything is layered over the core blocks
36
+ pterodoc already writes, through `render_block` filters, one stylesheet and one
37
+ script — so deactivating it leaves documentation that is still readable and
38
+ still navigable. Site-wide defaults live on a settings page; any single block
39
+ can override them from the block inspector.
40
+
41
+ Its design is built on the block supports rather than around them. Every token
42
+ resolves through a theme's own global-styles variables first, syntax colours
43
+ are derived with `color-mix` from the code block's resolved colours so a
44
+ palette choice repaints them to match, the gutter is padding on the column
45
+ rather than on any block so `spacing` composes, and every default sits inside
46
+ `:where()` so anything set in the inspector wins. There is no `!important` in
47
+ the stylesheet.
48
+
49
+ - `render.blocks`, either `'core'` (the default, and byte-for-byte what pterodoc
50
+ emitted before) or `'plugin'`. The second carries instructions the plugin can
51
+ act on in block-comment attributes only, never in markup, so WordPress stores
52
+ the same content either way and the editor has nothing to object to.
53
+
54
+ - Highlighted line ranges survive when `render.blocks` is `'plugin'`. A
55
+ `{1,3-5}` on a fence had no core equivalent and was reported as dropped; it is
56
+ now carried and rendered.
57
+
58
+ - `pterodoc doctor` reports whether the plugin is installed, and warns when its
59
+ class prefix disagrees with `render.classPrefix` — a mismatch that otherwise
60
+ publishes cleanly, loads cleanly and silently styles nothing.
61
+
62
+ ### Fixed
63
+
64
+ - `pterodoc/plugin` shipped an `exports` entry pointing at a declaration file that is not
65
+ where tsc emits one, so the subpath resolved to `any` for every consumer.
66
+ - `@types/mdast`, `@types/hast` and `@types/github-slugger` were development
67
+ dependencies, but the emitted declarations refer to those types; they are now real
68
+ dependencies of `@pterodoc/core`.
69
+ - The fake WordPress used by the tests set `title` twice in one object literal, so the
70
+ first was always dead. Typechecking the test suites, which nothing did before, found
71
+ it.
72
+ - Six tests asserted POSIX absolute paths and could not pass on Windows, where
73
+ `path.resolve` prepends the drive letter. They now build their fixtures with `path`.
74
+
75
+ ### Removed
76
+
77
+ - `remark-emoji`, which was declared as a dependency and never imported.
78
+
79
+ ## 0.1.0
80
+
81
+ ### Added
82
+ - Project skeleton: TypeScript sources, a Rollup build emitting `lib/`, declarations from
83
+ `tsc`, and a `prepare` script so the package can be consumed straight from git.
84
+ - Errors and exit codes, structured issues, path, hash and media-type helpers.
85
+ - The renderer: markdown to Gutenberg blocks, with a configurable class prefix and string
86
+ table so the output is not tied to one site's theme. Verified byte-identical to the
87
+ DocStack script it was extracted from on a shared fixture.
88
+
89
+ - The site model, read from Docusaurus itself through its own site loader: resolved
90
+ sidebars with autogenerated entries already expanded, versions, locales, permalinks,
91
+ draft and unlisted flags, and previous/next links. pterodoc never walks a docs
92
+ directory or parses a sidebar file.
93
+ - The page tree, ordered by the sidebar, with directory pages named by their category.
94
+ - Model capture, so a site can be rendered without Docusaurus and a bug can be reported
95
+ reproducibly.
96
+
97
+ - The WordPress target: page creation and updates identified by parent and slug, so a
98
+ re-run rewrites only what differs; media upload keyed by content hash; pruning that
99
+ trashes rather than deletes.
100
+ - The reconciler, the configuration file and the command line (`sync`, `render`,
101
+ `doctor`, `capture`, `init`), with rendered pages, a manifest and a plan written for
102
+ every run.
103
+
104
+ - MDX: imports and comments are removed, `Tabs` and `TabItem` become collapsible
105
+ sections that need no script, `Details`, `CodeBlock` and `Admonition` become their
106
+ block equivalents, and plain HTML is carried through. A component or an expression
107
+ with no equivalent is reported with its file, line and column rather than dropped.
108
+
109
+ - Images: references are found wherever they sit, resolved against the document, the
110
+ localised copy, the static directories or `@site/`, uploaded to the media library and
111
+ rewritten. A file is identified by the hash of its contents, carried in its media slug,
112
+ so a fresh checkout never uploads anything twice.
113
+ - Versions and locales, each published into its own subtree with its own navigation.
114
+ - A Docusaurus plugin, for a site that would rather publish from `postBuild`.
115
+
116
+ ### Fixed
117
+ Carried over from the original script, each with a test:
118
+ - Reference-style links (`[text][ref]`) resolve instead of printing as literal text, and
119
+ the definitions no longer appear on the page.
120
+ - Images are found wherever they sit, so a standalone image becomes an image block and an
121
+ inline one stays inline. Their URLs and alt text are escaped.
122
+ - Shortcode brackets are escaped on the tree rather than by pattern-matching the HTML, so
123
+ a `>` inside an attribute no longer confuses the escaper.
124
+ - A leading H1 is recognised as the title even when a comment precedes it.
125
+ - Code fences keep their `title` and `showLineNumbers`; a dropped highlight range is
126
+ reported rather than lost in silence.
package/LICENCE.md ADDED
@@ -0,0 +1,10 @@
1
+ Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
2
+
3
+ Copyright (c) Onyx <hello@onyx.ac> (https://onyx.ac)
4
+
5
+ This work is licensed under the Creative Commons Attribution-ShareAlike 4.0
6
+ International License. You are free to share and adapt this work, including
7
+ commercially, provided you give appropriate attribution and distribute any
8
+ derivative works under the same license.
9
+
10
+ Full legal text: https://creativecommons.org/licenses/by-sa/4.0/legalcode
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ <div align="center">
2
+
3
+ # pterodoc
4
+
5
+ **Your documentation, where people actually find it.**
6
+
7
+ Publishes a Docusaurus site to WordPress as a tree of native Gutenberg pages, so the
8
+ docs you write once are indexed under your own domain without being rewritten by hand.
9
+
10
+ [Install](#install) · [Usage](#usage) · [Configuration](#configuration) · [How it works](#how-it-works) · [Plugin](#the-wordpress-plugin) · [Status](#status)
11
+
12
+ </div>
13
+
14
+ ---
15
+
16
+ ## What is it?
17
+
18
+ A one-way publisher. Docusaurus stays the source of truth; WordPress becomes a mirror.
19
+ Every page it writes is real Gutenberg block markup — headings, lists, tables, code,
20
+ admonitions, images — so the result is editable in WordPress rather than a wall of
21
+ embedded HTML.
22
+
23
+ It does not invent its own idea of your site. It asks Docusaurus, using Docusaurus's own
24
+ loader, which means resolved sidebars (autogenerated ones included), versions, locales,
25
+ draft and unlisted flags, permalinks and previous/next links all come from the same code
26
+ that builds your site.
27
+
28
+ ## Install
29
+
30
+ ```console
31
+ npm install --save-dev pterodoc
32
+ ```
33
+
34
+ pterodoc runs inside a Docusaurus project and expects `@docusaurus/core` to be present.
35
+ It pulls in `@pterodoc/core`, `@pterodoc/docusaurus` and `@pterodoc/wordpress`, which are
36
+ published in lockstep with it.
37
+
38
+ Installing from a git URL is not supported: the repository is an npm workspace, and a git
39
+ install would pack only its private root.
40
+
41
+ ## Usage
42
+
43
+ ```console
44
+ npx pterodoc render # render every page locally; contacts nothing
45
+ npx pterodoc sync --dry-run # say what would change on the site
46
+ npx pterodoc sync # create and update
47
+ npx pterodoc sync --prune # also trash pages whose document is gone
48
+ npx pterodoc doctor # check config, credentials and permissions
49
+ ```
50
+
51
+ Credentials come from the environment, never from the config file:
52
+
53
+ ```console
54
+ export WP_URL=https://example.com
55
+ export WP_USER=someone
56
+ export WP_APP_PASSWORD='xxxx xxxx xxxx xxxx' # Users → Profile → Application Passwords
57
+ ```
58
+
59
+ Without them every command still renders, and reports what it would have done.
60
+
61
+ ## Configuration
62
+
63
+ `pterodoc.config.mjs` beside your Docusaurus config:
64
+
65
+ ```js
66
+ import { defineConfig } from 'pterodoc';
67
+
68
+ export default defineConfig({
69
+ site: { sidebars: ['docs'], versions: 'last', locales: 'default' },
70
+ target: { type: 'wordpress', root: '/docs' },
71
+ });
72
+ ```
73
+
74
+ Anything Docusaurus already knows — the site URL, base URL, route base path, locales,
75
+ markdown format, admonition keywords — is read from your Docusaurus config and is not
76
+ repeated here.
77
+
78
+ ## How it works
79
+
80
+ Pages mirror your documentation URLs, so `/docs/guides/sync` on Docusaurus becomes
81
+ `/<root>/guides/sync/` on WordPress. A directory becomes a page of its own, titled by its
82
+ sidebar category. A page is identified by its parent and its slug, so re-running only
83
+ rewrites what actually differs, and a second run reports everything as unchanged.
84
+
85
+ ## The WordPress plugin
86
+
87
+ Optional, and worth installing. pterodoc writes ordinary core blocks, which are
88
+ correct but plain: no syntax highlighting, tables that overflow, a sidebar that
89
+ is a bare expanded list. The plugin in `packages/wordpress/plugin` styles them.
90
+
91
+ It registers no block types, so nothing about your content becomes dependent on
92
+ it. Deactivate it and the documentation is still there, still readable, still
93
+ navigable.
94
+
95
+ ```console
96
+ npm run --workspace @pterodoc/wp-plugin build # writes pterodoc.zip
97
+ ```
98
+
99
+ Upload that under Plugins, Add New, Upload Plugin. Defaults live at Settings,
100
+ pterodoc; any single block can override them from the block inspector.
101
+
102
+ Two things to know. Its class prefix must match `render.classPrefix` — set it on
103
+ the settings page, which needs no re-publishing; `pterodoc doctor` says whether
104
+ the two agree. And because a sync rewrites a page's content, an override set on a
105
+ block in the WordPress editor is replaced the next time that page is published:
106
+ the settings page is the durable place for a preference.
107
+
108
+ Once it is installed, `render.blocks: 'plugin'` lets pterodoc carry instructions
109
+ core blocks cannot express — chiefly a fence's highlighted line range, which is
110
+ otherwise reported as dropped. It travels in the block comment rather than in
111
+ markup, so WordPress stores the same content either way.
112
+
113
+ ## Status
114
+
115
+ Working, and published.
116
+
117
+ The publisher has been verified against a real 47-page documentation set: rendering
118
+ matches the script it was extracted from on 42 of those pages, and every one of the
119
+ remaining five differs only where pterodoc is now correct.
120
+
121
+ Not yet exercised against a site that uses them: versions, locales, and the Docusaurus
122
+ build plugin. The WordPress plugin is newer still — its PHP and JavaScript are checked in
123
+ CI and its markup decisions are covered by tests on the publisher's side, but its
124
+ behaviour in a browser has not been through a release on a live site.
125
+
126
+ ## Licence
127
+
128
+ CC-BY-SA-4.0. See LICENCE.md.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ // Shipped unbuilt so the entry point stays readable and stable.
3
+ import { main } from '../lib/cli/run.js';
4
+
5
+ process.exitCode = await main(process.argv.slice(2));
@@ -0,0 +1,38 @@
1
+ import { createWordpressTarget } from '@pterodoc/wordpress';
2
+
3
+ /**
4
+ * Build the target a run publishes to.
5
+ *
6
+ * Both entry points — the command line and the Docusaurus plugin — need the
7
+ * same object built the same way, and having built it in two places once
8
+ * already, the copies drifted apart in how they spelled the URL policy.
9
+ */
10
+ /**
11
+ * Build the configured target.
12
+ *
13
+ * Always built, even offline: the target decides what a page's URL is, and a
14
+ * render with the wrong URLs is worse than no render at all. Only opening a
15
+ * session needs credentials.
16
+ *
17
+ * @param config The resolved configuration.
18
+ */
19
+ function resolveTarget(config) {
20
+ return createWordpressTarget({
21
+ url: config.targetUrl,
22
+ user: config.user,
23
+ appPassword: config.appPassword,
24
+ policy: {
25
+ rootSegments: config.rootSegments,
26
+ baseSegments: config.baseSegments,
27
+ },
28
+ status: config.status,
29
+ template: config.template,
30
+ lang: config.lang,
31
+ mediaSlugPrefix: config.mediaSlugPrefix,
32
+ methodOverride: config.methodOverride,
33
+ retry: config.retry,
34
+ });
35
+ }
36
+
37
+ export { resolveTarget as r };
38
+ //# sourceMappingURL=target-BC_VOAlJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"target-BC_VOAlJ.js","sources":["../../src/target.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;;AAMG;AAKH;;;;;;;;AAQG;AACG,SAAU,aAAa,CAAC,MAAsB,EAAA;AAClD,IAAA,OAAO,qBAAqB,CAAC;QAC3B,GAAG,EAAE,MAAM,CAAC,SAAS;QACrB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;AAC/B,QAAA,MAAM,EAAE;YACN,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,YAAY,EAAE,MAAM,CAAC,YAAY;AAClC,SAAA;QACD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,KAAK,EAAE,MAAM,CAAC,KAAK;AACpB,KAAA,CAAC;AACJ;;"}
@@ -0,0 +1,26 @@
1
+ /** Command line parsing and the usage text. */
2
+ import type { ConfigFlags } from '@pterodoc/core';
3
+ /** Commands the CLI accepts. */
4
+ export declare const COMMANDS: readonly ["sync", "render", "doctor", "capture", "init"];
5
+ /** One of the commands. */
6
+ export type Command = (typeof COMMANDS)[number];
7
+ /** The help text. */
8
+ export declare const USAGE = "Publish a Docusaurus site to WordPress as a tree of pages.\n\nUsage: pterodoc <command> [options]\n\nCommands\n sync Reconcile the target with the site. The default.\n render Render every page to the output directory; contacts nothing.\n doctor Check the configuration, the credentials and the target.\n capture Write the loaded site model to a JSON file.\n init Write a starter pterodoc.config.mjs.\n\nSource\n --site-dir <dir> Docusaurus site directory (default: the working directory).\n --config <file> pterodoc config file.\n --docusaurus-config <file> Explicit docusaurus.config.* path.\n --model <file> Use a captured model; Docusaurus is never loaded.\n --instance <id> Docs plugin instance. Repeatable.\n --locale <code> Locale to publish. Repeatable.\n --all-locales Publish every locale the site declares.\n --docs-version <name> Version to publish. Repeatable.\n --all-versions Publish every version.\n\nTarget\n --root <path> Path the documentation hangs from.\n --base <segment> Segment below the root (\"\" publishes under the root).\n --status <status> publish, draft or private.\n --only <prefix> Restrict writes to pages under <prefix>.\n --dry-run Plan and render, change nothing.\n --prune Trash pages with no source document.\n --offline Render only; never open a session.\n --no-media Skip uploads; leave image URLs as written.\n\nOutput\n --out <dir> Output directory (default <site-dir>/.pterodoc).\n --capture <file> Also write the site model to <file>.\n --env-file <file> Read this .env file. None is read otherwise.\n --strict Fail when an issue reaches the configured severity.\n --json Print a machine-readable summary.\n --verbose Log every page as it is processed.\n --quiet Only print errors.\n --help, --version\n\nCredentials come from the environment: WP_URL, WP_USER, WP_APP_PASSWORD.\nWithout them every command still renders and reports what it would have done.";
9
+ /** Flags after parsing. */
10
+ export interface ParsedArgs {
11
+ command: Command;
12
+ flags: ConfigFlags;
13
+ capture: string | undefined;
14
+ json: boolean;
15
+ verbose: boolean;
16
+ quiet: boolean;
17
+ help: boolean;
18
+ version: boolean;
19
+ }
20
+ /**
21
+ * Parse the command line.
22
+ *
23
+ * @param argv Arguments after the executable and script name.
24
+ */
25
+ export declare function parseCliArgs(argv: string[]): ParsedArgs;
26
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAI/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,gCAAgC;AAChC,eAAO,MAAM,QAAQ,0DAA2D,CAAC;AAEjF,2BAA2B;AAC3B,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhD,qBAAqB;AACrB,eAAO,MAAM,KAAK,ovEA2C4D,CAAC;AAE/E,2BAA2B;AAC3B,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAmFvD"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * What the user sees.
3
+ *
4
+ * GitHub Actions gets annotations it can surface on the run; a terminal gets
5
+ * something readable.
6
+ */
7
+ import { type Issue } from '@pterodoc/core/util';
8
+ import type { Plan } from '@pterodoc/core';
9
+ /** How output is presented. */
10
+ export interface Reporter {
11
+ info(message: string): void;
12
+ detail(message: string): void;
13
+ issue(issue: Issue): void;
14
+ summary(plan: Plan): void;
15
+ }
16
+ /** Build a reporter. */
17
+ export declare function createReporter(options: {
18
+ verbose?: boolean;
19
+ quiet?: boolean;
20
+ json?: boolean;
21
+ env?: NodeJS.ProcessEnv;
22
+ }): Reporter;
23
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/cli/reporter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAe,KAAK,KAAK,EAAiB,MAAM,qBAAqB,CAAC;AAC7E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE3C,+BAA+B;AAC/B,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CAC3B;AAED,wBAAwB;AACxB,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,QAAQ,CAuCX"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Command line entry point.
3
+ *
4
+ * The only place that catches: every other module raises, and this decides how
5
+ * it is shown and which exit code it becomes.
6
+ */
7
+ /** Run the CLI. */
8
+ export declare function main(argv: string[]): Promise<number>;
9
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,mBAAmB;AACnB,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2C1D"}