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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
4 changes: 4 additions & 0 deletions docs/cli/validate-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -47,6 +50,7 @@ Examples:

```sh
yini validate <fileOrDirectory...> [options]
yini check <fileOrDirectory...> [options]
```

---
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
"ci:test": "vitest run --reporter=verbose",
"ci:test:smoke": "vitest run tests/smoke --reporter=verbose",
"lint": "eslint src --ext .ts",
"format": "prettier --check .",
"format:fix": "prettier --write .",
"format": "prettier --check . \"!**/*.md\"",
"format:fix": "prettier --write . \"!**/*.md\"",
"build": "tsc",
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
"prepare": "npm run build",
Expand Down
52 changes: 26 additions & 26 deletions prettier.config.cjs
Original file line number Diff line number Diff line change
@@ -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',
bracketSameLine: 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
'<THIRD_PARTY_MODULES>', // 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
'<THIRD_PARTY_MODULES>', // Then other external dependencies
'^[@/](.*)$', // Then “@/…” or “@alias/…” imports
'^[./]', // Then relative imports
],
importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
importOrderTypeScriptVersion: '5.0.0',
importOrderCaseSensitive: false,
}
5 changes: 1 addition & 4 deletions samples/basic.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
"App": {
"name": "Demo App",
"version": 1.2,
"features": [
"search",
"logs"
],
"features": ["search", "logs"],
"debug": false,
"pageSize": 25,
"Server": {
Expand Down
11 changes: 2 additions & 9 deletions samples/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 2 additions & 8 deletions samples/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 20 additions & 6 deletions src/globalOptions/helpOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ appendGlobalOptionsTo(parseCmd)
*/
const validateCmd = program
.command('validate <fileOrDirectory...>')
.alias('check')
.description(descr['For-command-validate'])

// ─────────────────────────────
Expand Down
69 changes: 69 additions & 0 deletions tests/command-validate/command-check-alias.test.ts
Original file line number Diff line number Diff line change
@@ -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 <type>')
})
})
30 changes: 15 additions & 15 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -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"]
}
Loading