Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
cd92dda
Add record to include syntax tree and diagnostics
Nuvindu Apr 7, 2025
52926d4
Ignore unnecessary spotbugs
Nuvindu Apr 7, 2025
8c7c2a0
Add method to generate syntax tree without imports
Nuvindu Apr 7, 2025
63ee785
Fix getting invalid types with the name anydata
Nuvindu Apr 7, 2025
8b57f07
Add new class for managing a context for syntax tree nodes
Nuvindu Apr 8, 2025
cf4314d
Add concrete methods for context class functions
Nuvindu Apr 8, 2025
cd0e3f0
Add enum for categorizing XSD components
Nuvindu Apr 8, 2025
52e2430
Add new class to represent a node in the syntax tree
Nuvindu Apr 8, 2025
40103e1
Add new record class to represent an XSD element
Nuvindu Apr 8, 2025
607351d
Add new record to contain generated response as a syntax tree
Nuvindu Apr 8, 2025
ee96aef
Move the response record to a separate package
Nuvindu Apr 8, 2025
9b54021
Add support to get syntax nodes from given syntax tree
Nuvindu Apr 8, 2025
18fd20e
Handle NPE when processing XSD elements
Nuvindu Apr 8, 2025
0e6203b
Fix not generating directories for a single XSD file
Nuvindu Apr 8, 2025
c356817
Refactor XSD Diagnostic class name
Nuvindu Apr 8, 2025
7543e35
Ignore unnecessary spotbugs
Nuvindu Apr 8, 2025
9f9ae35
Add new test case to validate having correct imports
Nuvindu Apr 8, 2025
f8320bf
Add new files as resources for test cases
Nuvindu Apr 8, 2025
f228558
Fix class name relates to error diagnostics
Nuvindu Apr 8, 2025
2ecb92f
Fix import for Response class
Nuvindu Apr 9, 2025
f1a6ca7
Apply review suggestions
Nuvindu Apr 9, 2025
b19e852
Apply review suggestions
Nuvindu Apr 9, 2025
2f72f48
Refactor Context class to NodeContext
Nuvindu Apr 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions build-config/spotbugs-exclude.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,15 @@
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<Match>
<Class name="io.ballerina.xsd.core.Response" />
<Class name="io.ballerina.xsd.core.response.Response" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<Match>
<Class name="io.ballerina.xsd.core.node.MemberNode" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<Match>
<Class name="io.ballerina.xsd.core.response.NodeResponse" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<Match>
Expand Down Expand Up @@ -70,7 +78,15 @@
<Bug pattern="EI_EXPOSE_REP2" />
</Match>
<Match>
<Class name="io.ballerina.xsd.core.Response" />
<Class name="io.ballerina.xsd.core.response.Response" />
<Bug pattern="EI_EXPOSE_REP2" />
</Match>
<Match>
<Class name="io.ballerina.xsd.core.node.MemberNode" />
<Bug pattern="EI_EXPOSE_REP2" />
</Match>
<Match>
<Class name="io.ballerina.xsd.core.response.NodeResponse" />
<Bug pattern="EI_EXPOSE_REP2" />
</Match>
<Match>
Expand Down
5 changes: 4 additions & 1 deletion xsd-cli/src/main/java/io/ballerina/xsd/cli/XsdCmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
package io.ballerina.xsd.cli;

import io.ballerina.projects.util.ProjectUtils;
import io.ballerina.xsd.core.Response;
import io.ballerina.xsd.core.response.Response;
import io.ballerina.xsd.core.XSDToRecord;
import org.w3c.dom.Document;
import org.xml.sax.ErrorHandler;
Expand Down Expand Up @@ -145,6 +145,9 @@ public void execute() {
}

