Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions packages/cli/src/commands/test/implementation/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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,
Expand Down Expand Up @@ -142,4 +168,4 @@ async function runTest({
}
}

export { runTest };
export { runTest };
21 changes: 19 additions & 2 deletions packages/core/src/features/internal-docs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>();
Expand Down Expand Up @@ -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 };
41 changes: 34 additions & 7 deletions packages/core/src/implementations/generate-internal-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(/\/$/, '');
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -142,4 +169,4 @@ async function generateInternalDocsImplementation({
return [...processedMarkdownItems, ...generatedReadmes, ...coreFiles];
}

export { generateInternalDocsImplementation };
export { generateInternalDocsImplementation };