datagrok-tools 6.3.2 → 6.4.0
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 +11 -0
- package/bin/commands/publish.js +2 -4
- package/bin/utils/python-celery-gen.js +16 -10
- package/bin/utils/test-utils.js +13 -28
- package/eslint.config.mjs +42 -0
- package/package.json +38 -36
- package/.eslintrc.json +0 -43
- package/bin/__tests__/build.test.js +0 -116
- package/bin/__tests__/jira-wiki-converter.test.js +0 -101
- package/bin/__tests__/node-dapi.connections.test.js +0 -120
- package/bin/__tests__/node-dapi.groups.test.js +0 -467
- package/bin/__tests__/node-dapi.integration.test.js +0 -406
- package/bin/__tests__/node-dapi.shares.test.js +0 -107
- package/bin/__tests__/node-dapi.users.test.js +0 -86
- package/bin/commands/build.js +0 -209
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Datagrok-tools changelog
|
|
2
2
|
|
|
3
|
+
## 6.4.0 (2026-06-18)
|
|
4
|
+
|
|
5
|
+
* Dependencies: sanitized and updated all dependencies; `npm install` is now warning-free and `npm audit` reports 0 vulnerabilities (was 24).
|
|
6
|
+
* Dependencies: migrated linting to ESLint 9 flat config (`eslint.config.mjs` + `typescript-eslint` + `@stylistic`), dropping the archived `eslint-config-google`.
|
|
7
|
+
* Dependencies: upgraded Puppeteer to v24 and migrated to its native `page.screencast()` for `--record`, removing `puppeteer-screen-recorder` and the deprecated `fluent-ffmpeg`.
|
|
8
|
+
* Dependencies: replaced `archiver-promise` with `archiver` directly, and replaced `@babel/cli` with a small `@babel/core` build script (`build.js`) to drop deprecated transitive packages (glob@7, inflight).
|
|
9
|
+
|
|
10
|
+
## 6.3.3 (2026-06-16)
|
|
11
|
+
|
|
12
|
+
* Fixed Celery Docker image generation — the image wasn't built locally on publish.
|
|
13
|
+
|
|
3
14
|
## 6.3.2 (2026-06-15)
|
|
4
15
|
|
|
5
16
|
* `func-gen` webpack plugin — generated RichFunctionView model inputs now use the script-form names (argument bounds/step `_t0`/`_t1`/`_h`, loop count `_count`) instead of the deprefixed forms, so the run, fitting, and sensitivity-analysis paths share one set of input names with diff-grok's pipeline. Fixes `Inconsistent inputs: "_t0" is missing` when starting fitting/SA from a Rich Function View.
|
package/bin/commands/publish.js
CHANGED
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.processPackage = processPackage;
|
|
8
8
|
exports.publish = publish;
|
|
9
|
-
var
|
|
9
|
+
var _archiver = _interopRequireDefault(require("archiver"));
|
|
10
10
|
var _crypto = _interopRequireDefault(require("crypto"));
|
|
11
11
|
var _fs = _interopRequireDefault(require("fs"));
|
|
12
12
|
var _nodeFetch = _interopRequireDefault(require("node-fetch"));
|
|
@@ -22,8 +22,6 @@ var _pythonCeleryGen = require("../utils/python-celery-gen");
|
|
|
22
22
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
23
23
|
// @ts-ignore
|
|
24
24
|
|
|
25
|
-
// @ts-ignore
|
|
26
|
-
|
|
27
25
|
const {
|
|
28
26
|
exec,
|
|
29
27
|
execSync
|
|
@@ -426,7 +424,7 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
|
|
|
426
424
|
if (color.isVerbose()) console.error(error);
|
|
427
425
|
return 1;
|
|
428
426
|
}
|
|
429
|
-
const zip = (0,
|
|
427
|
+
const zip = (0, _archiver.default)('zip', {
|
|
430
428
|
store: false
|
|
431
429
|
});
|
|
432
430
|
const chunks = [];
|
|
@@ -8,6 +8,7 @@ exports.generateCeleryArtifacts = generateCeleryArtifacts;
|
|
|
8
8
|
var _fs = _interopRequireDefault(require("fs"));
|
|
9
9
|
var _path = _interopRequireDefault(require("path"));
|
|
10
10
|
var color = _interopRequireWildcard(require("./color-utils"));
|
|
11
|
+
var _utils = require("./utils");
|
|
11
12
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
12
13
|
// Header tags recognized in Python function metadata comments (ported from ScriptParser.headerTags)
|
|
13
14
|
const headerTags = ['name', 'description', 'help-url', 'input', 'output', 'tags', 'sample', 'language', 'endpoint', 'requiresServer', 'param-csrfmiddlewaretoken', 'returns', 'test', 'sidebar', 'condition', 'top-menu', 'environment', 'require', 'editor-for', 'schedule', 'schedule.runAs', 'reference', 'editor'];
|
|
@@ -191,13 +192,16 @@ function copyDirContents(src, dest) {
|
|
|
191
192
|
function useConda(dir) {
|
|
192
193
|
return _fs.default.existsSync(_path.default.join(dir, 'environment.yaml')) || _fs.default.existsSync(_path.default.join(dir, 'environment.yml'));
|
|
193
194
|
}
|
|
194
|
-
|
|
195
|
+
|
|
196
|
+
// `dockerSubfolder` is the dockerfiles/ subdirectory name; the published image is
|
|
197
|
+
// `<base>-<dockerSubfolder>` (see publish.discoverDockerfiles).
|
|
198
|
+
function deployFolder(packageDir, folderPath, dockerSubfolder, base) {
|
|
195
199
|
const tasks = scanPythonFunctions(folderPath, folderPath);
|
|
196
200
|
if (tasks.length === 0) {
|
|
197
|
-
color.log(`No annotated Python functions found in ${
|
|
201
|
+
color.log(`No annotated Python functions found in ${dockerSubfolder}`);
|
|
198
202
|
return false;
|
|
199
203
|
}
|
|
200
|
-
const dockerfilesDir = _path.default.join(packageDir, 'dockerfiles',
|
|
204
|
+
const dockerfilesDir = _path.default.join(packageDir, 'dockerfiles', dockerSubfolder);
|
|
201
205
|
_fs.default.mkdirSync(dockerfilesDir, {
|
|
202
206
|
recursive: true
|
|
203
207
|
});
|
|
@@ -211,8 +215,9 @@ function deployFolder(packageDir, folderPath, dirName) {
|
|
|
211
215
|
tasks
|
|
212
216
|
}, null, 2));
|
|
213
217
|
|
|
214
|
-
//
|
|
215
|
-
|
|
218
|
+
// Entry point file name must equal $DATAGROK_CELERY_NAME (the image name, '-' -> '_'),
|
|
219
|
+
// so `celery -A $DATAGROK_CELERY_NAME` resolves it.
|
|
220
|
+
const celeryName = `${base}-${dockerSubfolder}`.replace(/-/g, '_');
|
|
216
221
|
_fs.default.writeFileSync(_path.default.join(dockerfilesDir, celeryName + '.py'), TEMPLATE_PYTHON_ENTRY);
|
|
217
222
|
|
|
218
223
|
// Copy Python source files
|
|
@@ -222,26 +227,27 @@ function deployFolder(packageDir, folderPath, dirName) {
|
|
|
222
227
|
const containerJsonSrc = _path.default.join(folderPath, 'container.json');
|
|
223
228
|
const containerJsonDest = _path.default.join(dockerfilesDir, 'container.json');
|
|
224
229
|
if (_fs.default.existsSync(containerJsonSrc) && !_fs.default.existsSync(containerJsonDest)) _fs.default.copyFileSync(containerJsonSrc, containerJsonDest);
|
|
225
|
-
color.log(`Generated Celery Docker artifacts in dockerfiles/${
|
|
230
|
+
color.log(`Generated Celery Docker artifacts in dockerfiles/${dockerSubfolder}/`);
|
|
226
231
|
return true;
|
|
227
232
|
}
|
|
228
233
|
function generateCeleryArtifacts(packageDir) {
|
|
229
234
|
const pythonDir = _path.default.join(packageDir, 'python');
|
|
230
235
|
if (!_fs.default.existsSync(pythonDir)) return false;
|
|
236
|
+
const packageJson = JSON.parse(_fs.default.readFileSync(_path.default.join(packageDir, 'package.json'), 'utf-8'));
|
|
237
|
+
const base = (0, _utils.removeScope)(packageJson.name).toLowerCase();
|
|
231
238
|
const entries = _fs.default.readdirSync(pythonDir, {
|
|
232
239
|
withFileTypes: true
|
|
233
240
|
});
|
|
234
|
-
const isNested = entries.length > 0 && entries.every(e => e.isDirectory);
|
|
241
|
+
const isNested = entries.length > 0 && entries.every(e => e.isDirectory());
|
|
235
242
|
let generated = false;
|
|
236
243
|
if (isNested) {
|
|
237
244
|
for (const entry of entries) {
|
|
238
245
|
if (!entry.isDirectory()) continue;
|
|
239
246
|
const folderPath = _path.default.join(pythonDir, entry.name);
|
|
240
|
-
if (deployFolder(packageDir, folderPath, entry.name)) generated = true;
|
|
247
|
+
if (deployFolder(packageDir, folderPath, `${entry.name.toLowerCase()}-celery`, base)) generated = true;
|
|
241
248
|
}
|
|
242
249
|
} else {
|
|
243
|
-
|
|
244
|
-
if (deployFolder(packageDir, pythonDir, dirName)) generated = true;
|
|
250
|
+
if (deployFolder(packageDir, pythonDir, 'celery', base)) generated = true;
|
|
245
251
|
}
|
|
246
252
|
return generated;
|
|
247
253
|
}
|
package/bin/utils/test-utils.js
CHANGED
|
@@ -21,7 +21,6 @@ exports.loadPackages = loadPackages;
|
|
|
21
21
|
exports.loadTestsList = loadTestsList;
|
|
22
22
|
exports.mergeBrowsersResults = mergeBrowsersResults;
|
|
23
23
|
exports.printBrowsersResult = printBrowsersResult;
|
|
24
|
-
exports.recorderConfig = void 0;
|
|
25
24
|
exports.runBrowser = runBrowser;
|
|
26
25
|
exports.runWithTimeout = runWithTimeout;
|
|
27
26
|
exports.saveCsvResults = saveCsvResults;
|
|
@@ -32,7 +31,6 @@ var _path = _interopRequireDefault(require("path"));
|
|
|
32
31
|
var _jsYaml = _interopRequireDefault(require("js-yaml"));
|
|
33
32
|
var _utils = _interopRequireWildcard(require("../utils/utils"));
|
|
34
33
|
var utils = _utils;
|
|
35
|
-
var _puppeteerScreenRecorder = require("puppeteer-screen-recorder");
|
|
36
34
|
var _puppeteer = _interopRequireDefault(require("puppeteer"));
|
|
37
35
|
var color = _interopRequireWildcard(require("../utils/color-utils"));
|
|
38
36
|
var _papaparse = _interopRequireDefault(require("papaparse"));
|
|
@@ -43,8 +41,8 @@ const confPath = _path.default.join(grokDir, 'config.yaml');
|
|
|
43
41
|
const testCollectionTimeout = 600000;
|
|
44
42
|
const defaultLaunchParameters = exports.defaultLaunchParameters = {
|
|
45
43
|
args: ['--disable-dev-shm-usage', '--disable-features=site-per-process', '--window-size=1920,1080', '--js-flags=--expose-gc'],
|
|
46
|
-
|
|
47
|
-
headless:
|
|
44
|
+
acceptInsecureCerts: true,
|
|
45
|
+
headless: true,
|
|
48
46
|
protocolTimeout: 0
|
|
49
47
|
};
|
|
50
48
|
async function getToken(url, key) {
|
|
@@ -150,9 +148,10 @@ async function getBrowserPage(puppeteer, params = defaultLaunchParameters, urlPa
|
|
|
150
148
|
});
|
|
151
149
|
page.setDefaultNavigationTimeout(0);
|
|
152
150
|
await page.goto(`${url}/oauth/`);
|
|
153
|
-
await page.setCookie({
|
|
151
|
+
await page.browser().setCookie({
|
|
154
152
|
name: 'auth',
|
|
155
|
-
value: token
|
|
153
|
+
value: token,
|
|
154
|
+
domain: new URL(url).hostname
|
|
156
155
|
});
|
|
157
156
|
await page.evaluate(token => {
|
|
158
157
|
window.localStorage.setItem('auth', token);
|
|
@@ -201,23 +200,6 @@ function exitWithCode(code) {
|
|
|
201
200
|
console.log(`Exiting with code ${code}`);
|
|
202
201
|
process.exit(code);
|
|
203
202
|
}
|
|
204
|
-
const recorderConfig = exports.recorderConfig = {
|
|
205
|
-
followNewTab: true,
|
|
206
|
-
fps: 25,
|
|
207
|
-
ffmpeg_Path: null,
|
|
208
|
-
videoFrame: {
|
|
209
|
-
width: 1280,
|
|
210
|
-
height: 630
|
|
211
|
-
},
|
|
212
|
-
videoCrf: 18,
|
|
213
|
-
videoCodec: 'libx264',
|
|
214
|
-
videoPreset: 'ultrafast',
|
|
215
|
-
videoBitrate: 1000,
|
|
216
|
-
autopad: {
|
|
217
|
-
color: 'black'
|
|
218
|
-
}
|
|
219
|
-
// aspectRatio: '16:9',
|
|
220
|
-
};
|
|
221
203
|
async function loadPackage(packageDir, dirName, hostString, skipPublish, skipBuild, linkPackage, release) {
|
|
222
204
|
if (skipPublish != true) {
|
|
223
205
|
process.stdout.write(`Building and publishing ${dirName}...`);
|
|
@@ -274,8 +256,9 @@ async function loadTestsList(packages, core = false, record = false) {
|
|
|
274
256
|
const suffix = process.env.BACKUP_SIZE && process.env.WORKER_ID && process.env.TOTAL_WORKERS ? `_${process.env.BACKUP_SIZE}_${process.env.WORKER_ID}_${process.env.TOTAL_WORKERS}` : '';
|
|
275
257
|
const logsDir = `./load-test-console-output${suffix}.log`;
|
|
276
258
|
const recordDir = `./load-test-record${suffix}.mp4`;
|
|
277
|
-
recorder =
|
|
278
|
-
|
|
259
|
+
recorder = await page.screencast({
|
|
260
|
+
path: recordDir
|
|
261
|
+
});
|
|
279
262
|
await page.exposeFunction('addLogsToFile', addLogsToFile);
|
|
280
263
|
_fs.default.writeFileSync(logsDir, ``);
|
|
281
264
|
page.on('console', msg => {
|
|
@@ -648,13 +631,15 @@ async function runBrowser(testExecutionData, browserOptions, browsersId, testInv
|
|
|
648
631
|
page = out.page;
|
|
649
632
|
webUrl = await getWebUrlFromPage(page);
|
|
650
633
|
}
|
|
651
|
-
|
|
634
|
+
let recorder = null;
|
|
652
635
|
const currentBrowserNum = browsersId;
|
|
653
636
|
const logsDir = `./test-console-output-${currentBrowserNum}.log`;
|
|
654
637
|
const recordDir = `./test-record-${currentBrowserNum}.mp4`;
|
|
655
638
|
if (browserOptions.record && !existingBrowserSession) {
|
|
656
639
|
// Only set up recording on initial browser creation, not on retry
|
|
657
|
-
await
|
|
640
|
+
recorder = await page.screencast({
|
|
641
|
+
path: recordDir
|
|
642
|
+
});
|
|
658
643
|
await page.exposeFunction('addLogsToFile', addLogsToFile);
|
|
659
644
|
_fs.default.writeFileSync(logsDir, ``);
|
|
660
645
|
page.on('console', msg => {
|
|
@@ -866,7 +851,7 @@ async function runBrowser(testExecutionData, browserOptions, browsersId, testInv
|
|
|
866
851
|
|
|
867
852
|
// Print the final category summary
|
|
868
853
|
printFinalCategorySummary();
|
|
869
|
-
if (browserOptions.record && !existingBrowserSession) await recorder
|
|
854
|
+
if (browserOptions.record && !existingBrowserSession) await recorder?.stop();
|
|
870
855
|
if (modernOutput) {
|
|
871
856
|
testingResults.verbosePassed = '';
|
|
872
857
|
testingResults.verboseSkipped = '';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
import stylistic from '@stylistic/eslint-plugin';
|
|
4
|
+
import globals from 'globals';
|
|
5
|
+
|
|
6
|
+
// Flat config (ESLint 9). Replaces the legacy .eslintrc.json + eslint-config-google.
|
|
7
|
+
// Stylistic rules that used to live in ESLint core now come from @stylistic.
|
|
8
|
+
export default tseslint.config(
|
|
9
|
+
{
|
|
10
|
+
ignores: [
|
|
11
|
+
'bin/**/*.js',
|
|
12
|
+
'bin/**/*.js.map',
|
|
13
|
+
'node_modules/**',
|
|
14
|
+
'package-template/**',
|
|
15
|
+
'entity-template/**',
|
|
16
|
+
'script-template/**',
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
js.configs.recommended,
|
|
20
|
+
...tseslint.configs.recommended,
|
|
21
|
+
{
|
|
22
|
+
files: ['bin/**/*.ts'],
|
|
23
|
+
plugins: {'@stylistic': stylistic},
|
|
24
|
+
languageOptions: {
|
|
25
|
+
ecmaVersion: 2022,
|
|
26
|
+
sourceType: 'module',
|
|
27
|
+
globals: {...globals.browser, ...globals.node},
|
|
28
|
+
},
|
|
29
|
+
rules: {
|
|
30
|
+
'@stylistic/no-trailing-spaces': 'off',
|
|
31
|
+
'@stylistic/indent': ['error', 2],
|
|
32
|
+
'@stylistic/max-len': ['error', 140],
|
|
33
|
+
'@stylistic/padded-blocks': 'off',
|
|
34
|
+
'@stylistic/spaced-comment': 'off',
|
|
35
|
+
'@stylistic/linebreak-style': 'off',
|
|
36
|
+
'guard-for-in': 'off',
|
|
37
|
+
'curly': ['error', 'multi-or-nest'],
|
|
38
|
+
'@stylistic/brace-style': ['error', '1tbs', {allowSingleLine: true}],
|
|
39
|
+
'@stylistic/block-spacing': ['error', 'always'],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
);
|
package/package.json
CHANGED
|
@@ -1,39 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datagrok-tools",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.0",
|
|
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": {
|
|
7
|
-
"@babel/parser": "^7.
|
|
8
|
-
"@babel/runtime": "^7.
|
|
9
|
-
"@babel/traverse": "^7.
|
|
10
|
-
"@typescript-eslint/typescript-estree": "^8.
|
|
11
|
-
"@typescript-eslint/visitor-keys": "^8.
|
|
7
|
+
"@babel/parser": "^7.29.7",
|
|
8
|
+
"@babel/runtime": "^7.29.7",
|
|
9
|
+
"@babel/traverse": "^7.29.7",
|
|
10
|
+
"@typescript-eslint/typescript-estree": "^8.61.1",
|
|
11
|
+
"@typescript-eslint/visitor-keys": "^8.61.1",
|
|
12
12
|
"adm-zip": "^0.5.17",
|
|
13
|
-
"archiver": "^
|
|
14
|
-
"
|
|
15
|
-
"datagrok-api": "^1.26.0",
|
|
13
|
+
"archiver": "^7.0.1",
|
|
14
|
+
"datagrok-api": "^1.27.6",
|
|
16
15
|
"estraverse": "^5.3.0",
|
|
17
16
|
"glob": "^13.0.6",
|
|
18
|
-
"ignore-walk": "^
|
|
19
|
-
"inquirer": "^
|
|
20
|
-
"js-yaml": "^4.
|
|
17
|
+
"ignore-walk": "^9.0.0",
|
|
18
|
+
"inquirer": "^8.2.7",
|
|
19
|
+
"js-yaml": "^4.2.0",
|
|
21
20
|
"minimist": "^1.2.8",
|
|
22
21
|
"node-fetch": "^2.7.0",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"puppeteer": "22.10.0",
|
|
27
|
-
"puppeteer-screen-recorder": "3.0.3",
|
|
28
|
-
"ts-morph": "^27.0.2"
|
|
22
|
+
"papaparse": "^5.5.3",
|
|
23
|
+
"puppeteer": "^24.15.0",
|
|
24
|
+
"ts-morph": "^28.0.0"
|
|
29
25
|
},
|
|
30
26
|
"scripts": {
|
|
31
27
|
"link": "npm link",
|
|
32
|
-
"prepublishOnly": "
|
|
33
|
-
"babel": "
|
|
34
|
-
"build": "
|
|
28
|
+
"prepublishOnly": "node build.js",
|
|
29
|
+
"babel": "node build.js",
|
|
30
|
+
"build": "node build.js",
|
|
35
31
|
"update:ivp-parser": "esbuild plugins/ivp-parser.entry.mjs --bundle --format=cjs --platform=node --alias:diff-grok=../libraries/compute-utils/node_modules/diff-grok --outfile=plugins/ivp-parser.bundle.cjs",
|
|
36
|
-
"debug-source-map": "
|
|
32
|
+
"debug-source-map": "node build.js --source-maps",
|
|
37
33
|
"test": "vitest run --project unit",
|
|
38
34
|
"test:watch": "vitest --project unit",
|
|
39
35
|
"test:integration": "vitest run --project integration",
|
|
@@ -64,27 +60,33 @@
|
|
|
64
60
|
]
|
|
65
61
|
},
|
|
66
62
|
"devDependencies": {
|
|
67
|
-
"@babel/
|
|
68
|
-
"@babel/
|
|
69
|
-
"@babel/plugin-
|
|
70
|
-
"
|
|
71
|
-
"@babel/
|
|
72
|
-
"@
|
|
73
|
-
"@
|
|
74
|
-
"@datagrok-misc/eslint-plugin-config": "^1.0.0",
|
|
63
|
+
"@babel/core": "^7.29.7",
|
|
64
|
+
"@babel/plugin-proposal-decorators": "^7.29.0",
|
|
65
|
+
"@babel/plugin-transform-runtime": "^7.29.0",
|
|
66
|
+
"@babel/preset-env": "^7.29.7",
|
|
67
|
+
"@babel/preset-typescript": "^7.29.0",
|
|
68
|
+
"@eslint/js": "^9.39.0",
|
|
69
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
75
70
|
"@types/adm-zip": "^0.5.8",
|
|
71
|
+
"@types/archiver": "^6.0.3",
|
|
76
72
|
"@types/ignore-walk": "^4.0.3",
|
|
77
73
|
"@types/inquirer": "^8.2.10",
|
|
78
74
|
"@types/js-yaml": "^4.0.9",
|
|
79
|
-
"@types/node": "^
|
|
75
|
+
"@types/node": "^22.0.0",
|
|
80
76
|
"@types/papaparse": "^5.3.15",
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"eslint-config-google": "^0.14.0",
|
|
77
|
+
"esbuild": "^0.28.1",
|
|
78
|
+
"eslint": "^9.39.0",
|
|
79
|
+
"globals": "^17.6.0",
|
|
85
80
|
"typescript": "^5.3.3",
|
|
86
|
-
"
|
|
81
|
+
"typescript-eslint": "^8.61.1",
|
|
82
|
+
"vitest": "^3.2.6",
|
|
87
83
|
"webpack": "^5.89.0",
|
|
88
84
|
"webpack-cli": "^5.1.4"
|
|
85
|
+
},
|
|
86
|
+
"overrides": {
|
|
87
|
+
"esbuild": "^0.28.1",
|
|
88
|
+
"archiver-utils": {
|
|
89
|
+
"glob": "$glob"
|
|
90
|
+
}
|
|
89
91
|
}
|
|
90
92
|
}
|
package/.eslintrc.json
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"browser": true,
|
|
4
|
-
"es2022": true
|
|
5
|
-
},
|
|
6
|
-
"extends": [
|
|
7
|
-
"google"
|
|
8
|
-
],
|
|
9
|
-
"parser": "@typescript-eslint/parser",
|
|
10
|
-
"parserOptions": {
|
|
11
|
-
"ecmaVersion": 12,
|
|
12
|
-
"sourceType": "module"
|
|
13
|
-
},
|
|
14
|
-
"plugins": ["@typescript-eslint"],
|
|
15
|
-
"rules": {
|
|
16
|
-
"no-trailing-spaces": "off",
|
|
17
|
-
"indent": [
|
|
18
|
-
"error",
|
|
19
|
-
2
|
|
20
|
-
],
|
|
21
|
-
"max-len": [
|
|
22
|
-
"error",
|
|
23
|
-
140
|
|
24
|
-
],
|
|
25
|
-
"padded-blocks": "off",
|
|
26
|
-
"require-jsdoc": "off",
|
|
27
|
-
"spaced-comment": "off",
|
|
28
|
-
"linebreak-style": "off",
|
|
29
|
-
"guard-for-in": "off",
|
|
30
|
-
"curly": [
|
|
31
|
-
"error",
|
|
32
|
-
"multi-or-nest"
|
|
33
|
-
],
|
|
34
|
-
"brace-style": [
|
|
35
|
-
"error",
|
|
36
|
-
"1tbs",
|
|
37
|
-
{
|
|
38
|
-
"allowSingleLine": true
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
"block-spacing": 2
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _vitest = require("vitest");
|
|
4
|
-
var _build = require("../commands/build");
|
|
5
|
-
(0, _vitest.describe)('getNestedValue', () => {
|
|
6
|
-
(0, _vitest.it)('returns value for a simple key', () => {
|
|
7
|
-
(0, _vitest.expect)((0, _build.getNestedValue)({
|
|
8
|
-
name: 'Chem'
|
|
9
|
-
}, 'name')).toBe('Chem');
|
|
10
|
-
});
|
|
11
|
-
(0, _vitest.it)('returns value for a nested path', () => {
|
|
12
|
-
(0, _vitest.expect)((0, _build.getNestedValue)({
|
|
13
|
-
a: {
|
|
14
|
-
b: {
|
|
15
|
-
c: 42
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}, 'a.b.c')).toBe(42);
|
|
19
|
-
});
|
|
20
|
-
(0, _vitest.it)('returns undefined for a missing key', () => {
|
|
21
|
-
(0, _vitest.expect)((0, _build.getNestedValue)({
|
|
22
|
-
name: 'Chem'
|
|
23
|
-
}, 'version')).toBeUndefined();
|
|
24
|
-
});
|
|
25
|
-
(0, _vitest.it)('returns undefined when a mid-path segment is null', () => {
|
|
26
|
-
(0, _vitest.expect)((0, _build.getNestedValue)({
|
|
27
|
-
a: null
|
|
28
|
-
}, 'a.b')).toBeUndefined();
|
|
29
|
-
});
|
|
30
|
-
(0, _vitest.it)('returns undefined when a mid-path segment is missing', () => {
|
|
31
|
-
(0, _vitest.expect)((0, _build.getNestedValue)({
|
|
32
|
-
a: {}
|
|
33
|
-
}, 'a.b.c')).toBeUndefined();
|
|
34
|
-
});
|
|
35
|
-
(0, _vitest.it)('returns undefined for an empty path (splits to empty string key)', () => {
|
|
36
|
-
(0, _vitest.expect)((0, _build.getNestedValue)({
|
|
37
|
-
x: 1
|
|
38
|
-
}, '')).toBeUndefined();
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
const pkg = overrides => ({
|
|
42
|
-
dir: '/tmp/pkg',
|
|
43
|
-
name: overrides.name ?? 'test-pkg',
|
|
44
|
-
friendlyName: overrides.friendlyName ?? overrides.name ?? 'Test Pkg',
|
|
45
|
-
version: overrides.version ?? '1.0.0',
|
|
46
|
-
packageJson: overrides
|
|
47
|
-
});
|
|
48
|
-
(0, _vitest.describe)('applyFilter', () => {
|
|
49
|
-
const packages = [pkg({
|
|
50
|
-
name: 'Chem',
|
|
51
|
-
version: '1.5.0',
|
|
52
|
-
category: 'Cheminformatics'
|
|
53
|
-
}), pkg({
|
|
54
|
-
name: 'Bio',
|
|
55
|
-
version: '2.0.0',
|
|
56
|
-
category: 'Bioinformatics'
|
|
57
|
-
}), pkg({
|
|
58
|
-
name: 'PowerGrid',
|
|
59
|
-
version: '1.5.0',
|
|
60
|
-
category: 'Viewers'
|
|
61
|
-
})];
|
|
62
|
-
(0, _vitest.it)('returns all packages when filter matches all', () => {
|
|
63
|
-
(0, _vitest.expect)((0, _build.applyFilter)(packages, 'name:.')).toHaveLength(3);
|
|
64
|
-
});
|
|
65
|
-
(0, _vitest.it)('filters by exact name match', () => {
|
|
66
|
-
const result = (0, _build.applyFilter)(packages, 'name:^Chem$');
|
|
67
|
-
(0, _vitest.expect)(result).toHaveLength(1);
|
|
68
|
-
(0, _vitest.expect)(result[0].name).toBe('Chem');
|
|
69
|
-
});
|
|
70
|
-
(0, _vitest.it)('filters by partial name (regex substring)', () => {
|
|
71
|
-
const result = (0, _build.applyFilter)(packages, 'name:Bio');
|
|
72
|
-
(0, _vitest.expect)(result).toHaveLength(1);
|
|
73
|
-
(0, _vitest.expect)(result[0].name).toBe('Bio');
|
|
74
|
-
});
|
|
75
|
-
(0, _vitest.it)('returns empty array when nothing matches', () => {
|
|
76
|
-
(0, _vitest.expect)((0, _build.applyFilter)(packages, 'name:NOMATCH')).toHaveLength(0);
|
|
77
|
-
});
|
|
78
|
-
(0, _vitest.it)('filters by version', () => {
|
|
79
|
-
const result = (0, _build.applyFilter)(packages, 'version:^1\\.5');
|
|
80
|
-
(0, _vitest.expect)(result).toHaveLength(2);
|
|
81
|
-
(0, _vitest.expect)(result.map(p => p.name)).toEqual(_vitest.expect.arrayContaining(['Chem', 'PowerGrid']));
|
|
82
|
-
});
|
|
83
|
-
(0, _vitest.it)('applies && conjunction (both conditions must match)', () => {
|
|
84
|
-
const result = (0, _build.applyFilter)(packages, 'name:Chem && version:1\\.5');
|
|
85
|
-
(0, _vitest.expect)(result).toHaveLength(1);
|
|
86
|
-
(0, _vitest.expect)(result[0].name).toBe('Chem');
|
|
87
|
-
});
|
|
88
|
-
(0, _vitest.it)('returns empty when one part of && conjunction fails', () => {
|
|
89
|
-
(0, _vitest.expect)((0, _build.applyFilter)(packages, 'name:Chem && version:^2')).toHaveLength(0);
|
|
90
|
-
});
|
|
91
|
-
(0, _vitest.it)('filters by nested field', () => {
|
|
92
|
-
const withNested = [pkg({
|
|
93
|
-
name: 'A',
|
|
94
|
-
datagrok: {
|
|
95
|
-
apiVersion: '1.0'
|
|
96
|
-
}
|
|
97
|
-
}), pkg({
|
|
98
|
-
name: 'B',
|
|
99
|
-
datagrok: {
|
|
100
|
-
apiVersion: '2.0'
|
|
101
|
-
}
|
|
102
|
-
})];
|
|
103
|
-
const result = (0, _build.applyFilter)(withNested, 'datagrok.apiVersion:^1');
|
|
104
|
-
(0, _vitest.expect)(result).toHaveLength(1);
|
|
105
|
-
(0, _vitest.expect)(result[0].name).toBe('A');
|
|
106
|
-
});
|
|
107
|
-
(0, _vitest.it)('returns empty when field does not exist', () => {
|
|
108
|
-
(0, _vitest.expect)((0, _build.applyFilter)(packages, 'nonexistent:anything')).toHaveLength(0);
|
|
109
|
-
});
|
|
110
|
-
(0, _vitest.it)('treats filter with no colon as field name with match-all pattern', () => {
|
|
111
|
-
// No colon → field = whole string, pattern = /./ (matches any value)
|
|
112
|
-
// The function returns packages where the field exists and is non-empty
|
|
113
|
-
const result = (0, _build.applyFilter)(packages, 'name');
|
|
114
|
-
(0, _vitest.expect)(result).toHaveLength(3);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _vitest = require("vitest");
|
|
4
|
-
var _report = require("../commands/report");
|
|
5
|
-
(0, _vitest.describe)('markdownToJiraWiki — basic rules', () => {
|
|
6
|
-
(0, _vitest.it)('converts H1', () => {
|
|
7
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('# Title')).toBe('h1. Title');
|
|
8
|
-
});
|
|
9
|
-
(0, _vitest.it)('converts H2 / H3 / H6', () => {
|
|
10
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('## Sub')).toBe('h2. Sub');
|
|
11
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('### Sub-sub')).toBe('h3. Sub-sub');
|
|
12
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('###### Deep')).toBe('h6. Deep');
|
|
13
|
-
});
|
|
14
|
-
(0, _vitest.it)('converts bold', () => {
|
|
15
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('hello **world** foo')).toBe('hello *world* foo');
|
|
16
|
-
});
|
|
17
|
-
(0, _vitest.it)('converts italic with single asterisks', () => {
|
|
18
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('hello *world* foo')).toBe('hello _world_ foo');
|
|
19
|
-
});
|
|
20
|
-
(0, _vitest.it)('converts strikethrough', () => {
|
|
21
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('~~gone~~')).toBe('-gone-');
|
|
22
|
-
});
|
|
23
|
-
(0, _vitest.it)('converts links', () => {
|
|
24
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('see [docs](https://x.example/y)')).toBe('see [docs|https://x.example/y]');
|
|
25
|
-
});
|
|
26
|
-
(0, _vitest.it)('converts blockquote', () => {
|
|
27
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('> quoted line')).toBe('bq. quoted line');
|
|
28
|
-
});
|
|
29
|
-
(0, _vitest.it)('converts unordered list', () => {
|
|
30
|
-
const md = '- one\n- two\n- three';
|
|
31
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)(md)).toBe('* one\n* two\n* three');
|
|
32
|
-
});
|
|
33
|
-
(0, _vitest.it)('converts one level of nested unordered list', () => {
|
|
34
|
-
const md = '- top\n - sub\n- back';
|
|
35
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)(md)).toBe('* top\n** sub\n* back');
|
|
36
|
-
});
|
|
37
|
-
(0, _vitest.it)('converts ordered list', () => {
|
|
38
|
-
const md = '1. one\n2. two\n3. three';
|
|
39
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)(md)).toBe('# one\n# two\n# three');
|
|
40
|
-
});
|
|
41
|
-
(0, _vitest.it)('converts inline code', () => {
|
|
42
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('use `foo()` here')).toBe('use {{foo()}} here');
|
|
43
|
-
});
|
|
44
|
-
(0, _vitest.it)('converts plain code fence to noformat', () => {
|
|
45
|
-
const md = '```\nraw code\nmore\n```';
|
|
46
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)(md)).toBe('{noformat}\nraw code\nmore\n{noformat}');
|
|
47
|
-
});
|
|
48
|
-
(0, _vitest.it)('converts code fence with language tag to {code:lang}', () => {
|
|
49
|
-
const md = '```js\nconst x = 1;\n```';
|
|
50
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)(md)).toBe('{code:js}\nconst x = 1;\n{code}');
|
|
51
|
-
});
|
|
52
|
-
(0, _vitest.it)('converts HTML entities / & / < / >', () => {
|
|
53
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('a b')).toBe('a b');
|
|
54
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('a&b')).toBe('a&b');
|
|
55
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('a<b>c')).toBe('a<b>c');
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
(0, _vitest.describe)('markdownToJiraWiki — content-protection inside code fences', () => {
|
|
59
|
-
(0, _vitest.it)('does not transform `{{plates}}` inside a fenced block (run-#4 false-positive case)', () => {
|
|
60
|
-
const md = ['Before', '```', 'context: {{plates}} should stay literal', '# not a heading', '- not a list', '```', 'After'].join('\n');
|
|
61
|
-
const out = (0, _report.markdownToJiraWiki)(md);
|
|
62
|
-
(0, _vitest.expect)(out).toContain('{noformat}\ncontext: {{plates}} should stay literal');
|
|
63
|
-
(0, _vitest.expect)(out).toContain('# not a heading');
|
|
64
|
-
(0, _vitest.expect)(out).toContain('- not a list');
|
|
65
|
-
(0, _vitest.expect)(out).not.toContain('h1.');
|
|
66
|
-
});
|
|
67
|
-
(0, _vitest.it)('does not transform headings/links/lists inside an inline code span', () => {
|
|
68
|
-
const md = 'use `# not a heading` and `[ref](u)` here';
|
|
69
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)(md)).toBe('use {{# not a heading}} and {{[ref](u)}} here');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
(0, _vitest.describe)('markdownToJiraWiki — edge cases', () => {
|
|
73
|
-
(0, _vitest.it)('handles bold containing italic: **bold *inside* bold**', () => {
|
|
74
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('**bold *inside* bold**')).toBe('*bold _inside_ bold*');
|
|
75
|
-
});
|
|
76
|
-
(0, _vitest.it)('preserves bold and italic on the same line', () => {
|
|
77
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('**a** and *b*')).toBe('*a* and _b_');
|
|
78
|
-
});
|
|
79
|
-
(0, _vitest.it)('handles a heading whose text contains backticks', () => {
|
|
80
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('## use `foo()` for x')).toBe('h2. use {{foo()}} for x');
|
|
81
|
-
});
|
|
82
|
-
(0, _vitest.it)('passes plain text through unchanged', () => {
|
|
83
|
-
const plain = 'Just a normal sentence with no markdown.';
|
|
84
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)(plain)).toBe(plain);
|
|
85
|
-
});
|
|
86
|
-
(0, _vitest.it)('returns empty string unchanged', () => {
|
|
87
|
-
(0, _vitest.expect)((0, _report.markdownToJiraWiki)('')).toBe('');
|
|
88
|
-
});
|
|
89
|
-
(0, _vitest.it)('handles a multi-block document end-to-end', () => {
|
|
90
|
-
const md = ['# Handoff', '', 'Some **bold** intro and a [link](https://x.example).', '', '## Findings', '', '- first', '- second', '', '> note: this matters', '', '```js', 'const x = 1;', '```', '', 'Done here.'].join('\n');
|
|
91
|
-
const out = (0, _report.markdownToJiraWiki)(md);
|
|
92
|
-
(0, _vitest.expect)(out).toContain('h1. Handoff');
|
|
93
|
-
(0, _vitest.expect)(out).toContain('h2. Findings');
|
|
94
|
-
(0, _vitest.expect)(out).toContain('Some *bold* intro and a [link|https://x.example].');
|
|
95
|
-
(0, _vitest.expect)(out).toContain('* first\n* second');
|
|
96
|
-
(0, _vitest.expect)(out).toContain('bq. note: this matters');
|
|
97
|
-
(0, _vitest.expect)(out).toContain('{code:js}\nconst x = 1;\n{code}');
|
|
98
|
-
(0, _vitest.expect)(out).toContain('Done here.');
|
|
99
|
-
(0, _vitest.expect)(out).not.toContain(' ');
|
|
100
|
-
});
|
|
101
|
-
});
|