From 23b8ad62a5bc590ebc635c6ba1a3f0fdce9d7ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 19:57:45 +0100 Subject: [PATCH 01/13] chore: updating the release workflow to mark release PRs for coderabbit ignore list --- .github/workflows/release.yml | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9892555..3e25c323 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,21 +46,8 @@ jobs: uses: changesets/action@v1 with: commit: "changeset-release" - title: "Release Version" + title: "Release Version [@coderabbitai ignore]" publish: pnpm -r publish env: GITHUB_TOKEN: ${{ secrets.CHANGESETS_GH_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Log Changesets outputs - run: | - echo "published: ${{ steps.changesets.outputs.published }}" - echo "publishedPackages: ${{ steps.changesets.outputs.publishedPackages }}" - echo "hasChangesets: ${{ steps.changesets.outputs.hasChangesets }}" - - # Upload docs to GCP ONLY after publishing - - name: Upload docs - if: steps.changesets.outputs.published == 'true' - uses: "./.github/actions/upload-docs" - with: - gcp_credentials: "${{ secrets.GCP_CREDENTIALS }}" From 3ac2b13ea2815f4ae4332bfced19bf36cfbf4f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:01 +0100 Subject: [PATCH 02/13] feat(internal-docs): Add CSS variable for content margin --- packages/core/src/features/internal-docs/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/features/internal-docs/index.ts b/packages/core/src/features/internal-docs/index.ts index 9ef7fcbc..40d29a8d 100644 --- a/packages/core/src/features/internal-docs/index.ts +++ b/packages/core/src/features/internal-docs/index.ts @@ -21,6 +21,7 @@ const INTERNAL_DOCS_ASSETS = { :root { --theme-color: #1b62f8; --content-max-width: 104ch; + --content-margin-inline: 16px; --sidebar-toggle-alignment: start; /* start center end */ --sidebar-toggle-bg: var(--color-mono-2); From 74354127cf118d4a3eeb7088f0e9ac5096b111a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:01 +0100 Subject: [PATCH 03/13] feat(internal-docs): Enhance link handling and directory structure --- packages/core/src/features/internal-docs/index.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/core/src/features/internal-docs/index.ts b/packages/core/src/features/internal-docs/index.ts index 40d29a8d..9c70112c 100644 --- a/packages/core/src/features/internal-docs/index.ts +++ b/packages/core/src/features/internal-docs/index.ts @@ -211,6 +211,13 @@ Docs powered by [Docsify](https:docsifyjs.org) `, }; +/** + * Remove leading "/src/" or "src/" from a URL or path, if present. + */ +function removeLeadingSrc(url: string): string { + return url.replace(/^(\.\/)?(\/?src\/)/, '/'); +} + function capitalize(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } @@ -232,7 +239,7 @@ function generateAllFolderReadmes(paths: string[]): DocFile[] { const results: DocFile[] = []; for (const folder of allFolders) { - const readmePath = `${folder}/README.md`; + const readmePath = `${removeLeadingSrc(folder)}/README.md`; if (fileSet.has(readmePath.toLowerCase())) continue; // Already has a README // Find all direct children (folders or files, but not README.md itself) @@ -250,9 +257,9 @@ function generateAllFolderReadmes(paths: string[]): DocFile[] { let md = `# ${folder.split('/').pop()}\n\n`; md += `˙\n\n > [!INFO|label:Description]\n> This is just a brief table of contents. See what's inside below:`; - md += `## Contents:\n\n`; + md += `\n\n## Contents:\n\n`; for (const child of children.sort()) { - md += `- [${child}](/${folder}/${child}/)\n`; + md += `- [${child}](/${removeLeadingSrc(folder)}/${child}/)\n`; } results.push({ path: readmePath, content: md }); } From 0701013219f371a108aa2c47d01db89ce3ca6fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:01 +0100 Subject: [PATCH 04/13] feat(internal-docs): Improve link fixing in markdown content --- .../implementations/generate-internal-docs.ts | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/core/src/implementations/generate-internal-docs.ts b/packages/core/src/implementations/generate-internal-docs.ts index 71c7c27c..12542653 100644 --- a/packages/core/src/implementations/generate-internal-docs.ts +++ b/packages/core/src/implementations/generate-internal-docs.ts @@ -23,29 +23,53 @@ function removeLeadingSrc(url: string): string { return url.replace(/^\/?src\//, '/'); } +function getParentDir(path: string): string { + // Remove trailing slash if present + path = path.replace(/\/$/, ''); + // Remove last segment (file or directory) + const parts = path.split('/'); + parts.pop(); + return parts.join('/'); +} + /** * Fix links in markdown content: * - Normalizes dynamic segments in the URL. * - Removes leading "src/" or "/src/" from the URL. * - Adjusts links to README.md and directories for Docsify. + * - Replaces leading './' in links with the parent directory of current_path. */ -function fixMarkdownLinks(content: string, allPaths: string[]): string { +function fixMarkdownLinks(content: string, current_path: string, allPaths: string[]): string { + const parentDir = getParentDir(current_path); + return content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => { let cleanUrl = url.replace(/\\/g, '/'); + + // Magic: Replace leading './' with parentDir if present + if (cleanUrl.startsWith('./')) { + cleanUrl = (parentDir ? parentDir + '/' : '') + cleanUrl.slice(2); + // Remove possible double slashes + cleanUrl = cleanUrl.replace(/\/{2,}/g, '/'); + } + cleanUrl = removeLeadingSrc(cleanUrl); cleanUrl = normalizeDynamicSegments(cleanUrl); // Handle links to README.md if (cleanUrl.endsWith('/README.md')) { cleanUrl = cleanUrl.replace(/README\.md$/, ''); - if (!cleanUrl.endsWith('/')) cleanUrl += '/'; + if (cleanUrl === '') { + cleanUrl = '/'; + } else if (!cleanUrl.endsWith('/')) { + cleanUrl += '/'; + } } else if ( allPaths.includes(joinPath(cleanUrl, 'README.md')) || allPaths.includes(cleanUrl + '/README.md') ) { - // If it's a folder, ensure trailing slash if (!cleanUrl.endsWith('/')) cleanUrl += '/'; } + // Remove double slashes except for protocol (e.g., http://) cleanUrl = cleanUrl.replace(/([^:]\/)\/+/g, '$1'); return `[${text}](${cleanUrl})`; @@ -95,7 +119,7 @@ async function generateInternalDocsImplementation({ // Now process content with all link fixes const processedMarkdownItems = markdownItems.map((item) => ({ ...item, - content: fixDynamicLinksInMarkdown(fixMarkdownLinks(item.content, allPaths)), + content: fixDynamicLinksInMarkdown(fixMarkdownLinks(item.content, item.path, allPaths)), })); const generatedReadmes = generateAllFolderReadmes(allPaths); From 072832e171bb7e5a7835b9806ac3227798ea118e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:38 +0100 Subject: [PATCH 05/13] chore: include changeset --- .changeset/brown-pugs-add.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/brown-pugs-add.md diff --git a/.changeset/brown-pugs-add.md b/.changeset/brown-pugs-add.md new file mode 100644 index 00000000..17bf9cc5 --- /dev/null +++ b/.changeset/brown-pugs-add.md @@ -0,0 +1,6 @@ +--- +"@calycode/core": patch +"@calycode/cli": patch +--- + +fix: minor fixes for the internal documentation generation From 90cec02a4a3f22e1264f77b1a2d8bb167628c962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 19:57:45 +0100 Subject: [PATCH 06/13] chore: updating the release workflow to mark release PRs for coderabbit ignore list --- .github/workflows/release.yml | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9892555..3e25c323 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,21 +46,8 @@ jobs: uses: changesets/action@v1 with: commit: "changeset-release" - title: "Release Version" + title: "Release Version [@coderabbitai ignore]" publish: pnpm -r publish env: GITHUB_TOKEN: ${{ secrets.CHANGESETS_GH_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Log Changesets outputs - run: | - echo "published: ${{ steps.changesets.outputs.published }}" - echo "publishedPackages: ${{ steps.changesets.outputs.publishedPackages }}" - echo "hasChangesets: ${{ steps.changesets.outputs.hasChangesets }}" - - # Upload docs to GCP ONLY after publishing - - name: Upload docs - if: steps.changesets.outputs.published == 'true' - uses: "./.github/actions/upload-docs" - with: - gcp_credentials: "${{ secrets.GCP_CREDENTIALS }}" From 45ce18aa389394a74a7301450d0ef58ebb66e8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:01 +0100 Subject: [PATCH 07/13] feat(internal-docs): Add CSS variable for content margin --- packages/core/src/features/internal-docs/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/features/internal-docs/index.ts b/packages/core/src/features/internal-docs/index.ts index 9ef7fcbc..40d29a8d 100644 --- a/packages/core/src/features/internal-docs/index.ts +++ b/packages/core/src/features/internal-docs/index.ts @@ -21,6 +21,7 @@ const INTERNAL_DOCS_ASSETS = { :root { --theme-color: #1b62f8; --content-max-width: 104ch; + --content-margin-inline: 16px; --sidebar-toggle-alignment: start; /* start center end */ --sidebar-toggle-bg: var(--color-mono-2); From e3068b40c582cba36c3fc0a1820541a933d297c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:01 +0100 Subject: [PATCH 08/13] feat(internal-docs): Enhance link handling and directory structure --- packages/core/src/features/internal-docs/index.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/core/src/features/internal-docs/index.ts b/packages/core/src/features/internal-docs/index.ts index 40d29a8d..9c70112c 100644 --- a/packages/core/src/features/internal-docs/index.ts +++ b/packages/core/src/features/internal-docs/index.ts @@ -211,6 +211,13 @@ Docs powered by [Docsify](https:docsifyjs.org) `, }; +/** + * Remove leading "/src/" or "src/" from a URL or path, if present. + */ +function removeLeadingSrc(url: string): string { + return url.replace(/^(\.\/)?(\/?src\/)/, '/'); +} + function capitalize(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } @@ -232,7 +239,7 @@ function generateAllFolderReadmes(paths: string[]): DocFile[] { const results: DocFile[] = []; for (const folder of allFolders) { - const readmePath = `${folder}/README.md`; + const readmePath = `${removeLeadingSrc(folder)}/README.md`; if (fileSet.has(readmePath.toLowerCase())) continue; // Already has a README // Find all direct children (folders or files, but not README.md itself) @@ -250,9 +257,9 @@ function generateAllFolderReadmes(paths: string[]): DocFile[] { let md = `# ${folder.split('/').pop()}\n\n`; md += `˙\n\n > [!INFO|label:Description]\n> This is just a brief table of contents. See what's inside below:`; - md += `## Contents:\n\n`; + md += `\n\n## Contents:\n\n`; for (const child of children.sort()) { - md += `- [${child}](/${folder}/${child}/)\n`; + md += `- [${child}](/${removeLeadingSrc(folder)}/${child}/)\n`; } results.push({ path: readmePath, content: md }); } From 2c8abbd44db59cbb6b99a4c085c7847d8d7be456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:01 +0100 Subject: [PATCH 09/13] feat(internal-docs): Improve link fixing in markdown content --- .../implementations/generate-internal-docs.ts | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/core/src/implementations/generate-internal-docs.ts b/packages/core/src/implementations/generate-internal-docs.ts index 71c7c27c..12542653 100644 --- a/packages/core/src/implementations/generate-internal-docs.ts +++ b/packages/core/src/implementations/generate-internal-docs.ts @@ -23,29 +23,53 @@ function removeLeadingSrc(url: string): string { return url.replace(/^\/?src\//, '/'); } +function getParentDir(path: string): string { + // Remove trailing slash if present + path = path.replace(/\/$/, ''); + // Remove last segment (file or directory) + const parts = path.split('/'); + parts.pop(); + return parts.join('/'); +} + /** * Fix links in markdown content: * - Normalizes dynamic segments in the URL. * - Removes leading "src/" or "/src/" from the URL. * - Adjusts links to README.md and directories for Docsify. + * - Replaces leading './' in links with the parent directory of current_path. */ -function fixMarkdownLinks(content: string, allPaths: string[]): string { +function fixMarkdownLinks(content: string, current_path: string, allPaths: string[]): string { + const parentDir = getParentDir(current_path); + return content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => { let cleanUrl = url.replace(/\\/g, '/'); + + // Magic: Replace leading './' with parentDir if present + if (cleanUrl.startsWith('./')) { + cleanUrl = (parentDir ? parentDir + '/' : '') + cleanUrl.slice(2); + // Remove possible double slashes + cleanUrl = cleanUrl.replace(/\/{2,}/g, '/'); + } + cleanUrl = removeLeadingSrc(cleanUrl); cleanUrl = normalizeDynamicSegments(cleanUrl); // Handle links to README.md if (cleanUrl.endsWith('/README.md')) { cleanUrl = cleanUrl.replace(/README\.md$/, ''); - if (!cleanUrl.endsWith('/')) cleanUrl += '/'; + if (cleanUrl === '') { + cleanUrl = '/'; + } else if (!cleanUrl.endsWith('/')) { + cleanUrl += '/'; + } } else if ( allPaths.includes(joinPath(cleanUrl, 'README.md')) || allPaths.includes(cleanUrl + '/README.md') ) { - // If it's a folder, ensure trailing slash if (!cleanUrl.endsWith('/')) cleanUrl += '/'; } + // Remove double slashes except for protocol (e.g., http://) cleanUrl = cleanUrl.replace(/([^:]\/)\/+/g, '$1'); return `[${text}](${cleanUrl})`; @@ -95,7 +119,7 @@ async function generateInternalDocsImplementation({ // Now process content with all link fixes const processedMarkdownItems = markdownItems.map((item) => ({ ...item, - content: fixDynamicLinksInMarkdown(fixMarkdownLinks(item.content, allPaths)), + content: fixDynamicLinksInMarkdown(fixMarkdownLinks(item.content, item.path, allPaths)), })); const generatedReadmes = generateAllFolderReadmes(allPaths); From be43c274c4121c804b0def7c84e9e58647a50600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Mon, 10 Nov 2025 20:35:38 +0100 Subject: [PATCH 10/13] chore: include changeset --- .changeset/brown-pugs-add.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/brown-pugs-add.md diff --git a/.changeset/brown-pugs-add.md b/.changeset/brown-pugs-add.md new file mode 100644 index 00000000..17bf9cc5 --- /dev/null +++ b/.changeset/brown-pugs-add.md @@ -0,0 +1,6 @@ +--- +"@calycode/core": patch +"@calycode/cli": patch +--- + +fix: minor fixes for the internal documentation generation From e16f6679b35da1e26a94271152aced28f7af7ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Tue, 11 Nov 2025 17:39:46 +0100 Subject: [PATCH 11/13] feat: flexible config loader to allow custom asserts via a js config file --- .changeset/salty-parrots-matter.md | 5 ++++ .../src/commands/test/implementation/test.ts | 23 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 .changeset/salty-parrots-matter.md diff --git a/.changeset/salty-parrots-matter.md b/.changeset/salty-parrots-matter.md new file mode 100644 index 00000000..f265a1b0 --- /dev/null +++ b/.changeset/salty-parrots-matter.md @@ -0,0 +1,5 @@ +--- +"@calycode/cli": minor +--- + +feat: processing js and json testconfig files as well to allow advanced asserts diff --git a/packages/cli/src/commands/test/implementation/test.ts b/packages/cli/src/commands/test/implementation/test.ts index 96aafd96..8f769126 100644 --- a/packages/cli/src/commands/test/implementation/test.ts +++ b/packages/cli/src/commands/test/implementation/test.ts @@ -1,4 +1,5 @@ import { readFile, writeFile, mkdir } from 'node:fs/promises'; +import path from 'node:path'; import { intro, log, spinner } from '@clack/prompts'; import { normalizeApiGroupName, replacePlaceholders } from '@repo/utils'; import { @@ -40,6 +41,25 @@ function printTestSummary(results) { ); } +/** + * Load and prepare the test config, either from a .json file or a .js file. + * If test config is written in .js, then custom asserts are also allowed and possible (useful for advance cases). + * @param {string} testConfigPath - where's the testconfig that we want to use? + * @returns + */ +async function loadTestConfig(testConfigPath) { + const ext = path.extname(testConfigPath).toLowerCase(); + if (ext === '.json') { + const content = await readFile(testConfigPath, 'utf8'); + return JSON.parse(content); + } else if (ext === '.js' || ext === '.ts') { + const config = require(path.resolve(testConfigPath)); + return config.default || config; + } else { + throw new Error('Unsupported test config file type.'); + } +} + async function runTest({ instance, workspace, @@ -80,8 +100,7 @@ async function runTest({ // Take the core implementation for test running: // for now testconfig has to exist on the machine prior to running the tests. - const testConfigFileContent = await readFile(testConfigPath, { encoding: 'utf-8' }); - const testConfig = JSON.parse(testConfigFileContent); + const testConfig = await loadTestConfig(testConfigPath); const s = spinner(); s.start('Running tests based on the provided spec'); const testResults = await core.runTests({ From 79b1f6401cdd6657e67cea10c3262a7a11938517 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:50:14 +0000 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`d?= =?UTF-8?q?ev`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @MihalyToth20. * https://github.com/calycode/xano-tools/pull/167#issuecomment-3517802776 The following files were modified: * `packages/cli/src/commands/test/implementation/test.ts` * `packages/core/src/features/internal-docs/index.ts` * `packages/core/src/implementations/generate-internal-docs.ts` --- .../src/commands/test/implementation/test.ts | 36 +++++++++++++--- .../core/src/features/internal-docs/index.ts | 21 +++++++++- .../implementations/generate-internal-docs.ts | 41 +++++++++++++++---- 3 files changed, 84 insertions(+), 14 deletions(-) diff --git a/packages/cli/src/commands/test/implementation/test.ts b/packages/cli/src/commands/test/implementation/test.ts index 8f769126..32781fcd 100644 --- a/packages/cli/src/commands/test/implementation/test.ts +++ b/packages/cli/src/commands/test/implementation/test.ts @@ -9,6 +9,17 @@ import { resolveConfigs, } from '../../../utils/index'; +/** + * Prints a formatted summary table of test outcomes to the log. + * + * Logs a header, one row per result showing status, HTTP method, path, and duration, and a final summary line with totals and aggregate duration. + * + * @param results - Array of test result objects. Each object should include: + * - `success` (boolean): whether the test passed, + * - `method` (string): HTTP method used, + * - `path` (string): endpoint path, + * - `duration` (number, optional): duration of the test in milliseconds + */ function printTestSummary(results) { const total = results.length; const succeeded = results.filter((r) => r.success).length; @@ -42,10 +53,13 @@ function printTestSummary(results) { } /** - * Load and prepare the test config, either from a .json file or a .js file. - * If test config is written in .js, then custom asserts are also allowed and possible (useful for advance cases). - * @param {string} testConfigPath - where's the testconfig that we want to use? - * @returns + * Load a test configuration from a file path supporting `.json`, `.js`, and `.ts` files. + * + * For `.json` files the content is read and parsed as JSON. For `.js` and `.ts` files the module is required and the `default` export is returned if present, otherwise the module itself is returned. + * + * @param testConfigPath - Filesystem path to the test configuration file + * @returns The loaded test configuration object + * @throws Error if the file extension is not `.json`, `.js`, or `.ts` */ async function loadTestConfig(testConfigPath) { const ext = path.extname(testConfigPath).toLowerCase(); @@ -60,6 +74,18 @@ async function loadTestConfig(testConfigPath) { } } +/** + * Runs API tests for selected API groups using a provided test configuration and writes per-group results to disk. + * + * @param instance - Name or alias of the target instance + * @param workspace - Workspace name within the instance + * @param branch - Branch label within the workspace + * @param group - Specific API group name to run; when omitted and `isAll` is false the user may be prompted + * @param testConfigPath - Filesystem path to the test configuration file (supported: .json, .js, .ts) + * @param isAll - If true, run tests for all API groups without prompting + * @param printOutput - If true, display the output directory path after writing results + * @param core - Runtime provider exposing `loadToken` and `runTests` used to execute tests and load credentials + */ async function runTest({ instance, workspace, @@ -142,4 +168,4 @@ async function runTest({ } } -export { runTest }; +export { runTest }; \ No newline at end of file diff --git a/packages/core/src/features/internal-docs/index.ts b/packages/core/src/features/internal-docs/index.ts index 9c70112c..ff015d64 100644 --- a/packages/core/src/features/internal-docs/index.ts +++ b/packages/core/src/features/internal-docs/index.ts @@ -212,18 +212,35 @@ Docs powered by [Docsify](https:docsifyjs.org) }; /** - * Remove leading "/src/" or "src/" from a URL or path, if present. + * Normalize a path by replacing an initial "./", "src/", or "/src/" segment with a single leading "/". + * + * @param url - The URL or filesystem path to normalize; may start with "./", "src/", or "/src/". + * @returns The input path with a leading "./", "src/", or "/src/" replaced by "/" (otherwise returns the original string). */ function removeLeadingSrc(url: string): string { return url.replace(/^(\.\/)?(\/?src\/)/, '/'); } +/** + * Capitalizes the first character of the given string. + * + * @param str - The input string; if empty, the empty string is returned. + * @returns The input string with its first character converted to uppercase. + */ function capitalize(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } type DocFile = { path: string; content: string }; +/** + * Generate README.md files for folders that do not already contain a README, based on the provided file paths. + * + * Each generated README lists the folder's direct children (subfolders or files) as a simple contents section. + * + * @param paths - Array of file paths used to infer folder structure + * @returns An array of DocFile objects, each with `path` set to the new README path and `content` containing the generated Markdown for that folder + */ function generateAllFolderReadmes(paths: string[]): DocFile[] { const fileSet = new Set(paths.map((p) => p.toLowerCase())); const folderSet = new Set(); @@ -306,4 +323,4 @@ function generateWelcomeReadme(paths: string[], welcomeReadmeTemplate: string): return welcomeReadmeTemplate.replace('{{ doc_items }}', docItems.trim()); } -export { INTERNAL_DOCS_ASSETS, generateAllFolderReadmes, generateSidebar, generateWelcomeReadme }; +export { INTERNAL_DOCS_ASSETS, generateAllFolderReadmes, generateSidebar, generateWelcomeReadme }; \ No newline at end of file diff --git a/packages/core/src/implementations/generate-internal-docs.ts b/packages/core/src/implementations/generate-internal-docs.ts index 12542653..7065cd0c 100644 --- a/packages/core/src/implementations/generate-internal-docs.ts +++ b/packages/core/src/implementations/generate-internal-docs.ts @@ -17,12 +17,21 @@ function normalizeDynamicSegments(str: string): string { } /** - * Remove leading "/src/" or "src/" from a URL or path, if present. + * Remove a leading "src/" or "/src/" prefix from a path, replacing it with a single leading slash. + * + * @param url - The path or URL to normalize + * @returns The path with a leading `src/` or `/src/` replaced by `/`, or the original `url` if no such prefix exists */ function removeLeadingSrc(url: string): string { return url.replace(/^\/?src\//, '/'); } +/** + * Compute the parent directory of a forward-slash-delimited path. + * + * @param path - The input path (file or directory) using `/` as segment separator; may include a trailing slash + * @returns The parent path with no trailing slash; returns an empty string if the input has no parent (single-segment or root) + */ function getParentDir(path: string): string { // Remove trailing slash if present path = path.replace(/\/$/, ''); @@ -33,11 +42,16 @@ function getParentDir(path: string): string { } /** - * Fix links in markdown content: - * - Normalizes dynamic segments in the URL. - * - Removes leading "src/" or "/src/" from the URL. - * - Adjusts links to README.md and directories for Docsify. - * - Replaces leading './' in links with the parent directory of current_path. + * Rewrite Markdown links so they resolve correctly for the generated docs. + * + * Rewrites link targets to remove leading `src/`, normalize dynamic segments like `{slug}`, + * convert `README.md` targets into directory-style URLs, and resolve leading `./` links + * relative to the parent directory of `current_path`. + * + * @param content - The markdown text containing links to fix + * @param current_path - Path of the current markdown file used to resolve `./`-relative links + * @param allPaths - List of normalized markdown file paths used to detect existing `README.md` targets + * @returns The markdown text with updated link targets */ function fixMarkdownLinks(content: string, current_path: string, allPaths: string[]): string { const parentDir = getParentDir(current_path); @@ -83,6 +97,19 @@ function fixDynamicLinksInMarkdown(content: string): string { return normalizeDynamicSegments(content); } +/** + * Builds a set of internal documentation files from repository JSON and storage inputs. + * + * Processes repository items into normalized markdown files with fixed links, generates folder-level README files, and adds core documentation files (index.html, README.md, _sidebar.md). + * + * @param jsonData - Repository metadata or manifest used to produce repository items + * @param storage - Storage adapter or client used to read repository file contents + * @param core - Caly core instance used by the repository generation step + * @param instance - Optional instance identifier to scope the repository generation + * @param workspace - Optional workspace identifier to scope the repository generation + * @param branch - Optional branch name to scope the repository generation + * @returns An array of objects each containing `path` and `content` for generated documentation files (processed markdown, folder readmes, and core files) + */ async function generateInternalDocsImplementation({ jsonData, storage, @@ -142,4 +169,4 @@ async function generateInternalDocsImplementation({ return [...processedMarkdownItems, ...generatedReadmes, ...coreFiles]; } -export { generateInternalDocsImplementation }; +export { generateInternalDocsImplementation }; \ No newline at end of file From a55dc7c733acf41fbaec25c30621c4b27c78ac4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20T=C3=B3th?= Date: Tue, 11 Nov 2025 17:55:10 +0100 Subject: [PATCH 13/13] fix: remove .ts reference on the loadTestConfig fn --- packages/cli/src/commands/test/implementation/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/test/implementation/test.ts b/packages/cli/src/commands/test/implementation/test.ts index 8f769126..e3fdadcf 100644 --- a/packages/cli/src/commands/test/implementation/test.ts +++ b/packages/cli/src/commands/test/implementation/test.ts @@ -52,7 +52,7 @@ async function loadTestConfig(testConfigPath) { if (ext === '.json') { const content = await readFile(testConfigPath, 'utf8'); return JSON.parse(content); - } else if (ext === '.js' || ext === '.ts') { + } else if (ext === '.js') { const config = require(path.resolve(testConfigPath)); return config.default || config; } else {