Plugin catalogue

Every rule Luq can apply is a plugin you import by name. .use() puts one in the builder's bag.

Plugin objects
78
Import subpaths
77
Isolated tier
76
Extension tier
2

An isolated plugin imports nothing but the plugin kit, the shared types and its own directory, so adding one pulls in none of the others. An extension plugin may also import the JSON Schema layer and other plugins' entry files — which is why jsonSchemaFullFeature bundles 49 plugins on its own.

Browse and pick

Tick the plugins you need; the builder skeleton writes itself.

78 shown

Filter by slot

arrayContains

.contains()

At least one element satisfies the given element chain. Draft-07 contains, with optional min / max bounds for minContains / maxContains.

  • array
  • tuple
typescript
import { arrayContainsPlugin } from "@maroonedog/luq/plugins/arrayContains";

arrayEach

.each()

Applies one element chain to every element. It reports a single issue for the array; declare items[*] with .v() when you want one issue per element.

  • array
  • tuple
typescript
import { arrayEachPlugin } from "@maroonedog/luq/plugins/arrayEach";

arrayIncludes

.includes()

The array contains the given value. Membership is structural, so a value that came out of JSON.parse still matches.

  • array
  • tuple
typescript
import { arrayIncludesPlugin } from "@maroonedog/luq/plugins/arrayIncludes";

arrayMaxLength

.maxLength()

At most N elements. Draft-07 maxItems.

  • array
  • tuple
typescript
import { arrayMaxLengthPlugin } from "@maroonedog/luq/plugins/arrayMaxLength";

arrayMinLength

.minLength()

At least N elements. Draft-07 minItems.

  • array
  • tuple
typescript
import { arrayMinLengthPlugin } from "@maroonedog/luq/plugins/arrayMinLength";

arrayUnique

.unique()

No two elements are equal. Equality is structural, so the same object shape twice is a duplicate. Draft-07 uniqueItems.

  • array
  • tuple
typescript
import { arrayUniquePlugin } from "@maroonedog/luq/plugins/arrayUnique";

booleanFalsy

.falsy()

The value must be false.

  • boolean
typescript
import { booleanFalsyPlugin } from "@maroonedog/luq/plugins/booleanFalsy";

booleanTruthy

.truthy()

The value must be true — the accept-the-terms checkbox rule.

  • boolean
typescript
import { booleanTruthyPlugin } from "@maroonedog/luq/plugins/booleanTruthy";

compareField

.compareField()

Compares this field with another declared path. Equality by default; pass a comparison function for anything else. The path is checked against your type at compile time.

  • string
  • number
  • boolean
  • date
  • object
  • array
  • tuple
  • union
typescript
import { compareFieldPlugin } from "@maroonedog/luq/plugins/compareField";

conditionalSchema

.conditionalSchema()

Draft-07 if / then / else as one three-branch rule: when the condition chain passes, then applies, otherwise else does. Both branches are optional.

  • object
  • array
  • string
  • number
  • boolean
typescript
import { conditionalSchemaPlugin } from "@maroonedog/luq/plugins/conditionalSchema";

custom

.custom()

An arbitrary predicate over the field's value. It runs exactly once and may return { valid, message } to supply its own message.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { customPlugin } from "@maroonedog/luq/plugins/custom";

fromContext

.fromContext()

Checks the field against the external context handed to validate(value, { external }) — the read side of the async story. The plugin itself knows nothing about async.

  • string
  • number
  • boolean
  • date
  • object
  • array
  • tuple
  • union
typescript
import { fromContextPlugin } from "@maroonedog/luq/plugins/fromContext";

jsonSchema

.jsonSchema()

Constrains one declared field by a JSON Schema document, and takes the plugin bag explicitly. It reaches root-level keywords fromJsonSchema cannot, such as propertyNames and if / then / else on the document root.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { jsonSchemaPlugin } from "@maroonedog/luq/plugins/jsonSchema";

jsonSchemaFullFeature

.jsonSchemaFullFeature()

