yini-cli 1.0.0-alpha.3 β†’ 1.0.2-beta

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,32 @@ 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 concise syntax designed for clarity, especially in nested sections.
15
+ * Supports commonly used configuration structures.
16
+ - *Developed to meet practical needs, driven by curiosity and a desire **for configuration clarity, simplicity, minimalism, and flexibility**.
17
17
 
18
18
  ---
19
19
 
20
20
  ## πŸ’‘ 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.
21
+ - **INI-inspired** β€” with added support for typing, comments, and nested sections.
22
+ - **Uses minimal syntax** β€” yet aims to keep maximum clarity.
23
+ - Section nesting **without requiring indentation or dot-delimited keys**.
24
24
  - **Supports strict and lenient modes**, and all major data types.
25
- - Both **human-friendly** and **machine-friendly**.
26
- - πŸ‘‰ See [how YINI compares to JSON, YAML, INI, and TOML](https://github.com/YINI-lang/yini-parser-typescript/tree/main/examples/compare-formats.md).
25
+ - Designed for compatibility with both **manual editing** and **automation**.
26
+ - πŸ‘‰ See [how YINI differs from JSON, YAML, INI, and TOML](https://github.com/YINI-lang/yini-parser-typescript/tree/main/examples/compare-formats.md).
27
27
  - Want the full syntax reference? See the [YINI Specification](https://github.com/YINI-lang/YINI-spec).
28
28
 
29
29
  ---
30
30
 
31
+ ## Intro to YINI Config Format
32
+ **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.
33
+
34
+ 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.
35
+
36
+ ---
37
+
31
38
  ## Usage
32
39
 
33
40
  ### Installation
@@ -40,18 +47,47 @@ Command-line tool for working with YINI configuration files. A human-friendly co
40
47
 
41
48
  2. **Verify installation**
42
49
  Run this in your terminal:
43
- ```
50
+ ```bash
44
51
  yini --version
45
52
  ```
46
53
  Should print the version (e.g., 1.0.0).
47
54
 
48
55
  Then you may try:
49
- ```
56
+ ```bash
50
57
  yini --help
51
58
  ```
52
59
  Should show you the CLI help for YINI.
53
60
 
54
- ### πŸ“€ Output Modes for `yini parse`
61
+ 3. **Test functionality**
62
+ Create a simple test file, for example: `config.yini`:
63
+ ```yini
64
+ ^ App
65
+ name = "My App Title"
66
+ version = "1.2.3"
67
+ pageSize = 25
68
+ darkTheme = off
69
+ ```
70
+
71
+ Then run:
72
+ ```bash
73
+ yini parse config.yini
74
+ ```
75
+
76
+ Expected result, your CLI should output a parsed version of the config and output something similar to:
77
+ ```js
78
+ {
79
+ App: {
80
+ name: 'My App Title',
81
+ version: '1.2.3',
82
+ pageSize: 25,
83
+ darkTheme: false
84
+ }
85
+ }
86
+ ```
87
+
88
+ ---
89
+
90
+ ## πŸ“€ Output Modes for `yini parse`
55
91
 
56
92
  The `parse` command supports multiple output styles:
57
93
 
@@ -59,7 +95,6 @@ The `parse` command supports multiple output styles:
59
95
  |----------------------------------------------------|----------------------|------------------------------------------------------------------------------|
60
96
  | `yini parse config.yini` | JS-style object | Uses Node’s `util.inspect` β€” human-readable, shows types, nesting, etc. |
61
97
  | `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
98
  | `yini parse config.yini --json` | Compact JSON | Compact and machine-friendly `JSON.stringify(obj)`. |
64
99
  | `yini parse config.yini --output out.txt` | File (JS-style) | Default style, written to specified file. |
65
100
  | `yini parse config.yini --pretty --output out.json`| File (Pretty JSON) | Formatted JSON written to file. |
@@ -69,13 +104,26 @@ The `parse` command supports multiple output styles:
69
104
  ---
70
105
 
71
106
  ## 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)
107
+ - ➑️ [Getting Started: Intro to YINI Config Format](https://github.com/YINI-lang/YINI-spec/blob/develop/Docs/Intro-to-YINI-Config-Format.md)
108
+ *Beginner-friendly walkthrough and basic usage examples.*
109
+
110
+ - ➑️ [YINI Parser on npm](https://www.npmjs.com/package/yini-parser)
111
+ *Install and view package details.*
112
+
113
+ - ➑️ [Read the YINI Specification](https://github.com/YINI-lang/YINI-spec/blob/release/YINI-Specification.md#table-of-contents)
114
+ *Full formal spec for the YINI format, including syntax and features.*
115
+
116
+ - ➑️ [YINI Parser on GitHub](https://github.com/YINI-lang/yini-parser-typescript)
117
+ *TypeScript source code, issue tracker, and contributing guide.*
118
+
119
+ - ➑️ [YINI vs Other Formats](https://github.com/YINI-lang/YINI-spec/tree/release#-summary-difference-with-other-formats)
120
+ *How does YINI differ: comparison with INI, YAML, and JSON.*
121
+
122
+ - ➑️ [Why YINI? (Project Rationale)](https://github.com/YINI-lang/YINI-spec/blob/release/RATIONALE.md)
123
+ *Learn about the motivations and design decisions behind YINI.*
124
+
125
+ - ➑️ [YINI Project](https://github.com/YINI-lang)
126
+ *YINI home.*
79
127
 
80
128
  ---
81
129
 
@@ -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.2-beta",
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,8 +67,8 @@
67
67
  },
68
68
  "author": "Marko K. SeppΓ€nen",
69
69
  "dependencies": {
70
- "commander": "^11.0.0",
71
- "yini-parser": "^1.0.1-beta"
70
+ "commander": "^14.0.0",
71
+ "yini-parser": "^1.0.2-beta"
72
72
  },
73
73
  "devDependencies": {
74
74
  "@eslint/js": "^9.31.0",
package/sample.yini CHANGED
@@ -1,19 +1,19 @@
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
- ^^ Cache
11
- Type = "redis" // Defines Cache, a sub-section of Server.
10
+ ^^ Cache // Defines Cache, a sub-section of Server.
11
+ Type = "redis"
12
12
  TTL = 3600
13
13
 
14
- ^^^ Options // Defines Options, a sub-section of Cache.
14
+ ^^^ Options // Defines Options, a sub-section of Cache.
15
15
  Host = "127.0.0.1"
16
16
  Port = 6379
17
17
 
18
- ^ Env // Defines a section named Env.
18
+ ^ Env // Defines a section named Env.
19
19
  code = "dev"