Welcome to PDSL
The expressive declarative toolkit for composing predicates in TypeScript or JavaScript
const isSoftwareCreator = p`{
name: string,
age: > 16,
occupation: "Engineer" | "Designer" | "Project Manager"
}`;
isSoftwareCreator({
name: "Jane Kenith",
age: 22,
occupation: "Engineer"
}); // true
Predicate functions are just easier with PDSL
Creating predicate functions in JavaScript is often verbose, especially for checking the format of complex object types. We need predicate functions all the time when filtering an array, validating input, determining the type of an unknown object or creating guard conditions in TypeScript.
PDSL provides the developer a simple but powerful shorthand based on a combination of template strings and helper functions for defining predicate functions that makes it easy to understand intent. With pdsl
we can easily visualize the expected input’s structure and intent using it’s intuitive predicate composition language.
PDSL is:
- Intuitive
- Expressive
- Lightweight (under 6k)!
- No dependencies
- Small bundle size
- Fast
Installation
Install with npm or yarn
yarn add pdsl
npm install pdsl
Then import the default package into your JavaScript or TypeScript file:
import p from "pdsl";
p`{ name: string }`({ name: "Jane" });
If you have Babel in your build pipeline we recommend to use the babel plugin.
New in Version 5
Exact matching on objects is now off by default
New in version 5.2+ objects no longer have exact matching turned on by default. If you wish to continue using exact matching you can use the exact matching syntax:
p`{ name: "foo" }`({ name: "foo", age: 20 }); // true
Exact object matching mode can be turned on by using objects with pipes |
:
p`{| name: "foo" |}`({ name: "foo", age: 20 }); // false
Once you turn exact matching on in an object tree you can only turn it off by using the rest operator:
p`{|
name: "foo",
exact: {
hello:"hello"
},
loose: {
hello: "hello",
...
}
|}`({
name: "foo",
exact: {
hello: "hello"
},
loose: {
hello: "hello",
extra: true,
another: []
}
}); // true
New validation syntax
We now have a new validation syntax!
async function runValidation() {
const { validate, validateSync } = p.schema`{
name:
string <- "Name must be a string"
& string[>7] <- "Name must be longer than 7 characters",
age:
(number & > 18) <- "Age must be numeric and over 18"
}`;
try {
await validate({ name: "Rick" });
} catch (err) {
console.log(err); // "Name must be longer than 7 characters"
}
try {
validateSync({ name: 100, age: 24 });
} catch (err) {
console.log(err); // "Name must be a string"
}
try {
await validate({ name: "Rickardo", age: 16 });
} catch (err) {
console.log(err); // "Age must be numeric and over 18"
}
try {
validateSync({ name: "Rickardo", age: 24 });
} catch (err) {
console.log("Ye gads!");
}
}
runValidation();
New array includes syntax
Also new we have an array includes function:
[? <predicate> ]
p`[? >50 ]`([1, 2, 100, 12]); // true because 100 is greater than 50
Formik compatability
We also now have formik compatability!
import {schema as p} from 'pdsl';
export default () => (
<Formik
initialValues=
validationSchema={p`{
email:
_ <- "Required"
& Email <- "Invalid email address",
firstName:
_ <- "Required"
& string[>2] <- "Must be longer than 2 characters"
& string[<20] <- "Nice try nobody has a first name that long",
lastName:
_ <- "Required"
& string[>2] <- "Must be longer than 2 characters"
& string[<20] <- "Nice try nobody has a last name that long"
}`}
onSubmit={values => {
// submit values
}}
render={({ errors, touched }) => (
// render form
)}
/>
)
Roadmap
Help organise our priorities by telling us what is the most important to you
- Basic Language Design (✓)
- PDSL Compiler (✓)
- Comprehensive Test cases (✓)
- Babel Plugin to remove compiler perf overhead (✓)
- Validation errors (✓)
- Exact matching syntax (✓)
- Automatic type creation from queries
- Syntax Highlighting / VSCode Autocomplete / Prettier formatting