@naturalcycles/nodejs-lib 15.107.0 → 15.107.2
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.
|
@@ -117,7 +117,7 @@ export class SlackService {
|
|
|
117
117
|
* Returns a CommonLogger implementation based on this SlackService instance.
|
|
118
118
|
*/
|
|
119
119
|
getCommonLogger(opt) {
|
|
120
|
-
const { minLogLevel
|
|
120
|
+
const { minLogLevel, debugChannel, logChannel, warnChannel, errorChannel } = opt;
|
|
121
121
|
const defaultChannel = this.cfg.defaults?.channel || DEFAULTS.channel;
|
|
122
122
|
const q = new PQueue({
|
|
123
123
|
concurrency: 1,
|
|
@@ -1178,6 +1178,9 @@ function executeValidation(fn, builtSchema, input, opt = {}, defaultInputName) {
|
|
|
1178
1178
|
const errors = fn.errors;
|
|
1179
1179
|
const { inputId = _isObject(input) ? input['id'] : undefined, inputName = defaultInputName || 'Object', } = opt;
|
|
1180
1180
|
const dataVar = [inputName, inputId].filter(Boolean).join('.');
|
|
1181
|
+
// Build fingerprint before applyImprovementsOnErrorMessages: after it, /items/0/name becomes
|
|
1182
|
+
// .items[0].name, embedding the index into the segment and making it harder to strip without regex
|
|
1183
|
+
const fingerprint = buildAjvErrorFingerprint(errors[0], inputName);
|
|
1181
1184
|
applyImprovementsOnErrorMessages(errors, builtSchema);
|
|
1182
1185
|
let message = getAjv().errorsText(errors, {
|
|
1183
1186
|
dataVar,
|
|
@@ -1192,6 +1195,7 @@ function executeValidation(fn, builtSchema, input, opt = {}, defaultInputName) {
|
|
|
1192
1195
|
errors,
|
|
1193
1196
|
inputName,
|
|
1194
1197
|
inputId,
|
|
1198
|
+
fingerprint,
|
|
1195
1199
|
}));
|
|
1196
1200
|
return [err, output];
|
|
1197
1201
|
}
|
|
@@ -1218,6 +1222,22 @@ function applyImprovementsOnErrorMessages(errors, schema) {
|
|
|
1218
1222
|
error.instancePath = error.instancePath.replaceAll(/\/(\d+)/g, `[$1]`).replaceAll('/', '.');
|
|
1219
1223
|
}
|
|
1220
1224
|
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Groups repeated validation errors by rule rather than by unique request content.
|
|
1227
|
+
* Excludes instance-specific data like record IDs and array indices.
|
|
1228
|
+
*/
|
|
1229
|
+
function buildAjvErrorFingerprint(e, inputName) {
|
|
1230
|
+
const value = Object.values(e.params || {})[0];
|
|
1231
|
+
let rule = e.keyword;
|
|
1232
|
+
if (value !== undefined)
|
|
1233
|
+
rule += `:${value}`;
|
|
1234
|
+
const path = e.instancePath
|
|
1235
|
+
.split('/')
|
|
1236
|
+
.filter(s => s && isNaN(Number(s)))
|
|
1237
|
+
.join('.');
|
|
1238
|
+
const location = [inputName, path].filter(Boolean).join('.');
|
|
1239
|
+
return [location, rule].join(' ');
|
|
1240
|
+
}
|
|
1221
1241
|
/**
|
|
1222
1242
|
* Filters out noisy errors produced by nullable anyOf patterns.
|
|
1223
1243
|
* When `nullable()` wraps a schema in `anyOf: [realSchema, { type: 'null' }]`,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/nodejs-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.107.
|
|
4
|
+
"version": "15.107.2",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@naturalcycles/js-lib": "^15",
|
|
7
7
|
"@standard-schema/spec": "^1",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"yargs": "^18"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
21
|
-
"@naturalcycles/dev-lib": "
|
|
20
|
+
"@typescript/native-preview": "7.0.0-dev.20260415.1",
|
|
21
|
+
"@naturalcycles/dev-lib": "18.4.2"
|
|
22
22
|
},
|
|
23
23
|
"exports": {
|
|
24
24
|
".": "./dist/index.js",
|
|
@@ -156,7 +156,7 @@ export class SlackService<CTX = any> {
|
|
|
156
156
|
warnChannel?: string
|
|
157
157
|
errorChannel?: string
|
|
158
158
|
}): CommonLogger {
|
|
159
|
-
const { minLogLevel
|
|
159
|
+
const { minLogLevel, debugChannel, logChannel, warnChannel, errorChannel } = opt
|
|
160
160
|
const defaultChannel = this.cfg.defaults?.channel || DEFAULTS.channel!
|
|
161
161
|
|
|
162
162
|
const q = new PQueue({
|
|
@@ -1692,6 +1692,10 @@ function executeValidation<OUT>(
|
|
|
1692
1692
|
} = opt
|
|
1693
1693
|
const dataVar = [inputName, inputId].filter(Boolean).join('.')
|
|
1694
1694
|
|
|
1695
|
+
// Build fingerprint before applyImprovementsOnErrorMessages: after it, /items/0/name becomes
|
|
1696
|
+
// .items[0].name, embedding the index into the segment and making it harder to strip without regex
|
|
1697
|
+
const fingerprint = buildAjvErrorFingerprint(errors[0], inputName)
|
|
1698
|
+
|
|
1695
1699
|
applyImprovementsOnErrorMessages(errors, builtSchema)
|
|
1696
1700
|
|
|
1697
1701
|
let message = getAjv().errorsText(errors, {
|
|
@@ -1711,6 +1715,7 @@ function executeValidation<OUT>(
|
|
|
1711
1715
|
errors,
|
|
1712
1716
|
inputName,
|
|
1713
1717
|
inputId,
|
|
1718
|
+
fingerprint,
|
|
1714
1719
|
}),
|
|
1715
1720
|
)
|
|
1716
1721
|
return [err, output]
|
|
@@ -1719,7 +1724,7 @@ function executeValidation<OUT>(
|
|
|
1719
1724
|
// ==== Error formatting helpers ====
|
|
1720
1725
|
|
|
1721
1726
|
function applyImprovementsOnErrorMessages(
|
|
1722
|
-
errors: ErrorObject
|
|
1727
|
+
errors: ErrorObject[] | null | undefined,
|
|
1723
1728
|
schema: JsonSchema,
|
|
1724
1729
|
): void {
|
|
1725
1730
|
if (!errors) return
|
|
@@ -1746,16 +1751,29 @@ function applyImprovementsOnErrorMessages(
|
|
|
1746
1751
|
}
|
|
1747
1752
|
}
|
|
1748
1753
|
|
|
1754
|
+
/**
|
|
1755
|
+
* Groups repeated validation errors by rule rather than by unique request content.
|
|
1756
|
+
* Excludes instance-specific data like record IDs and array indices.
|
|
1757
|
+
*/
|
|
1758
|
+
function buildAjvErrorFingerprint(e: ErrorObject, inputName: string): string {
|
|
1759
|
+
const value = Object.values(e.params || {})[0]
|
|
1760
|
+
let rule = e.keyword
|
|
1761
|
+
if (value !== undefined) rule += `:${value}`
|
|
1762
|
+
const path = e.instancePath
|
|
1763
|
+
.split('/')
|
|
1764
|
+
.filter(s => s && isNaN(Number(s)))
|
|
1765
|
+
.join('.')
|
|
1766
|
+
const location = [inputName, path].filter(Boolean).join('.')
|
|
1767
|
+
return [location, rule].join(' ')
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1749
1770
|
/**
|
|
1750
1771
|
* Filters out noisy errors produced by nullable anyOf patterns.
|
|
1751
1772
|
* When `nullable()` wraps a schema in `anyOf: [realSchema, { type: 'null' }]`,
|
|
1752
1773
|
* AJV produces "must be null" and "must match a schema in anyOf" errors
|
|
1753
1774
|
* that are confusing. This method splices them out, keeping only the real errors.
|
|
1754
1775
|
*/
|
|
1755
|
-
function filterNullableAnyOfErrors(
|
|
1756
|
-
errors: ErrorObject<string, Record<string, any>, unknown>[],
|
|
1757
|
-
schema: JsonSchema,
|
|
1758
|
-
): void {
|
|
1776
|
+
function filterNullableAnyOfErrors(errors: ErrorObject[], schema: JsonSchema): void {
|
|
1759
1777
|
// Collect exact schemaPaths to remove (anyOf aggregates) and prefixes (null branches)
|
|
1760
1778
|
const exactPaths: string[] = []
|
|
1761
1779
|
const nullBranchPrefixes: string[] = []
|