diff --git a/packages/serverless-logic-web-tools/package.json b/packages/serverless-logic-web-tools/package.json index 999a1b09585..b23ea3c19e3 100644 --- a/packages/serverless-logic-web-tools/package.json +++ b/packages/serverless-logic-web-tools/package.json @@ -54,6 +54,7 @@ "@kie-tools/text-editor": "workspace:*", "@kie-tools/yard-editor": "workspace:*", "@kie-tools/yard-language-service": "workspace:*", + "@kie-tools/yard-validator": "workspace:*", "@octokit/plugin-rest-endpoint-methods": "^5.0.1", "@octokit/rest": "^18.5.3", "@patternfly/patternfly": "^4.224.2", diff --git a/packages/serverless-logic-web-tools/src/editor/EditorPage.tsx b/packages/serverless-logic-web-tools/src/editor/EditorPage.tsx index b1164c94008..f259600546b 100644 --- a/packages/serverless-logic-web-tools/src/editor/EditorPage.tsx +++ b/packages/serverless-logic-web-tools/src/editor/EditorPage.tsx @@ -71,7 +71,7 @@ export function EditorPage(props: Props) { const queryParams = useQueryParams(); const alertsDispatch = useGlobalAlertsDispatchContext(); - const notifications = useEditorNotifications({ + const { notifications, onLazyValidate } = useEditorNotifications({ webToolsEditor, content: lastContent.current, fileRelativePath: props.fileRelativePath, @@ -234,7 +234,11 @@ export function EditorPage(props: Props) { resolved={(file) => ( <> - + void; } const showWhenSmall: ToolbarItemProps["visibility"] = { @@ -938,6 +940,24 @@ If you are, it means that creating this Gist failed and it can safely be deleted ); }, [workspaces, props.workspaceFile, githubAuthInfo, comittingAlert, commitSuccessAlert]); + const validateDropdownItem = useMemo(() => { + return isOfKind("yard", props.workspaceFile.name) + ? [ + } + onClick={async () => { + props.onValidate(); + }} + description={"Run model validation"} + ouiaId={"commit-button"} + > + Validate + , + ] + : []; + }, [props]); + const pushSuccessAlert = useGlobalAlert( useCallback( ({ close }) => { @@ -1724,7 +1744,12 @@ If you are, it means that creating this Gist failed and it can safely be deleted , createSavePointDropdownItem]} + items={[ + deleteFileDropdownItem, + , + createSavePointDropdownItem, + ...validateDropdownItem, + ]} /> @@ -1735,6 +1760,7 @@ If you are, it means that creating this Gist failed and it can safely be deleted deleteFileDropdownItem, , createSavePointDropdownItem, + ...validateDropdownItem, , ...shareDropdownItems, ...(!canBeDeployed diff --git a/packages/serverless-logic-web-tools/src/editor/hooks/useEditorNotifications.tsx b/packages/serverless-logic-web-tools/src/editor/hooks/useEditorNotifications.tsx index e6d75a49367..220e9ac1e9c 100644 --- a/packages/serverless-logic-web-tools/src/editor/hooks/useEditorNotifications.tsx +++ b/packages/serverless-logic-web-tools/src/editor/hooks/useEditorNotifications.tsx @@ -33,12 +33,20 @@ interface HookArgs { export function useEditorNotifications(args: HookArgs) { const { webToolsEditor, content, fileRelativePath } = { ...args }; const [notifications, setNotifications] = useState([]); + const [lazyNotifications, setLazyNotifications] = useState([]); const editorDispatch = useEditorDispatch(); useEffect(() => { editorDispatch.setNotifications(notifications); }, [editorDispatch, notifications]); + const onLazyValidate = useCallback(async () => { + if (!webToolsEditor?.editor) { + return; + } + setLazyNotifications(await webToolsEditor.editor.validate()); + }, [webToolsEditor]); + useCancelableEffect( useCallback( ({ canceled }) => { @@ -70,13 +78,13 @@ export function useEditorNotifications(args: HookArgs) { }, } as Notification) ); - setNotifications(mappedDiagnostics); + setNotifications([...mappedDiagnostics, ...lazyNotifications]); }) .catch((e) => console.error(e)); }, - [content, fileRelativePath, webToolsEditor] + [content, fileRelativePath, webToolsEditor, lazyNotifications] ) ); - return notifications; + return { notifications, onLazyValidate }; } diff --git a/packages/serverless-logic-web-tools/webpack.config.ts b/packages/serverless-logic-web-tools/webpack.config.ts index 9d996a55205..7de03b0bad9 100644 --- a/packages/serverless-logic-web-tools/webpack.config.ts +++ b/packages/serverless-logic-web-tools/webpack.config.ts @@ -149,6 +149,10 @@ export default async (env: any, argv: any) => { to: "./dashbuilder-client", globOptions: { ignore: ["**/WEB-INF/**/*"] }, // "**/*.html" omitted because dashbuilder-client/index.html is needed }, + { + from: path.resolve(__dirname, "node_modules/@kie-tools/yard-validator/dist/yard-validator-worker.js"), + to: "./yard-validator-worker.js", + }, ], }), new ProvidePlugin({ diff --git a/packages/yard-editor/dev-webapp/webpack.config.js b/packages/yard-editor/dev-webapp/webpack.config.js index f03f967422a..168d29d76e0 100644 --- a/packages/yard-editor/dev-webapp/webpack.config.js +++ b/packages/yard-editor/dev-webapp/webpack.config.js @@ -46,6 +46,10 @@ module.exports = (env) => from: path.resolve(__dirname, "./static/envelope/yard-editor-envelope.html"), to: "./yard-editor-envelope.html", }, + { + from: path.resolve(__dirname, "../node_modules/@kie-tools/yard-validator/dist/yard-validator-worker.js"), + to: "./yard-validator-worker.js", + }, ], }), new MonacoWebpackPlugin({ diff --git a/packages/yard-editor/package.json b/packages/yard-editor/package.json index 9b989a3422c..1b1100d20d5 100644 --- a/packages/yard-editor/package.json +++ b/packages/yard-editor/package.json @@ -38,6 +38,7 @@ "@kie-tools-core/workspace": "workspace:*", "@kie-tools/i18n-common-dictionary": "workspace:*", "@kie-tools/yard-language-service": "workspace:*", + "@kie-tools/yard-validator": "workspace:*", "@patternfly/react-core": "^4.276.6", "@patternfly/react-icons": "^4.93.6", "@types/js-yaml": "^4.0.5", diff --git a/packages/yard-editor/src/editor/YardEditorView.tsx b/packages/yard-editor/src/editor/YardEditorView.tsx index f8059fa0214..6ebe4f89d1b 100644 --- a/packages/yard-editor/src/editor/YardEditorView.tsx +++ b/packages/yard-editor/src/editor/YardEditorView.tsx @@ -22,6 +22,7 @@ import * as React from "react"; import { YardEditor } from "./YardEditor"; import { YardEditorApi, YardEditorChannelApi } from "../api"; import { Position } from "monaco-editor"; +import { validationPromise } from "@kie-tools/yard-validator/dist/"; export class YardEditorView implements Editor { private readonly editorRef: React.RefObject; @@ -29,6 +30,7 @@ export class YardEditorView implements Editor { public af_isReact = true; public af_componentId: "yard-editor"; public af_componentTitle: "Yard Editor"; + private path: string; constructor( private readonly envelopeContext: KogitoEditorEnvelopeContextType, @@ -37,8 +39,8 @@ export class YardEditorView implements Editor { this.editorRef = React.createRef(); this.initArgs = initArgs; } - public setContent(path: string, content: string): Promise { + this.path = path; return this.editorRef.current!.setContent(path, content); } @@ -74,7 +76,22 @@ export class YardEditorView implements Editor { } public async validate(): Promise { - return this.editorRef.current!.validate(); + let result: Notification[] = []; + return this.editorRef + .current!.getContent() + .then((value) => { + return validationPromise(value); + }) + .then((value) => { + result = result.concat(value); + return this.editorRef.current!.validate(); + }) + .then((value) => { + result = result.concat(value); + return new Promise((resolve) => { + resolve(result); + }); + }); } public async setTheme(theme: EditorTheme) { diff --git a/packages/yard-model/LICENSE b/packages/yard-model/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/packages/yard-model/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/yard-model/env/index.js b/packages/yard-model/env/index.js new file mode 100644 index 00000000000..425fad9efe4 --- /dev/null +++ b/packages/yard-model/env/index.js @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env"); + +module.exports = composeEnv([require("@kie-tools/root-env/env")], { + vars: varsWithName({}), + get env() { + return { + yardModel: { + version: require("../package.json").version, + }, + }; + }, +}); diff --git a/packages/yard-model/install.js b/packages/yard-model/install.js new file mode 100644 index 00000000000..aa46eae8f39 --- /dev/null +++ b/packages/yard-model/install.js @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const buildEnv = require("./env"); +const { setup } = require("@kie-tools/maven-config-setup-helper"); + +setup(` + -Drevision=${buildEnv.env.yardModel.version} +`); diff --git a/packages/yard-model/package.json b/packages/yard-model/package.json new file mode 100644 index 00000000000..8ccb6117fdf --- /dev/null +++ b/packages/yard-model/package.json @@ -0,0 +1,48 @@ +{ + "private": false, + "name": "@kie-tools/yard-model", + "version": "0.0.0", + "description": "", + "license": "Apache-2.0", + "keywords": [], + "homepage": "https://github.com/kiegroup/kie-tools", + "repository": { + "type": "git", + "url": "https://github.com/kiegroup/kie-tools.git" + }, + "bugs": { + "url": "https://github.com/kiegroup/kie-tools/issues" + }, + "scripts": { + "build:dev": "run-script-os", + "build:dev:darwin:linux": "pnpm install:mvnw && mvn clean install -DskipTests", + "build:dev:win32": "pnpm install:mvnw && pnpm powershell \"mvn clean install `-DskipTests\"", + "build:prod": "pnpm lint && run-script-os", + "build:prod:darwin:linux": "pnpm install:mvnw && mvn clean install -DskipTests=$(build-env tests.run --not) -Dmaven.test.failure.ignore=$(build-env tests.ignoreFailures)", + "build:prod:win32": "pnpm install:mvnw && pnpm powershell \"mvn clean install `-DskipTests=$(build-env tests.run --not) `-Dmaven.test.failure.ignore=$(build-env tests.ignoreFailures)\"", + "install": "node install.js", + "install:mvnw": "run-script-os", + "install:mvnw:darwin:linux": "mvn wrapper:wrapper", + "install:mvnw:win32": "pnpm powershell \"mvn wrapper:wrapper\"", + "lint": "echo 'Linting'", + "powershell": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command" + }, + "dependencies": { + "@kie-tools-core/notifications": "workspace:*" + }, + "devDependencies": { + "@kie-tools/maven-config-setup-helper": "workspace:*", + "@kie-tools/root-env": "workspace:*", + "copy-webpack-plugin": "^11.0.0", + "rimraf": "^3.0.2", + "run-script-os": "^1.1.6", + "typescript": "^4.6.2", + "webpack": "^5.88.2" + }, + "kieTools": { + "requiredPreinstalledCliCommands": [ + "java", + "mvn" + ] + } +} \ No newline at end of file diff --git a/packages/yard-model/pom.xml b/packages/yard-model/pom.xml new file mode 100644 index 00000000000..3043f71efae --- /dev/null +++ b/packages/yard-model/pom.xml @@ -0,0 +1,97 @@ + + + + + 4.0.0 + org.kie.kogito + yard-model + ${revision} + + + + Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + 0.4 + 3.2.0 + 11 + 11 + UTF-8 + UTF-8 + + + + + org.treblereel.gwt.yaml.mapper + common + ${yaml.mapper} + + + + org.treblereel.gwt.yaml.mapper + processor + ${yaml.mapper} + provided + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${helper.maven.plugin} + + + add-source + generate-sources + + add-source + + + + target/generated-sources/annotations + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + diff --git a/packages/yard-model/src/main/java/org/yard/model/DecisionLogic.java b/packages/yard-model/src/main/java/org/yard/model/DecisionLogic.java new file mode 100644 index 00000000000..eca6770d609 --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/DecisionLogic.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + + +import org.treblereel.gwt.yaml.api.annotation.YamlSubtype; +import org.treblereel.gwt.yaml.api.annotation.YamlTypeInfo; + +@YamlTypeInfo( + key = "type", + value = { + @YamlSubtype(alias = "DecisionTable", type = DecisionTable.class), + @YamlSubtype(alias = "LiteralExpression", type = LiteralExpression.class) + }) +public interface DecisionLogic { +} diff --git a/packages/yard-model/src/main/java/org/yard/model/DecisionTable.java b/packages/yard-model/src/main/java/org/yard/model/DecisionTable.java new file mode 100644 index 00000000000..4513608cab0 --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/DecisionTable.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + + +import org.treblereel.gwt.yaml.api.annotation.YAMLMapper; +import org.treblereel.gwt.yaml.api.annotation.YamlTypeDeserializer; +import org.treblereel.gwt.yaml.api.annotation.YamlTypeSerializer; +import org.yard.model.RuleDefSerializer; + +import java.util.List; + +@YAMLMapper +public class DecisionTable implements DecisionLogic { + private List inputs; + private String hitPolicy = "ANY"; + @Deprecated + private List outputComponents; + @YamlTypeSerializer(RuleDefSerializer.class) + @YamlTypeDeserializer(RuleDefSerializer.class) + private List rules; + + public void setInputs(List inputs) { + this.inputs = inputs; + } + + public void setOutputComponents(List outputComponents) { + this.outputComponents = outputComponents; + } + + public List getInputs() { + return inputs; + } + + @Deprecated + public List getOutputComponents() { + return outputComponents; + } + + public String getHitPolicy() { + return hitPolicy; + } + + public void setHitPolicy(String hitPolicy) { + this.hitPolicy = hitPolicy; + } + + public List getRules() { + return rules; + } + + public void setRules(List rules) { + this.rules = rules; + } + +} \ No newline at end of file diff --git a/packages/yard-model/src/main/java/org/yard/model/Element.java b/packages/yard-model/src/main/java/org/yard/model/Element.java new file mode 100644 index 00000000000..7339d80039e --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/Element.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + + +import org.treblereel.gwt.yaml.api.annotation.YAMLMapper; + +import java.util.List; + +@YAMLMapper +public class Element { + + private String name; + private String type; + private List requirements; + private DecisionLogic logic; + + public void setName(String name) { + this.name = name; + } + + public void setType(String type) { + this.type = type; + } + + public void setRequirements(List requirements) { + this.requirements = requirements; + } + + public void setLogic(DecisionLogic logic) { + this.logic = logic; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public List getRequirements() { + return requirements; + } + + public DecisionLogic getLogic() { + return logic; + } +} \ No newline at end of file diff --git a/packages/yard-model/src/main/java/org/yard/model/InlineRule.java b/packages/yard-model/src/main/java/org/yard/model/InlineRule.java new file mode 100644 index 00000000000..59f2f2e45eb --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/InlineRule.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + +import java.util.List; + +public class InlineRule implements Rule { + + private final int rowNumber; + public List def; + + public InlineRule(int rowNumber, List data) { + this.rowNumber = rowNumber; + this.def = data; + } + + @Override + public int getRowNumber() { + return rowNumber; + } + + public List getDef() { + return def; + } + + public void setDef(List def) { + this.def = def; + } +} diff --git a/packages/yard-model/src/main/java/org/yard/model/Input.java b/packages/yard-model/src/main/java/org/yard/model/Input.java new file mode 100644 index 00000000000..2f25d7882aa --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/Input.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + + +import org.treblereel.gwt.yaml.api.annotation.YAMLMapper; + +@YAMLMapper +public class Input { + private String name; + private String type; + + public void setName(String name) { + this.name = name; + } + + public void setType(String type) { + this.type = type; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } +} \ No newline at end of file diff --git a/packages/yard-model/src/main/java/org/yard/model/LiteralExpression.java b/packages/yard-model/src/main/java/org/yard/model/LiteralExpression.java new file mode 100644 index 00000000000..160ed307540 --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/LiteralExpression.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + + +import org.treblereel.gwt.yaml.api.annotation.YAMLMapper; + +@YAMLMapper +public class LiteralExpression implements DecisionLogic { + private String expression; + + public void setExpression(String expression) { + this.expression = expression; + } + + public String getExpression() { + return expression; + } +} \ No newline at end of file diff --git a/packages/yard-model/src/main/java/org/yard/model/Operators.java b/packages/yard-model/src/main/java/org/yard/model/Operators.java new file mode 100644 index 00000000000..672eb3b0886 --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/Operators.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + +import java.util.Objects; + +/** + * Interface instead of enum due to possible custom operators. + */ +public interface Operators { + String NOT_EQUALS = "!="; + String EQUALS = "="; + String GREATER_OR_EQUAL = ">="; + String GREATER_THAN = ">"; + String LESS_OR_EQUAL = "<="; + String LESS_THAN = "<"; + + String[] ALL = {EQUALS, LESS_OR_EQUAL, LESS_THAN, GREATER_OR_EQUAL, GREATER_THAN, NOT_EQUALS}; + + static int compare(final String operator, + final String other) { + return getWeight(operator) - getWeight(other); + } + + static int getWeight(final String operator) { + for (int i = 0; i < ALL.length; i++) { + if (Objects.equals(operator, ALL[i])) { + return i; + } + } + return 0; + } +} diff --git a/packages/yard-model/src/main/java/org/yard/model/Rule.java b/packages/yard-model/src/main/java/org/yard/model/Rule.java new file mode 100644 index 00000000000..98944a05dbb --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/Rule.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + +public interface Rule { + int getRowNumber(); +} diff --git a/packages/yard-model/src/main/java/org/yard/model/RuleDefSerializer.java b/packages/yard-model/src/main/java/org/yard/model/RuleDefSerializer.java new file mode 100644 index 00000000000..2d984cf22bc --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/RuleDefSerializer.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + + +import org.treblereel.gwt.yaml.api.node.YamlMapping; +import org.treblereel.gwt.yaml.api.node.YamlNode; +import org.treblereel.gwt.yaml.api.node.YamlSequence; +import org.treblereel.gwt.yaml.api.YAMLDeserializer; +import org.treblereel.gwt.yaml.api.YAMLSerializer; +import org.treblereel.gwt.yaml.api.exception.YAMLDeserializationException; +import org.treblereel.gwt.yaml.api.internal.deser.YAMLDeserializationContext; +import org.treblereel.gwt.yaml.api.internal.ser.YAMLSerializationContext; + +import java.util.ArrayList; +import java.util.List; + +public class RuleDefSerializer + implements YAMLSerializer, YAMLDeserializer { + + private int rowNumber = 1; + @Override + public Object deserialize(YamlMapping yamlMapping, + String s, + YAMLDeserializationContext yamlDeserializationContext) throws YAMLDeserializationException { + return deserialize(yamlMapping.getNode(s), yamlDeserializationContext); + } + + @Override + public Object deserialize(YamlNode yamlNode, + YAMLDeserializationContext yamlDeserializationContext) { + if (yamlNode instanceof YamlSequence) { + final List items = getItems(yamlNode); + return new InlineRule(rowNumber++, items); + + } else if (yamlNode instanceof YamlMapping) { + final WhenThenRule whenThenRule = new WhenThenRule(rowNumber++); + final YamlNode when = ((YamlMapping) yamlNode).getNode("when"); + final YamlNode then = ((YamlMapping) yamlNode).getNode("then"); + whenThenRule.setWhen(getItems(when)); + whenThenRule.setThen(then.asScalar().value()); + return whenThenRule; + } + return new IllegalArgumentException("Unknown rule format."); + } + + private List getItems(final YamlNode yamlNode) { + final List result = new ArrayList<>(); + if (yamlNode instanceof YamlSequence) { + ((YamlSequence) yamlNode).iterator().forEachRemaining(x -> { + final Comparable value = (Comparable) x.asScalar().value(); + result.add(value); + }); + } + return result; + } + + @Override + public void serialize(YamlMapping yamlMapping, + String s, + Object objects, + YAMLSerializationContext yamlSerializationContext) { + // Not needed, we never serialize. + } + + @Override + public void serialize(YamlSequence yamlSequence, + Object objects, + YAMLSerializationContext yamlSerializationContext) { + // Not needed, we never serialize. + } +} diff --git a/packages/yard-model/src/main/java/org/yard/model/WhenThenRule.java b/packages/yard-model/src/main/java/org/yard/model/WhenThenRule.java new file mode 100644 index 00000000000..2293dadc7a6 --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/WhenThenRule.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + +import java.util.List; + +public class WhenThenRule implements Rule { + + private final int rowNumber; + private List when; + private Object then; + + public WhenThenRule(int rowNumber) { + this.rowNumber = rowNumber; + } + + @Override + public int getRowNumber() { + return rowNumber; + } + + public List getWhen() { + return when; + } + + public Object getThen() { + return then; + } + + public void setWhen(List when) { + this.when = when; + } + + public void setThen(Object then) { + this.then = then; + } +} diff --git a/packages/yard-model/src/main/java/org/yard/model/WhenThenRuleThenSerializer.java b/packages/yard-model/src/main/java/org/yard/model/WhenThenRuleThenSerializer.java new file mode 100644 index 00000000000..7debaed52e6 --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/WhenThenRuleThenSerializer.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + +import org.treblereel.gwt.yaml.api.YAMLDeserializer; +import org.treblereel.gwt.yaml.api.YAMLSerializer; +import org.treblereel.gwt.yaml.api.exception.YAMLDeserializationException; +import org.treblereel.gwt.yaml.api.internal.deser.YAMLDeserializationContext; +import org.treblereel.gwt.yaml.api.internal.ser.YAMLSerializationContext; +import org.treblereel.gwt.yaml.api.node.YamlMapping; +import org.treblereel.gwt.yaml.api.node.YamlNode; +import org.treblereel.gwt.yaml.api.node.YamlSequence; + +import java.util.Locale; + +public class WhenThenRuleThenSerializer + implements YAMLSerializer, YAMLDeserializer { + @Override + public Object deserialize(YamlMapping yamlMapping, String key, YAMLDeserializationContext yamlDeserializationContext) throws YAMLDeserializationException { + return deserialize(yamlMapping.getNode(key), yamlDeserializationContext); + } + + @Override + public Object deserialize(YamlNode yamlNode, YAMLDeserializationContext yamlDeserializationContext) { + if (yamlNode == null || yamlNode.isEmpty()) { + return null; + } + return yamlNode.asScalar().value().toLowerCase(Locale.ROOT); + } + + @Override + public void serialize(YamlMapping yamlMapping, String s, Object o, YAMLSerializationContext yamlSerializationContext) { + // Not needed, we never serialize. + } + + @Override + public void serialize(YamlSequence yamlSequence, Object o, YAMLSerializationContext yamlSerializationContext) { + // Not needed, we never serialize. + } +} diff --git a/packages/yard-model/src/main/java/org/yard/model/YaRD.java b/packages/yard-model/src/main/java/org/yard/model/YaRD.java new file mode 100644 index 00000000000..254b5a2ca88 --- /dev/null +++ b/packages/yard-model/src/main/java/org/yard/model/YaRD.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.model; + + +import org.treblereel.gwt.yaml.api.annotation.YAMLMapper; + +import java.util.List; + +@YAMLMapper +public class YaRD { + + private String specVersion = "alpha"; + private String kind = "YaRD"; + private String name; + private String expressionLang; + private List inputs; + private List elements; + + public void setInputs(List inputs) { + this.inputs = inputs; + } + + public void setElements(List elements) { + this.elements = elements; + } + + public String getName() { + return name; + } + + public String getExpressionLang() { + return expressionLang; + } + + public void setExpressionLang(String expressionLang) { + this.expressionLang = expressionLang; + } + + public String getKind() { + return kind; + } + + public void setKind(String kind) { + this.kind = kind; + } + + public String getSpecVersion() { + return specVersion; + } + + public void setSpecVersion(String specVersion) { + this.specVersion = specVersion; + } + + public void setName(String name) { + this.name = name; + } + + public List getInputs() { + return inputs; + } + + public List getElements() { + return elements; + } +} \ No newline at end of file diff --git a/packages/yard-validator-worker/README.md b/packages/yard-validator-worker/README.md new file mode 100644 index 00000000000..fb332661efd --- /dev/null +++ b/packages/yard-validator-worker/README.md @@ -0,0 +1,22 @@ +## YARD validator + +###### Module for YARD (Yet Another Rule Definition) validation. + +### Description + +This module contains a standalone J2CL/Java module that can be used to validate YARD file. J2CL version is recommended +to be ran in a webworker due to the heavy load. + +There is a static test page at demo/demo.html. Build the project before running it. + +### Validation items currently covered + +- Subsumption, when one row "eats" another by covering the same constraints as the subsumed row. +- Redundant rows. Either the same result is duplicated or one row is useless. + +### Validation item ideas for future + +- Masked rows, when a row subsumes another, but also blocks the subsumed row from getting ever activated. +- Conflicting rows. Two rows return different results with overlapping or subsuming constraints. +- Overlapping rows. Two rows can be activated by the same data, but the rows do not subsume each other. +- Gaps between the rows diff --git a/packages/yard-validator-worker/demo/demo.html b/packages/yard-validator-worker/demo/demo.html new file mode 100644 index 00000000000..8b6863615ab --- /dev/null +++ b/packages/yard-validator-worker/demo/demo.html @@ -0,0 +1,72 @@ + + + + Example + + + + + + + + diff --git a/packages/yard-validator-worker/env/index.js b/packages/yard-validator-worker/env/index.js new file mode 100644 index 00000000000..26e1811bd5a --- /dev/null +++ b/packages/yard-validator-worker/env/index.js @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env"); + +module.exports = composeEnv([require("@kie-tools/root-env/env")], { + vars: varsWithName({}), + get env() { + return { + yardValidator: { + version: require("../package.json").version, + }, + }; + }, +}); diff --git a/packages/yard-validator-worker/install.js b/packages/yard-validator-worker/install.js new file mode 100644 index 00000000000..4247286a3fc --- /dev/null +++ b/packages/yard-validator-worker/install.js @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const buildEnv = require("./env"); +const { setup } = require("@kie-tools/maven-config-setup-helper"); + +setup(` + -Drevision=${buildEnv.env.yardValidator.version} +`); diff --git a/packages/yard-validator-worker/package.json b/packages/yard-validator-worker/package.json new file mode 100644 index 00000000000..023d2a6fdeb --- /dev/null +++ b/packages/yard-validator-worker/package.json @@ -0,0 +1,50 @@ +{ + "private": false, + "name": "@kie-tools/yard-validator-worker", + "version": "0.0.0", + "description": "", + "license": "Apache-2.0", + "keywords": [], + "homepage": "https://github.com/kiegroup/kie-tools", + "repository": { + "type": "git", + "url": "https://github.com/kiegroup/kie-tools.git" + }, + "bugs": { + "url": "https://github.com/kiegroup/kie-tools/issues" + }, + "scripts": { + "build:dev": "rimraf dist && run-script-os && pnpm copy:webworker", + "build:dev:darwin:linux": "pnpm install:mvnw && mvn clean install -DskipTests", + "build:dev:win32": "pnpm install:mvnw && pnpm powershell \"mvn clean install `-DskipTests\"", + "build:prod": "pnpm lint && run-script-os && pnpm copy:webworker", + "build:prod:darwin:linux": "pnpm install:mvnw && mvn clean install -DskipTests=$(build-env tests.run --not) -Dmaven.test.failure.ignore=$(build-env tests.ignoreFailures)", + "build:prod:win32": "pnpm install:mvnw && pnpm powershell \"mvn clean install `-DskipTests=$(build-env tests.run --not) `-Dmaven.test.failure.ignore=$(build-env tests.ignoreFailures)\"", + "copy:webworker": "copyfiles -f target/worker/yard-validator-worker/yard-validator-worker.js dist", + "install": "node install.js", + "install:mvnw": "run-script-os", + "install:mvnw:darwin:linux": "mvn wrapper:wrapper", + "install:mvnw:win32": "pnpm powershell \"mvn wrapper:wrapper\"", + "lint": "echo 'Linting'", + "powershell": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command" + }, + "dependencies": { + "@kie-tools-core/notifications": "workspace:*", + "@kie-tools/yard-model": "workspace:*" + }, + "devDependencies": { + "@kie-tools/maven-config-setup-helper": "workspace:*", + "@kie-tools/root-env": "workspace:*", + "@kie-tools/tsconfig": "workspace:*", + "copyfiles": "^2.4.1", + "rimraf": "^3.0.2", + "run-script-os": "^1.1.6", + "typescript": "^4.6.2" + }, + "kieTools": { + "requiredPreinstalledCliCommands": [ + "java", + "mvn" + ] + } +} \ No newline at end of file diff --git a/packages/yard-validator-worker/pom.xml b/packages/yard-validator-worker/pom.xml new file mode 100644 index 00000000000..05862b71835 --- /dev/null +++ b/packages/yard-validator-worker/pom.xml @@ -0,0 +1,105 @@ + + + + 4.0.0 + org.kie.kogito + yard-validator-worker + ${revision} + + + + Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + 0.4 + 2.0.10 + 3.8.1 + 11 + 11 + UTF-8 + UTF-8 + 3.0.0-M5 + 4.13.1 + 0.20 + 4.13.1 + + + + + org.treblereel.gwt.yaml.mapper + common + ${yaml.mapper} + + + + org.kie.kogito + yard-model + ${project.version} + + + org.kie.kogito + yard-model + ${project.version} + sources + + + + junit + junit + ${version.org.junit} + test + + + + + + + + ../src/main/resources + + + + + com.vertispan.j2cl + j2cl-maven-plugin + ${j2cl.maven.plugin.version} + + + + build + + + + + ${project.build.directory}/worker + ADVANCED + + + + + diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/CustomTreeSet.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/CustomTreeSet.java new file mode 100644 index 00000000000..58c9595f5ed --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/CustomTreeSet.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + +import org.yard.model.Operators; +import org.yard.validator.key.ColumnKey; +import org.yard.validator.key.Key; +import org.yard.validator.key.OperatorValueKey; + +import java.util.*; + +public class CustomTreeSet { + + private final TreeSet innerSet; + + private final Set equalColumns = new HashSet<>(); + + public CustomTreeSet() { + innerSet = new TreeSet<>(getComparator()); + } + + private static Comparator getComparator() { + return (a, b) -> { + final int compareResult = compareKeys(a, b); + if (compareResult == 0) { + if (a instanceof OperatorValueKey + && b instanceof OperatorValueKey) { + return Operators.compare( + ((OperatorValueKey) a).getOperator(), + ((OperatorValueKey) b).getOperator()); + } else { + throw new IllegalArgumentException("What? Looks like it was not an OperatorValueKey."); + } + } + return compareResult; + }; + } + + private static int compareKeys(final Key a, + final Key b) { + if (a.getParent() instanceof Comparable + && b.getParent() instanceof Comparable) { + return ((Comparable) a.getParent()).compareTo(b.getParent()); + } + return -1; + } + + public Set getEqualColumns() { + return equalColumns; + } + + public int getHash(final Set bundleKeys) { + int result = 0; + + // Inner HashMap would speed this up, but not sure if it is worth it. + // All the ParentKeys that we are looking for are like on the front of the list. + for (Key key : innerSet) { + if (bundleKeys.contains(key.getParent())) { + result = 31 * result + ((OperatorValueKey) key).getValue().hashCode(); + } + } + + return result; + } + + public boolean addAll(final CustomTreeSet c) { + if (c instanceof CustomTreeSet) { + equalColumns.addAll(((CustomTreeSet) c).equalColumns); + } + return innerSet.addAll(c.innerSet); + } + + public boolean add(final Key o) { + if (o instanceof OperatorValueKey) { + if (Objects.equals(Operators.EQUALS, ((OperatorValueKey) o).getOperator())) { + equalColumns.add((ColumnKey) o.getParent()); + } + } + return innerSet.add(o); + } + + public boolean isEmpty() { + return innerSet.isEmpty(); + } + + public int size() { + return innerSet.size(); + } + + public Key[] toArray(final Key[] keys) { + return innerSet.toArray(keys); + } + + @Override + public String toString() { + String result = ""; + + for (Key key : innerSet) { + result += key.toString(); + result += "\n"; + } + + return result; + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/Issue.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/Issue.java new file mode 100644 index 00000000000..8d11223369e --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/Issue.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + +import org.yard.validator.key.Location; + +import java.util.Arrays; + +public class Issue { + private String message; + private Location[] locations; + + public Issue(final String message, final Location... locations) { + this.message = message; + this.locations = locations; + } + + public Location[] getLocations() { + return locations; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "Issue{" + + "message='" + message + '\'' + + ", locations=" + Arrays.toString(locations) + + '}'; + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/Parser.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/Parser.java new file mode 100644 index 00000000000..6926262542a --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/Parser.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + +import org.yard.model.*; +import org.yard.validator.key.*; +import org.yard.validator.util.Date; +import org.yard.validator.util.Logger; + +import java.math.BigDecimal; +import java.util.*; + +public class Parser { + + private String hitPolicy; + + public ParserResult parse(final String yaml) { + + try { + + final YaRD model = new YaRD_YamlMapperImpl().read(yaml); + + Logger.log("YaRD model has been read."); + Logger.log("YaRD model name is " + model.getName()); + final TreeMap result + = visit(findTableStartRow(yaml), model); + + return new ParserResult(result, hitPolicy.toUpperCase()); + } catch (Exception e) { + Logger.log("Failed to parse YAML " + e.getMessage()); + return new ParserResult(Collections.emptyMap(), "ANY"); + } + + } + + private int findTableStartRow(final String yaml) { + final String[] split = yaml.split("\n"); + for (int i = 0; i < split.length; i++) { + final String trim = split[i].trim(); + if (Objects.equals("rules:", trim)) { + return i + 1; + } + } + return -1; + } + + private TreeMap visit( + final int rulesRow, + final YaRD yard) { + final TreeMap result = new TreeMap<>(); + for (final Element element : yard.getElements()) { + if (element.getLogic() instanceof DecisionTable) { + final DecisionTable dt = (DecisionTable) element.getLogic(); + + Logger.log("Hit policy is : " + hitPolicy); + hitPolicy = dt.getHitPolicy(); + + final List rules = dt.getRules(); + for (Rule rule : rules) { + final RowLocation location = new RowLocation( + rule.getRowNumber(), + rule.getRowNumber() + rulesRow); + if (rule instanceof WhenThenRule) { + final CustomTreeSet keys = getWhenThenKeys(dt, (WhenThenRule) rule, location); + if (!keys.isEmpty()) { + result.put(location, keys); + } + } else if (rule instanceof InlineRule) { + final CustomTreeSet keys = getInlineRuleKeys(dt, (InlineRule) rule, location); + if (!keys.isEmpty()) { + result.put(location, keys); + } + } + } + } + } + return result; + } + + private CustomTreeSet getInlineRuleKeys( + final DecisionTable dt, + final InlineRule rule, + final RowLocation location) { + final CustomTreeSet keys = new CustomTreeSet(); + int columnIndex = 0; + for (Object o : rule.getDef()) { + if (dt.getInputs().size() > columnIndex) { + final String input = dt.getInputs().get(columnIndex++); + final ColumnKey columnKey = new ColumnKey(input); + keys.addAll( + getKeys( + location, + o, + columnKey)); + } + } + return keys; + } + + private CustomTreeSet getWhenThenKeys(final DecisionTable dt, + final WhenThenRule r, + final RowLocation location) { + final CustomTreeSet keys = new CustomTreeSet(); + + int columnIndex = 0; + for (Object o : r.getWhen()) { + final String input = dt.getInputs().get(columnIndex++); + final ColumnKey columnKey = new ColumnKey(input); + keys.addAll( + getKeys( + location, + o, + columnKey)); + } + return keys; + } + + private CustomTreeSet getKeys(final RowLocation location, + final Object o, + final ColumnKey columnKey) { + final CustomTreeSet keys = new CustomTreeSet(); + if (o instanceof Comparable) { + if (isSplit(o)) { + final String text = (String) o; + final String start = text.substring(0, text.indexOf("..")); + final String end = text.substring(text.indexOf("..") + 2); + final String operatorStart = resolveToOperator(start.charAt(0)); + final String operatorEnd = resolveToOperator(end.charAt(end.length() - 1)); + final Comparable valueStart = testType(start.substring(1)); + final Comparable valueEnd = testType(end.substring(0, end.length() - 1)); + keys.add(new OperatorValueKey(location, columnKey, operatorStart, valueStart)); + keys.add(new OperatorValueKey(location, columnKey, operatorEnd, valueEnd)); + } else { + + final String operator = getOperator(o); + final Comparable value = getValue(o, operator); + + if (value == null) { + // no need to add nulls + } else if (operator == null) { + keys.add(new ObjectKey(location, columnKey, (Comparable) o)); + } else { + keys.add(new OperatorValueKey(location, columnKey, operator, value)); + } + } + } + return keys; + } + + private String resolveToOperator(final char c) { + switch (c) { + case '(': + return Operators.GREATER_THAN; + case ')': + return Operators.LESS_THAN; + case '[': + return Operators.GREATER_OR_EQUAL; + case ']': + return Operators.LESS_OR_EQUAL; + } + throw new IllegalStateException("Ranged operator unknown."); + } + + private boolean isSplit(final Object o) { + if (o instanceof String) { + return ((String) o).contains("..") && isRangeStart((String) o) && isRangeEnd((String) o); + } + return false; + } + + private boolean isRangeEnd(final String text) { + return text.endsWith(")") || text.endsWith("]"); + } + + private boolean isRangeStart(final String text) { + return text.startsWith("(") || text.startsWith("["); + } + + private Comparable getValue(final Object o, + final String operator) { + if (operator != null && o instanceof String) { + final String value = ((String) o).substring(operator.length()); + return testType(value); + } else if (operator == null && o instanceof String && Objects.equals("-", ((String) o).trim())) { + return null; + } + return testType(o); + } + + private Comparable testType(final Object o) { + if (o instanceof String) { + final String value = ((String) o).trim(); + try { + return new BigDecimal(value); + } catch (NumberFormatException e) { + // Was a nice try, but no luck. + } + try { + return new Date(value); + } catch (IllegalArgumentException e) { + // Was a nice try, but no luck. + } + return value; + } + return null; + } + + private String getOperator(final Object o) { + if (o instanceof String) { + final String text = (String) o; + for (final String operator : Operators.ALL) { + if (text.trim().startsWith(operator)) { + return operator; + } + } + } + + return null; // Null is fine + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/ParserResult.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/ParserResult.java new file mode 100644 index 00000000000..9a73de0ab34 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/ParserResult.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + +import org.yard.validator.key.RowLocation; + +import java.util.HashMap; +import java.util.Map; + +public class ParserResult { + + private final Map result; + private final String hitPolicy; + + public ParserResult( + final Map result, + final String hitPolicy + ) { + this.result = result; + this.hitPolicy = hitPolicy; + } + + public Map getResult() { + return result; + } + + public String getHitPolicy() { + return hitPolicy; + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/ReportBus.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/ReportBus.java new file mode 100644 index 00000000000..a1cb2f306f4 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/ReportBus.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + +public interface ReportBus { + public void report(final Issue issue); +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/YardValidator.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/YardValidator.java new file mode 100644 index 00000000000..8e3e409b3c5 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/YardValidator.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + +import jsinterop.annotations.JsConstructor; +import jsinterop.annotations.JsMethod; +import org.yard.validator.checks.Check; +import org.yard.validator.checks.CheckProducer; +import org.yard.validator.key.Location; +import org.yard.validator.key.RowLocation; +import org.yard.validator.runner.Runner; +import org.yard.validator.util.Callback; +import org.yard.validator.util.Logger; + +import java.util.*; +import java.util.stream.Collectors; + +public class YardValidator { + + private final ArrayList log = new ArrayList<>(); + private ParserResult parse; + + @JsConstructor + public YardValidator() { + } + + @JsMethod + public void setLogger(final Callback callback) { + Logger.startLogging(callback); + } + + private void init(final String yaml) { + + Logger.startLogging(s -> log.add("\"" + s + "\"")); + Logger.log("Starting validator"); + + parse = new Parser().parse(yaml); + } + + @JsMethod + public String validate(final String yaml) { + final ArrayList issues = new ArrayList<>(); + validate(yaml, issue -> { + final StringBuilder builder = new StringBuilder(); + builder.append("{\"issue\":\"" + issue.getMessage() + "\""); + builder.append(","); + builder.append("\"locations\":["); + + builder.append(Arrays.stream(issue.getLocations()).map(i -> { + final StringBuilder innerBuilder = new StringBuilder(); + innerBuilder.append("{"); + innerBuilder.append("\"rowInFile\":" + ((RowLocation) i).getActualRowNumberInFile() + ","); + innerBuilder.append("\"rowInTable\":" + ((RowLocation) i).getTableRowNumber()); + innerBuilder.append("}"); + return innerBuilder.toString(); + }).collect(Collectors.joining(", "))); + + builder.append("]}"); + issues.add(builder.toString()); + }); + return "{\"log\":[" + log.toArray().toString() + "],\"result\":[" + issues.stream().collect(Collectors.joining(",")) + "]}"; + } + + public void validate(final String yaml, final ReportBus bus) { + try { + init(yaml); + } catch (final Exception e) { + Logger.log("Failed to initialize: " + e.getMessage()); + } + + new Runner(bus).run(getChecks()); + } + + private List getChecks() { + if (Objects.equals("COLLECT", parse.getHitPolicy())) { + return Collections.emptyList(); + } else { + return CheckProducer.getChecks(parse); + } + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/app.js b/packages/yard-validator-worker/src/main/java/org/yard/validator/app.js new file mode 100644 index 00000000000..c0a5ab5805f --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/app.js @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +goog.module("org.yard.validator"); + +const YardValidator = goog.require("org.yard.validator.YardValidator"); + +const validator = new YardValidator(); + +self.addEventListener("message", (e) => { + if (e.data === "ENABLE_LOGGING") { + validator.setLogger((e) => { + self.postMessage("Log: " + e); + }); + self.postMessage("Log logger set up"); + } else { + self.postMessage(validator.validate(e.data)); + } +}); diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/Check.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/Check.java new file mode 100644 index 00000000000..170828f3939 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/Check.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.checks; + +import org.yard.validator.Issue; + +import java.util.Optional; + +public interface Check { + Optional check(); +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/CheckItem.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/CheckItem.java new file mode 100644 index 00000000000..9461fbb5c1e --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/CheckItem.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.checks; + +import org.yard.validator.CustomTreeSet; +import org.yard.validator.key.Key; +import org.yard.validator.key.Location; + +public class CheckItem { + private final int index; + private final Location location; + private final Key[] keys; + + public CheckItem(final int index, + final Location location, + final CustomTreeSet keys) { + + this.index = index; + this.location = location; + this.keys = keys.toArray(new Key[keys.size()]); + } + + public int getIndex() { + return index; + } + + public Location getLocation() { + return location; + } + + public Key[] getKeys() { + return keys; + } + + @Override + public String toString() { + return "CheckItem{" + + "location=" + location + + '}'; + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/CheckProducer.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/CheckProducer.java new file mode 100644 index 00000000000..876d9900b8f --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/CheckProducer.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.checks; + +import org.yard.validator.CustomTreeSet; +import org.yard.validator.ParserResult; +import org.yard.validator.key.ColumnKey; +import org.yard.validator.key.Location; +import org.yard.validator.key.RowLocation; +import org.yard.validator.util.Logger; + +import java.util.*; +import java.util.stream.Collectors; + +public class CheckProducer { + + public static List getChecks(final ParserResult parse) { + final List result = new ArrayList<>(); + try { + final Set bundleKeys = formBundleKeys(parse.getResult()); + final Map bundles = formBundles(parse.getResult(), bundleKeys); + + for (final RunBundle value : bundles.values()) { + result.addAll(getCheckList(parse.getHitPolicy(), value.getMap())); + } + + } catch (final Exception e) { + Logger.log("Failed to create checks: " + e.getMessage()); + } + return result; + } + + private static Set formBundleKeys(final Map parse) { + final Set result = new HashSet<>(); + for (final CustomTreeSet value : parse.values()) { + if (value != null) { + if (result.isEmpty()) { + result.addAll(value.getEqualColumns()); + } else { + final Set removeKeys = result.stream().filter(x -> !value.getEqualColumns().contains(x)).collect(Collectors.toSet()); + result.removeAll(removeKeys); + } + } + } + return result; + } + + private static Map formBundles(final Map parse, + final Set bundleKeys) { + final Map result = new HashMap<>(); + for (Map.Entry entry : parse.entrySet()) { + int hash = entry.getValue().getHash(bundleKeys); + if (!result.containsKey(hash)) { + result.put(hash, new RunBundle()); + } + result.get(hash).put(entry.getKey(), entry.getValue()); + } + return result; + } + + private static List getCheckList( + final String hitPolicy, + final Map parse) { + final List result = new ArrayList<>(); + + // Dual row + int locationIndex = 0; + final RowLocation[] locations = new RowLocation[parse.keySet().size()]; + for (RowLocation location : parse.keySet()) { + locations[locationIndex++] = location; + } + + for (int i = 0; i < parse.entrySet().size(); i++) { + for (int j = i; j < parse.entrySet().size(); j++) { + if (i == j) { + continue; + } + final RowLocation locationA = getHigher(locations, i, j); + final RowLocation locationB = getLower(locations, i, j); + + final CheckItem checkItemA = new CheckItem( + locationA.getTableRowNumber(), + locationA, + parse.get(locationA)); + final CheckItem checkItemB = new CheckItem( + locationB.getTableRowNumber(), + locationB, + parse.get(locationB)); + + result.add(new SubsumptionCheck( + hitPolicy, + checkItemA, + checkItemB)); + } + } + return result; + } + + private static RowLocation getHigher( + final RowLocation[] locations, + final int i, + final int j) { + if (locations[i].getTableRowNumber() > locations[j].getTableRowNumber()) { + return locations[i]; + } else { + return locations[j]; + } + } + + private static RowLocation getLower( + final RowLocation[] locations, + final int i, + final int j) { + if (locations[i].getTableRowNumber() < locations[j].getTableRowNumber()) { + return locations[i]; + } else { + return locations[j]; + } + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/RunBundle.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/RunBundle.java new file mode 100644 index 00000000000..cb3e852e8fa --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/RunBundle.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.checks; + +import org.yard.validator.CustomTreeSet; +import org.yard.validator.key.RowLocation; + +import java.util.HashMap; +import java.util.Map; + +public class RunBundle { + + private final Map map = new HashMap<>(); + + public Map getMap() { + return map; + } + + public void put(final RowLocation key, + final CustomTreeSet value) { + map.put(key, value); + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/SubsumptionCheck.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/SubsumptionCheck.java new file mode 100644 index 00000000000..01d2b43e2d5 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/checks/SubsumptionCheck.java @@ -0,0 +1,265 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.checks; + +import org.yard.validator.Issue; +import org.yard.validator.key.Key; +import org.yard.validator.key.KeyParent; +import org.yard.validator.key.OperatorValueKey; + +import java.util.Objects; +import java.util.Optional; + +import static org.yard.model.Operators.*; + +public class SubsumptionCheck + implements Check { + + private final String hitPolicy; + private final CheckItem checkItemA; + private final CheckItem checkItemB; + + public SubsumptionCheck( + final String hitPolicy, + final CheckItem checkItemA, + final CheckItem checkItemB) { + this.hitPolicy = hitPolicy; + this.checkItemA = checkItemA; + this.checkItemB = checkItemB; + } + + @Override + public Optional check() { + final Optional aToB = getIssue(checkItemA, checkItemB); + + if (isFirstHitPolicy()) { + if (aToB.isPresent()) { + // No need to check for redundancy. The first row masks the rest. + return Optional.of(new Issue( + "Masking row. The higher row prevents the activation of the other row.", + checkItemA.getLocation(), + checkItemB.getLocation())); + } else { + // No need to check the other row for subsumption, + // since subsumption is likely there by rule design + return Optional.empty(); + } + } else { + final Optional bToA = getIssue(checkItemB, checkItemA); + + // If the counterpart in the table is subsumptant, meaning the other item subsumes this, we have redundancy. + if (aToB.isPresent() && bToA.isPresent()) { + return Optional.of(new Issue( + getRedundancyMessage(), + checkItemA.getLocation(), + checkItemB.getLocation())); + } else if (aToB.isPresent()) { + return aToB; + } else { + return bToA; + } + } + } + + private String getRedundancyMessage() { + if (Objects.equals("UNIQUE", hitPolicy)) { + return "Redundancy found. Unique hit policy fails when more than one row returns results."; + } else { + return "Redundancy found. If both rows return the same result, the other can be removed. If they return different results, the table fails to return a value."; + } + } + + private String getSubsumptionMessage() { + if (Objects.equals("UNIQUE", hitPolicy)) { + return "Subsumption found. Unique hit policy fails when more than one row returns results."; + } else { + return "Subsumption found. If both rows return the same result, the other can be removed. If they return different results, the table fails to return a value."; + } + } + + private boolean isFirstHitPolicy() { + return Objects.equals("FIRST", hitPolicy) + // PRIORITY can not be set since the column header does not support listing it. + // For this reason it acts the same way as FIRST + || Objects.equals("PRIORITY", hitPolicy); + } + + private Optional getIssue( + final CheckItem checkItemA, + final CheckItem checkItemB) { + // All values and ranges in A are covered by B + int coveredBIndex = 0; + for (int aIndex = 0; aIndex < checkItemA.getKeys().length; aIndex++) { + final Key key = checkItemA.getKeys()[aIndex]; + final KeyParent parent = key.getParent(); + + for (int bIndex = coveredBIndex; bIndex < checkItemB.getKeys().length; bIndex++) { + try { + final Key other = findCounterPartParent(checkItemB, parent, bIndex); + coveredBIndex = bIndex + 1; + if (!subsumes((OperatorValueKey) key, (OperatorValueKey) other)) { + return Optional.empty(); + } + break; + } catch (NotFoundException e) { + // All good for now, the other has "any" marked for this parent. + } + } + } + return Optional.of( + new Issue( + getSubsumptionMessage(), + checkItemA.getLocation(), + checkItemB.getLocation())); + } + + private Key findCounterPartParent(final CheckItem checkItem, + final KeyParent parent, + final int i) throws NotFoundException { + if (checkItem.getKeys()[i].getParent().equals(parent)) { + return checkItem.getKeys()[i]; + } + throw new NotFoundException(); + } + + public boolean subsumes(final OperatorValueKey keyA, + final OperatorValueKey keyB) { + switch (keyA.getOperator()) { + case NOT_EQUALS: + switch (keyB.getOperator()) { + case NOT_EQUALS: + return valueIsEqualTo(keyA.getValue(), keyB.getValue()); + case EQUALS: + boolean valueIsEqualTo = valueIsEqualTo(keyA.getValue(), keyB.getValue()); + boolean covers = covers(keyA, keyB.getValue()); + return !valueIsEqualTo && !covers; + default: + return false; + } + case EQUALS: + switch (keyB.getOperator()) { + case NOT_EQUALS: + boolean valueIsEqualTo = valueIsEqualTo(keyA.getValue(), keyB.getValue()); + boolean covers = covers(keyA, keyB.getValue()); + return !valueIsEqualTo && !covers; + default: + return covers(keyA, keyB.getValue()); + } + case GREATER_OR_EQUAL: + switch (keyB.getOperator()) { + case GREATER_OR_EQUAL: + case GREATER_THAN: + return covers(keyA, keyB.getValue()); + case NOT_EQUALS: + return valueIsGreaterThan(keyA, keyB.getValue()); + default: + return false; + } + + case LESS_OR_EQUAL: + switch (keyB.getOperator()) { + case LESS_OR_EQUAL: + case LESS_THAN: + return covers(keyA, keyB.getValue()); + case NOT_EQUALS: + return valueIsLessThan(keyA, keyB.getValue()); + default: + return false; + } + case LESS_THAN: + switch (keyB.getOperator()) { + case LESS_OR_EQUAL: + return covers(keyA, keyB.getValue()); + case LESS_THAN: + case NOT_EQUALS: + return valueIsLessThanOrEqualTo(keyA, keyB.getValue()); + default: + return false; + } + case GREATER_THAN: + switch (keyB.getOperator()) { + case GREATER_OR_EQUAL: + return covers(keyA, keyB.getValue()); + case GREATER_THAN: + case NOT_EQUALS: + return valueIsGreaterThanOrEqualTo(keyA, keyB.getValue()); + default: + return false; + } + default: + return false; + } + } + + protected boolean valueIsEqualTo(final Comparable valueA, + final Comparable valueB) { + if (valueA == null) { + return valueB == null; + } else { + if (valueB == null) { + return false; + } else { + return valueA.compareTo(valueB) == 0; + } + } + } + + public boolean covers(final OperatorValueKey key, + final Comparable otherValue) { + switch (key.getOperator()) { + case EQUALS: + return valueIsEqualTo(key.getValue(), otherValue); + case NOT_EQUALS: + return !valueIsEqualTo(key.getValue(), otherValue); + case GREATER_OR_EQUAL: + return valueIsGreaterThanOrEqualTo(key, otherValue); + case LESS_OR_EQUAL: + return valueIsLessThanOrEqualTo(key, otherValue); + case LESS_THAN: + return valueIsLessThan(key, otherValue); + case GREATER_THAN: + return valueIsGreaterThan(key, otherValue); + default: + return false; + } + } + + protected boolean valueIsGreaterThanOrEqualTo(final OperatorValueKey key, + final Comparable otherValue) { + return valueIsEqualTo(key.getValue(), otherValue) || valueIsGreaterThan(key, otherValue); + } + + protected boolean valueIsLessThanOrEqualTo(final OperatorValueKey key, + final Comparable otherValue) { + return valueIsEqualTo(key.getValue(), otherValue) || valueIsLessThan(key, otherValue); + } + + protected boolean valueIsGreaterThan(final OperatorValueKey key, + final Comparable otherValue) { + return otherValue.compareTo(key.getValue()) > 0; + } + + protected boolean valueIsLessThan(final OperatorValueKey key, + final Comparable otherValue) { + return otherValue.compareTo(key.getValue()) < 0; + } + + private class NotFoundException extends Throwable { + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/ColumnKey.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/ColumnKey.java new file mode 100644 index 00000000000..dadc536d260 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/ColumnKey.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + + +import java.util.Objects; + +public class ColumnKey implements KeyParent, Comparable { + + private final String column; + + public ColumnKey(final String column) { + this.column = column; + } + + @Override + public String toString() { + return column; + } + + @Override + public int compareTo(final KeyParent o) { + if (o instanceof ColumnKey) { + return column.compareTo(((ColumnKey) o).column); + } else { + return -1; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ColumnKey columnKey = (ColumnKey) o; + return Objects.equals(column, columnKey.column); + } + + @Override + public int hashCode() { + return Objects.hash(column); + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/Key.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/Key.java new file mode 100644 index 00000000000..20f6aae98d4 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/Key.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + +/** + * The key, path down to field in DRL or DMN case. + */ +public interface Key { + + Location getLocation(); + + KeyParent getParent(); +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/KeyImpl.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/KeyImpl.java new file mode 100644 index 00000000000..ad473f9002d --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/KeyImpl.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + +public class KeyImpl implements Key { + + protected final Location location; + protected final KeyParent parent; + + public KeyImpl(final Location location, + final KeyParent parent) { + this.location = location; + this.parent = parent; + } + + @Override + public Location getLocation() { + return location; + } + + @Override + public KeyParent getParent() { + return parent; + } + + @Override + public String toString() { + return parent.toString(); + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/KeyParent.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/KeyParent.java new file mode 100644 index 00000000000..c30e707fceb --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/KeyParent.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + +/** + * Parent of the key. Everything leading to pattern for example: + * + * rule-activation-group-from-pattern + */ +public interface KeyParent { + +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/Location.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/Location.java new file mode 100644 index 00000000000..447a4257d89 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/Location.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + +/** + * Used to group keys and track the location of use. + */ +public interface Location + extends Comparable{ + +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/ObjectKey.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/ObjectKey.java new file mode 100644 index 00000000000..9accc50ac16 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/ObjectKey.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + + +import org.yard.model.Operators; + +public class ObjectKey extends OperatorValueKey { + + public ObjectKey(final Location location, + final KeyParent parent, + final Comparable value) { + super(location, + parent, + Operators.EQUALS, + value); + } + + @Override + public String toString() { + return parent + " " + value; + } + +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/OperatorValueKey.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/OperatorValueKey.java new file mode 100644 index 00000000000..cbc27d3b8fe --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/OperatorValueKey.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + + +public class OperatorValueKey extends KeyImpl { + + private final String operator; + protected final Comparable value; + + public OperatorValueKey(final Location location, + final KeyParent parent, + final String operator, + final Comparable value) { + super(location, + parent ); + this.operator = operator; + this.value = value; + } + + public String getOperator() { + return operator; + } + + public Comparable getValue() { + return value; + } + + @Override + public String toString() { + return parent + " " + operator + " " + value; + } + +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/key/RowLocation.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/RowLocation.java new file mode 100644 index 00000000000..0baafe539e9 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/key/RowLocation.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.key; + +public class RowLocation implements Location { + + private final int actualRowNumberInFile; + final int tableRowNumber; + + public RowLocation(final int tableRowNumber, + final int actualRowNumberInFile) { + this.tableRowNumber = tableRowNumber; + this.actualRowNumberInFile = actualRowNumberInFile; + } + + public int getActualRowNumberInFile() { + return actualRowNumberInFile; + } + + public int getTableRowNumber() { + return tableRowNumber; + } + + @Override + public String toString() { + return "Table row " + tableRowNumber + " actual row " + actualRowNumberInFile; + } + + @Override + public int compareTo(final RowLocation o) { + return Integer.compare(tableRowNumber, o.tableRowNumber); + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/runner/Runner.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/runner/Runner.java new file mode 100644 index 00000000000..0f45e3839f4 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/runner/Runner.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.runner; + +import org.yard.validator.Issue; +import org.yard.validator.ReportBus; +import org.yard.validator.checks.Check; +import org.yard.validator.util.Logger; + +import java.util.List; +import java.util.Optional; + +public class Runner { + + private ReportBus reportBus; + + public Runner(ReportBus reportBus) { + this.reportBus = reportBus; + } + + public void run(final List checks) { + try { + + for (final Check check : checks) { + final Optional issue = check.check(); + issue.ifPresent(value -> reportBus.report(value)); + } + } catch (final Exception e) { + Logger.log("Failed to run checks: " + e.getMessage()); + } + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Callback.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Callback.java new file mode 100644 index 00000000000..02d6bc51a3a --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Callback.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.util; + +import jsinterop.annotations.JsFunction; + +@JsFunction +public interface Callback { + void callback(final String s); +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Date.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Date.java new file mode 100644 index 00000000000..71ef8229719 --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Date.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.util; + +/** + * Our own custom Date. + * We do not need all the features normal date has, just the ability to compare. + * This brings less trouble and dependencies for the J2CL. + */ +public class Date implements Comparable { + + private final String value; + private final int years; + private final int months; + private final int days; + + + public Date(final String value) { + this.value = value; + + final String[] split = value.split("-"); + // Format yyyy-MM-dd + try { + years = Integer.parseInt(split[0]); + months = Integer.parseInt(split[1]); + days = Integer.parseInt(split[2]); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(); + } + } + + @Override + public int compareTo(Object o) { + if (o instanceof Date) { + final Date other = (Date) o; + final int compareYears = Integer.compare(years, other.years); + if (compareYears == 0) { + final int compareMonths = Integer.compare(months, other.months); + if (compareMonths == 0) { + return Integer.compare(days, other.days); + } else { + return compareMonths; + } + } else { + return compareYears; + } + } else { + return -1; + } + } + + @Override + public String toString() { + return value; + } +} diff --git a/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Logger.java b/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Logger.java new file mode 100644 index 00000000000..16c2945192f --- /dev/null +++ b/packages/yard-validator-worker/src/main/java/org/yard/validator/util/Logger.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.util; + +import java.util.ArrayList; +import java.util.Collection; + +public class Logger { + + private static final Collection callbacks = new ArrayList<>(); + + public static void startLogging(final Callback callback) { + Logger.callbacks.add(callback); + } + + public static void log(final String s) { + for (Callback callback : callbacks) { + callback.callback(getTime() + " " + s); + } + } + + private static String getTime() { + return System.currentTimeMillis() + ""; + } +} diff --git a/packages/yard-validator-worker/src/test/java/org/yard/validator/ParserTest.java b/packages/yard-validator-worker/src/test/java/org/yard/validator/ParserTest.java new file mode 100644 index 00000000000..f608ca64565 --- /dev/null +++ b/packages/yard-validator-worker/src/test/java/org/yard/validator/ParserTest.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + + +import org.junit.Test; +import org.yard.validator.key.Key; +import org.yard.validator.key.Location; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.util.Map; +import java.util.Scanner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ParserTest { + + @Test + public void inlineRuleTest() throws IOException { + final String read = read("traffic-violation.yml"); + final ParserResult parse = new Parser().parse(read); + + + for (Location location : parse.getResult().keySet()) { + System.out.println(location); + + for (Key key : parse.getResult().get(location).toArray(new Key[parse.getResult().get(location).size()])) { + System.out.println(key); + } + } + assertEquals(4, parse.getResult().keySet().size()); + } + + @Test + public void whenThenRuleTest() throws IOException { + final String read = read("service-price.yml"); + final ParserResult parse = new Parser().parse(read); + + + for (Location location : parse.getResult().keySet()) { + System.out.println(location); + for (Key key : parse.getResult().get(location).toArray(new Key[parse.getResult().get(location).size()])) { + System.out.println(key); + } + } + assertEquals(4, parse.getResult().keySet().size()); + } + + private String read(final String name) throws FileNotFoundException { + final StringBuffer buffer = new StringBuffer(); + + final URL resource = ParserTest.class.getResource(name); + + final Scanner sc = new Scanner(new File(resource.getFile())); + + while (sc.hasNextLine()) { + buffer.append(sc.nextLine()); + buffer.append(System.lineSeparator()); + } + + return buffer.toString(); + } + +} \ No newline at end of file diff --git a/packages/yard-validator-worker/src/test/java/org/yard/validator/YardValidatorTest.java b/packages/yard-validator-worker/src/test/java/org/yard/validator/YardValidatorTest.java new file mode 100644 index 00000000000..6a8b259349d --- /dev/null +++ b/packages/yard-validator-worker/src/test/java/org/yard/validator/YardValidatorTest.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator; + +import org.junit.Test; +import org.yard.validator.key.Location; +import org.yard.validator.key.RowLocation; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.URL; +import java.util.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class YardValidatorTest { + + @Test + public void subsumption() throws FileNotFoundException { + final String read = read("subsumption.yml"); + final YardValidator validator = new YardValidator(); + + final List issues = new ArrayList<>(); + + validator.validate(read, issues::add); + + for (Issue issue : issues) { + System.out.println(issue.getMessage()); + } + + assertEquals(1, issues.size()); + assertIssue(issues.get(0), "Subsumption found. If both rows return the same result, the other can be removed. If they return different results, the table fails to return a value.", 2, 3); + + } + + @Test + public void subsumptionTheOtherWay() throws FileNotFoundException { + final String read = read("subsumption-the-other-way.yml"); + final YardValidator validator = new YardValidator(); + + final List issues = new ArrayList<>(); + + validator.validate(read, issues::add); + + for (Issue issue : issues) { + System.out.println(issue.getMessage()); + } + + assertEquals(1, issues.size()); + assertIssue(issues.get(0), "Subsumption found. If both rows return the same result, the other can be removed. If they return different results, the table fails to return a value.", 2, 3); + + } + + @Test + public void maskingRule() throws FileNotFoundException { + final String read = read("subsumption-the-other-way.yml", "First"); + final YardValidator validator = new YardValidator(); + + final List issues = new ArrayList<>(); + + validator.validate(read, issues::add); + + assertEquals(1, issues.size()); + assertIssue(issues.get(0), "Masking row. The higher row prevents the activation of the other row.", 2, 3); + } + + @Test + public void redundancy() throws FileNotFoundException { + final String read = read("redundancy.yml"); + final YardValidator validator = new YardValidator(); + + final List issues = new ArrayList<>(); + + validator.validate(read, issues::add); + + for (Issue issue : issues) { + System.out.println(issue.getMessage()); + } + + assertEquals(1, issues.size()); + assertIssue(issues.get(0), "Redundancy found. If both rows return the same result, the other can be removed. If they return different results, the table fails to return a value.", 1, 2); + } + + @Test + public void redundancyWithUniqueHP() throws FileNotFoundException { + final String read = read("redundancy.yml", "Unique"); + final YardValidator validator = new YardValidator(); + + final List issues = new ArrayList<>(); + + validator.validate(read, issues::add); + + for (Issue issue : issues) { + System.out.println(issue.getMessage()); + } + + assertEquals(1, issues.size()); + assertIssue(issues.get(0), "Redundancy found. Unique hit policy fails when more than one row returns results.", 1, 2); + } + private void assertIssue( + final Issue issue, + final String message, + final Integer... wantedRows) { + final List rows = Arrays.asList(wantedRows); + assertEquals(message, issue.getMessage()); + + for (Location location : issue.getLocations()) { + System.out.println(location); + } + + assertEquals(issue.getLocations().length, rows.size()); + for (Location location : issue.getLocations()) { + if (location instanceof RowLocation) { + assertTrue(rows.contains(((RowLocation) location).getTableRowNumber())); + } + } + } + + private String read(final String name) throws FileNotFoundException { + return read(name, null); + } + + private String read( + final String name, + final String hitPolicy) throws FileNotFoundException { + final StringBuilder buffer = new StringBuilder(); + + final URL resource = ParserTest.class.getResource(name); + + final Scanner sc = new Scanner(new File(resource.getFile())); + + while (sc.hasNextLine()) { + final String line = sc.nextLine(); + buffer.append(line); + buffer.append(System.lineSeparator()); + if (hitPolicy != null && line.trim().startsWith("outputComponents")) { + buffer.append(" hitPolicy: ").append(hitPolicy); + buffer.append(System.lineSeparator()); + } + } + + return buffer.toString(); + } +} \ No newline at end of file diff --git a/packages/yard-validator-worker/src/test/java/org/yard/validator/util/DateTest.java b/packages/yard-validator-worker/src/test/java/org/yard/validator/util/DateTest.java new file mode 100644 index 00000000000..8e86722dc40 --- /dev/null +++ b/packages/yard-validator-worker/src/test/java/org/yard/validator/util/DateTest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.yard.validator.util; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +@RunWith(Parameterized.class) +public class DateTest { + + private final String givenDateA; + private final String givenDateB; + private final int expectedNumber; + + public DateTest(final String givenDateA, + final String givenDateB, + final int expectedNumber) { + + this.givenDateA = givenDateA; + this.givenDateB = givenDateB; + this.expectedNumber = expectedNumber; + } + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + {"2000-10-30", "2000-10-30", 0}, + {"2000-10-30", "2000-10-31", -1}, + {"2000-10-31", "2000-10-30", 1}, + {"2000-10-30", "2000-11-30", -1}, + {"2000-11-30", "2000-10-30", 1}, + {"2000-10-30", "2001-10-30", -1}, + {"2001-10-30", "2000-10-30", 1} + }); + } + + @Test + public void test() { + assertEquals(expectedNumber, + new Date(givenDateA).compareTo( + new Date(givenDateB))); + + } +} \ No newline at end of file diff --git a/packages/yard-validator-worker/src/test/resources/org/yard/validator/redundancy.yml b/packages/yard-validator-worker/src/test/resources/org/yard/validator/redundancy.yml new file mode 100644 index 00000000000..ac98c5e21be --- /dev/null +++ b/packages/yard-validator-worker/src/test/resources/org/yard/validator/redundancy.yml @@ -0,0 +1,26 @@ +specVersion: alpha +kind: YaRD +name: "Traffic Violation" +expressionLang: alpha +inputs: + - name: "Driver" + type: "http://myapi.org/jsonSchema.json#Driver" + - name: "Violation" + type: "http://myapi.org/jsonSchema.json#Violation" +elements: + - name: "Fine" + type: Decision + requirements: ["Violation"] + logic: + type: DecisionTable + inputs: ["Violation.type", "Violation.Actual Speed - Violation.Speed Limit"] + outputComponents: ["Amount", "Points"] + rules: + - ['="speed"', "[10..30)", 500, 3] + - ['="speed"', "[10..30)", 500, 3] + - name: "Should the driver be suspended?" + type: Decision + requirements: ["Driver", "Fine"] + logic: + type: LiteralExpression + expression: 'if Driver.Points + Fine.Points >= 20 then "Yes" else "No"' diff --git a/packages/yard-validator-worker/src/test/resources/org/yard/validator/service-price.yml b/packages/yard-validator-worker/src/test/resources/org/yard/validator/service-price.yml new file mode 100644 index 00000000000..bd00ac3d73b --- /dev/null +++ b/packages/yard-validator-worker/src/test/resources/org/yard/validator/service-price.yml @@ -0,0 +1,24 @@ +specVersion: alpha +kind: YaRD +name: "BasePrice" +expressionLang: alpha +inputs: + - name: "Age" + type: date + - name: "Previous incidents?" + type: boolean +elements: + - name: "Base price" + type: Decision + logic: + type: DecisionTable + inputs: ["Age", "Previous incidents?"] + rules: + - when: ["<2017-09-07", false] + then: 800 + - when: ["<2017-09-07", true] + then: 1000 + - when: [">=2017-09-07", false] + then: 500 + - when: [">=2017-09-07", true] + then: 650 diff --git a/packages/yard-validator-worker/src/test/resources/org/yard/validator/subsumption-the-other-way.yml b/packages/yard-validator-worker/src/test/resources/org/yard/validator/subsumption-the-other-way.yml new file mode 100644 index 00000000000..38edae6a809 --- /dev/null +++ b/packages/yard-validator-worker/src/test/resources/org/yard/validator/subsumption-the-other-way.yml @@ -0,0 +1,29 @@ +specVersion: alpha +kind: YaRD +name: "Traffic Violation" +expressionLang: alpha +inputs: + - name: "Driver" + type: "http://myapi.org/jsonSchema.json#Driver" + - name: "Violation" + type: "http://myapi.org/jsonSchema.json#Violation" +elements: + - name: "Fine" + type: Decision + requirements: ["Violation"] + logic: + type: DecisionTable + inputs: ["Violation.type", "Violation.Actual Speed - Violation.Speed Limit"] + outputComponents: ["Amount", "Points"] + rules: + - ['="speed"', "[10..30)", 500, 3] + - ['="speed"', ">= 60", 1000, 7] + - ['="speed"', ">= 30", 1000, 7] + - ['="parking"', "-", 100, 1] + - ['="driving under the influence"', "-", 1000, 5] + - name: "Should the driver be suspended?" + type: Decision + requirements: ["Driver", "Fine"] + logic: + type: LiteralExpression + expression: 'if Driver.Points + Fine.Points >= 20 then "Yes" else "No"' diff --git a/packages/yard-validator-worker/src/test/resources/org/yard/validator/subsumption.yml b/packages/yard-validator-worker/src/test/resources/org/yard/validator/subsumption.yml new file mode 100644 index 00000000000..0eb20657f70 --- /dev/null +++ b/packages/yard-validator-worker/src/test/resources/org/yard/validator/subsumption.yml @@ -0,0 +1,29 @@ +specVersion: alpha +kind: YaRD +name: "Traffic Violation" +expressionLang: alpha +inputs: + - name: "Driver" + type: "http://myapi.org/jsonSchema.json#Driver" + - name: "Violation" + type: "http://myapi.org/jsonSchema.json#Violation" +elements: + - name: "Fine" + type: Decision + requirements: ["Violation"] + logic: + type: DecisionTable + inputs: ["Violation.type", "Violation.Actual Speed - Violation.Speed Limit"] + outputComponents: ["Amount", "Points"] + rules: + - ['="speed"', "[10..30)", 500, 3] + - ['="speed"', ">= 30", 1000, 7] + - ['="speed"', ">= 60", 1000, 7] + - ['="parking"', "-", 100, 1] + - ['="driving under the influence"', "-", 1000, 5] + - name: "Should the driver be suspended?" + type: Decision + requirements: ["Driver", "Fine"] + logic: + type: LiteralExpression + expression: 'if Driver.Points + Fine.Points >= 20 then "Yes" else "No"' diff --git a/packages/yard-validator-worker/src/test/resources/org/yard/validator/traffic-violation-empty-row.yml b/packages/yard-validator-worker/src/test/resources/org/yard/validator/traffic-violation-empty-row.yml new file mode 100644 index 00000000000..0eb20657f70 --- /dev/null +++ b/packages/yard-validator-worker/src/test/resources/org/yard/validator/traffic-violation-empty-row.yml @@ -0,0 +1,29 @@ +specVersion: alpha +kind: YaRD +name: "Traffic Violation" +expressionLang: alpha +inputs: + - name: "Driver" + type: "http://myapi.org/jsonSchema.json#Driver" + - name: "Violation" + type: "http://myapi.org/jsonSchema.json#Violation" +elements: + - name: "Fine" + type: Decision + requirements: ["Violation"] + logic: + type: DecisionTable + inputs: ["Violation.type", "Violation.Actual Speed - Violation.Speed Limit"] + outputComponents: ["Amount", "Points"] + rules: + - ['="speed"', "[10..30)", 500, 3] + - ['="speed"', ">= 30", 1000, 7] + - ['="speed"', ">= 60", 1000, 7] + - ['="parking"', "-", 100, 1] + - ['="driving under the influence"', "-", 1000, 5] + - name: "Should the driver be suspended?" + type: Decision + requirements: ["Driver", "Fine"] + logic: + type: LiteralExpression + expression: 'if Driver.Points + Fine.Points >= 20 then "Yes" else "No"' diff --git a/packages/yard-validator-worker/src/test/resources/org/yard/validator/traffic-violation.yml b/packages/yard-validator-worker/src/test/resources/org/yard/validator/traffic-violation.yml new file mode 100644 index 00000000000..452ff7505f4 --- /dev/null +++ b/packages/yard-validator-worker/src/test/resources/org/yard/validator/traffic-violation.yml @@ -0,0 +1,28 @@ +specVersion: alpha +kind: YaRD +name: "Traffic Violation" +expressionLang: alpha +inputs: + - name: "Driver" + type: "http://myapi.org/jsonSchema.json#Driver" + - name: "Violation" + type: "http://myapi.org/jsonSchema.json#Violation" +elements: + - name: "Fine" + type: Decision + requirements: ["Violation"] + logic: + type: DecisionTable + inputs: ["Violation.type", "Violation.Actual Speed - Violation.Speed Limit"] + outputComponents: ["Amount", "Points"] + rules: + - ['="speed"', "[10..30)", 500, 3] + - ['="speed"', ">= 30", 1000, 7] + - ['="parking"', "-", 100, 1] + - ['="driving under the influence"', "-", 1000, 5] + - name: "Should the driver be suspended?" + type: Decision + requirements: ["Driver", "Fine"] + logic: + type: LiteralExpression + expression: 'if Driver.Points + Fine.Points >= 20 then "Yes" else "No"' diff --git a/packages/yard-validator/README.md b/packages/yard-validator/README.md new file mode 100644 index 00000000000..5ecc889f2cb --- /dev/null +++ b/packages/yard-validator/README.md @@ -0,0 +1,8 @@ +## YARD validator + +###### Module for YARD (Yet Another Rule Definition) validation. + +### When used in an editor + +The TypeScript source provides methods for getting the reporting as VSCode compatible Notifications. +The webworker file needs to be included separately. diff --git a/packages/yard-validator/env/index.js b/packages/yard-validator/env/index.js new file mode 100644 index 00000000000..26e1811bd5a --- /dev/null +++ b/packages/yard-validator/env/index.js @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env"); + +module.exports = composeEnv([require("@kie-tools/root-env/env")], { + vars: varsWithName({}), + get env() { + return { + yardValidator: { + version: require("../package.json").version, + }, + }; + }, +}); diff --git a/packages/yard-validator/install.js b/packages/yard-validator/install.js new file mode 100644 index 00000000000..4247286a3fc --- /dev/null +++ b/packages/yard-validator/install.js @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const buildEnv = require("./env"); +const { setup } = require("@kie-tools/maven-config-setup-helper"); + +setup(` + -Drevision=${buildEnv.env.yardValidator.version} +`); diff --git a/packages/yard-validator/package.json b/packages/yard-validator/package.json new file mode 100644 index 00000000000..fb1bc88f4e2 --- /dev/null +++ b/packages/yard-validator/package.json @@ -0,0 +1,44 @@ +{ + "private": false, + "name": "@kie-tools/yard-validator", + "version": "0.0.0", + "description": "", + "license": "Apache-2.0", + "keywords": [], + "homepage": "https://github.com/kiegroup/kie-tools", + "repository": { + "type": "git", + "url": "https://github.com/kiegroup/kie-tools.git" + }, + "bugs": { + "url": "https://github.com/kiegroup/kie-tools/issues" + }, + "scripts": { + "build:dev": "rimraf dist && tsc -p tsconfig.json && pnpm copy:webworker", + "build:prod": "pnpm lint && tsc -p tsconfig.json && pnpm copy:webworker", + "copy:webworker": "copyfiles -f node_modules/@kie-tools/yard-validator-worker/dist/yard-validator-worker.js dist", + "install": "node install.js", + "install:mvnw": "run-script-os", + "lint": "echo 'Linting'", + "powershell": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command" + }, + "dependencies": { + "@kie-tools-core/notifications": "workspace:*", + "@kie-tools/yard-validator-worker": "workspace:*" + }, + "devDependencies": { + "@kie-tools/maven-config-setup-helper": "workspace:*", + "@kie-tools/root-env": "workspace:*", + "@kie-tools/tsconfig": "workspace:*", + "copyfiles": "^2.4.1", + "rimraf": "^3.0.2", + "run-script-os": "^1.1.6", + "typescript": "^4.6.2" + }, + "kieTools": { + "requiredPreinstalledCliCommands": [ + "java", + "mvn" + ] + } +} \ No newline at end of file diff --git a/packages/yard-validator/src/ValidationResult.ts b/packages/yard-validator/src/ValidationResult.ts new file mode 100644 index 00000000000..41ad01fb62a --- /dev/null +++ b/packages/yard-validator/src/ValidationResult.ts @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export interface ValidationResult { + log: string[]; + result: Result[]; +} + +export interface Result { + issue: string; + locations: Location[]; +} + +export interface Location { + rowInFile: number; + rowInTable: number; +} diff --git a/packages/yard-validator/src/index.ts b/packages/yard-validator/src/index.ts new file mode 100644 index 00000000000..6e2da143b33 --- /dev/null +++ b/packages/yard-validator/src/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from "./main"; diff --git a/packages/yard-validator/src/main.ts b/packages/yard-validator/src/main.ts new file mode 100644 index 00000000000..58c9fbccf6f --- /dev/null +++ b/packages/yard-validator/src/main.ts @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Notification } from "@kie-tools-core/notifications/dist/api"; +import { ValidationResult } from "./ValidationResult"; + +export function validationPromise(yaml: String): Promise { + return new Promise((resolve, reject) => { + const worker = new Worker("/yard-validator-worker.js"); + worker.postMessage(yaml); + worker.onmessage = (e) => { + const notifications: Notification[] = []; + + try { + const validationResult: ValidationResult = JSON.parse(e.data); + + for (const result of validationResult.result) { + for (const location of result.locations) { + notifications.push({ + path: "", + severity: "ERROR", + message: result.issue, + type: "PROBLEM", + position: { + startLineNumber: location.rowInFile, + startColumn: 0, + endLineNumber: 0, + endColumn: 0, + }, + }); + } + } + } catch (e) { + // We add nothing since json is malformed. + } + resolve(notifications); + worker.terminate(); + }; + }); +} diff --git a/packages/yard-validator/tsconfig.json b/packages/yard-validator/tsconfig.json new file mode 100644 index 00000000000..253b1749aac --- /dev/null +++ b/packages/yard-validator/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@kie-tools/tsconfig/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "include": ["./src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f7f6080bc9..48ebc73d56d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5409,7 +5409,7 @@ importers: version: 4.8.4 url-loader: specifier: ^4.1.1 - version: 4.1.1(webpack@5.88.2) + version: 4.1.1(file-loader@6.2.0)(webpack@5.88.2) webpack: specifier: ^5.88.2 version: 5.88.2(webpack-cli@4.10.0) @@ -5822,7 +5822,7 @@ importers: version: 4.1.1(file-loader@6.2.0)(webpack@5.88.2) webpack: specifier: ^5.88.2 - version: 5.88.2 + version: 5.88.2(webpack-cli@4.10.0) packages/playwright-base: devDependencies: @@ -6839,6 +6839,9 @@ importers: "@kie-tools/yard-language-service": specifier: workspace:* version: link:../yard-language-service + "@kie-tools/yard-validator": + specifier: workspace:* + version: link:../yard-validator "@octokit/plugin-rest-endpoint-methods": specifier: ^5.0.1 version: 5.0.1(@octokit/core@3.4.0) @@ -8643,10 +8646,10 @@ importers: version: 4.8.4 webpack: specifier: ^5.88.2 - version: 5.88.2 + version: 5.88.2(webpack-cli@4.10.0) webpack-dev-server: specifier: ^4.15.1 - version: 4.15.1(webpack@5.88.2) + version: 4.15.1(webpack-cli@4.10.0)(webpack@5.88.2) webpack-merge: specifier: ^5.9.0 version: 5.9.0 @@ -9529,7 +9532,7 @@ importers: version: 9.4.2(typescript@4.8.4)(webpack@5.88.2) webpack: specifier: ^5.88.2 - version: 5.88.2 + version: 5.88.2(webpack-cli@4.10.0) packages/workspace: dependencies: @@ -9882,6 +9885,9 @@ importers: "@kie-tools/yard-language-service": specifier: workspace:* version: link:../yard-language-service + "@kie-tools/yard-validator": + specifier: workspace:* + version: link:../yard-validator "@patternfly/react-core": specifier: ^4.276.6 version: 4.276.6(react-dom@17.0.2)(react@17.0.2) @@ -10074,6 +10080,96 @@ importers: specifier: ^4.6.2 version: 4.8.4 + packages/yard-model: + dependencies: + "@kie-tools-core/notifications": + specifier: workspace:* + version: link:../notifications + devDependencies: + "@kie-tools/maven-config-setup-helper": + specifier: workspace:* + version: link:../maven-config-setup-helper + "@kie-tools/root-env": + specifier: workspace:* + version: link:../root-env + copy-webpack-plugin: + specifier: ^11.0.0 + version: 11.0.0(webpack@5.88.2) + rimraf: + specifier: ^3.0.2 + version: 3.0.2 + run-script-os: + specifier: ^1.1.6 + version: 1.1.6 + typescript: + specifier: ^4.6.2 + version: 4.8.4 + webpack: + specifier: ^5.88.2 + version: 5.88.2(webpack-cli@4.10.0) + + packages/yard-validator: + dependencies: + "@kie-tools-core/notifications": + specifier: workspace:* + version: link:../notifications + "@kie-tools/yard-validator-worker": + specifier: workspace:* + version: link:../yard-validator-worker + devDependencies: + "@kie-tools/maven-config-setup-helper": + specifier: workspace:* + version: link:../maven-config-setup-helper + "@kie-tools/root-env": + specifier: workspace:* + version: link:../root-env + "@kie-tools/tsconfig": + specifier: workspace:* + version: link:../tsconfig + copyfiles: + specifier: ^2.4.1 + version: 2.4.1 + rimraf: + specifier: ^3.0.2 + version: 3.0.2 + run-script-os: + specifier: ^1.1.6 + version: 1.1.6 + typescript: + specifier: ^4.6.2 + version: 4.8.4 + + packages/yard-validator-worker: + dependencies: + "@kie-tools-core/notifications": + specifier: workspace:* + version: link:../notifications + "@kie-tools/yard-model": + specifier: workspace:* + version: link:../yard-model + devDependencies: + "@kie-tools/maven-config-setup-helper": + specifier: workspace:* + version: link:../maven-config-setup-helper + "@kie-tools/root-env": + specifier: workspace:* + version: link:../root-env + "@kie-tools/tsconfig": + specifier: workspace:* + version: link:../tsconfig + copyfiles: + specifier: ^2.4.1 + version: 2.4.1 + rimraf: + specifier: ^3.0.2 + version: 3.0.2 + run-script-os: + specifier: ^1.1.6 + version: 1.1.6 + typescript: + specifier: ^4.6.2 + version: 4.8.4 + packages/yard-vscode-extension: dependencies: "@kie-tools-core/backend": @@ -11080,7 +11176,7 @@ packages: "@babel/compat-data": 7.21.7 "@babel/core": 7.16.12 "@babel/helper-validator-option": 7.21.0 - browserslist: 4.21.5 + browserslist: 4.22.1 semver: 6.3.1 dev: true @@ -11094,7 +11190,7 @@ packages: "@babel/compat-data": 7.21.7 "@babel/core": 7.23.0 "@babel/helper-validator-option": 7.21.0 - browserslist: 4.21.5 + browserslist: 4.22.1 semver: 6.3.1 dev: true @@ -11108,7 +11204,7 @@ packages: "@babel/compat-data": 7.21.7 "@babel/core": 7.16.12 "@babel/helper-validator-option": 7.21.0 - browserslist: 4.21.5 + browserslist: 4.22.1 lru-cache: 5.1.1 semver: 6.3.1 dev: true @@ -11123,7 +11219,7 @@ packages: "@babel/compat-data": 7.21.7 "@babel/core": 7.18.10 "@babel/helper-validator-option": 7.21.0 - browserslist: 4.21.5 + browserslist: 4.22.1 lru-cache: 5.1.1 semver: 6.3.1 dev: true @@ -11138,7 +11234,7 @@ packages: "@babel/compat-data": 7.21.7 "@babel/core": 7.23.0 "@babel/helper-validator-option": 7.21.0 - browserslist: 4.21.5 + browserslist: 4.22.1 lru-cache: 5.1.1 semver: 6.3.1 dev: true @@ -23873,15 +23969,6 @@ packages: acorn: 8.10.0 dev: true - /acorn-import-assertions@1.9.0(acorn@8.8.2): - resolution: - { integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== } - peerDependencies: - acorn: ^8 - dependencies: - acorn: 8.8.2 - dev: true - /acorn-jsx@5.3.2(acorn@7.4.1): resolution: { integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== } @@ -24728,8 +24815,8 @@ packages: peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.21.5 - caniuse-lite: 1.0.30001486 + browserslist: 4.22.1 + caniuse-lite: 1.0.30001547 fraction.js: 4.2.0 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -25486,10 +25573,10 @@ packages: engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } hasBin: true dependencies: - caniuse-lite: 1.0.30001332 - electron-to-chromium: 1.4.107 + caniuse-lite: 1.0.30001547 + electron-to-chromium: 1.4.549 escalade: 3.1.1 - node-releases: 2.0.3 + node-releases: 2.0.13 picocolors: 1.0.0 dev: true @@ -25499,10 +25586,10 @@ packages: engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } hasBin: true dependencies: - caniuse-lite: 1.0.30001486 - electron-to-chromium: 1.4.388 - node-releases: 2.0.10 - update-browserslist-db: 1.0.11(browserslist@4.21.5) + caniuse-lite: 1.0.30001547 + electron-to-chromium: 1.4.549 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.21.5) dev: true /browserslist@4.22.1: @@ -25858,16 +25945,6 @@ packages: path-temp: 2.0.0 dev: true - /caniuse-lite@1.0.30001332: - resolution: - { integrity: sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw== } - dev: true - - /caniuse-lite@1.0.30001486: - resolution: - { integrity: sha512-uv7/gXuHi10Whlj0pp5q/tsK/32J2QSqVRKQhs2j8VsDCjgyruAh/eEXHF822VqO9yT6iZKw3nRwZRSPBE9OQg== } - dev: true - /caniuse-lite@1.0.30001547: resolution: { integrity: sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA== } @@ -26680,7 +26757,7 @@ packages: globby: 13.1.2 normalize-path: 3.0.0 schema-utils: 4.0.0 - serialize-javascript: 6.0.0 + serialize-javascript: 6.0.1 webpack: 5.76.1(esbuild@0.15.5) dev: true @@ -26696,7 +26773,7 @@ packages: globby: 13.1.2 normalize-path: 3.0.0 schema-utils: 4.0.0 - serialize-javascript: 6.0.0 + serialize-javascript: 6.0.1 webpack: 5.88.2(webpack-cli@4.10.0) dev: true @@ -26717,7 +26794,7 @@ packages: resolution: { integrity: sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g== } dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 semver: 7.0.0 dev: true @@ -26725,7 +26802,7 @@ packages: resolution: { integrity: sha512-nriW1nuJjUgvkEjIot1Spwakz52V9YkYHZAQG6A1eCgC8AA1p0zngrQEP9R0+V6hji5XilWKG1Bd0YRppmGimA== } dependencies: - browserslist: 4.21.5 + browserslist: 4.22.1 dev: true /core-js-compat@3.33.0: @@ -28265,16 +28342,6 @@ packages: jake: 10.8.7 dev: true - /electron-to-chromium@1.4.107: - resolution: - { integrity: sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg== } - dev: true - - /electron-to-chromium@1.4.388: - resolution: - { integrity: sha512-xZ0y4zjWZgp65okzwwt00f2rYibkFPHUv9qBz+Vzn8cB9UXIo9Zc6Dw81LJYhhNt0G/vR1OJEfStZ49NKl0YxQ== } - dev: true - /electron-to-chromium@1.4.549: resolution: { integrity: sha512-gpXfJslSi4hYDkA0mTLEpYKRv9siAgSUgZ+UWyk+J5Cttpd1ThCVwdclzIwQSclz3hYn049+M2fgrP1WpvF8xg== } @@ -28416,7 +28483,7 @@ packages: engines: { node: ">=10.13.0" } dependencies: graceful-fs: 4.2.11 - tapable: 2.2.0 + tapable: 2.2.1 dev: true /enhanced-resolve@5.9.3: @@ -28425,7 +28492,7 @@ packages: engines: { node: ">=10.13.0" } dependencies: graceful-fs: 4.2.11 - tapable: 2.2.0 + tapable: 2.2.1 dev: true /enquirer@2.3.6: @@ -30043,7 +30110,7 @@ packages: is-glob: 4.0.3 normalize-path: 3.0.0 schema-utils: 4.0.0 - webpack: 5.88.2 + webpack: 5.88.2(webpack-cli@4.10.0) dev: true /filename-reserved-regex@2.0.0: @@ -31439,7 +31506,7 @@ packages: html-minifier-terser: 6.1.0 lodash: 4.17.21 pretty-error: 4.0.0 - tapable: 2.2.0 + tapable: 2.2.1 webpack: 5.88.2(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0) dev: true @@ -33986,7 +34053,7 @@ packages: dependencies: glob: 7.2.0 minimatch: 3.0.5 - webpack: 5.88.2 + webpack: 5.88.2(webpack-cli@4.10.0) webpack-merge: 4.2.2 dev: true @@ -35890,21 +35957,11 @@ packages: webpack: 5.88.2(webpack-cli@4.10.0) dev: true - /node-releases@2.0.10: - resolution: - { integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== } - dev: true - /node-releases@2.0.13: resolution: { integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== } dev: true - /node-releases@2.0.3: - resolution: - { integrity: sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw== } - dev: true - /node.extend@2.0.2: resolution: { integrity: sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ== } @@ -37629,7 +37686,7 @@ packages: "@csstools/postcss-trigonometric-functions": 1.0.2(postcss@8.4.16) "@csstools/postcss-unset-value": 1.0.2(postcss@8.4.16) autoprefixer: 10.4.14(postcss@8.4.16) - browserslist: 4.21.5 + browserslist: 4.22.1 css-blank-pseudo: 3.0.3(postcss@8.4.16) css-has-pseudo: 3.0.4(postcss@8.4.16) css-prefers-color-scheme: 6.0.3(postcss@8.4.16) @@ -39818,7 +39875,7 @@ packages: klona: 2.0.5 neo-async: 2.6.2 sass: 1.49.9 - webpack: 5.88.2 + webpack: 5.88.2(webpack-cli@4.10.0) dev: true /sass-loader@13.0.2(sass@1.54.4)(webpack@5.76.1): @@ -40510,7 +40567,7 @@ packages: abab: 2.0.5 iconv-lite: 0.6.3 source-map-js: 0.6.2 - webpack: 5.88.2 + webpack: 5.88.2(webpack-cli@4.10.0) dev: true /source-map-loader@4.0.0(webpack@5.76.1): @@ -42394,9 +42451,9 @@ packages: setimmediate: 1.0.5 dev: true - /update-browserslist-db@1.0.11(browserslist@4.21.5): + /update-browserslist-db@1.0.13(browserslist@4.21.5): resolution: - { integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== } + { integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== } hasBin: true peerDependencies: browserslist: ">= 4.21.0" @@ -42466,23 +42523,6 @@ packages: optional: true dependencies: file-loader: 6.2.0(webpack@5.88.2) - loader-utils: 2.0.2 - mime-types: 2.1.34 - schema-utils: 3.1.1 - webpack: 5.88.2 - dev: true - - /url-loader@4.1.1(webpack@5.88.2): - resolution: - { integrity: sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== } - engines: { node: ">= 10.13.0" } - peerDependencies: - file-loader: "*" - webpack: ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - file-loader: - optional: true - dependencies: loader-utils: 2.0.2 mime-types: 2.1.34 schema-utils: 3.1.1 @@ -43489,58 +43529,6 @@ packages: - utf-8-validate dev: true - /webpack-dev-server@4.15.1(webpack@5.88.2): - resolution: - { integrity: sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA== } - engines: { node: ">= 12.13.0" } - hasBin: true - peerDependencies: - webpack: ^4.37.0 || ^5.0.0 - webpack-cli: "*" - peerDependenciesMeta: - webpack: - optional: true - webpack-cli: - optional: true - dependencies: - "@types/bonjour": 3.5.10 - "@types/connect-history-api-fallback": 1.3.5 - "@types/express": 4.17.17 - "@types/serve-index": 1.9.1 - "@types/serve-static": 1.13.10 - "@types/sockjs": 0.3.33 - "@types/ws": 8.5.5 - ansi-html-community: 0.0.8 - bonjour-service: 1.1.1 - chokidar: 3.5.3 - colorette: 2.0.16 - compression: 1.7.4 - connect-history-api-fallback: 2.0.0 - default-gateway: 6.0.3 - express: 4.18.2 - graceful-fs: 4.2.11 - html-entities: 2.3.2 - http-proxy-middleware: 2.0.6(@types/express@4.17.17) - ipaddr.js: 2.0.1 - launch-editor: 2.6.0 - open: 8.4.0 - p-retry: 4.6.1 - rimraf: 3.0.2 - schema-utils: 4.0.0 - selfsigned: 2.1.1 - serve-index: 1.9.1 - sockjs: 0.3.24 - spdy: 4.0.2 - webpack: 5.88.2 - webpack-dev-middleware: 5.3.3(webpack@5.88.2) - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - dev: true - /webpack-hot-middleware@2.25.4: resolution: { integrity: sha512-IRmTspuHM06aZh98OhBJtqLpeWFM8FXJS5UYpKYxCJzyFoyWj1w6VGFfomZU7OPA55dMLrQK0pRT1eQ3PACr4w== } @@ -43625,7 +43613,7 @@ packages: "@webassemblyjs/wasm-parser": 1.11.1 acorn: 8.10.0 acorn-import-assertions: 1.9.0(acorn@8.10.0) - browserslist: 4.21.5 + browserslist: 4.22.1 chrome-trace-event: 1.0.2 enhanced-resolve: 5.15.0 es-module-lexer: 0.9.3 @@ -43638,7 +43626,7 @@ packages: mime-types: 2.1.34 neo-async: 2.6.2 schema-utils: 3.3.0 - tapable: 2.2.0 + tapable: 2.2.1 terser-webpack-plugin: 5.3.9(esbuild@0.15.5)(webpack@5.76.1) watchpack: 2.4.0 webpack-sources: 3.2.3 @@ -43648,47 +43636,6 @@ packages: - uglify-js dev: true - /webpack@5.88.2: - resolution: - { integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== } - engines: { node: ">=10.13.0" } - hasBin: true - peerDependencies: - webpack-cli: "*" - peerDependenciesMeta: - webpack-cli: - optional: true - dependencies: - "@types/eslint-scope": 3.7.3 - "@types/estree": 1.0.1 - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/wasm-edit": 1.11.6 - "@webassemblyjs/wasm-parser": 1.11.6 - acorn: 8.10.0 - acorn-import-assertions: 1.9.0(acorn@8.10.0) - browserslist: 4.21.5 - chrome-trace-event: 1.0.2 - enhanced-resolve: 5.15.0 - es-module-lexer: 1.3.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.2.0 - mime-types: 2.1.34 - neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.2.0 - terser-webpack-plugin: 5.3.9(webpack@5.88.2) - watchpack: 2.4.0 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - "@swc/core" - - esbuild - - uglify-js - dev: true - /webpack@5.88.2(@swc/core@1.3.92)(esbuild@0.18.20)(webpack-cli@4.10.0): resolution: { integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== } @@ -43747,8 +43694,8 @@ packages: "@webassemblyjs/ast": 1.11.6 "@webassemblyjs/wasm-edit": 1.11.6 "@webassemblyjs/wasm-parser": 1.11.6 - acorn: 8.8.2 - acorn-import-assertions: 1.9.0(acorn@8.8.2) + acorn: 8.10.0 + acorn-import-assertions: 1.9.0(acorn@8.10.0) browserslist: 4.21.5 chrome-trace-event: 1.0.2 enhanced-resolve: 5.15.0 @@ -44242,12 +44189,12 @@ packages: resolution: { integrity: sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== } engines: { node: ">=10" } + dev: true /yargs-parser@20.2.9: resolution: { integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== } engines: { node: ">=10" } - dev: true /yargs-parser@21.0.0: resolution: @@ -44294,7 +44241,7 @@ packages: require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 - yargs-parser: 20.2.7 + yargs-parser: 20.2.9 /yargs@17.3.1: resolution: diff --git a/repo/graph.dot b/repo/graph.dot index 96fc6b44942..0f74d578815 100644 --- a/repo/graph.dot +++ b/repo/graph.dot @@ -146,6 +146,9 @@ digraph G { "vscode-extension-kogito-bundle" [ color = "blue", fontcolor = "blue", style = "rounded" ]; "@kie-tools/xml-parser-ts" [ color = "blue", fontcolor = "blue", style = "rounded" ]; "@kie-tools/yard-language-service" [ color = "blue", fontcolor = "blue", style = "rounded" ]; + "@kie-tools/yard-validator" [ color = "blue", fontcolor = "blue", style = "rounded" ]; + "@kie-tools/yard-model" [ color = "blue", fontcolor = "blue", style = "rounded" ]; + "@kie-tools/yard-validator-worker" [ color = "blue", fontcolor = "blue", style = "rounded" ]; "yard-vscode-extension" [ color = "blue", fontcolor = "blue", style = "rounded" ]; "@kie-tools-scripts/build-env" [ color = "blue", fontcolor = "blue", style = "rounded" ]; "kie-tools-root" -> "@kie-tools-scripts/bootstrap" [ style = "dashed", color = "black" ]; @@ -479,8 +482,13 @@ digraph G { "@kie-tools/yard-editor" -> "@kie-tools-core/editor" [ style = "solid", color = "blue" ]; "@kie-tools/yard-editor" -> "@kie-tools/i18n-common-dictionary" [ style = "solid", color = "blue" ]; "@kie-tools/yard-editor" -> "@kie-tools/yard-language-service" [ style = "solid", color = "blue" ]; + "@kie-tools/yard-editor" -> "@kie-tools/yard-validator" [ style = "solid", color = "blue" ]; "@kie-tools/yard-editor" -> "@kie-tools-core/webpack-base" [ style = "dashed", color = "blue" ]; "@kie-tools/yard-language-service" -> "@kie-tools/json-yaml-language-service" [ style = "solid", color = "blue" ]; + "@kie-tools/yard-model" -> "@kie-tools-core/notifications" [ style = "solid", color = "blue" ]; + "@kie-tools/yard-model" -> "@kie-tools/maven-config-setup-helper" [ style = "dashed", color = "blue" ]; + "@kie-tools/yard-validator" -> "@kie-tools/yard-validator-worker" [ style = "solid", color = "blue" ]; + "@kie-tools/yard-validator-worker" -> "@kie-tools/yard-model" [ style = "solid", color = "blue" ]; "yard-vscode-extension" -> "@kie-tools-core/vscode-extension" [ style = "solid", color = "blue" ]; "yard-vscode-extension" -> "@kie-tools/yard-editor" [ style = "solid", color = "blue" ]; "yard-vscode-extension" -> "@kie-tools/vscode-extension-common-test-helpers" [ style = "dashed", color = "blue" ]; diff --git a/repo/graph.json b/repo/graph.json index a58c6365540..9a107df4aea 100644 --- a/repo/graph.json +++ b/repo/graph.json @@ -133,6 +133,7 @@ { "id": "@kie-tools/serverless-logic-web-tools-swf-builder-image-env" }, { "id": "@kie-tools/serverless-logic-web-tools-swf-dev-mode-image-env" }, { "id": "@kie-tools/yard-language-service" }, + { "id": "@kie-tools/yard-validator" }, { "id": "@kie-tools/serverless-logic-web-tools-base-builder-image" }, { "id": "@kie-tools/serverless-logic-web-tools-swf-builder-image" }, { "id": "sonataflow-deployment-webapp" }, @@ -146,6 +147,8 @@ { "id": "vscode-extension-dashbuilder-editor" }, { "id": "vscode-extension-kie-ba-bundle" }, { "id": "vscode-extension-kogito-bundle" }, + { "id": "@kie-tools/yard-validator-worker" }, + { "id": "@kie-tools/yard-model" }, { "id": "yard-vscode-extension" } ], "links": [ @@ -783,6 +786,7 @@ { "source": "@kie-tools/yard-editor", "target": "@kie-tools-core/editor", "weight": 1 }, { "source": "@kie-tools/yard-editor", "target": "@kie-tools/i18n-common-dictionary", "weight": 1 }, { "source": "@kie-tools/yard-editor", "target": "@kie-tools/yard-language-service", "weight": 1 }, + { "source": "@kie-tools/yard-editor", "target": "@kie-tools/yard-validator", "weight": 1 }, { "source": "@kie-tools/yard-editor", "target": "@kie-tools-core/webpack-base", "weight": 1 }, { "source": "@kie-tools/serverless-logic-web-tools-base-builder-image-env", @@ -800,6 +804,7 @@ "weight": 1 }, { "source": "@kie-tools/yard-language-service", "target": "@kie-tools/json-yaml-language-service", "weight": 1 }, + { "source": "@kie-tools/yard-validator", "target": "@kie-tools/yard-validator-worker", "weight": 1 }, { "source": "@kie-tools/serverless-logic-web-tools-base-builder-image", "target": "@kie-tools/serverless-logic-web-tools-base-builder-image-env", @@ -899,6 +904,9 @@ { "source": "vscode-extension-kogito-bundle", "target": "@kie-tools-core/webpack-base", "weight": 1 }, { "source": "vscode-extension-kogito-bundle", "target": "@kie-tools/eslint", "weight": 1 }, { "source": "vscode-extension-kogito-bundle", "target": "@kie-tools/tsconfig", "weight": 1 }, + { "source": "@kie-tools/yard-validator-worker", "target": "@kie-tools/yard-model", "weight": 1 }, + { "source": "@kie-tools/yard-model", "target": "@kie-tools-core/notifications", "weight": 1 }, + { "source": "@kie-tools/yard-model", "target": "@kie-tools/maven-config-setup-helper", "weight": 1 }, { "source": "yard-vscode-extension", "target": "@kie-tools-core/vscode-extension", "weight": 1 }, { "source": "yard-vscode-extension", "target": "@kie-tools/yard-editor", "weight": 1 }, { "source": "yard-vscode-extension", "target": "@kie-tools/vscode-extension-common-test-helpers", "weight": 1 } @@ -1068,6 +1076,9 @@ ["@kie-tools/yaml-language-server", "packages/yaml-language-server"], ["@kie-tools/yard-editor", "packages/yard-editor"], ["@kie-tools/yard-language-service", "packages/yard-language-service"], + ["@kie-tools/yard-model", "packages/yard-model"], + ["@kie-tools/yard-validator", "packages/yard-validator"], + ["@kie-tools/yard-validator-worker", "packages/yard-validator-worker"], ["yard-vscode-extension", "packages/yard-vscode-extension"], ["@kie-tools-scripts/bootstrap", "scripts/bootstrap"], ["@kie-tools-scripts/build-env", "scripts/build-env"],