@discretetom/r-compose
Version:
Compose RegExp in JavaScript in a readable and maintainable way.
174 lines • 6.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.compose = exports.composables = void 0;
function intoString(content) {
return content instanceof RegExp ? content.source : content;
}
/**
* All the composable functions.
*/
exports.composables = Object.freeze({
/**
* Escape regex special characters.
* @example
* escape("(a*b)") === "\\(a\\*b\\)"
*/
escape(content) {
// use the `g` flag to replace all occurrences
return content.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
},
/**
* Concatenate strings.
* Empty strings are ignored.
* If a parameter is a `RegExp`, its source is used.
* @example
* concat("a", "b") === "ab"
* concat("a", '', "b") === "ab"
* concat('a', /\./, 'b') === "a\\.b"
*/
concat(...contents) {
return contents
.map(intoString)
.filter((c) => c.length)
.join("");
},
/**
* Match a list of candidates.
* Empty strings are ignored.
* If a parameter is a `RegExp`, its source is used.
* The result is wrapped in a non-capturing group.
* @example
* select("a", "b") === "(?:a|b)"
* select("a", '', "b") === "(?:a|b)"
* select('a', /\./, 'b') === "(?:a|\\.|b)"
*/
select(...contents) {
return `(?:${contents
.map(intoString)
.filter((c) => c.length)
.join("|")})`;
},
/**
* Wrap the content by a non-capturing group.
* If the content is a `RegExp`, its source is used.
* @example
* group("a") === "(?:a)"
* group(/\./) === "(?:\\.)"
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Groups_and_backreferences
*/
group(content) {
return `(?:${intoString(content)})`;
},
/**
* Wrap the content by a capturing group.
* If the content is a `RegExp`, its source is used.
* @example
* capture("a") === "(a)"
* capture(/\./) === "(\\.)"
* capture("a", { name: "n" }) === "(?<n>a)"
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Groups_and_backreferences
*/
capture(content, options) {
return (options === null || options === void 0 ? void 0 : options.name) === undefined
? `(${intoString(content)})`
: `(?<${options.name}>${intoString(content)})`;
},
/**
* Match zero or more times (`*`).
* If the content is a `RegExp`, its source is used.
* @example
* any("a") === "(?:a)*"
* any(/\./) === "(?:\\.)*"
* any("a", { greedy: false }) === "(?:a)*?"
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Quantifiers
*/
any(content, options) {
var _a;
return ((_a = options === null || options === void 0 ? void 0 : options.greedy) !== null && _a !== void 0 ? _a : true)
? `(?:${intoString(content)})*`
: `(?:${intoString(content)})*?`;
},
/**
* Match one or more times (`+`).
* If the content is a `RegExp`, its source is used.
* @example
* some("a") === "(?:a)+"
* some(/\./) === "(?:\\.)+"
* some("a", { greedy: false }) === "(?:a)+?"
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Quantifiers
*/
some(content, options) {
var _a;
return ((_a = options === null || options === void 0 ? void 0 : options.greedy) !== null && _a !== void 0 ? _a : true)
? `(?:${intoString(content)})+`
: `(?:${intoString(content)})+?`;
},
/**
* Match zero or one time (`?`).
* If the content is a `RegExp`, its source is used.
* @example
* optional("a") === "(?:a)?"
* optional(/\./) === "(?:\\.)?"
* optional("a", { greedy: false }) === "(?:a)??"
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Quantifiers
*/
optional(content, options) {
var _a;
return ((_a = options === null || options === void 0 ? void 0 : options.greedy) !== null && _a !== void 0 ? _a : true)
? `(?:${intoString(content)})?`
: `(?:${intoString(content)})??`;
},
/**
* If the content is a `RegExp`, its source is used.
* @example
* lookahead("a") === "(?=a)"
* lookahead(/\./) === "(?=\\.)"
* lookahead("a", { negative: true }) === "(?!a)"
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Assertions
*/
lookahead(content, options) {
var _a;
return ((_a = options === null || options === void 0 ? void 0 : options.negative) !== null && _a !== void 0 ? _a : false)
? `(?!${intoString(content)})`
: `(?=${intoString(content)})`;
},
/**
* If the content is a `RegExp`, its source is used.
* @example
* lookbehind("a") === "(?<=a)"
* lookbehind(/\./) === "(?<=\\.)"
* lookbehind("a", { negative: true }) === "(?<!a)"
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Assertions
*/
lookbehind(content, options) {
var _a;
return ((_a = options === null || options === void 0 ? void 0 : options.negative) !== null && _a !== void 0 ? _a : false)
? `(?<!${intoString(content)})`
: `(?<=${intoString(content)})`;
},
/**
* Match any character except the ones in the content.
* If the content is a `RegExp`, its source is used.
* @example
* not("a") === "[^a]"
* not(/\./) === "[^\\.]"
*/
not(content) {
return `[^${intoString(content)}]`;
},
/**
* @alias String.raw
* @example
* raw`\n` === "\\n"
*/
raw: String.raw,
});
/**
* @example
* compose(({ concat, group }) => concat(group("a"), group("b")), 'g') === /(?:a)(?:b)/g
*/
function compose(cb, flags) {
return new RegExp(cb(exports.composables), flags);
}
exports.compose = compose;
//# sourceMappingURL=index.js.map