@cyberskill/shared 3.16.0 → 3.17.0
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/node/cli/index.js
CHANGED
|
@@ -118,7 +118,12 @@ async function q() {
|
|
|
118
118
|
}
|
|
119
119
|
(async () => {
|
|
120
120
|
try {
|
|
121
|
-
await T(w(C.argv)).scriptName(g).usage("$0 <command> [options]").command("ai:setup", "Setup AI agent environment", L).command("lint", "Check code for linting issues", N).command("lint:fix", "Fix linting issues automatically", P).command("lint:inspect", "View active ESLint configuration", M).command("lint-staged", "Run lint checks on staged files", j).command("commitlint", "Validate commit message format", F).command("
|
|
121
|
+
await T(w(C.argv)).scriptName(g).usage("$0 <command> [options]").command("ai:setup", "Setup AI agent environment", L).command("lint", "Check code for linting issues", N).command("lint:fix", "Fix linting issues automatically", P).command("lint:inspect", "View active ESLint configuration", M).command("lint-staged", "Run lint checks on staged files", j).command("commitlint", "Validate commit message format", F).command("build", "Build the package", (e) => e.option("filter", {
|
|
122
|
+
describe: "Filter entry points to build",
|
|
123
|
+
type: "string"
|
|
124
|
+
}), async (e) => {
|
|
125
|
+
e.filter && (C.env.FILTER = e.filter), await p("Building package", await x.build(), { throwOnError: !0 });
|
|
126
|
+
}).command("ready", "Initialize project and dependencies", R).command("reset", "Reset the project and reinstall dependencies", z).command("inspect", "Analyze installed project dependencies", B).command("test:unit", "Run unit test suite", V).command("test:e2e", "Run end-to-end test suite", H).command("mongo:migrate:create <name>", "Create a MongoDB migration", (e) => e.positional("name", {
|
|
122
127
|
describe: "Migration name",
|
|
123
128
|
type: "string"
|
|
124
129
|
}), async (e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/node/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport process from 'node:process';\nimport { hideBin } from 'yargs/helpers';\nimport yargs from 'yargs/yargs';\n\nimport type { I_IssueEntry } from '../log/index.js';\n\nimport { clearAllErrorLists, getStoredErrorLists, resolveCommands, runCommand } from '../command/index.js';\nimport { addGitIgnoreEntry, pathExistsSync, readFileSync, removeSync, writeFileSync } from '../fs/index.js';\nimport { catchError, E_IssueType, log } from '../log/index.js';\nimport { getPackage, installDependencies } from '../package/index.js';\nimport { AG_KIT_PACKAGE_NAME, command, createGitHooksConfig, CYBERSKILL_CLI, CYBERSKILL_PACKAGE_NAME, DOT_AGENT, PATH, resolve, SIMPLE_GIT_HOOK_JSON } from '../path/index.js';\n\n/**\n * Retrieves the version from the package.json file.\n * This function reads the package.json file and extracts the version number.\n * If the file cannot be read or parsed, it returns a default version of '1.0.0'.\n *\n * @returns The version string from package.json or '1.0.0' as fallback.\n */\nfunction getVersion(): string {\n try {\n const pkg = JSON.parse(\n readFileSync(resolve(import.meta.dirname, '../../../package.json'), 'utf-8'),\n );\n return pkg.version;\n }\n catch {\n /* Intentionally empty — fallback to default version when package.json is unreadable */\n return '1.0.0';\n }\n}\n\n/**\n * Performs TypeScript validation if a TypeScript configuration file exists.\n * Uses `--incremental` mode to cache results — the first run may be slow\n * (especially with large generated files), but subsequent runs are near-instant.\n *\n * @returns A promise that resolves when the TypeScript validation is complete.\n */\nasync function checkTypescript() {\n if (!pathExistsSync(PATH.TS_CONFIG)) {\n log.warn('No TypeScript configuration found. Skipping type check.');\n return;\n }\n\n await runCommand('Performing TypeScript validation', await command.typescriptCheck());\n}\n\n/**\n * Performs ESLint checking with optional auto-fix functionality.\n * This function runs ESLint checks on the codebase and optionally applies\n * automatic fixes to resolve linting issues.\n *\n * @param fix - Whether to apply automatic fixes to linting issues (default: false).\n * @returns A promise that resolves when the ESLint check is complete.\n */\nasync function checkEslint(fix = false) {\n const commandToRun = fix ? await command.eslintFix() : await command.eslintCheck();\n const label = fix ? 'Running ESLint with auto-fix' : 'Running ESLint check';\n\n try {\n await runCommand(label, commandToRun, { timeout: 60000, throwOnError: true });\n }\n catch (error: unknown) {\n const errObj = error as { code?: string; killed?: boolean; signal?: string };\n if (errObj.code === 'ETIMEDOUT' || errObj.killed || errObj.signal === 'SIGTERM') {\n log.warn('Lint check timed out. Retrying with debug mode enabled...');\n process.env['DEBUG'] = 'true';\n await runCommand(`${label} (Debug Mode)`, commandToRun);\n }\n else {\n catchError(error);\n }\n }\n}\n\n/**\n * Prints a formatted list of issues (errors or warnings) to the console.\n * This function displays issues in a boxed format with appropriate color coding\n * based on the issue type. It only displays issues if the list is not empty.\n *\n * @param type - The type of issues to display ('Errors' or 'Warnings').\n * @param list - An array of issue entries to display.\n */\nfunction printIssues(type: 'Errors' | 'Warnings', list: I_IssueEntry[]) {\n if (!list.length) {\n return;\n }\n\n const color = type === 'Errors' ? 'red' : 'yellow';\n log.printBoxedLog(type === 'Errors' ? '✖ Errors' : '⚠ Warnings', list, color);\n}\n\n/**\n * Displays the final check results after all validation processes.\n * This function retrieves stored error lists and displays them in a formatted manner.\n * If no errors or warnings are found, it displays a success message. If errors are found,\n * it exits the process with code 1 to indicate failure.\n *\n * @returns A promise that resolves when the results are displayed.\n */\nasync function showCheckResult() {\n // Allow pending I/O (runCommand writes) to flush before reading results\n await new Promise(resolve => setImmediate(resolve));\n\n const allResults = (await getStoredErrorLists()) || [];\n const errors = allResults.filter(e => e.type === E_IssueType.Error);\n const warnings = allResults.filter(e => e.type === E_IssueType.Warning);\n\n if (!errors.length && !warnings.length) {\n log.printBoxedLog('✔ NO ISSUES FOUND', [], 'green');\n }\n else {\n printIssues('Warnings', warnings);\n printIssues('Errors', errors);\n\n if (errors.length > 0) {\n process.exit(1);\n }\n }\n}\n\n/**\n * Executes lint-staged to check only staged files.\n * This function runs lint-staged which executes linting tools only on files\n * that are staged for commit. It includes building the package if it's the current project\n * and displays the results after completion.\n *\n * @returns A promise that resolves when lint-staged execution is complete.\n */\nasync function lintStaged() {\n await clearAllErrorLists();\n const packageData = await getPackage({ name: CYBERSKILL_PACKAGE_NAME });\n\n if (!packageData.success) {\n log.error('Failed to retrieve package information. Aborting lint-staged.');\n return;\n }\n\n if (packageData.result.isCurrentProject) {\n await runCommand(`Building package: ${CYBERSKILL_PACKAGE_NAME}`, await command.build());\n }\n\n await runCommand('Executing lint-staged', await command.lintStaged());\n await showCheckResult();\n}\n\n/**\n * Inspects the ESLint configuration to show active rules and settings.\n * This function runs ESLint inspection to display the current configuration,\n * including which rules are active and their settings.\n *\n * @returns A promise that resolves when the ESLint inspection is complete.\n */\nasync function inspectLint() {\n await runCommand('Inspecting ESLint configuration', await command.eslintInspect());\n}\n\n/**\n * Performs comprehensive linting checks including TypeScript and ESLint.\n * This function runs both TypeScript validation and ESLint checks in parallel,\n * then displays the combined results.\n *\n * @returns A promise that resolves when all linting checks are complete.\n */\nasync function lintCheck() {\n await clearAllErrorLists();\n await checkTypescript();\n await checkEslint();\n await showCheckResult();\n}\n\n/**\n * Performs comprehensive linting checks with automatic fixes.\n * This function runs both TypeScript validation and ESLint checks with auto-fix\n * in parallel, then displays the combined results.\n *\n * @returns A promise that resolves when all linting checks with fixes are complete.\n */\nasync function lintFix() {\n await clearAllErrorLists();\n await checkTypescript();\n await checkEslint(true);\n await showCheckResult();\n}\n\n/**\n * Validates commit message format using commitlint.\n * This function runs commitlint to check if the current commit message\n * follows the conventional commit format and displays the results.\n *\n * @returns A promise that resolves when commit message validation is complete.\n */\nasync function commitLint() {\n await clearAllErrorLists();\n await runCommand('Validating commit message', await command.commitLint());\n await showCheckResult();\n}\n\n/**\n * Sets up Git hooks for automated code quality checks.\n * This function configures Git hooks using simple-git-hooks, creates the necessary\n * configuration files, and updates .gitignore to exclude hook configuration files.\n * It also sets up the hooks to run linting and commit validation automatically.\n *\n * @returns A promise that resolves when Git hook setup is complete.\n */\nasync function gitHookSetup() {\n await runCommand('Configuring Git hooks', await command.configureGitHook());\n\n removeSync(PATH.GIT_HOOK);\n\n const hooks = await resolveCommands(createGitHooksConfig);\n\n writeFileSync(PATH.SIMPLE_GIT_HOOKS_JSON, JSON.stringify(hooks, null, 4));\n\n addGitIgnoreEntry(PATH.GIT_IGNORE, SIMPLE_GIT_HOOK_JSON);\n\n await runCommand('Setting up simple-git-hooks', await command.simpleGitHooks());\n}\n\n/**\n * Sets up the AI agent environment.\n * This function ensures the ag-kit package is installed globally, initializes\n * or updates the AI agent configuration, and adds the agent directory\n * to .gitignore to exclude it from version control.\n *\n * @returns A promise that resolves when the AI agent setup is complete.\n */\nasync function aiSetup() {\n try {\n await runCommand(`Checking for ${AG_KIT_PACKAGE_NAME}`, `pnpm list -g ${AG_KIT_PACKAGE_NAME}`);\n }\n catch {\n /* Package not found globally — install it */\n await runCommand(`Installing ${AG_KIT_PACKAGE_NAME} globally`, `pnpm i -g ${AG_KIT_PACKAGE_NAME}`);\n }\n\n if (pathExistsSync(PATH.DOT_AGENT)) {\n await runCommand('Updating AI agent', 'echo y | ag-kit update');\n }\n else {\n await runCommand('Initializing AI agent', 'ag-kit init');\n }\n\n addGitIgnoreEntry(PATH.GIT_EXCLUDE, DOT_AGENT);\n}\n\n/**\n * Initializes the project with dependencies and Git hooks.\n * This function installs project dependencies and sets up Git hooks for\n * automated code quality checks. It's typically run when setting up a new project.\n *\n * @returns A promise that resolves when project initialization is complete.\n */\nasync function ready() {\n await installDependencies();\n await gitHookSetup();\n}\n\n/**\n * Resets the project by removing dependencies and reinstalling them.\n * This function removes node_modules and lock files, cleans the package manager cache,\n * reinstalls dependencies, and sets up Git hooks. It's useful for resolving\n * dependency-related issues.\n *\n * @returns A promise that resolves when project reset is complete.\n */\nasync function reset() {\n removeSync(PATH.NODE_MODULES, PATH.PNPM_LOCK_YAML, PATH.SIMPLE_GIT_HOOKS_JSON);\n await runCommand('Pruning pnpm store', await command.pnpmPruneStore());\n await runCommand('Clearing pnpm cache', await command.pnpmCleanCache());\n await installDependencies();\n await gitHookSetup();\n // await aiSetup();\n}\n\n/**\n * Inspects project dependencies to analyze their status.\n * This function runs dependency inspection to check for outdated packages,\n * security vulnerabilities, and other dependency-related issues.\n *\n * @returns A promise that resolves when dependency inspection is complete.\n */\nasync function inspect() {\n await runCommand('Inspecting project dependencies', await command.nodeModulesInspect());\n}\n\n/**\n * Runs the unit test suite.\n * This function executes unit tests using the configured test runner\n * and displays the test results.\n *\n * @returns A promise that resolves when unit tests are complete.\n */\nasync function testUnit() {\n try {\n const cmd = await command.testUnit();\n\n await runCommand('Running unit tests', cmd, { throwOnError: true });\n }\n catch (error) {\n log.error(error);\n process.exit(1);\n }\n}\n\n/**\n * Runs the end-to-end test suite.\n * This function executes end-to-end tests using the configured test runner\n * and displays the test results.\n *\n * @returns A promise that resolves when end-to-end tests are complete.\n */\nasync function testE2E() {\n try {\n const cmd = await command.testE2e();\n\n await runCommand('Running end-to-end tests', cmd, { throwOnError: true });\n }\n catch (error) {\n log.error(error);\n process.exit(1);\n }\n}\n\n/**\n * Creates a new MongoDB migration file.\n * This function creates a new migration file with the specified name\n * for database schema changes.\n *\n * @param migrationName - The name for the new migration file.\n * @returns A promise that resolves when the migration file is created.\n */\nasync function mongoMigrateCreate(migrationName: string) {\n await runCommand('Creating MongoDB migration', await command.mongoMigrateCreate(migrationName));\n}\n\n/**\n * Applies all pending MongoDB migrations.\n * This function runs all pending database migrations to update the database schema\n * to the latest version.\n *\n * @returns A promise that resolves when all migrations are applied.\n */\nasync function mongoMigrateUp() {\n await runCommand('Running MongoDB migrations', await command.mongoMigrateUp());\n}\n\n/**\n * Rolls back the last applied MongoDB migration.\n * This function reverts the most recent database migration, undoing\n * the last schema change.\n *\n * @returns A promise that resolves when the migration is rolled back.\n */\nasync function mongoMigrateDown() {\n await runCommand('Rolling back MongoDB migration', await command.mongoMigrateDown());\n}\n\n/**\n * Starts the Storybook development server.\n * This function runs Storybook in development mode, allowing you to\n * view and interact with your component stories in a browser.\n *\n * @returns A promise that resolves when the Storybook dev server is started.\n */\nasync function storybookDev() {\n await runCommand('Starting Storybook development server', await command.storybookDev());\n}\n\n/**\n * Builds Storybook for production deployment.\n * This function creates a static build of Storybook that can be\n * deployed to a web server or hosting service.\n *\n * @returns A promise that resolves when the Storybook build is complete.\n */\nasync function storybookBuild() {\n await runCommand('Building Storybook', await command.storybookBuild());\n}\n\n(async () => {\n try {\n await yargs(hideBin(process.argv))\n .scriptName(CYBERSKILL_CLI)\n .usage('$0 <command> [options]')\n .command('ai:setup', 'Setup AI agent environment', aiSetup)\n .command('lint', 'Check code for linting issues', lintCheck)\n .command('lint:fix', 'Fix linting issues automatically', lintFix)\n .command('lint:inspect', 'View active ESLint configuration', inspectLint)\n .command('lint-staged', 'Run lint checks on staged files', lintStaged)\n .command('commitlint', 'Validate commit message format', commitLint)\n .command('ready', 'Initialize project and dependencies', ready)\n .command('reset', 'Reset the project and reinstall dependencies', reset)\n .command('inspect', 'Analyze installed project dependencies', inspect)\n .command('test:unit', 'Run unit test suite', testUnit)\n .command('test:e2e', 'Run end-to-end test suite', testE2E)\n .command('mongo:migrate:create <name>', 'Create a MongoDB migration', y =>\n y.positional('name', {\n describe: 'Migration name',\n type: 'string',\n }), async (argv) => {\n if (!argv.name) {\n log.error('Migration name is required.');\n\n return;\n }\n\n await mongoMigrateCreate(argv.name);\n })\n .command('mongo:migrate:up', 'Apply all MongoDB migrations', mongoMigrateUp)\n .command('mongo:migrate:down', 'Rollback last MongoDB migration', mongoMigrateDown)\n .command('storybook:dev', 'Start Storybook development server', storybookDev)\n .command('storybook:build', 'Build Storybook for production', storybookBuild)\n .example('$0 lint:fix', 'Automatically block and fix linter errors')\n .example('$0 test:unit', 'Run the unit test suite')\n .example('$0 mongo:migrate:create init_db', 'Create a new migration file named \"init_db\"')\n .demandCommand(1, 'Please specify a valid command.')\n .strict()\n .help()\n .alias('h', 'help')\n .alias('v', 'version')\n .version(getVersion())\n .epilog('💡 Tip: Use \"--help\" with any command to see options\\n')\n .parse();\n }\n catch (error) {\n catchError(error);\n process.exit(1);\n }\n})();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/node/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport process from 'node:process';\nimport { hideBin } from 'yargs/helpers';\nimport yargs from 'yargs/yargs';\n\nimport type { I_IssueEntry } from '../log/index.js';\n\nimport { clearAllErrorLists, getStoredErrorLists, resolveCommands, runCommand } from '../command/index.js';\nimport { addGitIgnoreEntry, pathExistsSync, readFileSync, removeSync, writeFileSync } from '../fs/index.js';\nimport { catchError, E_IssueType, log } from '../log/index.js';\nimport { getPackage, installDependencies } from '../package/index.js';\nimport { AG_KIT_PACKAGE_NAME, command, createGitHooksConfig, CYBERSKILL_CLI, CYBERSKILL_PACKAGE_NAME, DOT_AGENT, PATH, resolve, SIMPLE_GIT_HOOK_JSON } from '../path/index.js';\n\n/**\n * Retrieves the version from the package.json file.\n * This function reads the package.json file and extracts the version number.\n * If the file cannot be read or parsed, it returns a default version of '1.0.0'.\n *\n * @returns The version string from package.json or '1.0.0' as fallback.\n */\nfunction getVersion(): string {\n try {\n const pkg = JSON.parse(\n readFileSync(resolve(import.meta.dirname, '../../../package.json'), 'utf-8'),\n );\n return pkg.version;\n }\n catch {\n /* Intentionally empty — fallback to default version when package.json is unreadable */\n return '1.0.0';\n }\n}\n\n/**\n * Performs TypeScript validation if a TypeScript configuration file exists.\n * Uses `--incremental` mode to cache results — the first run may be slow\n * (especially with large generated files), but subsequent runs are near-instant.\n *\n * @returns A promise that resolves when the TypeScript validation is complete.\n */\nasync function checkTypescript() {\n if (!pathExistsSync(PATH.TS_CONFIG)) {\n log.warn('No TypeScript configuration found. Skipping type check.');\n return;\n }\n\n await runCommand('Performing TypeScript validation', await command.typescriptCheck());\n}\n\n/**\n * Performs ESLint checking with optional auto-fix functionality.\n * This function runs ESLint checks on the codebase and optionally applies\n * automatic fixes to resolve linting issues.\n *\n * @param fix - Whether to apply automatic fixes to linting issues (default: false).\n * @returns A promise that resolves when the ESLint check is complete.\n */\nasync function checkEslint(fix = false) {\n const commandToRun = fix ? await command.eslintFix() : await command.eslintCheck();\n const label = fix ? 'Running ESLint with auto-fix' : 'Running ESLint check';\n\n try {\n await runCommand(label, commandToRun, { timeout: 60000, throwOnError: true });\n }\n catch (error: unknown) {\n const errObj = error as { code?: string; killed?: boolean; signal?: string };\n if (errObj.code === 'ETIMEDOUT' || errObj.killed || errObj.signal === 'SIGTERM') {\n log.warn('Lint check timed out. Retrying with debug mode enabled...');\n process.env['DEBUG'] = 'true';\n await runCommand(`${label} (Debug Mode)`, commandToRun);\n }\n else {\n catchError(error);\n }\n }\n}\n\n/**\n * Prints a formatted list of issues (errors or warnings) to the console.\n * This function displays issues in a boxed format with appropriate color coding\n * based on the issue type. It only displays issues if the list is not empty.\n *\n * @param type - The type of issues to display ('Errors' or 'Warnings').\n * @param list - An array of issue entries to display.\n */\nfunction printIssues(type: 'Errors' | 'Warnings', list: I_IssueEntry[]) {\n if (!list.length) {\n return;\n }\n\n const color = type === 'Errors' ? 'red' : 'yellow';\n log.printBoxedLog(type === 'Errors' ? '✖ Errors' : '⚠ Warnings', list, color);\n}\n\n/**\n * Displays the final check results after all validation processes.\n * This function retrieves stored error lists and displays them in a formatted manner.\n * If no errors or warnings are found, it displays a success message. If errors are found,\n * it exits the process with code 1 to indicate failure.\n *\n * @returns A promise that resolves when the results are displayed.\n */\nasync function showCheckResult() {\n // Allow pending I/O (runCommand writes) to flush before reading results\n await new Promise(resolve => setImmediate(resolve));\n\n const allResults = (await getStoredErrorLists()) || [];\n const errors = allResults.filter(e => e.type === E_IssueType.Error);\n const warnings = allResults.filter(e => e.type === E_IssueType.Warning);\n\n if (!errors.length && !warnings.length) {\n log.printBoxedLog('✔ NO ISSUES FOUND', [], 'green');\n }\n else {\n printIssues('Warnings', warnings);\n printIssues('Errors', errors);\n\n if (errors.length > 0) {\n process.exit(1);\n }\n }\n}\n\n/**\n * Executes lint-staged to check only staged files.\n * This function runs lint-staged which executes linting tools only on files\n * that are staged for commit. It includes building the package if it's the current project\n * and displays the results after completion.\n *\n * @returns A promise that resolves when lint-staged execution is complete.\n */\nasync function lintStaged() {\n await clearAllErrorLists();\n const packageData = await getPackage({ name: CYBERSKILL_PACKAGE_NAME });\n\n if (!packageData.success) {\n log.error('Failed to retrieve package information. Aborting lint-staged.');\n return;\n }\n\n if (packageData.result.isCurrentProject) {\n await runCommand(`Building package: ${CYBERSKILL_PACKAGE_NAME}`, await command.build());\n }\n\n await runCommand('Executing lint-staged', await command.lintStaged());\n await showCheckResult();\n}\n\n/**\n * Inspects the ESLint configuration to show active rules and settings.\n * This function runs ESLint inspection to display the current configuration,\n * including which rules are active and their settings.\n *\n * @returns A promise that resolves when the ESLint inspection is complete.\n */\nasync function inspectLint() {\n await runCommand('Inspecting ESLint configuration', await command.eslintInspect());\n}\n\n/**\n * Performs comprehensive linting checks including TypeScript and ESLint.\n * This function runs both TypeScript validation and ESLint checks in parallel,\n * then displays the combined results.\n *\n * @returns A promise that resolves when all linting checks are complete.\n */\nasync function lintCheck() {\n await clearAllErrorLists();\n await checkTypescript();\n await checkEslint();\n await showCheckResult();\n}\n\n/**\n * Performs comprehensive linting checks with automatic fixes.\n * This function runs both TypeScript validation and ESLint checks with auto-fix\n * in parallel, then displays the combined results.\n *\n * @returns A promise that resolves when all linting checks with fixes are complete.\n */\nasync function lintFix() {\n await clearAllErrorLists();\n await checkTypescript();\n await checkEslint(true);\n await showCheckResult();\n}\n\n/**\n * Validates commit message format using commitlint.\n * This function runs commitlint to check if the current commit message\n * follows the conventional commit format and displays the results.\n *\n * @returns A promise that resolves when commit message validation is complete.\n */\nasync function commitLint() {\n await clearAllErrorLists();\n await runCommand('Validating commit message', await command.commitLint());\n await showCheckResult();\n}\n\n/**\n * Sets up Git hooks for automated code quality checks.\n * This function configures Git hooks using simple-git-hooks, creates the necessary\n * configuration files, and updates .gitignore to exclude hook configuration files.\n * It also sets up the hooks to run linting and commit validation automatically.\n *\n * @returns A promise that resolves when Git hook setup is complete.\n */\nasync function gitHookSetup() {\n await runCommand('Configuring Git hooks', await command.configureGitHook());\n\n removeSync(PATH.GIT_HOOK);\n\n const hooks = await resolveCommands(createGitHooksConfig);\n\n writeFileSync(PATH.SIMPLE_GIT_HOOKS_JSON, JSON.stringify(hooks, null, 4));\n\n addGitIgnoreEntry(PATH.GIT_IGNORE, SIMPLE_GIT_HOOK_JSON);\n\n await runCommand('Setting up simple-git-hooks', await command.simpleGitHooks());\n}\n\n/**\n * Sets up the AI agent environment.\n * This function ensures the ag-kit package is installed globally, initializes\n * or updates the AI agent configuration, and adds the agent directory\n * to .gitignore to exclude it from version control.\n *\n * @returns A promise that resolves when the AI agent setup is complete.\n */\nasync function aiSetup() {\n try {\n await runCommand(`Checking for ${AG_KIT_PACKAGE_NAME}`, `pnpm list -g ${AG_KIT_PACKAGE_NAME}`);\n }\n catch {\n /* Package not found globally — install it */\n await runCommand(`Installing ${AG_KIT_PACKAGE_NAME} globally`, `pnpm i -g ${AG_KIT_PACKAGE_NAME}`);\n }\n\n if (pathExistsSync(PATH.DOT_AGENT)) {\n await runCommand('Updating AI agent', 'echo y | ag-kit update');\n }\n else {\n await runCommand('Initializing AI agent', 'ag-kit init');\n }\n\n addGitIgnoreEntry(PATH.GIT_EXCLUDE, DOT_AGENT);\n}\n\n/**\n * Initializes the project with dependencies and Git hooks.\n * This function installs project dependencies and sets up Git hooks for\n * automated code quality checks. It's typically run when setting up a new project.\n *\n * @returns A promise that resolves when project initialization is complete.\n */\nasync function ready() {\n await installDependencies();\n await gitHookSetup();\n}\n\n/**\n * Resets the project by removing dependencies and reinstalling them.\n * This function removes node_modules and lock files, cleans the package manager cache,\n * reinstalls dependencies, and sets up Git hooks. It's useful for resolving\n * dependency-related issues.\n *\n * @returns A promise that resolves when project reset is complete.\n */\nasync function reset() {\n removeSync(PATH.NODE_MODULES, PATH.PNPM_LOCK_YAML, PATH.SIMPLE_GIT_HOOKS_JSON);\n await runCommand('Pruning pnpm store', await command.pnpmPruneStore());\n await runCommand('Clearing pnpm cache', await command.pnpmCleanCache());\n await installDependencies();\n await gitHookSetup();\n // await aiSetup();\n}\n\n/**\n * Inspects project dependencies to analyze their status.\n * This function runs dependency inspection to check for outdated packages,\n * security vulnerabilities, and other dependency-related issues.\n *\n * @returns A promise that resolves when dependency inspection is complete.\n */\nasync function inspect() {\n await runCommand('Inspecting project dependencies', await command.nodeModulesInspect());\n}\n\n/**\n * Runs the unit test suite.\n * This function executes unit tests using the configured test runner\n * and displays the test results.\n *\n * @returns A promise that resolves when unit tests are complete.\n */\nasync function testUnit() {\n try {\n const cmd = await command.testUnit();\n\n await runCommand('Running unit tests', cmd, { throwOnError: true });\n }\n catch (error) {\n log.error(error);\n process.exit(1);\n }\n}\n\n/**\n * Runs the end-to-end test suite.\n * This function executes end-to-end tests using the configured test runner\n * and displays the test results.\n *\n * @returns A promise that resolves when end-to-end tests are complete.\n */\nasync function testE2E() {\n try {\n const cmd = await command.testE2e();\n\n await runCommand('Running end-to-end tests', cmd, { throwOnError: true });\n }\n catch (error) {\n log.error(error);\n process.exit(1);\n }\n}\n\n/**\n * Creates a new MongoDB migration file.\n * This function creates a new migration file with the specified name\n * for database schema changes.\n *\n * @param migrationName - The name for the new migration file.\n * @returns A promise that resolves when the migration file is created.\n */\nasync function mongoMigrateCreate(migrationName: string) {\n await runCommand('Creating MongoDB migration', await command.mongoMigrateCreate(migrationName));\n}\n\n/**\n * Applies all pending MongoDB migrations.\n * This function runs all pending database migrations to update the database schema\n * to the latest version.\n *\n * @returns A promise that resolves when all migrations are applied.\n */\nasync function mongoMigrateUp() {\n await runCommand('Running MongoDB migrations', await command.mongoMigrateUp());\n}\n\n/**\n * Rolls back the last applied MongoDB migration.\n * This function reverts the most recent database migration, undoing\n * the last schema change.\n *\n * @returns A promise that resolves when the migration is rolled back.\n */\nasync function mongoMigrateDown() {\n await runCommand('Rolling back MongoDB migration', await command.mongoMigrateDown());\n}\n\n/**\n * Starts the Storybook development server.\n * This function runs Storybook in development mode, allowing you to\n * view and interact with your component stories in a browser.\n *\n * @returns A promise that resolves when the Storybook dev server is started.\n */\nasync function storybookDev() {\n await runCommand('Starting Storybook development server', await command.storybookDev());\n}\n\n/**\n * Builds Storybook for production deployment.\n * This function creates a static build of Storybook that can be\n * deployed to a web server or hosting service.\n *\n * @returns A promise that resolves when the Storybook build is complete.\n */\nasync function storybookBuild() {\n await runCommand('Building Storybook', await command.storybookBuild());\n}\n\n(async () => {\n try {\n await yargs(hideBin(process.argv))\n .scriptName(CYBERSKILL_CLI)\n .usage('$0 <command> [options]')\n .command('ai:setup', 'Setup AI agent environment', aiSetup)\n .command('lint', 'Check code for linting issues', lintCheck)\n .command('lint:fix', 'Fix linting issues automatically', lintFix)\n .command('lint:inspect', 'View active ESLint configuration', inspectLint)\n .command('lint-staged', 'Run lint checks on staged files', lintStaged)\n .command('commitlint', 'Validate commit message format', commitLint)\n .command('build', 'Build the package', y =>\n y.option('filter', {\n describe: 'Filter entry points to build',\n type: 'string',\n }), async (argv) => {\n if (argv.filter) {\n process.env['FILTER'] = argv.filter;\n }\n await runCommand('Building package', await command.build(), { throwOnError: true });\n })\n .command('ready', 'Initialize project and dependencies', ready)\n .command('reset', 'Reset the project and reinstall dependencies', reset)\n .command('inspect', 'Analyze installed project dependencies', inspect)\n .command('test:unit', 'Run unit test suite', testUnit)\n .command('test:e2e', 'Run end-to-end test suite', testE2E)\n .command('mongo:migrate:create <name>', 'Create a MongoDB migration', y =>\n y.positional('name', {\n describe: 'Migration name',\n type: 'string',\n }), async (argv) => {\n if (!argv.name) {\n log.error('Migration name is required.');\n\n return;\n }\n\n await mongoMigrateCreate(argv.name);\n })\n .command('mongo:migrate:up', 'Apply all MongoDB migrations', mongoMigrateUp)\n .command('mongo:migrate:down', 'Rollback last MongoDB migration', mongoMigrateDown)\n .command('storybook:dev', 'Start Storybook development server', storybookDev)\n .command('storybook:build', 'Build Storybook for production', storybookBuild)\n .example('$0 lint:fix', 'Automatically block and fix linter errors')\n .example('$0 test:unit', 'Run the unit test suite')\n .example('$0 mongo:migrate:create init_db', 'Create a new migration file named \"init_db\"')\n .demandCommand(1, 'Please specify a valid command.')\n .strict()\n .help()\n .alias('h', 'help')\n .alias('v', 'version')\n .version(getVersion())\n .epilog('💡 Tip: Use \"--help\" with any command to see options\\n')\n .parse();\n }\n catch (error) {\n catchError(error);\n process.exit(1);\n }\n})();\n"],"mappings":"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"}
|
|
@@ -146,12 +146,27 @@ var f = {
|
|
|
146
146
|
return s.filter((e) => t.some((t) => n(e, t)));
|
|
147
147
|
},
|
|
148
148
|
health(e) {
|
|
149
|
-
let t = e.connection;
|
|
149
|
+
let t = e.connection, n = null;
|
|
150
|
+
try {
|
|
151
|
+
let e = t.getClient?.() ?? t.client;
|
|
152
|
+
if (e?.topology?.s?.servers && e.topology.s.servers instanceof Map) {
|
|
153
|
+
let t = 0, r = 0;
|
|
154
|
+
e.topology.s.servers.forEach((e) => {
|
|
155
|
+
let n = e.s?.pool;
|
|
156
|
+
n && (t += n.totalConnectionCount ?? 0, r += n.availableConnectionCount ?? 0);
|
|
157
|
+
}), n = {
|
|
158
|
+
totalConnections: t,
|
|
159
|
+
availableConnections: r
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
} catch {}
|
|
150
163
|
return {
|
|
151
164
|
readyState: t.readyState,
|
|
152
165
|
host: t.host,
|
|
153
166
|
name: t.name,
|
|
154
|
-
models: Object.keys(e.models).length
|
|
167
|
+
models: Object.keys(e.models).length,
|
|
168
|
+
pool: n,
|
|
169
|
+
poolMetricsAvailable: n !== null
|
|
155
170
|
};
|
|
156
171
|
}
|
|
157
172
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mongo.util.js","names":[],"sources":["../../../src/node/mongo/mongo.util.ts"],"sourcesContent":["import type migrate from 'migrate-mongo';\nimport type mongooseRaw from 'mongoose';\n\nimport aggregatePaginate from 'mongoose-aggregate-paginate-v2';\nimport mongoosePaginate from 'mongoose-paginate-v2';\nimport { randomUUID } from 'node:crypto';\n\nimport { getNestedValue, regexSearchMapper, setNestedValue } from '#util/index.js';\nimport { validate } from '#util/validate/index.js';\n\nimport type { MongoController } from './mongo.controller.js';\nimport type { C_Document, I_CreateModelOptions, I_CreateSchemaOptions, I_DynamicVirtualConfig, I_DynamicVirtualOptions, I_ExtendedModel, I_GenericDocument, I_MongooseModelMiddleware, T_Filter, T_MongoosePlugin, T_MongooseSchema, T_QueryFilter, T_VirtualOptions, T_WithId } from './mongo.type.js';\n\nimport { addGitIgnoreEntry, writeFileSync } from '../fs/index.js';\nimport { MIGRATE_MONGO_CONFIG, PATH } from '../path/index.js';\n/**\n * Converts enum values to proper model names.\n * Handles common naming conventions like converting 'USER' to 'User'.\n *\n * @param enumValue - The enum value to convert\n * @returns The converted model name\n */\nexport function convertEnumToModelName(enumValue: string): string {\n if (enumValue === enumValue.toUpperCase()) {\n return enumValue.charAt(0).toUpperCase() + enumValue.slice(1).toLowerCase();\n }\n\n return enumValue;\n}\n\n/**\n * Interface for the MongoDB utility object to enable explicit type annotation.\n * Required to avoid TS7056 (inferred type exceeds maximum serialization length).\n */\ninterface I_MongoUtils {\n createGenericFields: () => I_GenericDocument;\n applyPlugins: <T>(schema: T_MongooseSchema<T>, plugins: Array<T_MongoosePlugin | false>) => void;\n applyMiddlewares: <T extends Partial<C_Document>>(schema: T_MongooseSchema<T>, middlewares: I_MongooseModelMiddleware<T>[]) => void;\n createGenericSchema: (mongoose: typeof mongooseRaw) => T_MongooseSchema<I_GenericDocument>;\n createSchema: <T, R extends string = string>(options: I_CreateSchemaOptions<T, R>) => T_MongooseSchema<T>;\n createModel: <T extends Partial<C_Document>, R extends string = string>(options: I_CreateModelOptions<T, R>) => I_ExtendedModel<T>;\n validator: {\n isRequired: <T>() => (this: T, value: unknown) => Promise<boolean>;\n isUnique: <T extends { constructor: { exists: (query: { [key: string]: unknown }) => Promise<unknown> } }>(fields: string[]) => (this: T, value: unknown) => Promise<boolean>;\n matchesRegex: (regexArray: RegExp[]) => (value: string) => Promise<boolean>;\n };\n migrate: {\n getModule: () => Promise<typeof migrate>;\n setConfig: (options: Partial<migrate.config.Config> & { moduleSystem?: 'commonjs' | 'esm' }) => void;\n };\n regexify: <T>(filter?: T_QueryFilter<T>, fields?: (keyof T | string)[]) => T_QueryFilter<T>;\n isDynamicVirtual: <T, R extends string>(options?: T_VirtualOptions<T, R>) => options is I_DynamicVirtualOptions<T, R>;\n getNewRecords: <T extends I_GenericDocument>(controller: MongoController<T>, recordsToCheck: T[], filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean, filter?: T_Filter<T>) => Promise<T[]>;\n getExistingRecords: <T extends I_GenericDocument>(controller: MongoController<T>, recordsToCheck: T[], filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean, filter?: T_Filter<T>) => Promise<T_WithId<T>[]>;\n health: (mongooseInstance: typeof mongooseRaw) => Record<string, unknown>;\n}\n\n/**\n * MongoDB utility object providing comprehensive database operations and utilities.\n * This object contains methods for creating generic fields, applying plugins and middlewares,\n * creating schemas and models, validation functions, migration utilities, and regex filtering.\n */\nexport const mongo: I_MongoUtils = {\n /**\n * Creates generic fields that are commonly used across MongoDB documents.\n * This function generates standard fields including a UUID, deletion flag, and timestamps\n * that can be applied to any document schema.\n *\n * @returns An object containing generic document fields (id, isDel, createdAt, updatedAt).\n */\n createGenericFields(): I_GenericDocument {\n return {\n id: randomUUID(),\n isDel: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n },\n /**\n * Applies plugins to a Mongoose schema.\n * This function filters out falsy plugins and applies the remaining valid plugins\n * to the provided schema.\n *\n * @param schema - The Mongoose schema to apply plugins to.\n * @param plugins - An array of plugin functions or false values to filter and apply.\n */\n applyPlugins<T>(schema: T_MongooseSchema<T>, plugins: Array<T_MongoosePlugin | false>) {\n plugins\n .filter((plugin): plugin is T_MongoosePlugin => typeof plugin === 'function')\n .forEach(plugin => schema.plugin(plugin));\n },\n /**\n * Applies middleware functions to a Mongoose schema.\n * This function configures pre and post middleware for specified methods on the schema.\n *\n * @param schema - The Mongoose schema to apply middleware to.\n * @param middlewares - An array of middleware configurations with method, pre, and post functions.\n */\n applyMiddlewares<T extends Partial<C_Document>>(\n schema: T_MongooseSchema<T>,\n middlewares: I_MongooseModelMiddleware<T>[],\n ) {\n middlewares.forEach(({ method, pre, post }) => {\n if (method && pre) {\n schema.pre(method as RegExp, pre);\n }\n\n if (method && post) {\n schema.post(method as RegExp, post);\n }\n });\n },\n /**\n * Creates a generic Mongoose schema with common fields.\n * This function creates a base schema with UUID field and deletion flag,\n * configured with automatic timestamps.\n *\n * @param mongoose - The Mongoose instance to create the schema with.\n * @returns A Mongoose schema with generic document fields.\n */\n createGenericSchema(mongoose: typeof mongooseRaw) {\n return new mongoose.Schema<I_GenericDocument>(\n {\n id: { type: String, default: () => randomUUID(), unique: true },\n isDel: { type: Boolean, default: false },\n },\n { timestamps: true },\n );\n },\n /**\n * Creates a Mongoose schema with optional virtual fields and generic fields.\n * This function creates a new Mongoose schema from the provided schema definition,\n * optionally adds virtual fields, and includes generic fields (unless standalone is true).\n *\n * @param options - Configuration options including mongoose instance, schema definition, virtuals, and standalone flag.\n * @param options.mongoose - The Mongoose instance to use for schema creation.\n * @param options.schema - The schema definition object.\n * @param options.virtuals - Optional array of virtual field configurations.\n * @param options.standalone - Whether to exclude generic fields (default: false).\n * @returns A configured Mongoose schema.\n */\n createSchema<T, R extends string = string>({\n mongoose,\n schema,\n virtuals = [],\n standalone = false,\n }: I_CreateSchemaOptions<T, R>): T_MongooseSchema<T> {\n const createdSchema = new mongoose.Schema<T>(schema, {\n toJSON: { virtuals: true }, // So `res.json()` and other `JSON.stringify()` functions include virtuals\n toObject: { virtuals: true }, // So `console.log()` and other functions that use `toObject()` include virtuals\n });\n\n virtuals.forEach(({ name, options, get }) => {\n if (mongo.isDynamicVirtual<T, R>(options)) {\n const schemaStatics = createdSchema.statics as Record<string, unknown>;\n\n if (!schemaStatics['_dynamicVirtuals']) {\n schemaStatics['_dynamicVirtuals'] = [];\n }\n\n (schemaStatics['_dynamicVirtuals'] as I_DynamicVirtualConfig<T>[]).push({\n name: name as string,\n options,\n });\n\n const virtualInstance = createdSchema.virtual(name as string);\n\n if (get) {\n virtualInstance.get(get);\n }\n else {\n virtualInstance.get(function (this: T & { _populated?: { [key: string]: unknown } }) {\n return this._populated?.[name as string] || (options?.count ? 0 : (options?.justOne ? null : []));\n });\n }\n }\n else {\n const virtualInstance = createdSchema.virtual(name as string, options);\n\n if (get) {\n virtualInstance.get(get);\n }\n }\n });\n\n if (!standalone) {\n createdSchema.add(mongo.createGenericSchema(mongoose));\n }\n\n return createdSchema;\n },\n /**\n * Creates a Mongoose model with plugins, middleware, and pagination support.\n * This function creates a model from a schema with optional pagination and aggregation plugins,\n * and applies any specified middleware. If a model with the same name already exists, it returns the existing model.\n *\n * @param options - Configuration options including mongoose instance, model name, schema, and feature flags.\n * @param options.mongoose - The Mongoose instance to use for model creation.\n * @param options.name - The name of the model to create.\n * @param options.schema - The schema definition for the model.\n * @param options.pagination - Whether to enable pagination plugin (default: false).\n * @param options.aggregate - Whether to enable aggregation pagination plugin (default: false).\n * @param options.virtuals - Optional array of virtual field configurations.\n * @param options.middlewares - Optional array of middleware configurations.\n * @returns A configured Mongoose model with extended functionality.\n * @throws {Error} When the model name is not provided.\n */\n createModel<T extends Partial<C_Document>, R extends string = string>({\n mongoose: currentMongooseInstance,\n name,\n schema,\n virtuals = [],\n pagination = true,\n aggregate = true,\n middlewares = [],\n }: I_CreateModelOptions<T, R>): I_ExtendedModel<T> {\n if (!name) {\n throw new Error('Model name is required.');\n }\n\n if (currentMongooseInstance.models[name]) {\n return currentMongooseInstance.models[name] as I_ExtendedModel<T>;\n }\n\n const createdSchema = mongo.createSchema({ mongoose: currentMongooseInstance, schema, virtuals });\n\n if (pagination || aggregate) {\n mongo.applyPlugins<T>(createdSchema, [\n pagination && mongoosePaginate,\n aggregate && aggregatePaginate,\n ]);\n }\n\n mongo.applyMiddlewares<T>(createdSchema, middlewares);\n\n const model = currentMongooseInstance.model<T>(name, createdSchema) as I_ExtendedModel<T>;\n\n if (virtuals.length > 0) {\n (model as I_ExtendedModel<T> & { _virtualConfigs: typeof virtuals })._virtualConfigs = virtuals;\n }\n\n return model;\n },\n /**\n * Validation utilities for Mongoose schemas.\n * This object provides common validation functions that can be used in Mongoose schema definitions.\n */\n validator: {\n /**\n * Creates a required field validator.\n * This function returns a validator that checks if a field value is not empty\n * using the validate.isEmpty utility.\n *\n * @returns A validation function that returns true if the field is not empty.\n */\n isRequired<T>(): (this: T, value: unknown) => Promise<boolean> {\n return async function (this: T, value: unknown): Promise<boolean> {\n return !validate.isEmpty(value);\n };\n },\n /**\n * Creates a unique field validator.\n * This function returns a validator that checks if a field value is unique\n * across the specified fields in the collection.\n *\n * @param fields - An array of field names to check for uniqueness.\n * @returns A validation function that returns true if the value is unique across the specified fields.\n * @throws {Error} When fields is not a non-empty array of strings.\n */\n isUnique<T extends { constructor: { exists: (query: { [key: string]: unknown }) => Promise<unknown> } }>(fields: string[]) {\n return async function (this: T, value: unknown): Promise<boolean> {\n if (!Array.isArray(fields) || fields.length === 0) {\n throw new Error('Fields must be a non-empty array of strings.');\n }\n\n const query = { $or: fields.map(field => ({ [field]: { $eq: value } })) };\n const existingDocument = await this.constructor.exists(query);\n\n return !existingDocument;\n };\n },\n /**\n * Creates a regex pattern validator.\n * This function returns a validator that checks if a string value matches\n * all provided regular expressions.\n *\n * @param regexArray - An array of regular expressions to test against the value.\n * @returns A validation function that returns true if the value matches all regex patterns.\n * @throws {Error} When regexArray is not an array of valid RegExp objects.\n */\n matchesRegex(regexArray: RegExp[]): (value: string) => Promise<boolean> {\n return async (value: string): Promise<boolean> => {\n if (!Array.isArray(regexArray) || regexArray.some(r => !(r instanceof RegExp))) {\n throw new Error('regexArray must be an array of valid RegExp objects.');\n }\n\n return regexArray.every(regex => regex.test(value));\n };\n },\n },\n /**\n * Migration utilities for MongoDB.\n * This object extends the migrate-mongo library with additional configuration utilities.\n */\n migrate: {\n /**\n * Lazily loads the migrate-mongo module to avoid eager import overhead.\n * Use this to access migrate-mongo methods (up, down, status, create) programmatically.\n *\n * @returns A promise resolving to the migrate-mongo module.\n */\n async getModule(): Promise<typeof migrate> {\n return (await import('migrate-mongo')).default;\n },\n /**\n * Sets the migration configuration and updates .gitignore.\n * This function creates a migration configuration file and ensures it's properly\n * excluded from version control.\n *\n * @param options - Migration configuration options to write to the config file.\n */\n setConfig: (options: Partial<migrate.config.Config> & { moduleSystem?: 'commonjs' | 'esm' }) => {\n const optionsJS = `// This file is automatically generated by the Cyberskill CLI.\\nmodule.exports = ${JSON.stringify(options, null, 4)}`;\n\n writeFileSync(PATH.MIGRATE_MONGO_CONFIG, optionsJS);\n\n addGitIgnoreEntry(PATH.GIT_IGNORE, MIGRATE_MONGO_CONFIG);\n },\n },\n /**\n * Converts string values in a filter to regex patterns for case-insensitive search.\n * This function recursively processes a filter object and converts string values in specified fields\n * to MongoDB regex patterns that support accented character matching.\n *\n * @remarks\n * **Performance guard:** Input strings are capped at 200 characters to mitigate ReDoS risk.\n * The generated regex patterns include accented character alternation groups (e.g., `(a|à|á|...)`)\n * which can be polynomially complex for very long inputs. For production search on large collections,\n * consider using MongoDB `$text` search indexes instead of `$regex` for better performance.\n *\n * @param filter - The filter object to process.\n * @param fields - An array of field names to convert to regex patterns.\n * @returns A new filter object with string values converted to regex patterns.\n */\n regexify<T>(filter?: T_QueryFilter<T>, fields?: (keyof T | string)[]): T_QueryFilter<T> {\n if (!filter) {\n return {} as T_QueryFilter<T>;\n }\n\n let newFilter = { ...filter };\n\n if (!fields || fields.length === 0) {\n return newFilter;\n }\n\n const MAX_REGEX_INPUT_LENGTH = 200;\n\n for (const field of fields) {\n const path = field.toString().split('.');\n const value = getNestedValue(newFilter, path);\n\n if (typeof value === 'string' && value.length > 0 && value.length <= MAX_REGEX_INPUT_LENGTH) {\n const regexValue = {\n $regex: `.*${regexSearchMapper(value)}.*`,\n $options: 'i',\n };\n\n newFilter = setNestedValue(newFilter, path, regexValue);\n }\n }\n\n return newFilter;\n },\n /**\n * Checks if a virtual options object has a dynamic ref function.\n *\n * @param options - The virtual options to check.\n * @returns True if the options contain a dynamic ref function.\n */\n isDynamicVirtual<T, R extends string = string>(options?: T_VirtualOptions<T, R>): options is I_DynamicVirtualOptions<T, R> {\n return Boolean(options && typeof options.ref === 'function');\n },\n\n /**\n * Generic utility function to get new records from the database\n * @param controller - MongoController instance\n * @param recordsToCheck - Array of records to check\n * @param filterFn - Function to determine if a record already exists\n * @param filter - Optional filter to narrow the query\n * @returns Array of records that don't exist in the database\n * @since 3.13.0\n */\n async getNewRecords<T extends I_GenericDocument>(\n controller: MongoController<T>,\n recordsToCheck: T[],\n filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean,\n filter: T_Filter<T> = {} as T_Filter<T>,\n ): Promise<T[]> {\n const batchSize = 1000;\n let skip = 0;\n let isComplete = false;\n\n const allExistingRecords: T_WithId<T>[] = [];\n\n while (!isComplete) {\n const pageResult = await controller.findAll(filter, { skip, limit: batchSize });\n\n if (!pageResult.success) {\n throw new Error(`Failed to query existing records on skip ${skip}: ${pageResult.message}`);\n }\n\n allExistingRecords.push(...pageResult.result);\n\n if (pageResult.truncated && pageResult.result.length === batchSize) {\n skip += batchSize;\n }\n else {\n isComplete = true;\n }\n }\n\n const filteredRecords = recordsToCheck.filter(newRecord =>\n !allExistingRecords.some((existingRecord: T_WithId<T>) =>\n filterFn(existingRecord, newRecord),\n ),\n );\n\n return filteredRecords;\n },\n\n /**\n * Generic utility function to get existing records that match the filter criteria\n * @param controller - MongoController instance\n * @param recordsToCheck - Array of records to check\n * @param filterFn - Function to determine if a record exists\n * @param filter - Optional filter to narrow the query\n * @returns Array of existing records that match the filter criteria\n * @throws {Error} When the database query fails — prevents silent data inconsistency.\n * @since 3.13.0\n */\n async getExistingRecords<T extends I_GenericDocument>(\n controller: MongoController<T>,\n recordsToCheck: T[],\n filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean,\n filter: T_Filter<T> = {} as T_Filter<T>,\n ): Promise<T_WithId<T>[]> {\n const batchSize = 1000;\n let skip = 0;\n let isComplete = false;\n\n const allExistingRecords: T_WithId<T>[] = [];\n\n while (!isComplete) {\n const pageResult = await controller.findAll(filter, { skip, limit: batchSize });\n\n if (!pageResult.success) {\n throw new Error(`Failed to query existing records on skip ${skip}: ${pageResult.message}`);\n }\n\n allExistingRecords.push(...pageResult.result);\n\n if (pageResult.truncated && pageResult.result.length === batchSize) {\n skip += batchSize;\n }\n else {\n isComplete = true;\n }\n }\n\n const foundRecords = allExistingRecords.filter((existingRecord: T_WithId<T>) =>\n recordsToCheck.some((newRecord: T) =>\n filterFn(existingRecord, newRecord),\n ),\n );\n\n return foundRecords;\n },\n\n /**\n * Retrieves health and connection pool statistics for the Mongoose connection.\n * This utility helps monitor database connection health and observability.\n *\n * @param mongooseInstance - The Mongoose instance to check.\n * @returns An object containing connection health statistics.\n */\n health(mongooseInstance: typeof mongooseRaw): Record<string, unknown> {\n const conn = mongooseInstance.connection;\n\n return {\n readyState: conn.readyState,\n host: conn.host,\n name: conn.name,\n models: Object.keys(mongooseInstance.models).length,\n };\n },\n};\n\nexport { applyNestedPopulate } from './mongo.populate.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mongo.util.js","names":[],"sources":["../../../src/node/mongo/mongo.util.ts"],"sourcesContent":["import type migrate from 'migrate-mongo';\nimport type mongooseRaw from 'mongoose';\n\nimport aggregatePaginate from 'mongoose-aggregate-paginate-v2';\nimport mongoosePaginate from 'mongoose-paginate-v2';\nimport { randomUUID } from 'node:crypto';\n\nimport { getNestedValue, regexSearchMapper, setNestedValue } from '#util/index.js';\nimport { validate } from '#util/validate/index.js';\n\nimport type { MongoController } from './mongo.controller.js';\nimport type { C_Document, I_CreateModelOptions, I_CreateSchemaOptions, I_DynamicVirtualConfig, I_DynamicVirtualOptions, I_ExtendedModel, I_GenericDocument, I_MongooseModelMiddleware, T_Filter, T_MongoosePlugin, T_MongooseSchema, T_QueryFilter, T_VirtualOptions, T_WithId } from './mongo.type.js';\n\nimport { addGitIgnoreEntry, writeFileSync } from '../fs/index.js';\nimport { MIGRATE_MONGO_CONFIG, PATH } from '../path/index.js';\n/**\n * Converts enum values to proper model names.\n * Handles common naming conventions like converting 'USER' to 'User'.\n *\n * @param enumValue - The enum value to convert\n * @returns The converted model name\n */\nexport function convertEnumToModelName(enumValue: string): string {\n if (enumValue === enumValue.toUpperCase()) {\n return enumValue.charAt(0).toUpperCase() + enumValue.slice(1).toLowerCase();\n }\n\n return enumValue;\n}\n\n/**\n * Interface for the MongoDB utility object to enable explicit type annotation.\n * Required to avoid TS7056 (inferred type exceeds maximum serialization length).\n */\ninterface I_MongoUtils {\n createGenericFields: () => I_GenericDocument;\n applyPlugins: <T>(schema: T_MongooseSchema<T>, plugins: Array<T_MongoosePlugin | false>) => void;\n applyMiddlewares: <T extends Partial<C_Document>>(schema: T_MongooseSchema<T>, middlewares: I_MongooseModelMiddleware<T>[]) => void;\n createGenericSchema: (mongoose: typeof mongooseRaw) => T_MongooseSchema<I_GenericDocument>;\n createSchema: <T, R extends string = string>(options: I_CreateSchemaOptions<T, R>) => T_MongooseSchema<T>;\n createModel: <T extends Partial<C_Document>, R extends string = string>(options: I_CreateModelOptions<T, R>) => I_ExtendedModel<T>;\n validator: {\n isRequired: <T>() => (this: T, value: unknown) => Promise<boolean>;\n isUnique: <T extends { constructor: { exists: (query: { [key: string]: unknown }) => Promise<unknown> } }>(fields: string[]) => (this: T, value: unknown) => Promise<boolean>;\n matchesRegex: (regexArray: RegExp[]) => (value: string) => Promise<boolean>;\n };\n migrate: {\n getModule: () => Promise<typeof migrate>;\n setConfig: (options: Partial<migrate.config.Config> & { moduleSystem?: 'commonjs' | 'esm' }) => void;\n };\n regexify: <T>(filter?: T_QueryFilter<T>, fields?: (keyof T | string)[]) => T_QueryFilter<T>;\n isDynamicVirtual: <T, R extends string>(options?: T_VirtualOptions<T, R>) => options is I_DynamicVirtualOptions<T, R>;\n getNewRecords: <T extends I_GenericDocument>(controller: MongoController<T>, recordsToCheck: T[], filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean, filter?: T_Filter<T>) => Promise<T[]>;\n getExistingRecords: <T extends I_GenericDocument>(controller: MongoController<T>, recordsToCheck: T[], filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean, filter?: T_Filter<T>) => Promise<T_WithId<T>[]>;\n health: (mongooseInstance: typeof mongooseRaw) => Record<string, unknown>;\n}\n\n/**\n * MongoDB utility object providing comprehensive database operations and utilities.\n * This object contains methods for creating generic fields, applying plugins and middlewares,\n * creating schemas and models, validation functions, migration utilities, and regex filtering.\n */\nexport const mongo: I_MongoUtils = {\n /**\n * Creates generic fields that are commonly used across MongoDB documents.\n * This function generates standard fields including a UUID, deletion flag, and timestamps\n * that can be applied to any document schema.\n *\n * @returns An object containing generic document fields (id, isDel, createdAt, updatedAt).\n */\n createGenericFields(): I_GenericDocument {\n return {\n id: randomUUID(),\n isDel: false,\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n },\n /**\n * Applies plugins to a Mongoose schema.\n * This function filters out falsy plugins and applies the remaining valid plugins\n * to the provided schema.\n *\n * @param schema - The Mongoose schema to apply plugins to.\n * @param plugins - An array of plugin functions or false values to filter and apply.\n */\n applyPlugins<T>(schema: T_MongooseSchema<T>, plugins: Array<T_MongoosePlugin | false>) {\n plugins\n .filter((plugin): plugin is T_MongoosePlugin => typeof plugin === 'function')\n .forEach(plugin => schema.plugin(plugin));\n },\n /**\n * Applies middleware functions to a Mongoose schema.\n * This function configures pre and post middleware for specified methods on the schema.\n *\n * @param schema - The Mongoose schema to apply middleware to.\n * @param middlewares - An array of middleware configurations with method, pre, and post functions.\n */\n applyMiddlewares<T extends Partial<C_Document>>(\n schema: T_MongooseSchema<T>,\n middlewares: I_MongooseModelMiddleware<T>[],\n ) {\n middlewares.forEach(({ method, pre, post }) => {\n if (method && pre) {\n schema.pre(method as RegExp, pre);\n }\n\n if (method && post) {\n schema.post(method as RegExp, post);\n }\n });\n },\n /**\n * Creates a generic Mongoose schema with common fields.\n * This function creates a base schema with UUID field and deletion flag,\n * configured with automatic timestamps.\n *\n * @param mongoose - The Mongoose instance to create the schema with.\n * @returns A Mongoose schema with generic document fields.\n */\n createGenericSchema(mongoose: typeof mongooseRaw) {\n return new mongoose.Schema<I_GenericDocument>(\n {\n id: { type: String, default: () => randomUUID(), unique: true },\n isDel: { type: Boolean, default: false },\n },\n { timestamps: true },\n );\n },\n /**\n * Creates a Mongoose schema with optional virtual fields and generic fields.\n * This function creates a new Mongoose schema from the provided schema definition,\n * optionally adds virtual fields, and includes generic fields (unless standalone is true).\n *\n * @param options - Configuration options including mongoose instance, schema definition, virtuals, and standalone flag.\n * @param options.mongoose - The Mongoose instance to use for schema creation.\n * @param options.schema - The schema definition object.\n * @param options.virtuals - Optional array of virtual field configurations.\n * @param options.standalone - Whether to exclude generic fields (default: false).\n * @returns A configured Mongoose schema.\n */\n createSchema<T, R extends string = string>({\n mongoose,\n schema,\n virtuals = [],\n standalone = false,\n }: I_CreateSchemaOptions<T, R>): T_MongooseSchema<T> {\n const createdSchema = new mongoose.Schema<T>(schema, {\n toJSON: { virtuals: true }, // So `res.json()` and other `JSON.stringify()` functions include virtuals\n toObject: { virtuals: true }, // So `console.log()` and other functions that use `toObject()` include virtuals\n });\n\n virtuals.forEach(({ name, options, get }) => {\n if (mongo.isDynamicVirtual<T, R>(options)) {\n const schemaStatics = createdSchema.statics as Record<string, unknown>;\n\n if (!schemaStatics['_dynamicVirtuals']) {\n schemaStatics['_dynamicVirtuals'] = [];\n }\n\n (schemaStatics['_dynamicVirtuals'] as I_DynamicVirtualConfig<T>[]).push({\n name: name as string,\n options,\n });\n\n const virtualInstance = createdSchema.virtual(name as string);\n\n if (get) {\n virtualInstance.get(get);\n }\n else {\n virtualInstance.get(function (this: T & { _populated?: { [key: string]: unknown } }) {\n return this._populated?.[name as string] || (options?.count ? 0 : (options?.justOne ? null : []));\n });\n }\n }\n else {\n const virtualInstance = createdSchema.virtual(name as string, options);\n\n if (get) {\n virtualInstance.get(get);\n }\n }\n });\n\n if (!standalone) {\n createdSchema.add(mongo.createGenericSchema(mongoose));\n }\n\n return createdSchema;\n },\n /**\n * Creates a Mongoose model with plugins, middleware, and pagination support.\n * This function creates a model from a schema with optional pagination and aggregation plugins,\n * and applies any specified middleware. If a model with the same name already exists, it returns the existing model.\n *\n * @param options - Configuration options including mongoose instance, model name, schema, and feature flags.\n * @param options.mongoose - The Mongoose instance to use for model creation.\n * @param options.name - The name of the model to create.\n * @param options.schema - The schema definition for the model.\n * @param options.pagination - Whether to enable pagination plugin (default: false).\n * @param options.aggregate - Whether to enable aggregation pagination plugin (default: false).\n * @param options.virtuals - Optional array of virtual field configurations.\n * @param options.middlewares - Optional array of middleware configurations.\n * @returns A configured Mongoose model with extended functionality.\n * @throws {Error} When the model name is not provided.\n */\n createModel<T extends Partial<C_Document>, R extends string = string>({\n mongoose: currentMongooseInstance,\n name,\n schema,\n virtuals = [],\n pagination = true,\n aggregate = true,\n middlewares = [],\n }: I_CreateModelOptions<T, R>): I_ExtendedModel<T> {\n if (!name) {\n throw new Error('Model name is required.');\n }\n\n if (currentMongooseInstance.models[name]) {\n return currentMongooseInstance.models[name] as I_ExtendedModel<T>;\n }\n\n const createdSchema = mongo.createSchema({ mongoose: currentMongooseInstance, schema, virtuals });\n\n if (pagination || aggregate) {\n mongo.applyPlugins<T>(createdSchema, [\n pagination && mongoosePaginate,\n aggregate && aggregatePaginate,\n ]);\n }\n\n mongo.applyMiddlewares<T>(createdSchema, middlewares);\n\n const model = currentMongooseInstance.model<T>(name, createdSchema) as I_ExtendedModel<T>;\n\n if (virtuals.length > 0) {\n (model as I_ExtendedModel<T> & { _virtualConfigs: typeof virtuals })._virtualConfigs = virtuals;\n }\n\n return model;\n },\n /**\n * Validation utilities for Mongoose schemas.\n * This object provides common validation functions that can be used in Mongoose schema definitions.\n */\n validator: {\n /**\n * Creates a required field validator.\n * This function returns a validator that checks if a field value is not empty\n * using the validate.isEmpty utility.\n *\n * @returns A validation function that returns true if the field is not empty.\n */\n isRequired<T>(): (this: T, value: unknown) => Promise<boolean> {\n return async function (this: T, value: unknown): Promise<boolean> {\n return !validate.isEmpty(value);\n };\n },\n /**\n * Creates a unique field validator.\n * This function returns a validator that checks if a field value is unique\n * across the specified fields in the collection.\n *\n * @param fields - An array of field names to check for uniqueness.\n * @returns A validation function that returns true if the value is unique across the specified fields.\n * @throws {Error} When fields is not a non-empty array of strings.\n */\n isUnique<T extends { constructor: { exists: (query: { [key: string]: unknown }) => Promise<unknown> } }>(fields: string[]) {\n return async function (this: T, value: unknown): Promise<boolean> {\n if (!Array.isArray(fields) || fields.length === 0) {\n throw new Error('Fields must be a non-empty array of strings.');\n }\n\n const query = { $or: fields.map(field => ({ [field]: { $eq: value } })) };\n const existingDocument = await this.constructor.exists(query);\n\n return !existingDocument;\n };\n },\n /**\n * Creates a regex pattern validator.\n * This function returns a validator that checks if a string value matches\n * all provided regular expressions.\n *\n * @param regexArray - An array of regular expressions to test against the value.\n * @returns A validation function that returns true if the value matches all regex patterns.\n * @throws {Error} When regexArray is not an array of valid RegExp objects.\n */\n matchesRegex(regexArray: RegExp[]): (value: string) => Promise<boolean> {\n return async (value: string): Promise<boolean> => {\n if (!Array.isArray(regexArray) || regexArray.some(r => !(r instanceof RegExp))) {\n throw new Error('regexArray must be an array of valid RegExp objects.');\n }\n\n return regexArray.every(regex => regex.test(value));\n };\n },\n },\n /**\n * Migration utilities for MongoDB.\n * This object extends the migrate-mongo library with additional configuration utilities.\n */\n migrate: {\n /**\n * Lazily loads the migrate-mongo module to avoid eager import overhead.\n * Use this to access migrate-mongo methods (up, down, status, create) programmatically.\n *\n * @returns A promise resolving to the migrate-mongo module.\n */\n async getModule(): Promise<typeof migrate> {\n return (await import('migrate-mongo')).default;\n },\n /**\n * Sets the migration configuration and updates .gitignore.\n * This function creates a migration configuration file and ensures it's properly\n * excluded from version control.\n *\n * @param options - Migration configuration options to write to the config file.\n */\n setConfig: (options: Partial<migrate.config.Config> & { moduleSystem?: 'commonjs' | 'esm' }) => {\n const optionsJS = `// This file is automatically generated by the Cyberskill CLI.\\nmodule.exports = ${JSON.stringify(options, null, 4)}`;\n\n writeFileSync(PATH.MIGRATE_MONGO_CONFIG, optionsJS);\n\n addGitIgnoreEntry(PATH.GIT_IGNORE, MIGRATE_MONGO_CONFIG);\n },\n },\n /**\n * Converts string values in a filter to regex patterns for case-insensitive search.\n * This function recursively processes a filter object and converts string values in specified fields\n * to MongoDB regex patterns that support accented character matching.\n *\n * @remarks\n * **Performance guard:** Input strings are capped at 200 characters to mitigate ReDoS risk.\n * The generated regex patterns include accented character alternation groups (e.g., `(a|à|á|...)`)\n * which can be polynomially complex for very long inputs. For production search on large collections,\n * consider using MongoDB `$text` search indexes instead of `$regex` for better performance.\n *\n * @param filter - The filter object to process.\n * @param fields - An array of field names to convert to regex patterns.\n * @returns A new filter object with string values converted to regex patterns.\n */\n regexify<T>(filter?: T_QueryFilter<T>, fields?: (keyof T | string)[]): T_QueryFilter<T> {\n if (!filter) {\n return {} as T_QueryFilter<T>;\n }\n\n let newFilter = { ...filter };\n\n if (!fields || fields.length === 0) {\n return newFilter;\n }\n\n const MAX_REGEX_INPUT_LENGTH = 200;\n\n for (const field of fields) {\n const path = field.toString().split('.');\n const value = getNestedValue(newFilter, path);\n\n if (typeof value === 'string' && value.length > 0 && value.length <= MAX_REGEX_INPUT_LENGTH) {\n const regexValue = {\n $regex: `.*${regexSearchMapper(value)}.*`,\n $options: 'i',\n };\n\n newFilter = setNestedValue(newFilter, path, regexValue);\n }\n }\n\n return newFilter;\n },\n /**\n * Checks if a virtual options object has a dynamic ref function.\n *\n * @param options - The virtual options to check.\n * @returns True if the options contain a dynamic ref function.\n */\n isDynamicVirtual<T, R extends string = string>(options?: T_VirtualOptions<T, R>): options is I_DynamicVirtualOptions<T, R> {\n return Boolean(options && typeof options.ref === 'function');\n },\n\n /**\n * Generic utility function to get new records from the database\n * @param controller - MongoController instance\n * @param recordsToCheck - Array of records to check\n * @param filterFn - Function to determine if a record already exists\n * @param filter - Optional filter to narrow the query\n * @returns Array of records that don't exist in the database\n * @since 3.13.0\n */\n async getNewRecords<T extends I_GenericDocument>(\n controller: MongoController<T>,\n recordsToCheck: T[],\n filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean,\n filter: T_Filter<T> = {} as T_Filter<T>,\n ): Promise<T[]> {\n const batchSize = 1000;\n let skip = 0;\n let isComplete = false;\n\n const allExistingRecords: T_WithId<T>[] = [];\n\n while (!isComplete) {\n const pageResult = await controller.findAll(filter, { skip, limit: batchSize });\n\n if (!pageResult.success) {\n throw new Error(`Failed to query existing records on skip ${skip}: ${pageResult.message}`);\n }\n\n allExistingRecords.push(...pageResult.result);\n\n if (pageResult.truncated && pageResult.result.length === batchSize) {\n skip += batchSize;\n }\n else {\n isComplete = true;\n }\n }\n\n const filteredRecords = recordsToCheck.filter(newRecord =>\n !allExistingRecords.some((existingRecord: T_WithId<T>) =>\n filterFn(existingRecord, newRecord),\n ),\n );\n\n return filteredRecords;\n },\n\n /**\n * Generic utility function to get existing records that match the filter criteria\n * @param controller - MongoController instance\n * @param recordsToCheck - Array of records to check\n * @param filterFn - Function to determine if a record exists\n * @param filter - Optional filter to narrow the query\n * @returns Array of existing records that match the filter criteria\n * @throws {Error} When the database query fails — prevents silent data inconsistency.\n * @since 3.13.0\n */\n async getExistingRecords<T extends I_GenericDocument>(\n controller: MongoController<T>,\n recordsToCheck: T[],\n filterFn: (existingRecord: T_WithId<T>, newRecord: T) => boolean,\n filter: T_Filter<T> = {} as T_Filter<T>,\n ): Promise<T_WithId<T>[]> {\n const batchSize = 1000;\n let skip = 0;\n let isComplete = false;\n\n const allExistingRecords: T_WithId<T>[] = [];\n\n while (!isComplete) {\n const pageResult = await controller.findAll(filter, { skip, limit: batchSize });\n\n if (!pageResult.success) {\n throw new Error(`Failed to query existing records on skip ${skip}: ${pageResult.message}`);\n }\n\n allExistingRecords.push(...pageResult.result);\n\n if (pageResult.truncated && pageResult.result.length === batchSize) {\n skip += batchSize;\n }\n else {\n isComplete = true;\n }\n }\n\n const foundRecords = allExistingRecords.filter((existingRecord: T_WithId<T>) =>\n recordsToCheck.some((newRecord: T) =>\n filterFn(existingRecord, newRecord),\n ),\n );\n\n return foundRecords;\n },\n\n /**\n * Retrieves health and connection pool statistics for the Mongoose connection.\n * This utility helps monitor database connection health and observability.\n *\n * @param mongooseInstance - The Mongoose instance to check.\n * @returns An object containing connection health statistics.\n */\n health(mongooseInstance: typeof mongooseRaw): Record<string, unknown> {\n const conn = mongooseInstance.connection;\n\n let pool: { totalConnections: number; availableConnections: number } | null = null;\n\n try {\n // Prefer the public getClient() API; fall back to the internal .client\n // property for older mongoose versions that do not expose getClient().\n const client = (conn as any).getClient?.() ?? (conn as any).client;\n\n if (client?.topology?.s?.servers && client.topology.s.servers instanceof Map) {\n let totalConnections = 0;\n let availableConnections = 0;\n\n client.topology.s.servers.forEach((server: any) => {\n const serverPool = server.s?.pool;\n if (serverPool) {\n totalConnections += serverPool.totalConnectionCount ?? 0;\n availableConnections += serverPool.availableConnectionCount ?? 0;\n }\n });\n\n pool = { totalConnections, availableConnections };\n }\n }\n catch {\n // Pool metrics rely on driver internals that may change across upgrades\n }\n\n return {\n readyState: conn.readyState,\n host: conn.host,\n name: conn.name,\n models: Object.keys(mongooseInstance.models).length,\n pool,\n poolMetricsAvailable: pool !== null,\n };\n },\n};\n\nexport { applyNestedPopulate } from './mongo.populate.js';\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.constant.js","names":[],"sources":["../../../src/node/path/path.constant.ts"],"sourcesContent":["import fsExtra from 'fs-extra';\n\nimport { getEnv } from '#config/env/index.js';\n\nimport type { I_PackageInput, I_PackageJson } from '../package/index.js';\n\nimport { E_CommandType, formatCommand, rawCommand } from '../command/index.js';\nimport { E_PackageType, setupPackages } from '../package/index.js';\nimport { join, resolveWorkingPath } from './path.util.js';\n\nexport const WORKING_DIRECTORY = getEnv().CWD;\nexport const CYBERSKILL_PACKAGE_NAME = '@cyberskill/shared';\nexport const NODE_MODULES = 'node_modules';\nexport const BUILD_DIRECTORY = 'dist';\nexport const PUBLIC_DIRECTORY = 'public';\nexport const PACKAGE_JSON = 'package.json';\nexport const PACKAGE_LOCK_JSON = 'package-lock.json';\nexport const TSCONFIG_JSON = 'tsconfig.json';\nexport const GIT_IGNORE = '.gitignore';\nexport const SIMPLE_GIT_HOOK_JSON = '.simple-git-hooks.json';\nexport const PNPM_LOCK_YAML = 'pnpm-lock.yaml';\nexport const GIT_HOOK = '.git/hooks/';\nexport const GIT_COMMIT_EDITMSG = '.git/COMMIT_EDITMSG';\nexport const GIT_EXCLUDE = '.git/info/exclude';\nexport const MIGRATE_MONGO_CONFIG = '.migrate-mongo.config.js';\nlet _cyberskillDir: string | null = null;\n\n/**\n * Resets the cached directory path. For testing only.\n */\nexport function resetCyberskillDirCacheForTesting(): void {\n _cyberskillDir = null;\n}\n\n/**\n * Lazily computes the CyberSkill directory path.\n * Reads package.json on first access to determine whether this is the shared package itself\n * or a consumer project, avoiding filesystem reads at module load time.\n */\nexport function getCyberskillDirectory(): string {\n if (_cyberskillDir !== null) {\n return _cyberskillDir;\n }\n\n try {\n const packageJson = fsExtra.readJsonSync(resolveWorkingPath(PACKAGE_JSON)) as I_PackageJson;\n\n _cyberskillDir = packageJson.name === CYBERSKILL_PACKAGE_NAME\n ? join(WORKING_DIRECTORY, BUILD_DIRECTORY)\n : join(WORKING_DIRECTORY, NODE_MODULES, CYBERSKILL_PACKAGE_NAME, BUILD_DIRECTORY);\n }\n catch {\n /* Intentionally empty — fallback to node_modules path when package.json is unreadable */\n _cyberskillDir = join(WORKING_DIRECTORY, NODE_MODULES, CYBERSKILL_PACKAGE_NAME, BUILD_DIRECTORY);\n }\n\n return _cyberskillDir;\n}\n\n/** @deprecated Use `getCyberskillDirectory()` instead. Kept for backward compatibility. */\nexport const CYBERSKILL_DIRECTORY = getCyberskillDirectory();\nexport const CYBERSKILL_CLI = 'cyberskill';\nexport const CYBERSKILL_CLI_PATH = 'src/node/cli/index.ts';\nexport const ESLINT_PACKAGE_NAME = 'eslint';\nexport const ESLINT_CLI = 'eslint';\nexport const VITEST_PACKAGE_NAME = 'vitest';\nexport const VITEST_CLI = 'vitest';\nexport const COMMIT_LINT_PACKAGE_NAME = '@commitlint/cli';\nexport const COMMIT_LINT_CONVENTIONAL_CONFIG_PACKAGE_NAME = '@commitlint/config-conventional';\nexport const COMMIT_LINT_CLI = 'commitlint';\nexport const LINT_STAGED_PACKAGE_NAME = 'lint-staged';\nexport const LINT_STAGED_CLI = 'lint-staged';\nexport const TSC_PACKAGE_NAME = 'typescript';\nexport const TSC_CLI = 'tsc';\nexport const TSX_CLI = 'tsx';\nexport const GIT_CLI = 'git';\nexport const PNPM_CLI = 'pnpm';\nexport const PNPM_EXEC_CLI = 'pnpm exec';\nexport const SIMPLE_GIT_HOOKS_PACKAGE_NAME = 'simple-git-hooks';\nexport const SIMPLE_GIT_HOOK_CLI = 'simple-git-hooks';\nexport const ESLINT_INSPECT_PACKAGE_NAME = '@eslint/config-inspector';\nexport const ESLINT_INSPECT_CLI = 'eslint-config-inspector';\nexport const NODE_MODULES_INSPECT_PACKAGE_NAME = 'node-modules-inspector';\nexport const NODE_MODULES_INSPECT_CLI = 'node-modules-inspector';\nexport const MIGRATE_MONGO_PACKAGE_NAME = 'migrate-mongo';\nexport const MIGRATE_MONGO_CLI = './node_modules/migrate-mongo/bin/migrate-mongo';\nexport const STORYBOOK_PACKAGE_NAME = 'storybook';\nexport const STORYBOOK_CLI = 'storybook';\nexport const AG_KIT_PACKAGE_NAME = '@vudovn/ag-kit';\nexport const DOT_AGENT = '.agent';\n\nexport const PATH = {\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get CYBERSKILL_DIRECTORY() { return getCyberskillDirectory(); },\n WORKING_DIRECTORY,\n PUBLIC_DIRECTORY: resolveWorkingPath(PUBLIC_DIRECTORY),\n TS_CONFIG: resolveWorkingPath(TSCONFIG_JSON),\n GIT_IGNORE: resolveWorkingPath(GIT_IGNORE),\n GIT_HOOK: resolveWorkingPath(GIT_HOOK),\n GIT_COMMIT_MSG: resolveWorkingPath(GIT_COMMIT_EDITMSG),\n GIT_EXCLUDE: resolveWorkingPath(GIT_EXCLUDE),\n SIMPLE_GIT_HOOKS_JSON: resolveWorkingPath(SIMPLE_GIT_HOOK_JSON),\n PACKAGE_JSON: resolveWorkingPath(PACKAGE_JSON),\n PACKAGE_LOCK_JSON: resolveWorkingPath(PACKAGE_LOCK_JSON),\n PNPM_LOCK_YAML: resolveWorkingPath(PNPM_LOCK_YAML),\n NODE_MODULES: resolveWorkingPath(NODE_MODULES),\n MIGRATE_MONGO_CONFIG: resolveWorkingPath(MIGRATE_MONGO_CONFIG),\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get LINT_STAGED_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/lint-staged/index.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get COMMITLINT_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/commitlint/index.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get VITEST_UNIT_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/vitest/vitest.unit.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get VITEST_E2E_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/vitest/vitest.e2e.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get STORYBOOK_MAIN_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/storybook/storybook.main.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get STORYBOOK_PREVIEW_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/storybook/storybook.preview.js`); },\n DOT_AGENT: resolveWorkingPath(DOT_AGENT),\n};\n\n/**\n * Creates Git hooks configuration based on whether this is the current project.\n * This function generates a configuration object for Git hooks that includes\n * pre-commit and commit-msg hooks, with an optional pre-push hook for the current project.\n *\n * @returns A Git hooks configuration object with appropriate commands for each hook.\n */\nexport function createGitHooksConfig() {\n return {\n 'pre-commit': LINT_STAGED_CLI,\n 'commit-msg': COMMIT_LINT_CLI,\n 'pre-push': rawCommand(`${GIT_CLI} pull && ${PNPM_CLI} run --if-present test`),\n };\n}\n\n/**\n * Builds a command function based on the specified type and configuration.\n * This function creates a command executor that handles different command types\n * including CLI commands and string commands. It manages package dependencies\n * and formats commands appropriately for execution.\n *\n * The function supports:\n * - CLI commands that require package installation\n * - String commands that are executed directly\n * - Automatic package dependency management\n * - Command formatting and validation\n *\n * @param config - Configuration object containing type, packages, and command properties.\n * @param config.type - The type of command to build (CLI or STRING).\n * @param config.packages - Optional array of packages required for CLI commands.\n * @param config.command - The command string to execute.\n * @returns A function that returns a promise resolving to the formatted command string.\n * @throws {Error} When an unsupported command type is provided.\n */\nfunction buildCommand({ type, packages, command }: { type: E_CommandType; packages?: I_PackageInput[]; command: string }): () => Promise<string> {\n const uniquePackages = packages?.reduce((acc: I_PackageInput[], pkg) => {\n if (!acc.some(existingPkg => existingPkg.name === pkg.name)) {\n acc.push(pkg);\n }\n return acc;\n }, []);\n\n return async () => {\n switch (type) {\n case E_CommandType.CLI: {\n if (uniquePackages?.length) {\n await setupPackages(uniquePackages, {\n install: true,\n });\n }\n\n return formatCommand(rawCommand(`${PNPM_EXEC_CLI} ${command}`)) as string;\n }\n case E_CommandType.STRING: {\n return formatCommand(rawCommand(command)) as string;\n }\n default: {\n throw new Error('Unsupported command type');\n }\n }\n };\n}\n\nconst RE_MIGRATE_NAME = /^[\\w-]+$/;\n\nexport const command = {\n simpleGitHooks: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: SIMPLE_GIT_HOOKS_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: SIMPLE_GIT_HOOK_CLI,\n }),\n eslintInspect: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name:\n ESLINT_INSPECT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: ESLINT_INSPECT_CLI,\n }),\n nodeModulesInspect: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: NODE_MODULES_INSPECT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: NODE_MODULES_INSPECT_CLI,\n }),\n eslintCheck: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: ESLINT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: `${ESLINT_CLI} ${PATH.WORKING_DIRECTORY} --no-cache`,\n }),\n eslintFix: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: ESLINT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: `${ESLINT_CLI} ${PATH.WORKING_DIRECTORY} --fix --no-cache`,\n }),\n typescriptCheck: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSC_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: `${TSC_CLI} -p ${PATH.TS_CONFIG} --noEmit --incremental`,\n }),\n testUnit: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: VITEST_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${VITEST_CLI} --config ${PATH.VITEST_UNIT_CONFIG}`,\n }),\n testE2e: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: VITEST_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${VITEST_CLI} --config ${PATH.VITEST_E2E_CONFIG}`,\n }),\n mongoMigrateCreate: (migrateName: string) => {\n if (!RE_MIGRATE_NAME.test(migrateName)) {\n throw new Error('Migration name must only contain alphanumeric characters, underscores, and hyphens.');\n }\n\n return buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSX_CLI,\n type: E_PackageType.DEPENDENCY,\n },\n {\n name: MIGRATE_MONGO_PACKAGE_NAME,\n type: E_PackageType.DEPENDENCY,\n },\n ],\n command: `${TSX_CLI} ${MIGRATE_MONGO_CLI} create ${migrateName} -f ${PATH.MIGRATE_MONGO_CONFIG}`,\n })();\n },\n mongoMigrateUp: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSX_CLI,\n type: E_PackageType.DEPENDENCY,\n },\n {\n name: MIGRATE_MONGO_PACKAGE_NAME,\n type: E_PackageType.DEPENDENCY,\n },\n ],\n command: `${TSX_CLI} ${MIGRATE_MONGO_CLI} up -f ${PATH.MIGRATE_MONGO_CONFIG}`,\n }),\n mongoMigrateDown: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSX_CLI,\n type: E_PackageType.DEPENDENCY,\n },\n {\n name: MIGRATE_MONGO_PACKAGE_NAME,\n type: E_PackageType.DEPENDENCY,\n },\n ],\n command: `${TSX_CLI} ${MIGRATE_MONGO_CLI} down -f ${PATH.MIGRATE_MONGO_CONFIG}`,\n }),\n commitLint: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: COMMIT_LINT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n {\n name: COMMIT_LINT_CONVENTIONAL_CONFIG_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${COMMIT_LINT_CLI} --edit ${PATH.GIT_COMMIT_MSG} --config ${PATH.COMMITLINT_CONFIG}`,\n }),\n lintStaged: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: LINT_STAGED_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${LINT_STAGED_CLI} --config ${PATH.LINT_STAGED_CONFIG}`,\n }),\n configureGitHook: buildCommand({\n type: E_CommandType.STRING,\n command: `${GIT_CLI} config core.hooksPath ${PATH.GIT_HOOK}`,\n }),\n build: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} run --if-present build`,\n }),\n pnpmInstallStandard: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} install --ignore-scripts`,\n }),\n pnpmInstallLegacy: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} install --ignore-scripts --legacy-peer-deps`,\n }),\n pnpmInstallForce: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} install --ignore-scripts --force`,\n }),\n pnpmPruneStore: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} store prune`,\n }),\n pnpmCleanCache: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} cache delete`,\n }),\n storybookDev: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: STORYBOOK_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${STORYBOOK_CLI} dev`,\n }),\n storybookBuild: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: STORYBOOK_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${STORYBOOK_CLI} build`,\n }),\n};\n"],"mappings":";;;;;;;;AAUA,IAAa,IAAoB,GAAQ,CAAC,KAC7B,IAA0B,sBAC1B,IAAe,gBACf,IAAkB,QAClB,IAAmB,UACnB,IAAe,gBACf,IAAoB,qBACpB,IAAgB,iBAChB,IAAa,cACb,IAAuB,0BACvB,IAAiB,kBACjB,IAAW,eACX,IAAqB,uBACrB,IAAc,qBACd,IAAuB,4BAChC,IAAgC;AAKpC,SAAgB,KAA0C;AACtD,KAAiB;;AAQrB,SAAgB,IAAiC;AAC7C,KAAI,MAAmB,KACnB,QAAO;AAGX,KAAI;AAGA,MAFoB,EAAQ,aAAa,EAAA,eAAgC,CAAC,CAE7C,SAAA,uBACvB,EAAK,GAAmB,EAAgB,GACxC,EAAK,GAAmB,GAAc,GAAyB,EAAgB;SAEnF;AAEF,MAAiB,EAAK,GAAmB,GAAc,GAAyB,EAAgB;;AAGpG,QAAO;;AAIX,IAAa,IAAuB,GAAwB,EAC/C,IAAiB,cACjB,KAAsB,yBACtB,IAAsB,UACtB,IAAa,UACb,IAAsB,UACtB,IAAa,UACb,IAA2B,mBAC3B,IAA+C,mCAC/C,IAAkB,cAClB,IAA2B,eAC3B,IAAkB,eAClB,IAAmB,cACnB,KAAU,OACV,IAAU,OACV,IAAU,OACV,IAAW,QACX,IAAgB,aAChB,IAAgC,oBAChC,IAAsB,oBACtB,IAA8B,4BAC9B,IAAqB,2BACrB,IAAoC,0BACpC,IAA2B,0BAC3B,IAA6B,iBAC7B,IAAoB,kDACpB,IAAyB,aACzB,IAAgB,aAChB,KAAsB,kBACtB,IAAY,UAEZ,IAAO;CAEhB,IAAI,uBAAuB;AAAE,SAAO,GAAwB;;CAC5D;CACA,kBAAkB,EAAmB,EAAiB;CACtD,WAAW,EAAmB,EAAc;CAC5C,YAAY,EAAmB,EAAW;CAC1C,UAAU,EAAmB,EAAS;CACtC,gBAAgB,EAAmB,EAAmB;CACtD,aAAa,EAAmB,EAAY;CAC5C,uBAAuB,EAAmB,EAAqB;CAC/D,cAAc,EAAmB,EAAa;CAC9C,mBAAmB,EAAmB,EAAkB;CACxD,gBAAgB,EAAmB,EAAe;CAClD,cAAc,EAAmB,EAAa;CAC9C,sBAAsB,EAAmB,EAAqB;CAE9D,IAAI,qBAAqB;AAAE,SAAO,EAAmB,GAAG,GAAwB,CAAC,8BAA8B;;CAE/G,IAAI,oBAAoB;AAAE,SAAO,EAAmB,GAAG,GAAwB,CAAC,6BAA6B;;CAE7G,IAAI,qBAAqB;AAAE,SAAO,EAAmB,GAAG,GAAwB,CAAC,+BAA+B;;CAEhH,IAAI,oBAAoB;AAAE,SAAO,EAAmB,GAAG,GAAwB,CAAC,8BAA8B;;CAE9G,IAAI,wBAAwB;AAAE,SAAO,EAAmB,GAAG,GAAwB,CAAC,qCAAqC;;CAEzH,IAAI,2BAA2B;AAAE,SAAO,EAAmB,GAAG,GAAwB,CAAC,wCAAwC;;CAC/H,WAAW,EAAmB,EAAU;CAC3C;AASD,SAAgB,KAAuB;AACnC,QAAO;EACH,cAAc;EACd,cAAc;EACd,YAAY,EAAW,eAAsB,EAAS,wBAAwB;EACjF;;AAsBL,SAAS,EAAa,EAAE,SAAM,aAAU,cAAyG;CAC7I,IAAM,IAAiB,GAAU,QAAQ,GAAuB,OACvD,EAAI,MAAK,MAAe,EAAY,SAAS,EAAI,KAAK,IACvD,EAAI,KAAK,EAAI,EAEV,IACR,EAAE,CAAC;AAEN,QAAO,YAAY;AACf,UAAQ,GAAR;GACI,KAAK,EAAc,IAOf,QANI,GAAgB,UAChB,MAAM,GAAc,GAAgB,EAChC,SAAS,IACZ,CAAC,EAGC,EAAc,EAAW,GAAG,EAAc,GAAG,IAAU,CAAC;GAEnE,KAAK,EAAc,OACf,QAAO,EAAc,EAAW,EAAQ,CAAC;GAE7C,QACI,OAAU,MAAM,2BAA2B;;;;AAM3D,IAAM,KAAkB,YAEX,KAAU;CACnB,gBAAgB,EAAa;EACzB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CAEJ;EACD,SAAS;EACZ,CAAC;CACF,eAAe,EAAa;EACxB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MACI;GACJ,MAAM,EAAc;GACvB,CAEJ;EACD,SAAS;EACZ,CAAC;CACF,oBAAoB,EAAa;EAC7B,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CAEJ;EACD,SAAS;EACZ,CAAC;CACF,aAAa,EAAa;EACtB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CAEJ;EACD,SAAS,GAAG,EAAW,GAAG,EAAK,kBAAkB;EACpD,CAAC;CACF,WAAW,EAAa;EACpB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CAEJ;EACD,SAAS,GAAG,EAAW,GAAG,EAAK,kBAAkB;EACpD,CAAC;CACF,iBAAiB,EAAa;EAC1B,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CAEJ;EACD,SAAS,UAAiB,EAAK,UAAU;EAC5C,CAAC;CACF,UAAU,EAAa;EACnB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,GAAG,EAAW,YAAY,EAAK;EAC3C,CAAC;CACF,SAAS,EAAa;EAClB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,GAAG,EAAW,YAAY,EAAK;EAC3C,CAAC;CACF,qBAAqB,MAAwB;AACzC,MAAI,CAAC,GAAgB,KAAK,EAAY,CAClC,OAAU,MAAM,sFAAsF;AAG1G,SAAO,EAAa;GAChB,MAAM,EAAc;GACpB,UAAU,CACN;IACI,MAAA;IACA,MAAM,EAAc;IACvB,EACD;IACI,MAAM;IACN,MAAM,EAAc;IACvB,CACJ;GACD,SAAS,OAAc,EAAkB,UAAU,EAAY,MAAM,EAAK;GAC7E,CAAC,EAAE;;CAER,gBAAgB,EAAa;EACzB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAA;GACA,MAAM,EAAc;GACvB,EACD;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,OAAc,EAAkB,SAAS,EAAK;EAC1D,CAAC;CACF,kBAAkB,EAAa;EAC3B,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAA;GACA,MAAM,EAAc;GACvB,EACD;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,OAAc,EAAkB,WAAW,EAAK;EAC5D,CAAC;CACF,YAAY,EAAa;EACrB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,EACD;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,GAAG,EAAgB,UAAU,EAAK,eAAe,YAAY,EAAK;EAC9E,CAAC;CACF,YAAY,EAAa;EACrB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,GAAG,EAAgB,YAAY,EAAK;EAChD,CAAC;CACF,kBAAkB,EAAa;EAC3B,MAAM,EAAc;EACpB,SAAS,6BAAoC,EAAK;EACrD,CAAC;CACF,OAAO,EAAa;EAChB,MAAM,EAAc;EACpB,SAAS,GAAG,EAAS;EACxB,CAAC;CACF,qBAAqB,EAAa;EAC9B,MAAM,EAAc;EACpB,SAAS,GAAG,EAAS;EACxB,CAAC;CACF,mBAAmB,EAAa;EAC5B,MAAM,EAAc;EACpB,SAAS,GAAG,EAAS;EACxB,CAAC;CACF,kBAAkB,EAAa;EAC3B,MAAM,EAAc;EACpB,SAAS,GAAG,EAAS;EACxB,CAAC;CACF,gBAAgB,EAAa;EACzB,MAAM,EAAc;EACpB,SAAS,GAAG,EAAS;EACxB,CAAC;CACF,gBAAgB,EAAa;EACzB,MAAM,EAAc;EACpB,SAAS,GAAG,EAAS;EACxB,CAAC;CACF,cAAc,EAAa;EACvB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,GAAG,EAAc;EAC7B,CAAC;CACF,gBAAgB,EAAa;EACzB,MAAM,EAAc;EACpB,UAAU,CACN;GACI,MAAM;GACN,MAAM,EAAc;GACvB,CACJ;EACD,SAAS,GAAG,EAAc;EAC7B,CAAC;CACL"}
|
|
1
|
+
{"version":3,"file":"path.constant.js","names":[],"sources":["../../../src/node/path/path.constant.ts"],"sourcesContent":["import fsExtra from 'fs-extra';\n\nimport { getEnv } from '#config/env/index.js';\n\nimport type { I_PackageInput, I_PackageJson } from '../package/index.js';\n\nimport { E_CommandType, formatCommand, rawCommand } from '../command/index.js';\nimport { E_PackageType, setupPackages } from '../package/index.js';\nimport { join, resolveWorkingPath } from './path.util.js';\n\nexport const WORKING_DIRECTORY = getEnv().CWD;\nexport const CYBERSKILL_PACKAGE_NAME = '@cyberskill/shared';\nexport const NODE_MODULES = 'node_modules';\nexport const BUILD_DIRECTORY = 'dist';\nexport const PUBLIC_DIRECTORY = 'public';\nexport const PACKAGE_JSON = 'package.json';\nexport const PACKAGE_LOCK_JSON = 'package-lock.json';\nexport const TSCONFIG_JSON = 'tsconfig.json';\nexport const GIT_IGNORE = '.gitignore';\nexport const SIMPLE_GIT_HOOK_JSON = '.simple-git-hooks.json';\nexport const PNPM_LOCK_YAML = 'pnpm-lock.yaml';\nexport const GIT_HOOK = '.git/hooks/';\nexport const GIT_COMMIT_EDITMSG = '.git/COMMIT_EDITMSG';\nexport const GIT_EXCLUDE = '.git/info/exclude';\nexport const MIGRATE_MONGO_CONFIG = '.migrate-mongo.config.js';\nlet _cyberskillDir: string | null = null;\n\n/**\n * Resets the cached directory path. For testing only.\n */\nexport function resetCyberskillDirCacheForTesting(): void {\n _cyberskillDir = null;\n}\n\n/**\n * Lazily computes the CyberSkill directory path.\n * Reads package.json on first access to determine whether this is the shared package itself\n * or a consumer project, avoiding filesystem reads at module load time.\n */\nexport function getCyberskillDirectory(): string {\n if (_cyberskillDir !== null) {\n return _cyberskillDir;\n }\n\n try {\n const packageJson = fsExtra.readJsonSync(resolveWorkingPath(PACKAGE_JSON)) as I_PackageJson;\n\n _cyberskillDir = packageJson.name === CYBERSKILL_PACKAGE_NAME\n ? join(WORKING_DIRECTORY, BUILD_DIRECTORY)\n : join(WORKING_DIRECTORY, NODE_MODULES, CYBERSKILL_PACKAGE_NAME, BUILD_DIRECTORY);\n }\n catch {\n /* Intentionally empty — fallback to node_modules path when package.json is unreadable */\n _cyberskillDir = join(WORKING_DIRECTORY, NODE_MODULES, CYBERSKILL_PACKAGE_NAME, BUILD_DIRECTORY);\n }\n\n return _cyberskillDir;\n}\n\n/** @deprecated Use `getCyberskillDirectory()` instead. Kept for backward compatibility. */\nexport const CYBERSKILL_DIRECTORY = getCyberskillDirectory();\nexport const CYBERSKILL_CLI = 'cyberskill';\nexport const CYBERSKILL_CLI_PATH = 'src/node/cli/index.ts';\nexport const ESLINT_PACKAGE_NAME = 'eslint';\nexport const ESLINT_CLI = 'eslint';\nexport const VITEST_PACKAGE_NAME = 'vitest';\nexport const VITEST_CLI = 'vitest';\nexport const COMMIT_LINT_PACKAGE_NAME = '@commitlint/cli';\nexport const COMMIT_LINT_CONVENTIONAL_CONFIG_PACKAGE_NAME = '@commitlint/config-conventional';\nexport const COMMIT_LINT_CLI = 'commitlint';\nexport const LINT_STAGED_PACKAGE_NAME = 'lint-staged';\nexport const LINT_STAGED_CLI = 'lint-staged';\nexport const TSC_PACKAGE_NAME = 'typescript';\nexport const TSC_CLI = 'tsc';\nexport const TSX_CLI = 'tsx';\nexport const GIT_CLI = 'git';\nexport const PNPM_CLI = 'pnpm';\nexport const PNPM_EXEC_CLI = 'pnpm exec';\nexport const SIMPLE_GIT_HOOKS_PACKAGE_NAME = 'simple-git-hooks';\nexport const SIMPLE_GIT_HOOK_CLI = 'simple-git-hooks';\nexport const ESLINT_INSPECT_PACKAGE_NAME = '@eslint/config-inspector';\nexport const ESLINT_INSPECT_CLI = 'eslint-config-inspector';\nexport const NODE_MODULES_INSPECT_PACKAGE_NAME = 'node-modules-inspector';\nexport const NODE_MODULES_INSPECT_CLI = 'node-modules-inspector';\nexport const MIGRATE_MONGO_PACKAGE_NAME = 'migrate-mongo';\nexport const MIGRATE_MONGO_CLI = './node_modules/migrate-mongo/bin/migrate-mongo';\nexport const STORYBOOK_PACKAGE_NAME = 'storybook';\nexport const STORYBOOK_CLI = 'storybook';\nexport const AG_KIT_PACKAGE_NAME = '@vudovn/ag-kit';\nexport const DOT_AGENT = '.agent';\n\nexport const PATH = {\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get CYBERSKILL_DIRECTORY() { return getCyberskillDirectory(); },\n WORKING_DIRECTORY,\n PUBLIC_DIRECTORY: resolveWorkingPath(PUBLIC_DIRECTORY),\n TS_CONFIG: resolveWorkingPath(TSCONFIG_JSON),\n GIT_IGNORE: resolveWorkingPath(GIT_IGNORE),\n GIT_HOOK: resolveWorkingPath(GIT_HOOK),\n GIT_COMMIT_MSG: resolveWorkingPath(GIT_COMMIT_EDITMSG),\n GIT_EXCLUDE: resolveWorkingPath(GIT_EXCLUDE),\n SIMPLE_GIT_HOOKS_JSON: resolveWorkingPath(SIMPLE_GIT_HOOK_JSON),\n PACKAGE_JSON: resolveWorkingPath(PACKAGE_JSON),\n PACKAGE_LOCK_JSON: resolveWorkingPath(PACKAGE_LOCK_JSON),\n PNPM_LOCK_YAML: resolveWorkingPath(PNPM_LOCK_YAML),\n NODE_MODULES: resolveWorkingPath(NODE_MODULES),\n MIGRATE_MONGO_CONFIG: resolveWorkingPath(MIGRATE_MONGO_CONFIG),\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get LINT_STAGED_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/lint-staged/index.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get COMMITLINT_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/commitlint/index.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get VITEST_UNIT_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/vitest/vitest.unit.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get VITEST_E2E_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/vitest/vitest.e2e.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get STORYBOOK_MAIN_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/storybook/storybook.main.js`); },\n /** Lazily resolved — defers `getCyberskillDirectory()` until first property access. */\n get STORYBOOK_PREVIEW_CONFIG() { return resolveWorkingPath(`${getCyberskillDirectory()}/config/storybook/storybook.preview.js`); },\n DOT_AGENT: resolveWorkingPath(DOT_AGENT),\n};\n\n/**\n * Creates Git hooks configuration based on whether this is the current project.\n * This function generates a configuration object for Git hooks that includes\n * pre-commit and commit-msg hooks, with an optional pre-push hook for the current project.\n *\n * @returns A Git hooks configuration object with appropriate commands for each hook.\n */\nexport function createGitHooksConfig() {\n return {\n 'pre-commit': LINT_STAGED_CLI,\n 'commit-msg': COMMIT_LINT_CLI,\n 'pre-push': rawCommand(`${GIT_CLI} pull && ${PNPM_CLI} run --if-present test`),\n };\n}\n\n/**\n * Builds a command function based on the specified type and configuration.\n * This function creates a command executor that handles different command types\n * including CLI commands and string commands. It manages package dependencies\n * and formats commands appropriately for execution.\n *\n * The function supports:\n * - CLI commands that require package installation\n * - String commands that are executed directly\n * - Automatic package dependency management\n * - Command formatting and validation\n *\n * @param config - Configuration object containing type, packages, and command properties.\n * @param config.type - The type of command to build (CLI or STRING).\n * @param config.packages - Optional array of packages required for CLI commands.\n * @param config.command - The command string to execute.\n * @returns A function that returns a promise resolving to the formatted command string.\n * @throws {Error} When an unsupported command type is provided.\n */\nfunction buildCommand({ type, packages, command }: { type: E_CommandType; packages?: I_PackageInput[]; command: string }): () => Promise<string> {\n const uniquePackages = packages?.reduce((acc: I_PackageInput[], pkg) => {\n if (!acc.some(existingPkg => existingPkg.name === pkg.name)) {\n acc.push(pkg);\n }\n return acc;\n }, []);\n\n return async () => {\n switch (type) {\n case E_CommandType.CLI: {\n if (uniquePackages?.length) {\n await setupPackages(uniquePackages, {\n install: true,\n });\n }\n\n return formatCommand(rawCommand(`${PNPM_EXEC_CLI} ${command}`)) as string;\n }\n case E_CommandType.STRING: {\n return formatCommand(rawCommand(command)) as string;\n }\n default: {\n throw new Error('Unsupported command type');\n }\n }\n };\n}\n\nconst RE_MIGRATE_NAME = /^[\\w-]+$/;\n\nexport const command = {\n simpleGitHooks: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: SIMPLE_GIT_HOOKS_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: SIMPLE_GIT_HOOK_CLI,\n }),\n eslintInspect: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name:\n ESLINT_INSPECT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: ESLINT_INSPECT_CLI,\n }),\n nodeModulesInspect: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: NODE_MODULES_INSPECT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: NODE_MODULES_INSPECT_CLI,\n }),\n eslintCheck: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: ESLINT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: `${ESLINT_CLI} ${PATH.WORKING_DIRECTORY} --no-cache`,\n }),\n eslintFix: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: ESLINT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: `${ESLINT_CLI} ${PATH.WORKING_DIRECTORY} --fix --no-cache`,\n }),\n typescriptCheck: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSC_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n\n ],\n command: `${TSC_CLI} -p ${PATH.TS_CONFIG} --noEmit --incremental`,\n }),\n testUnit: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: VITEST_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${VITEST_CLI} --config ${PATH.VITEST_UNIT_CONFIG}`,\n }),\n testE2e: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: VITEST_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${VITEST_CLI} --config ${PATH.VITEST_E2E_CONFIG}`,\n }),\n mongoMigrateCreate: (migrateName: string) => {\n if (!RE_MIGRATE_NAME.test(migrateName)) {\n throw new Error('Migration name must only contain alphanumeric characters, underscores, and hyphens.');\n }\n\n return buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSX_CLI,\n type: E_PackageType.DEPENDENCY,\n },\n {\n name: MIGRATE_MONGO_PACKAGE_NAME,\n type: E_PackageType.DEPENDENCY,\n },\n ],\n command: `${TSX_CLI} ${MIGRATE_MONGO_CLI} create ${migrateName} -f ${PATH.MIGRATE_MONGO_CONFIG}`,\n })();\n },\n mongoMigrateUp: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSX_CLI,\n type: E_PackageType.DEPENDENCY,\n },\n {\n name: MIGRATE_MONGO_PACKAGE_NAME,\n type: E_PackageType.DEPENDENCY,\n },\n ],\n command: `${TSX_CLI} ${MIGRATE_MONGO_CLI} up -f ${PATH.MIGRATE_MONGO_CONFIG}`,\n }),\n mongoMigrateDown: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: TSX_CLI,\n type: E_PackageType.DEPENDENCY,\n },\n {\n name: MIGRATE_MONGO_PACKAGE_NAME,\n type: E_PackageType.DEPENDENCY,\n },\n ],\n command: `${TSX_CLI} ${MIGRATE_MONGO_CLI} down -f ${PATH.MIGRATE_MONGO_CONFIG}`,\n }),\n commitLint: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: COMMIT_LINT_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n {\n name: COMMIT_LINT_CONVENTIONAL_CONFIG_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${COMMIT_LINT_CLI} --edit ${PATH.GIT_COMMIT_MSG} --config ${PATH.COMMITLINT_CONFIG}`,\n }),\n lintStaged: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: LINT_STAGED_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${LINT_STAGED_CLI} --config ${PATH.LINT_STAGED_CONFIG}`,\n }),\n configureGitHook: buildCommand({\n type: E_CommandType.STRING,\n command: `${GIT_CLI} config core.hooksPath ${PATH.GIT_HOOK}`,\n }),\n build: buildCommand({\n type: E_CommandType.STRING,\n command: `vite build`,\n }),\n pnpmInstallStandard: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} install --ignore-scripts`,\n }),\n pnpmInstallLegacy: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} install --ignore-scripts --legacy-peer-deps`,\n }),\n pnpmInstallForce: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} install --ignore-scripts --force`,\n }),\n pnpmPruneStore: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} store prune`,\n }),\n pnpmCleanCache: buildCommand({\n type: E_CommandType.STRING,\n command: `${PNPM_CLI} cache delete`,\n }),\n storybookDev: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: STORYBOOK_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${STORYBOOK_CLI} dev`,\n }),\n storybookBuild: buildCommand({\n type: E_CommandType.CLI,\n packages: [\n {\n name: STORYBOOK_PACKAGE_NAME,\n type: E_PackageType.DEV_DEPENDENCY,\n },\n ],\n command: `${STORYBOOK_CLI} build`,\n }),\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyberskill/shared",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.17.0",
|
|
5
5
|
"description": "CyberSkill Shared",
|
|
6
6
|
"author": "Stephen Cheng",
|
|
7
7
|
"license": "MIT",
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
},
|
|
231
231
|
"scripts": {
|
|
232
232
|
"ai:setup": "tsx src/node/cli/index.ts ai:setup",
|
|
233
|
-
"build": "
|
|
233
|
+
"build": "tsx src/node/cli/index.ts build",
|
|
234
234
|
"commitlint": "tsx src/node/cli/index.ts commitlint",
|
|
235
235
|
"dev": "vite build --watch",
|
|
236
236
|
"inspect": "tsx src/node/cli/index.ts inspect",
|
|
@@ -289,8 +289,8 @@
|
|
|
289
289
|
"mongoose": "9.3.3",
|
|
290
290
|
"mongoose-aggregate-paginate-v2": "1.1.4",
|
|
291
291
|
"mongoose-paginate-v2": "1.9.4",
|
|
292
|
-
"next-intl": "4.
|
|
293
|
-
"path-to-regexp": "8.4.
|
|
292
|
+
"next-intl": "4.9.0",
|
|
293
|
+
"path-to-regexp": "8.4.2",
|
|
294
294
|
"qs": "6.15.0",
|
|
295
295
|
"react": "19.2.4",
|
|
296
296
|
"react-dom": "19.2.4",
|
|
@@ -308,8 +308,8 @@
|
|
|
308
308
|
"@semantic-release/changelog": "6.0.3",
|
|
309
309
|
"@semantic-release/git": "10.0.1",
|
|
310
310
|
"@semantic-release/github": "12.0.6",
|
|
311
|
-
"@storybook/react": "10.3.
|
|
312
|
-
"@storybook/react-vite": "10.3.
|
|
311
|
+
"@storybook/react": "10.3.4",
|
|
312
|
+
"@storybook/react-vite": "10.3.4",
|
|
313
313
|
"@testing-library/dom": "10.4.1",
|
|
314
314
|
"@testing-library/jest-dom": "6.9.1",
|
|
315
315
|
"@testing-library/react": "16.3.2",
|
|
@@ -355,9 +355,10 @@
|
|
|
355
355
|
},
|
|
356
356
|
"pnpm": {
|
|
357
357
|
"overrides": {
|
|
358
|
-
"lodash": ">=4.
|
|
358
|
+
"lodash": ">=4.18.0",
|
|
359
|
+
"lodash-es": ">=4.18.0",
|
|
359
360
|
"minimatch": ">=10.2.4",
|
|
360
|
-
"path-to-regexp": "8.4.
|
|
361
|
+
"path-to-regexp": "8.4.2"
|
|
361
362
|
}
|
|
362
363
|
}
|
|
363
364
|
}
|