fp-ts-routing
Version:
A type-safe routing library for TypeScript
200 lines • 6.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.query = exports.lit = exports.int = exports.IntegerFromString = exports.str = exports.type = exports.end = exports.succeed = exports.then = exports.imap = exports.Match = void 0;
/**
* @since 0.6.0
*/
var E = require("fp-ts/lib/Either");
var function_1 = require("fp-ts/lib/function");
var O = require("fp-ts/lib/Option");
// This `pipe` version is deprecated, but provided by `fp-ts` v2.0.1 and higher.
var pipeable_1 = require("fp-ts/lib/pipeable");
var io_ts_1 = require("io-ts");
var formatter_1 = require("./formatter");
var parser_1 = require("./parser");
var route_1 = require("./route");
/**
* @category matchers
* @since 0.4.0
*/
var Match = /** @class */ (function () {
function Match(parser, formatter) {
this.parser = parser;
this.formatter = formatter;
}
/**
* @since 0.4.0
*/
Match.prototype.imap = function (f, g) {
return new Match(this.parser.map(f), this.formatter.contramap(g));
};
/**
* @since 0.4.0
*/
Match.prototype.then = function (that) {
return new Match(this.parser.then(that.parser), this.formatter.then(that.formatter));
};
return Match;
}());
exports.Match = Match;
/**
* @category matchers
* @since 0.5.1
*/
var imap = function (f, g) {
return function (ma) {
return ma.imap(f, g);
};
};
exports.imap = imap;
/**
* @category matchers
* @since 0.5.1
*/
var then = function (mb) {
return function (ma) {
return ma.then(mb);
};
};
exports.then = then;
var singleton = function (k, v) {
var _a;
return (_a = {}, _a[k] = v, _a);
};
/**
* `succeed` matches everything but consumes nothing
*
* @category matchers
* @since 0.4.0
*/
var succeed = function (a) { return new Match(new parser_1.Parser(function (r) { return O.some([a, r]); }), new formatter_1.Formatter(function_1.identity)); };
exports.succeed = succeed;
/**
* `end` matches the end of a route
*
* @category matchers
* @since 0.4.0
*/
exports.end = new Match(new parser_1.Parser(function (r) { return (route_1.Route.isEmpty(r) ? O.some([{}, r]) : O.none); }), new formatter_1.Formatter(function_1.identity));
/**
* `type` matches any io-ts type path component
*
* @example
* import * as t from 'io-ts'
* import { lit, type, Route } from 'fp-ts-routing'
* import { some, none } from 'fp-ts/lib/Option'
*
* const T = t.keyof({
* a: null,
* b: null
* })
*
* const match = lit('search').then(type('topic', T))
*
* assert.deepStrictEqual(match.parser.run(Route.parse('/search/a')), some([{ topic: 'a' }, Route.empty]))
* assert.deepStrictEqual(match.parser.run(Route.parse('/search/b')), some([{ topic: 'b' }, Route.empty]))
* assert.deepStrictEqual(match.parser.run(Route.parse('/search/')), none)
*
* @category matchers
* @since 0.4.0
*/
var type = function (k, type) {
return new Match(new parser_1.Parser(function (r) {
if (r.parts.length === 0) {
return O.none;
}
return (0, pipeable_1.pipe)(type.decode(r.parts[0]), O.fromEither, O.map(function (a) { return [singleton(k, a), new route_1.Route(r.parts.slice(1), r.query)]; }));
}), new formatter_1.Formatter(function (r, o) { return new route_1.Route(r.parts.concat(type.encode(o[k])), r.query); }));
};
exports.type = type;
/**
* `str` matches any string path component
*
* @example
* import { str, Route } from 'fp-ts-routing'
* import { some, none } from 'fp-ts/lib/Option'
*
* assert.deepStrictEqual(str('id').parser.run(Route.parse('/abc')), some([{ id: 'abc' }, new Route([], {})]))
* assert.deepStrictEqual(str('id').parser.run(Route.parse('/')), none)
*
* @category matchers
* @since 0.4.0
*/
var str = function (k) { return (0, exports.type)(k, io_ts_1.string); };
exports.str = str;
/**
* @category matchers
* @since 0.4.2
*/
exports.IntegerFromString = new io_ts_1.Type('IntegerFromString', function (u) { return io_ts_1.Int.is(u); }, function (u, c) {
return (0, pipeable_1.pipe)(io_ts_1.string.validate(u, c), E.chain(function (s) {
var n = +s;
return isNaN(n) || !Number.isInteger(n) ? (0, io_ts_1.failure)(s, c) : (0, io_ts_1.success)(n);
}));
}, String);
/**
* `int` matches any integer path component
*
* @example
* import { int, Route } from 'fp-ts-routing'
* import { some, none } from 'fp-ts/lib/Option'
*
* assert.deepStrictEqual(int('id').parser.run(Route.parse('/1')), some([{ id: 1 }, new Route([], {})]))
* assert.deepStrictEqual(int('id').parser.run(Route.parse('/a')), none)
*
* @category matchers
* @since 0.4.0
*/
var int = function (k) { return (0, exports.type)(k, exports.IntegerFromString); };
exports.int = int;
/**
* `lit(x)` will match exactly the path component `x`
*
* @example
* import { lit, Route } from 'fp-ts-routing'
* import { some, none } from 'fp-ts/lib/Option'
*
* assert.deepStrictEqual(lit('subview').parser.run(Route.parse('/subview/')), some([{}, new Route([], {})]))
* assert.deepStrictEqual(lit('subview').parser.run(Route.parse('/')), none)
*
* @category matchers
* @since 0.4.0
*/
var lit = function (literal) {
return new Match(new parser_1.Parser(function (r) {
if (r.parts.length === 0) {
return O.none;
}
return r.parts[0] === literal ? O.some([{}, new route_1.Route(r.parts.slice(1), r.query)]) : O.none;
}), new formatter_1.Formatter(function (r) { return new route_1.Route(r.parts.concat(literal), r.query); }));
};
exports.lit = lit;
/**
* Will match a querystring.
*
*
* **Note**. Use `io-ts`'s `strict` instead of `type` otherwise excess properties won't be removed.
*
* @example
* import * as t from 'io-ts'
* import { lit, str, query, Route } from 'fp-ts-routing'
*
* const route = lit('accounts')
* .then(str('accountId'))
* .then(lit('files'))
* .then(query(t.strict({ pathparam: t.string })))
* .formatter.run(Route.empty, { accountId: 'testId', pathparam: '123' })
* .toString()
*
* assert.strictEqual(route, '/accounts/testId/files?pathparam=123')
*
* @category matchers
* @since 0.4.0
*/
var query = function (type) {
return new Match(new parser_1.Parser(function (r) {
return (0, pipeable_1.pipe)(type.decode(r.query), O.fromEither, O.map(function (query) { return [query, new route_1.Route(r.parts, {})]; }));
}), new formatter_1.Formatter(function (r, query) { return new route_1.Route(r.parts, type.encode(query)); }));
};
exports.query = query;
//# sourceMappingURL=matcher.js.map