yini-cli 1.0.0-alpha.3 β†’ 1.0.1-beta.1

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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # YINI-CLI
2
- Command-line tool for working with YINI configuration files. A human-friendly config format β€” like INI, but with type-safe values, nested sections, comments, minimal syntax noise, and optional strict mode.
2
+ **Command-line tool for working with YINI configuration files. Validate, inspect, and convert to JSON with pretty output.**
3
+
4
+ *YINI aims to be a human-friendly config format: like INI, but with type-safe values, nested sections, comments, minimal syntax noise, and optional strict mode.*
3
5
 
4
6
  [![npm version](https://img.shields.io/npm/v/yini-parser.svg)](https://www.npmjs.com/package/yini-parser) [![All Tests](https://github.com/YINI-lang/yini-cli/actions/workflows/run-all-tests.yml/badge.svg)](https://github.com/YINI-lang/yini-cli/actions/workflows/run-all-tests.yml)
5
7
 
@@ -7,27 +9,33 @@ Command-line tool for working with YINI configuration files. A human-friendly co
7
9
 
8
10
  ## πŸ™‹β€β™€οΈ Why YINI?
9
11
  - **YINI is an alternative** to other great config formats like INI, JSON, YAML, XML, and TOML β€” designed for clarity, simplicity, and straightforward section nesting.
10
- - **Started as a personal project and a research challenge:** Aiming for something more readable than JSON, more structured than INI, and less surprising than YAML.
12
+ - **Started as a personal project and a research challenge:** Provides structure similar to INI, with features inspired by JSON and YAML.
11
13
  - **Built for clarity:**
12
- * Easy to read and write for humans, especially for nested sections.
13
- * Not too much syntax noise.
14
- * Just enough structure for real-world configs.
15
- - **A little bit of fun and joy:**
16
- * Created to scratch our own itch β€” if you like it too, that's a bonus!
14
+ * Uses minimal syntax for humans, especially for nested sections.
15
+ * Uses a concise syntax, aims to not have too much syntax noise.
16
+ * Supports commonly used configuration structures.
17
+ - *Originated from practical needs **for configuration clarity, simplicity, minimalism, and flexibility**.
17
18
 
18
19
  ---
19
20
 
20
21
  ## πŸ’‘ What is YINI?
21
- - **Simple like INI** β€” but with strong typing, comments, and nested sections.
22
- - **Easy to read and write** β€” minimal syntax noise, maximum clarity.
23
- - **Clear, minimal section nesting** β€” no painful indentation or long dot-delimited keys.
22
+ - **INI-inspired** β€” with added support for typing, comments, and nested sections.
23
+ - **Uses minimal syntax** β€” minimal syntax noise, maximum clarity.
24
+ - Section nesting **without requiring indentation or dot-delimited keys**.
24
25
  - **Supports strict and lenient modes**, and all major data types.
25
- - Both **human-friendly** and **machine-friendly**.
26
+ - Designed for compatibility with both **manual editing** and **automation**.
26
27
  - πŸ‘‰ See [how YINI compares to JSON, YAML, INI, and TOML](https://github.com/YINI-lang/yini-parser-typescript/tree/main/examples/compare-formats.md).
27
28
  - Want the full syntax reference? See the [YINI Specification](https://github.com/YINI-lang/YINI-spec).
28
29
 
29
30
  ---
30
31
 
32
+ ## Intro to YINI Config Format
33
+ **YINI** is a simple and readable configuration format. Sections are defined with `^ SectionName`, and values are assigned using `key = value`. The format supports common data types (same as those found in JSON), including strings, numbers, booleans, nulls, and lists.
34
+
35
+ To learn more, see the [Getting Started: Intro to YINI Config Format](https://github.com/YINI-lang/YINI-spec/blob/develop/Docs/Intro-to-YINI-Config-Format.md) tutorial.
36
+
37
+ ---
38
+
31
39
  ## Usage
32
40
 
33
41
  ### Installation
@@ -40,18 +48,47 @@ Command-line tool for working with YINI configuration files. A human-friendly co
40
48
 
41
49
  2. **Verify installation**
42
50
  Run this in your terminal:
43
- ```
51
+ ```bash
44
52
  yini --version
45
53
  ```
46
54
  Should print the version (e.g., 1.0.0).
47
55
 
48
56
  Then you may try:
49
- ```
57
+ ```bash
50
58
  yini --help
51
59
  ```
52
60
  Should show you the CLI help for YINI.
53
61
 
54
- ### πŸ“€ Output Modes for `yini parse`
62
+ 3. **Test functionality**
63
+ Create a simple test file, for example: `config.yini`:
64
+ ```yini
65
+ ^ App
66
+ name = "My App Title"
67
+ version = "1.2.3"
68
+ pageSize = 25
69
+ darkTheme = off
70
+ ```
71
+
72
+ Then run:
73
+ ```bash
74
+ yini parse config.yini
75
+ ```
76
+
77
+ Expected result, your CLI should output a parsed version of the config and output something similar to:
78
+ ```js
79
+ {
80
+ App: {
81
+ name: 'My App Title',
82
+ version: '1.2.3',
83
+ pageSize: 25,
84
+ darkTheme: false
85
+ }
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## πŸ“€ Output Modes for `yini parse`
55
92
 
56
93
  The `parse` command supports multiple output styles:
57
94
 
@@ -59,7 +96,6 @@ The `parse` command supports multiple output styles:
59
96
  |----------------------------------------------------|----------------------|------------------------------------------------------------------------------|
60
97
  | `yini parse config.yini` | JS-style object | Uses Node’s `util.inspect` β€” human-readable, shows types, nesting, etc. |
61
98
  | `yini parse config.yini --pretty` | Pretty JSON | Formatted and indented with `JSON.stringify(obj, null, 4)`. |
62
- | `yini parse config.yini --log` | Console log | Uses `console.log` β€” quick output but may truncate deep structures. |
63
99
  | `yini parse config.yini --json` | Compact JSON | Compact and machine-friendly `JSON.stringify(obj)`. |
64
100
  | `yini parse config.yini --output out.txt` | File (JS-style) | Default style, written to specified file. |
65
101
  | `yini parse config.yini --pretty --output out.json`| File (Pretty JSON) | Formatted JSON written to file. |
@@ -69,13 +105,26 @@ The `parse` command supports multiple output styles:
69
105
  ---
70
106
 
71
107
  ## Links
72
- - ➑️ [Why YINI? Why another format!?](https://github.com/YINI-lang/YINI-spec/blob/develop/RATIONALE.md) (rationale)
73
- - ➑️ [Intro to YINI Config Format](https://github.com/YINI-lang/yini-parser-typescript?tab=readme-ov-file#intro-to-yini-config-format) (learn YINI)
74
- - ➑️ [Read the YINI Specification](https://github.com/YINI-lang/YINI-spec/blob/develop/YINI-Specification.md#table-of-contents) (spec)
75
- - ➑️ [Official YINI Parser on npm](https://www.npmjs.com/package/yini-parser) (npm)
76
- - ➑️ [YINI Parser GitHub Repo](https://github.com/YINI-lang/yini-parser-typescript) (GitHub)
77
- - ➑️ [YINI vs Other Formats](https://github.com/YINI-lang/YINI-spec/blob/develop/Docs/Examples%20of%20YINI%20vs%20Other%20Formats.md)
78
- - ➑️ [YINI Project](https://github.com/YINI-lang) (home)
108
+ - ➑️ [Getting Started: Intro to YINI Config Format](https://github.com/YINI-lang/YINI-spec/blob/develop/Docs/Intro-to-YINI-Config-Format.md)
109
+ *Beginner-friendly walkthrough and basic usage examples.*
110
+
111
+ - ➑️ [YINI Parser on npm](https://www.npmjs.com/package/yini-parser)
112
+ *Install and view package details.*
113
+
114
+ - ➑️ [Read the YINI Specification](https://github.com/YINI-lang/YINI-spec/blob/release/YINI-Specification.md#table-of-contents)
115
+ *Full formal spec for the YINI format, including syntax and features.*
116
+
117
+ - ➑️ [YINI Parser on GitHub](https://github.com/YINI-lang/yini-parser-typescript)
118
+ *TypeScript source code, issue tracker, and contributing guide.*
119
+
120
+ - ➑️ [YINI vs Other Formats](https://github.com/YINI-lang/YINI-spec/tree/release#-summary-difference-with-other-formats)
121
+ *How does YINI differ: comparison with INI, YAML, and JSON.*
122
+
123
+ - ➑️ [Why YINI? (Project Rationale)](https://github.com/YINI-lang/YINI-spec/blob/release/RATIONALE.md)
124
+ *Learn about the motivations and design decisions behind YINI.*
125
+
126
+ - ➑️ [YINI Project](https://github.com/YINI-lang)
127
+ *YINI home.*
79
128
 
80
129
  ---
81
130
 
@@ -1,8 +1,6 @@
1
- // import pkg from '../../package.json'
2
1
  import { createRequire } from 'module';
3
2
  const require = createRequire(import.meta.url);
4
3
  const pkg = require('../../package.json');
5
- // import pkg from '../../package.json' assert { type: 'json' }
6
4
  export const printInfo = () => {
7
5
  console.log(`** YINI CLI **`);
8
6
  console.log(`yini-cli: ${pkg.version}`);
@@ -2,14 +2,14 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import util from 'util';
4
4
  import YINI from 'yini-parser';
5
- import { printObject, toPrettyJSON } from '../utils/print.js';
5
+ import { debugPrint, printObject, toPrettyJSON } from '../utils/print.js';
6
6
  export const parseFile = (file, options) => {
7
7
  const outputFile = options.output || '';
8
8
  const isStrictMode = !!options.strict;
9
9
  let outputStyle = 'JS-style';
10
- console.log('file = ' + file);
11
- console.log('output = ' + options.output);
12
- console.log('options:');
10
+ debugPrint('file = ' + file);
11
+ debugPrint('output = ' + options.output);
12
+ debugPrint('options:');
13
13
  printObject(options);
14
14
  if (options.pretty) {
15
15
  outputStyle = 'Pretty-JSON';
@@ -29,42 +29,43 @@ const doParseFile = (file, outputStyle, isStrictMode = false, outputFile = '') =
29
29
  // let strictMode = !!options.strict
30
30
  let bailSensitivity = 'auto';
31
31
  let includeMetaData = false;
32
- console.log('File = ' + file);
33
- console.log('outputStyle = ' + outputStyle);
34
- // try {
35
- // const raw = fs.readFileSync(file, 'utf-8')
36
- // const parsed = YINI.parseFile(
37
- //const parsed = YINI.parseFile(file)
38
- const parsed = YINI.parseFile(file, isStrictMode, bailSensitivity, includeMetaData);
39
- // const parsed = YINI.parse(raw)
40
- // const output = options.pretty
41
- // ? // ? JSON.stringify(parsed, null, 2)
42
- // toPrettyJSON(parsed)
43
- // : JSON.stringify(parsed)
44
- let output = '';
45
- switch (outputStyle) {
46
- case 'Pretty-JSON':
47
- output = toPrettyJSON(parsed);
48
- break;
49
- case 'Console.log':
50
- output = '<todo>';
51
- break;
52
- case 'JSON-compact':
53
- output = JSON.stringify(parsed);
54
- break;
55
- default:
56
- output = util.inspect(parsed, { depth: null, colors: false });
32
+ debugPrint('File = ' + file);
33
+ debugPrint('outputStyle = ' + outputStyle);
34
+ try {
35
+ // const raw = fs.readFileSync(file, 'utf-8')
36
+ // const parsed = YINI.parseFile(
37
+ //const parsed = YINI.parseFile(file)
38
+ const parsed = YINI.parseFile(file, isStrictMode, bailSensitivity, includeMetaData);
39
+ // const parsed = YINI.parse(raw)
40
+ // const output = options.pretty
41
+ // ? // ? JSON.stringify(parsed, null, 2)
42
+ // toPrettyJSON(parsed)
43
+ // : JSON.stringify(parsed)
44
+ let output = '';
45
+ switch (outputStyle) {
46
+ case 'Pretty-JSON':
47
+ output = toPrettyJSON(parsed);
48
+ break;
49
+ case 'Console.log':
50
+ output = '<todo>';
51
+ break;
52
+ case 'JSON-compact':
53
+ output = JSON.stringify(parsed);
54
+ break;
55
+ default:
56
+ output = util.inspect(parsed, { depth: null, colors: false });
57
+ }
58
+ if (outputFile) {
59
+ // Write JSON output to file instead of stdout.
60
+ fs.writeFileSync(path.resolve(outputFile), output, 'utf-8');
61
+ console.log(`Output written to file: "${outputFile}"`);
62
+ }
63
+ else {
64
+ console.log(output);
65
+ }
57
66
  }
58
- if (outputFile) {
59
- // Write JSON output to file instead of stdout.
60
- fs.writeFileSync(path.resolve(outputFile), output, 'utf-8');
61
- console.log(`Output written to ${outputFile}`);
67
+ catch (err) {
68
+ console.error(`Error: ${err.message}`);
69
+ process.exit(1);
62
70
  }
63
- else {
64
- console.log(output);
65
- }
66
- // } catch (err: any) {
67
- // console.error(`Error: ${err.message}`)
68
- // process.exit(1)
69
- // }
70
71
  };
@@ -8,7 +8,7 @@ export const validateFile = (file, options = {}) => {
8
8
  const isMeta = true;
9
9
  const parsed = YINI.parse(content, options.strict ?? false, 'auto', isMeta);
10
10
  if (!options.silent) {
11
- console.log(`βœ” File is valid${options.strict ? ' (strict mode)' : ''}.`);
11
+ console.log(`βœ” File is valid${options.strict ? ' (strict mode)' : ''}.`);
12
12
  if (options.details) {
13
13
  //@todo format parsed.meta to details as
14
14
  /*
@@ -1,6 +1,6 @@
1
1
  export declare const descriptions: {
2
2
  yini: string;
3
- 'For-command-info': string;
4
3
  'For-command-parse': string;
5
4
  'For-command-validate': string;
5
+ 'For-command-info': string;
6
6
  };
@@ -1,6 +1,6 @@
1
1
  export const descriptions = {
2
- yini: 'CLI for parsing and validating YINI config files',
3
- 'For-command-info': 'Show extended information (details, links, etc.)',
4
- 'For-command-parse': 'Parse a YINI file and print the result',
5
- 'For-command-validate': 'Checks if the file can be parsed as valid YINI',
2
+ yini: 'CLI for parsing and validating YINI config files.',
3
+ 'For-command-parse': 'Parse a YINI file (*.yini) and print the result.',
4
+ 'For-command-validate': 'Checks if the file can be parsed as valid YINI.',
5
+ 'For-command-info': 'Show extended information (details, links, etc.).',
6
6
  };
package/dist/index.js CHANGED
@@ -6,8 +6,8 @@ import { Command } from 'commander';
6
6
  import { printInfo } from './commands/info.js';
7
7
  import { parseFile } from './commands/parse.js';
8
8
  import { validateFile } from './commands/validate.js';
9
- import { isDebug } from './config/env.js';
10
- import { descriptions as descripts } from './descriptions.js';
9
+ import { isDebug, isDev } from './config/env.js';
10
+ import { descriptions as descr } from './descriptions.js';
11
11
  import { debugPrint, toPrettyJSON } from './utils/print.js';
12
12
  const require = createRequire(import.meta.url);
13
13
  const pkg = require('../package.json');
@@ -54,37 +54,48 @@ Current suggestion:
54
54
 
55
55
  */
56
56
  // Display help for command
57
- program.name('yini').description(descripts.yini).version(pkg.version);
57
+ program
58
+ .name('yini')
59
+ .description(descr.yini)
60
+ // Below will replace all auto-registered items (especially the descriptions starting with a capital and ending with a period).
61
+ .version(pkg.version, '-v, --version', 'Output the version number.')
62
+ .helpOption('-h, --help', 'Display help for command.')
63
+ .helpCommand('help [command]', 'Display help for command.');
58
64
  program.addHelpText('before', `YINI CLI (Yet another INI)
59
65
 
60
66
  For parsing and validating YINI configuration files.
61
- A human-friendly config format - like INI, but with type-safe values,
62
- nested sections, comments, minimal syntax noise, and optional strict mode.
67
+ A config format, inspired by INI, with type-safe values, nested
68
+ sections, comments, minimal syntax noise, and optional strict mode.
63
69
 
64
- Crafted for clarity, consistency, and the simple joy of it. :)`);
70
+ Designed for clarity and consistency. :)\n`);
65
71
  program.addHelpText('after', `
66
72
  Examples:
67
73
  $ yini parse config.yini
68
74
  $ yini validate config.yini --strict
69
75
  $ yini parse config.yini --pretty --output out.json
70
76
 
71
- More info: https://github.com/YINI-lang/yini-parser
72
- `);
77
+ Example of "config.yini":
78
+ ^ App
79
+ title = 'My App'
80
+ items = 10
81
+ debug = ON
82
+
83
+ ^ Server
84
+ host = 'localhost'
85
+ port = 8080
86
+ useTLS = OFF
87
+
88
+ // Sub-section of Server.
89
+ ^^ Login
90
+ username = 'user'
91
+ password = 'secret'
92
+
93
+ More info:
94
+ https://github.com/YINI-lang/yini-cli
95
+
96
+ Into to YINI Config:
97
+ https://github.com/YINI-lang/YINI-spec/blob/develop/Docs/Intro-to-YINI-Config-Format.md`);
73
98
  //program.command('help [command]').description('Display help for command')
74
- // Command info
75
- program
76
- .command('info')
77
- // .command('')
78
- .description(descripts['For-command-info'])
79
- // .option('info')
80
- .action((options) => {
81
- debugPrint('Run command "info"');
82
- if (isDebug()) {
83
- console.log('options:');
84
- console.log(toPrettyJSON(options));
85
- }
86
- printInfo();
87
- });
88
99
  /**
89
100
  *
90
101
  * Maybe later, to as default command: parse <parse>
@@ -106,14 +117,16 @@ program
106
117
  // Explicit "parse" command
107
118
  program
108
119
  .command('parse <file>')
109
- .description(descripts['For-command-parse'])
110
- .option('--strict', 'Parse YINI in strict-mode')
111
- .option('--pretty', 'Pretty-print output as JSON')
120
+ .description(descr['For-command-parse'])
121
+ .option('--strict', 'Parse YINI in strict-mode.')
122
+ .option('--pretty', 'Pretty-print output as JSON.')
112
123
  // .option('--log', 'Use console.log output format (compact, quick view)')
113
- .option('--json', 'Compact JSON output using JSON.stringify')
114
- .option('--output <file>', 'Write output to a specified file')
124
+ .option('--json', 'Compact JSON output using JSON.stringify.')
125
+ .option('--output <file>', 'Write output to a specified file.')
115
126
  .action((file, options) => {
116
127
  debugPrint('Run command "parse"');
128
+ debugPrint('isDebug(): ' + isDebug());
129
+ debugPrint('isDev() : ' + isDev());
117
130
  debugPrint(`<file> = ${file}`);
118
131
  if (isDebug()) {
119
132
  console.log('options:');
@@ -144,9 +157,9 @@ program
144
157
  */
145
158
  program
146
159
  .command('validate <file>')
147
- .description(descripts['For-command-validate'])
160
+ .description(descr['For-command-validate'])
148
161
  .option('--strict', 'Enable parsing in strict-mode')
149
- .option('--details', 'Print detailed meta-data info (e.g., key count, nesting, etc.)')
162
+ .option('--details', 'Print detailed meta-data info (e.g., key count, nesting, etc.).')
150
163
  .option('--silent', 'Suppress output')
151
164
  .action((file, options) => {
152
165
  //@todo add debugPrint
@@ -157,6 +170,20 @@ program
157
170
  program.help();
158
171
  }
159
172
  });
173
+ // Command info
174
+ program
175
+ .command('info')
176
+ // .command('')
177
+ .description(descr['For-command-info'])
178
+ // .option('info')
179
+ .action((options) => {
180
+ debugPrint('Run command "info"');
181
+ if (isDebug()) {
182
+ console.log('options:');
183
+ console.log(toPrettyJSON(options));
184
+ }
185
+ printInfo();
186
+ });
160
187
  // NOTE: Converting YINI files to other formats than json and js.
161
188
  // Other format should go into a new CLI-command called 'yini-convert'.
162
189
  program.parseAsync();
@@ -2,7 +2,8 @@ export declare const debugPrint: (str?: any) => void;
2
2
  export declare const devPrint: (str?: any) => void;
3
3
  export declare const toJSON: (obj: any) => string;
4
4
  export declare const toPrettyJSON: (obj: any) => string;
5
- /** Pretty-prints a JavaScript object as formatted JSON to the console.
5
+ /**
6
+ * Pretty-prints a JavaScript object as formatted JSON to the console.
6
7
  * Strict JSON, all keys are enclosed in ", etc.
7
8
  */
8
9
  export declare const printJSON: (obj: any) => void;
@@ -4,14 +4,11 @@
4
4
  */
5
5
  import util from 'util';
6
6
  import { isDebug, isDev, isProdEnv, isTestEnv } from '../config/env.js';
7
- // import { isDebug, isDev, isProdEnv, isTestEnv } from '../config/env'
8
7
  export const debugPrint = (str = '') => {
9
8
  isDebug() && console.debug('DEBUG: ' + str);
10
- console.debug('DEBUG: ' + str);
11
9
  };
12
10
  export const devPrint = (str = '') => {
13
11
  isDev() && !isTestEnv() && console.log('DEV: ' + str);
14
- console.log('DEV: ' + str);
15
12
  };
16
13
  export const toJSON = (obj) => {
17
14
  const str = JSON.stringify(obj);
@@ -21,7 +18,8 @@ export const toPrettyJSON = (obj) => {
21
18
  const str = JSON.stringify(obj, null, 4);
22
19
  return str;
23
20
  };
24
- /** Pretty-prints a JavaScript object as formatted JSON to the console.
21
+ /**
22
+ * Pretty-prints a JavaScript object as formatted JSON to the console.
25
23
  * Strict JSON, all keys are enclosed in ", etc.
26
24
  */
27
25
  export const printJSON = (obj) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yini-cli",
3
- "version": "1.0.0-alpha.3",
3
+ "version": "1.0.1-beta.1",
4
4
  "description": "CLI for parsing and validating YINI config files: type-safe values, nested sections, comments, minimal syntax noise, and optional strict mode.",
5
5
  "keywords": [
6
6
  "yini",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "author": "Marko K. SeppΓ€nen",
69
69
  "dependencies": {
70
- "commander": "^11.0.0",
70
+ "commander": "^14.0.0",
71
71
  "yini-parser": "^1.0.1-beta"
72
72
  },
73
73
  "devDependencies": {
package/sample.yini CHANGED
@@ -1,10 +1,10 @@
1
- @YINI
1
+ @yini
2
2
 
3
3
  /*
4
4
  Example of a YINI document.
5
5
  */
6
6
 
7
- ^ Service // Defines a section named Server.
7
+ ^ Service // Defines a section named Service.
8
8
  Enabled = true
9
9
 
10
10
  ^^ Cache