onroute-policy-engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +49 -0
  2. package/dist/enum/facts.d.ts +5 -0
  3. package/dist/enum/facts.js +9 -0
  4. package/dist/enum/index.d.ts +5 -0
  5. package/dist/enum/index.js +13 -0
  6. package/dist/enum/permit-app-info.d.ts +10 -0
  7. package/dist/enum/permit-app-info.js +14 -0
  8. package/dist/enum/relative-position.d.ts +6 -0
  9. package/dist/enum/relative-position.js +10 -0
  10. package/dist/enum/validation-result-code.d.ts +6 -0
  11. package/dist/enum/validation-result-code.js +10 -0
  12. package/dist/enum/validation-result-type.d.ts +6 -0
  13. package/dist/enum/validation-result-type.js +10 -0
  14. package/dist/helper/facts.helper.d.ts +15 -0
  15. package/dist/helper/facts.helper.js +41 -0
  16. package/dist/helper/lists.helper.d.ts +11 -0
  17. package/dist/helper/lists.helper.js +22 -0
  18. package/dist/helper/rules-engine.helper.d.ts +10 -0
  19. package/dist/helper/rules-engine.helper.js +47 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.js +9 -0
  22. package/dist/policy-engine.d.ts +59 -0
  23. package/dist/policy-engine.js +108 -0
  24. package/dist/rule-operator/custom-operators.d.ts +3 -0
  25. package/dist/rule-operator/custom-operators.js +25 -0
  26. package/dist/types/commodity.d.ts +5 -0
  27. package/dist/types/commodity.js +2 -0
  28. package/dist/types/dimension-modifier.d.ts +9 -0
  29. package/dist/types/dimension-modifier.js +2 -0
  30. package/dist/types/facts.d.ts +10 -0
  31. package/dist/types/facts.js +2 -0
  32. package/dist/types/geographic-region.d.ts +4 -0
  33. package/dist/types/geographic-region.js +2 -0
  34. package/dist/types/identified-object.d.ts +4 -0
  35. package/dist/types/identified-object.js +2 -0
  36. package/dist/types/index.d.ts +14 -0
  37. package/dist/types/index.js +2 -0
  38. package/dist/types/permit-type.d.ts +11 -0
  39. package/dist/types/permit-type.js +2 -0
  40. package/dist/types/policy-definition.d.ts +13 -0
  41. package/dist/types/policy-definition.js +2 -0
  42. package/dist/types/region-size-override.d.ts +6 -0
  43. package/dist/types/region-size-override.js +2 -0
  44. package/dist/types/self-issuable.d.ts +3 -0
  45. package/dist/types/self-issuable.js +2 -0
  46. package/dist/types/size-dimension.d.ts +10 -0
  47. package/dist/types/size-dimension.js +2 -0
  48. package/dist/types/vehicle-category.d.ts +14 -0
  49. package/dist/types/vehicle-category.js +2 -0
  50. package/dist/types/vehicle-type.d.ts +15 -0
  51. package/dist/types/vehicle-type.js +2 -0
  52. package/dist/types/vehicle.d.ts +12 -0
  53. package/dist/types/vehicle.js +2 -0
  54. package/dist/types/weight-dimension.d.ts +19 -0
  55. package/dist/types/weight-dimension.js +2 -0
  56. package/dist/validation-result.d.ts +19 -0
  57. package/dist/validation-result.js +23 -0
  58. package/dist/validation-results.d.ts +28 -0
  59. package/dist/validation-results.js +63 -0
  60. package/package.json +76 -0
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ A JSON-based rules engine to validate onRouteBC permit applications against commercial vehicle policy.
2
+
3
+ ## Synopsis
4
+ ```orbc-policy-engine``` is a library designed to compare a commercial vehicle permit application against policy expressed in JSON format, and return a list of policy violations as well as other informational policy messages related to the permit.
5
+
6
+ ```orbc-policy-engine``` makes use of https://github.com/CacheControl/json-rules-engine for rules engine functionality. Complex rules are modeled by extending the core ```json-rules-engine``` operators and other capabilities.
7
+
8
+ ## Usage
9
+ ```js
10
+ import Policy from 'orbc-policy-engine';
11
+
12
+ // Instantiate a new Policy object
13
+ // policyConfiguration is a JSON object of type PolicyDefinition
14
+ const policy: Policy = new Policy(policyDefinition);
15
+
16
+ // Get list of all available permit types (ID and name)
17
+ const permitTypes: Map<string, string> = policy.getPermitTypes();
18
+
19
+ // Get list of all available commodities (ID and name)
20
+ const commodities: Map<string, string> = policy.getCommodities();
21
+
22
+ // Get list of all available power unit types
23
+ const powerUnits: Map<string, string> = policy.getPowerUnitTypes();
24
+
25
+ // Get list of all available trailer types
26
+ const trailers: Map<string, string> = policy.getTrailerTypes();
27
+
28
+ // Get list of all valid commodities for a given permit type
29
+ const commodities: Map<string, string> = policy.getCommodities(permitTypeId);
30
+
31
+ // Get list of all vehicle types valid to be added to a configuration,
32
+ // by permit type and commodity. Requires supplying the vehicles already
33
+ // added to the configuration, or empty array if starting from scratch
34
+ const allowableVehicles: Map<string, string> = policy.getAllowableVehicles(
35
+ permitTypeId,
36
+ commodityId,
37
+ currentConfiguration);
38
+
39
+ // Validate a permit application against policy
40
+ // permitApplication is a JSON object of type PermitApplication
41
+ // A PermitApplication is just the standard permitData object wrapped
42
+ // in an object with a permitType key. For example:
43
+ // {
44
+ // permitType: 'TROS',
45
+ // permitData: { ... }
46
+ // }
47
+ const results: ValidationResults = policy.validate(permitApplication);
48
+ ```
49
+
@@ -0,0 +1,5 @@
1
+ export declare enum PolicyFacts {
2
+ AllowedVehicles = "allowedVehicles",
3
+ DaysInPermitYear = "daysInPermitYear",
4
+ ValidationDate = "validationDate"
5
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PolicyFacts = void 0;
4
+ var PolicyFacts;
5
+ (function (PolicyFacts) {
6
+ PolicyFacts["AllowedVehicles"] = "allowedVehicles";
7
+ PolicyFacts["DaysInPermitYear"] = "daysInPermitYear";
8
+ PolicyFacts["ValidationDate"] = "validationDate";
9
+ })(PolicyFacts || (exports.PolicyFacts = PolicyFacts = {}));
@@ -0,0 +1,5 @@
1
+ export { PolicyFacts } from './facts';
2
+ export { PermitAppInfo } from './permit-app-info';
3
+ export { RelativePosition } from './relative-position';
4
+ export { ValidationResultCode } from './validation-result-code';
5
+ export { ValidationResultType } from './validation-result-type';
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationResultType = exports.ValidationResultCode = exports.RelativePosition = exports.PermitAppInfo = exports.PolicyFacts = void 0;
4
+ var facts_1 = require("./facts");
5
+ Object.defineProperty(exports, "PolicyFacts", { enumerable: true, get: function () { return facts_1.PolicyFacts; } });
6
+ var permit_app_info_1 = require("./permit-app-info");
7
+ Object.defineProperty(exports, "PermitAppInfo", { enumerable: true, get: function () { return permit_app_info_1.PermitAppInfo; } });
8
+ var relative_position_1 = require("./relative-position");
9
+ Object.defineProperty(exports, "RelativePosition", { enumerable: true, get: function () { return relative_position_1.RelativePosition; } });
10
+ var validation_result_code_1 = require("./validation-result-code");
11
+ Object.defineProperty(exports, "ValidationResultCode", { enumerable: true, get: function () { return validation_result_code_1.ValidationResultCode; } });
12
+ var validation_result_type_1 = require("./validation-result-type");
13
+ Object.defineProperty(exports, "ValidationResultType", { enumerable: true, get: function () { return validation_result_type_1.ValidationResultType; } });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This enum represents a subset of commonly-used paths and
3
+ * other information in permit applications which may be
4
+ * referenced from within source code.
5
+ */
6
+ export declare enum PermitAppInfo {
7
+ PermitStartDate = "permitData.startDate",
8
+ PermitDateFormat = "YYYY-MM-DD",
9
+ CompanyName = "permitData.companyName"
10
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PermitAppInfo = void 0;
4
+ /**
5
+ * This enum represents a subset of commonly-used paths and
6
+ * other information in permit applications which may be
7
+ * referenced from within source code.
8
+ */
9
+ var PermitAppInfo;
10
+ (function (PermitAppInfo) {
11
+ PermitAppInfo["PermitStartDate"] = "permitData.startDate";
12
+ PermitAppInfo["PermitDateFormat"] = "YYYY-MM-DD";
13
+ PermitAppInfo["CompanyName"] = "permitData.companyName";
14
+ })(PermitAppInfo || (exports.PermitAppInfo = PermitAppInfo = {}));
@@ -0,0 +1,6 @@
1
+ export declare enum RelativePosition {
2
+ Before = "before",
3
+ After = "after",
4
+ First = "first",
5
+ Last = "last"
6
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RelativePosition = void 0;
4
+ var RelativePosition;
5
+ (function (RelativePosition) {
6
+ RelativePosition["Before"] = "before";
7
+ RelativePosition["After"] = "after";
8
+ RelativePosition["First"] = "first";
9
+ RelativePosition["Last"] = "last";
10
+ })(RelativePosition || (exports.RelativePosition = RelativePosition = {}));
@@ -0,0 +1,6 @@
1
+ export declare enum ValidationResultCode {
2
+ PermitTypeUnknown = "permit-type-unknown",
3
+ FieldValidationError = "field-validation-error",
4
+ ConfigurationInvalid = "configuration-invalid",
5
+ GeneralResult = "general-result"
6
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationResultCode = void 0;
4
+ var ValidationResultCode;
5
+ (function (ValidationResultCode) {
6
+ ValidationResultCode["PermitTypeUnknown"] = "permit-type-unknown";
7
+ ValidationResultCode["FieldValidationError"] = "field-validation-error";
8
+ ValidationResultCode["ConfigurationInvalid"] = "configuration-invalid";
9
+ ValidationResultCode["GeneralResult"] = "general-result";
10
+ })(ValidationResultCode || (exports.ValidationResultCode = ValidationResultCode = {}));
@@ -0,0 +1,6 @@
1
+ export declare enum ValidationResultType {
2
+ Violation = "violation",
3
+ Requirement = "requirement",
4
+ Warning = "warning",
5
+ Information = "information"
6
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationResultType = void 0;
4
+ var ValidationResultType;
5
+ (function (ValidationResultType) {
6
+ ValidationResultType["Violation"] = "violation";
7
+ ValidationResultType["Requirement"] = "requirement";
8
+ ValidationResultType["Warning"] = "warning";
9
+ ValidationResultType["Information"] = "information";
10
+ })(ValidationResultType || (exports.ValidationResultType = ValidationResultType = {}));
@@ -0,0 +1,15 @@
1
+ import { Engine } from 'json-rules-engine';
2
+ import { PermitFacts } from 'onroute-policy-engine/types';
3
+ /**
4
+ * Adds runtime facts for the validation. For example, adds the
5
+ * validation date for comparison against startDate of the permit.
6
+ * @param engine json-rules-engine Engine instance to add facts to.
7
+ */
8
+ export declare function addRuntimeFacts(engine: Engine): void;
9
+ /**
10
+ * Flattens the permit application, using keys taken from the PermitFacts enum so
11
+ * the facts can be used more easily within validation rules.
12
+ * @param permitApplication Permit application object to flatten.
13
+ * @returns Flattened permit application object for validation.
14
+ */
15
+ export declare function transformPermitFacts(permitApplication: any): PermitFacts;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.transformPermitFacts = exports.addRuntimeFacts = void 0;
7
+ const dayjs_1 = __importDefault(require("dayjs"));
8
+ const flattie_1 = require("flattie");
9
+ const enum_1 = require("onroute-policy-engine/enum");
10
+ /**
11
+ * Adds runtime facts for the validation. For example, adds the
12
+ * validation date for comparison against startDate of the permit.
13
+ * @param engine json-rules-engine Engine instance to add facts to.
14
+ */
15
+ function addRuntimeFacts(engine) {
16
+ const today = (0, dayjs_1.default)().format(enum_1.PermitAppInfo.PermitDateFormat.toString());
17
+ engine.addFact(enum_1.PolicyFacts.ValidationDate.toString(), today);
18
+ // Will be either 365 or 366, for use when comparing against
19
+ // duration for 1 year permits.
20
+ engine.addFact(enum_1.PolicyFacts.DaysInPermitYear.toString(), async function (params, almanac) {
21
+ const startDate = await almanac.factValue(enum_1.PermitAppInfo.PermitStartDate.toString());
22
+ const dateFrom = (0, dayjs_1.default)(startDate, enum_1.PermitAppInfo.PermitDateFormat.toString());
23
+ return dateFrom.diff(dateFrom.add(1, 'year'), 'day');
24
+ });
25
+ }
26
+ exports.addRuntimeFacts = addRuntimeFacts;
27
+ /**
28
+ * Flattens the permit application, using keys taken from the PermitFacts enum so
29
+ * the facts can be used more easily within validation rules.
30
+ * @param permitApplication Permit application object to flatten.
31
+ * @returns Flattened permit application object for validation.
32
+ */
33
+ function transformPermitFacts(permitApplication) {
34
+ // Flatten the permit application so all properties can be accessed
35
+ // by key
36
+ const permitFacts = (0, flattie_1.flattie)(permitApplication);
37
+ // Add the app itself as a fact to be used by more complex rules
38
+ permitFacts.app = permitApplication;
39
+ return permitFacts;
40
+ }
41
+ exports.transformPermitFacts = transformPermitFacts;
@@ -0,0 +1,11 @@
1
+ import { IdentifiedObject } from 'onroute-policy-engine/types';
2
+ /**
3
+ * Extracts a map containing just the ID and name of each of the supplied
4
+ * identified objects.
5
+ * @param objects List of identified objects to extract id and name from.
6
+ * @param filter Optional list of IDs to constrain the map to. Only objects
7
+ * with an ID matching one of the elements in the filter will
8
+ * be returned. If no filter supplied, all objects will be returned.
9
+ * @returns Map of object ID to object name.
10
+ */
11
+ export declare function extractIdentifiedObjects(objects: Array<IdentifiedObject>, filter?: Array<string>): Map<string, string>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractIdentifiedObjects = void 0;
4
+ /**
5
+ * Extracts a map containing just the ID and name of each of the supplied
6
+ * identified objects.
7
+ * @param objects List of identified objects to extract id and name from.
8
+ * @param filter Optional list of IDs to constrain the map to. Only objects
9
+ * with an ID matching one of the elements in the filter will
10
+ * be returned. If no filter supplied, all objects will be returned.
11
+ * @returns Map of object ID to object name.
12
+ */
13
+ function extractIdentifiedObjects(objects, filter) {
14
+ const objectMap = new Map();
15
+ objects.forEach((o) => {
16
+ if (!filter || filter.includes(o.id)) {
17
+ objectMap.set(o.id, o.name);
18
+ }
19
+ });
20
+ return objectMap;
21
+ }
22
+ exports.extractIdentifiedObjects = extractIdentifiedObjects;
@@ -0,0 +1,10 @@
1
+ import { Engine } from 'json-rules-engine';
2
+ import { Policy } from 'onroute-policy-engine';
3
+ /**
4
+ * Creates a json-rules-engine Engine object for each permit type specified in
5
+ * the policy definition, added to a Map. All rules specific to each permit type
6
+ * will be added to the appropriate Engine instance.
7
+ * @param policy orbc-policy-engine Policy object containg current policy definition.
8
+ * @returns Map of json-rules-engines, one per permit type, keyed on permit type ID.
9
+ */
10
+ export declare function getRulesEngines(policy: Policy): Map<string, Engine>;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRulesEngines = void 0;
4
+ const json_rules_engine_1 = require("json-rules-engine");
5
+ const custom_operators_1 = require("../rule-operator/custom-operators");
6
+ const enum_1 = require("onroute-policy-engine/enum");
7
+ /**
8
+ * Gets a json-rules-engine with all onRouteBC custom operators added,
9
+ * and all policy rules that apply to all permit types added.
10
+ * @param policyDefinition The definition of policy to validate against.
11
+ * @returns json-rules-engine Engine instance.
12
+ */
13
+ function getEngine(policyDefinition) {
14
+ const engine = new json_rules_engine_1.Engine();
15
+ custom_operators_1.CustomOperators.forEach((o) => engine.addOperator(o));
16
+ policyDefinition.commonRules.forEach((r) => engine.addRule(r));
17
+ return engine;
18
+ }
19
+ /**
20
+ * Creates a json-rules-engine Engine object for each permit type specified in
21
+ * the policy definition, added to a Map. All rules specific to each permit type
22
+ * will be added to the appropriate Engine instance.
23
+ * @param policy orbc-policy-engine Policy object containg current policy definition.
24
+ * @returns Map of json-rules-engines, one per permit type, keyed on permit type ID.
25
+ */
26
+ function getRulesEngines(policy) {
27
+ var _a, _b;
28
+ const engineMap = new Map();
29
+ (_b = (_a = policy.policyDefinition) === null || _a === void 0 ? void 0 : _a.permitTypes) === null || _b === void 0 ? void 0 : _b.forEach((permitType) => {
30
+ var _a;
31
+ const engine = getEngine(policy.policyDefinition);
32
+ (_a = permitType.rules) === null || _a === void 0 ? void 0 : _a.forEach((r) => engine.addRule(r));
33
+ let allowedVehicles;
34
+ if (permitType.allowedVehicles && permitType.allowedVehicles.length > 0) {
35
+ allowedVehicles = permitType.allowedVehicles;
36
+ }
37
+ else {
38
+ // If no allowed vehicles are specified, none are permitted
39
+ allowedVehicles = [];
40
+ }
41
+ // Each permit type should have a list of allowed vehicles configured.
42
+ engine.addFact(enum_1.PolicyFacts.AllowedVehicles.toString(), allowedVehicles);
43
+ engineMap.set(permitType.id, engine);
44
+ });
45
+ return engineMap;
46
+ }
47
+ exports.getRulesEngines = getRulesEngines;
@@ -0,0 +1,3 @@
1
+ export { Policy } from './policy-engine';
2
+ export { ValidationResult } from './validation-result';
3
+ export { ValidationResults } from './validation-results';
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationResults = exports.ValidationResult = exports.Policy = void 0;
4
+ var policy_engine_1 = require("./policy-engine");
5
+ Object.defineProperty(exports, "Policy", { enumerable: true, get: function () { return policy_engine_1.Policy; } });
6
+ var validation_result_1 = require("./validation-result");
7
+ Object.defineProperty(exports, "ValidationResult", { enumerable: true, get: function () { return validation_result_1.ValidationResult; } });
8
+ var validation_results_1 = require("./validation-results");
9
+ Object.defineProperty(exports, "ValidationResults", { enumerable: true, get: function () { return validation_results_1.ValidationResults; } });
@@ -0,0 +1,59 @@
1
+ import { PolicyDefinition, PermitType } from 'onroute-policy-engine/types';
2
+ import { Engine } from 'json-rules-engine';
3
+ import { ValidationResults } from './validation-results';
4
+ /** Class representing commercial vehicle policy. */
5
+ export declare class Policy {
6
+ /** Object representation of policy definition and rules. */
7
+ policyDefinition: PolicyDefinition;
8
+ /**
9
+ * Map of json-rules-engine instances, one for each
10
+ * permit type defined in the permit definition. Keyed
11
+ * on permit type id.
12
+ */
13
+ rulesEngines: Map<string, Engine>;
14
+ /**
15
+ * Creates a new Policy object.
16
+ * @param definition Policy definition to validate permits against
17
+ */
18
+ constructor(definition: PolicyDefinition);
19
+ /**
20
+ * Validates a permit application against the policy definition.
21
+ * @param permit The permit application to validate against policy
22
+ * @returns Results of the validation of the permit application
23
+ */
24
+ validate(permit: any): Promise<ValidationResults>;
25
+ /**
26
+ * Gets a list of all configured permit types in the policy definition.
27
+ * @returns Map of permit type IDs to permit type names.
28
+ */
29
+ getPermitTypes(): Map<string, string>;
30
+ /**
31
+ * Gets a list of all configured geographic regions in the policy definition.
32
+ * @returns Map of geographic region IDs to region names.
33
+ */
34
+ getGeographicRegions(): Map<string, string>;
35
+ /**
36
+ * Gets a list of all configured commodities in the policy definition.
37
+ * @param permitTypeId Return only commodities valid for this permit type.
38
+ * If not supplied, return all commodities configured in policy. If permit
39
+ * type does not require commodity (e.g. 'TROS'), return all commodities.
40
+ * @returns Map of commodity IDs to commodity names.
41
+ */
42
+ getCommodities(permitTypeId?: string): Map<string, string>;
43
+ /**
44
+ * Gets a list of all configured power unit types in the policy definition.
45
+ * @returns Map of power unit type IDs to power unit type names.
46
+ */
47
+ getPowerUnitTypes(): Map<string, string>;
48
+ /**
49
+ * Gets a list of all configured trailer types in the policy definition.
50
+ * @returns Map of trailer type IDs to trailer type names.
51
+ */
52
+ getTrailerTypes(): Map<string, string>;
53
+ /**
54
+ * Gets a full PermitType definition by ID.
55
+ * @param type Type ID of the permit definition to return.
56
+ * @returns PermitType definition for the supplied ID.
57
+ */
58
+ getPermitTypeDefinition(type?: string): PermitType | null;
59
+ }
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Policy = void 0;
4
+ const lists_helper_1 = require("./helper/lists.helper");
5
+ const rules_engine_helper_1 = require("./helper/rules-engine.helper");
6
+ const validation_results_1 = require("./validation-results");
7
+ const validation_result_1 = require("./validation-result");
8
+ const facts_helper_1 = require("./helper/facts.helper");
9
+ const enum_1 = require("onroute-policy-engine/enum");
10
+ /** Class representing commercial vehicle policy. */
11
+ class Policy {
12
+ /**
13
+ * Creates a new Policy object.
14
+ * @param definition Policy definition to validate permits against
15
+ */
16
+ constructor(definition) {
17
+ this.policyDefinition = definition;
18
+ this.rulesEngines = (0, rules_engine_helper_1.getRulesEngines)(this);
19
+ }
20
+ /**
21
+ * Validates a permit application against the policy definition.
22
+ * @param permit The permit application to validate against policy
23
+ * @returns Results of the validation of the permit application
24
+ */
25
+ async validate(permit) {
26
+ const engine = this.rulesEngines.get(permit.permitType);
27
+ if (!engine) {
28
+ // If the permit type being validated has no configuration in the
29
+ // policy definition, there will be no engine for it. Return with
30
+ // a single violation result.
31
+ const validationResult = new validation_results_1.ValidationResults();
32
+ validationResult.violations.push(new validation_result_1.ValidationResult(enum_1.ValidationResultType.Violation, enum_1.ValidationResultCode.PermitTypeUnknown, `Permit type ${permit.permitType} unknown`));
33
+ return validationResult;
34
+ }
35
+ else {
36
+ // Add facts specific to this run of the validation (e.g. validation
37
+ // date for comparison against start date of the permit).
38
+ (0, facts_helper_1.addRuntimeFacts)(engine);
39
+ const permitFacts = (0, facts_helper_1.transformPermitFacts)(permit);
40
+ // Run the json-rules-engine against the permit facts
41
+ const engineResult = await engine.run(permitFacts);
42
+ // Wrap the json-rules-engine result in a ValidationResult object
43
+ return new validation_results_1.ValidationResults(engineResult);
44
+ }
45
+ }
46
+ /**
47
+ * Gets a list of all configured permit types in the policy definition.
48
+ * @returns Map of permit type IDs to permit type names.
49
+ */
50
+ getPermitTypes() {
51
+ const permitTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.permitTypes);
52
+ return permitTypes;
53
+ }
54
+ /**
55
+ * Gets a list of all configured geographic regions in the policy definition.
56
+ * @returns Map of geographic region IDs to region names.
57
+ */
58
+ getGeographicRegions() {
59
+ const geographicRegions = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.geographicRegions);
60
+ return geographicRegions;
61
+ }
62
+ /**
63
+ * Gets a list of all configured commodities in the policy definition.
64
+ * @param permitTypeId Return only commodities valid for this permit type.
65
+ * If not supplied, return all commodities configured in policy. If permit
66
+ * type does not require commodity (e.g. 'TROS'), return all commodities.
67
+ * @returns Map of commodity IDs to commodity names.
68
+ */
69
+ getCommodities(permitTypeId) {
70
+ const permitType = this.getPermitTypeDefinition(permitTypeId);
71
+ const commodities = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.commodities, permitType === null || permitType === void 0 ? void 0 : permitType.allowedCommodities);
72
+ return commodities;
73
+ }
74
+ /**
75
+ * Gets a list of all configured power unit types in the policy definition.
76
+ * @returns Map of power unit type IDs to power unit type names.
77
+ */
78
+ getPowerUnitTypes() {
79
+ const powerUnitTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.powerUnitTypes);
80
+ return powerUnitTypes;
81
+ }
82
+ /**
83
+ * Gets a list of all configured trailer types in the policy definition.
84
+ * @returns Map of trailer type IDs to trailer type names.
85
+ */
86
+ getTrailerTypes() {
87
+ const trailerTypes = (0, lists_helper_1.extractIdentifiedObjects)(this.policyDefinition.vehicleTypes.trailerTypes);
88
+ return trailerTypes;
89
+ }
90
+ /**
91
+ * Gets a full PermitType definition by ID.
92
+ * @param type Type ID of the permit definition to return.
93
+ * @returns PermitType definition for the supplied ID.
94
+ */
95
+ getPermitTypeDefinition(type) {
96
+ let permitType;
97
+ if (this.policyDefinition.permitTypes) {
98
+ permitType = this.policyDefinition.permitTypes.find((p) => p.id === type);
99
+ }
100
+ if (permitType) {
101
+ return permitType;
102
+ }
103
+ else {
104
+ return null;
105
+ }
106
+ }
107
+ }
108
+ exports.Policy = Policy;
@@ -0,0 +1,3 @@
1
+ import { Operator } from 'json-rules-engine';
2
+ declare const CustomOperators: Array<Operator>;
3
+ export { CustomOperators };
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CustomOperators = void 0;
7
+ const json_rules_engine_1 = require("json-rules-engine");
8
+ const enum_1 = require("onroute-policy-engine/enum");
9
+ const dayjs_1 = __importDefault(require("dayjs"));
10
+ function stringValidator(a) {
11
+ return typeof a === 'string';
12
+ }
13
+ function dateStringValidator(a) {
14
+ const d = (0, dayjs_1.default)(a, enum_1.PermitAppInfo.PermitDateFormat.toString());
15
+ return d.isValid();
16
+ }
17
+ const CustomOperators = [];
18
+ exports.CustomOperators = CustomOperators;
19
+ CustomOperators.push(new json_rules_engine_1.Operator('stringMinimumLength', (a, b) => a.trim().length >= b, stringValidator));
20
+ CustomOperators.push(new json_rules_engine_1.Operator('dateLessThan', (a, b) => {
21
+ const firstDate = (0, dayjs_1.default)(a, enum_1.PermitAppInfo.PermitDateFormat.toString());
22
+ const secondDate = (0, dayjs_1.default)(b, enum_1.PermitAppInfo.PermitDateFormat.toString());
23
+ return firstDate.diff(secondDate) < 0;
24
+ }, dateStringValidator));
25
+ CustomOperators.push(new json_rules_engine_1.Operator('regex', (a, b) => RegExp(b).exec(a) !== null, stringValidator));
@@ -0,0 +1,5 @@
1
+ import { IdentifiedObject, PowerUnit, Trailer } from 'onroute-policy-engine/types';
2
+ export type Commodity = IdentifiedObject & {
3
+ powerUnits?: Array<PowerUnit>;
4
+ trailers?: Array<Trailer>;
5
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ import { SelfIssuable } from 'onroute-policy-engine/types';
2
+ export type DimensionModifier = SelfIssuable & {
3
+ position: string;
4
+ type?: string;
5
+ category?: string;
6
+ axles?: number;
7
+ minInterAxleSpacing?: number;
8
+ maxInterAxleSpacing?: number;
9
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ export type PermitFacts = {
2
+ companyName?: string;
3
+ duration?: number;
4
+ permitType?: string;
5
+ startDate?: string;
6
+ vehicleIdentificationNumber?: string;
7
+ vehiclePlate?: string;
8
+ vehicleType?: string;
9
+ app?: object;
10
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ import { IdentifiedObject } from 'onroute-policy-engine/types';
2
+ export type GeographicRegion = IdentifiedObject & {
3
+ description?: string;
4
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ export type IdentifiedObject = {
2
+ id: string;
3
+ name: string;
4
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ export { Commodity } from './commodity';
2
+ export { DimensionModifier } from './dimension-modifier';
3
+ export { PermitFacts } from './facts';
4
+ export { GeographicRegion } from './geographic-region';
5
+ export { IdentifiedObject } from './identified-object';
6
+ export { PermitType } from './permit-type';
7
+ export { PolicyDefinition } from './policy-definition';
8
+ export { RegionSizeOverride } from './region-size-override';
9
+ export { SelfIssuable } from './self-issuable';
10
+ export { SizeDimension } from './size-dimension';
11
+ export { VehicleCategory, PowerUnitCategory, TrailerCategory, VehicleCategories, } from './vehicle-category';
12
+ export { VehicleType, PowerUnitType, TrailerType, VehicleTypes, } from './vehicle-type';
13
+ export { Vehicle, PowerUnit, Trailer } from './vehicle';
14
+ export { WeightDimension, PowerUnitWeightDimension, TrailerWeightDimension, DefaultWeightDimensions, } from './weight-dimension';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ import { RuleProperties } from 'json-rules-engine';
2
+ import { IdentifiedObject } from 'onroute-policy-engine/types';
3
+ export type PermitType = IdentifiedObject & {
4
+ routingRequired: boolean;
5
+ weightDimensionRequired: boolean;
6
+ sizeDimensionRequired: boolean;
7
+ commodityRequired: boolean;
8
+ allowedVehicles: Array<string>;
9
+ allowedCommodities?: Array<string>;
10
+ rules?: Array<RuleProperties>;
11
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import { GeographicRegion, PermitType, DefaultWeightDimensions, VehicleTypes, Commodity, SizeDimension, VehicleCategories } from 'onroute-policy-engine/types';
2
+ import { RuleProperties } from 'json-rules-engine';
3
+ export type PolicyDefinition = {
4
+ version: string;
5
+ geographicRegions: Array<GeographicRegion>;
6
+ permitTypes: Array<PermitType>;
7
+ commonRules: Array<RuleProperties>;
8
+ globalWeightDefaults: DefaultWeightDimensions;
9
+ globalSizeDefaults: SizeDimension;
10
+ vehicleCategories: VehicleCategories;
11
+ vehicleTypes: VehicleTypes;
12
+ commodities: Array<Commodity>;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export type RegionSizeOverride = {
2
+ region: string;
3
+ width?: number;
4
+ height?: number;
5
+ length?: number;
6
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ export type SelfIssuable = {
2
+ canSelfIssue?: boolean;
3
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ import { DimensionModifier, RegionSizeOverride } from 'onroute-policy-engine/types';
2
+ export type SizeDimension = {
3
+ frontProjection: number;
4
+ rearProjection: number;
5
+ width: number;
6
+ height: number;
7
+ length: number;
8
+ modifiers?: Array<DimensionModifier>;
9
+ regions?: Array<RegionSizeOverride>;
10
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ import { IdentifiedObject, SizeDimension, PowerUnitWeightDimension, TrailerWeightDimension } from 'onroute-policy-engine/types';
2
+ export type VehicleCategory = IdentifiedObject & {
3
+ defaultSizeDimensions?: SizeDimension;
4
+ };
5
+ export type PowerUnitCategory = VehicleCategory & {
6
+ defaultWeightDimensions?: Array<PowerUnitWeightDimension>;
7
+ };
8
+ export type TrailerCategory = VehicleCategory & {
9
+ defaultWeightDimensions?: Array<TrailerWeightDimension>;
10
+ };
11
+ export type VehicleCategories = {
12
+ powerUnitCategories: Array<PowerUnitCategory>;
13
+ trailerCategories: Array<TrailerCategory>;
14
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,15 @@
1
+ import { IdentifiedObject, SizeDimension, PowerUnitWeightDimension, TrailerWeightDimension } from 'onroute-policy-engine/types';
2
+ export type VehicleType = IdentifiedObject & {
3
+ category: string;
4
+ defaultSizeDimensions?: SizeDimension;
5
+ };
6
+ export type PowerUnitType = VehicleType & {
7
+ defaultWeightDimensions?: Array<PowerUnitWeightDimension>;
8
+ };
9
+ export type TrailerType = VehicleType & {
10
+ defaultWeightDimensions?: Array<TrailerWeightDimension>;
11
+ };
12
+ export type VehicleTypes = {
13
+ powerUnitTypes: Array<PowerUnitType>;
14
+ trailerTypes: Array<TrailerType>;
15
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import { SizeDimension, PowerUnitWeightDimension, TrailerWeightDimension } from 'onroute-policy-engine/types';
2
+ export type Vehicle = {
3
+ type: string;
4
+ canFollow: Array<string>;
5
+ sizeDimensions?: Array<SizeDimension>;
6
+ };
7
+ export type PowerUnit = Vehicle & {
8
+ weightDimensions?: Array<PowerUnitWeightDimension>;
9
+ };
10
+ export type Trailer = Vehicle & {
11
+ weightDimensions?: Array<TrailerWeightDimension>;
12
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
1
+ import { DimensionModifier, SelfIssuable } from 'onroute-policy-engine/types';
2
+ export type WeightDimension = SelfIssuable & {
3
+ axles: number;
4
+ modifiers?: Array<DimensionModifier>;
5
+ };
6
+ export type PowerUnitWeightDimension = WeightDimension & {
7
+ saLegal?: number;
8
+ saPermittable?: number;
9
+ daLegal?: number;
10
+ daPermittable?: number;
11
+ };
12
+ export type TrailerWeightDimension = WeightDimension & {
13
+ legal?: number;
14
+ permittable?: number;
15
+ };
16
+ export type DefaultWeightDimensions = {
17
+ powerUnits: Array<PowerUnitWeightDimension>;
18
+ trailers: Array<TrailerWeightDimension>;
19
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Represents a single validation result when a permit application is
3
+ * validated against policy. A single validation run can result in multiple
4
+ * validation result messages.
5
+ */
6
+ export declare class ValidationResult {
7
+ /**
8
+ * Creates a new ValidationResult from the supplied type, code, and message.
9
+ *
10
+ * @param type type of result, one of the ValidationResultType enum
11
+ * @param code code for identifying common categories of results
12
+ * @param message text message describing the result
13
+ */
14
+ constructor(type: string, code: string, message: string);
15
+ type: string;
16
+ code: string;
17
+ message: string;
18
+ fieldReference?: string;
19
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationResult = void 0;
4
+ /**
5
+ * Represents a single validation result when a permit application is
6
+ * validated against policy. A single validation run can result in multiple
7
+ * validation result messages.
8
+ */
9
+ class ValidationResult {
10
+ /**
11
+ * Creates a new ValidationResult from the supplied type, code, and message.
12
+ *
13
+ * @param type type of result, one of the ValidationResultType enum
14
+ * @param code code for identifying common categories of results
15
+ * @param message text message describing the result
16
+ */
17
+ constructor(type, code, message) {
18
+ this.type = type;
19
+ this.code = code;
20
+ this.message = message;
21
+ }
22
+ }
23
+ exports.ValidationResult = ValidationResult;
@@ -0,0 +1,28 @@
1
+ import { EngineResult } from 'json-rules-engine';
2
+ import { ValidationResult } from './validation-result';
3
+ /** Represents the results of a permit application validation against policy */
4
+ export declare class ValidationResults {
5
+ /** Array of policy violations found during validation. */
6
+ violations: Array<ValidationResult>;
7
+ /**
8
+ * Array of additional requirements found during validation. For example,
9
+ * a permit may require that other additional permits be applied for in
10
+ * order to be legal.
11
+ */
12
+ requirements: Array<ValidationResult>;
13
+ /** Array of policy warnings found during validation. */
14
+ warnings: Array<ValidationResult>;
15
+ /**
16
+ * Array of policy messages found during validation. These should be
17
+ * considered informational only and do not impact the validity of the
18
+ * permit.
19
+ */
20
+ information: Array<ValidationResult>;
21
+ /**
22
+ * Creates a new ValidationResults from the json-rules-engine result.
23
+ * Populates the violations, requirements, warnings, and messages arrays
24
+ * based on the events in the json-rules-engine result.
25
+ * @param engineResult json-rules-engine run result.
26
+ */
27
+ constructor(engineResult?: EngineResult);
28
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationResults = void 0;
4
+ const validation_result_type_1 = require("./enum/validation-result-type");
5
+ const validation_result_code_1 = require("./enum/validation-result-code");
6
+ const validation_result_1 = require("./validation-result");
7
+ /** Represents the results of a permit application validation against policy */
8
+ class ValidationResults {
9
+ /**
10
+ * Creates a new ValidationResults from the json-rules-engine result.
11
+ * Populates the violations, requirements, warnings, and messages arrays
12
+ * based on the events in the json-rules-engine result.
13
+ * @param engineResult json-rules-engine run result.
14
+ */
15
+ constructor(engineResult) {
16
+ /** Array of policy violations found during validation. */
17
+ this.violations = [];
18
+ /**
19
+ * Array of additional requirements found during validation. For example,
20
+ * a permit may require that other additional permits be applied for in
21
+ * order to be legal.
22
+ */
23
+ this.requirements = [];
24
+ /** Array of policy warnings found during validation. */
25
+ this.warnings = [];
26
+ /**
27
+ * Array of policy messages found during validation. These should be
28
+ * considered informational only and do not impact the validity of the
29
+ * permit.
30
+ */
31
+ this.information = [];
32
+ if (engineResult) {
33
+ engineResult.events.forEach((e) => {
34
+ var _a, _b, _c, _d, _e, _f;
35
+ const message = (_b = (_a = e.params) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : `Unknown message: params=${JSON.stringify(e.params)}`;
36
+ const code = (_d = (_c = e.params) === null || _c === void 0 ? void 0 : _c.code) !== null && _d !== void 0 ? _d : validation_result_code_1.ValidationResultCode.GeneralResult;
37
+ const type = (_e = e.type) !== null && _e !== void 0 ? _e : validation_result_type_1.ValidationResultType.Violation.toString();
38
+ const result = new validation_result_1.ValidationResult(type, code, message);
39
+ result.fieldReference = (_f = e.params) === null || _f === void 0 ? void 0 : _f.fieldReference;
40
+ switch (type) {
41
+ case validation_result_type_1.ValidationResultType.Violation:
42
+ this.violations.push(result);
43
+ break;
44
+ case validation_result_type_1.ValidationResultType.Requirement:
45
+ this.requirements.push(result);
46
+ break;
47
+ case validation_result_type_1.ValidationResultType.Warning:
48
+ this.warnings.push(result);
49
+ break;
50
+ case validation_result_type_1.ValidationResultType.Information:
51
+ this.information.push(result);
52
+ break;
53
+ default:
54
+ // Treat any unknown validation event as a violation since
55
+ // it is an unexpected scenario.
56
+ console.log('Unknown validation event encountered');
57
+ this.violations.push(new validation_result_1.ValidationResult(validation_result_type_1.ValidationResultType.Violation, validation_result_code_1.ValidationResultCode.GeneralResult, 'Unknown validation event encountered'));
58
+ }
59
+ });
60
+ }
61
+ }
62
+ }
63
+ exports.ValidationResults = ValidationResults;
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "onroute-policy-engine",
3
+ "version": "0.1.0",
4
+ "description": "Policy Engine library for commercial vehicle permitting",
5
+ "main": "dist/index.js",
6
+ "exports": {
7
+ ".": "./dist/index.js",
8
+ "./types": "./dist/types/index.js",
9
+ "./enum": "./dist/enum/index.js"
10
+ },
11
+ "types": "dist/index.d.ts",
12
+ "private": false,
13
+ "scripts": {
14
+ "clean": "rimraf dist && rimraf -g *.tgz",
15
+ "test": "jest",
16
+ "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17
+ "format": "prettier --write \"src/**/*.ts\"",
18
+ "build": "tsc",
19
+ "clean-build": "rimraf dist && rimraf -g *.tgz && tsc"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/bcgov/onroutebc.git"
24
+ },
25
+ "author": "John Fletcher",
26
+ "license": "Apache-2.0",
27
+ "homepage": "https://github.com/bcgov/onroutebc#readme",
28
+ "devDependencies": {
29
+ "@types/jest": "^29.5.12",
30
+ "@typescript-eslint/eslint-plugin": "^7.5.0",
31
+ "eslint": "^8.57.0",
32
+ "eslint-config-prettier": "^9.1.0",
33
+ "jest": "^29.7.0",
34
+ "prettier": "^3.2.5",
35
+ "rimraf": "^5.0.7",
36
+ "ts-jest": "^29.1.2",
37
+ "typescript": "^5.4.3"
38
+ },
39
+ "dependencies": {
40
+ "dayjs": "^1.11.10",
41
+ "flattie": "^1.1.1",
42
+ "json-rules-engine": "^6.5.0"
43
+ },
44
+ "jest": {
45
+ "moduleFileExtensions": [
46
+ "js",
47
+ "json",
48
+ "ts"
49
+ ],
50
+ "rootDir": ".",
51
+ "roots": [
52
+ "<rootDir>/src"
53
+ ],
54
+ "moduleNameMapper": {
55
+ "^src/(.*)$": "<rootDir>/src/$1",
56
+ "^test/(.*)$": "<rootDir>/test/$1"
57
+ },
58
+ "testRegex": ".*\\.spec\\.ts$",
59
+ "transform": {
60
+ "^.+\\.ts$": "ts-jest"
61
+ },
62
+ "collectCoverage": true,
63
+ "collectCoverageFrom": [
64
+ "**/*.js"
65
+ ],
66
+ "coverageDirectory": "./coverage",
67
+ "coveragePathIgnorePatterns": [
68
+ "/node_modules/",
69
+ "/src/_test/",
70
+ ".enum.ts",
71
+ ".interface.ts",
72
+ "index.ts"
73
+ ],
74
+ "testEnvironment": "node"
75
+ }
76
+ }