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
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
class FieldComponent extends require('./BaseComponent.js') {
|
|
2
|
-
constructor ({ recursive = false }) {
|
|
3
|
-
super(...arguments);
|
|
4
|
-
this.recursive = recursive;
|
|
5
|
-
Object.freeze(this);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
render (record) {
|
|
9
|
-
return this.formatValue(record ? record[this.name] : undefined);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
module.exports = FieldComponent;
|
package/lib/path/Query.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
class Query {
|
|
2
|
-
prefix;
|
|
3
|
-
complete;
|
|
4
|
-
|
|
5
|
-
static render (template, query) {
|
|
6
|
-
debugger;
|
|
7
|
-
|
|
8
|
-
return new this();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
constructor (prefix, complete) {
|
|
12
|
-
this.prefix = prefix;
|
|
13
|
-
this.complete = complete;
|
|
14
|
-
Object.freeze(this);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module.exports = Query;
|
package/lib/path/Template.js
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const LiteralComponent = require('./LiteralComponent.js');
|
|
3
|
-
const FieldComponent = require('./FieldComponent.js');
|
|
4
|
-
const ExpressionComponent = require('./ExpressionComponent.js');
|
|
5
|
-
// const Query = require('./Query.js');
|
|
6
|
-
|
|
7
|
-
const FIELD_EXPRESSION_RE = /^[a-zA-Z0-9_\-]+(\/\*\*)?$/;
|
|
8
|
-
const INSTANCE_CACHE = new Map();
|
|
9
|
-
const PATH_COMPONENT_TEMPLATE = {
|
|
10
|
-
kind: LiteralComponent,
|
|
11
|
-
prefix: '',
|
|
12
|
-
name: '',
|
|
13
|
-
suffix: '',
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
class Template
|
|
17
|
-
{
|
|
18
|
-
static fromString (templateString) {
|
|
19
|
-
let instance = INSTANCE_CACHE.get(templateString);
|
|
20
|
-
|
|
21
|
-
if (instance) {
|
|
22
|
-
return instance;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
instance = new this(parseRecordPathTemplate(templateString));
|
|
26
|
-
INSTANCE_CACHE.set(templateString, instance);
|
|
27
|
-
|
|
28
|
-
return instance;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
#components;
|
|
32
|
-
|
|
33
|
-
constructor (templateComponents) {
|
|
34
|
-
this.#components = templateComponents;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
render (record) {
|
|
38
|
-
const recordPath = [];
|
|
39
|
-
|
|
40
|
-
for (const component of this.#components) {
|
|
41
|
-
const string = component.render(record);
|
|
42
|
-
|
|
43
|
-
if (string === null) {
|
|
44
|
-
throw new Error('unable to render path component');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
recordPath.push(string);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return recordPath.join('/');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async* queryTree (tree, query, pathPrefix = '', depth = 0) {
|
|
54
|
-
const numComponents = this.#components.length;
|
|
55
|
-
|
|
56
|
-
if (!tree) {
|
|
57
|
-
// no results if tree doesn't exist
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
for (let i = depth, currentTree = tree; i < numComponents; i++) {
|
|
62
|
-
const isLast = i +1 == numComponents;
|
|
63
|
-
const cur = this.#components[i];
|
|
64
|
-
const nextName = cur.render(query);
|
|
65
|
-
|
|
66
|
-
if (isLast) {
|
|
67
|
-
if (nextName) {
|
|
68
|
-
const child = await currentTree.getChild(`${nextName}.toml`);
|
|
69
|
-
|
|
70
|
-
if (child) {
|
|
71
|
-
yield { path: path.join(pathPrefix, nextName), blob: child };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// absolute match on a leaf, we're done with this query
|
|
75
|
-
return;
|
|
76
|
-
} else {
|
|
77
|
-
// each record in current tree is a result
|
|
78
|
-
const children = cur.recursive
|
|
79
|
-
? await currentTree.getBlobMap()
|
|
80
|
-
: await currentTree.getChildren();
|
|
81
|
-
|
|
82
|
-
let attachmentsPrefix;
|
|
83
|
-
|
|
84
|
-
for (const childPath in children) {
|
|
85
|
-
if (!childPath.endsWith('.toml')) {
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (attachmentsPrefix && childPath.indexOf(attachmentsPrefix) === 0) {
|
|
90
|
-
// this file is an attachment under the previous record
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const child = children[childPath];
|
|
95
|
-
|
|
96
|
-
if (!child || !child.isBlob) {
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const childName = childPath.substr(0, childPath.length - 5);
|
|
101
|
-
attachmentsPrefix = `${childName}/`;
|
|
102
|
-
yield { path: path.join(pathPrefix, childName), blob: child };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// crawl down the tree
|
|
110
|
-
if (nextName) {
|
|
111
|
-
const nextTree = await currentTree.getChild(nextName);
|
|
112
|
-
|
|
113
|
-
if (nextTree) {
|
|
114
|
-
currentTree = nextTree;
|
|
115
|
-
pathPrefix = path.join(pathPrefix, nextName);
|
|
116
|
-
} else {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
// each tree in current tree could contain matching records
|
|
121
|
-
const children = await currentTree.getChildren();
|
|
122
|
-
for (const childPath in children) {
|
|
123
|
-
const child = children[childPath];
|
|
124
|
-
|
|
125
|
-
if (!child.isTree) {
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
yield* this.queryTree(child, query, path.join(pathPrefix, childPath), i+1);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
module.exports = Template;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// private library
|
|
142
|
-
function parseRecordPathTemplate(templateString) {
|
|
143
|
-
templateString = path.join('.', templateString, '.');
|
|
144
|
-
const stringLength = templateString.length;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
let i = 0, cur = { ...PATH_COMPONENT_TEMPLATE };
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const parsed = [];
|
|
151
|
-
const finishCurrentComponent = () => {
|
|
152
|
-
if (cur.name) {
|
|
153
|
-
parsed.push(new cur.kind(cur));
|
|
154
|
-
}
|
|
155
|
-
cur = { ...PATH_COMPONENT_TEMPLATE };
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
while (i < stringLength) {
|
|
160
|
-
const nextChar = templateString[i];
|
|
161
|
-
|
|
162
|
-
// read an expression from ${{ to }}
|
|
163
|
-
if (nextChar == '$' && templateString.substr(i, 3) == '${{') {
|
|
164
|
-
cur.kind = ExpressionComponent;
|
|
165
|
-
i += 3;
|
|
166
|
-
|
|
167
|
-
if (cur.name) {
|
|
168
|
-
cur.prefix = cur.name;
|
|
169
|
-
cur.name = '';
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
while (templateString.substr(i, 2) != '}}') {
|
|
173
|
-
cur.name += templateString[i];
|
|
174
|
-
i++;
|
|
175
|
-
|
|
176
|
-
if (i == stringLength) {
|
|
177
|
-
throw new Error(`expression ${cur.name} not closed with }}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// finish reading name expression
|
|
182
|
-
cur.name = cur.name.trim();
|
|
183
|
-
|
|
184
|
-
// reduce to Field kind if name is a bare field name
|
|
185
|
-
if (FIELD_EXPRESSION_RE.test(cur.name)) {
|
|
186
|
-
cur.kind = FieldComponent;
|
|
187
|
-
|
|
188
|
-
if (cur.name.endsWith('/**')) {
|
|
189
|
-
cur.recursive = true;
|
|
190
|
-
cur.name = cur.name.substr(0, cur.name.length - 3);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// skip }} and continue scan from the top
|
|
195
|
-
i += 2;
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// process next character
|
|
200
|
-
if (nextChar == '/') {
|
|
201
|
-
finishCurrentComponent();
|
|
202
|
-
} else if (cur.kind !== LiteralComponent) {
|
|
203
|
-
cur.suffix += nextChar;
|
|
204
|
-
} else {
|
|
205
|
-
cur.name += nextChar;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
i++;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
finishCurrentComponent();
|
|
212
|
-
|
|
213
|
-
return parsed;
|
|
214
|
-
}
|
package/server.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
const Koa = require('koa')
|
|
2
|
-
const Router = require('koa-router')
|
|
3
|
-
const bodyParser = require('koa-bodyparser')
|
|
4
|
-
const { format: csvFormat } = require('fast-csv')
|
|
5
|
-
const JsonStringify = require('streaming-json-stringify')
|
|
6
|
-
const GitSheets = require('./lib/GitSheets')
|
|
7
|
-
|
|
8
|
-
const validRefPattern = /^[\w-\/]+$/
|
|
9
|
-
const validPathTemplatePattern = /^[{}\w- \/]+$/
|
|
10
|
-
|
|
11
|
-
module.exports = createServer
|
|
12
|
-
|
|
13
|
-
if (!module.parent) {
|
|
14
|
-
GitSheets.create()
|
|
15
|
-
.then(createServer)
|
|
16
|
-
.then((app) => {
|
|
17
|
-
app.listen(3000)
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function createServer (gitSheets) {
|
|
22
|
-
const app = new Koa()
|
|
23
|
-
const router = new Router()
|
|
24
|
-
|
|
25
|
-
router.get('/config/:ref+', async (ctx) => {
|
|
26
|
-
const ref = ctx.params.ref
|
|
27
|
-
ctx.assert(validRefPattern.test(ref), 400, 'invalid ref')
|
|
28
|
-
|
|
29
|
-
const config = await gitSheets.getConfig(ref)
|
|
30
|
-
ctx.body = { config }
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
router.put('/config/:ref+', bodyParser(), async (ctx) => {
|
|
34
|
-
const ref = ctx.params.ref
|
|
35
|
-
const { path } = ctx.request.body.config
|
|
36
|
-
const config = { path }
|
|
37
|
-
|
|
38
|
-
ctx.assert(validRefPattern.test(ref), 400, 'invalid ref')
|
|
39
|
-
ctx.assert(validPathTemplatePattern.test(path), 400, 'invalid path template')
|
|
40
|
-
|
|
41
|
-
await gitSheets.setConfig(ref, config)
|
|
42
|
-
ctx.status = 204
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
router.get('/records/:ref+', async (ctx) => {
|
|
46
|
-
const ref = ctx.params.ref
|
|
47
|
-
const format = ctx.query.format
|
|
48
|
-
ctx.assert(validRefPattern.test(ref), 400, 'invalid ref')
|
|
49
|
-
|
|
50
|
-
const rows = await gitSheets.export(ref)
|
|
51
|
-
|
|
52
|
-
switch (format || ctx.accepts('json', 'csv')) {
|
|
53
|
-
case 'csv':
|
|
54
|
-
ctx.type = 'text/csv'
|
|
55
|
-
ctx.set('Content-Disposition', `attachment; filename=${ref}.csv`)
|
|
56
|
-
ctx.body = rows.pipe(csvFormat({ headers: true }))
|
|
57
|
-
break
|
|
58
|
-
default:
|
|
59
|
-
ctx.type = 'application/json'
|
|
60
|
-
ctx.body = rows.pipe(JsonStringify())
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
router.post('/import/:ref+', async (ctx) => {
|
|
65
|
-
const ref = ctx.params.ref
|
|
66
|
-
const readStream = ctx.req
|
|
67
|
-
const branch = ctx.request.query.branch || ref
|
|
68
|
-
|
|
69
|
-
ctx.assert(ctx.is('csv'), 415, 'content-type must be text/csv')
|
|
70
|
-
ctx.assert(validRefPattern.test(ref), 400, 'invalid ref')
|
|
71
|
-
|
|
72
|
-
await gitSheets.import({
|
|
73
|
-
data: readStream,
|
|
74
|
-
dataType: 'csv',
|
|
75
|
-
parentRef: ref,
|
|
76
|
-
saveToBranch: branch
|
|
77
|
-
})
|
|
78
|
-
ctx.status = 204
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
router.get('/compare/:srcRef([\\w-\\/]+)..:dstRef([\\w-\\/]+)', async (ctx) => {
|
|
82
|
-
const { srcRef, dstRef } = ctx.params
|
|
83
|
-
|
|
84
|
-
ctx.assert(validRefPattern.test(srcRef), 400, 'invalid src ref')
|
|
85
|
-
ctx.assert(validRefPattern.test(dstRef), 400, 'invalid dst ref')
|
|
86
|
-
|
|
87
|
-
const diffs = await gitSheets.compare(srcRef, dstRef)
|
|
88
|
-
ctx.body = diffs
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
router.post('/compare/:srcRef([\\w-\\/]+)..:dstRef([\\w-\\/]+)', async (ctx) => {
|
|
92
|
-
const { srcRef, dstRef } = ctx.params
|
|
93
|
-
const msg = ctx.query.msg
|
|
94
|
-
|
|
95
|
-
ctx.assert(validRefPattern.test(srcRef), 400, 'invalid src ref')
|
|
96
|
-
ctx.assert(validRefPattern.test(dstRef), 400, 'invalid dst ref')
|
|
97
|
-
|
|
98
|
-
await gitSheets.merge(srcRef, dstRef, msg)
|
|
99
|
-
ctx.status = 204
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
async function errorHandler (ctx, next) {
|
|
103
|
-
try {
|
|
104
|
-
await next()
|
|
105
|
-
} catch (err) {
|
|
106
|
-
if (err.status) {
|
|
107
|
-
ctx.status = err.status
|
|
108
|
-
ctx.body = { message: err.message, code: err.constructor.name }
|
|
109
|
-
} else {
|
|
110
|
-
ctx.status = 500
|
|
111
|
-
ctx.body = { message: 'An unexpected error occurred' }
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return app
|
|
117
|
-
.use(errorHandler)
|
|
118
|
-
.use(router.routes())
|
|
119
|
-
.use(router.allowedMethods())
|
|
120
|
-
}
|