Skip to content

Commit 7891d17

Browse files
committed
xtended the --query option to accept a file path
1 parent 9f2d703 commit 7891d17

File tree

6 files changed

+125
-34
lines changed

6 files changed

+125
-34
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Added `--force` option to enforce overwritting a file
77
- Added `--dry-run` option
88
- Added `--verbose` option
9+
- Extended the `--query` option to accept a file path containing a Jora query, the file must have a `.jora` extension
910
- Changed behavior for writing to an existing file specified with the --output option. The operation now fails unless the --force option is used
1011
- Removed `--sandbox` option (until re-implemented)
1112

README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,19 @@ jora version <package.json
4747
# get all top level dependencies count
4848
jora -i package.json -q '(dependencies.keys() + devDependencies.keys()).size()'
4949
50-
# find packages with more than a single version
51-
npm ls --json | jora "
52-
..(dependencies.entries().({ name: key, ...value }))
53-
.group(=>name, =>version)
54-
.({ name: key, versions: value })
55-
.[versions.size() > 1]
56-
";
50+
# find packages with more than a single version (run query from a file)
51+
npm ls --json | jora find-multi-version-packages.jora
5752
```
5853
54+
> The content of `find-multi-version-packages.jora` may be as follows:
55+
>
56+
> ```js
57+
> ..(dependencies.entries().({ name: key, ...value }))
58+
> .group(=>name, =>version)
59+
> .({ name: key, versions: value })
60+
> .[versions.size() > 1]
61+
> ```
62+
5963
## Caveats
6064
6165
`jora-cli` takes a valid JSON and produce a valid JSON as a result. However, `jora` language could produce some values that incompatable with JSON, such values are transforming:

src/index.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ function safeOperation(name, fn) {
5252
}
5353
}
5454

55+
function extractQuery(queryOrFilename) {
56+
const maybeFilename = normFilepath(queryOrFilename);
57+
58+
if (typeof maybeFilename === 'string' && path.extname(maybeFilename) === '.jora') {
59+
if (!fs.existsSync(maybeFilename)) {
60+
throw new cli.Error(`ERROR! No such file or directory: ${maybeFilename}`);
61+
}
62+
63+
return safeOperation('Read jora query from file', () =>
64+
fs.readFileSync(maybeFilename, 'utf8')
65+
);
66+
}
67+
68+
return queryOrFilename;
69+
}
70+
5571
function prepareQuery(query) {
5672
return safeOperation('Jora query prepare', () =>
5773
jora(query || '')
@@ -83,7 +99,7 @@ function normFormat(value) {
8399
const encodings = ['json', 'jsonxl'];
84100
const command = cli.command('jora [query]')
85101
.version('', '', '', () => console.log(JSON.parse(fs.readFileSync('./package.json')).version))
86-
.option('-q, --query <query>', 'Jora query', normFilepath)
102+
.option('-q, --query <query>', 'Jora query or path to a query file with extension .jora', normFilepath)
87103
.option('-i, --input <filename>', 'Input file', normFilepath)
88104
.option('-o, --output <filename>', 'Output file (outputs to stdout if not set)')
89105
.option('-e, --encoding <encoding>', 'Output encoding: json (default), jsonxl (snapshot9)', normFormat, 'json')
@@ -134,7 +150,7 @@ const command = cli.command('jora [query]')
134150
// return;
135151
// }
136152

137-
const query = options.query || args[0];
153+
const query = extractQuery(options.query || args[0]);
138154
const queryFn = prepareQuery(query);
139155
const resultData = performQuery(queryFn, input.data, undefined);
140156
const encoding = options.encoding;

test/fixture.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "jora-cli",
3+
"version": "2.0.0",
4+
"description": "Command line interface for Jora",
5+
"keywords": [
6+
"cli",
7+
"jora"
8+
],
9+
"maintainers": [
10+
{
11+
"name": "Roman Dvornov",
12+
"email": "rdvornov@gmail.com",
13+
"github-username": "lahmatiy"
14+
}
15+
],
16+
"license": "MIT",
17+
"repository": "discoveryjs/jora-cli",
18+
"bin": {
19+
"jora": "./bin/jora"
20+
},
21+
"type": "module",
22+
"main": "./src/index.js",
23+
"scripts": {
24+
"test": "mocha --reporter progress",
25+
"lint": "eslint src/*.js test/*.js",
26+
"lint-and-test": "npm run lint && npm test",
27+
"coverage": "c8 --reporter=lcovonly npm test",
28+
"prepublishOnly": "npm run lint-and-test"
29+
},
30+
"dependencies": {
31+
"@discoveryjs/json-ext": "^0.6.2",
32+
"ansi-styles": "^6.2.1",
33+
"clap": "^3.1.1",
34+
"jora": "1.0.0-beta.13",
35+
"jora-sandbox": "^1.3.0",
36+
"open": "^10.1.0",
37+
"supports-color": "^9.4.0",
38+
"tempfile": "^5.0.0"
39+
},
40+
"devDependencies": {
41+
"c8": "^10.1.2",
42+
"eslint": "^8.57.1",
43+
"mocha": "^10.7.3"
44+
},
45+
"engines": {
46+
"node": ">=18.0.0"
47+
},
48+
"files": [
49+
"bin",
50+
"utils",
51+
"index.js"
52+
]
53+
}

test/query.jora

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
version

test/test.js

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import { fileURLToPath } from 'url';
66
import { parseJsonxl, style } from './helpers.js';
77

88
const __dirname = path.dirname(fileURLToPath(import.meta.url));
9-
const pkgJson = path.join(__dirname, '../package.json');
10-
const pkgJsonData = JSON.parse(fs.readFileSync(pkgJson));
11-
const fixture = fs.readFileSync(path.join(__dirname, 'color-fixture.json'), 'utf8');
9+
const queryFilename = path.join(__dirname, 'query.jora');
10+
const fixtureFilename = path.join(__dirname, 'fixture.json');
11+
const fixture = fs.readFileSync(fixtureFilename, 'utf8');
1212
const fixtureData = JSON.parse(fixture);
13-
const fixtureJsonxlFilename = path.join(__dirname, './fixture.jsonxl');
13+
const fixtureJsonxlFilename = path.join(__dirname, 'fixture.jsonxl');
1414
const fixtureJsonxl = fs.readFileSync(fixtureJsonxlFilename);
1515
const fixtureJsonxlData = parseJsonxl(fixtureJsonxl);
1616
const fixtureJsonxlJson = JSON.stringify(fixtureJsonxlData);
17-
const fixtureExpected = fs.readFileSync(path.join(__dirname, 'color-fixture.expected'), 'utf8').trim();
18-
const fixtureExpectedCompact = fs.readFileSync(path.join(__dirname, 'color-fixture.compact.expected'), 'utf8').trim();
17+
const colorFixture = fs.readFileSync(path.join(__dirname, 'color-fixture.json'), 'utf8');
18+
const colorFixtureData = JSON.parse(colorFixture);
19+
const colorFixtureExpected = fs.readFileSync(path.join(__dirname, 'color-fixture.expected'), 'utf8').trim();
20+
const colorFixtureExpectedCompact = fs.readFileSync(path.join(__dirname, 'color-fixture.compact.expected'), 'utf8').trim();
1921
const envWithForceColors = Object.assign({}, process.env, {
2022
FORCE_COLOR: true
2123
});
@@ -116,20 +118,34 @@ describe('non-JSON primitives', () => {
116118

117119
it('should output version', () =>
118120
run('-v')
119-
.output(pkgJsonData.version)
121+
.output(fixtureData.version)
120122
);
121123

122124
it('should read content from stdin if no file specified', () =>
123125
run('version')
124-
.input(JSON.stringify(pkgJsonData))
125-
.output(JSON.stringify(pkgJsonData.version))
126+
.input(fixture)
127+
.output(JSON.stringify(fixtureData.version))
126128
);
127129

128130
it('should read from file', () =>
129-
run('-i', pkgJson, '-q', 'version')
130-
.output(JSON.stringify(pkgJsonData.version))
131+
run('-i', fixtureFilename, '-q', 'version')
132+
.output(JSON.stringify(fixtureData.version))
131133
);
132134

135+
describe('query from a file', () => {
136+
it('as arg', () =>
137+
run(queryFilename)
138+
.input(fixture)
139+
.output(JSON.stringify(fixtureData.version))
140+
);
141+
142+
it('as option', () =>
143+
run('-q', queryFilename)
144+
.input(fixture)
145+
.output(JSON.stringify(fixtureData.version))
146+
);
147+
});
148+
133149
describe('jsonxl', () => {
134150
it('should read from jsonxl file', () =>
135151
run('-i', fixtureJsonxlFilename, '-q', 'version')
@@ -158,14 +174,14 @@ describe('jsonxl', () => {
158174
describe('pretty print', function() {
159175
it('indentation should be 4 spaces by default', () =>
160176
run('dependencies.keys()', '-p')
161-
.input(JSON.stringify(pkgJsonData))
162-
.output(JSON.stringify(Object.keys(pkgJsonData.dependencies), null, 4))
177+
.input(fixture)
178+
.output(JSON.stringify(Object.keys(fixtureData.dependencies), null, 4))
163179
);
164180

165181
it('indentation should be as specified', () =>
166182
run('dependencies.keys()', '-p', '3')
167-
.input(JSON.stringify(pkgJsonData))
168-
.output(JSON.stringify(Object.keys(pkgJsonData.dependencies), null, 3))
183+
.input(fixture)
184+
.output(JSON.stringify(Object.keys(fixtureData.dependencies), null, 3))
169185
);
170186
});
171187

@@ -194,10 +210,10 @@ describe('errors', function() {
194210

195211
// FIXME: skip colored output tests for Windows since no way currently to pass custom env variable (FORCE_COLOR) to a child process
196212
// FIXME: --color temporary disabled
197-
(false && process.platform !== 'win32' ? describe : describe.skip)('colored output', function() {
213+
(process.platform !== 'win32' ? describe : describe.skip)('colored output', function() {
198214
const tests = {
199-
string: style('STRING', JSON.stringify(fixtureData.string)),
200-
number: style('NUMBER', fixtureData.number),
215+
string: style('STRING', JSON.stringify(colorFixtureData.string)),
216+
number: style('NUMBER', colorFixtureData.number),
201217
emptyArray: style('LEFT_BRACKET', '[', 'RIGHT_BRACKET', ']'),
202218
emptyObject: style('LEFT_BRACE', '{', 'RIGHT_BRACE', '}'),
203219
singlePropObject: style('LEFT_BRACE', '{', 'STRING_KEY', '"', 'STRING_KEY_CONTENT', 'foo', 'STRING_KEY', '"', 'COLON', ':', 'STRING', '"test"', 'RIGHT_BRACE', '}'),
@@ -209,7 +225,7 @@ describe('errors', function() {
209225
Object.keys(tests).forEach(key => {
210226
it(key, () =>
211227
runWithForceColors(key)
212-
.input(fixture)
228+
.input(colorFixture)
213229
.output(tests[key])
214230
);
215231
});
@@ -230,21 +246,21 @@ describe('errors', function() {
230246
// FORCE_COLOR=true node bin/jora <test/color-fixture.json >test/color-fixture.compact.expected
231247
it('compact', () =>
232248
runWithForceColors()
233-
.input(fixture)
234-
.output(fixtureExpectedCompact)
249+
.input(colorFixture)
250+
.output(colorFixtureExpectedCompact)
235251
);
236252

237253
// FORCE_COLOR=true node bin/jora -p <test/color-fixture.json >test/color-fixture.expected
238254
it('pretty print', () =>
239255
runWithForceColors('-p')
240-
.input(fixture)
241-
.output(fixtureExpected)
256+
.input(colorFixture)
257+
.output(colorFixtureExpected)
242258
);
243259
});
244260

245261
it('--no-color should suppress output coloring', () =>
246262
runWithForceColors('--no-color')
247-
.input(fixture)
248-
.output(JSON.stringify(fixtureData))
263+
.input(colorFixture)
264+
.output(JSON.stringify(colorFixtureData))
249265
);
250266
});

0 commit comments

Comments
 (0)