datagrok-tools 6.1.9 → 6.1.11
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/CHANGELOG.md +15 -0
- package/CLAUDE.md +68 -0
- package/GROK_S.md +361 -0
- package/bin/__tests__/build.test.js +116 -0
- package/bin/__tests__/build.test.ts +101 -0
- package/bin/__tests__/node-dapi.connections.test.js +120 -0
- package/bin/__tests__/node-dapi.connections.test.ts +84 -0
- package/bin/__tests__/node-dapi.groups.test.js +467 -0
- package/bin/__tests__/node-dapi.groups.test.ts +298 -0
- package/bin/__tests__/node-dapi.integration.test.js +406 -0
- package/bin/__tests__/node-dapi.integration.test.ts +447 -0
- package/bin/__tests__/node-dapi.shares.test.js +107 -0
- package/bin/__tests__/node-dapi.shares.test.ts +70 -0
- package/bin/__tests__/node-dapi.users.test.js +86 -0
- package/bin/__tests__/node-dapi.users.test.ts +58 -0
- package/bin/__tests__/server-output.test.js +171 -0
- package/bin/__tests__/server-output.test.ts +133 -0
- package/bin/__tests__/server.test.js +277 -0
- package/bin/__tests__/server.test.ts +197 -0
- package/bin/commands/api.js +13 -3
- package/bin/commands/build.js +1 -1
- package/bin/commands/create.js +8 -5
- package/bin/commands/help.js +80 -4
- package/bin/commands/report.js +231 -36
- package/bin/commands/server.js +670 -0
- package/bin/grok.js +3 -1
- package/bin/utils/node-dapi.js +582 -0
- package/bin/utils/server-client.js +15 -0
- package/bin/utils/server-output.js +127 -0
- package/bin/utils/utils.js +35 -5
- package/package-template/package.json +1 -1
- package/package.json +10 -3
- package/vitest.config.ts +25 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.cellStr = cellStr;
|
|
7
|
+
exports.csvCell = csvCell;
|
|
8
|
+
exports.getKeys = getKeys;
|
|
9
|
+
exports.printBatchOutput = printBatchOutput;
|
|
10
|
+
exports.printError = printError;
|
|
11
|
+
exports.printOutput = printOutput;
|
|
12
|
+
/// Docs: [Grok Dapi](/docs/plans/grok-dapi/)
|
|
13
|
+
|
|
14
|
+
function printOutput(data, format) {
|
|
15
|
+
if (data === null || data === undefined) {
|
|
16
|
+
if (format !== 'quiet') console.log('(empty)');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const rows = Array.isArray(data) ? data : [data];
|
|
20
|
+
switch (format) {
|
|
21
|
+
case 'json':
|
|
22
|
+
console.log(JSON.stringify(data, null, 2));
|
|
23
|
+
break;
|
|
24
|
+
case 'csv':
|
|
25
|
+
printCsv(rows);
|
|
26
|
+
break;
|
|
27
|
+
case 'quiet':
|
|
28
|
+
for (const row of rows) {
|
|
29
|
+
if (typeof row === 'object' && row !== null) console.log(row.id ?? row.name ?? JSON.stringify(row));else console.log(row);
|
|
30
|
+
}
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
printTable(rows);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function cellStr(v) {
|
|
37
|
+
if (v === null || v === undefined) return '';
|
|
38
|
+
if (typeof v === 'object') {
|
|
39
|
+
if (v.name) return v.name;
|
|
40
|
+
if (v.id) return v.id;
|
|
41
|
+
return JSON.stringify(v).slice(0, 40);
|
|
42
|
+
}
|
|
43
|
+
return String(v);
|
|
44
|
+
}
|
|
45
|
+
function printTable(rows) {
|
|
46
|
+
if (!rows.length) {
|
|
47
|
+
console.log('(no results)');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (typeof rows[0] !== 'object' || rows[0] === null) {
|
|
51
|
+
for (const r of rows) console.log(r);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const keys = getKeys(rows);
|
|
55
|
+
const widths = {};
|
|
56
|
+
for (const k of keys) widths[k] = k.length;
|
|
57
|
+
for (const row of rows) for (const k of keys) widths[k] = Math.max(widths[k], cellStr(row[k]).length);
|
|
58
|
+
const header = keys.map(k => k.padEnd(widths[k])).join(' ');
|
|
59
|
+
const sep = keys.map(k => '-'.repeat(widths[k])).join(' ');
|
|
60
|
+
console.log(header);
|
|
61
|
+
console.log(sep);
|
|
62
|
+
for (const row of rows) console.log(keys.map(k => cellStr(row[k]).padEnd(widths[k])).join(' '));
|
|
63
|
+
}
|
|
64
|
+
function printCsv(rows) {
|
|
65
|
+
if (!rows.length) return;
|
|
66
|
+
if (typeof rows[0] !== 'object' || rows[0] === null) {
|
|
67
|
+
for (const r of rows) console.log(csvCell(String(r)));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const keys = getKeys(rows);
|
|
71
|
+
console.log(keys.map(csvCell).join(','));
|
|
72
|
+
for (const row of rows) console.log(keys.map(k => csvCell(cellStr(row[k]))).join(','));
|
|
73
|
+
}
|
|
74
|
+
function csvCell(s) {
|
|
75
|
+
return s.includes(',') || s.includes('"') || s.includes('\n') ? `"${s.replace(/"/g, '""')}"` : s;
|
|
76
|
+
}
|
|
77
|
+
function getKeys(rows) {
|
|
78
|
+
const seen = new Set();
|
|
79
|
+
const keys = [];
|
|
80
|
+
for (const row of rows) for (const k of Object.keys(row)) if (!seen.has(k)) {
|
|
81
|
+
seen.add(k);
|
|
82
|
+
keys.push(k);
|
|
83
|
+
}
|
|
84
|
+
return keys.slice(0, 12);
|
|
85
|
+
}
|
|
86
|
+
function printBatchOutput(response, format) {
|
|
87
|
+
if (format === 'json') {
|
|
88
|
+
console.log(JSON.stringify(response, null, 2));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (format === 'quiet') {
|
|
92
|
+
const s = response.summary;
|
|
93
|
+
console.log(`${s.total} total: ${s.succeeded} succeeded, ${s.failed} failed, ${s.partial} partial, ${s.skipped} skipped`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// table and csv: print summary then per-op rows
|
|
98
|
+
const s = response.summary;
|
|
99
|
+
console.log(`Summary: ${s.total} total ${s.succeeded} succeeded ${s.failed} failed ${s.partial} partial ${s.skipped} skipped`);
|
|
100
|
+
if (!response.results.length) return;
|
|
101
|
+
console.log('');
|
|
102
|
+
const rows = response.results.map(r => {
|
|
103
|
+
const brief = r.status === 'error' ? r.error?.error ?? 'error' : r.status === 'skipped' ? r.reason ?? 'skipped' : r.status === 'partial' ? `${r.summary?.succeeded}/${r.summary?.total} succeeded` : '';
|
|
104
|
+
return {
|
|
105
|
+
id: r.id ?? '',
|
|
106
|
+
action: r.action,
|
|
107
|
+
status: r.status,
|
|
108
|
+
detail: brief
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
if (format === 'csv') printCsv(rows);else printTable(rows);
|
|
112
|
+
|
|
113
|
+
// Write per-op errors to stderr
|
|
114
|
+
const errors = response.results.filter(r => r.status === 'error');
|
|
115
|
+
if (errors.length) process.stderr.write(JSON.stringify(errors.map(r => ({
|
|
116
|
+
id: r.id,
|
|
117
|
+
action: r.action,
|
|
118
|
+
error: r.error
|
|
119
|
+
})), null, 2) + '\n');
|
|
120
|
+
}
|
|
121
|
+
function printError(err) {
|
|
122
|
+
const apiErr = err?.apiError;
|
|
123
|
+
const out = apiErr ?? {
|
|
124
|
+
error: String(err?.message ?? err)
|
|
125
|
+
};
|
|
126
|
+
process.stderr.write(JSON.stringify(out, null, 2) + '\n');
|
|
127
|
+
}
|
package/bin/utils/utils.js
CHANGED
|
@@ -4,7 +4,9 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.
|
|
7
|
+
exports.absUrlRegex = exports.TemplateBuilder = void 0;
|
|
8
|
+
exports.buildJsDoc = buildJsDoc;
|
|
9
|
+
exports.cacheValues = void 0;
|
|
8
10
|
exports.camelCaseToKebab = camelCaseToKebab;
|
|
9
11
|
exports.checkScriptLocation = checkScriptLocation;
|
|
10
12
|
exports.commentMap = void 0;
|
|
@@ -58,6 +60,26 @@ function descriptionToComment(s) {
|
|
|
58
60
|
if (s.length === 0) return '';
|
|
59
61
|
return '/**\n' + s + '\n*/\n';
|
|
60
62
|
}
|
|
63
|
+
const JSDOC_META_KEYS = ['choices', 'suggestions', 'semType'];
|
|
64
|
+
function buildJsDoc(opts) {
|
|
65
|
+
const {
|
|
66
|
+
description,
|
|
67
|
+
inputs
|
|
68
|
+
} = opts;
|
|
69
|
+
const lines = [];
|
|
70
|
+
if (description) lines.push(` * ${description}`);
|
|
71
|
+
for (const {
|
|
72
|
+
name,
|
|
73
|
+
type,
|
|
74
|
+
options = {}
|
|
75
|
+
} of inputs) {
|
|
76
|
+
const metaLines = JSDOC_META_KEYS.filter(k => options[k]).map(k => ` * ${k}: ${options[k]}`);
|
|
77
|
+
if (!options.description && !metaLines.length) continue;
|
|
78
|
+
const desc = options.description ? ` - ${options.description}` : '';
|
|
79
|
+
lines.push(` * @param {${type}} ${name}${desc}`, ...metaLines);
|
|
80
|
+
}
|
|
81
|
+
return lines.length ? `/**\n${lines.join('\n')}\n */\n` : '';
|
|
82
|
+
}
|
|
61
83
|
function spaceToCamelCase(s, firstUpper = true) {
|
|
62
84
|
s = s.replace(/\s+./g, x => x[x.length - 1].toUpperCase());
|
|
63
85
|
return (firstUpper ? s[0].toUpperCase() : s[0].toLowerCase()) + s.slice(1);
|
|
@@ -107,6 +129,7 @@ const replacers = exports.replacers = {
|
|
|
107
129
|
PACKAGE_DETECTORS_NAME: (s, name) => s.replace(/#{PACKAGE_DETECTORS_NAME}/g, kebabToCamelCase(name)),
|
|
108
130
|
PACKAGE_NAMESPACE: (s, name) => s.replace(/#{PACKAGE_NAMESPACE}/g, name),
|
|
109
131
|
FUNC_DESCRIPTION: (s, desc) => s.replace(/#{FUNC_DESCRIPTION}/g, descriptionToComment(desc)),
|
|
132
|
+
FUNC_JSDOC: (s, opts) => s.replace(/#{FUNC_JSDOC}/g, buildJsDoc(opts)),
|
|
110
133
|
FUNC_NAME: (s, name) => s.replace(/#{FUNC_NAME}/g, friendlyNameToName(name)),
|
|
111
134
|
FUNC_NAME_LOWERCASE: (s, name) => s.replace(/#{FUNC_NAME_LOWERCASE}/g, friendlyNameToName(name, false)),
|
|
112
135
|
PARAMS_OBJECT: (s, params) => s.replace(/#{PARAMS_OBJECT}/g, params.length ? `{ ${params.map(p => p.name).join(', ')} }` : `{}`),
|
|
@@ -219,7 +242,7 @@ function getScriptOutputType(script, comment = '#') {
|
|
|
219
242
|
}
|
|
220
243
|
;
|
|
221
244
|
function getScriptInputs(script, comment = '#') {
|
|
222
|
-
const regex = new RegExp(`${comment}\\s*input:\\s?([a-z_]+)(?:<[^>]*>)?\\s+(\\w+)(?:[^{\\n]
|
|
245
|
+
const regex = new RegExp(`${comment}\\s*input:\\s?([a-z_]+)(?:<[^>]*>)?\\s+(\\w+)(?:[^{\\n]*\\{([^}\\n]*)\\})?`, 'g');
|
|
223
246
|
const testOptional = inputAnnotation => /isOptional\s*:\s*true/.test(inputAnnotation) || /optional\s*:\s*true/.test(inputAnnotation);
|
|
224
247
|
const inputAnnotations = [...script.matchAll(regex)];
|
|
225
248
|
let firstTsValidOptionalIdx = inputAnnotations.length - 1;
|
|
@@ -235,12 +258,19 @@ function getScriptInputs(script, comment = '#') {
|
|
|
235
258
|
const nullable = /nullable\s*:\s*true/.test(match[0]);
|
|
236
259
|
const type = dgToTsTypeMap[match[1]] || 'any';
|
|
237
260
|
const name = match[2];
|
|
261
|
+
const options = {};
|
|
262
|
+
for (const part of (match[3] ?? '').split(';')) {
|
|
263
|
+
const i = part.indexOf(':');
|
|
264
|
+
if (i < 0) continue;
|
|
265
|
+
options[part.slice(0, i).trim()] = part.slice(i + 1).trim();
|
|
266
|
+
}
|
|
238
267
|
inputs.push({
|
|
239
268
|
type,
|
|
240
269
|
name,
|
|
241
270
|
isOptional,
|
|
242
271
|
undefinable,
|
|
243
|
-
nullable
|
|
272
|
+
nullable,
|
|
273
|
+
options
|
|
244
274
|
});
|
|
245
275
|
}
|
|
246
276
|
return inputs;
|
|
@@ -254,10 +284,10 @@ function getScriptDescription(script, comment = '#') {
|
|
|
254
284
|
}
|
|
255
285
|
;
|
|
256
286
|
const dgImports = exports.dgImports = `import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n`;
|
|
257
|
-
const scriptWrapperTemplate = exports.scriptWrapperTemplate = `#{
|
|
287
|
+
const scriptWrapperTemplate = exports.scriptWrapperTemplate = `#{FUNC_JSDOC}export async function #{FUNC_NAME_LOWERCASE}(#{TYPED_PARAMS}): Promise<#{OUTPUT_TYPE}> {
|
|
258
288
|
return await grok.functions.call('#{PACKAGE_NAMESPACE}:#{FUNC_NAME}', #{PARAMS_OBJECT});
|
|
259
289
|
}`;
|
|
260
|
-
const queryWrapperTemplate = exports.queryWrapperTemplate = `#{
|
|
290
|
+
const queryWrapperTemplate = exports.queryWrapperTemplate = `#{FUNC_JSDOC}export async function #{FUNC_NAME_LOWERCASE}(#{TYPED_PARAMS}): Promise<#{OUTPUT_TYPE}> {
|
|
261
291
|
return await grok.data.query('#{PACKAGE_NAMESPACE}:#{FUNC_NAME}', #{PARAMS_OBJECT});
|
|
262
292
|
}`;
|
|
263
293
|
const namespaceTemplate = exports.namespaceTemplate = `export namespace #{PACKAGE_NAMESPACE} {\n#{NAME}\n}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datagrok-tools",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.11",
|
|
4
4
|
"description": "Utility to upload and publish packages to Datagrok",
|
|
5
5
|
"homepage": "https://github.com/datagrok-ai/public/tree/master/tools#readme",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"@babel/traverse": "^7.23.7",
|
|
10
10
|
"@typescript-eslint/typescript-estree": "^8.31.1",
|
|
11
11
|
"@typescript-eslint/visitor-keys": "^8.31.1",
|
|
12
|
+
"adm-zip": "^0.5.17",
|
|
12
13
|
"archiver": "^4.0.2",
|
|
13
14
|
"archiver-promise": "^1.0.0",
|
|
14
15
|
"datagrok-api": "^1.26.0",
|
|
@@ -32,7 +33,11 @@
|
|
|
32
33
|
"prepublishOnly": "babel bin --extensions .ts -d bin",
|
|
33
34
|
"babel": "babel bin --extensions .ts -d bin",
|
|
34
35
|
"build": "babel bin --extensions .ts -d bin",
|
|
35
|
-
"debug-source-map": "babel bin --extensions .ts -d bin --source-maps true"
|
|
36
|
+
"debug-source-map": "babel bin --extensions .ts -d bin --source-maps true",
|
|
37
|
+
"test": "vitest run --project unit",
|
|
38
|
+
"test:watch": "vitest --project unit",
|
|
39
|
+
"test:integration": "vitest run --project integration",
|
|
40
|
+
"test:all": "vitest run"
|
|
36
41
|
},
|
|
37
42
|
"bin": {
|
|
38
43
|
"datagrok-upload": "./bin/_deprecated/upload.js",
|
|
@@ -66,16 +71,18 @@
|
|
|
66
71
|
"@babel/preset-env": "^7.23.8",
|
|
67
72
|
"@babel/preset-typescript": "7.15.0",
|
|
68
73
|
"@datagrok-misc/eslint-plugin-config": "^1.0.0",
|
|
74
|
+
"@types/adm-zip": "^0.5.8",
|
|
69
75
|
"@types/ignore-walk": "^4.0.3",
|
|
70
76
|
"@types/inquirer": "^8.2.10",
|
|
71
77
|
"@types/js-yaml": "^4.0.9",
|
|
72
|
-
"@types/node": "^
|
|
78
|
+
"@types/node": "^18.0.0",
|
|
73
79
|
"@types/papaparse": "^5.3.15",
|
|
74
80
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
75
81
|
"@typescript-eslint/parser": "^5.62.0",
|
|
76
82
|
"eslint": "^8.56.0",
|
|
77
83
|
"eslint-config-google": "^0.14.0",
|
|
78
84
|
"typescript": "^5.3.3",
|
|
85
|
+
"vitest": "^3.2.4",
|
|
79
86
|
"webpack": "^5.89.0",
|
|
80
87
|
"webpack-cli": "^5.1.4"
|
|
81
88
|
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {defineConfig} from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
projects: [
|
|
6
|
+
{
|
|
7
|
+
test: {
|
|
8
|
+
name: 'unit',
|
|
9
|
+
environment: 'node',
|
|
10
|
+
include: ['bin/**/*.test.ts'],
|
|
11
|
+
exclude: ['bin/**/*.integration.test.ts'],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
test: {
|
|
16
|
+
name: 'integration',
|
|
17
|
+
environment: 'node',
|
|
18
|
+
include: ['bin/**/*.integration.test.ts'],
|
|
19
|
+
testTimeout: 30_000,
|
|
20
|
+
hookTimeout: 30_000,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
});
|