@tenonhq/dovetail-servicenow 0.0.29 → 0.0.30
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/cli.js +48 -10
- package/dist/fieldsFromJson.d.ts +22 -0
- package/dist/fieldsFromJson.js +107 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -60,6 +60,7 @@ const fs = __importStar(require("fs"));
|
|
|
60
60
|
const path = __importStar(require("path"));
|
|
61
61
|
const loadEnv_1 = require("./loadEnv");
|
|
62
62
|
const client_1 = require("./client");
|
|
63
|
+
const fieldsFromJson_1 = require("./fieldsFromJson");
|
|
63
64
|
const choices_1 = require("./choices");
|
|
64
65
|
const formatter_1 = require("./formatter");
|
|
65
66
|
const views_1 = require("./layout/views");
|
|
@@ -897,11 +898,12 @@ function printHelp() {
|
|
|
897
898
|
" DRY-RUN BY DEFAULT — nothing is sent without --confirm\n" +
|
|
898
899
|
" (--method <GET|POST|PUT|DELETE> --path /api/<scope>/<service>/<resource>\n" +
|
|
899
900
|
" [--body '<json>' | --body-json <path>] [--confirm] [--dry-run] [--json])\n" +
|
|
900
|
-
" set-field Set
|
|
901
|
-
|
|
902
|
-
|
|
901
|
+
" set-field Set field value(s) on an EXISTING record, into an update set, then verify\n" +
|
|
902
|
+
" (--table <t> --sys-id <id>|--query <q> --update-set <sys_id>\n" +
|
|
903
|
+
' (--fields "k=v,k2=v2" | --from-json <path>) [--dry-run] [--json])\n' +
|
|
903
904
|
" create-record Create ONE NEW record in a data table, into an update set, then verify\n" +
|
|
904
|
-
|
|
905
|
+
" (--table <t> --scope <s> --update-set <sys_id>\n" +
|
|
906
|
+
' (--fields "k=v,k2=v2" | --from-json <path>)\n' +
|
|
905
907
|
" [--if-absent <encoded-query>] [--dry-run] [--json])\n" +
|
|
906
908
|
" host-assets Deploy a built dist/ to ServiceNow (carrier sys_ui_script + attachment + m2m)\n" +
|
|
907
909
|
" (--dir <dist> --app <sys_id> --scope <namespace>\n" +
|
|
@@ -1228,24 +1230,48 @@ function parseFieldsInline(input) {
|
|
|
1228
1230
|
}
|
|
1229
1231
|
return out;
|
|
1230
1232
|
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Merge the two field sources for the record-write verbs: inline `--fields "k=v,k2=v2"`
|
|
1235
|
+
* and `--from-json <path>` (a JSON object — the only form that can carry a large or
|
|
1236
|
+
* multiline value, since the inline form splits on commas and trims). On a key present in
|
|
1237
|
+
* both, `--from-json` wins: it is the explicit spec file. Throws on an unreadable file,
|
|
1238
|
+
* malformed JSON, or a non-scalar value (surfaced by the caller as a bad-args error).
|
|
1239
|
+
*/
|
|
1240
|
+
function mergeFields(flags) {
|
|
1241
|
+
var inline = parseFieldsInline(flags.fields || "");
|
|
1242
|
+
if (!flags["from-json"])
|
|
1243
|
+
return inline;
|
|
1244
|
+
return Object.assign(inline, (0, fieldsFromJson_1.readFieldsFromJsonFile)(flags["from-json"]));
|
|
1245
|
+
}
|
|
1231
1246
|
/**
|
|
1232
1247
|
* dove-sn set-field:
|
|
1233
1248
|
* --table x_cadso_core_metric_point_type
|
|
1234
1249
|
* --sys-id <id> | --query "name=send_size" (query must resolve to exactly 1 row)
|
|
1235
|
-
* --fields "order=20"
|
|
1250
|
+
* [--fields "order=20"] (comma-separated key=value pairs)
|
|
1251
|
+
* [--from-json <path>] (JSON { field: value }; carries large or
|
|
1252
|
+
* multiline values the inline form can't;
|
|
1253
|
+
* overrides --fields on a shared key)
|
|
1254
|
+
* — at least one of --fields / --from-json is required
|
|
1236
1255
|
* --update-set <sys_id> (required — the change is captured here)
|
|
1237
1256
|
* [--dry-run] [--json]
|
|
1238
1257
|
* Exit codes: 0 applied/dry-run, 1 bad args, 2 write landed but read-back unverified.
|
|
1239
1258
|
*/
|
|
1240
1259
|
async function runSetField(flags) {
|
|
1241
1260
|
var table = flags.table;
|
|
1242
|
-
var fields
|
|
1261
|
+
var fields;
|
|
1262
|
+
try {
|
|
1263
|
+
fields = mergeFields(flags);
|
|
1264
|
+
}
|
|
1265
|
+
catch (err) {
|
|
1266
|
+
process.stderr.write("set-field: " + (err instanceof Error ? err.message : String(err)) + "\n");
|
|
1267
|
+
return 1;
|
|
1268
|
+
}
|
|
1243
1269
|
var hasTarget = Boolean(flags["sys-id"] || flags.query);
|
|
1244
1270
|
if (!table ||
|
|
1245
1271
|
Object.keys(fields).length === 0 ||
|
|
1246
1272
|
!hasTarget ||
|
|
1247
1273
|
!flags["update-set"]) {
|
|
1248
|
-
process.stderr.write('set-field: --table,
|
|
1274
|
+
process.stderr.write('set-field: --table, one of --sys-id/--query, --update-set, and at least one field (--fields "k=v" or --from-json <path>) are required\n');
|
|
1249
1275
|
return 1;
|
|
1250
1276
|
}
|
|
1251
1277
|
var params = {
|
|
@@ -1285,7 +1311,10 @@ async function runSetField(flags) {
|
|
|
1285
1311
|
/**
|
|
1286
1312
|
* dove-sn create-record:
|
|
1287
1313
|
* --table x_cadso_core_metric_point_type
|
|
1288
|
-
* --fields "name=avg_message_parts,label=Avg. Message Parts,order=35"
|
|
1314
|
+
* [--fields "name=avg_message_parts,label=Avg. Message Parts,order=35"]
|
|
1315
|
+
* [--from-json <path>] (JSON { field: value }; carries large or
|
|
1316
|
+
* multiline values the inline form can't)
|
|
1317
|
+
* — at least one of --fields / --from-json is required
|
|
1289
1318
|
* --scope x_cadso_core (the app that owns the new record)
|
|
1290
1319
|
* --update-set <sys_id> (required — the insert is captured here)
|
|
1291
1320
|
* [--if-absent "name=avg_message_parts"] (skip the insert when this query already matches)
|
|
@@ -1295,12 +1324,21 @@ async function runSetField(flags) {
|
|
|
1295
1324
|
*/
|
|
1296
1325
|
async function runCreateRecord(flags) {
|
|
1297
1326
|
var table = flags.table;
|
|
1298
|
-
var fields
|
|
1327
|
+
var fields;
|
|
1328
|
+
try {
|
|
1329
|
+
fields = mergeFields(flags);
|
|
1330
|
+
}
|
|
1331
|
+
catch (err) {
|
|
1332
|
+
process.stderr.write("create-record: " +
|
|
1333
|
+
(err instanceof Error ? err.message : String(err)) +
|
|
1334
|
+
"\n");
|
|
1335
|
+
return 1;
|
|
1336
|
+
}
|
|
1299
1337
|
if (!table ||
|
|
1300
1338
|
Object.keys(fields).length === 0 ||
|
|
1301
1339
|
!flags.scope ||
|
|
1302
1340
|
!flags["update-set"]) {
|
|
1303
|
-
process.stderr.write('create-record: --table, --fields "k=v"
|
|
1341
|
+
process.stderr.write('create-record: --table, --scope, --update-set, and at least one field (--fields "k=v" or --from-json <path>) are required\n');
|
|
1304
1342
|
return 1;
|
|
1305
1343
|
}
|
|
1306
1344
|
var params = {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--from-json` field-map loader for the record-write verbs (set-field, create-record).
|
|
3
|
+
*
|
|
4
|
+
* The inline `--fields "k=v,k2=v2"` form splits on commas and trims each piece — so it
|
|
5
|
+
* cannot carry a value that contains a comma, a newline, an `=`, or leading/trailing
|
|
6
|
+
* whitespace. That rules out every large field: a script body, an HTML/XML/CSS field, a
|
|
7
|
+
* JSON blob. `--from-json <path>` closes that gap: the file is a flat JSON object of
|
|
8
|
+
* `field → value`, and JSON quoting carries any character faithfully.
|
|
9
|
+
*
|
|
10
|
+
* Values may be string | number | boolean. Numbers/booleans are stringified — matching
|
|
11
|
+
* the inline parser and the wire format, where ServiceNow scalar fields are strings.
|
|
12
|
+
* `null`/`undefined` values are skipped. Nested objects and arrays are rejected: a scalar
|
|
13
|
+
* field cannot take one, and silently JSON-encoding it would write garbage into the record.
|
|
14
|
+
*/
|
|
15
|
+
export declare function coerceFieldsFromJson(parsed: unknown): Record<string, string>;
|
|
16
|
+
/**
|
|
17
|
+
* Read + parse a `--from-json` file into a validated field map. The path is resolved
|
|
18
|
+
* against the process cwd, matching the other `--from-json` consumers in the CLI.
|
|
19
|
+
* Throws a clean, prefixed message on a missing file or malformed JSON so the caller can
|
|
20
|
+
* surface it as a bad-args error rather than an uncaught stack trace.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readFieldsFromJsonFile(filePath: string): Record<string, string>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.coerceFieldsFromJson = coerceFieldsFromJson;
|
|
37
|
+
exports.readFieldsFromJsonFile = readFieldsFromJsonFile;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
/**
|
|
41
|
+
* `--from-json` field-map loader for the record-write verbs (set-field, create-record).
|
|
42
|
+
*
|
|
43
|
+
* The inline `--fields "k=v,k2=v2"` form splits on commas and trims each piece — so it
|
|
44
|
+
* cannot carry a value that contains a comma, a newline, an `=`, or leading/trailing
|
|
45
|
+
* whitespace. That rules out every large field: a script body, an HTML/XML/CSS field, a
|
|
46
|
+
* JSON blob. `--from-json <path>` closes that gap: the file is a flat JSON object of
|
|
47
|
+
* `field → value`, and JSON quoting carries any character faithfully.
|
|
48
|
+
*
|
|
49
|
+
* Values may be string | number | boolean. Numbers/booleans are stringified — matching
|
|
50
|
+
* the inline parser and the wire format, where ServiceNow scalar fields are strings.
|
|
51
|
+
* `null`/`undefined` values are skipped. Nested objects and arrays are rejected: a scalar
|
|
52
|
+
* field cannot take one, and silently JSON-encoding it would write garbage into the record.
|
|
53
|
+
*/
|
|
54
|
+
function coerceFieldsFromJson(parsed) {
|
|
55
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
56
|
+
throw new Error("--from-json must contain a JSON object of field → value pairs");
|
|
57
|
+
}
|
|
58
|
+
var obj = parsed;
|
|
59
|
+
var out = {};
|
|
60
|
+
var keys = Object.keys(obj);
|
|
61
|
+
for (var i = 0; i < keys.length; i += 1) {
|
|
62
|
+
var key = keys[i];
|
|
63
|
+
var value = obj[key];
|
|
64
|
+
if (value === null || value === undefined)
|
|
65
|
+
continue;
|
|
66
|
+
var valueType = typeof value;
|
|
67
|
+
if (valueType === "string") {
|
|
68
|
+
out[key] = value;
|
|
69
|
+
}
|
|
70
|
+
else if (valueType === "number" || valueType === "boolean") {
|
|
71
|
+
out[key] = String(value);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
throw new Error("--from-json field '" +
|
|
75
|
+
key +
|
|
76
|
+
"' must be a string, number, or boolean (got " +
|
|
77
|
+
valueType +
|
|
78
|
+
")");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read + parse a `--from-json` file into a validated field map. The path is resolved
|
|
85
|
+
* against the process cwd, matching the other `--from-json` consumers in the CLI.
|
|
86
|
+
* Throws a clean, prefixed message on a missing file or malformed JSON so the caller can
|
|
87
|
+
* surface it as a bad-args error rather than an uncaught stack trace.
|
|
88
|
+
*/
|
|
89
|
+
function readFieldsFromJsonFile(filePath) {
|
|
90
|
+
var raw;
|
|
91
|
+
try {
|
|
92
|
+
raw = fs.readFileSync(path.resolve(filePath), "utf8");
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
var readMsg = err instanceof Error ? err.message : String(err);
|
|
96
|
+
throw new Error("--from-json: cannot read '" + filePath + "': " + readMsg);
|
|
97
|
+
}
|
|
98
|
+
var parsed;
|
|
99
|
+
try {
|
|
100
|
+
parsed = JSON.parse(raw);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
var parseMsg = err instanceof Error ? err.message : String(err);
|
|
104
|
+
throw new Error("--from-json: '" + filePath + "' is not valid JSON: " + parseMsg);
|
|
105
|
+
}
|
|
106
|
+
return coerceFieldsFromJson(parsed);
|
|
107
|
+
}
|