UNPKG

@comunica/actor-function-factory-term-regex

Version:

A term-regex function-factory actor

104 lines 4.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TermFunctionRegex = void 0; const bus_function_factory_1 = require("@comunica/bus-function-factory"); const utils_expression_evaluator_1 = require("@comunica/utils-expression-evaluator"); /** * https://www.w3.org/TR/sparql11-query/#func-regex */ class TermFunctionRegex extends bus_function_factory_1.TermFunctionBase { constructor() { super({ arity: [2, 3], operator: utils_expression_evaluator_1.SparqlOperator.REGEX, overloads: (0, utils_expression_evaluator_1.declare)(utils_expression_evaluator_1.SparqlOperator.REGEX) .onBinaryTyped([utils_expression_evaluator_1.TypeAlias.SPARQL_STRINGLY, utils_expression_evaluator_1.TypeURL.XSD_STRING], TermFunctionRegex.regex2) .onTernaryTyped([utils_expression_evaluator_1.TypeAlias.SPARQL_STRINGLY, utils_expression_evaluator_1.TypeURL.XSD_STRING, utils_expression_evaluator_1.TypeURL.XSD_STRING], TermFunctionRegex.regex3) .collect(), }); } static regex2() { return (text, pattern) => (0, utils_expression_evaluator_1.bool)(TermFunctionRegex.matches(text, pattern)); } static regex3() { return (text, pattern, flags) => (0, utils_expression_evaluator_1.bool)(TermFunctionRegex.matches(text, pattern, flags)); } // https://www.w3.org/TR/xpath-functions/#func-matches // https://www.w3.org/TR/xpath-functions/#flags static matches(text, pattern, flags = '') { // Flags: // i: case-insensitive: same as the 'i' flag in JavaScript // m: multi-line mode: same as the 'm' flag in JavaScript // s: dot-all mode: matches 's' flag in JavaScript very well. // x: whitespace characters (#x9, #xA, #xD and #x20) // in the regular expression are removed prior to matching with one exception: // whitespace characters within character class expressions. // q: regex-no-metacharacters: // all characters in the regular expression are treated as representing themselves, not as metacharacters // If it is used together with the m, s, or x flag, that flag has no effect. flags = TermFunctionRegex.cleanFlags(flags); if (flags.includes('x')) { pattern = TermFunctionRegex.flagX(pattern); } if (flags.includes('q')) { pattern = TermFunctionRegex.flagQ(pattern); } const reg = new RegExp(pattern, flags.replaceAll(/[qx]/gu, '')); return reg.test(text); } static cleanFlags(flags) { // Check flag validity if (!/^[imsxq]*$/u.test(flags)) { throw new Error('Invalid flags'); } const duplicateFlag = [...flags] .find((value, index, self) => self.indexOf(value) !== index); if (duplicateFlag) { throw new Error(`Duplicate flag: ${duplicateFlag}`); } // If the 'q' flag is used, the 'm', 's', and 'x' flags have no effect if (flags?.includes('q')) { flags = flags.replaceAll(/[msx]/gu, ''); } // Add the JS 'u' flag to the flags to allow for safer regex execution. // See reasons given by [ESLint](https://eslint.org/docs/latest/rules/require-unicode-regexp). // Disable [Annex B](https://262.ecma-international.org/6.0/#sec-regular-expressions-patterns) return `${flags}u`; } static flagX(pattern) { if (!pattern) { return pattern; } // Remove all spaces in the pattern, excluding those in character classes let prev = pattern[0]; while (['\u0009', '\u000A', '\u000D', '\u0020'].includes(prev)) { pattern = pattern.slice(1); prev = pattern[0]; } let inClass = prev === '['; for (let i = 1; i < pattern.length; i++) { const c = pattern[i]; if (['\u0009', '\u000A', '\u000D', '\u0020'].includes(c) && !inClass) { pattern = pattern.slice(0, i) + pattern.slice(i + 1); i--; } else if (c === '[' && prev !== '\\') { inClass = true; } else if (c === ']' && prev !== '\\') { inClass = false; } prev = c; } return pattern; } static flagQ(pattern) { // Escape all metacharacters in the pattern return pattern .replaceAll(/([?+*.{}()[\]\\|])/gu, '\\$1') .replaceAll(/^\^/gu, '\\^') .replaceAll(/\$$/gu, '\\$'); } } exports.TermFunctionRegex = TermFunctionRegex; //# sourceMappingURL=TermFunctionRegex.js.map