@knitli/astro-docs-template 0.1.0 → 0.1.2
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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +137 -0
- package/dist/config.d.ts +59 -0
- package/dist/config.d.ts.map +1 -0
- package/{src/config.ts → dist/config.js} +164 -250
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +150 -0
- package/package.json +16 -6
- package/scaffolding/package.json +7 -3
- package/src/index.ts +0 -128
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { stdout, stdin } from 'node:process';
|
|
3
|
+
import { createInterface } from 'node:readline/promises';
|
|
4
|
+
import { PIECES, PIECE_NAMES, addPieces, initDocsTemplate } from './index.js';
|
|
5
|
+
|
|
6
|
+
function parseArgs(argv) {
|
|
7
|
+
const flags = {};
|
|
8
|
+
const positional = [];
|
|
9
|
+
for (let i = 0; i < argv.length; i++) {
|
|
10
|
+
const arg = argv[i];
|
|
11
|
+
if (arg === "--help" || arg === "-h") {
|
|
12
|
+
flags.help = "true";
|
|
13
|
+
} else if (arg === "--force" || arg === "-f") {
|
|
14
|
+
flags.force = "true";
|
|
15
|
+
} else if (arg.startsWith("--") && i + 1 < argv.length) {
|
|
16
|
+
flags[arg.slice(2)] = argv[++i];
|
|
17
|
+
} else {
|
|
18
|
+
positional.push(arg);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { flags, positional };
|
|
22
|
+
}
|
|
23
|
+
const HELP = `knitli-docs — scaffold and manage Knitli docs sites
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
knitli-docs init [dir] Full scaffold into dir (default: .)
|
|
27
|
+
knitli-docs add <piece...> [--dir d] Add specific pieces to a project
|
|
28
|
+
knitli-docs list Show available pieces
|
|
29
|
+
|
|
30
|
+
Pieces:
|
|
31
|
+
${Object.entries(PIECES).map(([name, { description }]) => ` ${name.padEnd(18)} ${description}`).join("\n")}
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
--app-name <name> Product name (e.g. "Recoco")
|
|
35
|
+
--name <pkg> npm package name (e.g. "@knitli-site/recoco-docs")
|
|
36
|
+
--description <desc> Short product description
|
|
37
|
+
--worker-name <name> Cloudflare Worker name (default: <appname>-docs)
|
|
38
|
+
--dir <path> Target directory for 'add' (default: .)
|
|
39
|
+
--force, -f Overwrite existing files
|
|
40
|
+
--help, -h Show this help
|
|
41
|
+
`;
|
|
42
|
+
async function getOptions(flags) {
|
|
43
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
44
|
+
const ask = async (question, defaultValue) => {
|
|
45
|
+
const suffix = defaultValue ? ` [${defaultValue}]` : "";
|
|
46
|
+
const answer = await rl.question(`${question}${suffix}: `);
|
|
47
|
+
return answer.trim() || defaultValue || "";
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
const appName = flags["app-name"] || await ask("Product name (e.g. Recoco)");
|
|
51
|
+
if (!appName) {
|
|
52
|
+
console.error("Error: product name is required");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const name = flags.name || await ask(
|
|
56
|
+
"npm package name",
|
|
57
|
+
`@knitli-site/${appName.toLowerCase()}-docs`
|
|
58
|
+
);
|
|
59
|
+
const description = flags.description || await ask("Short description");
|
|
60
|
+
const workerName = flags["worker-name"] || await ask("Worker name", `${appName.toLowerCase()}-docs`);
|
|
61
|
+
return { appName, name, description, workerName };
|
|
62
|
+
} finally {
|
|
63
|
+
rl.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function main() {
|
|
67
|
+
const { flags, positional } = parseArgs(process.argv.slice(2));
|
|
68
|
+
const command = positional[0];
|
|
69
|
+
if (flags.help || !command) {
|
|
70
|
+
console.log(HELP);
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
switch (command) {
|
|
74
|
+
case "list": {
|
|
75
|
+
console.log("\nAvailable pieces:\n");
|
|
76
|
+
for (const [name, { description, paths }] of Object.entries(PIECES)) {
|
|
77
|
+
console.log(` ${name.padEnd(18)} ${description}`);
|
|
78
|
+
for (const p of paths) {
|
|
79
|
+
console.log(` ${"".padEnd(18)} └ ${p}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
console.log();
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case "init": {
|
|
86
|
+
const dir = flags.dir || positional[1] || ".";
|
|
87
|
+
const options = await getOptions(flags);
|
|
88
|
+
console.log(`
|
|
89
|
+
Scaffolding into ${dir} ...
|
|
90
|
+
`);
|
|
91
|
+
const created = initDocsTemplate(dir, options);
|
|
92
|
+
console.log(`
|
|
93
|
+
Done — ${created.length} files created`);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case "add": {
|
|
97
|
+
const pieces = positional.slice(1).filter((p) => !p.startsWith("-"));
|
|
98
|
+
if (pieces.length === 0) {
|
|
99
|
+
console.error(
|
|
100
|
+
"Error: specify at least one piece. Run 'knitli-docs list' to see options."
|
|
101
|
+
);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
const invalid = pieces.filter(
|
|
105
|
+
(p) => !PIECE_NAMES.includes(p)
|
|
106
|
+
);
|
|
107
|
+
if (invalid.length > 0) {
|
|
108
|
+
console.error(`Error: unknown piece(s): ${invalid.join(", ")}`);
|
|
109
|
+
console.error(`Available: ${PIECE_NAMES.join(", ")}`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
const dir = flags.dir || ".";
|
|
113
|
+
const options = await getOptions(flags);
|
|
114
|
+
console.log(`
|
|
115
|
+
Adding ${pieces.join(", ")} to ${dir} ...
|
|
116
|
+
`);
|
|
117
|
+
const created = addPieces(dir, {
|
|
118
|
+
...options,
|
|
119
|
+
pieces,
|
|
120
|
+
force: flags.force === "true"
|
|
121
|
+
});
|
|
122
|
+
console.log(`
|
|
123
|
+
Done — ${created.length} files created`);
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
default: {
|
|
127
|
+
console.error(`Unknown command: ${command}
|
|
128
|
+
`);
|
|
129
|
+
console.log(HELP);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
main().catch((err) => {
|
|
135
|
+
console.error(err.message);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
});
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { OutgoingHttpHeaders } from "node:http2";
|
|
2
|
+
type defaultIntegration = "sitemap" | "astroD2" | "markdoc" | "mdx" | "favicons" | "cloudflare-pages-headers";
|
|
3
|
+
export declare const headlineLogoDark: string, headlineLogoLight: string, variables: string, docsStyle: string, faviconIco: string, faviconSvg: string;
|
|
4
|
+
declare const shikiCfg: {
|
|
5
|
+
themes: {
|
|
6
|
+
light: "catppuccin-latte";
|
|
7
|
+
dark: "catppuccin-mocha";
|
|
8
|
+
};
|
|
9
|
+
bundledLangs: string[];
|
|
10
|
+
langAlias: {
|
|
11
|
+
js: string;
|
|
12
|
+
md: string;
|
|
13
|
+
py: string;
|
|
14
|
+
rs: string;
|
|
15
|
+
sh: string;
|
|
16
|
+
yml: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
declare const imgDomains: {
|
|
20
|
+
protocol: string;
|
|
21
|
+
hostname: string;
|
|
22
|
+
}[];
|
|
23
|
+
export interface DocsTemplateOptions {
|
|
24
|
+
appName: string;
|
|
25
|
+
description: string;
|
|
26
|
+
llmConfig: {
|
|
27
|
+
llmDescription: string;
|
|
28
|
+
promotePatterns: string[];
|
|
29
|
+
demotePatterns: string[];
|
|
30
|
+
};
|
|
31
|
+
rootDir: string;
|
|
32
|
+
shikiConfig?: typeof shikiCfg;
|
|
33
|
+
logoDark?: string;
|
|
34
|
+
logoLight?: string;
|
|
35
|
+
imageDomains?: typeof imgDomains;
|
|
36
|
+
is_codeweaver?: boolean;
|
|
37
|
+
sitemapFilter?: (page: string) => boolean;
|
|
38
|
+
linkValidationConfig?: Record<string, unknown>;
|
|
39
|
+
sidebarConfig?: {
|
|
40
|
+
label: string;
|
|
41
|
+
autogenerate: {
|
|
42
|
+
directory: string;
|
|
43
|
+
};
|
|
44
|
+
}[];
|
|
45
|
+
unwantedPlugins?: string[];
|
|
46
|
+
pluginConfigs?: Record<string, any>;
|
|
47
|
+
unwantedIntegrations?: defaultIntegration[];
|
|
48
|
+
integrationConfigs?: Record<string, any>;
|
|
49
|
+
headersConfig?: OutgoingHttpHeaders;
|
|
50
|
+
}
|
|
51
|
+
export type IntegrationOptions = Pick<DocsTemplateOptions, "appName" | "sitemapFilter" | "integrationConfigs"> & {
|
|
52
|
+
unwantedIntegrations?: defaultIntegration[];
|
|
53
|
+
};
|
|
54
|
+
export type PluginOptions = Pick<DocsTemplateOptions, "appName" | "llmConfig" | "pluginConfigs"> & {
|
|
55
|
+
unwantedPlugins?: string[];
|
|
56
|
+
};
|
|
57
|
+
export default function createConfig(options: DocsTemplateOptions): import("astro").AstroUserConfig<never, never, never>;
|
|
58
|
+
export {};
|
|
59
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AA6BtD,KAAK,kBAAkB,GACnB,SAAS,GACT,SAAS,GACT,SAAS,GACT,KAAK,GACL,UAAU,GACV,0BAA0B,CAAC;AAQ/B,eAAO,MACL,gBAAgB,UAChB,iBAAiB,UACjB,SAAS,UACT,SAAS,UACT,UAAU,UACV,UAAU,QACE,CAAC;AAEf,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;CAyBb,CAAC;AAEF,QAAA,MAAM,UAAU;;;GAMf,CAAC;AA8DF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE;QACT,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,EAAE,CAAC;QAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,QAAQ,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,UAAU,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE;QACd,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE;YAAE,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;KACrC,EAAE,CAAC;IACJ,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,oBAAoB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAE5C,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACrC;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,mBAAmB,EACnB,SAAS,GAAG,eAAe,GAAG,oBAAoB,CACnD,GAAG;IAAE,oBAAoB,CAAC,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAAC;AA+DpD,MAAM,MAAM,aAAa,GAAG,IAAI,CAC9B,mBAAmB,EACnB,SAAS,GAAG,WAAW,GAAG,eAAe,CAC1C,GAAG;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAoEnC,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,OAAO,EAAE,mBAAmB,wDAuOhE"}
|
|
@@ -1,65 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import cloudflare from '@astrojs/cloudflare';
|
|
2
|
+
import markdoc from '@astrojs/markdoc';
|
|
3
|
+
import mdx from '@astrojs/mdx';
|
|
4
|
+
import sitemap from '@astrojs/sitemap';
|
|
5
|
+
import starlight from '@astrojs/starlight';
|
|
6
|
+
import { DocsAssets } from '@knitli/docs-components';
|
|
7
|
+
import llmEnhancements from '@nuasite/llm-enhancements';
|
|
8
|
+
import { fontProviders, defineConfig } from 'astro/config';
|
|
9
|
+
import cloudflarePagesHeaders from 'astro-cloudflare-pages-headers';
|
|
10
|
+
import astroD2 from 'astro-d2';
|
|
11
|
+
import favicons from 'astro-favicons';
|
|
12
|
+
import rehypeExternalLinks from 'rehype-external-links';
|
|
13
|
+
import starlightAnnouncement from 'starlight-announcement';
|
|
14
|
+
import starlightChangelogs from 'starlight-changelogs';
|
|
15
|
+
import starlightHeadingBadges from 'starlight-heading-badges';
|
|
16
|
+
import starlightLinksValidator from 'starlight-links-validator';
|
|
17
|
+
import starlightLlmsText from 'starlight-llms-txt';
|
|
18
|
+
import starlightPageActions from 'starlight-page-actions';
|
|
19
|
+
import { starlightIconsIntegration, starlightIconsPlugin } from 'starlight-plugin-icons';
|
|
20
|
+
import starlightScrollToTop from 'starlight-scroll-to-top';
|
|
21
|
+
import starlightSidebarTopics from 'starlight-sidebar-topics';
|
|
22
|
+
import starlightTags from 'starlight-tags';
|
|
23
|
+
import { searchForWorkspaceRoot } from 'vite';
|
|
24
|
+
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
|
4
25
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import type { OutgoingHttpHeaders } from "node:http2";
|
|
8
|
-
import cloudflare from "@astrojs/cloudflare";
|
|
9
|
-
import markdoc from "@astrojs/markdoc";
|
|
10
|
-
import mdx from "@astrojs/mdx";
|
|
11
|
-
import sitemap from "@astrojs/sitemap";
|
|
12
|
-
import starlight from "@astrojs/starlight";
|
|
13
|
-
import { DocsAssets } from "@knitli/docs-components";
|
|
14
|
-
import llmEnhancements from "@nuasite/llm-enhancements";
|
|
15
|
-
import { defineConfig, fontProviders } from "astro/config";
|
|
16
|
-
import cloudflarePagesHeaders from "astro-cloudflare-pages-headers";
|
|
17
|
-
import astroD2 from "astro-d2";
|
|
18
|
-
import favicons from "astro-favicons";
|
|
19
|
-
import rehypeExternalLinks from "rehype-external-links";
|
|
20
|
-
import starlightAnnouncement from "starlight-announcement";
|
|
21
|
-
import starlightChangelogs from "starlight-changelogs";
|
|
22
|
-
import starlightHeadingBadges from "starlight-heading-badges";
|
|
23
|
-
import starlightLinksValidator from "starlight-links-validator";
|
|
24
|
-
import starlightLlmsText from "starlight-llms-txt";
|
|
25
|
-
import starlightPageActions from "starlight-page-actions";
|
|
26
|
-
import {
|
|
27
|
-
starlightIconsIntegration,
|
|
28
|
-
starlightIconsPlugin,
|
|
29
|
-
} from "starlight-plugin-icons";
|
|
30
|
-
import starlightScrollToTop from "starlight-scroll-to-top";
|
|
31
|
-
import starlightSidebarTopics from "starlight-sidebar-topics";
|
|
32
|
-
import starlightTags from "starlight-tags";
|
|
33
|
-
import { searchForWorkspaceRoot } from "vite";
|
|
34
|
-
import viteTsconfigPaths from "vite-tsconfig-paths";
|
|
35
|
-
|
|
36
|
-
type defaultIntegration =
|
|
37
|
-
| "sitemap"
|
|
38
|
-
| "astroD2"
|
|
39
|
-
| "markdoc"
|
|
40
|
-
| "mdx"
|
|
41
|
-
| "favicons"
|
|
42
|
-
| "cloudflare-pages-headers";
|
|
43
|
-
|
|
44
|
-
function nonNullable<T>(value: T): value is NonNullable<T> {
|
|
26
|
+
function nonNullable(value) {
|
|
45
27
|
return value != null;
|
|
46
28
|
}
|
|
47
|
-
|
|
48
|
-
// ── Defaults (defined before interface so `typeof` references work) ──
|
|
49
|
-
|
|
50
|
-
export const {
|
|
29
|
+
const {
|
|
51
30
|
headlineLogoDark,
|
|
52
31
|
headlineLogoLight,
|
|
53
32
|
variables,
|
|
54
33
|
docsStyle,
|
|
55
34
|
faviconIco,
|
|
56
|
-
faviconSvg
|
|
35
|
+
faviconSvg
|
|
57
36
|
} = DocsAssets;
|
|
58
|
-
|
|
59
37
|
const shikiCfg = {
|
|
60
38
|
themes: {
|
|
61
|
-
light: "catppuccin-latte"
|
|
62
|
-
dark: "catppuccin-mocha"
|
|
39
|
+
light: "catppuccin-latte",
|
|
40
|
+
dark: "catppuccin-mocha"
|
|
63
41
|
},
|
|
64
42
|
bundledLangs: [
|
|
65
43
|
"ansi",
|
|
@@ -71,7 +49,7 @@ const shikiCfg = {
|
|
|
71
49
|
"rust",
|
|
72
50
|
"toml",
|
|
73
51
|
"typescript",
|
|
74
|
-
"yaml"
|
|
52
|
+
"yaml"
|
|
75
53
|
],
|
|
76
54
|
langAlias: {
|
|
77
55
|
js: "typescript",
|
|
@@ -79,64 +57,61 @@ const shikiCfg = {
|
|
|
79
57
|
py: "python",
|
|
80
58
|
rs: "rust",
|
|
81
59
|
sh: "bash",
|
|
82
|
-
yml: "yaml"
|
|
83
|
-
}
|
|
60
|
+
yml: "yaml"
|
|
61
|
+
}
|
|
84
62
|
};
|
|
85
|
-
|
|
86
63
|
const imgDomains = [
|
|
87
64
|
{ protocol: "https", hostname: "ui-avatars.com" },
|
|
88
65
|
{ protocol: "https", hostname: "knitli.com" },
|
|
89
66
|
{ protocol: "https", hostname: "*.knitli.com" },
|
|
90
67
|
{ protocol: "https", hostname: "*.githubusercontent.com" },
|
|
91
|
-
{ protocol: "https", hostname: "*.cloudflare.com" }
|
|
68
|
+
{ protocol: "https", hostname: "*.cloudflare.com" }
|
|
92
69
|
];
|
|
93
|
-
|
|
94
70
|
const defaultFontConfig = [
|
|
95
71
|
{
|
|
96
72
|
provider: fontProviders.google(),
|
|
97
73
|
name: "DM Mono",
|
|
98
74
|
cssVariable: "--font-sans",
|
|
99
|
-
weights: [400, 500, 700]
|
|
100
|
-
styles: ["normal", "italic"]
|
|
101
|
-
subsets: ["latin"]
|
|
102
|
-
formats: ["woff2"]
|
|
75
|
+
weights: [400, 500, 700],
|
|
76
|
+
styles: ["normal", "italic"],
|
|
77
|
+
subsets: ["latin"],
|
|
78
|
+
formats: ["woff2"],
|
|
103
79
|
fallbacks: [
|
|
104
80
|
"Roboto Mono",
|
|
105
81
|
"Menlo",
|
|
106
82
|
"Consolas",
|
|
107
83
|
"DejaVu Sans Mono",
|
|
108
|
-
"monospace"
|
|
109
|
-
]
|
|
84
|
+
"monospace"
|
|
85
|
+
]
|
|
110
86
|
},
|
|
111
87
|
{
|
|
112
88
|
provider: fontProviders.google(),
|
|
113
89
|
name: "JetBrains Mono",
|
|
114
90
|
cssVariable: "--font-mono",
|
|
115
|
-
weights: [400, 500, 700]
|
|
116
|
-
styles: ["normal", "italic"]
|
|
117
|
-
subsets: ["latin"]
|
|
118
|
-
formats: ["woff2"]
|
|
91
|
+
weights: [400, 500, 700],
|
|
92
|
+
styles: ["normal", "italic"],
|
|
93
|
+
subsets: ["latin"],
|
|
94
|
+
formats: ["woff2"],
|
|
119
95
|
fallbacks: [
|
|
120
96
|
"DM Mono",
|
|
121
97
|
"Roboto Mono",
|
|
122
98
|
"Menlo",
|
|
123
99
|
"Consolas",
|
|
124
100
|
"DejaVu Sans Mono",
|
|
125
|
-
"monospace"
|
|
126
|
-
]
|
|
127
|
-
}
|
|
101
|
+
"monospace"
|
|
102
|
+
]
|
|
103
|
+
}
|
|
128
104
|
];
|
|
129
|
-
|
|
130
105
|
const codeweaverFontConfig = [
|
|
131
106
|
{ ...defaultFontConfig[1], cssVariable: "--font-sans" },
|
|
132
107
|
{
|
|
133
108
|
provider: fontProviders.google(),
|
|
134
109
|
name: "IBM Plex Mono",
|
|
135
110
|
cssVariable: "--font-mono",
|
|
136
|
-
weights: [400, 500, 700]
|
|
137
|
-
styles: ["normal", "italic"]
|
|
138
|
-
subsets: ["latin"]
|
|
139
|
-
formats: ["woff2"]
|
|
111
|
+
weights: [400, 500, 700],
|
|
112
|
+
styles: ["normal", "italic"],
|
|
113
|
+
subsets: ["latin"],
|
|
114
|
+
formats: ["woff2"],
|
|
140
115
|
fallbacks: [
|
|
141
116
|
"JetBrains Mono",
|
|
142
117
|
"DM Mono",
|
|
@@ -144,53 +119,16 @@ const codeweaverFontConfig = [
|
|
|
144
119
|
"Menlo",
|
|
145
120
|
"Consolas",
|
|
146
121
|
"DejaVu Sans Mono",
|
|
147
|
-
"monospace"
|
|
148
|
-
]
|
|
149
|
-
}
|
|
122
|
+
"monospace"
|
|
123
|
+
]
|
|
124
|
+
}
|
|
150
125
|
];
|
|
151
|
-
|
|
152
|
-
// ── Public interface ──
|
|
153
|
-
|
|
154
|
-
export interface DocsTemplateOptions {
|
|
155
|
-
appName: string;
|
|
156
|
-
description: string;
|
|
157
|
-
llmConfig: {
|
|
158
|
-
llmDescription: string;
|
|
159
|
-
promotePatterns: string[];
|
|
160
|
-
demotePatterns: string[];
|
|
161
|
-
};
|
|
162
|
-
rootDir: string;
|
|
163
|
-
shikiConfig?: typeof shikiCfg;
|
|
164
|
-
logoDark?: string;
|
|
165
|
-
logoLight?: string;
|
|
166
|
-
imageDomains?: typeof imgDomains;
|
|
167
|
-
is_codeweaver?: boolean;
|
|
168
|
-
sitemapFilter?: (page: string) => boolean;
|
|
169
|
-
linkValidationConfig?: Record<string, unknown>;
|
|
170
|
-
sidebarConfig?: {
|
|
171
|
-
label: string;
|
|
172
|
-
autogenerate: { directory: string };
|
|
173
|
-
}[];
|
|
174
|
-
unwantedPlugins?: string[];
|
|
175
|
-
// biome-ignore lint/suspicious/noExplicitAny: plugin configs are opaque pass-throughs
|
|
176
|
-
pluginConfigs?: Record<string, any>;
|
|
177
|
-
unwantedIntegrations?: defaultIntegration[];
|
|
178
|
-
// biome-ignore lint/suspicious/noExplicitAny: integration configs are opaque pass-throughs
|
|
179
|
-
integrationConfigs?: Record<string, any>;
|
|
180
|
-
headersConfig?: OutgoingHttpHeaders;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export type IntegrationOptions = Pick<
|
|
184
|
-
DocsTemplateOptions,
|
|
185
|
-
"appName" | "sitemapFilter" | "integrationConfigs"
|
|
186
|
-
> & { unwantedIntegrations?: defaultIntegration[] };
|
|
187
|
-
|
|
188
|
-
const getIntegrations = (options: IntegrationOptions) => {
|
|
126
|
+
const getIntegrations = (options) => {
|
|
189
127
|
const {
|
|
190
128
|
appName,
|
|
191
129
|
sitemapFilter,
|
|
192
130
|
integrationConfigs,
|
|
193
|
-
unwantedIntegrations = []
|
|
131
|
+
unwantedIntegrations = []
|
|
194
132
|
} = options;
|
|
195
133
|
const defaultIntegrations = [
|
|
196
134
|
astroD2({ skipGeneration: true }),
|
|
@@ -201,57 +139,45 @@ const getIntegrations = (options: IntegrationOptions) => {
|
|
|
201
139
|
name: `${appName} Docs by Knitli`,
|
|
202
140
|
short_name: `${appName} Docs`,
|
|
203
141
|
input: {
|
|
204
|
-
favicons: [faviconSvg]
|
|
205
|
-
}
|
|
142
|
+
favicons: [faviconSvg]
|
|
143
|
+
}
|
|
206
144
|
}),
|
|
207
145
|
cloudflarePagesHeaders({}),
|
|
208
146
|
sitemap({
|
|
209
147
|
filter: sitemapFilter || ((page) => !/\^\/(?!cdn-cgi\/)/.test(page)),
|
|
210
148
|
changefreq: "weekly",
|
|
211
149
|
priority: 0.4,
|
|
212
|
-
lastmod: new Date(),
|
|
150
|
+
lastmod: /* @__PURE__ */ new Date(),
|
|
213
151
|
namespaces: {
|
|
214
152
|
image: false,
|
|
215
|
-
video: false
|
|
216
|
-
}
|
|
217
|
-
})
|
|
153
|
+
video: false
|
|
154
|
+
}
|
|
155
|
+
})
|
|
218
156
|
];
|
|
219
|
-
|
|
220
157
|
const filtered = defaultIntegrations.filter((integration) => {
|
|
221
158
|
const name = integration?.name;
|
|
222
|
-
return !name || !unwantedIntegrations.includes(name
|
|
159
|
+
return !name || !unwantedIntegrations.includes(name);
|
|
223
160
|
});
|
|
224
|
-
|
|
225
161
|
if (!integrationConfigs) return filtered;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
})
|
|
244
|
-
.filter(nonNullable);
|
|
245
|
-
|
|
162
|
+
const overrides = Object.entries(integrationConfigs).map(([integrationName, config]) => {
|
|
163
|
+
switch (integrationName) {
|
|
164
|
+
case "astroD2":
|
|
165
|
+
return astroD2(config);
|
|
166
|
+
case "markdoc":
|
|
167
|
+
return markdoc(config);
|
|
168
|
+
case "mdx":
|
|
169
|
+
return mdx(config);
|
|
170
|
+
case "favicons":
|
|
171
|
+
return favicons(config);
|
|
172
|
+
case "sitemap":
|
|
173
|
+
return sitemap(config);
|
|
174
|
+
default:
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}).filter(nonNullable);
|
|
246
178
|
return [...filtered, ...overrides];
|
|
247
179
|
};
|
|
248
|
-
|
|
249
|
-
export type PluginOptions = Pick<
|
|
250
|
-
DocsTemplateOptions,
|
|
251
|
-
"appName" | "llmConfig" | "pluginConfigs"
|
|
252
|
-
> & { unwantedPlugins?: string[] };
|
|
253
|
-
|
|
254
|
-
const get_plugins = (options: PluginOptions) => {
|
|
180
|
+
const get_plugins = (options) => {
|
|
255
181
|
const { appName, llmConfig, pluginConfigs, unwantedPlugins = [] } = options;
|
|
256
182
|
const defaultPlugins = [
|
|
257
183
|
starlightAnnouncement(),
|
|
@@ -263,12 +189,10 @@ const get_plugins = (options: PluginOptions) => {
|
|
|
263
189
|
starlightPageActions({
|
|
264
190
|
baseUrl: `https://docs.knitli.com/${appName.toLowerCase()}`,
|
|
265
191
|
actions: { claude: true, chatgpt: true, markdown: true },
|
|
266
|
-
share: true
|
|
192
|
+
share: true
|
|
267
193
|
}),
|
|
268
194
|
starlightTags({ onInlineTagsNotFound: "warn" }),
|
|
269
|
-
pluginConfigs?.starlightSidebarTopics
|
|
270
|
-
? starlightSidebarTopics(pluginConfigs.starlightSidebarTopics)
|
|
271
|
-
: null,
|
|
195
|
+
pluginConfigs?.starlightSidebarTopics ? starlightSidebarTopics(pluginConfigs.starlightSidebarTopics) : null,
|
|
272
196
|
starlightScrollToTop({ showOnHomepage: false }),
|
|
273
197
|
// We need to configure starlight-tags with a tags.yml.
|
|
274
198
|
//starlightTags(),
|
|
@@ -280,44 +204,35 @@ const get_plugins = (options: PluginOptions) => {
|
|
|
280
204
|
minify: {
|
|
281
205
|
whitespace: true,
|
|
282
206
|
note: true,
|
|
283
|
-
details: true
|
|
284
|
-
},
|
|
285
|
-
}),
|
|
286
|
-
];
|
|
287
|
-
|
|
288
|
-
const filtered = defaultPlugins
|
|
289
|
-
.filter(nonNullable)
|
|
290
|
-
.filter((plugin) => !unwantedPlugins.includes(plugin.name));
|
|
291
|
-
|
|
292
|
-
if (!pluginConfigs) return filtered;
|
|
293
|
-
|
|
294
|
-
const overrides = Object.entries(pluginConfigs)
|
|
295
|
-
.map(([pluginName, config]) => {
|
|
296
|
-
switch (pluginName) {
|
|
297
|
-
case "starlightAnnouncement":
|
|
298
|
-
return starlightAnnouncement(config);
|
|
299
|
-
case "starlightIconsIntegration":
|
|
300
|
-
return starlightIconsIntegration(config);
|
|
301
|
-
case "starlightIconsPlugin":
|
|
302
|
-
return starlightIconsPlugin(config);
|
|
303
|
-
case "starlightLinksValidator":
|
|
304
|
-
return starlightLinksValidator(config);
|
|
305
|
-
case "starlightPageActions":
|
|
306
|
-
return starlightPageActions(config);
|
|
307
|
-
case "starlightTags":
|
|
308
|
-
return starlightTags(config);
|
|
309
|
-
case "starlightScrollToTop":
|
|
310
|
-
return starlightScrollToTop(config);
|
|
311
|
-
default:
|
|
312
|
-
return null;
|
|
207
|
+
details: true
|
|
313
208
|
}
|
|
314
209
|
})
|
|
315
|
-
|
|
316
|
-
|
|
210
|
+
];
|
|
211
|
+
const filtered = defaultPlugins.filter(nonNullable).filter((plugin) => !unwantedPlugins.includes(plugin.name));
|
|
212
|
+
if (!pluginConfigs) return filtered;
|
|
213
|
+
const overrides = Object.entries(pluginConfigs).map(([pluginName, config]) => {
|
|
214
|
+
switch (pluginName) {
|
|
215
|
+
case "starlightAnnouncement":
|
|
216
|
+
return starlightAnnouncement(config);
|
|
217
|
+
case "starlightIconsIntegration":
|
|
218
|
+
return starlightIconsIntegration(config);
|
|
219
|
+
case "starlightIconsPlugin":
|
|
220
|
+
return starlightIconsPlugin(config);
|
|
221
|
+
case "starlightLinksValidator":
|
|
222
|
+
return starlightLinksValidator(config);
|
|
223
|
+
case "starlightPageActions":
|
|
224
|
+
return starlightPageActions(config);
|
|
225
|
+
case "starlightTags":
|
|
226
|
+
return starlightTags(config);
|
|
227
|
+
case "starlightScrollToTop":
|
|
228
|
+
return starlightScrollToTop(config);
|
|
229
|
+
default:
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}).filter(nonNullable);
|
|
317
233
|
return [...filtered, ...overrides];
|
|
318
234
|
};
|
|
319
|
-
|
|
320
|
-
export default function createConfig(options: DocsTemplateOptions) {
|
|
235
|
+
function createConfig(options) {
|
|
321
236
|
const {
|
|
322
237
|
appName,
|
|
323
238
|
description,
|
|
@@ -334,59 +249,57 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
334
249
|
integrationConfigs,
|
|
335
250
|
unwantedIntegrations,
|
|
336
251
|
unwantedPlugins,
|
|
337
|
-
headersConfig
|
|
252
|
+
headersConfig
|
|
338
253
|
} = options;
|
|
339
|
-
|
|
340
|
-
// https://astro.build/config
|
|
341
254
|
return defineConfig({
|
|
342
255
|
site: "https://docs.knitli.com",
|
|
343
256
|
base: `/${appName.toLowerCase()}/`,
|
|
344
257
|
adapter: cloudflare({
|
|
345
258
|
prerenderEnvironment: "workerd",
|
|
346
259
|
experimental: {
|
|
347
|
-
headersAndRedirectsDevModeSupport: true
|
|
260
|
+
headersAndRedirectsDevModeSupport: true
|
|
348
261
|
},
|
|
349
262
|
configPath: `${rootDir}/wrangler.jsonc`,
|
|
350
|
-
imageService: "compile"
|
|
263
|
+
imageService: "compile"
|
|
351
264
|
}),
|
|
352
265
|
// Image optimization
|
|
353
266
|
image: {
|
|
354
267
|
service: {
|
|
355
|
-
entrypoint: "astro/assets/services/sharp"
|
|
268
|
+
entrypoint: "astro/assets/services/sharp"
|
|
356
269
|
},
|
|
357
270
|
responsiveStyles: true,
|
|
358
271
|
layout: "constrained",
|
|
359
|
-
remotePatterns: imageDomains
|
|
272
|
+
remotePatterns: imageDomains
|
|
360
273
|
},
|
|
361
274
|
compressHTML: true,
|
|
362
275
|
// biome-ignore lint/suspicious/noExplicitAny: Astro's FontFamily generic inference doesn't match spread patterns
|
|
363
|
-
fonts:
|
|
276
|
+
fonts: is_codeweaver ? codeweaverFontConfig : defaultFontConfig,
|
|
364
277
|
// Build optimizations
|
|
365
278
|
build: {
|
|
366
279
|
inlineStylesheets: "auto",
|
|
367
|
-
assets: "_astro"
|
|
280
|
+
assets: "_astro"
|
|
368
281
|
},
|
|
369
282
|
markdown: {
|
|
370
283
|
shikiConfig: Object.fromEntries(
|
|
371
|
-
Object.entries(shikiConfig).filter(([key]) => key !== "bundledLangs")
|
|
284
|
+
Object.entries(shikiConfig).filter(([key]) => key !== "bundledLangs")
|
|
372
285
|
),
|
|
373
286
|
rehypePlugins: [
|
|
374
287
|
rehypeExternalLinks({
|
|
375
|
-
content: { type: "text", value: "
|
|
376
|
-
rel: ["nofollow"]
|
|
377
|
-
})
|
|
378
|
-
]
|
|
288
|
+
content: { type: "text", value: " ↗" },
|
|
289
|
+
rel: ["nofollow"]
|
|
290
|
+
})
|
|
291
|
+
]
|
|
379
292
|
},
|
|
380
293
|
server: {
|
|
381
|
-
headers: headersConfig
|
|
294
|
+
headers: headersConfig
|
|
382
295
|
},
|
|
383
296
|
trailingSlash: "always",
|
|
384
297
|
// Vite configuration for better bundling
|
|
385
298
|
vite: {
|
|
386
299
|
server: {
|
|
387
300
|
fs: {
|
|
388
|
-
allow: [searchForWorkspaceRoot(rootDir)]
|
|
389
|
-
}
|
|
301
|
+
allow: [searchForWorkspaceRoot(rootDir)]
|
|
302
|
+
}
|
|
390
303
|
},
|
|
391
304
|
assetsInclude: [
|
|
392
305
|
"src/*.webp",
|
|
@@ -394,11 +307,11 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
394
307
|
"src/*.jpg",
|
|
395
308
|
"src/*.jpeg",
|
|
396
309
|
"src/*.svg",
|
|
397
|
-
"src/*.avif"
|
|
310
|
+
"src/*.avif"
|
|
398
311
|
],
|
|
399
312
|
plugins: [viteTsconfigPaths({ loose: true })],
|
|
400
313
|
define: {
|
|
401
|
-
"import.meta.env.PUBLIC_DOCS_PRODUCT": JSON.stringify(appName)
|
|
314
|
+
"import.meta.env.PUBLIC_DOCS_PRODUCT": JSON.stringify(appName)
|
|
402
315
|
},
|
|
403
316
|
build: {
|
|
404
317
|
cssMinify: "lightningcss",
|
|
@@ -411,7 +324,7 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
411
324
|
dir: `${rootDir}/dist/_astro/`,
|
|
412
325
|
compact: true,
|
|
413
326
|
interop: "esModule",
|
|
414
|
-
experimentalMinChunkSize:
|
|
327
|
+
experimentalMinChunkSize: 1e4,
|
|
415
328
|
banner: `
|
|
416
329
|
/* SPDX-FileCopyrightText: 2026 Knitli Inc.
|
|
417
330
|
* SPDX-License-Identifier: MIT OR Apache-2.0
|
|
@@ -423,22 +336,22 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
423
336
|
arrowFunctions: true,
|
|
424
337
|
constBindings: true,
|
|
425
338
|
objectShorthand: true,
|
|
426
|
-
symbols: true
|
|
339
|
+
symbols: true
|
|
427
340
|
},
|
|
428
341
|
entryFileNames: "assets/[name]-[hash].js",
|
|
429
342
|
chunkFileNames: "assets/[name]-[hash].js",
|
|
430
|
-
assetFileNames: "assets/[name]-[hash][extname]"
|
|
343
|
+
assetFileNames: "assets/[name]-[hash][extname]"
|
|
431
344
|
},
|
|
432
|
-
treeshake: "smallest"
|
|
345
|
+
treeshake: "smallest"
|
|
433
346
|
},
|
|
434
|
-
ssr: false
|
|
347
|
+
ssr: false
|
|
435
348
|
},
|
|
436
349
|
css: {
|
|
437
|
-
lightningcss: {}
|
|
438
|
-
}
|
|
350
|
+
lightningcss: {}
|
|
351
|
+
}
|
|
439
352
|
},
|
|
440
353
|
prefetch: {
|
|
441
|
-
defaultStrategy: "viewport"
|
|
354
|
+
defaultStrategy: "viewport"
|
|
442
355
|
},
|
|
443
356
|
prerenderConflictBehavior: "warn",
|
|
444
357
|
experimental: {
|
|
@@ -447,7 +360,7 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
447
360
|
contentIntellisense: true,
|
|
448
361
|
queuedRendering: {
|
|
449
362
|
contentCache: true,
|
|
450
|
-
enabled: true
|
|
363
|
+
enabled: true
|
|
451
364
|
},
|
|
452
365
|
rustCompiler: true,
|
|
453
366
|
svgo: {
|
|
@@ -456,14 +369,13 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
456
369
|
name: "preset-default",
|
|
457
370
|
params: {
|
|
458
371
|
overrides: {
|
|
459
|
-
removeMetadata: false
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
]
|
|
464
|
-
}
|
|
372
|
+
removeMetadata: false
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
]
|
|
377
|
+
}
|
|
465
378
|
},
|
|
466
|
-
|
|
467
379
|
// Static site generation for Cloudflare
|
|
468
380
|
output: "static",
|
|
469
381
|
integrations: [
|
|
@@ -471,20 +383,20 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
471
383
|
appName,
|
|
472
384
|
sitemapFilter,
|
|
473
385
|
integrationConfigs,
|
|
474
|
-
unwantedIntegrations
|
|
386
|
+
unwantedIntegrations
|
|
475
387
|
}),
|
|
476
388
|
starlight({
|
|
477
389
|
title: `${appName} Docs`,
|
|
478
390
|
pagefind: true,
|
|
479
|
-
description
|
|
391
|
+
description,
|
|
480
392
|
logo: {
|
|
481
393
|
dark: logoDark,
|
|
482
394
|
light: logoLight,
|
|
483
395
|
alt: is_codeweaver ? "CodeWeaver Logo" : "Knitli Logo",
|
|
484
|
-
replacesTitle: true
|
|
396
|
+
replacesTitle: true
|
|
485
397
|
},
|
|
486
398
|
editLink: {
|
|
487
|
-
baseUrl: `https://github.com/knitli/${appName.toLowerCase()}/edit/main/docs-site/src
|
|
399
|
+
baseUrl: `https://github.com/knitli/${appName.toLowerCase()}/edit/main/docs-site/src`
|
|
488
400
|
},
|
|
489
401
|
expressiveCode: {
|
|
490
402
|
useStarlightDarkModeSwitch: true,
|
|
@@ -492,27 +404,27 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
492
404
|
removeUnusedThemes: true,
|
|
493
405
|
shiki: {
|
|
494
406
|
...Object.fromEntries(
|
|
495
|
-
Object.entries(shikiConfig).filter(([key]) => key !== "themes")
|
|
496
|
-
)
|
|
497
|
-
}
|
|
407
|
+
Object.entries(shikiConfig).filter(([key]) => key !== "themes")
|
|
408
|
+
)
|
|
409
|
+
}
|
|
498
410
|
},
|
|
499
411
|
plugins: get_plugins({
|
|
500
412
|
appName,
|
|
501
413
|
llmConfig,
|
|
502
414
|
pluginConfigs,
|
|
503
|
-
unwantedPlugins
|
|
415
|
+
unwantedPlugins
|
|
504
416
|
// biome-ignore lint/suspicious/noExplicitAny: Starlight plugin types are complex Zod inferences
|
|
505
|
-
})
|
|
417
|
+
}),
|
|
506
418
|
social: [
|
|
507
419
|
{
|
|
508
420
|
icon: "github",
|
|
509
421
|
label: "GitHub",
|
|
510
|
-
href: `https://github.com/knitli/${appName.toLowerCase()}
|
|
511
|
-
}
|
|
422
|
+
href: `https://github.com/knitli/${appName.toLowerCase()}`
|
|
423
|
+
}
|
|
512
424
|
],
|
|
513
425
|
components: {
|
|
514
426
|
Footer: "@knitli/docs-components/Footer.astro",
|
|
515
|
-
PageFrame: "@knitli/docs-components/PageFrame.astro"
|
|
427
|
+
PageFrame: "@knitli/docs-components/PageFrame.astro"
|
|
516
428
|
},
|
|
517
429
|
customCss: [variables, docsStyle, `${rootDir}/src/styles/custom.css`],
|
|
518
430
|
head: [
|
|
@@ -520,32 +432,34 @@ export default function createConfig(options: DocsTemplateOptions) {
|
|
|
520
432
|
tag: "meta",
|
|
521
433
|
attrs: {
|
|
522
434
|
property: "og:image",
|
|
523
|
-
content: `https://docs.knitli.com/${appName.toLowerCase()}/og-image.png
|
|
524
|
-
}
|
|
435
|
+
content: `https://docs.knitli.com/${appName.toLowerCase()}/og-image.png`
|
|
436
|
+
}
|
|
525
437
|
},
|
|
526
438
|
{
|
|
527
439
|
tag: "meta",
|
|
528
440
|
attrs: {
|
|
529
441
|
property: "twitter:card",
|
|
530
|
-
content: "summary_large_image"
|
|
531
|
-
}
|
|
532
|
-
}
|
|
442
|
+
content: "summary_large_image"
|
|
443
|
+
}
|
|
444
|
+
}
|
|
533
445
|
],
|
|
534
446
|
sidebar: sidebarConfig || [
|
|
535
447
|
{
|
|
536
448
|
label: "Guides",
|
|
537
|
-
autogenerate: { directory: "guides" }
|
|
449
|
+
autogenerate: { directory: "guides" }
|
|
538
450
|
},
|
|
539
451
|
{
|
|
540
452
|
label: "Examples",
|
|
541
|
-
autogenerate: { directory: "examples" }
|
|
453
|
+
autogenerate: { directory: "examples" }
|
|
542
454
|
},
|
|
543
455
|
{
|
|
544
456
|
label: "Reference",
|
|
545
|
-
autogenerate: { directory: "reference" }
|
|
546
|
-
}
|
|
547
|
-
]
|
|
548
|
-
})
|
|
549
|
-
]
|
|
457
|
+
autogenerate: { directory: "reference" }
|
|
458
|
+
}
|
|
459
|
+
]
|
|
460
|
+
})
|
|
461
|
+
]
|
|
550
462
|
});
|
|
551
463
|
}
|
|
464
|
+
|
|
465
|
+
export { createConfig as default, docsStyle, faviconIco, faviconSvg, headlineLogoDark, headlineLogoLight, variables };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export { type DocsTemplateOptions, default as createConfig } from "./config.js";
|
|
2
|
+
export interface InitOptions {
|
|
3
|
+
/** Display name for the product (e.g. "Recoco", "CodeWeaver") */
|
|
4
|
+
appName: string;
|
|
5
|
+
/** npm package name (e.g. "@knitli-site/recoco-docs") */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Short product description */
|
|
8
|
+
description: string;
|
|
9
|
+
/** Cloudflare Worker name (e.g. "recoco-docs") */
|
|
10
|
+
workerName?: string;
|
|
11
|
+
/** Whether this is a CodeWeaver-branded site */
|
|
12
|
+
is_codeweaver?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface AddPiecesOptions extends InitOptions {
|
|
15
|
+
pieces: PieceName[];
|
|
16
|
+
/** Overwrite existing files (default: false — skips with a warning) */
|
|
17
|
+
force?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const PIECES: {
|
|
20
|
+
readonly config: {
|
|
21
|
+
readonly description: "Astro config using createConfig()";
|
|
22
|
+
readonly paths: readonly ["astro.config.ts"];
|
|
23
|
+
};
|
|
24
|
+
readonly wrangler: {
|
|
25
|
+
readonly description: "Cloudflare Worker deployment config";
|
|
26
|
+
readonly paths: readonly ["wrangler.jsonc"];
|
|
27
|
+
};
|
|
28
|
+
readonly tsconfig: {
|
|
29
|
+
readonly description: "TypeScript config extending shared base";
|
|
30
|
+
readonly paths: readonly ["tsconfig.json"];
|
|
31
|
+
};
|
|
32
|
+
readonly content: {
|
|
33
|
+
readonly description: "Content collections, env types, and tags";
|
|
34
|
+
readonly paths: readonly ["src/content.config.ts", "src/env.d.ts", "tags.yml"];
|
|
35
|
+
};
|
|
36
|
+
readonly mise: {
|
|
37
|
+
readonly description: "mise dev tasks (build, deploy, clean, etc.)";
|
|
38
|
+
readonly paths: readonly ["mise.toml"];
|
|
39
|
+
};
|
|
40
|
+
readonly styles: {
|
|
41
|
+
readonly description: "Custom CSS hook for site-specific styles";
|
|
42
|
+
readonly paths: readonly ["src/styles/custom.css"];
|
|
43
|
+
};
|
|
44
|
+
readonly deps: {
|
|
45
|
+
readonly description: "package.json with template dependencies";
|
|
46
|
+
readonly paths: readonly ["package.json"];
|
|
47
|
+
};
|
|
48
|
+
readonly "starter-content": {
|
|
49
|
+
readonly description: "Example documentation pages";
|
|
50
|
+
readonly paths: readonly ["src/content/docs"];
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export type PieceName = keyof typeof PIECES;
|
|
54
|
+
export declare const PIECE_NAMES: PieceName[];
|
|
55
|
+
/**
|
|
56
|
+
* Initialize a new Knitli docs site from the template scaffolding.
|
|
57
|
+
*
|
|
58
|
+
* Copies all files from the scaffolding directory to the target path,
|
|
59
|
+
* applying placeholder substitution to text files.
|
|
60
|
+
*/
|
|
61
|
+
export declare function initDocsTemplate(targetPath: string, options: InitOptions): string[];
|
|
62
|
+
/**
|
|
63
|
+
* Add specific pieces from the template scaffolding to an existing project.
|
|
64
|
+
*
|
|
65
|
+
* Unlike initDocsTemplate, this only copies the files belonging to the
|
|
66
|
+
* requested pieces and skips existing files unless force is set.
|
|
67
|
+
*/
|
|
68
|
+
export declare function addPieces(targetPath: string, options: AddPiecesOptions): string[];
|
|
69
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,mBAAmB,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhF,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCT,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,MAAM,CAAC;AAC5C,eAAO,MAAM,WAAW,EAA0B,SAAS,EAAE,CAAC;AAyF9D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW,GACnB,MAAM,EAAE,CAWV;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,gBAAgB,GACxB,MAAM,EAAE,CAyCV"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { existsSync, statSync, mkdirSync, readdirSync, readFileSync, writeFileSync, cpSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
export { default as createConfig } from './config.js';
|
|
5
|
+
|
|
6
|
+
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const SCAFFOLDING_DIR = resolve(__dirname$1, "../scaffolding");
|
|
8
|
+
const PIECES = {
|
|
9
|
+
config: {
|
|
10
|
+
description: "Astro config using createConfig()",
|
|
11
|
+
paths: ["astro.config.ts"]
|
|
12
|
+
},
|
|
13
|
+
wrangler: {
|
|
14
|
+
description: "Cloudflare Worker deployment config",
|
|
15
|
+
paths: ["wrangler.jsonc"]
|
|
16
|
+
},
|
|
17
|
+
tsconfig: {
|
|
18
|
+
description: "TypeScript config extending shared base",
|
|
19
|
+
paths: ["tsconfig.json"]
|
|
20
|
+
},
|
|
21
|
+
content: {
|
|
22
|
+
description: "Content collections, env types, and tags",
|
|
23
|
+
paths: ["src/content.config.ts", "src/env.d.ts", "tags.yml"]
|
|
24
|
+
},
|
|
25
|
+
mise: {
|
|
26
|
+
description: "mise dev tasks (build, deploy, clean, etc.)",
|
|
27
|
+
paths: ["mise.toml"]
|
|
28
|
+
},
|
|
29
|
+
styles: {
|
|
30
|
+
description: "Custom CSS hook for site-specific styles",
|
|
31
|
+
paths: ["src/styles/custom.css"]
|
|
32
|
+
},
|
|
33
|
+
deps: {
|
|
34
|
+
description: "package.json with template dependencies",
|
|
35
|
+
paths: ["package.json"]
|
|
36
|
+
},
|
|
37
|
+
"starter-content": {
|
|
38
|
+
description: "Example documentation pages",
|
|
39
|
+
paths: ["src/content/docs"]
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const PIECE_NAMES = Object.keys(PIECES);
|
|
43
|
+
const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
44
|
+
".ts",
|
|
45
|
+
".js",
|
|
46
|
+
".mjs",
|
|
47
|
+
".json",
|
|
48
|
+
".jsonc",
|
|
49
|
+
".md",
|
|
50
|
+
".mdx",
|
|
51
|
+
".yml",
|
|
52
|
+
".yaml",
|
|
53
|
+
".css",
|
|
54
|
+
".html",
|
|
55
|
+
".astro",
|
|
56
|
+
".toml"
|
|
57
|
+
]);
|
|
58
|
+
function isTextFile(filePath) {
|
|
59
|
+
return TEXT_EXTENSIONS.has(filePath.slice(filePath.lastIndexOf(".")));
|
|
60
|
+
}
|
|
61
|
+
function buildReplacements(options) {
|
|
62
|
+
return {
|
|
63
|
+
"{{appName}}": options.appName,
|
|
64
|
+
"{{appNameLower}}": options.appName.toLowerCase(),
|
|
65
|
+
"{{name}}": options.name,
|
|
66
|
+
"{{description}}": options.description,
|
|
67
|
+
"{{workerName}}": options.workerName ?? `${options.appName.toLowerCase()}-docs`
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function applyReplacements(content, replacements) {
|
|
71
|
+
let result = content;
|
|
72
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
73
|
+
result = result.replaceAll(placeholder, value);
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
function copyFile(srcPath, destPath, replacements, created, force) {
|
|
78
|
+
if (!force && existsSync(destPath)) {
|
|
79
|
+
console.log(` skip ${destPath} (exists, use --force to overwrite)`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
83
|
+
if (isTextFile(srcPath)) {
|
|
84
|
+
const content = readFileSync(srcPath, "utf-8");
|
|
85
|
+
writeFileSync(destPath, applyReplacements(content, replacements), "utf-8");
|
|
86
|
+
} else {
|
|
87
|
+
cpSync(srcPath, destPath);
|
|
88
|
+
}
|
|
89
|
+
created.push(destPath);
|
|
90
|
+
}
|
|
91
|
+
function copyDirRecursive(srcDir, destDir, replacements, created, force) {
|
|
92
|
+
mkdirSync(destDir, { recursive: true });
|
|
93
|
+
for (const entry of readdirSync(srcDir)) {
|
|
94
|
+
const srcPath = join(srcDir, entry);
|
|
95
|
+
const destPath = join(destDir, entry);
|
|
96
|
+
if (statSync(srcPath).isDirectory()) {
|
|
97
|
+
copyDirRecursive(srcPath, destPath, replacements, created, force);
|
|
98
|
+
} else {
|
|
99
|
+
copyFile(srcPath, destPath, replacements, created, force);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function initDocsTemplate(targetPath, options) {
|
|
104
|
+
const target = resolve(targetPath);
|
|
105
|
+
const replacements = buildReplacements(options);
|
|
106
|
+
const created = [];
|
|
107
|
+
if (!existsSync(SCAFFOLDING_DIR)) {
|
|
108
|
+
throw new Error(`Scaffolding directory not found at ${SCAFFOLDING_DIR}`);
|
|
109
|
+
}
|
|
110
|
+
copyDirRecursive(SCAFFOLDING_DIR, target, replacements, created, true);
|
|
111
|
+
return created;
|
|
112
|
+
}
|
|
113
|
+
function addPieces(targetPath, options) {
|
|
114
|
+
const target = resolve(targetPath);
|
|
115
|
+
const replacements = buildReplacements(options);
|
|
116
|
+
const created = [];
|
|
117
|
+
if (!existsSync(SCAFFOLDING_DIR)) {
|
|
118
|
+
throw new Error(`Scaffolding directory not found at ${SCAFFOLDING_DIR}`);
|
|
119
|
+
}
|
|
120
|
+
for (const piece of options.pieces) {
|
|
121
|
+
const pieceDef = PIECES[piece];
|
|
122
|
+
if (!pieceDef) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Unknown piece: ${piece}. Available: ${PIECE_NAMES.join(", ")}`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
for (const relPath of pieceDef.paths) {
|
|
128
|
+
const srcPath = join(SCAFFOLDING_DIR, relPath);
|
|
129
|
+
const destPath = join(target, relPath);
|
|
130
|
+
if (!existsSync(srcPath)) {
|
|
131
|
+
console.warn(` warn: ${relPath} not found in scaffolding, skipping`);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (statSync(srcPath).isDirectory()) {
|
|
135
|
+
copyDirRecursive(
|
|
136
|
+
srcPath,
|
|
137
|
+
destPath,
|
|
138
|
+
replacements,
|
|
139
|
+
created,
|
|
140
|
+
options.force
|
|
141
|
+
);
|
|
142
|
+
} else {
|
|
143
|
+
copyFile(srcPath, destPath, replacements, created, options.force);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return created;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { PIECES, PIECE_NAMES, addPieces, initDocsTemplate };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knitli/astro-docs-template",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Opinionated Astro + Starlight docs site template with Knitli branding",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"knitli",
|
|
@@ -19,17 +19,26 @@
|
|
|
19
19
|
"author": "Knitli Inc.",
|
|
20
20
|
"type": "module",
|
|
21
21
|
"exports": {
|
|
22
|
-
".":
|
|
23
|
-
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./config": {
|
|
27
|
+
"types": "./dist/config.d.ts",
|
|
28
|
+
"import": "./dist/config.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"bin": {
|
|
32
|
+
"knitli-docs": "dist/cli.js"
|
|
24
33
|
},
|
|
25
34
|
"files": [
|
|
26
|
-
"
|
|
35
|
+
"dist",
|
|
27
36
|
"scaffolding",
|
|
28
37
|
"README.md",
|
|
29
38
|
"CHANGELOG.md"
|
|
30
39
|
],
|
|
31
40
|
"scripts": {
|
|
32
|
-
"build": "
|
|
41
|
+
"build": "vite build && tsc --emitDeclarationOnly --noCheck --noEmit false",
|
|
33
42
|
"prepublishOnly": "bun run build",
|
|
34
43
|
"publish": "npm publish --access public",
|
|
35
44
|
"typecheck": "bunx tsc --noEmit"
|
|
@@ -69,7 +78,8 @@
|
|
|
69
78
|
"lightningcss": "catalog:optimization",
|
|
70
79
|
"sharp": "catalog:astro-core",
|
|
71
80
|
"svgo": "catalog:optimization",
|
|
72
|
-
"typescript": "catalog:dev-common"
|
|
81
|
+
"typescript": "catalog:dev-common",
|
|
82
|
+
"vite": "catalog:dev-common"
|
|
73
83
|
},
|
|
74
84
|
"devEngines": {
|
|
75
85
|
"packageManager": {
|
package/scaffolding/package.json
CHANGED
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
+
"astro": "bunx astro",
|
|
8
|
+
"prepare": "test -f ./node_modules/bun/install.js && node ./node_modules/bun/install.js || true",
|
|
9
|
+
|
|
10
|
+
"prebuild": "bunx wrangler types; bunx astro sync",
|
|
7
11
|
"build": "bunx astro build",
|
|
8
|
-
"deploy": "
|
|
12
|
+
"deploy": "bun run build && bunx wrangler deploy",
|
|
9
13
|
"dev": "bunx astro dev",
|
|
10
|
-
"
|
|
11
|
-
"
|
|
14
|
+
"preview": "bunx astro preview",
|
|
15
|
+
"wrangler": "bunx wrangler"
|
|
12
16
|
},
|
|
13
17
|
"dependencies": {
|
|
14
18
|
"@knitli/astro-docs-template": "workspace:*",
|
package/src/index.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2026 Knitli Inc.
|
|
2
|
-
//
|
|
3
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
cpSync,
|
|
7
|
-
existsSync,
|
|
8
|
-
mkdirSync,
|
|
9
|
-
readdirSync,
|
|
10
|
-
readFileSync,
|
|
11
|
-
statSync,
|
|
12
|
-
writeFileSync,
|
|
13
|
-
} from "node:fs";
|
|
14
|
-
import { dirname, join, resolve } from "node:path";
|
|
15
|
-
import { fileURLToPath } from "node:url";
|
|
16
|
-
|
|
17
|
-
export { type DocsTemplateOptions, default as createConfig } from "./config.js";
|
|
18
|
-
|
|
19
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
-
const SCAFFOLDING_DIR = resolve(__dirname, "../scaffolding");
|
|
21
|
-
|
|
22
|
-
export interface InitOptions {
|
|
23
|
-
/** Display name for the product (e.g. "Recoco", "CodeWeaver") */
|
|
24
|
-
appName: string;
|
|
25
|
-
/** npm package name (e.g. "@knitli-site/recoco-docs") */
|
|
26
|
-
name: string;
|
|
27
|
-
/** Short product description */
|
|
28
|
-
description: string;
|
|
29
|
-
/** Cloudflare Worker name (e.g. "recoco-docs") */
|
|
30
|
-
workerName?: string;
|
|
31
|
-
/** Whether this is a CodeWeaver-branded site */
|
|
32
|
-
is_codeweaver?: boolean;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** File extensions that should have placeholder substitution applied */
|
|
36
|
-
const TEXT_EXTENSIONS = new Set([
|
|
37
|
-
".ts",
|
|
38
|
-
".js",
|
|
39
|
-
".mjs",
|
|
40
|
-
".json",
|
|
41
|
-
".jsonc",
|
|
42
|
-
".md",
|
|
43
|
-
".mdx",
|
|
44
|
-
".yml",
|
|
45
|
-
".yaml",
|
|
46
|
-
".css",
|
|
47
|
-
".html",
|
|
48
|
-
".astro",
|
|
49
|
-
".d.ts",
|
|
50
|
-
]);
|
|
51
|
-
|
|
52
|
-
function isTextFile(filePath: string): boolean {
|
|
53
|
-
return TEXT_EXTENSIONS.has(filePath.slice(filePath.lastIndexOf(".")));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function buildReplacements(options: InitOptions): Record<string, string> {
|
|
57
|
-
return {
|
|
58
|
-
"{{appName}}": options.appName,
|
|
59
|
-
"{{appNameLower}}": options.appName.toLowerCase(),
|
|
60
|
-
"{{name}}": options.name,
|
|
61
|
-
"{{description}}": options.description,
|
|
62
|
-
"{{workerName}}":
|
|
63
|
-
options.workerName ?? `${options.appName.toLowerCase()}-docs`,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function applyReplacements(
|
|
68
|
-
content: string,
|
|
69
|
-
replacements: Record<string, string>,
|
|
70
|
-
): string {
|
|
71
|
-
let result = content;
|
|
72
|
-
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
73
|
-
result = result.replaceAll(placeholder, value);
|
|
74
|
-
}
|
|
75
|
-
return result;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Initialize a new Knitli docs site from the template scaffolding.
|
|
80
|
-
*
|
|
81
|
-
* Copies all files from the scaffolding directory to the target path,
|
|
82
|
-
* applying placeholder substitution to text files.
|
|
83
|
-
*
|
|
84
|
-
* @param targetPath - Directory to scaffold into (will be created if it doesn't exist)
|
|
85
|
-
* @param options - Configuration for placeholder substitution
|
|
86
|
-
* @returns List of files created
|
|
87
|
-
*/
|
|
88
|
-
export function initDocsTemplate(
|
|
89
|
-
targetPath: string,
|
|
90
|
-
options: InitOptions,
|
|
91
|
-
): string[] {
|
|
92
|
-
const target = resolve(targetPath);
|
|
93
|
-
const replacements = buildReplacements(options);
|
|
94
|
-
const created: string[] = [];
|
|
95
|
-
|
|
96
|
-
if (!existsSync(SCAFFOLDING_DIR)) {
|
|
97
|
-
throw new Error(`Scaffolding directory not found at ${SCAFFOLDING_DIR}`);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function copyDir(srcDir: string, destDir: string) {
|
|
101
|
-
if (!existsSync(destDir)) {
|
|
102
|
-
mkdirSync(destDir, { recursive: true });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
for (const entry of readdirSync(srcDir)) {
|
|
106
|
-
const srcPath = join(srcDir, entry);
|
|
107
|
-
const destPath = join(destDir, entry);
|
|
108
|
-
const stat = statSync(srcPath);
|
|
109
|
-
|
|
110
|
-
if (stat.isDirectory()) {
|
|
111
|
-
copyDir(srcPath, destPath);
|
|
112
|
-
} else if (isTextFile(srcPath)) {
|
|
113
|
-
const content = readFileSync(srcPath, "utf-8");
|
|
114
|
-
const processed = applyReplacements(content, replacements);
|
|
115
|
-
mkdirSync(dirname(destPath), { recursive: true });
|
|
116
|
-
writeFileSync(destPath, processed, "utf-8");
|
|
117
|
-
created.push(destPath);
|
|
118
|
-
} else {
|
|
119
|
-
mkdirSync(dirname(destPath), { recursive: true });
|
|
120
|
-
cpSync(srcPath, destPath);
|
|
121
|
-
created.push(destPath);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
copyDir(SCAFFOLDING_DIR, target);
|
|
127
|
-
return created;
|
|
128
|
-
}
|