datagrok-tools 5.1.2 → 5.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Datagrok-tools changelog
2
2
 
3
+ ## 5.1.3 (2026-02-03)
4
+
5
+ * GROK-19407:
6
+ * Improved developer experience for grok check, grok api, grok publish
7
+ * Fixed warnings all over the packages when using grok check
8
+
9
+ ### Bug Fixes
10
+
3
11
  ## 4.14.72 (2026-01-13)
4
12
 
5
13
  ### Bug Fixes
@@ -21,11 +21,13 @@ const funcFilePath = _path.default.join(_fs.default.existsSync(srcDir) ? srcDir
21
21
  const packagePath = _path.default.join(curDir, 'package.json');
22
22
  const names = new Set();
23
23
  let _package = {};
24
- function generateQueryWrappers() {
24
+ function generateQueryWrappers(verbose) {
25
25
  const queriesDir = _path.default.join(curDir, 'queries');
26
26
  if (!_fs.default.existsSync(queriesDir)) {
27
- color.warn(`Directory ${queriesDir} not found`);
28
- console.log('Skipping API generation for queries...');
27
+ if (verbose) {
28
+ color.warn(`Directory ${queriesDir} not found`);
29
+ console.log('Skipping API generation for queries...');
30
+ }
29
31
  return;
30
32
  }
31
33
  const files = _ignoreWalk.default.sync({
@@ -51,14 +53,16 @@ function generateQueryWrappers() {
51
53
  wrappers.push(tb.build(1));
52
54
  }
53
55
  }
54
- saveWrappersToFile('queries', wrappers);
56
+ saveWrappersToFile('queries', wrappers, verbose);
55
57
  }
56
- function generateScriptWrappers() {
58
+ function generateScriptWrappers(verbose) {
57
59
  const scriptsDir = _path.default.join(curDir, 'scripts');
58
60
  const pythonDir = _fs.default.existsSync(srcDir) ? _path.default.join(srcDir, 'python') : _path.default.join(curDir, 'python');
59
61
  if (!_fs.default.existsSync(scriptsDir)) {
60
- color.warn(`Directory ${scriptsDir} not found`);
61
- console.log('Skipping API generation for scripts...');
62
+ if (verbose) {
63
+ color.warn(`Directory ${scriptsDir} not found`);
64
+ console.log('Skipping API generation for scripts...');
65
+ }
62
66
  return;
63
67
  }
64
68
  const wrappers = [];
@@ -85,9 +89,9 @@ function generateScriptWrappers() {
85
89
  wrappers.push(tb.build(1));
86
90
  }
87
91
  }
88
- saveWrappersToFile('scripts', wrappers);
92
+ saveWrappersToFile('scripts', wrappers, verbose);
89
93
  }
90
- function generateFunctionWrappers() {
94
+ function generateFunctionWrappers(verbose) {
91
95
  let filesToParse = packageFuncDirs.map(e => _path.default.join(curDir, 'src', e)).filter(e => _fs.default.existsSync(e));
92
96
  const annotaionRegex = /(?:\/\/[^\n]*\n)+export[^{]*/g;
93
97
  const nameRegex = /\s*export(?:\sasync)?\s*function\s*([^\s(]*)/;
@@ -109,17 +113,17 @@ function generateFunctionWrappers() {
109
113
  wrappers.push(tb.build(1));
110
114
  }
111
115
  }
112
- saveWrappersToFile('funcs', wrappers);
116
+ saveWrappersToFile('funcs', wrappers, verbose);
113
117
  }
114
- function saveWrappersToFile(namespaceName, wrappers) {
118
+ function saveWrappersToFile(namespaceName, wrappers, verbose) {
115
119
  if (wrappers.length === 0) return;
116
- if (!_fs.default.existsSync(funcFilePath)) createApiFile();
120
+ if (!_fs.default.existsSync(funcFilePath)) createApiFile(verbose);
117
121
  const scriptApi = new utils.TemplateBuilder(utils.namespaceTemplate).replace('PACKAGE_NAMESPACE', namespaceName).replace('NAME', wrappers.join(sep.repeat(2)));
118
122
  _fs.default.appendFileSync(funcFilePath, sep + scriptApi.build() + sep);
119
- color.success(`Successfully generated file ${apiFile}${sep}`);
123
+ if (verbose) color.success(`Successfully generated file ${apiFile}${sep}`);
120
124
  }
121
- function createApiFile() {
122
- if (_fs.default.existsSync(funcFilePath)) {
125
+ function createApiFile(verbose) {
126
+ if (_fs.default.existsSync(funcFilePath) && verbose) {
123
127
  color.warn(`The file ${funcFilePath} already exists`);
124
128
  console.log('Rewriting its contents...');
125
129
  }
@@ -130,19 +134,20 @@ function checkNameColision(name) {
130
134
  names.add(name);
131
135
  }
132
136
  function api(args) {
137
+ const verbose = args.verbose || args.v || false;
133
138
  _package = JSON.parse(_fs.default.readFileSync(packagePath, {
134
139
  encoding: 'utf-8'
135
140
  }));
136
141
  if (_package.friendlyName) _package.friendlyName = _package.friendlyName.replaceAll(' ', '');
137
- const nOptions = Object.keys(args).length - 1;
142
+ const nOptions = Object.keys(args).length - 1 - (args.verbose ? 1 : 0) - (args.v ? 1 : 0);
138
143
  if (args['_'].length !== 1 || nOptions > 0) return false;
139
144
  if (!utils.isPackageDir(process.cwd())) {
140
145
  color.error('File `package.json` not found. Run the command from the package directory');
141
146
  return false;
142
147
  }
143
- createApiFile();
144
- generateScriptWrappers();
145
- generateQueryWrappers();
146
- generateFunctionWrappers();
148
+ createApiFile(verbose);
149
+ generateScriptWrappers(verbose);
150
+ generateQueryWrappers(verbose);
151
+ generateFunctionWrappers(verbose);
147
152
  return true;
148
153
  }
@@ -26,16 +26,17 @@ const warns = ['Latest package version', 'Datagrok API version should contain'];
26
26
  const forbiddenNames = ['function', 'class', 'export'];
27
27
  const namesInFiles = new Map();
28
28
  function check(args) {
29
+ const verbose = args.verbose || args.v || false;
29
30
  const curDir = args._.length == 2 ? args._[1] : process.cwd();
30
- if (args.recursive) return runChecksRec(curDir, args.soft ?? false);else {
31
+ if (args.recursive) return runChecksRec(curDir, args.soft ?? false, verbose);else {
31
32
  if (!utils.isPackageDir(curDir)) {
32
33
  color.error('File `package.json` not found. Run the command from the package directory');
33
34
  return false;
34
35
  }
35
- return runChecks(curDir, args.soft ?? false);
36
+ return runChecks(curDir, args.soft ?? false, false, verbose);
36
37
  }
37
38
  }
38
- function runChecks(packagePath, soft = false, noExit = false) {
39
+ function runChecks(packagePath, soft = false, noExit = false, verbose = false) {
39
40
  if (packagePath.includes(`${_path.default.sep}node_modules${_path.default.sep}`)) return true;
40
41
  const files = _ignoreWalk.default.sync({
41
42
  path: packagePath,
@@ -89,10 +90,10 @@ function runChecks(packagePath, soft = false, noExit = false) {
89
90
  if (soft || json.version.startsWith('0') || errors.every(w => warns.some(ww => w.includes(ww)))) return true;
90
91
  if (noExit) return false;else testUtils.exitWithCode(1);
91
92
  }
92
- console.log(`Checking package ${_path.default.basename(packagePath)}...\t\t\t\u2713 OK`);
93
+ if (verbose) console.log(`Checking package ${_path.default.basename(packagePath)}...\t\t\t\u2713 OK`);
93
94
  return true;
94
95
  }
95
- function runChecksRec(dir, soft = false) {
96
+ function runChecksRec(dir, soft = false, verbose = false) {
96
97
  const files = _fs.default.readdirSync(dir);
97
98
  let allPassed = true;
98
99
  for (const file of files) {
@@ -100,11 +101,11 @@ function runChecksRec(dir, soft = false) {
100
101
  const stats = _fs.default.statSync(filepath);
101
102
  if (stats.isDirectory()) {
102
103
  if (utils.isPackageDir(filepath)) {
103
- const passed = runChecks(filepath, soft, true);
104
+ const passed = runChecks(filepath, soft, true, verbose);
104
105
  allPassed = allPassed && passed;
105
106
  } else {
106
107
  if (file !== 'node_modules' && !file.startsWith('.')) {
107
- const passed = runChecksRec(_path.default.join(dir, file), soft);
108
+ const passed = runChecksRec(_path.default.join(dir, file), soft, verbose);
108
109
  allPassed = allPassed && passed;
109
110
  }
110
111
  }
@@ -492,10 +493,14 @@ function checkNpmIgnore(packagePath) {
492
493
  }
493
494
  function checkScriptNames(packagePath) {
494
495
  const warnings = [];
496
+ // Only check source code files - test data and documentation can have descriptive names with spaces
497
+ const sourceExtensions = ['.ts', '.js', '.py', '.r', '.jl', '.m', '.sql'];
495
498
  try {
496
499
  if (_fs.default.existsSync(packagePath)) {
497
500
  const filesInDirectory = getAllFilesInDirectory(packagePath);
498
501
  for (const fileName of filesInDirectory) {
502
+ const ext = _path.default.extname(fileName).toLowerCase();
503
+ if (!sourceExtensions.includes(ext)) continue;
499
504
  if (fileName.match(new RegExp('^[A-Za-z0-9._-]*$'))?.length !== 1) warnings.push(`${fileName}: file name contains inappropriate symbols`);
500
505
  }
501
506
  }
@@ -503,13 +508,14 @@ function checkScriptNames(packagePath) {
503
508
  return warnings;
504
509
  }
505
510
  function getAllFilesInDirectory(directoryPath) {
506
- const excludedFilesToCheck = ['node_modules', 'dist'];
511
+ // Exclude directories that typically contain test data, fixtures, or documentation
512
+ const excludedDirs = ['node_modules', 'dist', 'files', 'fixtures', 'data', 'templates', 'test-data', 'scenarios', 'samples', 'demo', 'docs', 'documentation'];
507
513
  let fileNames = [];
508
514
  const entries = _fs.default.readdirSync(directoryPath);
509
515
  entries.forEach(entry => {
510
516
  const entryPath = _path.default.join(directoryPath, entry);
511
517
  const stat = _fs.default.statSync(entryPath);
512
- if (stat.isFile()) fileNames.push(entry);else if (stat.isDirectory() && !excludedFilesToCheck.includes(entry)) {
518
+ if (stat.isFile()) fileNames.push(entry);else if (stat.isDirectory() && !excludedDirs.includes(entry.toLowerCase())) {
513
519
  const subDirectoryFiles = getAllFilesInDirectory(entryPath);
514
520
  fileNames = fileNames.concat(subDirectoryFiles);
515
521
  }
@@ -70,6 +70,11 @@ const HELP_API = `
70
70
  Usage: grok api
71
71
 
72
72
  Create wrapper functions for package scripts and queries
73
+
74
+ Options:
75
+ [-v | --verbose]
76
+
77
+ --verbose Print detailed output
73
78
  `;
74
79
  const HELP_CONFIG = `
75
80
  Usage: grok config
@@ -111,15 +116,15 @@ Uploads a package
111
116
  Checks for errors before publishing — the package won't be published if there are any.
112
117
 
113
118
  Options:
114
- [--all] [--refresh] [--link] [--build] [--release] [--skip-check]
119
+ [--all] [--refresh] [--link] [--build] [--release] [--skip-check] [-v | --verbose]
115
120
 
116
- --all Publish all available packages(run in packages directory)
117
- --refresh Publish all available already loaded packages(run in packages directory)
118
- --link Link the package to local packages
119
- --build Builds the package
121
+ --all Publish all available packages (run in packages directory)
122
+ --refresh Publish all available already loaded packages (run in packages directory)
123
+ --link Link the package to local packages
124
+ --build Builds the package
120
125
  --release Publish package as release version
121
- --skip-check Skip check stage
122
- --verbose Show debug information
126
+ --skip-check Skip check stage
127
+ --verbose Print detailed output
123
128
 
124
129
  Running \`grok publish\` is the same as running \`grok publish defaultHost --build --debug\`
125
130
  `;
@@ -127,10 +132,11 @@ const HELP_CHECK = `
127
132
  Usage: grok check <pluginFolder>
128
133
 
129
134
  Options:
130
- [-r | --recursive]
135
+ [-r | --recursive] [-v | --verbose]
131
136
 
132
137
  --recursive Check all packages in the current directory
133
138
  --soft Even if an error occurs, it doesn't throw an exception
139
+ --verbose Print detailed output
134
140
 
135
141
  Check package content (function signatures, import statements of external modules, etc.)
136
142
  `;
@@ -35,7 +35,7 @@ let curDir = process.cwd();
35
35
  const packDir = _path.default.join(curDir, 'package.json');
36
36
  const packageFiles = ['src/package.ts', 'src/detectors.ts', 'src/package.js', 'src/detectors.js', 'src/package-test.ts', 'src/package-test.js', 'package.js', 'detectors.js'];
37
37
  let config;
38
- async function processPackage(debug, rebuild, host, devKey, packageName, dropDb, suffix, verbose) {
38
+ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb, suffix, hostAlias, verbose = false) {
39
39
  // Get the server timestamps
40
40
  verbose = verbose || false;
41
41
  let timestamps = {};
@@ -84,9 +84,7 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
84
84
  rebuild = true;
85
85
  }
86
86
  }
87
-
88
- // let contentValidationLog = '';
89
- console.log('Starting package checks...');
87
+ if (verbose) console.log('Starting package checks...');
90
88
  const checkStart = Date.now();
91
89
  const jsTsFiles = files.filter(f => !f.startsWith('dist/') && (f.endsWith('.js') || f.endsWith('.ts')));
92
90
  const packageFilePath = _path.default.join(curDir, 'package.json');
@@ -98,20 +96,9 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
98
96
  const content = _fs.default.readFileSync(webpackConfigPath, {
99
97
  encoding: 'utf-8'
100
98
  });
101
- // const externals = extractExternals(content);
102
- // if (externals) {
103
- // const importWarnings = checkImportStatements(curDir, jsTsFiles, externals);
104
- // contentValidationLog += importWarnings.join('\n') + (importWarnings.length ? '\n' : '');
105
- // }
106
99
  }
107
100
  const funcFiles = jsTsFiles.filter(f => packageFiles.includes(f));
108
- // const funcWarnings = checkFuncSignatures(curDir, funcFiles);
109
- // contentValidationLog += funcWarnings.join('\n') + (funcWarnings.length ? '\n' : '');
110
- // const packageWarnings = checkPackageFile(curDir, json);
111
- // contentValidationLog += packageWarnings.join('\n') + (packageWarnings.length ? '\n' : '');
112
- // const changelogWarnings = checkChangelog(curDir, json);
113
- // contentValidationLog += changelogWarnings.join('\n') + '';
114
- console.log(`Checks finished in ${Date.now() - checkStart} ms`);
101
+ if (verbose) console.log(`Checks finished in ${Date.now() - checkStart} ms`);
115
102
  const reg = new RegExp(/\${(\w*)}/g);
116
103
  const errs = [];
117
104
  files.forEach(file => {
@@ -127,13 +114,10 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
127
114
  }
128
115
  if (relativePath.startsWith('upload.keys.json')) return;
129
116
  if (relativePath === 'zip') return;
130
- // if (!utils.checkScriptLocation(canonicalRelativePath)) {
131
- // contentValidationLog += `Warning: file \`${canonicalRelativePath}\`` +
132
- // ` should be in directory \`${path.basename(curDir)}/scripts/\`\n`;
133
- // }
134
117
  const t = _fs.default.statSync(fullPath).mtime.toUTCString();
135
118
  localTimestamps[canonicalRelativePath] = t;
136
119
  if (debug && timestamps[canonicalRelativePath] === t) {
120
+ if (verbose) console.log(`Skipping ${canonicalRelativePath}`);
137
121
  return;
138
122
  }
139
123
  if (canonicalRelativePath.startsWith('connections/')) {
@@ -152,11 +136,13 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
152
136
  zip.append(f, {
153
137
  name: relativePath
154
138
  });
139
+ if (verbose) console.log(`Adding ${canonicalRelativePath}...`);
155
140
  return;
156
141
  }
157
142
  zip.append(_fs.default.createReadStream(fullPath), {
158
143
  name: relativePath
159
144
  });
145
+ if (verbose) console.log(`Adding ${canonicalRelativePath}...`);
160
146
  });
161
147
  if (errs.length) {
162
148
  errs.forEach(e => color.error(e));
@@ -184,8 +170,10 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
184
170
  console.error(log['innerMessage']);
185
171
  console.log(log);
186
172
  return 1;
187
- } else console.log(log);
188
- // color.warn(contentValidationLog);
173
+ } else {
174
+ if (verbose) console.log(log);
175
+ color.success(`✓ Published to ${hostAlias || new URL(host).hostname}`);
176
+ }
189
177
  }
190
178
  } catch (error) {
191
179
  if (utils.isConnectivityError(error)) color.error(`Server is possibly offline: ${url}`);
@@ -195,8 +183,10 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
195
183
  return 0;
196
184
  }
197
185
  async function publish(args) {
186
+ const verbose = args.verbose || args.v || false;
198
187
  if (!args['skip-check'] && !args['all'] && !args['refresh']) (0, _check.check)({
199
- _: ['check']
188
+ _: ['check'],
189
+ verbose: verbose
200
190
  });
201
191
  config = _jsYaml.default.load(_fs.default.readFileSync(confPath, {
202
192
  encoding: 'utf-8'
@@ -218,27 +208,27 @@ async function publish(args) {
218
208
  packagesToLoad = (await (await (0, _nodeFetch.default)(url, {
219
209
  method: 'GET',
220
210
  headers: {
221
- 'Authorization': token // Attach cookies here
211
+ 'Authorization': token
222
212
  }
223
213
  })).json()).map(item => item.name);
224
214
  }
225
- console.log('Loading packages:');
215
+ if (verbose) console.log('Loading packages:');
226
216
  await (0, _testUtils.loadPackages)(curDir, packagesToLoad.join(' '), host, false, false, args.link, args.release);
227
217
  } else {
228
218
  if (args.link) {
229
- console.log('Linking');
219
+ if (verbose) console.log('Linking');
230
220
  await utils.runScript(`npm install`, curDir);
231
221
  await utils.runScript(`grok link`, curDir);
232
222
  await utils.runScript(`npm run build`, curDir);
233
223
  }
234
- await publishPackage(args);
224
+ await publishPackage(args, verbose);
235
225
  }
236
226
  }
237
- async function publishPackage(args) {
227
+ async function publishPackage(args, verbose) {
238
228
  const nArgs = args['_'].length;
239
229
  if (!args.link) {
240
230
  if (args.build || args.rebuild) {
241
- console.log('Building');
231
+ if (verbose) console.log('Building');
242
232
  await utils.runScript('npm install', curDir, false);
243
233
  await utils.runScript('npm run build', curDir, false);
244
234
  }
@@ -247,7 +237,7 @@ async function publishPackage(args) {
247
237
  color.error('Incompatible options: --debug and --release');
248
238
  return false;
249
239
  }
250
- console.log('Publishing...');
240
+ if (verbose) console.log('Publishing...');
251
241
  // Create `config.yaml` if it doesn't exist yet
252
242
  if (!_fs.default.existsSync(grokDir)) _fs.default.mkdirSync(grokDir);
253
243
  if (!_fs.default.existsSync(confPath)) _fs.default.writeFileSync(confPath, _jsYaml.default.dump(confTemplate));
@@ -296,12 +286,12 @@ async function publishPackage(args) {
296
286
  if (!args.suffix && stdout) args.suffix = stdout.toString().substring(0, 8);
297
287
  });
298
288
  await utils.delay(100);
299
- code = await processPackage(!args.release, Boolean(args.rebuild), url, key, packageName, args.dropDb ?? false, args.suffix, args.verbose);
289
+ code = await processPackage(!args.release, Boolean(args.rebuild), url, key, packageName, args.dropDb ?? false, args.suffix, host, verbose);
300
290
  } catch (error) {
301
291
  console.error(error);
302
292
  code = 1;
303
293
  }
304
- console.log(`Exiting with code ${code}`);
294
+ if (verbose) console.log(`Exiting with code ${code}`);
305
295
  process.exit(code);
306
296
  });
307
297
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datagrok-tools",
3
- "version": "5.1.2",
3
+ "version": "5.1.3",
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": {