gitsheets 0.22.4 → 1.0.3
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/LICENSE +201 -0
- package/README.md +21 -0
- package/bin/gitsheets +5 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +256 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/errors.d.ts +72 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/patch.d.ts +2 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +39 -0
- package/dist/patch.js.map +1 -0
- package/dist/path-template/index.d.ts +42 -0
- package/dist/path-template/index.d.ts.map +1 -0
- package/dist/path-template/index.js +288 -0
- package/dist/path-template/index.js.map +1 -0
- package/dist/push-daemon.d.ts +53 -0
- package/dist/push-daemon.d.ts.map +1 -0
- package/dist/push-daemon.js +148 -0
- package/dist/push-daemon.js.map +1 -0
- package/dist/repository.d.ts +67 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +322 -0
- package/dist/repository.js.map +1 -0
- package/dist/sheet.d.ts +107 -0
- package/dist/sheet.d.ts.map +1 -0
- package/dist/sheet.js +605 -0
- package/dist/sheet.js.map +1 -0
- package/dist/store.d.ts +41 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +49 -0
- package/dist/store.js.map +1 -0
- package/dist/toml.d.ts +11 -0
- package/dist/toml.d.ts.map +1 -0
- package/dist/toml.js +28 -0
- package/dist/toml.js.map +1 -0
- package/dist/transaction.d.ts +96 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +227 -0
- package/dist/transaction.js.map +1 -0
- package/dist/validation.d.ts +37 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +105 -0
- package/dist/validation.js.map +1 -0
- package/package.json +41 -35
- package/bin/cli.js +0 -61
- package/commands/edit.js +0 -90
- package/commands/normalize.js +0 -81
- package/commands/query.js +0 -206
- package/commands/read.js +0 -64
- package/commands/singer-target.js +0 -214
- package/commands/upsert.js +0 -260
- package/lib/GitSheets.js +0 -464
- package/lib/Repository.js +0 -88
- package/lib/Sheet.js +0 -625
- package/lib/errors.js +0 -21
- package/lib/hologit.js +0 -1
- package/lib/logger.js +0 -18
- package/lib/path/BaseComponent.js +0 -24
- package/lib/path/ExpressionComponent.js +0 -26
- package/lib/path/FieldComponent.js +0 -13
- package/lib/path/LiteralComponent.js +0 -12
- package/lib/path/Query.js +0 -18
- package/lib/path/Template.js +0 -214
- package/server.js +0 -120
package/package.json
CHANGED
|
@@ -1,52 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitsheets",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "A git-backed document store for low-volume, high-touch, human-scale data",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
8
13
|
},
|
|
9
14
|
"bin": {
|
|
10
|
-
"
|
|
15
|
+
"gitsheets": "./bin/gitsheets",
|
|
16
|
+
"git-sheet": "./bin/gitsheets"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"bin",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.build.json",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"type-check": "tsc --noEmit"
|
|
11
32
|
},
|
|
12
33
|
"repository": {
|
|
13
34
|
"type": "git",
|
|
14
|
-
"url": "git+
|
|
35
|
+
"url": "git+https://github.com/JarvusInnovations/gitsheets.git"
|
|
15
36
|
},
|
|
16
|
-
"
|
|
17
|
-
"license": "Apache-2.0",
|
|
37
|
+
"homepage": "https://github.com/JarvusInnovations/gitsheets#readme",
|
|
18
38
|
"bugs": {
|
|
19
39
|
"url": "https://github.com/JarvusInnovations/gitsheets/issues"
|
|
20
40
|
},
|
|
21
|
-
"
|
|
41
|
+
"license": "Apache-2.0",
|
|
42
|
+
"author": "Jarvus Innovations",
|
|
22
43
|
"dependencies": {
|
|
23
44
|
"@iarna/toml": "^2.2.5",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"hologit": "^0.41.8",
|
|
30
|
-
"http-assert": "^1.4.1",
|
|
31
|
-
"koa": "^2.13.1",
|
|
32
|
-
"koa-bodyparser": "^4.3.0",
|
|
33
|
-
"koa-router": "^7.4.0",
|
|
34
|
-
"maxstache": "^1.0.7",
|
|
35
|
-
"mz": "^2.7.0",
|
|
36
|
-
"rfc6902": "^5.0.1",
|
|
37
|
-
"sort-keys": "^4.2.0",
|
|
38
|
-
"streaming-json-stringify": "^3.1.0",
|
|
39
|
-
"tmp": "^0.2.1",
|
|
40
|
-
"to-readable-stream": "^2.1.0",
|
|
41
|
-
"winston": "^3.3.3",
|
|
42
|
-
"yargs": "^17.5.1"
|
|
45
|
+
"ajv": "^8.20.0",
|
|
46
|
+
"ajv-formats": "^3.0.1",
|
|
47
|
+
"hologit": "^0.49.1",
|
|
48
|
+
"sort-keys": "^6.0.0",
|
|
49
|
+
"yargs": "^18.0.0"
|
|
43
50
|
},
|
|
44
51
|
"devDependencies": {
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"supertest": "^4.0.2"
|
|
52
|
+
"@types/node": "^25.8.0",
|
|
53
|
+
"@types/yargs": "^17.0.35",
|
|
54
|
+
"tmp": "^0.2.5",
|
|
55
|
+
"typescript": "^6.0.3",
|
|
56
|
+
"vitest": "^4.1.6"
|
|
51
57
|
}
|
|
52
58
|
}
|
package/bin/cli.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// setup logger
|
|
5
|
-
const logger = require('winston');
|
|
6
|
-
const loggerConsole = new logger.transports.Console({
|
|
7
|
-
level: process.env.DEBUG ? 'debug' : 'info',
|
|
8
|
-
format: logger.format.combine(
|
|
9
|
-
logger.format.colorize(),
|
|
10
|
-
logger.format.prettyPrint(),
|
|
11
|
-
logger.format.splat(),
|
|
12
|
-
logger.format.simple(),
|
|
13
|
-
),
|
|
14
|
-
|
|
15
|
-
// all logger output to STDERR
|
|
16
|
-
stderrLevels: Object.keys(require('winston/lib/winston/config').cli.levels),
|
|
17
|
-
});
|
|
18
|
-
logger.add(loggerConsole);
|
|
19
|
-
|
|
20
|
-
module.exports = { logger };
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// route command line
|
|
24
|
-
require('yargs')
|
|
25
|
-
.version(require('../package.json').version)
|
|
26
|
-
.option('d', {
|
|
27
|
-
alias: 'debug',
|
|
28
|
-
type: 'boolean',
|
|
29
|
-
default: false,
|
|
30
|
-
global: true,
|
|
31
|
-
})
|
|
32
|
-
.option('q', {
|
|
33
|
-
alias: 'quiet',
|
|
34
|
-
type: 'boolean',
|
|
35
|
-
default: false,
|
|
36
|
-
global: true,
|
|
37
|
-
})
|
|
38
|
-
.check(function (argv) {
|
|
39
|
-
if (argv.debug) {
|
|
40
|
-
loggerConsole.level = 'debug';
|
|
41
|
-
} else if (argv.quiet) {
|
|
42
|
-
loggerConsole.level = 'error';
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return true;
|
|
46
|
-
})
|
|
47
|
-
.commandDir('../commands', { exclude: /\.test\.js$/ })
|
|
48
|
-
.demandCommand()
|
|
49
|
-
.showHelpOnFail(false, 'Specify --help for available options')
|
|
50
|
-
.fail((msg, err) => {
|
|
51
|
-
logger.error(msg || err.message);
|
|
52
|
-
|
|
53
|
-
if (err) {
|
|
54
|
-
logger.debug(err.stack);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
process.exit(1);
|
|
58
|
-
})
|
|
59
|
-
.strict()
|
|
60
|
-
.help()
|
|
61
|
-
.argv;
|
package/commands/edit.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
exports.command = 'edit <record-path> [resume-path]';
|
|
2
|
-
exports.desc = 'Edit a record, validating and formatting it automatically';
|
|
3
|
-
exports.builder = {
|
|
4
|
-
'record-path': {
|
|
5
|
-
type: 'string',
|
|
6
|
-
describe: 'The path to a record file to edit',
|
|
7
|
-
demandOption: true,
|
|
8
|
-
},
|
|
9
|
-
'resume-path': {
|
|
10
|
-
type: 'string',
|
|
11
|
-
describe: 'If set, read initial editor content from this file instead of the target record',
|
|
12
|
-
},
|
|
13
|
-
encoding: {
|
|
14
|
-
type: 'string',
|
|
15
|
-
default: 'utf8',
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
exports.handler = async function edit({ recordPath, resumePath, encoding }) {
|
|
20
|
-
const fs = require('fs');
|
|
21
|
-
const { spawn } = require('child_process');
|
|
22
|
-
const path = require('path');
|
|
23
|
-
const tmp = require('tmp');
|
|
24
|
-
const TOML = require('@iarna/toml');
|
|
25
|
-
const Repository = require('../lib/Repository.js');
|
|
26
|
-
const Sheet = require('../lib/Sheet.js')
|
|
27
|
-
const repo = await Repository.getFromEnvironment({ working: true });
|
|
28
|
-
const git = await repo.getGit();
|
|
29
|
-
|
|
30
|
-
// open record
|
|
31
|
-
let recordToml = fs.readFileSync(resumePath || recordPath, encoding);
|
|
32
|
-
|
|
33
|
-
// try to parse and format
|
|
34
|
-
try {
|
|
35
|
-
const record = TOML.parse(recordToml);
|
|
36
|
-
recordToml = Sheet.stringifyRecord(record);
|
|
37
|
-
} catch (err) {
|
|
38
|
-
console.warn(`Failed to parse opened record:\n${err}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// get temp path
|
|
42
|
-
const { name: tempFilePath } = tmp.fileSync({
|
|
43
|
-
prefix: path.basename(recordPath, '.toml'),
|
|
44
|
-
postfix: '.toml',
|
|
45
|
-
discardDescriptor: true,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// populate temp path
|
|
49
|
-
fs.writeFileSync(tempFilePath, recordToml, encoding);
|
|
50
|
-
|
|
51
|
-
// get editor
|
|
52
|
-
const editor = (await git.var('GIT_EDITOR')) || 'vim';
|
|
53
|
-
|
|
54
|
-
// invoke editor
|
|
55
|
-
try {
|
|
56
|
-
const editorProcess = spawn('sh', ['-c', `eval ${editor} ${tempFilePath}`], { stdio: 'inherit' });
|
|
57
|
-
const exitCode = await new Promise(resolve => editorProcess.on('close', resolve));
|
|
58
|
-
|
|
59
|
-
if (exitCode !== 0) {
|
|
60
|
-
console.error(`editor exited with code ${exitCode}, canceling edit`);
|
|
61
|
-
fs.unlinkSync(tempFilePath);
|
|
62
|
-
process.exit(exitCode);
|
|
63
|
-
}
|
|
64
|
-
} catch (err) {
|
|
65
|
-
console.error(`Failed to invoke editor: ${err}`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// read and clean up temp file
|
|
69
|
-
const editedToml = fs.readFileSync(tempFilePath, encoding);
|
|
70
|
-
|
|
71
|
-
// parse toml
|
|
72
|
-
let editedRecord;
|
|
73
|
-
try {
|
|
74
|
-
editedRecord = TOML.parse(editedToml);
|
|
75
|
-
} catch (err) {
|
|
76
|
-
console.error(`Failed to parse edited record:\n${err}`);
|
|
77
|
-
console.error(`To resume editing, run: git sheet edit ${recordPath} ${tempFilePath}`);
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// delete temp file
|
|
82
|
-
fs.unlinkSync(tempFilePath);
|
|
83
|
-
|
|
84
|
-
// save normalized TOML to input path
|
|
85
|
-
fs.writeFileSync(recordPath, Sheet.stringifyRecord(editedRecord));
|
|
86
|
-
process.exit(0);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// library
|
package/commands/normalize.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
exports.command = 'normalize [sheet...]';
|
|
2
|
-
exports.desc = 'Normalize the content of any hand-edited records to be consistent';
|
|
3
|
-
exports.builder = {
|
|
4
|
-
sheet: {
|
|
5
|
-
describe: 'Name of sheet to upsert into',
|
|
6
|
-
type: 'array',
|
|
7
|
-
},
|
|
8
|
-
root: {
|
|
9
|
-
describe: 'Root path to .gitsheets in repository (defaults to GITSHEETS_ROOT or /)',
|
|
10
|
-
},
|
|
11
|
-
prefix: {
|
|
12
|
-
describe: 'Path to prefix after root to all sheet paths (defaults to GITSHEETS_PREFIX or none)',
|
|
13
|
-
},
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
exports.handler = async function query({
|
|
17
|
-
sheet: selectedSheets,
|
|
18
|
-
root,
|
|
19
|
-
prefix,
|
|
20
|
-
}) {
|
|
21
|
-
const logger = require('../lib/logger.js');
|
|
22
|
-
const Repository = require('../lib/Repository.js')
|
|
23
|
-
const path = require('path');
|
|
24
|
-
const fs = require('mz/fs');
|
|
25
|
-
|
|
26
|
-
const { GITSHEETS_ROOT, GITSHEETS_PREFIX } = process.env;
|
|
27
|
-
|
|
28
|
-
// apply dynamic defaults
|
|
29
|
-
if (!root) {
|
|
30
|
-
root = GITSHEETS_ROOT || '/';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (!prefix) {
|
|
34
|
-
prefix = GITSHEETS_PREFIX || null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// get repo interface
|
|
38
|
-
const repo = await Repository.getFromEnvironment({ working: true });
|
|
39
|
-
logger.debug('instantiated repository:', repo);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// get sheets
|
|
43
|
-
const sheets = await repo.openSheets({ root, dataTree: prefix });
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// loop through selected, or all sheets
|
|
47
|
-
const sheetNames = selectedSheets || Object.keys(sheets);
|
|
48
|
-
|
|
49
|
-
for (const sheetName of sheetNames) {
|
|
50
|
-
const sheet = sheets[sheetName];
|
|
51
|
-
|
|
52
|
-
if (!sheet) {
|
|
53
|
-
throw new Error(`sheet ${sheetName} is not defined`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// loop through all records and re-upsert
|
|
57
|
-
try {
|
|
58
|
-
for await (const record of sheet.query()) {
|
|
59
|
-
const originalPath = record[Symbol.for('gitsheets-path')];
|
|
60
|
-
logger.info(`rewriting ${path.join(root, prefix||'', sheetName, originalPath)}.toml`);
|
|
61
|
-
const { path: normalizedPath } = await sheet.upsert(record);
|
|
62
|
-
|
|
63
|
-
if (normalizedPath !== originalPath) {
|
|
64
|
-
logger.warn(`^- moved to ${path.join(root, prefix||'', sheetName, normalizedPath)}.toml`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
} catch (err) {
|
|
68
|
-
if (err.constructor.name == 'TomlError') {
|
|
69
|
-
logger.error(`failed to parse ${path.join(root, prefix||'', err.file)}\n${err.message}`);
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
throw err;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// write changes to workspace
|
|
79
|
-
const workspace = await repo.getWorkspace();
|
|
80
|
-
await workspace.writeWorkingChanges();
|
|
81
|
-
};
|
package/commands/query.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
exports.command = 'query <sheet>';
|
|
2
|
-
exports.desc = 'Read records from a sheet';
|
|
3
|
-
exports.builder = {
|
|
4
|
-
sheet: {
|
|
5
|
-
describe: 'Name of sheet to upsert into',
|
|
6
|
-
},
|
|
7
|
-
root: {
|
|
8
|
-
describe: 'Root path to .gitsheets in repository (defaults to GITSHEETS_ROOT or /)',
|
|
9
|
-
},
|
|
10
|
-
prefix: {
|
|
11
|
-
describe: 'Path to prefix after root to all sheet paths (defaults to GITSHEETS_PREFIX or none)',
|
|
12
|
-
},
|
|
13
|
-
format: {
|
|
14
|
-
describe: 'Format to serialize output data in (defaults to json)',
|
|
15
|
-
choices: ['json', 'csv', 'tsv', 'toml'],
|
|
16
|
-
default: 'json',
|
|
17
|
-
},
|
|
18
|
-
headers: {
|
|
19
|
-
describe: 'Whether to show headers in output formats that have headers (i.e. csv)',
|
|
20
|
-
type: 'boolean',
|
|
21
|
-
default: true,
|
|
22
|
-
},
|
|
23
|
-
// encoding: {
|
|
24
|
-
// describe: 'Encoding to write output with',
|
|
25
|
-
// default: 'utf8',
|
|
26
|
-
// },
|
|
27
|
-
limit: {
|
|
28
|
-
describe: 'Truncate results to given count',
|
|
29
|
-
type: 'number'
|
|
30
|
-
},
|
|
31
|
-
'filter': {
|
|
32
|
-
group: 'Filtering',
|
|
33
|
-
describe: 'Filter results by one or more field values',
|
|
34
|
-
type: 'array'
|
|
35
|
-
},
|
|
36
|
-
'filter.<field>[=<value>]': {
|
|
37
|
-
group: 'Filtering',
|
|
38
|
-
describe: 'Field to filter by'
|
|
39
|
-
},
|
|
40
|
-
fields: {
|
|
41
|
-
group: 'Field selection',
|
|
42
|
-
describe: 'List of fields to order/limit output columns with',
|
|
43
|
-
type: 'array'
|
|
44
|
-
},
|
|
45
|
-
'fields.<from>=<to>': {
|
|
46
|
-
group: 'Field selection',
|
|
47
|
-
describe: 'Field to remap',
|
|
48
|
-
type: 'array'
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
exports.handler = async function query({
|
|
53
|
-
sheet: sheetName,
|
|
54
|
-
root,
|
|
55
|
-
prefix,
|
|
56
|
-
format,
|
|
57
|
-
headers,
|
|
58
|
-
// encoding,
|
|
59
|
-
limit,
|
|
60
|
-
filter,
|
|
61
|
-
fields,
|
|
62
|
-
}) {
|
|
63
|
-
const logger = require('../lib/logger.js');
|
|
64
|
-
const Repository = require('../lib/Repository.js')
|
|
65
|
-
const path = require('path');
|
|
66
|
-
const fs = require('mz/fs');
|
|
67
|
-
|
|
68
|
-
const { GITSHEETS_ROOT, GITSHEETS_PREFIX } = process.env;
|
|
69
|
-
|
|
70
|
-
// apply dynamic defaults
|
|
71
|
-
if (!root) {
|
|
72
|
-
root = GITSHEETS_ROOT || '/';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (!prefix) {
|
|
76
|
-
prefix = GITSHEETS_PREFIX || null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// get repo interface
|
|
80
|
-
const repo = await Repository.getFromEnvironment({ working: true });
|
|
81
|
-
logger.debug('instantiated repository:', repo);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// get sheet
|
|
85
|
-
const sheet = await repo.openSheet(sheetName, { root, dataTree: prefix });
|
|
86
|
-
|
|
87
|
-
if (!sheet) {
|
|
88
|
-
throw new Error(`sheet '${sheetName}' not found under ${root}/.gitsheets/`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
logger.debug('loaded sheet:', sheet);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// query records
|
|
95
|
-
let result = sheet.query(filter);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// apply limit
|
|
99
|
-
if (limit) {
|
|
100
|
-
result = limitResult(result, limit);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// apply field shaping
|
|
105
|
-
if (fields) {
|
|
106
|
-
result = mapResult(result, fields);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// output results
|
|
111
|
-
switch (format) {
|
|
112
|
-
case 'json': return outputJson(result);
|
|
113
|
-
case 'csv': return outputCsv(result, { headers });
|
|
114
|
-
case 'tsv': return outputCsv(result, { headers, delimiter: '\t' });
|
|
115
|
-
case 'toml': return outputToml(result);
|
|
116
|
-
default: throw new Error(`Unsupported output format: ${format}`);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// library
|
|
122
|
-
async function* limitResult(result, limit) {
|
|
123
|
-
let count = 0;
|
|
124
|
-
|
|
125
|
-
for await (const record of result) {
|
|
126
|
-
count++;
|
|
127
|
-
yield record;
|
|
128
|
-
|
|
129
|
-
if (count >= limit) {
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async function* mapResult(result, fields) {
|
|
136
|
-
if (!Array.isArray(fields)) {
|
|
137
|
-
const fieldsObject = fields;
|
|
138
|
-
fields = [];
|
|
139
|
-
for (const fromKey in fieldsObject) {
|
|
140
|
-
const fieldMap = {};
|
|
141
|
-
fieldMap[fromKey] = fieldsObject[fromKey];
|
|
142
|
-
fields.push(fieldMap);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
for await (const record of result) {
|
|
147
|
-
const output = {};
|
|
148
|
-
|
|
149
|
-
for (const field of fields) {
|
|
150
|
-
if (Array.isArray(field)) {
|
|
151
|
-
for (const fieldValue of field) {
|
|
152
|
-
output[fieldValue] = record[fieldValue];
|
|
153
|
-
}
|
|
154
|
-
} else if (typeof field == 'object') {
|
|
155
|
-
for (const from in field) {
|
|
156
|
-
output[field[from]] = record[from];
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
output[field] = record[field];
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
yield output;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async function outputJson(result) {
|
|
168
|
-
let firstRecord = true;
|
|
169
|
-
|
|
170
|
-
console.log('[');
|
|
171
|
-
|
|
172
|
-
for await (const record of result) {
|
|
173
|
-
if (firstRecord) {
|
|
174
|
-
console.log(`${JSON.stringify(record)}`);
|
|
175
|
-
firstRecord = false;
|
|
176
|
-
} else {
|
|
177
|
-
console.log(`,${JSON.stringify(record)}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
console.log(']');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async function outputCsv(result, { headers = true, delimiter = ',' } = {}) {
|
|
185
|
-
const { Readable } = require('stream');
|
|
186
|
-
const { format: csvFormat } = require('fast-csv');
|
|
187
|
-
const csvStream = csvFormat({ headers, delimiter, includeEndRowDelimiter: true });
|
|
188
|
-
|
|
189
|
-
csvStream.pipe(process.stdout).on('end', () => process.exit());
|
|
190
|
-
|
|
191
|
-
Readable.from(result).pipe(csvStream);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
async function outputToml(result) {
|
|
195
|
-
const TOML = require('@iarna/toml');
|
|
196
|
-
let firstRecord = true;
|
|
197
|
-
|
|
198
|
-
for await (const record of result) {
|
|
199
|
-
if (firstRecord) {
|
|
200
|
-
console.log(`${TOML.stringify(record)}`);
|
|
201
|
-
firstRecord = false;
|
|
202
|
-
} else {
|
|
203
|
-
console.log(`\0\n${TOML.stringify(record)}`);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
package/commands/read.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
exports.command = 'read <record-path>';
|
|
2
|
-
exports.desc = 'Read a record, converting to desired format';
|
|
3
|
-
exports.builder = {
|
|
4
|
-
'record-path': {
|
|
5
|
-
type: 'string',
|
|
6
|
-
describe: 'The path to a record file to read',
|
|
7
|
-
demandOption: true,
|
|
8
|
-
},
|
|
9
|
-
encoding: {
|
|
10
|
-
type: 'string',
|
|
11
|
-
default: 'utf8',
|
|
12
|
-
},
|
|
13
|
-
format: {
|
|
14
|
-
describe: 'Format to serialize output data in (defaults to json)',
|
|
15
|
-
choices: ['json', 'csv', 'tsv', 'toml'],
|
|
16
|
-
default: 'json',
|
|
17
|
-
},
|
|
18
|
-
headers: {
|
|
19
|
-
describe: 'Whether to show headers in output formats that have headers (i.e. csv)',
|
|
20
|
-
type: 'boolean',
|
|
21
|
-
default: true,
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
exports.handler = async function edit({ recordPath, encoding, format, headers }) {
|
|
26
|
-
const fs = require('fs');
|
|
27
|
-
const TOML = require('@iarna/toml');
|
|
28
|
-
|
|
29
|
-
// open record
|
|
30
|
-
const recordToml = fs.readFileSync(recordPath, encoding);
|
|
31
|
-
|
|
32
|
-
// parse record
|
|
33
|
-
const record = TOML.parse(recordToml);
|
|
34
|
-
|
|
35
|
-
// output results
|
|
36
|
-
switch (format) {
|
|
37
|
-
case 'json': return outputJson(record);
|
|
38
|
-
case 'csv': return outputCsv(record, { headers });
|
|
39
|
-
case 'tsv': return outputCsv(record, { headers, delimiter: '\t' });
|
|
40
|
-
case 'toml': return outputToml(record);
|
|
41
|
-
default: throw new Error(`Unsupported output format: ${format}`);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// library
|
|
47
|
-
async function outputJson(record) {
|
|
48
|
-
console.log(`${JSON.stringify(record)}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async function outputCsv(record, { headers = true, delimiter = ',' } = {}) {
|
|
52
|
-
const { format: csvFormat } = require('fast-csv');
|
|
53
|
-
const csvStream = csvFormat({ headers, delimiter, includeEndRowDelimiter: true });
|
|
54
|
-
|
|
55
|
-
csvStream.pipe(process.stdout).on('end', () => process.exit());
|
|
56
|
-
|
|
57
|
-
csvStream.write(record);
|
|
58
|
-
csvStream.end();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function outputToml(record) {
|
|
62
|
-
const Sheet = require('../lib/Sheet.js')
|
|
63
|
-
console.log(`${Sheet.stringifyRecord(record)}`);
|
|
64
|
-
}
|