@tenonhq/sincronia-core 0.0.71 → 0.0.73
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/dist/allScopesCommands.js +4 -4
- package/dist/appUtils.js +23 -35
- package/dist/commander.js +18 -1
- package/dist/constants.js +6 -1
- package/dist/dashboardCommand.js +3 -3
- package/dist/genericUtils.js +44 -0
- package/dist/initSystem/discovery.js +10 -1
- package/dist/tests/discovery.test.js +11 -0
- package/package.json +1 -1
|
@@ -358,7 +358,7 @@ async function watchAllScopesCommand(args) {
|
|
|
358
358
|
}
|
|
359
359
|
// Start dashboard unless --no-dashboard flag is set
|
|
360
360
|
if (!args.noDashboard) {
|
|
361
|
-
dashboardProcess = startDashboardProcess();
|
|
361
|
+
dashboardProcess = startDashboardProcess(args.port);
|
|
362
362
|
}
|
|
363
363
|
// Import and start the multi-scope watcher
|
|
364
364
|
const { startMultiScopeWatching } = await Promise.resolve().then(() => __importStar(require("./MultiScopeWatcher")));
|
|
@@ -383,7 +383,7 @@ async function watchAllScopesCommand(args) {
|
|
|
383
383
|
throw error;
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
|
-
function startDashboardProcess() {
|
|
386
|
+
function startDashboardProcess(portOverride) {
|
|
387
387
|
var serverPath;
|
|
388
388
|
try {
|
|
389
389
|
serverPath = require.resolve("@tenonhq/sincronia-dashboard/server.js");
|
|
@@ -392,11 +392,11 @@ function startDashboardProcess() {
|
|
|
392
392
|
Logger_1.logger.warn("Dashboard package not installed. Run: npm install @tenonhq/sincronia-dashboard");
|
|
393
393
|
return null;
|
|
394
394
|
}
|
|
395
|
-
var port = process.env.DASHBOARD_PORT || "3456";
|
|
395
|
+
var port = portOverride ? String(portOverride) : (process.env.DASHBOARD_PORT || "3456");
|
|
396
396
|
var server = (0, child_process_1.spawn)("node", [serverPath], {
|
|
397
397
|
cwd: process.cwd(),
|
|
398
398
|
stdio: "ignore",
|
|
399
|
-
env: { ...process.env },
|
|
399
|
+
env: { ...process.env, DASHBOARD_PORT: port },
|
|
400
400
|
detached: false,
|
|
401
401
|
});
|
|
402
402
|
server.on("error", function (err) {
|
package/dist/appUtils.js
CHANGED
|
@@ -72,10 +72,7 @@ const processFilesInManRec = async (recPath, rec, forceWrite) => {
|
|
|
72
72
|
}, null, 2)
|
|
73
73
|
};
|
|
74
74
|
await fileWrite(metadataFile, recPath);
|
|
75
|
-
const
|
|
76
|
-
return fileWrite(file, recPath);
|
|
77
|
-
});
|
|
78
|
-
const writeResults = await Promise.allSettled(regularPromises);
|
|
75
|
+
const writeResults = await (0, genericUtils_1.allSettledBatched)(rec.files, constants_1.CONCURRENCY_FILES, function (file) { return fileWrite(file, recPath); });
|
|
79
76
|
const writeFailures = writeResults.filter((r) => r.status === "rejected");
|
|
80
77
|
if (writeFailures.length > 0) {
|
|
81
78
|
writeFailures.forEach((f) => {
|
|
@@ -97,16 +94,12 @@ const processRecsInManTable = async (tablePath, table, forceWrite, onRecordProce
|
|
|
97
94
|
.map(recKeyToPath)
|
|
98
95
|
.map(fUtils.createDirRecursively);
|
|
99
96
|
await Promise.all(recPathPromises);
|
|
100
|
-
|
|
101
|
-
return [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}),
|
|
107
|
-
];
|
|
108
|
-
}, []);
|
|
109
|
-
return Promise.all(filePromises);
|
|
97
|
+
await (0, genericUtils_1.processBatched)(recKeys, constants_1.CONCURRENCY_RECORDS, function (recKey) {
|
|
98
|
+
return processFilesInManRec(recKeyToPath(recKey), records[recKey], forceWrite).then(function () {
|
|
99
|
+
if (onRecordProcessed)
|
|
100
|
+
onRecordProcessed();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
110
103
|
};
|
|
111
104
|
const countRecordsInTables = (tables) => {
|
|
112
105
|
return Object.keys(tables).reduce(function (sum, tableName) {
|
|
@@ -116,10 +109,9 @@ const countRecordsInTables = (tables) => {
|
|
|
116
109
|
const processTablesInManifest = async (tables, forceWrite, sourcePath, onRecordProcessed) => {
|
|
117
110
|
var basePath = sourcePath || ConfigManager.getSourcePath();
|
|
118
111
|
const tableNames = Object.keys(tables);
|
|
119
|
-
|
|
112
|
+
await (0, genericUtils_1.processBatched)(tableNames, constants_1.CONCURRENCY_TABLES, function (tableName) {
|
|
120
113
|
return processRecsInManTable(path_1.default.join(basePath, tableName), tables[tableName], forceWrite, onRecordProcessed);
|
|
121
114
|
});
|
|
122
|
-
await Promise.all(tablePromises);
|
|
123
115
|
};
|
|
124
116
|
const processManifest = async (manifest, forceWrite = false, sourcePath) => {
|
|
125
117
|
const tableCount = Object.keys(manifest.tables).length;
|
|
@@ -367,7 +359,7 @@ const pushFiles = async (recs) => {
|
|
|
367
359
|
Logger_1.logger.info(`Update set routing active: ${activeScopes}`);
|
|
368
360
|
}
|
|
369
361
|
const tick = getProgTick(Logger_1.logger.getLogLevel(), recs.length * 2) || (() => { });
|
|
370
|
-
const
|
|
362
|
+
const results = await (0, genericUtils_1.allSettledBatched)(recs, constants_1.CONCURRENCY_PUSH, async function (rec) {
|
|
371
363
|
const fieldNames = Object.keys(rec.fields);
|
|
372
364
|
const firstField = rec.fields[fieldNames[0]];
|
|
373
365
|
const recSummary = (0, exports.summarizeRecord)(rec.table, firstField.name);
|
|
@@ -382,8 +374,7 @@ const pushFiles = async (recs) => {
|
|
|
382
374
|
tick();
|
|
383
375
|
return pushRes;
|
|
384
376
|
});
|
|
385
|
-
|
|
386
|
-
return results.map((result) => {
|
|
377
|
+
return results.map(function (result) {
|
|
387
378
|
if (result.status === "fulfilled") {
|
|
388
379
|
return result.value;
|
|
389
380
|
}
|
|
@@ -431,20 +422,18 @@ const writeBuildFile = async (preBuild, buildRes, summary) => {
|
|
|
431
422
|
const sourcePath = ConfigManager.getSourcePath();
|
|
432
423
|
const buildPath = ConfigManager.getBuildPath();
|
|
433
424
|
const fieldNames = Object.keys(fields);
|
|
434
|
-
const writePromises = fieldNames.map(async (field) => {
|
|
435
|
-
const fieldCtx = fields[field];
|
|
436
|
-
const srcFilePath = fieldCtx.filePath;
|
|
437
|
-
const relativePath = path_1.default.relative(sourcePath, srcFilePath);
|
|
438
|
-
const relPathNoExt = relativePath.split(".").slice(0, -1).join();
|
|
439
|
-
const buildExt = fUtils.getBuildExt(fieldCtx.tableName, fieldCtx.name, fieldCtx.targetField);
|
|
440
|
-
const relPathNewExt = `${relPathNoExt}.${buildExt}`;
|
|
441
|
-
const buildFilePath = path_1.default.join(buildPath, relPathNewExt);
|
|
442
|
-
await fUtils.createDirRecursively(path_1.default.dirname(buildFilePath));
|
|
443
|
-
const writeResult = await fUtils.writeFileForce(buildFilePath, buildRes.builtRec[fieldCtx.targetField]);
|
|
444
|
-
return writeResult;
|
|
445
|
-
});
|
|
446
425
|
try {
|
|
447
|
-
await
|
|
426
|
+
await (0, genericUtils_1.processBatched)(fieldNames, constants_1.CONCURRENCY_FILES, async function (field) {
|
|
427
|
+
const fieldCtx = fields[field];
|
|
428
|
+
const srcFilePath = fieldCtx.filePath;
|
|
429
|
+
const relativePath = path_1.default.relative(sourcePath, srcFilePath);
|
|
430
|
+
const relPathNoExt = relativePath.split(".").slice(0, -1).join();
|
|
431
|
+
const buildExt = fUtils.getBuildExt(fieldCtx.tableName, fieldCtx.name, fieldCtx.targetField);
|
|
432
|
+
const relPathNewExt = `${relPathNoExt}.${buildExt}`;
|
|
433
|
+
const buildFilePath = path_1.default.join(buildPath, relPathNewExt);
|
|
434
|
+
await fUtils.createDirRecursively(path_1.default.dirname(buildFilePath));
|
|
435
|
+
await fUtils.writeFileForce(buildFilePath, buildRes.builtRec[fieldCtx.targetField]);
|
|
436
|
+
});
|
|
448
437
|
return { success: true, message: `${recSummary} built successfully` };
|
|
449
438
|
}
|
|
450
439
|
catch (e) {
|
|
@@ -456,7 +445,7 @@ const writeBuildFile = async (preBuild, buildRes, summary) => {
|
|
|
456
445
|
};
|
|
457
446
|
const buildFiles = async (fileList) => {
|
|
458
447
|
const tick = getProgTick(Logger_1.logger.getLogLevel(), fileList.length * 2) || (() => { });
|
|
459
|
-
const
|
|
448
|
+
const results = await (0, genericUtils_1.allSettledBatched)(fileList, constants_1.CONCURRENCY_BUILD, async function (rec) {
|
|
460
449
|
const { fields, table } = rec;
|
|
461
450
|
const fieldNames = Object.keys(fields);
|
|
462
451
|
const recSummary = (0, exports.summarizeRecord)(table, fields[fieldNames[0]].name);
|
|
@@ -471,8 +460,7 @@ const buildFiles = async (fileList) => {
|
|
|
471
460
|
tick();
|
|
472
461
|
return writeRes;
|
|
473
462
|
});
|
|
474
|
-
|
|
475
|
-
return results.map((result) => {
|
|
463
|
+
return results.map(function (result) {
|
|
476
464
|
if (result.status === "fulfilled") {
|
|
477
465
|
return result.value;
|
|
478
466
|
}
|
package/dist/commander.js
CHANGED
|
@@ -30,6 +30,11 @@ async function initCommands() {
|
|
|
30
30
|
default: false,
|
|
31
31
|
describe: "Skip launching the dashboard web UI",
|
|
32
32
|
},
|
|
33
|
+
port: {
|
|
34
|
+
alias: "p",
|
|
35
|
+
type: "number",
|
|
36
|
+
describe: "Dashboard port (default: DASHBOARD_PORT env or 3456)",
|
|
37
|
+
},
|
|
33
38
|
});
|
|
34
39
|
return cmdArgs;
|
|
35
40
|
}, async (args) => {
|
|
@@ -286,7 +291,19 @@ async function initCommands() {
|
|
|
286
291
|
});
|
|
287
292
|
return cmdArgs;
|
|
288
293
|
}, updateSetCommands_1.showCurrentScopeCommand)
|
|
289
|
-
.command("dashboard", "Launch the Update Set Dashboard web UI",
|
|
294
|
+
.command("dashboard", "Launch the Update Set Dashboard web UI", (cmdArgs) => {
|
|
295
|
+
cmdArgs.options({
|
|
296
|
+
...sharedOptions,
|
|
297
|
+
port: {
|
|
298
|
+
alias: "p",
|
|
299
|
+
type: "number",
|
|
300
|
+
describe: "Dashboard port (default: DASHBOARD_PORT env or 3456)",
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
return cmdArgs;
|
|
304
|
+
}, async (args) => {
|
|
305
|
+
await (0, dashboardCommand_1.dashboardCommand)(args);
|
|
306
|
+
})
|
|
290
307
|
.command("schema <subcommand>", "Manage ServiceNow table schemas (subcommands: pull)", (cmdArgs) => {
|
|
291
308
|
cmdArgs.positional("subcommand", {
|
|
292
309
|
describe: "Schema subcommand to run",
|
package/dist/constants.js
CHANGED
|
@@ -3,8 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.PUSH_RETRY_LIMIT = exports.PUSH_RETRY_WAIT = exports.PATH_DELIMITER = void 0;
|
|
6
|
+
exports.CONCURRENCY_BUILD = exports.CONCURRENCY_PUSH = exports.CONCURRENCY_FILES = exports.CONCURRENCY_RECORDS = exports.CONCURRENCY_TABLES = exports.PUSH_RETRY_LIMIT = exports.PUSH_RETRY_WAIT = exports.PATH_DELIMITER = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
exports.PATH_DELIMITER = `${path_1.default.delimiter}${path_1.default.delimiter}`;
|
|
9
9
|
exports.PUSH_RETRY_WAIT = 3000;
|
|
10
10
|
exports.PUSH_RETRY_LIMIT = 3;
|
|
11
|
+
exports.CONCURRENCY_TABLES = 2;
|
|
12
|
+
exports.CONCURRENCY_RECORDS = 5;
|
|
13
|
+
exports.CONCURRENCY_FILES = 10;
|
|
14
|
+
exports.CONCURRENCY_PUSH = 3;
|
|
15
|
+
exports.CONCURRENCY_BUILD = 5;
|
package/dist/dashboardCommand.js
CHANGED
|
@@ -13,16 +13,16 @@ async function dashboardCommand(args) {
|
|
|
13
13
|
catch (e) {
|
|
14
14
|
throw new Error("Dashboard package not installed. Run: npm install @tenonhq/sincronia-dashboard");
|
|
15
15
|
}
|
|
16
|
+
var port = args.port ? String(args.port) : (process.env.DASHBOARD_PORT || "3456");
|
|
16
17
|
Logger_1.logger.info("Starting Update Set Dashboard...");
|
|
17
18
|
const server = (0, child_process_1.spawn)("node", [serverPath], {
|
|
18
19
|
cwd: process.cwd(),
|
|
19
20
|
stdio: "inherit",
|
|
20
|
-
env: { ...process.env },
|
|
21
|
+
env: { ...process.env, DASHBOARD_PORT: port },
|
|
21
22
|
});
|
|
22
23
|
// Open browser after a short delay
|
|
23
24
|
setTimeout(() => {
|
|
24
|
-
const
|
|
25
|
-
const url = `http://localhost:${port}`;
|
|
25
|
+
const url = "http://localhost:" + port;
|
|
26
26
|
(0, child_process_1.spawn)("open", [url]);
|
|
27
27
|
}, 1000);
|
|
28
28
|
server.on("close", (code) => {
|
package/dist/genericUtils.js
CHANGED
|
@@ -41,6 +41,8 @@ exports.parseFileNameParams = parseFileNameParams;
|
|
|
41
41
|
exports.getParsedFilesPayload = getParsedFilesPayload;
|
|
42
42
|
exports.wait = wait;
|
|
43
43
|
exports.chunkArr = chunkArr;
|
|
44
|
+
exports.processBatched = processBatched;
|
|
45
|
+
exports.allSettledBatched = allSettledBatched;
|
|
44
46
|
const path_1 = __importDefault(require("path"));
|
|
45
47
|
const ConfigManager = __importStar(require("./config"));
|
|
46
48
|
async function _getConfigFromPath(params) {
|
|
@@ -125,6 +127,48 @@ function chunkArr(arr, chunkSize) {
|
|
|
125
127
|
}
|
|
126
128
|
return chunks;
|
|
127
129
|
}
|
|
130
|
+
async function processBatched(items, concurrency, fn) {
|
|
131
|
+
var results = new Array(items.length);
|
|
132
|
+
var index = 0;
|
|
133
|
+
async function runNext() {
|
|
134
|
+
while (index < items.length) {
|
|
135
|
+
var currentIndex = index;
|
|
136
|
+
index++;
|
|
137
|
+
results[currentIndex] = await fn(items[currentIndex]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
var workers = [];
|
|
141
|
+
var workerCount = Math.min(concurrency, items.length);
|
|
142
|
+
for (var i = 0; i < workerCount; i++) {
|
|
143
|
+
workers.push(runNext());
|
|
144
|
+
}
|
|
145
|
+
await Promise.all(workers);
|
|
146
|
+
return results;
|
|
147
|
+
}
|
|
148
|
+
async function allSettledBatched(items, concurrency, fn) {
|
|
149
|
+
var results = new Array(items.length);
|
|
150
|
+
var index = 0;
|
|
151
|
+
async function runNext() {
|
|
152
|
+
while (index < items.length) {
|
|
153
|
+
var currentIndex = index;
|
|
154
|
+
index++;
|
|
155
|
+
try {
|
|
156
|
+
var value = await fn(items[currentIndex]);
|
|
157
|
+
results[currentIndex] = { status: "fulfilled", value: value };
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
results[currentIndex] = { status: "rejected", reason: e };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
var workers = [];
|
|
165
|
+
var workerCount = Math.min(concurrency, items.length);
|
|
166
|
+
for (var i = 0; i < workerCount; i++) {
|
|
167
|
+
workers.push(runNext());
|
|
168
|
+
}
|
|
169
|
+
await Promise.all(workers);
|
|
170
|
+
return results;
|
|
171
|
+
}
|
|
128
172
|
const allSettled = (promises) => {
|
|
129
173
|
return Promise.all(promises.map((prom) => prom
|
|
130
174
|
.then((value) => ({
|
|
@@ -37,7 +37,16 @@ exports.discoverPlugins = discoverPlugins;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const Logger_1 = require("../Logger");
|
|
40
|
-
|
|
40
|
+
// Skip packages that are not init plugins:
|
|
41
|
+
// - core/types: the discovery system itself
|
|
42
|
+
// - dashboard: starts Express server on require (side effect)
|
|
43
|
+
// - schema: library imported directly by schemaCommand, not a plugin
|
|
44
|
+
const SKIP_PACKAGES = new Set([
|
|
45
|
+
"sincronia-core",
|
|
46
|
+
"sincronia-types",
|
|
47
|
+
"sincronia-dashboard",
|
|
48
|
+
"sincronia-schema",
|
|
49
|
+
]);
|
|
41
50
|
const MAX_PARENT_DEPTH = 3;
|
|
42
51
|
/**
|
|
43
52
|
* @description Scans node_modules for @tenonhq/sincronia-* packages that export a sincPlugin.
|
|
@@ -53,4 +53,15 @@ describe("discoverPlugins", function () {
|
|
|
53
53
|
const names = plugins.map(function (p) { return p.name; });
|
|
54
54
|
expect(names).not.toContain("sass-plugin");
|
|
55
55
|
});
|
|
56
|
+
it("skips sincronia-dashboard and sincronia-schema", function () {
|
|
57
|
+
Logger_1.logger.warn.mockClear();
|
|
58
|
+
mockReaddirSync.mockReturnValue([
|
|
59
|
+
"sincronia-dashboard",
|
|
60
|
+
"sincronia-schema",
|
|
61
|
+
]);
|
|
62
|
+
const plugins = (0, discovery_1.discoverPlugins)();
|
|
63
|
+
expect(plugins).toEqual([]);
|
|
64
|
+
// No require() attempted, so no warn from load failure
|
|
65
|
+
expect(Logger_1.logger.warn).not.toHaveBeenCalled();
|
|
66
|
+
});
|
|
56
67
|
});
|