One import that covers a whole Draft-07 document. The same subpath exports fromJsonSchema<T>(schema), which builds a validator with no builder chain at all.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { jsonSchemaFullFeaturePlugin } from "@maroonedog/luq/plugins/jsonSchemaFullFeature";

literal

.literal()

Equality against one constant. Comparison is structural, so it matches values that came out of JSON.parse. Draft-07 const.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { literalPlugin } from "@maroonedog/luq/plugins/literal";

nullable

.nullable()

null is an accepted value for this field.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { nullablePlugin } from "@maroonedog/luq/plugins/nullable";

numberFinite

.finite()

Rejects NaN, Infinity and -Infinity.

  • number
typescript
import { numberFinitePlugin } from "@maroonedog/luq/plugins/numberFinite";

numberInteger

.integer()

The value has no fractional part. Draft-07 integer.

  • number
typescript
import { numberIntegerPlugin } from "@maroonedog/luq/plugins/numberInteger";

numberMax

.max()

Upper bound. Pass true as the second argument for an exclusive bound. Draft-07 maximum / exclusiveMaximum.

  • number
typescript
import { numberMaxPlugin } from "@maroonedog/luq/plugins/numberMax";

numberMin

.min()

Lower bound. Pass true as the second argument for an exclusive bound. Draft-07 minimum / exclusiveMinimum.

  • number
typescript
import { numberMinPlugin } from "@maroonedog/luq/plugins/numberMin";

numberMultipleOf

.multipleOf()

The value is an exact multiple of the divisor. Draft-07 multipleOf.

  • number
typescript
import { numberMultipleOfPlugin } from "@maroonedog/luq/plugins/numberMultipleOf";

numberNegative

.negative()

Strictly less than zero.

  • number
typescript
import { numberNegativePlugin } from "@maroonedog/luq/plugins/numberNegative";

numberPositive

.positive()

Strictly greater than zero.

  • number
typescript
import { numberPositivePlugin } from "@maroonedog/luq/plugins/numberPositive";

numberRange

.range()

Both bounds at once, inclusive.

  • number
typescript
import { numberRangePlugin } from "@maroonedog/luq/plugins/numberRange";

object

.object()

**Deprecated, and inert.** Entering b.object already checks that the value is a plain object, under the code objectType, so this rule answers PASS for everything. Drop the import and the .object() call: the field goes on rejecting arrays, null and primitives either way.

  • object
typescript
import { objectPlugin } from "@maroonedog/luq/plugins/object";

objectAdditionalProperties

.additionalProperties()

Draft-07's boolean additionalProperties. false forbids any key the schema did not declare; the optional second argument is a plain allow-list of extra key names.

  • object
typescript
import { objectAdditionalPropertiesPlugin } from "@maroonedog/luq/plugins/objectAdditionalProperties";

objectAdditionalProperties

.additionalPropertiesSchema()

Draft-07's schema form of additionalProperties: every undeclared key's value must satisfy the sub-chain. Passing false forbids undeclared keys outright.

  • object
typescript
import { objectAdditionalPropertiesSchemaPlugin } from "@maroonedog/luq/plugins/objectAdditionalProperties";

objectDependentRequired

.dependentRequired()

When a trigger key is present, the keys it lists must be present too. Draft-07 dependentRequired.

  • object
typescript
import { objectDependentRequiredPlugin } from "@maroonedog/luq/plugins/objectDependentRequired";

objectDependentSchemas

.dependentSchemas()

When a trigger key is present, the whole object must also satisfy that key's sub-chain. Draft-07 dependentSchemas.

  • object
typescript
import { objectDependentSchemasPlugin } from "@maroonedog/luq/plugins/objectDependentSchemas";

objectMaxProperties

.maxProperties()

At most N own keys. Draft-07 maxProperties.

  • object
typescript
import { objectMaxPropertiesPlugin } from "@maroonedog/luq/plugins/objectMaxProperties";

objectMinProperties

.minProperties()

