130 lines
4.4 KiB
JavaScript
130 lines
4.4 KiB
JavaScript
'use strict';
|
|
|
|
const NO_WRAP_RE = /^(?:\(.*\)|\\?.)$/;
|
|
function wrap(s) {
|
|
const v = s.toString();
|
|
return NO_WRAP_RE.test(v) ? v : `(?:${v})`;
|
|
}
|
|
|
|
const GROUPED_AS_REPLACE_RE = /^(?:\(\?:(.+)\)|(.+))$/;
|
|
const GROUPED_REPLACE_RE = /^(?:\(\?:(.+)\)([?+*]|\{[\d,]+\})?|(.+))$/;
|
|
function createInput(s) {
|
|
const groupedAsFn = (key) => createInput(`(?<${key}>${`${s}`.replace(GROUPED_AS_REPLACE_RE, "$1$2")})`);
|
|
return {
|
|
toString: () => s.toString(),
|
|
and: Object.assign((...inputs) => createInput(`${s}${exactly(...inputs)}`), {
|
|
referenceTo: (groupName) => createInput(`${s}\\k<${groupName}>`)
|
|
}),
|
|
or: (...inputs) => createInput(`(?:${s}|${inputs.map((v) => exactly(v)).join("|")})`),
|
|
after: (...input) => createInput(`(?<=${exactly(...input)})${s}`),
|
|
before: (...input) => createInput(`${s}(?=${exactly(...input)})`),
|
|
notAfter: (...input) => createInput(`(?<!${exactly(...input)})${s}`),
|
|
notBefore: (...input) => createInput(`${s}(?!${exactly(...input)})`),
|
|
times: Object.assign((number) => createInput(`${wrap(s)}{${number}}`), {
|
|
any: () => createInput(`${wrap(s)}*`),
|
|
atLeast: (min) => createInput(`${wrap(s)}{${min},}`),
|
|
atMost: (max) => createInput(`${wrap(s)}{0,${max}}`),
|
|
between: (min, max) => createInput(`${wrap(s)}{${min},${max}}`)
|
|
}),
|
|
optionally: () => createInput(`${wrap(s)}?`),
|
|
as: groupedAsFn,
|
|
groupedAs: groupedAsFn,
|
|
grouped: () => createInput(`${s}`.replace(GROUPED_REPLACE_RE, "($1$3)$2")),
|
|
at: {
|
|
lineStart: () => createInput(`^${s}`),
|
|
lineEnd: () => createInput(`${s}$`)
|
|
}
|
|
};
|
|
}
|
|
|
|
const ESCAPE_REPLACE_RE = /[.*+?^${}()|[\]\\/]/g;
|
|
function createCharInput(raw) {
|
|
const input = createInput(`[${raw}]`);
|
|
const from = (charFrom, charTo) => createCharInput(`${raw}${escapeCharInput(charFrom)}-${escapeCharInput(charTo)}`);
|
|
const orChar = Object.assign((chars) => createCharInput(`${raw}${escapeCharInput(chars)}`), { from });
|
|
return Object.assign(input, { orChar, from });
|
|
}
|
|
function escapeCharInput(raw) {
|
|
return raw.replace(/[-\\^\]]/g, "\\$&");
|
|
}
|
|
const charIn = Object.assign((chars) => {
|
|
return createCharInput(escapeCharInput(chars));
|
|
}, createCharInput(""));
|
|
const charNotIn = Object.assign((chars) => {
|
|
return createCharInput(`^${escapeCharInput(chars)}`);
|
|
}, createCharInput("^"));
|
|
function anyOf(...inputs) {
|
|
return createInput(`(?:${inputs.map((a) => exactly(a)).join("|")})`);
|
|
}
|
|
const char = createInput(".");
|
|
const word = createInput("\\b\\w+\\b");
|
|
const wordChar = createInput("\\w");
|
|
const wordBoundary = createInput("\\b");
|
|
const digit = createInput("\\d");
|
|
const whitespace = createInput("\\s");
|
|
const letter = Object.assign(createInput("[a-zA-Z]"), {
|
|
lowercase: createInput("[a-z]"),
|
|
uppercase: createInput("[A-Z]")
|
|
});
|
|
const tab = createInput("\\t");
|
|
const linefeed = createInput("\\n");
|
|
const carriageReturn = createInput("\\r");
|
|
const not = {
|
|
word: createInput("\\W+"),
|
|
wordChar: createInput("\\W"),
|
|
wordBoundary: createInput("\\B"),
|
|
digit: createInput("\\D"),
|
|
whitespace: createInput("\\S"),
|
|
letter: Object.assign(createInput("[^a-zA-Z]"), {
|
|
lowercase: createInput("[^a-z]"),
|
|
uppercase: createInput("[^A-Z]")
|
|
}),
|
|
tab: createInput("[^\\t]"),
|
|
linefeed: createInput("[^\\n]"),
|
|
carriageReturn: createInput("[^\\r]")
|
|
};
|
|
function maybe(...inputs) {
|
|
return createInput(`${wrap(exactly(...inputs))}?`);
|
|
}
|
|
function exactly(...inputs) {
|
|
return createInput(
|
|
inputs.map((input) => typeof input === "string" ? input.replace(ESCAPE_REPLACE_RE, "\\$&") : input).join("")
|
|
);
|
|
}
|
|
function oneOrMore(...inputs) {
|
|
return createInput(`${wrap(exactly(...inputs))}+`);
|
|
}
|
|
|
|
const withIndices = "d";
|
|
const caseInsensitive = "i";
|
|
const global = "g";
|
|
const multiline = "m";
|
|
const dotAll = "s";
|
|
const unicode = "u";
|
|
const sticky = "y";
|
|
|
|
exports.anyOf = anyOf;
|
|
exports.carriageReturn = carriageReturn;
|
|
exports.caseInsensitive = caseInsensitive;
|
|
exports.char = char;
|
|
exports.charIn = charIn;
|
|
exports.charNotIn = charNotIn;
|
|
exports.digit = digit;
|
|
exports.dotAll = dotAll;
|
|
exports.exactly = exactly;
|
|
exports.global = global;
|
|
exports.letter = letter;
|
|
exports.linefeed = linefeed;
|
|
exports.maybe = maybe;
|
|
exports.multiline = multiline;
|
|
exports.not = not;
|
|
exports.oneOrMore = oneOrMore;
|
|
exports.sticky = sticky;
|
|
exports.tab = tab;
|
|
exports.unicode = unicode;
|
|
exports.whitespace = whitespace;
|
|
exports.withIndices = withIndices;
|
|
exports.word = word;
|
|
exports.wordBoundary = wordBoundary;
|
|
exports.wordChar = wordChar;
|