private void handleSingleFile(Path outputDirPath, String fileName) throws Exception {
if (Files.notExists(outputDirPath)) {
Files.createDirectories(outputDirPath);
}
Path filePath = Path.of(fileName);
if (!Files.exists(filePath)) {
outStream.println(fileName + " file does not exist.");
Expand Down
38 changes: 22 additions & 16 deletions xsd-core/src/main/java/io/ballerina/xsd/core/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import io.ballerina.compiler.syntax.tree.NodeList;
import io.ballerina.compiler.syntax.tree.NodeParser;
import io.ballerina.compiler.syntax.tree.Token;
import io.ballerina.xsd.core.node.Kind;
import io.ballerina.xsd.core.node.MemberNode;
import io.ballerina.xsd.core.visitor.XSDVisitor;
import io.ballerina.xsd.core.visitor.XSDVisitorImpl;
import org.ballerinalang.formatter.core.Formatter;
Expand Down Expand Up @@ -55,32 +57,36 @@ public class Utils {
private Utils() {
}

public static ModulePartNode generateModulePartNode(Map<String, ModuleMemberDeclarationNode> nodes,
XSDVisitor xsdVisitor) throws Exception {
NodeList<ModuleMemberDeclarationNode> moduleMembers = AbstractNodeFactory.createNodeList(nodes.values());
public static ModulePartNode generateModulePartNode(Map<String, MemberNode> nodes,
XSDVisitor xsdVisitor) throws Exception {
NodeList<ModuleMemberDeclarationNode> moduleMembers = AbstractNodeFactory
.createNodeList(nodes.values().stream().map(MemberNode::node).toList());
NodeList<ImportDeclarationNode> imports = getImportDeclarations(xsdVisitor);
Token eofToken = AbstractNodeFactory.createIdentifierToken(XSDToRecord.EOF_TOKEN);
return NodeFactory.createModulePartNode(imports, moduleMembers, eofToken);
}

static void processRecordTypeElements(Map<String, ModuleMemberDeclarationNode> nodes,
static void processRecordTypeElements(Map<String, MemberNode> nodes,
String element, String type, String contentField) {
String fields = extractSubstring(nodes.get(type).toString(), RECORD_WITH_OPEN_BRACE,
VERTICAL_BAR + CLOSE_BRACES + SEMICOLON, contentField);
String extendedValue = nodes.get(element)
.toString().replace(type + WHITESPACE + contentField + SEMICOLON, fields);
ModuleMemberDeclarationNode moduleNode = NodeParser.parseModuleMemberDeclaration(extendedValue);
nodes.put(element, moduleNode);
if (nodes.containsKey(type) && nodes.containsKey(element)) {
String fields = extractSubstring(nodes.get(type).node().toString(), RECORD_WITH_OPEN_BRACE,
VERTICAL_BAR + CLOSE_BRACES + SEMICOLON, contentField);
String extendedValue = nodes.get(element).node()
.toString().replace(type + WHITESPACE + contentField + SEMICOLON, fields);
ModuleMemberDeclarationNode moduleNode = NodeParser.parseModuleMemberDeclaration(extendedValue);
nodes.put(element, new MemberNode(moduleNode, Kind.ELEMENT));
}
}

static void processSingleTypeElements(Map<String, ModuleMemberDeclarationNode> nodes,
static void processSingleTypeElements(Map<String, MemberNode> nodes,
String element, String type, String[] tokens, String contentField) {
String token = (!nodes.containsKey(type)) || nodes.get(type).toString().contains(XSDVisitorImpl.ENUM)
String token = (!nodes.containsKey(type) || nodes.get(type).node().toString().contains(XSDVisitorImpl.ENUM))
? STRING : tokens[tokens.length - 2];
String rootElement = nodes.get(element).toString().replace(type + WHITESPACE + contentField,
token + WHITESPACE + contentField);
ModuleMemberDeclarationNode moduleNode = NodeParser.parseModuleMemberDeclaration(rootElement);
nodes.put(element, moduleNode);
if (nodes.containsKey(element)) {
String rootElement = nodes.get(element).node().toString()
.replace(type + WHITESPACE + contentField, token + WHITESPACE + contentField);
nodes.put(element, new MemberNode(NodeParser.parseModuleMemberDeclaration(rootElement), Kind.ELEMENT));
}
}

static String extractSubstring(String baseString, String startToken, String endToken, String contentField) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com)
*
* WSO2 LLC. 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 io.ballerina.xsd.core;

import io.ballerina.compiler.syntax.tree.ModuleMemberDeclarationNode;
import io.ballerina.xsd.core.context.NodeContext;
import io.ballerina.xsd.core.node.Kind;
import io.ballerina.xsd.core.node.MemberNode;
import io.ballerina.xsd.core.node.XSDElement;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* Represents the nodeContext for processing XSD elements.
* This class provides methods to manage and retrieve syntax tree nodes and XSD elements.
*/
final class XSDNodeContext implements NodeContext {
private final Map<String, MemberNode> nodes = new HashMap<>();
private final Map<String, XSDElement> nameResolvers = new HashMap<>();

public XSDNodeContext(Map<String, MemberNode> nodes, Map<String, XSDElement> nameResolvers) {
this.nodes.putAll(nodes);
this.nameResolvers.putAll(nameResolvers);
}

static <K, V> K getKeyByValue(Map<K, V> map, V value) {
for (Map.Entry<K, V> entry : map.entrySet()) {
if (Objects.equals(value, entry.getValue())) {
return entry.getKey();
}
}
return null;
}

@Override
public ModuleMemberDeclarationNode findNode(String element, Kind kind) {
List<MemberNode> memberNodeList = new ArrayList<>();
if (nodes.containsKey(element)) {
memberNodeList.add(nodes.get(element));
}
Collection<XSDElement> elements = nameResolvers.values();
for (XSDElement xsdElement : elements) {
if (Objects.equals(xsdElement.type(), element)) {
String key = getKeyByValue(nameResolvers, xsdElement);
if (key != null && nodes.containsKey(key)) {
memberNodeList.add(nodes.get(key));
}
}
}
return memberNodeList.stream()
.filter(memberNode -> memberNode.kind() == kind)
.findFirst()
.map(MemberNode::node)
.orElse(null);
}
}
Loading