At least N own keys. Draft-07 minProperties.

  • object
typescript
import { objectMinPropertiesPlugin } from "@maroonedog/luq/plugins/objectMinProperties";

objectPatternProperties

.patternProperties()

Every property whose key matches a regular expression must satisfy that pattern's sub-chain. Draft-07 patternProperties.

  • object
typescript
import { objectPatternPropertiesPlugin } from "@maroonedog/luq/plugins/objectPatternProperties";

objectPropertyNames

.propertyNames()

Constrains the object's KEYS with a string sub-chain — the subject is the key, never the value. Draft-07 propertyNames.

  • object
typescript
import { objectPropertyNamesPlugin } from "@maroonedog/luq/plugins/objectPropertyNames";

objectRecursively

.recursively()

Re-enters this field's own plan, on itself ("self") or on its elements ("element"), down to maxDepth (default 10). A cycle ends the descent silently.

  • object
  • array
typescript
import { objectRecursivelyPlugin } from "@maroonedog/luq/plugins/objectRecursively";

oneOf

.oneOf()

The value is one of a fixed list. Membership is structural. This is the value enum — not the oneOf composition keyword, which takes sub-schemas.

  • string
  • number
  • boolean
typescript
import { oneOfPlugin } from "@maroonedog/luq/plugins/oneOf";

optional

.optional()

The field may be absent. undefined passes and no other rule on the field runs.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { optionalPlugin } from "@maroonedog/luq/plugins/optional";

optionalIf

.optionalIf()

The field is optional only while the predicate holds, and required otherwise. The logical dual of requiredIf.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { optionalIfPlugin } from "@maroonedog/luq/plugins/optionalIf";

orFail

.orFail()

While the predicate holds, the field must carry no value at all, whatever that value would be — a deprecated field, or one a role forbids.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { orFailPlugin } from "@maroonedog/luq/plugins/orFail";

readOnly

.readOnly()

JSON Schema readOnly as an access check: on a write, the field must not be supplied.

  • string
  • number
  • boolean
  • date
  • array
  • object
typescript
import { readOnlyPlugin } from "@maroonedog/luq/plugins/readOnly";

required

.required()

The field must be present. It narrows null out of the field's type as well as undefined.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { requiredPlugin } from "@maroonedog/luq/plugins/required";

requiredIf

.requiredIf()

The field is required only while the predicate holds. The predicate sees the whole root value, and inside an array path it also sees the element's context.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { requiredIfPlugin } from "@maroonedog/luq/plugins/requiredIf";

skip

.skip()

Skips every rule on this field while the predicate holds. The polarity-inverted twin of validateIf.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { skipPlugin } from "@maroonedog/luq/plugins/skip";

stitch

.stitch()

Checks this field against the values of other declared paths in one function. The paths are type-checked, and the check runs exactly once.

  • string
  • number
  • boolean
  • date
  • object
  • array
  • tuple
  • union
typescript
import { stitchPlugin } from "@maroonedog/luq/plugins/stitch";

stitchWith

.stitchWith()

EXPERIMENTAL. Cross-field validation over a TYPED bundle. Name the paths under aliases, then judge them together in one sub-chain. stitch hands the bundle over as Record<string, unknown>; here a misspelt member or a wrong type is a compile error.

  • string
  • number
  • boolean
  • date
  • object
  • array
  • tuple
  • union
typescript
import { stitchWithPlugin } from "@maroonedog/luq/plugins/stitchWith";

stringAlphanumeric

.alphanumeric()

ASCII letters and digits only. The empty string fails; pass true to allow spaces.

  • string
typescript
import { stringAlphanumericPlugin } from "@maroonedog/luq/plugins/stringAlphanumeric";

stringBase64

.base64()

The string looks like base64. Recognition only — nothing here decodes it, so there is no decoded value to inspect.

  • string
typescript
import { stringBase64Plugin } from "@maroonedog/luq/plugins/stringBase64";

stringContentEncoding

.contentEncoding()

