UNPKG

ifc-expressions

Version:

Parsing and evaluation of IFC expressions

272 lines (271 loc) 15.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IfcExpressionFunctions = void 0; const IfcExpressionUtils_js_1 = require("../../util/IfcExpressionUtils.js"); const MAP_js_1 = require("./impl/MAP.js"); const ROUND_js_1 = require("./impl/ROUND.js"); const AttributeAccessorFunction_js_1 = require("./impl/AttributeAccessorFunction.js"); const PROPERTYSET_js_1 = require("./impl/PROPERTYSET.js"); const PROPERTY_js_1 = require("./impl/PROPERTY.js"); const TYPE_js_1 = require("./impl/TYPE.js"); const FuncBooleanBinary_js_1 = require("./impl/FuncBooleanBinary.js"); const NOT_js_1 = require("./impl/NOT.js"); const CHOOSE_js_1 = require("./impl/CHOOSE.js"); const MatchesPattern_js_1 = require("./impl/MatchesPattern.js"); const Types_js_1 = require("../../type/Types.js"); const TOSTRING_js_1 = require("./impl/TOSTRING.js"); const EXISTS_js_1 = require("./impl/EXISTS.js"); const EQUALS_js_1 = require("./impl/EQUALS.js"); const CompareMagnitudes_js_1 = require("./impl/CompareMagnitudes.js"); const ReplacePattern_js_1 = require("./impl/ReplacePattern.js"); const IF_js_1 = require("./impl/IF.js"); const TONUMERIC_js_1 = require("./impl/TONUMERIC.js"); const IfcExpressionFunctionConfigException_js_1 = require("../../error/IfcExpressionFunctionConfigException.js"); const TOBOOLEAN_js_1 = require("./impl/TOBOOLEAN.js"); const TOLOGICAL_js_1 = require("./impl/TOLOGICAL.js"); const TOLOWERCASE_js_1 = require("./impl/TOLOWERCASE.js"); const TOUPPERCASE_js_1 = require("./impl/TOUPPERCASE.js"); const SUBSTRING_js_1 = require("./impl/SUBSTRING.js"); const SPLIT_js_1 = require("./impl/SPLIT.js"); const AT_js_1 = require("./impl/AT.js"); const TOIFCDATE_js_1 = require("./impl/TOIFCDATE.js"); const TOIFCDATETIME_js_1 = require("./impl/TOIFCDATETIME.js"); const TOIFCTIME_js_1 = require("./impl/TOIFCTIME.js"); const TOIFCDURATION_js_1 = require("./impl/TOIFCDURATION.js"); const TOIFCTIMESTAMP_js_1 = require("./impl/TOIFCTIMESTAMP.js"); const ADDDURATION_js_1 = require("./impl/ADDDURATION.js"); const builtinFunctions = new Map(); function registerOrDie(fnKey, func) { if (builtinFunctions.has(fnKey)) { throw new IfcExpressionFunctionConfigException_js_1.IfcExpressionFunctionConfigException(`cannot register function with name '${fnKey}': name already in use`); } builtinFunctions.set(fnKey, func); } function toDocKey(label) { return label.replace(/[^a-zA-Z0-9]+/g, "_"); } function withDocumentation(func, summary, args = []) { func.withDocumentation({ key: `function.${func.getName()}.summary`, fallback: summary, }); args.forEach((argument, index) => { const formalArgument = func.getFormalArguments()[index]; if (!formalArgument) { return; } const docKey = toDocKey(argument.label); formalArgument.withDocumentation({ key: `function.${func.getName()}.arg.${docKey}.label`, fallback: argument.label, }, { key: `function.${func.getName()}.arg.${docKey}.summary`, fallback: argument.documentation, }); }); return func; } function registerFunc(func, ...aliases) { const fnKey = func.getName(); const keys = [...aliases]; keys.unshift(fnKey); keys.forEach((key) => registerOrDie(IfcExpressionFunctions.normalizeName(key), func)); } function documentAttributeAccessor(name, summary) { return withDocumentation(new AttributeAccessorFunction_js_1.AttributeAccessorFunction(name, Types_js_1.Type.STRING), summary, [ { label: "object", documentation: "The IFC object to read from", }, ]); } class IfcExpressionFunctions { static normalizeName(name) { if ((0, IfcExpressionUtils_js_1.isNullish)(name)) { return undefined; } return name.toUpperCase(); } static isBuiltinFunction(name) { if ((0, IfcExpressionUtils_js_1.isNullish)(name)) { return false; } return builtinFunctions.has(this.normalizeName(name)); } static getFunction(name) { if ((0, IfcExpressionUtils_js_1.isNullish)(name)) { return undefined; } return builtinFunctions.get(this.normalizeName(name)); } static getBuiltinFunctionNames() { return [...builtinFunctions.keys()].sort((left, right) => left.localeCompare(right)); } } exports.IfcExpressionFunctions = IfcExpressionFunctions; registerFunc(withDocumentation(new MAP_js_1.MAP(), "map an input value through a list of key/value mappings", [ { label: "input", documentation: "The value to look up" }, { label: "mappings", documentation: "The mapping table as [key, value] pairs", }, { label: "defaultValue", documentation: "The fallback value to return when no mapping matches", }, ])); registerFunc(withDocumentation(new CHOOSE_js_1.CHOOSE(), "return the value from the first matching boolean case", [ { label: "cases", documentation: "The candidate [condition, value] pairs to evaluate in order", }, { label: "defaultValue", documentation: "The fallback value when no case evaluates to true", }, ])); registerFunc(withDocumentation(new AT_js_1.AT(), "return the item at the specified index from an array or tuple", [ { label: "input", documentation: "The array or tuple to read from" }, { label: "index", documentation: "The zero-based index to read" }, ])); registerFunc(withDocumentation(new IF_js_1.IF(), "choose one of two or three values based on a boolean or logical condition", [ { label: "condition", documentation: "The condition to evaluate" }, { label: "thenValue", documentation: "The value returned when the condition is true", }, { label: "elseValue", documentation: "The value returned when the condition is false", }, { label: "unknownValue", documentation: "The value returned when a logical condition is unknown", }, ])); registerFunc(withDocumentation(new ROUND_js_1.ROUND(), "round a numeric value to the requested number of decimal places", [ { label: "input", documentation: "The numeric value to round" }, { label: "decimals", documentation: "The number of decimal places to keep", }, ])); registerFunc(documentAttributeAccessor("name", "read the name attribute from an IFC object")); registerFunc(documentAttributeAccessor("guid", "read the global identifier from an IFC object")); registerFunc(documentAttributeAccessor("ifcClass", "read the IFC class name from an IFC object")); registerFunc(documentAttributeAccessor("description", "read the description attribute from an IFC object")); registerFunc(withDocumentation(new AttributeAccessorFunction_js_1.AttributeAccessorFunction("value", Types_js_1.Types.or(Types_js_1.Type.STRING, Types_js_1.Type.NUMERIC, Types_js_1.Type.BOOLEAN, Types_js_1.Type.ARRAY)), "read the value of an IFC property object", [{ label: "object", documentation: "The IFC property object to read from" }])); registerFunc(withDocumentation(new PROPERTYSET_js_1.PROPERTYSET(), "resolve a property set on an IFC object", [ { label: "object", documentation: "The IFC object to inspect" }, { label: "name", documentation: "The name of the property set to resolve", }, ])); registerFunc(withDocumentation(new PROPERTY_js_1.PROPERTY(), "resolve a property on an IFC element, type object, or property set", [ { label: "object", documentation: "The IFC object to inspect" }, { label: "name", documentation: "The name of the property to resolve" }, ])); registerFunc(withDocumentation(new TYPE_js_1.TYPE(), "resolve the IFC type object of an element", [ { label: "object", documentation: "The IFC element to inspect" }, ])); registerFunc(withDocumentation(new NOT_js_1.NOT(), "negate a boolean or logical value", [ { label: "value", documentation: "The value to negate" }, ])); registerFunc(withDocumentation(new TOSTRING_js_1.TOSTRING(), "convert a value to its string representation", [{ label: "input", documentation: "The value to convert" }])); registerFunc(withDocumentation(new TONUMERIC_js_1.TONUMERIC(), "convert a value to a numeric representation", [{ label: "input", documentation: "The value to convert" }]), "TONUMBER"); registerFunc(withDocumentation(new TOBOOLEAN_js_1.TOBOOLEAN(), "convert a value to a boolean representation", [{ label: "input", documentation: "The value to convert" }])); registerFunc(withDocumentation(new TOLOGICAL_js_1.TOLOGICAL(), "convert a value to a logical representation that can be true, false, or unknown", [{ label: "input", documentation: "The value to convert" }]), "NOTFOUNDASUNKNOWN"); registerFunc(withDocumentation(new TOIFCDATE_js_1.TOIFCDATE(), "convert a value to an IFC date", [ { label: "input", documentation: "The value to convert" }, ])); registerFunc(withDocumentation(new TOIFCTIME_js_1.TOIFCTIME(), "convert a value to an IFC time", [ { label: "input", documentation: "The value to convert" }, ])); registerFunc(withDocumentation(new TOIFCDATETIME_js_1.TOIFCDATETIME(), "convert a value to an IFC date-time", [{ label: "input", documentation: "The value to convert" }])); registerFunc(withDocumentation(new TOIFCDURATION_js_1.TOIFCDURATION(), "convert a value to an IFC duration", [ { label: "input", documentation: "The value to convert" }, ])); registerFunc(withDocumentation(new TOIFCTIMESTAMP_js_1.TOIFCTIMESTAMP(), "convert a value to an IFC timestamp", [{ label: "input", documentation: "The value to convert" }])); registerFunc(withDocumentation(new ADDDURATION_js_1.ADDDURATION(), "add a duration to an IFC date-time or timestamp", [ { label: "pointInTime", documentation: "The IFC date-time or timestamp to shift", }, { label: "duration", documentation: "The duration to add" }, ])); registerFunc(withDocumentation(new TOLOWERCASE_js_1.TOLOWERCASE(), "convert a string to lowercase", [ { label: "input", documentation: "The string to transform" }, ])); registerFunc(withDocumentation(new TOUPPERCASE_js_1.TOUPPERCASE(), "convert a string to uppercase", [ { label: "input", documentation: "The string to transform" }, ])); registerFunc(withDocumentation(new SUBSTRING_js_1.SUBSTRING(), "extract a substring from a string", [ { label: "input", documentation: "The source string" }, { label: "from", documentation: "The inclusive start index" }, { label: "to", documentation: "The exclusive end index" }, ])); registerFunc(withDocumentation(new SPLIT_js_1.SPLIT(), "split a string into an array of substrings", [ { label: "input", documentation: "The source string" }, { label: "separator", documentation: "The separator string to split on" }, { label: "limit", documentation: "The maximum number of resulting items" }, ])); registerFunc(withDocumentation(new EXISTS_js_1.EXISTS(), "check whether an IFC reference can be resolved", [{ label: "object", documentation: "The IFC reference to test" }])); registerFunc(withDocumentation(new FuncBooleanBinary_js_1.FuncBooleanBinary("AND", "and"), "return true only when both inputs are true", [ { label: "left", documentation: "The left logical operand" }, { label: "right", documentation: "The right logical operand" }, ])); registerFunc(withDocumentation(new FuncBooleanBinary_js_1.FuncBooleanBinary("OR", "or"), "return true when at least one input is true", [ { label: "left", documentation: "The left logical operand" }, { label: "right", documentation: "The right logical operand" }, ])); registerFunc(withDocumentation(new FuncBooleanBinary_js_1.FuncBooleanBinary("XOR", "xor"), "return true when exactly one input is true", [ { label: "left", documentation: "The left logical operand" }, { label: "right", documentation: "The right logical operand" }, ])); registerFunc(withDocumentation(new FuncBooleanBinary_js_1.FuncBooleanBinary("IMPLIES", "implies"), "evaluate logical implication from left to right", [ { label: "left", documentation: "The premise" }, { label: "right", documentation: "The consequence" }, ])); registerFunc(withDocumentation(new EQUALS_js_1.EQUALS(), "compare two values for equality", [ { label: "left", documentation: "The left value to compare" }, { label: "right", documentation: "The right value to compare" }, ])); registerFunc(withDocumentation(new CompareMagnitudes_js_1.CompareMagnitudes("GREATERTHAN", (cmp) => cmp > 0), "return true when the left value is greater than the right value", [ { label: "left", documentation: "The left value to compare" }, { label: "right", documentation: "The right value to compare" }, ])); registerFunc(withDocumentation(new CompareMagnitudes_js_1.CompareMagnitudes("GREATERTHANOREQUAL", (cmp) => cmp >= 0), "return true when the left value is greater than or equal to the right value", [ { label: "left", documentation: "The left value to compare" }, { label: "right", documentation: "The right value to compare" }, ])); registerFunc(withDocumentation(new CompareMagnitudes_js_1.CompareMagnitudes("LESSTHAN", (cmp) => cmp < 0), "return true when the left value is less than the right value", [ { label: "left", documentation: "The left value to compare" }, { label: "right", documentation: "The right value to compare" }, ])); registerFunc(withDocumentation(new CompareMagnitudes_js_1.CompareMagnitudes("LESSTHANOREQUAL", (cmp) => cmp <= 0), "return true when the left value is less than or equal to the right value", [ { label: "left", documentation: "The left value to compare" }, { label: "right", documentation: "The right value to compare" }, ])); registerFunc(withDocumentation(new MatchesPattern_js_1.MatchesPattern("CONTAINS", true, false), "check whether the input contains a simple wildcard pattern", [ { label: "input", documentation: "The source string" }, { label: "pattern", documentation: "The wildcard pattern to search for" }, ])); registerFunc(withDocumentation(new MatchesPattern_js_1.MatchesPattern("MATCHES", true, true), "check whether the input fully matches a simple wildcard pattern", [ { label: "input", documentation: "The source string" }, { label: "pattern", documentation: "The wildcard pattern to match" }, ])); registerFunc(withDocumentation(new MatchesPattern_js_1.MatchesPattern("REGEXCONTAINS", false, false), "check whether the input contains a regular-expression match", [ { label: "input", documentation: "The source string" }, { label: "pattern", documentation: "The regular expression to search for", }, ])); registerFunc(withDocumentation(new MatchesPattern_js_1.MatchesPattern("REGEXMATCHES", false, true), "check whether the input fully matches a regular expression", [ { label: "input", documentation: "The source string" }, { label: "pattern", documentation: "The regular expression to match" }, ])); registerFunc(new ReplacePattern_js_1.ReplacePattern("REPLACE", true)); registerFunc(new ReplacePattern_js_1.ReplacePattern("REGEXREPLACE", false)); //# sourceMappingURL=IfcExpressionFunctions.js.map