From c2f8ed3736eb8be7c7ab237d03d752ab65c268d5 Mon Sep 17 00:00:00 2001 From: "Marko K. S." Date: Wed, 8 Jul 2026 22:56:52 +0200 Subject: [PATCH 1/3] feat: Add 'check' command as an alias for 'validate' --- README.md | 5 ++ docs/CHANGELOG.md | 3 + docs/cli/validate-command.md | 4 ++ src/globalOptions/helpOption.ts | 26 +++++-- src/index.ts | 1 + .../command-check-alias.test.ts | 69 +++++++++++++++++++ 6 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 tests/command-validate/command-check-alias.test.ts diff --git a/README.md b/README.md index 8d8024d..8cf5575 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,11 @@ yini validate --strict config.yini ``` → Validate using strict mode. +```bash +yini check config.yini +``` +→ Alias for `yini validate config.yini`. + For help with a specific command: ```bash diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f44946d..87a93d1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,9 @@ # CHANGELOG +**Changelog** for `yini-cli`. + ## [Upcoming/Unreleased] - FUTURE +- **Added:** Added the command `check` as alias for the command `validate`. ## 1.5.1 - 2026 June - Bumped dependency `yini-parser` to `^1.6.1` with the following changes: diff --git a/docs/cli/validate-command.md b/docs/cli/validate-command.md index 116f365..9f123bc 100644 --- a/docs/cli/validate-command.md +++ b/docs/cli/validate-command.md @@ -9,6 +9,8 @@ Validate one or more YINI files. Multiple files and directories may be provided, separated by spaces. +The `check` command is an alias for `validate`. + --- ## Default behavior @@ -36,6 +38,7 @@ The validate command operates in two run modes: **file mode** and **directory mo Examples: - `yini validate config.yini` → file mode +- `yini check config.yini` → file mode - `yini validate a.yini b.yini` → file mode - `yini validate .` → directory mode - `yini validate configs/` → directory mode @@ -47,6 +50,7 @@ Examples: ```sh yini validate [options] +yini check [options] ``` --- diff --git a/src/globalOptions/helpOption.ts b/src/globalOptions/helpOption.ts index 2f65009..3c69c5c 100644 --- a/src/globalOptions/helpOption.ts +++ b/src/globalOptions/helpOption.ts @@ -28,12 +28,26 @@ export const getHelpTextAfter = () => { ======================================================== Quick Examples: - $ yini parse file.yini - $ yini parse file.yini --json - $ yini parse file.yini --js - $ yini parse file.yini -o output.json - $ yini validate config.yini --stats - $ yini validate . --strict + Parse config.yini and print formatted JSON: + $ yini parse config.yini + + Parse config.yini and explicitly output JSON: + $ yini parse config.yini --json + + Parse config.yini as a JavaScript object: + $ yini parse config.yini --js + + Parse config.yini and write the output to a file: + $ yini parse config.yini -o output.json + + Validate one YINI file and show stats: + $ yini validate config.yini --stats + + Check whether one YINI file is valid: + $ yini check config.yini + + Validate all YINI files in the current directory: + $ yini validate . For help with a specific command, use -h or --help. For example: $ yini validate --help diff --git a/src/index.ts b/src/index.ts index aecf53b..d3ff095 100644 --- a/src/index.ts +++ b/src/index.ts @@ -144,6 +144,7 @@ appendGlobalOptionsTo(parseCmd) */ const validateCmd = program .command('validate ') + .alias('check') .description(descr['For-command-validate']) // ───────────────────────────── diff --git a/tests/command-validate/command-check-alias.test.ts b/tests/command-validate/command-check-alias.test.ts new file mode 100644 index 0000000..fb24379 --- /dev/null +++ b/tests/command-validate/command-check-alias.test.ts @@ -0,0 +1,69 @@ +// tests/command-validate/command-check-alias.test.ts +import path from 'node:path' +import { describe, expect, it } from 'vitest' +import { yiniCLI } from '../test-helpers' + +const FIXTURES_DIR = path.resolve(__dirname, '../fixtures/validate/lenient') +const VALID_DIR = path.join(FIXTURES_DIR, 'valid') +const INVALID_DIR = path.join(FIXTURES_DIR, 'invalid') + +const validFixture = (fileName: string) => path.join(VALID_DIR, fileName) +const invalidFixture = (fileName: string) => path.join(INVALID_DIR, fileName) + +describe('Check command alias.', () => { + it('validates one valid file successfully.', async () => { + // Arrange. + const fullPath = validFixture('validate-valid-basic-1.yini') + + // Act. + const { stdout, stderr, exitCode } = await yiniCLI([ + 'check', + fullPath, + '--lenient', + '--format', + 'json', + ]) + + // Assert. + const parsed = JSON.parse(stdout) + + expect(exitCode).toBe(0) + expect(stderr).toBe('') + expect(parsed.file).toBe(fullPath) + expect(parsed.mode).toBe('lenient') + expect(parsed.status).toBe('passed') + expect(parsed.summary.errors).toBe(0) + }) + + it('fails for one invalid file.', async () => { + // Arrange. + const fullPath = invalidFixture('invalid-garbage-1.yini') + + // Act. + const { stdout, stderr, exitCode } = await yiniCLI([ + 'check', + fullPath, + '--lenient', + '--format', + 'text', + ]) + + // Assert. + expect(exitCode).toBe(1) + expect(stdout).toContain('Validation failed') + expect(stdout).toContain(`File: "${fullPath}"`) + expect(stderr).toContain(`"${fullPath}"`) + }) + + it('shows validate command help.', async () => { + // Act. + const { stdout, stderr, exitCode } = await yiniCLI(['check', '--help']) + + // Assert. + expect(exitCode).toBe(0) + expect(stderr).toBe('') + expect(stdout).toContain('Usage: yini validate|check') + expect(stdout).toContain('--warnings-as-errors') + expect(stdout).toContain('--format ') + }) +}) From 30e210bc795b9571552252c986ed0e5d698611a2 Mon Sep 17 00:00:00 2001 From: "Marko K. S." Date: Wed, 8 Jul 2026 23:07:34 +0200 Subject: [PATCH 2/3] Ran: `npm run format:fix` --- package.json | 2 +- prettier.config.cjs | 52 +++++++++++++++++++++---------------------- samples/basic.json | 5 +---- samples/config.json | 11 ++------- samples/settings.json | 10 ++------- tsconfig.json | 30 ++++++++++++------------- 6 files changed, 47 insertions(+), 63 deletions(-) diff --git a/package.json b/package.json index 1be8e3a..1ee0380 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "ci:test:smoke": "vitest run tests/smoke --reporter=verbose", "lint": "eslint src --ext .ts", "format": "prettier --check .", - "format:fix": "prettier --write .", + "format:fix": "prettier --write . \"!**/*.md\"", "build": "tsc", "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"", "prepare": "npm run build", diff --git a/prettier.config.cjs b/prettier.config.cjs index 2729327..0afdd53 100644 --- a/prettier.config.cjs +++ b/prettier.config.cjs @@ -1,33 +1,33 @@ // prettier.config.js /** @type {import("prettier").Config} */ module.exports = { - // ──────────────────────────────────────────────────────────────── - // Formatting Options - // ─ - useTabs: false, + // ──────────────────────────────────────────────────────────────── + // Formatting Options + // ─ + useTabs: false, - // Maximum line length before Prettier wraps. - // "printWidth": 120, - printWidth: 80, + // Maximum line length before Prettier wraps. + // "printWidth": 120, + printWidth: 80, - // Number of spaces per indentation level. - tabWidth: 4, - singleQuote: true, - trailingComma: "all", - jsxBracketSameLine: true, - semi: false, -// Whether to add a space between brackets in object literals - bracketSpacing: true, - // Since prettier 3.0, manually specifying plugins is required - plugins: ['@ianvs/prettier-plugin-sort-imports'], - // This plugin's options + // Number of spaces per indentation level. + tabWidth: 4, + singleQuote: true, + trailingComma: 'all', + jsxBracketSameLine: true, + semi: false, + // Whether to add a space between brackets in object literals + bracketSpacing: true, + // Since prettier 3.0, manually specifying plugins is required + plugins: ['@ianvs/prettier-plugin-sort-imports'], + // This plugin's options importOrder: [ - '^react$', // Put React first - '', // Then other external dependencies - '^[@/](.*)$', // Then “@/…” or “@alias/…” imports - '^[./]', // Then relative imports - ], - importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'], - importOrderTypeScriptVersion: '5.0.0', - importOrderCaseSensitive: false, + '^react$', // Put React first + '', // Then other external dependencies + '^[@/](.*)$', // Then “@/…” or “@alias/…” imports + '^[./]', // Then relative imports + ], + importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'], + importOrderTypeScriptVersion: '5.0.0', + importOrderCaseSensitive: false, } diff --git a/samples/basic.json b/samples/basic.json index a381a9c..1748454 100644 --- a/samples/basic.json +++ b/samples/basic.json @@ -2,10 +2,7 @@ "App": { "name": "Demo App", "version": 1.2, - "features": [ - "search", - "logs" - ], + "features": ["search", "logs"], "debug": false, "pageSize": 25, "Server": { diff --git a/samples/config.json b/samples/config.json index 3badad0..6b83965 100644 --- a/samples/config.json +++ b/samples/config.json @@ -8,21 +8,14 @@ }, "UserPrefs": { "homePath": "./", - "lastFiles": [ - "MyDoc.txt", - "Notes.md", - "Todo.txt" - ] + "lastFiles": ["MyDoc.txt", "Notes.md", "Todo.txt"] }, "Features": { "enableSearch": true, "experimental": null, "dbEngine": "mysql", "ratio": 1.2, - "flags": [ - "new-ui", - "streaming-api" - ], + "flags": ["new-ui", "streaming-api"], "cache": { "maxMb": 256, "maxHours": 0.5 diff --git a/samples/settings.json b/samples/settings.json index de830ae..6440ff3 100644 --- a/samples/settings.json +++ b/samples/settings.json @@ -7,17 +7,11 @@ "Network": { "bindAddress": "127.0.0.1", "bindPort": 8080, - "allowedOrigins": [ - "https://myapp.com", - "http://localhost:3000" - ] + "allowedOrigins": ["https://myapp.com", "http://localhost:3000"] }, "Capabilities": { "enableSearch": true, - "experimental": [ - "new-ui", - "streaming-api" - ], + "experimental": ["new-ui", "streaming-api"], "pools": { "min_units": 2, "max_units": 5, diff --git a/tsconfig.json b/tsconfig.json index c50f224..9981857 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,17 @@ { - "compilerOptions": { - "target": "ES2020", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "types": ["node"], - "outDir": "./dist", - "rootDir": "./src", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "resolveJsonModule": true, - "declaration": true, - }, - "include": ["src"] + "compilerOptions": { + "target": "ES2020", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "types": ["node"], + "outDir": "./dist", + "rootDir": "./src", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "declaration": true + }, + "include": ["src"] } From c814197b49fafd84e39d21dc693b18bfbb8b4d43 Mon Sep 17 00:00:00 2001 From: "Marko K. S." Date: Wed, 8 Jul 2026 23:12:17 +0200 Subject: [PATCH 3/3] Fixed "format" to also ignore .md files --- package.json | 2 +- prettier.config.cjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1ee0380..17f7499 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "ci:test": "vitest run --reporter=verbose", "ci:test:smoke": "vitest run tests/smoke --reporter=verbose", "lint": "eslint src --ext .ts", - "format": "prettier --check .", + "format": "prettier --check . \"!**/*.md\"", "format:fix": "prettier --write . \"!**/*.md\"", "build": "tsc", "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"", diff --git a/prettier.config.cjs b/prettier.config.cjs index 0afdd53..68b4e5c 100644 --- a/prettier.config.cjs +++ b/prettier.config.cjs @@ -14,7 +14,7 @@ module.exports = { tabWidth: 4, singleQuote: true, trailingComma: 'all', - jsxBracketSameLine: true, + bracketSameLine: true, semi: false, // Whether to add a space between brackets in object literals bracketSpacing: true,