@dogsbay/dita-ot-plugin 0.0.0-stage → 0.2.0-beta.116
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/README.md +42 -2
- package/bin/cli.js +41 -0
- package/dist/com.dogsbay.publish/README.md +67 -0
- package/dist/com.dogsbay.publish/build_dogsbay.xml +149 -0
- package/dist/com.dogsbay.publish/converter/VERSION +1 -0
- package/dist/com.dogsbay.publish/converter/publish-dita.mjs +360 -0
- package/dist/com.dogsbay.publish/plugin.xml +37 -0
- package/dist/com.dogsbay.publish-0.2.0-beta.116.zip +0 -0
- package/dist/com.dogsbay.publish-0.2.0-beta.116.zip.sha256 +1 -0
- package/lib/index.js +61 -0
- package/lib/version.js +20 -0
- package/lib/zip.js +89 -0
- package/package.json +45 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
com.dogsbay.publish: publish a DITA deliverable as a dogsbay site.
|
|
4
|
+
|
|
5
|
+
dogsbay DITA-OT preprocessing, then the publish-dita converter on the
|
|
6
|
+
temp folder: content/*.md, content/nav.yml, dogsbay.config.yml.
|
|
7
|
+
The converter is converter/publish-dita.mjs (run with Node.js),
|
|
8
|
+
or the converter dogsbay.converter names.
|
|
9
|
+
dogsbay-site dogsbay, then `dogsbay site build` and the Astro build:
|
|
10
|
+
HTML, .md copies, llms.txt, Pagefind search.
|
|
11
|
+
|
|
12
|
+
Conditions are resolved by DITA-OT with args.filter, as for any output.
|
|
13
|
+
-->
|
|
14
|
+
<plugin id="com.dogsbay.publish" version="0.2.0.beta-116">
|
|
15
|
+
<require plugin="org.dita.base"/>
|
|
16
|
+
<transtype name="dogsbay" desc="dogsbay site project (Markdown, navigation, site config)">
|
|
17
|
+
<param name="dogsbay.cli" desc="The dogsbay CLI that dogsbay-site runs for site init and site build: a command on the PATH, or an absolute path to its bin script (default: dogsbay)" type="string"/>
|
|
18
|
+
<param name="dogsbay.converter" desc="The publish-dita converter: a command on the PATH, or an absolute path to its script (default: the plugin's converter/publish-dita.mjs)" type="string"/>
|
|
19
|
+
<param name="dogsbay.node" desc="The Node.js executable that runs a script converter (default: node on the PATH)" type="file"/>
|
|
20
|
+
<param name="dogsbay.family.links" desc="Parent, previous and next topic links after each topic, as the html5 output has them (a dogsbay site has previous/next buttons and a sidebar)" type="enum">
|
|
21
|
+
<val>yes</val>
|
|
22
|
+
<val default="true">no</val>
|
|
23
|
+
</param>
|
|
24
|
+
<param name="dogsbay.numbering" desc="Number titled tables and figures (Table 1., Figure 1.) as the html5 output does" type="enum">
|
|
25
|
+
<val default="true">yes</val>
|
|
26
|
+
<val>no</val>
|
|
27
|
+
</param>
|
|
28
|
+
</transtype>
|
|
29
|
+
<transtype name="dogsbay-site" extends="dogsbay" desc="dogsbay site (Astro HTML, .md copies, llms.txt, search)">
|
|
30
|
+
<param name="dogsbay.site.install" desc="Install the site's npm dependencies before building" type="enum">
|
|
31
|
+
<val default="true">yes</val>
|
|
32
|
+
<val>no</val>
|
|
33
|
+
</param>
|
|
34
|
+
<param name="dogsbay.site.npm" desc="The package manager that installs and builds the site: npm (default), pnpm or yarn" type="string"/>
|
|
35
|
+
</transtype>
|
|
36
|
+
<feature extension="ant.import" file="build_dogsbay.xml"/>
|
|
37
|
+
</plugin>
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2faf46eb73ab6e76711932d51847bef112d4be004590efcaf09ba257c15740c2 com.dogsbay.publish-0.2.0-beta.116.zip
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DITA-OT plugin com.dogsbay.publish, as built into this package's dist/,
|
|
3
|
+
* and installing it into a DITA-OT installation.
|
|
4
|
+
*/
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { cpSync, existsSync, readFileSync, rmSync, statSync } from "node:fs";
|
|
7
|
+
import { dirname, join, resolve } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
export const PLUGIN_ID = "com.dogsbay.publish";
|
|
11
|
+
|
|
12
|
+
const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
13
|
+
|
|
14
|
+
/** This package's version: the plugin's version. */
|
|
15
|
+
export const version = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf-8")).version;
|
|
16
|
+
|
|
17
|
+
/** The built plugin folder (dist/com.dogsbay.publish). */
|
|
18
|
+
export const pluginDir = join(packageRoot, "dist", PLUGIN_ID);
|
|
19
|
+
|
|
20
|
+
/** The built plugin zip, for `dita install <zip>`. */
|
|
21
|
+
export const pluginZip = join(packageRoot, "dist", `${PLUGIN_ID}-${version}.zip`);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Copy the plugin into a DITA-OT installation's plugins/ folder (replacing an
|
|
25
|
+
* earlier copy), then integrate it with DITA-OT's `dita install`.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} ditaOt the DITA-OT installation folder
|
|
28
|
+
* @param {{ integrate?: boolean, run?: (command: string, args: string[], cwd: string) => number, from?: string }} [options]
|
|
29
|
+
* integrate: run `dita install` (default true); run: runs the command and returns its exit
|
|
30
|
+
* status (for tests); from: the plugin folder to install (default: this package's build)
|
|
31
|
+
* @returns {{ target: string, integrated: boolean }}
|
|
32
|
+
*/
|
|
33
|
+
export function installPlugin(ditaOt, options = {}) {
|
|
34
|
+
const home = resolve(ditaOt);
|
|
35
|
+
const from = options.from ?? pluginDir;
|
|
36
|
+
if (!existsSync(join(from, "plugin.xml"))) {
|
|
37
|
+
throw new Error(`The plugin is not built: ${from} has no plugin.xml (run the package's build)`);
|
|
38
|
+
}
|
|
39
|
+
if (!existsSync(home) || !statSync(home).isDirectory() || !existsSync(join(home, "plugins")) || !existsSync(join(home, "build.xml"))) {
|
|
40
|
+
throw new Error(`${home} is not a DITA-OT installation (no plugins/ folder and build.xml)`);
|
|
41
|
+
}
|
|
42
|
+
const target = join(home, "plugins", PLUGIN_ID);
|
|
43
|
+
rmSync(target, { recursive: true, force: true });
|
|
44
|
+
cpSync(from, target, { recursive: true });
|
|
45
|
+
if (options.integrate === false) return { target, integrated: false };
|
|
46
|
+
|
|
47
|
+
const windows = process.platform === "win32";
|
|
48
|
+
const dita = join(home, "bin", windows ? "dita.bat" : "dita");
|
|
49
|
+
if (!existsSync(dita)) {
|
|
50
|
+
throw new Error(`Copied the plugin to ${target}, but ${dita} is missing: integrate it with DITA-OT's installer`);
|
|
51
|
+
}
|
|
52
|
+
const run = options.run ?? ((command, args, cwd) =>
|
|
53
|
+
windows
|
|
54
|
+
// Node runs a .bat only through the shell, which joins arguments unquoted: quote the
|
|
55
|
+
// command so a DITA-OT path with spaces (C:\Program Files\...) stays one word
|
|
56
|
+
? spawnSync(`"${command}" ${args.join(" ")}`, { cwd, stdio: "inherit", shell: true }).status ?? 1
|
|
57
|
+
: spawnSync(command, args, { cwd, stdio: "inherit" }).status ?? 1);
|
|
58
|
+
const status = run(dita, ["install"], home);
|
|
59
|
+
if (status !== 0) throw new Error(`dita install failed (exit ${status}); the plugin is in ${target}`);
|
|
60
|
+
return { target, integrated: true };
|
|
61
|
+
}
|
package/lib/version.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugin.xml version for a package version. DITA-OT checks plugin versions against
|
|
3
|
+
* major.minor.micro[.qualifier], where the qualifier has no dots (PluginParser
|
|
4
|
+
* VERSION_PATTERN), so a pre-release `0.2.0-beta.116` becomes `0.2.0.beta-116`, and
|
|
5
|
+
* build metadata joins the qualifier (`1.0.0-rc.1+build.5` → `1.0.0.rc-1_build-5`).
|
|
6
|
+
* @param {string} version a semantic version
|
|
7
|
+
* @returns {string}
|
|
8
|
+
*/
|
|
9
|
+
export function pluginVersion(version) {
|
|
10
|
+
const match = /^(\d+\.\d+\.\d+)(?:-([^+]*))?(?:\+(.*))?$/.exec(version);
|
|
11
|
+
if (!match) throw new Error(`No DITA-OT plugin version for ${version}`);
|
|
12
|
+
const [, release, pre, build] = match;
|
|
13
|
+
const qualifier = [pre, build].filter(Boolean).join("+").replace(/\./g, "-").replace(/[^0-9A-Za-z_-]/g, "_");
|
|
14
|
+
const out = qualifier ? `${release}.${qualifier}` : release;
|
|
15
|
+
if (!DITA_OT_VERSION.test(out)) throw new Error(`No DITA-OT plugin version for ${version}`);
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** DITA-OT's plugin version pattern (org.dita.dost.platform.PluginParser.VERSION_PATTERN). */
|
|
20
|
+
export const DITA_OT_VERSION = /^\d+(?:\.\d+(?:\.\d+(?:\.[0-9a-zA-Z_-]+)?)?)?$/;
|
package/lib/zip.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal zip writer (deflate, no dependencies): enough for the plugin zip
|
|
3
|
+
* DITA-OT's `dita install` reads, without a `zip` binary on the build machine.
|
|
4
|
+
*/
|
|
5
|
+
import { deflateRawSync } from "node:zlib";
|
|
6
|
+
|
|
7
|
+
const CRC_TABLE = (() => {
|
|
8
|
+
const table = new Uint32Array(256);
|
|
9
|
+
for (let n = 0; n < 256; n++) {
|
|
10
|
+
let c = n;
|
|
11
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
12
|
+
table[n] = c >>> 0;
|
|
13
|
+
}
|
|
14
|
+
return table;
|
|
15
|
+
})();
|
|
16
|
+
|
|
17
|
+
const crc32 = (data) => {
|
|
18
|
+
let crc = 0xffffffff;
|
|
19
|
+
for (const byte of data) crc = CRC_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8);
|
|
20
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** DOS date and time for 1980-01-01 00:00, so a build is reproducible. */
|
|
24
|
+
const DOS_TIME = 0;
|
|
25
|
+
const DOS_DATE = (1 << 5) | 1;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A zip archive of `entries` ({ name, data }), in the order given. Folder
|
|
29
|
+
* entries are names ending in "/" with empty data.
|
|
30
|
+
* @param {Array<{ name: string, data: Buffer }>} entries
|
|
31
|
+
* @returns {Buffer}
|
|
32
|
+
*/
|
|
33
|
+
export function createZip(entries) {
|
|
34
|
+
// No ZIP64: the plugin is a handful of files, well inside these limits
|
|
35
|
+
if (entries.length > 0xffff) throw new Error("createZip: more than 65535 entries needs ZIP64");
|
|
36
|
+
const locals = [];
|
|
37
|
+
const centrals = [];
|
|
38
|
+
let offset = 0;
|
|
39
|
+
for (const { name, data } of entries) {
|
|
40
|
+
const nameBytes = Buffer.from(name, "utf-8");
|
|
41
|
+
const isDir = name.endsWith("/");
|
|
42
|
+
const compressed = isDir ? Buffer.alloc(0) : deflateRawSync(data);
|
|
43
|
+
const method = isDir ? 0 : 8;
|
|
44
|
+
const crc = isDir ? 0 : crc32(data);
|
|
45
|
+
const local = Buffer.alloc(30);
|
|
46
|
+
local.writeUInt32LE(0x04034b50, 0);
|
|
47
|
+
local.writeUInt16LE(20, 4);
|
|
48
|
+
local.writeUInt16LE(0x0800, 6); // UTF-8 names
|
|
49
|
+
local.writeUInt16LE(method, 8);
|
|
50
|
+
local.writeUInt16LE(DOS_TIME, 10);
|
|
51
|
+
local.writeUInt16LE(DOS_DATE, 12);
|
|
52
|
+
local.writeUInt32LE(crc, 14);
|
|
53
|
+
local.writeUInt32LE(compressed.length, 18);
|
|
54
|
+
local.writeUInt32LE(data.length, 22);
|
|
55
|
+
local.writeUInt16LE(nameBytes.length, 26);
|
|
56
|
+
local.writeUInt16LE(0, 28);
|
|
57
|
+
const central = Buffer.alloc(46);
|
|
58
|
+
central.writeUInt32LE(0x02014b50, 0);
|
|
59
|
+
central.writeUInt16LE(0x031e, 4); // made by Unix, zip 3.0
|
|
60
|
+
central.writeUInt16LE(20, 6);
|
|
61
|
+
central.writeUInt16LE(0x0800, 8);
|
|
62
|
+
central.writeUInt16LE(method, 10);
|
|
63
|
+
central.writeUInt16LE(DOS_TIME, 12);
|
|
64
|
+
central.writeUInt16LE(DOS_DATE, 14);
|
|
65
|
+
central.writeUInt32LE(crc, 16);
|
|
66
|
+
central.writeUInt32LE(compressed.length, 20);
|
|
67
|
+
central.writeUInt32LE(data.length, 24);
|
|
68
|
+
central.writeUInt16LE(nameBytes.length, 28);
|
|
69
|
+
central.writeUInt16LE(0, 30);
|
|
70
|
+
central.writeUInt16LE(0, 32);
|
|
71
|
+
central.writeUInt16LE(0, 34);
|
|
72
|
+
central.writeUInt16LE(0, 36);
|
|
73
|
+
// Unix permissions: folders 755, files 644
|
|
74
|
+
central.writeUInt32LE(((isDir ? 0o40755 : 0o100644) << 16) >>> 0, 38);
|
|
75
|
+
central.writeUInt32LE(offset, 42);
|
|
76
|
+
locals.push(local, nameBytes, compressed);
|
|
77
|
+
centrals.push(central, nameBytes);
|
|
78
|
+
offset += local.length + nameBytes.length + compressed.length;
|
|
79
|
+
}
|
|
80
|
+
const centralSize = centrals.reduce((n, b) => n + b.length, 0);
|
|
81
|
+
if (offset + centralSize > 0xffffffff) throw new Error("createZip: archives over 4 GB need ZIP64");
|
|
82
|
+
const end = Buffer.alloc(22);
|
|
83
|
+
end.writeUInt32LE(0x06054b50, 0);
|
|
84
|
+
end.writeUInt16LE(entries.length, 8);
|
|
85
|
+
end.writeUInt16LE(entries.length, 10);
|
|
86
|
+
end.writeUInt32LE(centralSize, 12);
|
|
87
|
+
end.writeUInt32LE(offset, 16);
|
|
88
|
+
return Buffer.concat([...locals, ...centrals, end]);
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/dita-ot-plugin",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0-beta.116",
|
|
4
|
+
"description": "DITA-OT plugin com.dogsbay.publish: publish DITA as a dogsbay site (transtypes dogsbay and dogsbay-site)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dogsbay-dita-ot-plugin": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./lib/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"bin",
|
|
15
|
+
"lib",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"dogsbay",
|
|
20
|
+
"dita",
|
|
21
|
+
"dita-ot",
|
|
22
|
+
"dita-ot-plugin",
|
|
23
|
+
"documentation"
|
|
24
|
+
],
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"vitest": "^4.1.10",
|
|
27
|
+
"@dogsbay/dita-publish": "0.2.0-beta.116"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/dogsbay/dogsbay.git",
|
|
36
|
+
"directory": "packages/dita-ot-plugin"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/dogsbay/dogsbay/tree/main/packages/dita-ot-plugin",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/dogsbay/dogsbay/issues"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "node scripts/build-plugin.mjs",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"smoke": "bash scripts/smoke.sh"
|
|
47
|
+
}
|
|
6
48
|
}
|