@gitpagedocs/cli 1.1.68 → 1.1.69
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/ai/application/ai-command.ts +1 -1
- package/ai/application/docs-pattern.ts +9 -5
- package/ai/application/resolve-chat-credentials.ts +13 -6
- package/ai/core/models/parse-ai-cli-config.ts +6 -8
- package/application/home/handler.mjs +3 -1
- package/application/ports/cli-runtime-ports.ts +2 -0
- package/application/report/config-only-reporter.mjs +2 -5
- package/builders/config-orchestrator.mjs +4 -7
- package/builders/language-bundles-builder.mjs +4 -4
- package/builders/root-config-builder.mjs +1 -1
- package/content/docs-en.mjs +4 -4
- package/content/docs-es.mjs +4 -4
- package/content/docs-pt.mjs +4 -4
- package/contracts/doc-versions.mjs +1 -1
- package/contracts/langs-paths.mjs +8 -5
- package/contracts/layouts-paths.mjs +4 -4
- package/contracts/path-segments.d.mts +2 -0
- package/contracts/path-segments.mjs +15 -0
- package/data/default-site-config.mjs +9 -2
- package/domain/services/layouts-migration.mjs +15 -1
- package/home/home-file-writer.mjs +2 -3
- package/home/templates.mjs +5 -2
- package/infrastructure/home/runtime.mjs +2 -2
- package/package.json +3 -3
- package/presentation/commands/config-info.ts +44 -9
- package/presentation/commands/diagnostics.ts +30 -20
- package/presentation/commands/docs.ts +7 -2
- package/presentation/commands/pages.ts +4 -2
- package/presentation/options/parser.ts +46 -45
- package/presentation/ui/prompts.ts +6 -5
- package/runtime/doc-path-resolver.mjs +8 -6
- package/runtime/exec.mjs +168 -0
- package/runtime/git-ops.mjs +22 -20
- package/runtime/layouts-migrator.mjs +15 -1
- package/runtime/output.mjs +88 -58
- package/runtime/workflow.mjs +3 -1
- package/start.mjs +8 -6
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { ILLMProvider } from '../core/ports/illm-provider';
|
|
6
6
|
|
|
7
7
|
export class AiCommandService {
|
|
8
|
-
constructor(private provider: ILLMProvider) { }
|
|
8
|
+
constructor(private readonly provider: ILLMProvider) { }
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Executes the AI Documentation Generation for a specific content
|
|
@@ -14,21 +14,25 @@ export interface AiDocPage {
|
|
|
14
14
|
body: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
// Slug is everything up to the first `|`, title everything up to the closing
|
|
18
|
+
// `===`; both are trimmed by the caller. Kept free of overlapping quantifiers
|
|
19
|
+
// so a hostile line cannot make the match super-linear.
|
|
20
|
+
const PAGE_DELIMITER = /^===\s*PAGE:([^|]*)\|(.*)===\s*$/;
|
|
18
21
|
|
|
19
22
|
/** Turn an arbitrary heading into a safe lowercase-kebab slug. */
|
|
20
23
|
export function slugify(raw: string): string {
|
|
21
24
|
const slug = (raw ?? "")
|
|
22
25
|
.toLowerCase()
|
|
23
26
|
.normalize("NFKD")
|
|
24
|
-
.
|
|
25
|
-
.
|
|
27
|
+
.split(/[^a-z0-9]+/)
|
|
28
|
+
.filter(Boolean)
|
|
29
|
+
.join("-")
|
|
26
30
|
.slice(0, 60);
|
|
27
31
|
return slug || "page";
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export function parseAiPages(markdown: string): AiDocPage[] {
|
|
31
|
-
const text = (markdown ?? "").
|
|
35
|
+
const text = (markdown ?? "").replaceAll("\r\n", "\n").trim();
|
|
32
36
|
if (!text) return [];
|
|
33
37
|
|
|
34
38
|
const pages: AiDocPage[] = [];
|
|
@@ -41,7 +45,7 @@ export function parseAiPages(markdown: string): AiDocPage[] {
|
|
|
41
45
|
};
|
|
42
46
|
|
|
43
47
|
for (const line of text.split("\n")) {
|
|
44
|
-
const match =
|
|
48
|
+
const match = PAGE_DELIMITER.exec(line);
|
|
45
49
|
if (match) {
|
|
46
50
|
flush();
|
|
47
51
|
const rawSlug = match[1].trim();
|
|
@@ -2,6 +2,7 @@ import { legacyProviderToCatalogId, resolveApiKeyFromEnv } from "@gitpagedocs/to
|
|
|
2
2
|
import type { AiProviderId } from "@gitpagedocs/tools/ports";
|
|
3
3
|
import { PROVIDER_CATALOG } from "@gitpagedocs/tools";
|
|
4
4
|
import { AiConfigFileRepository } from "../infrastructure/ai-config-file";
|
|
5
|
+
import type { AiCliConfig } from "../core/models/ai-cli-config";
|
|
5
6
|
|
|
6
7
|
export interface ResolvedChatCredentials {
|
|
7
8
|
readonly providerId: AiProviderId;
|
|
@@ -35,12 +36,7 @@ export async function resolveChatCredentials(
|
|
|
35
36
|
const configRepo = input.configRepo ?? new AiConfigFileRepository({ cwd: input.cwd });
|
|
36
37
|
const stored = await configRepo.read().catch(() => null);
|
|
37
38
|
|
|
38
|
-
const providerId = input.providerOverride
|
|
39
|
-
? legacyProviderToCatalogId(input.providerOverride)
|
|
40
|
-
: stored
|
|
41
|
-
? legacyProviderToCatalogId(stored.ai.provider)
|
|
42
|
-
: firstProviderFromEnv(env) ?? "openai";
|
|
43
|
-
|
|
39
|
+
const providerId = resolveProviderId(input.providerOverride, stored, env);
|
|
44
40
|
const spec = PROVIDER_CATALOG[providerId];
|
|
45
41
|
const model = input.modelOverride?.trim() || stored?.ai.model?.trim() || spec.defaultModel;
|
|
46
42
|
const baseUrl = stored?.ai.baseUrl?.trim() || undefined;
|
|
@@ -52,6 +48,17 @@ export async function resolveChatCredentials(
|
|
|
52
48
|
return { providerId, model, apiKey, baseUrl };
|
|
53
49
|
}
|
|
54
50
|
|
|
51
|
+
/** Explicit override > stored config > first provider with an env key > openai. */
|
|
52
|
+
function resolveProviderId(
|
|
53
|
+
override: string | undefined,
|
|
54
|
+
stored: AiCliConfig | null,
|
|
55
|
+
env: Readonly<Record<string, string | undefined>>,
|
|
56
|
+
): AiProviderId {
|
|
57
|
+
if (override) return legacyProviderToCatalogId(override);
|
|
58
|
+
if (stored) return legacyProviderToCatalogId(stored.ai.provider);
|
|
59
|
+
return firstProviderFromEnv(env) ?? "openai";
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
function firstProviderFromEnv(
|
|
56
63
|
env: Readonly<Record<string, string | undefined>>,
|
|
57
64
|
): AiProviderId | undefined {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { AI_MODEL_DEFAULTS, type AiProviderId } from "../../config";
|
|
2
2
|
import type { AiCliConfig } from "./ai-cli-config";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
type SupportedLanguage = AiCliConfig["ai"]["languages"][number];
|
|
5
|
+
|
|
6
|
+
const SUPPORTED_PROVIDERS: ReadonlySet<string> = new Set(Object.keys(AI_MODEL_DEFAULTS));
|
|
7
|
+
const SUPPORTED_LANGUAGES: ReadonlySet<string> = new Set<SupportedLanguage>(["pt", "en", "es"]);
|
|
6
8
|
|
|
7
9
|
/** Fallbacks for optional fields, mirroring the interactive prompt defaults. */
|
|
8
10
|
const DEFAULT_LANGUAGES: AiCliConfig["ai"]["languages"] = ["en", "pt", "es"];
|
|
@@ -27,17 +29,13 @@ function asPaths(value: unknown): string[] {
|
|
|
27
29
|
|
|
28
30
|
function asLanguages(value: unknown): AiCliConfig["ai"]["languages"] {
|
|
29
31
|
const languages = Array.isArray(value)
|
|
30
|
-
? value.filter((language): language is
|
|
31
|
-
SUPPORTED_LANGUAGES.includes(language as AiCliConfig["ai"]["languages"][number]),
|
|
32
|
-
)
|
|
32
|
+
? value.filter((language): language is SupportedLanguage => isString(language) && SUPPORTED_LANGUAGES.has(language))
|
|
33
33
|
: [];
|
|
34
34
|
return languages.length > 0 ? languages : [...DEFAULT_LANGUAGES];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function asProviderId(value: unknown): AiProviderId | null {
|
|
38
|
-
return isString(value) && SUPPORTED_PROVIDERS.
|
|
39
|
-
? (value as AiProviderId)
|
|
40
|
-
: null;
|
|
38
|
+
return isString(value) && SUPPORTED_PROVIDERS.has(value) ? (value as AiProviderId) : null;
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Home distribution use case - static site + auxiliary files */
|
|
2
2
|
|
|
3
3
|
import { STATIC_OUTPUT_DIR, ARTIFACTS_DIR } from "../../home/constants.mjs";
|
|
4
|
+
import { trimSlashes } from "../../contracts/path-segments.mjs";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Execute home distribution use case
|
|
@@ -30,7 +31,7 @@ export async function executeHome(params, runtime) {
|
|
|
30
31
|
runtime.ensureDirEmpty(root, outputDir);
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
const pathSegment = basePath ? basePath
|
|
34
|
+
const pathSegment = basePath ? trimSlashes(basePath) : "";
|
|
34
35
|
const buildEnv = {
|
|
35
36
|
...process.env,
|
|
36
37
|
GITHUB_ACTIONS: "true",
|
|
@@ -83,3 +84,4 @@ export async function executeHome(params, runtime) {
|
|
|
83
84
|
runtime.logInfo(`Serve: cd ${cdDir} && npx serve .`);
|
|
84
85
|
runtime.logInfo(`Docker: cd ${cdDir} && docker build -t gitpagedocshome . && docker run -p 3000:80 gitpagedocshome`);
|
|
85
86
|
}
|
|
87
|
+
|
|
@@ -16,6 +16,8 @@ export interface LayoutDefinition {
|
|
|
16
16
|
|
|
17
17
|
export interface BuiltConfigArtifacts {
|
|
18
18
|
rootConfig: unknown;
|
|
19
|
+
/** UI-string bundle per language, written to `<outputDir>/langs/<lang>.json`. */
|
|
20
|
+
languageBundles: Record<string, unknown>;
|
|
19
21
|
layoutsConfig: unknown;
|
|
20
22
|
fallbackLayoutsConfig: unknown;
|
|
21
23
|
docs?: Record<string, Record<string, string>>;
|
|
@@ -8,7 +8,7 @@ export function reportConfigOnlySuccess(options) {
|
|
|
8
8
|
const langs = languageArtifactPaths(options.outputDir);
|
|
9
9
|
return [
|
|
10
10
|
`Generated: ${options.outputDir}/ (config-only)`,
|
|
11
|
-
`UI strings: ${langs.
|
|
11
|
+
`UI strings: ${langs.dir}/{${SUPPORTED_LANGUAGES.join(",")}}.json (enable/disable each language in ${langs.config} -> site.languages)`,
|
|
12
12
|
"No index.html/index.js generated.",
|
|
13
13
|
];
|
|
14
14
|
}
|
|
@@ -51,10 +51,7 @@ export function reportPrebuiltDetected() {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export function reportAll(options, prebuiltDetected) {
|
|
54
|
-
const lines = [];
|
|
55
|
-
lines.push(...reportConfigOnlySuccess(options));
|
|
56
|
-
lines.push(...reportLayoutConfig(options));
|
|
57
|
-
lines.push(...reportRenderingUrl(options));
|
|
54
|
+
const lines = [...reportConfigOnlySuccess(options), ...reportLayoutConfig(options), ...reportRenderingUrl(options)];
|
|
58
55
|
if (options.shouldPush) {
|
|
59
56
|
lines.push(...reportPushMode());
|
|
60
57
|
}
|
|
@@ -9,14 +9,12 @@ import { buildLanguageArtifacts } from "./language-bundles-builder.mjs";
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Build all config artifacts (root, languages, layouts, versions, docs).
|
|
12
|
-
* @param {object} options - { useLocalLayoutConfig, githubOwner, githubRepo,
|
|
13
|
-
* @returns {object} { rootConfig,
|
|
12
|
+
* @param {object} options - { useLocalLayoutConfig, githubOwner, githubRepo, layoutsDir }
|
|
13
|
+
* @returns {object} { rootConfig, languageBundles, layoutsConfig, fallbackLayoutsConfig, docs, docsHtml, versionConfigs }
|
|
14
14
|
*/
|
|
15
15
|
export function buildConfigArtifacts(options = {}) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const rootConfig = buildRootConfig(options);
|
|
19
|
-
const { languageManifest, languageBundles } = buildLanguageArtifacts();
|
|
16
|
+
const { languageToggles, languageBundles } = buildLanguageArtifacts();
|
|
17
|
+
const rootConfig = buildRootConfig({ ...options, languageToggles });
|
|
20
18
|
const layoutsConfig = { layouts: LAYOUTS };
|
|
21
19
|
const fallbackLayoutsConfig = { layouts: FALLBACK_LAYOUTS };
|
|
22
20
|
|
|
@@ -27,7 +25,6 @@ export function buildConfigArtifacts(options = {}) {
|
|
|
27
25
|
|
|
28
26
|
return {
|
|
29
27
|
rootConfig,
|
|
30
|
-
languageManifest,
|
|
31
28
|
languageBundles,
|
|
32
29
|
layoutsConfig,
|
|
33
30
|
fallbackLayoutsConfig,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** Build the
|
|
2
|
-
import {
|
|
1
|
+
/** Build the `site.languages` toggles + per-language UI string bundles for gitpagedocs */
|
|
2
|
+
import { buildLanguageToggles, splitLanguageBundles } from "@gitpagedocs/tools/i18n";
|
|
3
3
|
import { SUPPORTED_LANGUAGES } from "../contracts/languages.mjs";
|
|
4
4
|
import { defaultLangMenu } from "../data/i18n-langmenu.mjs";
|
|
5
5
|
import { defaultTranslations } from "../data/i18n-translations.mjs";
|
|
@@ -12,13 +12,13 @@ function assertLanguageStrings(languages) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @returns {{
|
|
15
|
+
* @returns {{ languageToggles: Record<string, boolean>, languageBundles: Record<string, object> }}
|
|
16
16
|
*/
|
|
17
17
|
export function buildLanguageArtifacts() {
|
|
18
18
|
const languages = [...SUPPORTED_LANGUAGES];
|
|
19
19
|
assertLanguageStrings(languages);
|
|
20
20
|
return {
|
|
21
|
-
|
|
21
|
+
languageToggles: buildLanguageToggles(languages),
|
|
22
22
|
languageBundles: splitLanguageBundles(languages, defaultLangMenu, defaultTranslations),
|
|
23
23
|
};
|
|
24
24
|
}
|
|
@@ -34,7 +34,7 @@ export function buildRootConfig(options = {}) {
|
|
|
34
34
|
"source-viewer-path": sourceViewerPath,
|
|
35
35
|
}));
|
|
36
36
|
|
|
37
|
-
const baseSiteConfig = getDefaultSiteConfig(projectLink);
|
|
37
|
+
const baseSiteConfig = getDefaultSiteConfig(projectLink, options.languageToggles);
|
|
38
38
|
|
|
39
39
|
return {
|
|
40
40
|
site: {
|
package/content/docs-en.mjs
CHANGED
|
@@ -175,7 +175,7 @@ The version config can render a **Source code** container through \`routes-sourc
|
|
|
175
175
|
- \`name\`, \`defaultLanguage\`
|
|
176
176
|
- \`docsVersion\`, \`rendering\`, \`ThemeDefault\`, \`ThemeModeDefault\`
|
|
177
177
|
- \`ProjectLink\`, \`layoutsConfigPathOficial\`, \`layoutsConfigPath\`
|
|
178
|
-
- Languages
|
|
178
|
+
- Languages: \`site.languages\` (enable/disable each one); UI strings: \`gitpagedocs/langs/<lang>.json\`
|
|
179
179
|
|
|
180
180
|
## Environment variables
|
|
181
181
|
|
|
@@ -319,11 +319,11 @@ Supported adapters:
|
|
|
319
319
|
|
|
320
320
|
Runtime configuration lives in \`gitpagedocs/config.json\`. UI text lives next to it, one file per language.
|
|
321
321
|
|
|
322
|
-
## Languages (\`
|
|
322
|
+
## Languages (\`site.languages\` + \`langs/\`)
|
|
323
323
|
|
|
324
|
-
- \`gitpagedocs/
|
|
324
|
+
- \`site.languages\` in \`gitpagedocs/config.json\` switches each language on (\`true\`) or off (\`false\`), in menu order: \`{ "languages": { "en": true, "pt": true, "es": false } }\`. A language set to \`false\` disappears from the language selector and its strings are not loaded, even when its docs exist.
|
|
325
325
|
- \`gitpagedocs/langs/<lang>.json\` holds that language's strings: \`langmenu\` (header, search, source viewer, audio player, AI chat and docs-access labels) and \`translations\` (\`notFound\`, \`navigation\`, \`footer\`).
|
|
326
|
-
- To add a language, create \`langs/<lang>.json\` and
|
|
326
|
+
- To add a language, create \`langs/<lang>.json\` and add \`"<lang>": true\` to \`site.languages\`. There is no \`langs.json\` any more: a manifest left by release 1.1.68 is still read by configs without \`site.languages\`, and the generator removes it.
|
|
327
327
|
- Older \`config.json\` files that still inline \`site.langmenu\` / \`translations\` keep working; when both exist, the \`langs/\` files win and any missing key is backfilled from the current release.
|
|
328
328
|
|
|
329
329
|
## \`site\` section
|
package/content/docs-es.mjs
CHANGED
|
@@ -159,7 +159,7 @@ El config de version puede renderizar un contenedor **Codigo fuente** via \`rout
|
|
|
159
159
|
- \`name\`, \`defaultLanguage\`
|
|
160
160
|
- \`docsVersion\`, \`rendering\`, \`ThemeDefault\`, \`ThemeModeDefault\`
|
|
161
161
|
- \`ProjectLink\`, \`layoutsConfigPathOficial\`, \`layoutsConfigPath\`
|
|
162
|
-
- Idiomas
|
|
162
|
+
- Idiomas: \`site.languages\` (activa/desactiva cada uno); textos de la UI: \`gitpagedocs/langs/<lang>.json\`
|
|
163
163
|
|
|
164
164
|
## Variables de entorno
|
|
165
165
|
|
|
@@ -170,11 +170,11 @@ El config de version puede renderizar un contenedor **Codigo fuente** via \`rout
|
|
|
170
170
|
|
|
171
171
|
La configuracion de runtime esta en \`gitpagedocs/config.json\`. Los textos de la UI viven al lado, un archivo por idioma.
|
|
172
172
|
|
|
173
|
-
## Idiomas (\`
|
|
173
|
+
## Idiomas (\`site.languages\` + \`langs/\`)
|
|
174
174
|
|
|
175
|
-
- \`gitpagedocs/
|
|
175
|
+
- \`site.languages\` en \`gitpagedocs/config.json\` activa (\`true\`) o desactiva (\`false\`) cada idioma, en el orden del menu: \`{ "languages": { "en": true, "pt": true, "es": false } }\`. Un idioma en \`false\` desaparece del selector de idiomas y sus textos no se cargan, aunque existan sus docs.
|
|
176
176
|
- \`gitpagedocs/langs/<lang>.json\` guarda los textos de ese idioma: \`langmenu\` (cabecera, busqueda, visor de codigo, reproductor de audio, chat de IA y acceso a los docs) y \`translations\` (\`notFound\`, \`navigation\`, \`footer\`).
|
|
177
|
-
- Para agregar un idioma, crea \`langs/<lang>.json\` y agrega
|
|
177
|
+
- Para agregar un idioma, crea \`langs/<lang>.json\` y agrega \`"<lang>": true\` en \`site.languages\`. Ya no existe \`langs.json\`: un manifiesto dejado por la version 1.1.68 aun se lee en configs antiguos sin \`site.languages\`, y el generador lo elimina.
|
|
178
178
|
- Los \`config.json\` antiguos que aun traen \`site.langmenu\` / \`translations\` inline siguen funcionando; cuando existen ambos, los archivos de \`langs/\` prevalecen y cualquier clave ausente se completa desde la version actual.
|
|
179
179
|
|
|
180
180
|
## Seccion \`site\`
|
package/content/docs-pt.mjs
CHANGED
|
@@ -159,7 +159,7 @@ O config da versao pode renderizar um container **Codigo fonte** via \`routes-so
|
|
|
159
159
|
- \`name\`, \`defaultLanguage\`
|
|
160
160
|
- \`docsVersion\`, \`rendering\`, \`ThemeDefault\`, \`ThemeModeDefault\`
|
|
161
161
|
- \`ProjectLink\`, \`layoutsConfigPathOficial\`, \`layoutsConfigPath\`
|
|
162
|
-
- Idiomas
|
|
162
|
+
- Idiomas: \`site.languages\` (liga/desliga cada um); textos da UI: \`gitpagedocs/langs/<lang>.json\`
|
|
163
163
|
|
|
164
164
|
## Variaveis de ambiente
|
|
165
165
|
|
|
@@ -170,11 +170,11 @@ O config da versao pode renderizar um container **Codigo fonte** via \`routes-so
|
|
|
170
170
|
|
|
171
171
|
A configuracao de runtime fica em \`gitpagedocs/config.json\`. Os textos da UI ficam ao lado, um arquivo por idioma.
|
|
172
172
|
|
|
173
|
-
## Idiomas (\`
|
|
173
|
+
## Idiomas (\`site.languages\` + \`langs/\`)
|
|
174
174
|
|
|
175
|
-
- \`gitpagedocs/
|
|
175
|
+
- \`site.languages\` em \`gitpagedocs/config.json\` liga (\`true\`) ou desliga (\`false\`) cada idioma, na ordem do menu: \`{ "languages": { "en": true, "pt": true, "es": false } }\`. Um idioma em \`false\` some do seletor de idiomas e seus textos nao sao carregados, mesmo que os docs existam.
|
|
176
176
|
- \`gitpagedocs/langs/<lang>.json\` guarda os textos daquele idioma: \`langmenu\` (cabecalho, busca, visualizador de codigo, player de audio, chat de IA e acesso aos docs) e \`translations\` (\`notFound\`, \`navigation\`, \`footer\`).
|
|
177
|
-
- Para adicionar um idioma, crie \`langs/<lang>.json\` e inclua
|
|
177
|
+
- Para adicionar um idioma, crie \`langs/<lang>.json\` e inclua \`"<lang>": true\` em \`site.languages\`. Nao existe mais \`langs.json\`: um manifesto deixado pela versao 1.1.68 ainda e lido por configs antigos sem \`site.languages\`, e o gerador o remove.
|
|
178
178
|
- Arquivos \`config.json\` antigos que ainda trazem \`site.langmenu\` / \`translations\` inline continuam funcionando; quando os dois existem, os arquivos de \`langs/\` prevalecem e qualquer chave ausente e preenchida a partir da versao atual.
|
|
179
179
|
|
|
180
180
|
## Secao \`site\`
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Canonical locations for the language artifacts inside the docs output dir:
|
|
3
3
|
*
|
|
4
|
-
* <outputDir>/
|
|
4
|
+
* <outputDir>/config.json `site.languages` — enable (true) / disable (false) each language
|
|
5
5
|
* <outputDir>/langs/<lang>.json UI strings (langmenu + translations) of one language
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* `<outputDir>/langs.json` was the 1.1.68 manifest; `site.languages` replaced
|
|
8
|
+
* it, so the generator deletes a stale copy. The file names come from
|
|
9
|
+
* @gitpagedocs/tools so the generator and the viewer never disagree about where
|
|
10
|
+
* the bundles live.
|
|
9
11
|
*/
|
|
10
12
|
import { LANGS_DIRNAME, LANGS_MANIFEST_FILENAME } from "@gitpagedocs/tools/i18n";
|
|
11
13
|
|
|
@@ -13,12 +15,13 @@ import { LANGS_DIRNAME, LANGS_MANIFEST_FILENAME } from "@gitpagedocs/tools/i18n"
|
|
|
13
15
|
* Repo-relative POSIX paths of the language artifacts for a docs output dir.
|
|
14
16
|
*
|
|
15
17
|
* @param {string} outputDir Docs output dir (e.g. `gitpagedocs`).
|
|
16
|
-
* @returns {{
|
|
18
|
+
* @returns {{ config: string, legacyManifest: string, dir: string, bundle: (language: string) => string }}
|
|
17
19
|
*/
|
|
18
20
|
export function languageArtifactPaths(outputDir) {
|
|
19
21
|
const dir = `${outputDir}/${LANGS_DIRNAME}`;
|
|
20
22
|
return {
|
|
21
|
-
|
|
23
|
+
config: `${outputDir}/config.json`,
|
|
24
|
+
legacyManifest: `${outputDir}/${LANGS_MANIFEST_FILENAME}`,
|
|
22
25
|
dir,
|
|
23
26
|
bundle: (language) => `${dir}/${language}.json`,
|
|
24
27
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { trimSlashes } from "./path-segments.mjs";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Canonical locations for layout artifacts.
|
|
3
5
|
*
|
|
@@ -34,10 +36,8 @@ export const LEGACY_LAYOUTS_SUBDIR = "layouts";
|
|
|
34
36
|
* @returns {string} Normalized path, or `DEFAULT_LAYOUTS_DIR` when empty.
|
|
35
37
|
*/
|
|
36
38
|
export function normalizeLayoutsDir(dir) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
.replace(/^\/+|\/+$/g, "")
|
|
40
|
-
.trim();
|
|
39
|
+
const collapsed = String(dir ?? "").replace(/[\\/]+/g, "/");
|
|
40
|
+
const normalized = trimSlashes(collapsed).trim();
|
|
41
41
|
return normalized || DEFAULT_LAYOUTS_DIR;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip every leading and trailing `/` from a user-supplied path segment in a
|
|
3
|
+
* single forward/backward scan. Same result as `.replace(/^\/+|\/+$/g, "")`
|
|
4
|
+
* without the super-linear backtracking that regex incurs on long slash runs.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} value Raw segment such as "/docs/" or "///".
|
|
7
|
+
* @returns {string} The segment without surrounding slashes ("" when only slashes).
|
|
8
|
+
*/
|
|
9
|
+
export function trimSlashes(value) {
|
|
10
|
+
let start = 0;
|
|
11
|
+
let end = value.length;
|
|
12
|
+
while (start < end && value[start] === "/") start += 1;
|
|
13
|
+
while (end > start && value[end - 1] === "/") end -= 1;
|
|
14
|
+
return value.slice(start, end);
|
|
15
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Site chrome defaults. `languages` enables (true) / disables (false) each
|
|
3
|
+
* language; the UI strings themselves live in langs/<lang>.json.
|
|
4
|
+
*/
|
|
5
|
+
import { buildLanguageToggles } from "@gitpagedocs/tools/i18n";
|
|
6
|
+
import { SUPPORTED_LANGUAGES } from "../contracts/languages.mjs";
|
|
7
|
+
|
|
8
|
+
export function getDefaultSiteConfig(projectLink, languageToggles = buildLanguageToggles(SUPPORTED_LANGUAGES)) {
|
|
3
9
|
return {
|
|
4
10
|
name: "Git Pages Docs",
|
|
5
11
|
defaultLanguage: "en",
|
|
12
|
+
languages: { ...languageToggles },
|
|
6
13
|
HideThemeSelector: false,
|
|
7
14
|
ThemeDefault: "aurora-dark",
|
|
8
15
|
ThemeModeDefault: "dark",
|
|
@@ -56,5 +56,19 @@ function toSortedPaths(paths) {
|
|
|
56
56
|
const normalized = paths
|
|
57
57
|
.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
|
|
58
58
|
.map((entry) => entry.replace(/[\\/]+/g, "/").replace(/^\/+/, ""));
|
|
59
|
-
return [...new Set(normalized)].sort();
|
|
59
|
+
return [...new Set(normalized)].sort(compareCodeUnits);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Plain UTF-16 code-unit order (what `sort()` does by default), spelled out so
|
|
64
|
+
* a plan never depends on the runtime locale.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} a
|
|
67
|
+
* @param {string} b
|
|
68
|
+
* @returns {number}
|
|
69
|
+
*/
|
|
70
|
+
function compareCodeUnits(a, b) {
|
|
71
|
+
if (a < b) return -1;
|
|
72
|
+
if (a > b) return 1;
|
|
73
|
+
return 0;
|
|
60
74
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/** Write .env, Dockerfile, README to home output directory */
|
|
2
2
|
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { mkdir } from "node:fs/promises";
|
|
5
|
-
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
5
|
import { getEnvTemplate, getDockerfileTemplate, getReadmeTemplate } from "./templates.mjs";
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -16,5 +15,5 @@ export async function writeHomeFiles(root, outputDir, opts = {}) {
|
|
|
16
15
|
|
|
17
16
|
await writeFile(path.join(basePath, ".env"), getEnvTemplate(opts), "utf-8");
|
|
18
17
|
await writeFile(path.join(basePath, "Dockerfile"), getDockerfileTemplate(), "utf-8");
|
|
19
|
-
await writeFile(path.join(basePath, "README.md"), getReadmeTemplate(
|
|
18
|
+
await writeFile(path.join(basePath, "README.md"), getReadmeTemplate(), "utf-8");
|
|
20
19
|
}
|
package/home/templates.mjs
CHANGED
|
@@ -22,8 +22,11 @@ CMD ["nginx", "-g", "daemon off;"]
|
|
|
22
22
|
`;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* README shipped next to the static export. Every command runs from the
|
|
27
|
+
* folder the file lives in, so it never needs to know the output dir name.
|
|
28
|
+
*/
|
|
29
|
+
export function getReadmeTemplate() {
|
|
27
30
|
return `# GitPageDocs Home
|
|
28
31
|
|
|
29
32
|
Pre-built GitPageDocs static site by Vidigal-code.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { cpSync, existsSync, readdirSync, rmSync } from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { runExecutable } from "../../runtime/exec.mjs";
|
|
4
4
|
import { writeConfigOnlyOutput, writeText } from "../../runtime/output.mjs";
|
|
5
5
|
import { writeHomeFiles } from "../../home/home-file-writer.mjs";
|
|
6
6
|
import { logInfo, logSuccess } from "../../ui/logger.mjs";
|
|
@@ -17,7 +17,7 @@ function copyRecursive(src, dest) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function runNextBuild(root, env) {
|
|
20
|
-
|
|
20
|
+
runExecutable("npx", ["next", "build", "frontend"], { cwd: root, env, stdio: "inherit" });
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export function createHomeRuntime() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitpagedocs/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.69",
|
|
4
4
|
"description": "CLI that scaffolds and maintains gitpagedocs documentation, generates docs with AI, configures GitHub Pages, and runs the MCP server.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"gitpagedocs": "index.mjs"
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@clack/prompts": "^1.5.1",
|
|
32
|
-
"@gitpagedocs/mcp": "^1.1.
|
|
33
|
-
"@gitpagedocs/tools": "^1.1.
|
|
32
|
+
"@gitpagedocs/mcp": "^1.1.69",
|
|
33
|
+
"@gitpagedocs/tools": "^1.1.69",
|
|
34
34
|
"tsx": "^4.21.0"
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
@@ -1,19 +1,53 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_LANGS_MANIFEST_PATH,
|
|
5
|
+
defaultConfigLoader,
|
|
6
|
+
getEnabledLanguages,
|
|
7
|
+
isAppError,
|
|
8
|
+
parseLanguageManifest,
|
|
9
|
+
parseLanguageToggles,
|
|
10
|
+
} from "@gitpagedocs/tools";
|
|
4
11
|
import type { CommandContext } from "./run-command";
|
|
5
12
|
|
|
6
13
|
const UNKNOWN = "—";
|
|
7
14
|
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
interface LanguageSummary {
|
|
16
|
+
enabled: string[];
|
|
17
|
+
disabled: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The 1.1.68 manifest, read only for sites whose config.json predates `site.languages`. */
|
|
21
|
+
async function readLegacyManifestLanguages(cwd: string): Promise<string[]> {
|
|
10
22
|
try {
|
|
11
23
|
const manifest = parseLanguageManifest(JSON.parse(await readFile(path.join(cwd, DEFAULT_LANGS_MANIFEST_PATH), "utf-8")));
|
|
12
24
|
if (manifest) return manifest.languages;
|
|
13
25
|
} catch {
|
|
14
|
-
// No manifest:
|
|
26
|
+
// No manifest: nothing to report.
|
|
27
|
+
}
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** `site.languages` toggles from config.json, else the legacy inline list, else the legacy manifest. */
|
|
32
|
+
async function summarizeLanguages(cwd: string, site: Record<string, unknown>): Promise<LanguageSummary> {
|
|
33
|
+
const toggles = parseLanguageToggles(site.languages);
|
|
34
|
+
if (toggles) {
|
|
35
|
+
const enabled = getEnabledLanguages(toggles);
|
|
36
|
+
return { enabled, disabled: Object.keys(toggles).filter((language) => !enabled.includes(language)) };
|
|
15
37
|
}
|
|
16
|
-
|
|
38
|
+
if (Array.isArray(site.supportedLanguages)) {
|
|
39
|
+
return { enabled: site.supportedLanguages as string[], disabled: [] };
|
|
40
|
+
}
|
|
41
|
+
return { enabled: await readLegacyManifestLanguages(cwd), disabled: [] };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function formatList(languages: string[]): string {
|
|
45
|
+
return languages.length > 0 ? languages.join(", ") : UNKNOWN;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Scalars print as-is; anything else (missing, object) prints as unknown instead of "[object Object]". */
|
|
49
|
+
function formatScalar(value: unknown): string {
|
|
50
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : UNKNOWN;
|
|
17
51
|
}
|
|
18
52
|
|
|
19
53
|
/** `gitpagedocs config` — resolve and summarize the active gitpagedocs config. */
|
|
@@ -21,13 +55,14 @@ export async function runConfig(ctx: CommandContext): Promise<void> {
|
|
|
21
55
|
try {
|
|
22
56
|
const { config, sourcePath, extension } = await defaultConfigLoader.loadGitPageDocsConfig(ctx.cwd);
|
|
23
57
|
const site = (config as { site?: Record<string, unknown> }).site ?? {};
|
|
24
|
-
const languages = await
|
|
58
|
+
const languages = await summarizeLanguages(ctx.cwd, site);
|
|
25
59
|
// eslint-disable-next-line no-console
|
|
26
60
|
console.log(
|
|
27
61
|
`\n Config: ${path.relative(ctx.cwd, sourcePath)} (${extension})\n` +
|
|
28
|
-
` site name : ${
|
|
29
|
-
` default language : ${
|
|
30
|
-
` languages : ${languages.
|
|
62
|
+
` site name : ${formatScalar(site.name)}\n` +
|
|
63
|
+
` default language : ${formatScalar(site.defaultLanguage)}\n` +
|
|
64
|
+
` languages : ${formatList(languages.enabled)}\n` +
|
|
65
|
+
` disabled : ${formatList(languages.disabled)}\n`,
|
|
31
66
|
);
|
|
32
67
|
} catch (error) {
|
|
33
68
|
const message = isAppError(error) ? error.message : String(error);
|