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.
@@ -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
+ }
@@ -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.cacheValues = exports.absUrlRegex = exports.TemplateBuilder = void 0;
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]*{[^}\\n]*})?`, 'g');
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 = `#{FUNC_DESCRIPTION}export async function #{FUNC_NAME_LOWERCASE}(#{TYPED_PARAMS}): Promise<#{OUTPUT_TYPE}> {
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 = `#{FUNC_DESCRIPTION}export async function #{FUNC_NAME_LOWERCASE}(#{TYPED_PARAMS}): Promise<#{OUTPUT_TYPE}> {
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}`;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "#{PACKAGE_NAME_LOWERCASE}",
3
- "friendlyName": "#{PACKAGE_NAME}",
3
+ "friendlyName": "#{PACKAGE_FRIENDLY_NAME}",
4
4
  "version": "0.0.1",
5
5
  "description": "#{PACKAGE_NAME} package",
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datagrok-tools",
3
- "version": "6.1.9",
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": "^16.18.70",
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
  }
@@ -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
+ });