
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@dldc/chemin
Advanced tools
A type-safe pattern builder & route matching library written in TypeScript
A type-safe pattern builder & route matching library written in TypeScript
import { chemin, pNumber, pOptionalConst } from '@dldc/chemin';
// admin/post/:postId(number)/delete?
const path = chemin('admin', 'post', pNumber('postId'), pOptionalConst('delete'));
console.log(path.match('/no/valid'));
// => null
const match = path.match('/admin/post/45');
console.log(match);
// => { rest: [], exact: true, params: { postId: 45, delete: false } }
// match.params is typed as { postId: number, delete: boolean } !
You can use a Chemin
inside another one to easily compose your routes !
import { chemin, pNumber, pString } from '@dldc/chemin';
const postFragment = chemin('post', pNumber('postId'));
const postAdmin = chemin('admin', pString('userId'), postFragment, 'edit');
console.log(postAdmin.stringify()); // /admin/:userId/post/:postId(number)/edit
The following params are build-in and exported from @dldc/chemin
.
A number using
parseFloat(x)
const chemin = chemin(pNumber('myNum'));
matchExact(chemin, '/3.1415'); // { myNum: 3.1415 }
NOTE: Because it uses parseFloat
this will also accept Infinity
, 10e2
...
A integer using
parseInt(x, 10)
const chemin = chemin(pInteger('myInt'));
matchExact(chemin, '/42'); // { myInt: 42 }
The options
parameter is optional and accepts a strict
boolean property (true
by default). When strict is set to true
(the default) it will only match if the parsed number is the same as the raw value (so 1.0
or 42blabla
will not match).
const chemin = chemin(pInteger('myInt', { strict: false }));
matchExact(chemin, '/42fooo'); // { myInt: 42 }
Any non-empty string
const chemin = chemin(pString('myStr'));
matchExact(chemin, '/cat'); // { myStr: 'cat' }
A constant string
const chemin = chemin(pConstant('edit'));
matchExact(chemin, '/edit'); // {}
matchExact(chemin, '/'); // false
Make any
Param
optional
const chemin = chemin(pOptional(pInteger('myInt')));
matchExact(chemin, '/42'); // { myInt: { present: true, value: 42 } }
matchExact(chemin, '/'); // { myInt: { present: false } }
An optional contant string
const chemin = chemin(pOptionalConst('isEditing', 'edit'));
matchExact(chemin, '/edit'); // { isEditing: true }
matchExact(chemin, '/'); // { isEditing: false }
If path
is omitted then the name is used as the path.
const chemin = chemin(pOptionalConst('edit'));
matchExact(chemin, '/edit'); // { edit: true }
matchExact(chemin, '/'); // { edit: false }
An optional string parameter
const chemin = chemin(pOptionalString('name'));
matchExact(chemin, '/paul'); // { name: 'paul' }
matchExact(chemin, '/'); // { name: false }
Allow a params to be repeated any number of time
const chemin = chemin(pMultiple(pString('categories')));
matchExact(chemin, '/'); // { categories: [] }
matchExact(chemin, '/foo/bar'); // { categories: ['foo', 'bar'] }
const chemin = chemin(pMultiple(pString('categories'), true));
matchExact(chemin, '/'); // false because atLeastOne is true
matchExact(chemin, '/foo/bar'); // { categories: ['foo', 'bar'] }
Param
You can create your own Param
to better fit your application while keeping full type-safety !
import { chemin, type TCheminParam } from '@dldc/chemin';
// match only string of 4 char [a-z0-9]
function pFourCharStringId<N extends string>(name: N): TCheminParam<N, string> {
const reg = /^[a-z0-9]{4}$/;
return {
factory: pFourCharStringId,
name,
meta: null,
isEqual: (other) => other.name === name,
match: (...all) => {
if (all[0].match(reg)) {
return { match: true, value: all[0], next: all.slice(1) };
}
return { match: false, next: all };
},
serialize: (value) => value,
stringify: () => `:${name}(id4)`,
};
}
const path = chemin('item', pFourCharStringId('itemId'));
console.log(path.match('/item/a4e3t')); // null (5 char)
console.log(path.match('/item/A4e3')); // null (because A is uppercase)
console.log(path.match('/item/a4e3')); // { rest: [], exact: true, params: { itemId: 'a4e3' } }
Take a look a the custom-advanced.test.ts example. and the build-in Params.
Create a
Chemin
Accepts any number or arguments of type string
, TCheminParam
or IChemin
.
Note: strings are converted to pConstant
.
chemin('admin', pNumber('userId'), pOptionalConst('edit'));
The chemin
function returns an object with the following properties:
parts
: an array of the parts (other Chemin
s or Param
s), this is what was passed to the chemin
function except that strings are converted to pConstant
.match(pathname)
: test a chemin against a pathname, see match
for more details.matchExact(pathname)
: test a chemin against a pathname for an exact match, see matchExact
for more details.stringify(params?, options?)
: serialize a chemin, see stringify
for more details.serialize(params?, options?)
: serialize a chemin, see serialize
for more details.extract()
: return an array of all the Chemin
it contains (as well as the Chemin
itself), see extract
for more details.flatten()
: return all the Param
it contains, see flatten
for more details.Note: Most of these functions are also exported as standalone functions (see below). The only difference is that extract
and flatten
are cached when called on a Chemin
itself, but you should rarely need to use them anyway.
Test wether an object is a
Chemin
or not
Accepts one argument and return true
if it's a Chemin
, false otherwise.
isChemin(chemin('admin')); // true
The cheminFactory
function returns a function that works exactly like chemin
but with a default serialize
/ stringify
options.
The defaultSerializeOptions
parameter is optional and accepts two boolean
properties:
leadingSlash
(default true
): Add a slash at the beginingtrailingSlash
(default: false
): Add a slash at the endTest a chemin against a pathname
Returns null
or ICheminMatch
.
pathname
can be either a string (/admin/user/5
) or an array of strings (['admin', 'user', '5']
)ICheminMatch
is an object with three properties
rest
: an array of string of the remaining parts of the pathname once the matching is doneexact
: a boolean indicating if the match is exact or not (if rest
is empty or not)params
: an object of params extracted from the matchingNote: When pathname
is a string
, it is splitted using the splitPathname
function. This function is exported so you can use it to split your pathnames in the same way.
import { chemin, pNumber, pOptionalConst, match } from '@dldc/chemin';
const chemin = chemin('admin', pNumber('userId'), pOptionalConst('edit'));
match(chemin, '/admin/42/edit'); // { rest: [], exact: true, params: { userId: 42, edit: true } }
match(chemin, '/admin/42/edit/rest'); // { rest: ['rest'], exact: false, params: { userId: 42, edit: true } }
match(chemin, '/noop'); // null
Accepts the same arguments as match
but return null
if the path does not match or if rest
is not empty, otherwise it returns the params
object directly.
Print a chemin from its params.
Accepts a chemin
some params
(an object or null
) and an optional option
object.
The option object accepts two boolean
properties:
leadingSlash
(default true
): Add a slash at the beginingtrailingSlash
(default: false
): Add a slash at the endconst chemin = chemin('admin', pNumber('userId'), pOptionalConst('edit'));
serialize(chemin, { userId: 42, edit: true }); // /admin/42/edit
Split a pathname and prevent empty parts
Accepts a string and returns an array of strings.
splitPathname('/admin/user/5'); // ['admin', 'user', '5']
This function let you extract the params of a chemin that is part of another one
const workspaceBase = chemin('workspace', pString('tenant'));
const routes = [
chemin('home'), // home
chemin('settings'), // settings
chemin(workspaceBase, 'home'), // workspace home
chemin(workspaceBase, 'settings'), // workspace settings
];
function app(pathname: string) {
const route = matchFirst(routes, pathname);
if (!route) {
return { route: null };
}
const { chemin, match } = route;
// extract the tenant from the workspace if it's a workspace route
const params = partialMatch(chemin, match, workspaceBase);
// params is typed as { tenant: string } | null
if (params) {
return { tenant: params.tenant, route: chemin.stringify() };
}
return { route: chemin.stringify() };
}
Note: This is based on reference equality so it will not work if you create a new Chemin
with the same parts: chemin('workspace', pString('tenant'))
!
Note 2: In reality this function simply returns the match.params
object if the part
is contained in chemin
or null
otherwise. This mean that you might get more properties that what the type gives you (but this is quite commoin in TypeScript).
Given an object of
Chemin
and apathname
return an new object with the result ofmatch
for each keys
const chemins = {
home: chemin('home'),
workspace: chemin('workspace', pString('tenant')),
workspaceSettings: chemin('workspace', pString('tenant'), 'settings'),
};
const match = matchAll(chemins, '/workspace/123/settings');
expect(match).toEqual({
home: null,
workspace: { rest: ['settings'], exact: false, params: { tenant: '123' } },
workspaceSettings: { rest: [], exact: true, params: { tenant: '123' } },
});
Same as
matchAll
but also match nested objects
Return an array of all the
Chemin
it contains (as well as theChemin
itself).
import { Chemin } from '@dldc/chemin';
const admin = chemin('admin');
const adminUser = chemin(admin, 'user');
adminUser.extract(); // [adminUser, admin];
Note: You probably don't need this but it's used internally in partialMatch
Return a string representation of the chemin.
import { Chemin, pNumber, pString, stringify } from '@dldc/chemin';
const postFragment = chemin('post', pNumber('postId'));
const postAdmin = chemin('admin', pString('userId'), postFragment, 'edit');
console.log(stringify(postAdmin)); // /admin/:userId/post/:postId(number)/edit
The option object accepts two boolean
properties:
leadingSlash
(default true
): Add a slash at the beginingtrailingSlash
(default: false
): Add a slash at the endFAQs
A type-safe pattern builder & route matching library written in TypeScript
The npm package @dldc/chemin receives a total of 8 weekly downloads. As such, @dldc/chemin popularity was classified as not popular.
We found that @dldc/chemin demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.