Skip to content

Commit

Permalink
feat: Add CLI tool (#523)
Browse files Browse the repository at this point in the history
Skip CI tests for Node.js < 20
  • Loading branch information
eemeli committed Feb 25, 2024
1 parent 959f1cf commit e6a5e28
Show file tree
Hide file tree
Showing 17 changed files with 503 additions and 27 deletions.
20 changes: 11 additions & 9 deletions README.md
Expand Up @@ -33,6 +33,8 @@ npm install yaml
The API provided by `yaml` has three layers, depending on how deep you need to go: [Parse & Stringify](https://eemeli.org/yaml/#parse-amp-stringify), [Documents](https://eemeli.org/yaml/#documents), and the underlying [Lexer/Parser/Composer](https://eemeli.org/yaml/#parsing-yaml).
The first has the simplest API and "just works", the second gets you all the bells and whistles supported by the library along with a decent [AST](https://eemeli.org/yaml/#content-nodes), and the third lets you get progressively closer to YAML source, if that's your thing.

A [command-line tool](https://eemeli.org/yaml/#command-line-tool) is also included.

```js
import { parse, stringify } from 'yaml'
// or
Expand All @@ -55,26 +57,26 @@ const YAML = require('yaml')
- [`#directives`](https://eemeli.org/yaml/#stream-directives)
- [`#errors`](https://eemeli.org/yaml/#errors)
- [`#warnings`](https://eemeli.org/yaml/#errors)
- [`isDocument(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isDocument(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`parseAllDocuments(str, options?): Document[]`](https://eemeli.org/yaml/#parsing-documents)
- [`parseDocument(str, options?): Document`](https://eemeli.org/yaml/#parsing-documents)

### Content Nodes

- [`isAlias(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isCollection(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isMap(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isNode(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isPair(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isScalar(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isSeq(foo): boolean`](https://eemeli.org/yaml/#identifying-nodes)
- [`isAlias(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`isCollection(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`isMap(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`isNode(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`isPair(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`isScalar(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`isSeq(foo): boolean`](https://eemeli.org/yaml/#identifying-node-types)
- [`new Scalar(value)`](https://eemeli.org/yaml/#scalar-values)
- [`new YAMLMap()`](https://eemeli.org/yaml/#collections)
- [`new YAMLSeq()`](https://eemeli.org/yaml/#collections)
- [`doc.createAlias(node, name?): Alias`](https://eemeli.org/yaml/#working-with-anchors)
- [`doc.createNode(value, options?): Node`](https://eemeli.org/yaml/#creating-nodes)
- [`doc.createPair(key, value): Pair`](https://eemeli.org/yaml/#creating-nodes)
- [`visit(node, visitor)`](https://eemeli.org/yaml/#modifying-nodes)
- [`visit(node, visitor)`](https://eemeli.org/yaml/#finding-and-modifying-nodes)

### Parsing YAML

Expand Down
11 changes: 11 additions & 0 deletions bin.mjs
@@ -0,0 +1,11 @@
#!/usr/bin/env node

import { UserError, cli, help } from './dist/cli.mjs'

cli(process.stdin, error => {
if (error instanceof UserError) {
if (error.code === UserError.ARGS) console.error(`${help}\n`)
console.error(error.message)
process.exitCode = error.code
} else if (error) throw error
})
8 changes: 7 additions & 1 deletion config/jest.config.js
@@ -1,6 +1,6 @@
let moduleNameMapper
const transform = {
'[/\\\\]tests[/\\\\].*\\.(js|ts)$': [
'[/\\\\]tests[/\\\\].*\\.(m?js|ts)$': [
'babel-jest',
{ configFile: './config/babel.config.js' }
]
Expand All @@ -12,16 +12,22 @@ switch (process.env.npm_lifecycle_event) {
console.log('Testing build output from dist/')
moduleNameMapper = {
'^yaml$': '<rootDir>/dist/index.js',
'^yaml/cli$': '<rootDir>/dist/cli.mjs',
'^yaml/util$': '<rootDir>/dist/util.js',
'^../src/test-events$': '<rootDir>/dist/test-events.js'
}
transform['[/\\\\]dist[/\\\\].*\\.mjs$'] = [
'babel-jest',
{ configFile: './config/babel.config.js' }
]
break

case 'test':
default:
process.env.TRACE_LEVEL = 'log'
moduleNameMapper = {
'^yaml$': '<rootDir>/src/index.ts',
'^yaml/cli$': '<rootDir>/src/cli.ts',
'^yaml/util$': '<rootDir>/src/util.ts'
}
transform['[/\\\\]src[/\\\\].*\\.ts$'] = [
Expand Down
37 changes: 23 additions & 14 deletions config/rollup.node-config.mjs
@@ -1,17 +1,26 @@
import { chmod, stat } from 'node:fs/promises'
import typescript from '@rollup/plugin-typescript'

export default {
input: {
index: 'src/index.ts',
'test-events': 'src/test-events.ts',
util: 'src/util.ts'
export default [
{
input: {
index: 'src/index.ts',
'test-events': 'src/test-events.ts',
util: 'src/util.ts'
},
output: {
dir: 'dist',
format: 'cjs',
esModule: false,
preserveModules: true
},
plugins: [typescript()],
treeshake: { moduleSideEffects: false, propertyReadSideEffects: false }
},
output: {
dir: 'dist',
format: 'cjs',
esModule: false,
preserveModules: true
},
plugins: [typescript()],
treeshake: { moduleSideEffects: false, propertyReadSideEffects: false }
}
{
input: 'src/cli.ts',
output: { file: 'dist/cli.mjs' },
external: () => true,
plugins: [typescript()]
}
]
2 changes: 2 additions & 0 deletions docs/01_intro.md
Expand Up @@ -43,6 +43,8 @@ This requirement may be updated between minor versions of the library.
The API provided by `yaml` has three layers, depending on how deep you need to go: [Parse & Stringify](#parse-amp-stringify), [Documents](#documents), and the underlying [Lexer/Parser/Composer](#parsing-yaml).
The first has the simplest API and "just works", the second gets you all the bells and whistles supported by the library along with a decent [AST](#content-nodes), and the third lets you get progressively closer to YAML source, if that's your thing.

A [command-line tool](#command-line-tool) is also included.

<h3>Parse & Stringify</h3>

```js
Expand Down
26 changes: 26 additions & 0 deletions docs/09_cli.md
@@ -0,0 +1,26 @@
# Command-line Tool

Available as `npx yaml` or `npm exec yaml`:

<pre id="cli-help" style="float: none">
yaml: A command-line YAML processor and inspector

Reads stdin and writes output to stdout and errors & warnings to stderr.

Usage:
yaml Process a YAML stream, outputting it as YAML
yaml cst Parse the CST of a YAML stream
yaml lex Parse the lexical tokens of a YAML stream
yaml valid Validate a YAML stream, returning 0 on success

Options:
--help, -h Show this message.
--json, -j Output JSON.

Additional options for bare "yaml" command:
--doc, -d Output pretty-printed JS Document objects.
--single, -1 Require the input to consist of a single YAML document.
--strict, -s Stop on errors.
--visit, -v Apply a visitor to each document (requires a path to import)
--yaml 1.1 Set the YAML version. (default: 1.2)
</pre>
File renamed without changes.
3 changes: 2 additions & 1 deletion docs/index.html.md
Expand Up @@ -15,7 +15,8 @@ includes:
- 06_custom_tags
- 07_parsing_yaml
- 08_errors
- 09_yaml_syntax
- 09_cli
- 10_yaml_syntax

search: true
---
20 changes: 19 additions & 1 deletion docs/prepare-docs.mjs
@@ -1,12 +1,30 @@
#!/usr/bin/env node

import { lstat, mkdir, readdir, readFile, symlink, rm } from 'node:fs/promises'
import {
lstat,
mkdir,
readdir,
readFile,
symlink,
rm,
writeFile
} from 'node:fs/promises'
import { resolve } from 'node:path'
import { help } from '../dist/cli.mjs'
import { parseAllDocuments } from '../dist/index.js'

const source = 'docs'
const target = 'docs-slate/source'

// Update CLI help
const cli = resolve(source, '09_cli.md')
const docs = await readFile(cli, 'utf-8')
const update = docs.replace(
/(<pre id="cli-help".*?>).*?(<\/pre>)/s,
'$1\n' + help + '\n$2'
)
if (update !== docs) await writeFile(cli, update)

// Create symlink for index.html.md
const indexSource = resolve(source, 'index.html.md')
const indexTarget = resolve(target, 'index.html.md')
Expand Down
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -18,6 +18,7 @@
],
"type": "commonjs",
"main": "./dist/index.js",
"bin": "./bin.mjs",
"browser": {
"./dist/index.js": "./browser/index.js",
"./dist/util.js": "./browser/dist/util.js",
Expand Down

0 comments on commit e6a5e28

Please sign in to comment.