@xyd-js/next-plugin 0.0.0-build-cdbb0d7-20260901160230
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 +53 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +155 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) LiveSession Sp.z.o.o
|
|
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,53 @@
|
|
|
1
|
+
# @xyd-js/next-plugin
|
|
2
|
+
|
|
3
|
+
[xyd](https://xyd.dev) docs inside your **Next.js** app — one deployable, one origin:
|
|
4
|
+
your app at `/`, your docs under `/docs`.
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
// next.config.mjs
|
|
8
|
+
import { withXyd } from "@xyd-js/next-plugin";
|
|
9
|
+
|
|
10
|
+
/** @type {import('next').NextConfig} */
|
|
11
|
+
const nextConfig = {};
|
|
12
|
+
|
|
13
|
+
export default withXyd({ docsRoot: "./docs", base: "/docs" })(nextConfig);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## How it works
|
|
17
|
+
|
|
18
|
+
- **`next build`** — runs `xyd build` for the docs project (child process) and merges
|
|
19
|
+
the static output into `public/` (pages under `public/docs`, hashed assets under
|
|
20
|
+
`public/assets` — Next serves `public/` at the site root). Extensionless docs URLs
|
|
21
|
+
(`/docs/overview`) are mapped to the flat `.html` files via `afterFiles` rewrites,
|
|
22
|
+
which `next start` and Vercel honor at runtime. A manifest
|
|
23
|
+
(`public/.xyd-docs-manifest.json`) tracks the generated files so every rebuild
|
|
24
|
+
cleans its previous output first.
|
|
25
|
+
|
|
26
|
+
Add the generated paths to your `.gitignore`:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
public/docs/
|
|
30
|
+
public/assets/
|
|
31
|
+
public/public/
|
|
32
|
+
public/.xyd-docs-manifest.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **`next dev`** — spawns `xyd dev` (bun engine) on an internal port and proxies the
|
|
36
|
+
mount + xyd's `/_xyd/*` + `/_bun/*` internals via rewrites to that origin. App and
|
|
37
|
+
docs share one URL/port. (Next's rewrite proxy is HTTP-only, so the docs
|
|
38
|
+
live-reload websocket degrades gracefully — pages and styles still work; refresh
|
|
39
|
+
manually after edits.)
|
|
40
|
+
|
|
41
|
+
## Which xyd runs?
|
|
42
|
+
|
|
43
|
+
Same resolution as [`@xyd-js/vite-plugin`](https://www.npmjs.com/package/@xyd-js/vite-plugin):
|
|
44
|
+
the `command` option → a local `xyd-js` / `@xyd-js/cli` install → an `xyd` binary on
|
|
45
|
+
PATH. Recommended: `npm i -D xyd-js`.
|
|
46
|
+
|
|
47
|
+
## Options
|
|
48
|
+
|
|
49
|
+
Accepts the same options as `@xyd-js/vite-plugin` (minus `outDir`): `docsRoot`
|
|
50
|
+
(required), `base`, `enabled`, `dev`, `command`, `env`, `nodeOptions`,
|
|
51
|
+
`sitemap`/`robots`, `timeoutMs`, `silent`, `verbose`. The mount comes from `base`
|
|
52
|
+
(passed to xyd via `XYD_BASENAME`) or the docs' own `advanced.basename` — the docs
|
|
53
|
+
side wins when both are set (they must match).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { XydOptions } from '@xyd-js/vite-plugin';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Next.js integration for xyd docs, mirroring @xyd-js/vite-plugin:
|
|
5
|
+
*
|
|
6
|
+
* - `next build`: runs `xyd build` for the docs project and merges the static
|
|
7
|
+
* output into `public/` (docs pages under public/<base>, hashed assets under
|
|
8
|
+
* public/assets — Next serves public/ at the site root). Extensionless docs
|
|
9
|
+
* URLs are handled by afterFiles rewrites (`/docs/x` → `/docs/x.html`), which
|
|
10
|
+
* `next start` and Vercel honor at runtime.
|
|
11
|
+
* - `next dev`: spawns `xyd dev` (bun engine) on an internal port and proxies
|
|
12
|
+
* the mount + xyd's /_xyd + /_bun internals via rewrites to that origin —
|
|
13
|
+
* app and docs on ONE URL/port. (Next's rewrite proxy is HTTP-only, so the
|
|
14
|
+
* docs livereload websocket degrades gracefully — pages still work.)
|
|
15
|
+
*
|
|
16
|
+
* Usage (next.config.mjs):
|
|
17
|
+
* import { withXyd } from "@xyd-js/next-plugin";
|
|
18
|
+
* export default withXyd({ docsRoot: "./docs", base: "/docs" })(nextConfig);
|
|
19
|
+
*/
|
|
20
|
+
type XydNextOptions = Omit<XydOptions, "outDir">;
|
|
21
|
+
declare function withXyd(userOptions: XydNextOptions): (nextConfig?: any) => (phase: string, phaseCtx: any) => Promise<any>;
|
|
22
|
+
/** exported for tests */
|
|
23
|
+
declare function composeRewrites(userRewrites: any, ours: any[]): Promise<any>;
|
|
24
|
+
|
|
25
|
+
export { type XydNextOptions, composeRewrites, withXyd };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import {
|
|
5
|
+
createLogger,
|
|
6
|
+
mergeDocsBuild,
|
|
7
|
+
normalizeBase,
|
|
8
|
+
normalizeOptions,
|
|
9
|
+
pickFreePort,
|
|
10
|
+
resolveCli,
|
|
11
|
+
runDocsBuild,
|
|
12
|
+
spawnDocsDev,
|
|
13
|
+
XydError,
|
|
14
|
+
XYD_DEV_INTERNAL_PREFIXES
|
|
15
|
+
} from "@xyd-js/vite-plugin";
|
|
16
|
+
var PHASE_BUILD = "phase-production-build";
|
|
17
|
+
var PHASE_DEV = "phase-development-server";
|
|
18
|
+
var MANIFEST = ".xyd-docs-manifest.json";
|
|
19
|
+
var devStates = /* @__PURE__ */ new Map();
|
|
20
|
+
var buildsDone = /* @__PURE__ */ new Set();
|
|
21
|
+
function withXyd(userOptions) {
|
|
22
|
+
const options = normalizeOptions(userOptions);
|
|
23
|
+
const log = createLogger(options.verbose);
|
|
24
|
+
return (nextConfig = {}) => {
|
|
25
|
+
return async (phase, phaseCtx) => {
|
|
26
|
+
const resolved = typeof nextConfig === "function" ? await nextConfig(phase, phaseCtx) : { ...nextConfig };
|
|
27
|
+
if (!options.enabled) return resolved;
|
|
28
|
+
const root = process.cwd();
|
|
29
|
+
const absDocsRoot = path.resolve(root, options.docsRoot);
|
|
30
|
+
const base = options.base ?? readSettingsBasename(absDocsRoot);
|
|
31
|
+
if (!base) {
|
|
32
|
+
throw new XydError(
|
|
33
|
+
`no mount path for the docs \u2014 set \`base\` (e.g. base: "/docs") in withXyd(), or advanced.basename in ${absDocsRoot}/docs.json`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
let ourRewrites;
|
|
37
|
+
if (phase === PHASE_DEV && options.dev) {
|
|
38
|
+
const port = await ensureDocsDev(absDocsRoot, base, options, log);
|
|
39
|
+
const target = `http://localhost:${port}`;
|
|
40
|
+
ourRewrites = [
|
|
41
|
+
{ source: base, destination: `${target}${base}` },
|
|
42
|
+
{ source: `${base}/:path*`, destination: `${target}${base}/:path*` },
|
|
43
|
+
...XYD_DEV_INTERNAL_PREFIXES.flatMap((p) => [
|
|
44
|
+
{ source: p, destination: `${target}${p}` },
|
|
45
|
+
{ source: `${p}/:path*`, destination: `${target}${p}/:path*` }
|
|
46
|
+
])
|
|
47
|
+
];
|
|
48
|
+
} else {
|
|
49
|
+
ourRewrites = [
|
|
50
|
+
{ source: base, destination: `${base}/index.html` },
|
|
51
|
+
{ source: `${base}/:path*`, destination: `${base}/:path*.html` }
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
if (phase === PHASE_BUILD && !buildsDone.has(absDocsRoot)) {
|
|
55
|
+
buildsDone.add(absDocsRoot);
|
|
56
|
+
await buildAndMergeIntoPublic(root, absDocsRoot, base, options, log);
|
|
57
|
+
}
|
|
58
|
+
const userRewrites = resolved.rewrites;
|
|
59
|
+
resolved.rewrites = async () => composeRewrites(userRewrites, ourRewrites);
|
|
60
|
+
return resolved;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async function ensureDocsDev(absDocsRoot, base, options, log) {
|
|
65
|
+
let state = devStates.get(absDocsRoot);
|
|
66
|
+
if (!state) {
|
|
67
|
+
state = { port: await pickFreePort(), spawned: false };
|
|
68
|
+
devStates.set(absDocsRoot, state);
|
|
69
|
+
}
|
|
70
|
+
if (!state.spawned) {
|
|
71
|
+
state.spawned = true;
|
|
72
|
+
const cli = resolveCli(options.command, process.cwd());
|
|
73
|
+
log.info(`docs dev (${cli.source}): ${cli.argv.join(" ")} dev on :${state.port} \u2192 rewritten at ${base}`);
|
|
74
|
+
const spawnOptions = { ...options, env: { ...options.env, XYD_LIVERELOAD: "0" } };
|
|
75
|
+
spawnDocsDev(cli.argv, absDocsRoot, state.port, base, spawnOptions, log);
|
|
76
|
+
}
|
|
77
|
+
return state.port;
|
|
78
|
+
}
|
|
79
|
+
async function buildAndMergeIntoPublic(root, absDocsRoot, base, options, log) {
|
|
80
|
+
const publicDir = path.join(root, "public");
|
|
81
|
+
fs.mkdirSync(publicDir, { recursive: true });
|
|
82
|
+
const manifestPath = path.join(publicDir, MANIFEST);
|
|
83
|
+
if (fs.existsSync(manifestPath)) {
|
|
84
|
+
try {
|
|
85
|
+
const prev = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
86
|
+
for (const rel of prev.files || []) {
|
|
87
|
+
fs.rmSync(path.join(publicDir, rel), { force: true });
|
|
88
|
+
}
|
|
89
|
+
pruneEmptyDirs(publicDir);
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const cli = resolveCli(options.command, root);
|
|
94
|
+
log.info(`building docs (${cli.source}): ${cli.argv.join(" ")} build [cwd ${absDocsRoot}]`);
|
|
95
|
+
const startedAt = Date.now();
|
|
96
|
+
await runDocsBuild(cli.argv, absDocsRoot, options, log);
|
|
97
|
+
const before = snapshotFiles(publicDir);
|
|
98
|
+
const docsClientDir = path.join(absDocsRoot, ".xyd", "build", "client");
|
|
99
|
+
const summary = mergeDocsBuild(docsClientDir, publicDir, {
|
|
100
|
+
base,
|
|
101
|
+
sitemap: options.sitemap,
|
|
102
|
+
robots: options.robots
|
|
103
|
+
});
|
|
104
|
+
const generated = snapshotFiles(publicDir).filter((f) => !before.includes(f) && f !== MANIFEST);
|
|
105
|
+
fs.writeFileSync(manifestPath, JSON.stringify({ files: generated }, null, 2));
|
|
106
|
+
const secs = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
107
|
+
for (const note of summary.notes) log.info(note);
|
|
108
|
+
log.info(
|
|
109
|
+
`merged docs into public/ \u2014 mount ${summary.mount}, ${summary.pages} pages, ${summary.assets} assets` + (summary.skippedIdentical ? ` (+${summary.skippedIdentical} identical skipped)` : "") + `, ${secs}s`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
async function composeRewrites(userRewrites, ours) {
|
|
113
|
+
const user = typeof userRewrites === "function" ? await userRewrites() : userRewrites;
|
|
114
|
+
if (!user) {
|
|
115
|
+
return { beforeFiles: [], afterFiles: ours, fallback: [] };
|
|
116
|
+
}
|
|
117
|
+
if (Array.isArray(user)) {
|
|
118
|
+
return { beforeFiles: [], afterFiles: [...user, ...ours], fallback: [] };
|
|
119
|
+
}
|
|
120
|
+
return { ...user, afterFiles: [...user.afterFiles || [], ...ours] };
|
|
121
|
+
}
|
|
122
|
+
function readSettingsBasename(absDocsRoot) {
|
|
123
|
+
try {
|
|
124
|
+
const settings = JSON.parse(fs.readFileSync(path.join(absDocsRoot, "docs.json"), "utf-8"));
|
|
125
|
+
const basename = settings?.advanced?.basename;
|
|
126
|
+
return basename ? normalizeBase(String(basename)) : void 0;
|
|
127
|
+
} catch {
|
|
128
|
+
return void 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function snapshotFiles(dir) {
|
|
132
|
+
const out = [];
|
|
133
|
+
const walk = (d) => {
|
|
134
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
135
|
+
const abs = path.join(d, entry.name);
|
|
136
|
+
if (entry.isDirectory()) walk(abs);
|
|
137
|
+
else out.push(path.relative(dir, abs).split(path.sep).join("/"));
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
if (fs.existsSync(dir)) walk(dir);
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
function pruneEmptyDirs(dir) {
|
|
144
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
145
|
+
if (!entry.isDirectory()) continue;
|
|
146
|
+
const abs = path.join(dir, entry.name);
|
|
147
|
+
pruneEmptyDirs(abs);
|
|
148
|
+
if (!fs.readdirSync(abs).length) fs.rmdirSync(abs);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
composeRewrites,
|
|
153
|
+
withXyd
|
|
154
|
+
};
|
|
155
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport {\n createLogger,\n mergeDocsBuild,\n normalizeBase,\n normalizeOptions,\n pickFreePort,\n resolveCli,\n runDocsBuild,\n spawnDocsDev,\n XydError,\n XYD_DEV_INTERNAL_PREFIXES,\n type XydOptions,\n} from \"@xyd-js/vite-plugin\";\n\n/**\n * Next.js integration for xyd docs, mirroring @xyd-js/vite-plugin:\n *\n * - `next build`: runs `xyd build` for the docs project and merges the static\n * output into `public/` (docs pages under public/<base>, hashed assets under\n * public/assets — Next serves public/ at the site root). Extensionless docs\n * URLs are handled by afterFiles rewrites (`/docs/x` → `/docs/x.html`), which\n * `next start` and Vercel honor at runtime.\n * - `next dev`: spawns `xyd dev` (bun engine) on an internal port and proxies\n * the mount + xyd's /_xyd + /_bun internals via rewrites to that origin —\n * app and docs on ONE URL/port. (Next's rewrite proxy is HTTP-only, so the\n * docs livereload websocket degrades gracefully — pages still work.)\n *\n * Usage (next.config.mjs):\n * import { withXyd } from \"@xyd-js/next-plugin\";\n * export default withXyd({ docsRoot: \"./docs\", base: \"/docs\" })(nextConfig);\n */\n\nexport type XydNextOptions = Omit<XydOptions, \"outDir\">;\n\nconst PHASE_BUILD = \"phase-production-build\";\nconst PHASE_DEV = \"phase-development-server\";\n\n/** Tracks generated files inside public/ so a rebuild can clean them first. */\nconst MANIFEST = \".xyd-docs-manifest.json\";\n\ninterface DevState {\n port: number;\n spawned: boolean;\n}\n// keyed by absolute docsRoot — next.config can be evaluated more than once per process\nconst devStates = new Map<string, DevState>();\n// next build evaluates the config multiple times — build the docs once per process\nconst buildsDone = new Set<string>();\n\nexport function withXyd(userOptions: XydNextOptions) {\n const options = normalizeOptions(userOptions as XydOptions);\n const log = createLogger(options.verbose);\n\n return (nextConfig: any = {}) => {\n return async (phase: string, phaseCtx: any) => {\n const resolved =\n typeof nextConfig === \"function\" ? await nextConfig(phase, phaseCtx) : { ...nextConfig };\n\n if (!options.enabled) return resolved;\n\n const root = process.cwd();\n const absDocsRoot = path.resolve(root, options.docsRoot);\n const base = options.base ?? readSettingsBasename(absDocsRoot);\n if (!base) {\n throw new XydError(\n `no mount path for the docs — set \\`base\\` (e.g. base: \"/docs\") in withXyd(), or advanced.basename in ${absDocsRoot}/docs.json`\n );\n }\n\n let ourRewrites: any[];\n if (phase === PHASE_DEV && options.dev) {\n const port = await ensureDocsDev(absDocsRoot, base, options, log);\n const target = `http://localhost:${port}`;\n ourRewrites = [\n { source: base, destination: `${target}${base}` },\n { source: `${base}/:path*`, destination: `${target}${base}/:path*` },\n ...XYD_DEV_INTERNAL_PREFIXES.flatMap((p) => [\n { source: p, destination: `${target}${p}` },\n { source: `${p}/:path*`, destination: `${target}${p}/:path*` },\n ]),\n ];\n } else {\n // build + start + everything else: extensionless docs URLs → the\n // merged flat .html files in public/ (afterFiles = public wins for\n // real files like /docs/public/logo.svg)\n ourRewrites = [\n { source: base, destination: `${base}/index.html` },\n { source: `${base}/:path*`, destination: `${base}/:path*.html` },\n ];\n }\n\n if (phase === PHASE_BUILD && !buildsDone.has(absDocsRoot)) {\n buildsDone.add(absDocsRoot);\n await buildAndMergeIntoPublic(root, absDocsRoot, base, options, log);\n }\n\n const userRewrites = resolved.rewrites;\n resolved.rewrites = async () => composeRewrites(userRewrites, ourRewrites);\n return resolved;\n };\n };\n}\n\nasync function ensureDocsDev(\n absDocsRoot: string,\n base: string,\n options: ReturnType<typeof normalizeOptions>,\n log: ReturnType<typeof createLogger>\n): Promise<number> {\n let state = devStates.get(absDocsRoot);\n if (!state) {\n state = { port: await pickFreePort(), spawned: false };\n devStates.set(absDocsRoot, state);\n }\n if (!state.spawned) {\n state.spawned = true;\n const cli = resolveCli(options.command, process.cwd());\n log.info(`docs dev (${cli.source}): ${cli.argv.join(\" \")} dev on :${state.port} → rewritten at ${base}`);\n // Next's rewrite proxy is HTTP-only — tell the docs dev not to inject its\n // livereload websocket client (it would just retry against a dead upgrade)\n const spawnOptions = { ...options, env: { ...options.env, XYD_LIVERELOAD: \"0\" } };\n spawnDocsDev(cli.argv, absDocsRoot, state.port, base, spawnOptions, log);\n }\n return state.port;\n}\n\nasync function buildAndMergeIntoPublic(\n root: string,\n absDocsRoot: string,\n base: string,\n options: ReturnType<typeof normalizeOptions>,\n log: ReturnType<typeof createLogger>\n): Promise<void> {\n const publicDir = path.join(root, \"public\");\n fs.mkdirSync(publicDir, { recursive: true });\n\n // clean the PREVIOUS generation first — a rebuild would otherwise conflict\n // with its own stale output (changed pages = same path, different content)\n const manifestPath = path.join(publicDir, MANIFEST);\n if (fs.existsSync(manifestPath)) {\n try {\n const prev: { files: string[] } = JSON.parse(fs.readFileSync(manifestPath, \"utf-8\"));\n for (const rel of prev.files || []) {\n fs.rmSync(path.join(publicDir, rel), { force: true });\n }\n pruneEmptyDirs(publicDir);\n } catch {\n /* unreadable manifest — the merge's conflict detection still protects */\n }\n }\n\n const cli = resolveCli(options.command, root);\n log.info(`building docs (${cli.source}): ${cli.argv.join(\" \")} build [cwd ${absDocsRoot}]`);\n const startedAt = Date.now();\n await runDocsBuild(cli.argv, absDocsRoot, options, log);\n\n const before = snapshotFiles(publicDir);\n const docsClientDir = path.join(absDocsRoot, \".xyd\", \"build\", \"client\");\n const summary = mergeDocsBuild(docsClientDir, publicDir, {\n base,\n sitemap: options.sitemap,\n robots: options.robots,\n });\n\n // manifest = everything that appeared during the merge\n const generated = snapshotFiles(publicDir).filter((f) => !before.includes(f) && f !== MANIFEST);\n fs.writeFileSync(manifestPath, JSON.stringify({ files: generated }, null, 2));\n\n const secs = ((Date.now() - startedAt) / 1000).toFixed(1);\n for (const note of summary.notes) log.info(note);\n log.info(\n `merged docs into public/ — mount ${summary.mount}, ${summary.pages} pages, ${summary.assets} assets` +\n (summary.skippedIdentical ? ` (+${summary.skippedIdentical} identical skipped)` : \"\") +\n `, ${secs}s`\n );\n}\n\n/** exported for tests */\nexport async function composeRewrites(userRewrites: any, ours: any[]): Promise<any> {\n const user = typeof userRewrites === \"function\" ? await userRewrites() : userRewrites;\n if (!user) {\n return { beforeFiles: [], afterFiles: ours, fallback: [] };\n }\n if (Array.isArray(user)) {\n // plain-array rewrites are afterFiles-equivalent in Next\n return { beforeFiles: [], afterFiles: [...user, ...ours], fallback: [] };\n }\n return { ...user, afterFiles: [...(user.afterFiles || []), ...ours] };\n}\n\n/** `advanced.basename` from a statically readable docs.json (normalized), else undefined. */\nfunction readSettingsBasename(absDocsRoot: string): string | undefined {\n try {\n const settings = JSON.parse(fs.readFileSync(path.join(absDocsRoot, \"docs.json\"), \"utf-8\"));\n const basename = settings?.advanced?.basename;\n return basename ? normalizeBase(String(basename)) : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction snapshotFiles(dir: string): string[] {\n const out: string[] = [];\n const walk = (d: string) => {\n for (const entry of fs.readdirSync(d, { withFileTypes: true })) {\n const abs = path.join(d, entry.name);\n if (entry.isDirectory()) walk(abs);\n else out.push(path.relative(dir, abs).split(path.sep).join(\"/\"));\n }\n };\n if (fs.existsSync(dir)) walk(dir);\n return out;\n}\n\nfunction pruneEmptyDirs(dir: string): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const abs = path.join(dir, entry.name);\n pruneEmptyDirs(abs);\n if (!fs.readdirSync(abs).length) fs.rmdirSync(abs);\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xyd-js/next-plugin",
|
|
3
|
+
"version": "0.0.0-build-cdbb0d7-20260901160230",
|
|
4
|
+
"description": "Next.js plugin that builds xyd docs during `next build` and serves them under a subpath of your app — with a spawned `xyd dev` + proxy rewrites in `next dev`",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"xyd",
|
|
21
|
+
"next",
|
|
22
|
+
"nextjs",
|
|
23
|
+
"docs",
|
|
24
|
+
"documentation"
|
|
25
|
+
],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@xyd-js/vite-plugin": "0.0.0-build-cdbb0d7-20260901160230"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"rimraf": "^3.0.2",
|
|
31
|
+
"tsup": "^8.3.0",
|
|
32
|
+
"vitest": "^2.1.8"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"clean": "rimraf dist",
|
|
36
|
+
"prebuild": "pnpm clean",
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"test": "vitest",
|
|
39
|
+
"ci:test": "vitest run"
|
|
40
|
+
}
|
|
41
|
+
}
|