The string is valid under the named encoding: base64, base32, binary, 7bit, 8bit or quoted-printable. Draft-07 contentEncoding.

  • string
typescript
import { stringContentEncodingPlugin } from "@maroonedog/luq/plugins/stringContentEncoding";

stringContentMediaType

.contentMediaType()

The string parses as the named media type. Draft-07 contentMediaType.

  • string
typescript
import { stringContentMediaTypePlugin } from "@maroonedog/luq/plugins/stringContentMediaType";

stringDate

.date()

An RFC 3339 full-date, YYYY-MM-DD. Draft-07 date.

  • string
typescript
import { stringDatePlugin } from "@maroonedog/luq/plugins/stringDate";

stringDatetime

.datetime()

An RFC 3339 date-time. Draft-07 date-time.

  • string
typescript
import { stringDatetimePlugin } from "@maroonedog/luq/plugins/stringDatetime";

stringDuration

.duration()

An ISO 8601 duration. Draft-07 duration.

  • string
typescript
import { stringDurationPlugin } from "@maroonedog/luq/plugins/stringDuration";

stringEmail

.email()

An email address. Pass customRegex to substitute your own grammar. Draft-07 email.

  • string
typescript
import { stringEmailPlugin } from "@maroonedog/luq/plugins/stringEmail";

stringEndsWith

.endsWith()

The string ends with the suffix. An empty suffix always passes.

  • string
typescript
import { stringEndsWithPlugin } from "@maroonedog/luq/plugins/stringEndsWith";

stringExactLength

.exactLength()

Exactly N UTF-16 code units.

  • string
typescript
import { stringExactLengthPlugin } from "@maroonedog/luq/plugins/stringExactLength";

stringHostname

.hostname()

An RFC 1123 hostname. Draft-07 hostname.

  • string
typescript
import { stringHostnamePlugin } from "@maroonedog/luq/plugins/stringHostname";

stringIdnEmail

.idnEmail()

An internationalised email address. Draft-07 idn-email.

  • string
typescript
import { stringIdnEmailPlugin } from "@maroonedog/luq/plugins/stringIdnEmail";

stringIdnHostname

.idnHostname()

An internationalised hostname. Draft-07 idn-hostname.

  • string
typescript
import { stringIdnHostnamePlugin } from "@maroonedog/luq/plugins/stringIdnHostname";

stringIpv4

.ipv4()

A dotted-quad IPv4 address. Draft-07 ipv4.

  • string
typescript
import { stringIpv4Plugin } from "@maroonedog/luq/plugins/stringIpv4";

stringIpv6

.ipv6()

An IPv6 address. Draft-07 ipv6.

  • string
typescript
import { stringIpv6Plugin } from "@maroonedog/luq/plugins/stringIpv6";

stringIri

.iri()

An IRI (RFC 3987, deliberately approximate). Draft-07 iri.

  • string
typescript
import { stringIriPlugin } from "@maroonedog/luq/plugins/stringIri";

stringIriReference

.iriReference()

An IRI reference, absolute or relative. Draft-07 iri-reference.

  • string
typescript
import { stringIriReferencePlugin } from "@maroonedog/luq/plugins/stringIriReference";

stringJsonPointer

.jsonPointer()

An RFC 6901 JSON Pointer. Draft-07 json-pointer.

  • string
typescript
import { stringJsonPointerPlugin } from "@maroonedog/luq/plugins/stringJsonPointer";

stringMax

.max()

At most N UTF-16 code units. max: 0 permits only the empty string. Draft-07 maxLength.

  • string
typescript
import { stringMaxPlugin } from "@maroonedog/luq/plugins/stringMax";

stringMin

.min()

At least N UTF-16 code units, so an astral character counts as two. Draft-07 minLength.

  • string
typescript
import { stringMinPlugin } from "@maroonedog/luq/plugins/stringMin";

stringPattern

.pattern()

The string matches a RegExp.

  • string
typescript
import { stringPatternPlugin } from "@maroonedog/luq/plugins/stringPattern";

