mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
perf(tools): stop counting string code points once the bounds are decided
Strings without length bounds are not counted, and counting stops at the larger bound, so a huge tool argument costs no more than its limit.
This commit is contained in:
1 parent
d74556a801
commit
c12938cd05
2 files changed
+27
-6
No files matched your search
+14
-6
@@ -106,12 +106,20 @@ export function validateValue(schema, value, path = 'arguments') {
|
|||||||
fail('must be a string');
|
fail('must be a string');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let length = 0;
|
if (schema.minLength != null || schema.maxLength != null) {
|
||||||
for (const character of value) length += 1;
|
// Code points, as JSON Schema counts. Counting stops once both bounds
|
||||||
if (schema.minLength != null && length < schema.minLength)
|
// are decided, so a huge argument costs no more than its limit.
|
||||||
fail(`must be at least ${schema.minLength} characters`);
|
const limit = Math.max(
|
||||||
if (schema.maxLength != null && length > schema.maxLength)
|
schema.minLength ?? 0,
|
||||||
fail(`must be at most ${schema.maxLength} characters`);
|
schema.maxLength != null ? schema.maxLength + 1 : 0,
|
||||||
|
);
|
||||||
|
let length = 0;
|
||||||
|
for (const _ of value) if (++length >= limit) break;
|
||||||
|
if (schema.minLength != null && length < schema.minLength)
|
||||||
|
fail(`must be at least ${schema.minLength} characters`);
|
||||||
|
if (schema.maxLength != null && length > schema.maxLength)
|
||||||
|
fail(`must be at most ${schema.maxLength} characters`);
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
schema.pattern !== undefined &&
|
schema.pattern !== undefined &&
|
||||||
!new RegExp(schema.pattern, 'u').test(value)
|
!new RegExp(schema.pattern, 'u').test(value)
|
||||||
|
|||||||
@@ -18,3 +18,16 @@ test('tool string schemas count Unicode characters rather than UTF-16 units', ()
|
|||||||
);
|
);
|
||||||
assert.equal(validateValue({ type: 'string', minLength: 2 }, '𠮷').length, 1);
|
assert.equal(validateValue({ type: 'string', minLength: 2 }, '𠮷').length, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('tool string bounds hold at their edges and on huge arguments', () => {
|
||||||
|
const string = (bounds) => ({ type: 'string', ...bounds });
|
||||||
|
assert.deepEqual(validateValue(string({ maxLength: 3 }), '😀😀😀'), []);
|
||||||
|
assert.equal(validateValue(string({ maxLength: 3 }), '😀😀😀😀').length, 1);
|
||||||
|
assert.deepEqual(validateValue(string({ minLength: 3 }), '😀😀😀'), []);
|
||||||
|
assert.deepEqual(validateValue(string({}), 'x'.repeat(1e6)), []);
|
||||||
|
// Counting all of it takes roughly 0.7 s; stopping at the limit takes none.
|
||||||
|
const huge = 'x'.repeat(1e8);
|
||||||
|
const started = performance.now();
|
||||||
|
assert.equal(validateValue(string({ maxLength: 60 }), huge).length, 1);
|
||||||
|
assert.ok(performance.now() - started < 200, 'stops counting past the limit');
|
||||||
|
});
|
||||||
Reference in new issue
Block a user