stringRegex

.regex()

The string is itself a valid regular expression. Draft-07 regex.

  • string
typescript
import { stringRegexPlugin } from "@maroonedog/luq/plugins/stringRegex";

stringRelativeJsonPointer

.relativeJsonPointer()

A relative JSON Pointer. Draft-07 relative-json-pointer.

  • string
typescript
import { stringRelativeJsonPointerPlugin } from "@maroonedog/luq/plugins/stringRelativeJsonPointer";

stringStartsWith

.startsWith()

The string starts with the prefix. An empty prefix always passes.

  • string
typescript
import { stringStartsWithPlugin } from "@maroonedog/luq/plugins/stringStartsWith";

stringTime

.time()

An RFC 3339 full-time. Draft-07 time.

  • string
typescript
import { stringTimePlugin } from "@maroonedog/luq/plugins/stringTime";

stringUriReference

.uriReference()

A URI reference, absolute or relative. Draft-07 uri-reference.

  • string
typescript
import { stringUriReferencePlugin } from "@maroonedog/luq/plugins/stringUriReference";

stringUriTemplate

.uriTemplate()

An RFC 6570 URI template. Draft-07 uri-template.

  • string
typescript
import { stringUriTemplatePlugin } from "@maroonedog/luq/plugins/stringUriTemplate";

stringUrl

.url()

An absolute URL, and the single home of the Draft-07 uri format.

  • string
typescript
import { stringUrlPlugin } from "@maroonedog/luq/plugins/stringUrl";

transform

.transform()

Maps the value to a new one. Transforms run LAST and only in parse() — validate() gives you back the original value.

  • string
  • number
  • boolean
  • date
  • array
  • object
  • union
typescript
import { transformPlugin } from "@maroonedog/luq/plugins/transform";

tupleBuilder

.builder()

One chain per tuple position, plus an optional chain for the rest. Each position is typed by the tuple member it sits on.

  • tuple
typescript
import { tupleBuilderPlugin } from "@maroonedog/luq/plugins/tupleBuilder";

unionGuard

.guard()

A type guard plus the rules that apply to the branch it narrows to. Every member of the union must be covered before build() is offered.

  • union
typescript
import { unionGuardPlugin } from "@maroonedog/luq/plugins/unionGuard";

uuid

.uuid()

A UUID. Pass a version, or a list of versions, to narrow it.

  • string
typescript
import { uuidPlugin } from "@maroonedog/luq/plugins/uuid";

validateIf

.validateIf()

Runs this field's rules only while the predicate holds. Where the call sits in the chain is irrelevant — the engine asks every gate before it runs any rule.

  • string
  • number
  • boolean
  • date
  • array
  • tuple
  • object
  • union
  • any
typescript
import { validateIfPlugin } from "@maroonedog/luq/plugins/validateIf";

writeOnly

.writeOnly()

JSON Schema writeOnly as an access check: on a read, the field must not be returned.

  • string
  • number
  • boolean
  • date
  • array
  • object
typescript
import { writeOnlyPlugin } from "@maroonedog/luq/plugins/writeOnly";

How a plugin is used

draft-validator.ts
import { Builder } from "@maroonedog/luq";
import { requiredPlugin } from "@maroonedog/luq/plugins/required";
import { stringMinPlugin } from "@maroonedog/luq/plugins/stringMin";

type Draft = { title: string };

const draftValidator = Builder()
  .use(requiredPlugin)
  .use(stringMinPlugin)
  .for<Draft>()
  .v("title", (b) => b.string.required().min(3))
  .build();

const result = draftValidator.validate({ title: "x" });

if (result.valid) {
  console.log(result.data.title);
} else {
  for (const issue of result.issues) {
    console.error(`${issue.path}: ${issue.message} (${issue.code})`);
  }
}

The result shape, and the four members of the built object: the Validator page.

Your builder

One import per plugin — the root export deliberately ships none, so every line names its own subpath. Ticking a plugin also ticks the plugins its example chain calls.