diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 85f0dfd..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "configurations": [ - { - "name": "Ballerina Debug", - "type": "ballerina", - "request": "launch", - "programArgs": [], - "commandOptions": [], - "env": {} - }, - { - "name": "Ballerina Test", - "type": "ballerina", - "request": "launch", - "debugTests": true, - "programArgs": [], - "commandOptions": [], - "env": {} - }, - { - "name": "Ballerina Remote", - "type": "ballerina", - "request": "attach", - "debuggeeHost": "127.0.0.1", - "debuggeePort": "5005" - } - ] -} \ No newline at end of file diff --git a/README.md b/README.md index 784c665..22ff65d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The Ballerina CSV Data Library is a comprehensive toolkit designed to facilitate ### Converting CSV string to a record array -To convert an CSV document value to a record value, you can utilize the `parseStringToRecord` function provided by the library. The example below showcases the transformation of a CSV document into a record array. +To convert a CSV string into a record value, you can use the `parseStringToRecord` function from the library. The following example demonstrates how to transform a CSV document into an array of records. ```ballerina import ballerina/data.csv; @@ -194,4 +194,4 @@ All contributors are encouraged to read the [Ballerina code of conduct](https:// ## Useful links * Chat live with us via our [Discord server](https://discord.gg/ballerinalang). -* Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag. \ No newline at end of file +* Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag. diff --git a/ballerina-tests/build.gradle b/ballerina-tests/build.gradle index 5f973bf..03df5cf 100644 --- a/ballerina-tests/build.gradle +++ b/ballerina-tests/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,6 @@ plugins { id 'jacoco' } -//apply plugin: 'java' - import org.apache.tools.ant.taskdefs.condition.Os description = 'Ballerina - HTTP/WS Ballerina Tests' @@ -32,7 +30,7 @@ def testCommonTomlFilePlaceHolder = new File("${project.rootDir}/build-config/re def ballerinaDist = "${project.rootDir}/target/ballerina-runtime" def distributionBinPath = "${ballerinaDist}/bin" def testCoverageParam = "--code-coverage --coverage-format=xml --includes=io.ballerina.stdlib.data.*:ballerina.*" -def testPackages = ["user-config-tests", "parse-string-array-types-tests", "type-compatible-tests", "unicode-tests", "constraint-validation-tests", +def testPackages = ["user-config-tests", "type-compatible-tests", "parse-string-array-types-tests", "unicode-tests", "constraint-validation-tests", "parse-list-types-tests", "parse-record-types-tests", "parse-string-record-types-tests", "union-type-tests"] def testCommonPackage = "csv-commons" diff --git a/ballerina-tests/constraint-validation-tests/Ballerina.toml b/ballerina-tests/constraint-validation-tests/Ballerina.toml index c0b0817..32c446c 100644 --- a/ballerina-tests/constraint-validation-tests/Ballerina.toml +++ b/ballerina-tests/constraint-validation-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/constraint-validation-tests/tests/constraint_validation_test.bal b/ballerina-tests/constraint-validation-tests/tests/constraint_validation_test.bal index 3710770..fe017b0 100644 --- a/ballerina-tests/constraint-validation-tests/tests/constraint_validation_test.bal +++ b/ballerina-tests/constraint-validation-tests/tests/constraint_validation_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/constraint; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; type ConstrainedRec record { diff --git a/ballerina-tests/csv-commons/Ballerina.toml b/ballerina-tests/csv-commons/Ballerina.toml index 0b77a15..13c0bc8 100644 --- a/ballerina-tests/csv-commons/Ballerina.toml +++ b/ballerina-tests/csv-commons/Ballerina.toml @@ -2,3 +2,6 @@ org = "ballerina" name = "csv_commons" version = "0.1.0" + +[platform.java17] +graalvmCompatible = true diff --git a/ballerina-tests/csv-commons/test_utils.bal b/ballerina-tests/csv-commons/test_utils.bal index 64123d1..b4b0447 100644 --- a/ballerina-tests/csv-commons/test_utils.bal +++ b/ballerina-tests/csv-commons/test_utils.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + public function generateErrorMessageForMissingRequiredField(string 'field) returns string { return string `no matching header value is found for the required field '${'field}'`; } diff --git a/ballerina-tests/parse-list-types-tests/Ballerina.toml b/ballerina-tests/parse-list-types-tests/Ballerina.toml index 6374fc7..fed1b89 100644 --- a/ballerina-tests/parse-list-types-tests/Ballerina.toml +++ b/ballerina-tests/parse-list-types-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_list_test.bal b/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_list_test.bal index f3ef889..548b42c 100644 --- a/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_list_test.bal +++ b/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_list_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_record_test.bal b/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_record_test.bal index 751e756..0893c54 100644 --- a/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_record_test.bal +++ b/ballerina-tests/parse-list-types-tests/tests/parse_list_type_as_record_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-list-types-tests/tests/test_data_values.bal b/ballerina-tests/parse-list-types-tests/tests/test_data_values.bal index 360a493..a9698aa 100644 --- a/ballerina-tests/parse-list-types-tests/tests/test_data_values.bal +++ b/ballerina-tests/parse-list-types-tests/tests/test_data_values.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + boolean b1 = true; false b2 = false; boolean? b3 = (); diff --git a/ballerina-tests/parse-list-types-tests/tests/types.bal b/ballerina-tests/parse-list-types-tests/tests/types.bal index 62f8f98..2c7c117 100644 --- a/ballerina-tests/parse-list-types-tests/tests/types.bal +++ b/ballerina-tests/parse-list-types-tests/tests/types.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + type BooleanRecord1 record { boolean b1; boolean|string b2; diff --git a/ballerina-tests/parse-record-types-tests/Ballerina.toml b/ballerina-tests/parse-record-types-tests/Ballerina.toml index 508c204..bd4f487 100644 --- a/ballerina-tests/parse-record-types-tests/Ballerina.toml +++ b/ballerina-tests/parse-record-types-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_list_test.bal b/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_list_test.bal index 98f980c..6ddef47 100644 --- a/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_list_test.bal +++ b/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_list_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_record_test.bal b/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_record_test.bal index a1373ae..50dde64 100644 --- a/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_record_test.bal +++ b/ballerina-tests/parse-record-types-tests/tests/parse_record_type_as_record_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-record-types-tests/tests/test_data_values.bal b/ballerina-tests/parse-record-types-tests/tests/test_data_values.bal index 360a493..a9698aa 100644 --- a/ballerina-tests/parse-record-types-tests/tests/test_data_values.bal +++ b/ballerina-tests/parse-record-types-tests/tests/test_data_values.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + boolean b1 = true; false b2 = false; boolean? b3 = (); diff --git a/ballerina-tests/parse-record-types-tests/tests/types.bal b/ballerina-tests/parse-record-types-tests/tests/types.bal index a2b4b2b..b496d60 100644 --- a/ballerina-tests/parse-record-types-tests/tests/types.bal +++ b/ballerina-tests/parse-record-types-tests/tests/types.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + type BooleanRecord1 record { boolean b1; boolean|string b2; diff --git a/ballerina-tests/parse-string-array-types-tests/Ballerina.toml b/ballerina-tests/parse-string-array-types-tests/Ballerina.toml index 256e0d0..bfffdb6 100644 --- a/ballerina-tests/parse-string-array-types-tests/Ballerina.toml +++ b/ballerina-tests/parse-string-array-types-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_array_test.bal b/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_array_test.bal index ce7d4c5..0a6c492 100644 --- a/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_array_test.bal +++ b/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_array_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_tuple_test.bal b/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_tuple_test.bal index 7cc5087..efc268b 100644 --- a/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_tuple_test.bal +++ b/ballerina-tests/parse-string-array-types-tests/tests/parse_string_to_tuple_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-string-array-types-tests/tests/test_data_values.bal b/ballerina-tests/parse-string-array-types-tests/tests/test_data_values.bal index 360a493..a9698aa 100644 --- a/ballerina-tests/parse-string-array-types-tests/tests/test_data_values.bal +++ b/ballerina-tests/parse-string-array-types-tests/tests/test_data_values.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + boolean b1 = true; false b2 = false; boolean? b3 = (); diff --git a/ballerina-tests/parse-string-array-types-tests/tests/types.bal b/ballerina-tests/parse-string-array-types-tests/tests/types.bal index a2b4b2b..b496d60 100644 --- a/ballerina-tests/parse-string-array-types-tests/tests/types.bal +++ b/ballerina-tests/parse-string-array-types-tests/tests/types.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + type BooleanRecord1 record { boolean b1; boolean|string b2; diff --git a/ballerina-tests/parse-string-record-types-tests/Ballerina.toml b/ballerina-tests/parse-string-record-types-tests/Ballerina.toml index a9d8337..3775e98 100644 --- a/ballerina-tests/parse-string-record-types-tests/Ballerina.toml +++ b/ballerina-tests/parse-string-record-types-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_map_tests copy.bal b/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_map_tests.bal similarity index 95% rename from ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_map_tests copy.bal rename to ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_map_tests.bal index 8e95f6a..c15191a 100644 --- a/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_map_tests copy.bal +++ b/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_map_tests.bal @@ -1,4 +1,20 @@ -import ballerina/data.csv as csv; +// Copyright (c) 2024, WSO2 LLC. (https://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. + +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_record_tests.bal b/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_record_tests.bal index 2383f72..de15f81 100644 --- a/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_record_tests.bal +++ b/ballerina-tests/parse-string-record-types-tests/tests/parse_string_to_record_tests.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/parse-string-record-types-tests/tests/test_data_values.bal b/ballerina-tests/parse-string-record-types-tests/tests/test_data_values.bal index 360a493..a9698aa 100644 --- a/ballerina-tests/parse-string-record-types-tests/tests/test_data_values.bal +++ b/ballerina-tests/parse-string-record-types-tests/tests/test_data_values.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + boolean b1 = true; false b2 = false; boolean? b3 = (); diff --git a/ballerina-tests/parse-string-record-types-tests/tests/types.bal b/ballerina-tests/parse-string-record-types-tests/tests/types.bal index a2b4b2b..b496d60 100644 --- a/ballerina-tests/parse-string-record-types-tests/tests/types.bal +++ b/ballerina-tests/parse-string-record-types-tests/tests/types.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + type BooleanRecord1 record { boolean b1; boolean|string b2; diff --git a/ballerina-tests/type-compatible-tests/Ballerina.toml b/ballerina-tests/type-compatible-tests/Ballerina.toml index 2d5ec74..cfdb846 100644 --- a/ballerina-tests/type-compatible-tests/Ballerina.toml +++ b/ballerina-tests/type-compatible-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/type-compatible-tests/Dependencies.toml b/ballerina-tests/type-compatible-tests/Dependencies.toml index 2e33529..5cc76ac 100644 --- a/ballerina-tests/type-compatible-tests/Dependencies.toml +++ b/ballerina-tests/type-compatible-tests/Dependencies.toml @@ -28,6 +28,19 @@ modules = [ {org = "ballerina", packageName = "data.csv", moduleName = "data.csv"} ] +[[package]] +org = "ballerina" +name = "io" +version = "1.6.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] + [[package]] org = "ballerina" name = "jballerina.java" @@ -69,6 +82,15 @@ name = "lang.object" version = "0.0.0" scope = "testOnly" +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + [[package]] org = "ballerina" name = "test" @@ -90,6 +112,7 @@ version = "0.1.0" dependencies = [ {org = "ballerina", name = "csv_commons"}, {org = "ballerina", name = "data.csv"}, + {org = "ballerina", name = "io"}, {org = "ballerina", name = "test"} ] modules = [ diff --git a/ballerina-tests/type-compatible-tests/tests/csv_error_content.txt b/ballerina-tests/type-compatible-tests/tests/csv_error_content.txt new file mode 100644 index 0000000..d2335d3 --- /dev/null +++ b/ballerina-tests/type-compatible-tests/tests/csv_error_content.txt @@ -0,0 +1,2 @@ +a, b, c d, e +"Hello W \ No newline at end of file diff --git a/ballerina-tests/type-compatible-tests/tests/parse_string_compatibality_test.bal b/ballerina-tests/type-compatible-tests/tests/parse_string_compatibality_test.bal index 8cb60fd..35bf23e 100644 --- a/ballerina-tests/type-compatible-tests/tests/parse_string_compatibality_test.bal +++ b/ballerina-tests/type-compatible-tests/tests/parse_string_compatibality_test.bal @@ -1,9 +1,26 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/io; import ballerina/test; const string filepath = "tests/csv_content.txt"; +const string errorFilepath = "tests/csv_error_content.txt"; @test:Config function testFromCsvStringWithTypeCompatibility() { @@ -212,6 +229,14 @@ function testParseBytes() returns error? { ["Hello World", "\"Hello World\"", "Hello World", "2"], ["Hello World", "\"Hello World\"", "Hello World", "2"] ]); + + int[][]|csv:Error rec3 = csv:parseBytesToList(csvBytes, {}); + test:assertTrue(rec3 is csv:Error); + test:assertEquals(( rec3).message(), common:generateErrorMessageForInvalidCast("Hello World", "int")); + + record{int a;}[]|csv:Error rec4 = csv:parseBytesToRecord(csvBytes, {}); + test:assertTrue(rec4 is csv:Error); + test:assertEquals(( rec4).message(), common:generateErrorMessageForInvalidCast("Hello World", "int")); } @test:Config @@ -231,4 +256,44 @@ function testParseStream() returns error? { ["Hello World", "\"Hello World\"", "Hello World", "2"], ["Hello World", "\"Hello World\"", "Hello World", "2"] ]); + + csvByteStream = check io:fileReadBlocksAsStream(filepath); + record{int a;}[]|csv:Error rec3 = csv:parseStreamToRecord(csvByteStream, {}); + test:assertTrue(rec3 is csv:Error); + test:assertEquals(( rec3).message(), "Error occurred while reading the stream: " + + common:generateErrorMessageForInvalidCast("Hello World", "int")); + + csvByteStream = check io:fileReadBlocksAsStream(filepath); + int[][]|csv:Error rec4 = csv:parseStreamToList(csvByteStream, {}); + test:assertTrue(rec4 is csv:Error); + test:assertEquals(( rec4).message(), "Error occurred while reading the stream: " + + common:generateErrorMessageForInvalidCast("Hello World", "int")); +} + +@test:Config +function testErrorParseBytes() returns error? { + byte[] csvBytes = check io:fileReadBytes(errorFilepath); + + int[][]|csv:Error rec3 = csv:parseBytesToList(csvBytes, {}); + test:assertTrue(rec3 is csv:Error); + test:assertTrue(( rec3).message().includes("cannot be cast into")); + + record{int a;}[]|csv:Error rec4 = csv:parseBytesToRecord(csvBytes, {}); + test:assertTrue(rec4 is csv:Error); + test:assertTrue(( rec3).message().includes("cannot be cast into")); +} + +@test:Config +function testErrorParseStream() returns error? { + byte[] csvBytes = check io:fileReadBytes(errorFilepath); + stream csvByteStream = check io:fileReadBlocksAsStream(errorFilepath); + + record{int a;}[]|csv:Error rec3 = csv:parseStreamToRecord(csvByteStream, {}); + test:assertTrue(rec3 is csv:Error); + test:assertTrue(( rec3).message().includes("cannot be cast into")); + + csvByteStream = check io:fileReadBlocksAsStream(errorFilepath); + int[][]|csv:Error rec4 = csv:parseStreamToList(csvByteStream, {}); + test:assertTrue(rec4 is csv:Error); + test:assertTrue(( rec4).message().includes("cannot be cast into")); } diff --git a/ballerina-tests/type-compatible-tests/tests/parse_type_compatibility_test.bal b/ballerina-tests/type-compatible-tests/tests/parse_type_compatibility_test.bal index ed41a81..250dc69 100644 --- a/ballerina-tests/type-compatible-tests/tests/parse_type_compatibility_test.bal +++ b/ballerina-tests/type-compatible-tests/tests/parse_type_compatibility_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/type-compatible-tests/tests/test_data_values.bal b/ballerina-tests/type-compatible-tests/tests/test_data_values.bal index 360a493..a9698aa 100644 --- a/ballerina-tests/type-compatible-tests/tests/test_data_values.bal +++ b/ballerina-tests/type-compatible-tests/tests/test_data_values.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + boolean b1 = true; false b2 = false; boolean? b3 = (); diff --git a/ballerina-tests/type-compatible-tests/tests/types.bal b/ballerina-tests/type-compatible-tests/tests/types.bal index a2b4b2b..b496d60 100644 --- a/ballerina-tests/type-compatible-tests/tests/types.bal +++ b/ballerina-tests/type-compatible-tests/tests/types.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + type BooleanRecord1 record { boolean b1; boolean|string b2; diff --git a/ballerina-tests/unicode-tests/Ballerina.toml b/ballerina-tests/unicode-tests/Ballerina.toml index b2ec347..5dba598 100644 --- a/ballerina-tests/unicode-tests/Ballerina.toml +++ b/ballerina-tests/unicode-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/unicode-tests/Dependencies.toml b/ballerina-tests/unicode-tests/Dependencies.toml new file mode 100644 index 0000000..9497389 --- /dev/null +++ b/ballerina-tests/unicode-tests/Dependencies.toml @@ -0,0 +1,88 @@ +# AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.9.0" + +[[package]] +org = "ballerina" +name = "data.csv" +version = "0.1.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "data.csv", moduleName = "data.csv"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java" +version = "0.0.0" +scope = "testOnly" + +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" +scope = "testOnly" + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.error"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + +[[package]] +org = "ballerina" +name = "unicode_tests" +version = "0.1.0" +dependencies = [ + {org = "ballerina", name = "data.csv"}, + {org = "ballerina", name = "test"} +] +modules = [ + {org = "ballerina", packageName = "unicode_tests", moduleName = "unicode_tests"} +] + diff --git a/ballerina-tests/unicode-tests/tests/escape_character_test.bal b/ballerina-tests/unicode-tests/tests/escape_character_test.bal index cee018f..297fa87 100644 --- a/ballerina-tests/unicode-tests/tests/escape_character_test.bal +++ b/ballerina-tests/unicode-tests/tests/escape_character_test.bal @@ -1,4 +1,20 @@ -import ballerina/data.csv as csv; +// Copyright (c) 2024, WSO2 LLC. (https://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. + +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/union-type-tests/Ballerina.toml b/ballerina-tests/union-type-tests/Ballerina.toml index 5d819d3..1480b52 100644 --- a/ballerina-tests/union-type-tests/Ballerina.toml +++ b/ballerina-tests/union-type-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/union-type-tests/tests/test_data_values.bal b/ballerina-tests/union-type-tests/tests/test_data_values.bal index 360a493..a9698aa 100644 --- a/ballerina-tests/union-type-tests/tests/test_data_values.bal +++ b/ballerina-tests/union-type-tests/tests/test_data_values.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + boolean b1 = true; false b2 = false; boolean? b3 = (); diff --git a/ballerina-tests/union-type-tests/tests/test_with_intersection_types.bal b/ballerina-tests/union-type-tests/tests/test_with_intersection_types.bal index 141fce7..299397e 100644 --- a/ballerina-tests/union-type-tests/tests/test_with_intersection_types.bal +++ b/ballerina-tests/union-type-tests/tests/test_with_intersection_types.bal @@ -1,4 +1,20 @@ -import ballerina/data.csv as csv; +// Copyright (c) 2024, WSO2 LLC. (https://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. + +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/union-type-tests/tests/test_with_singleton_test.bal b/ballerina-tests/union-type-tests/tests/test_with_singleton_test.bal index 495180a..3aa7369 100644 --- a/ballerina-tests/union-type-tests/tests/test_with_singleton_test.bal +++ b/ballerina-tests/union-type-tests/tests/test_with_singleton_test.bal @@ -1,4 +1,20 @@ -import ballerina/data.csv as csv; +// Copyright (c) 2024, WSO2 LLC. (https://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. + +import ballerina/data.csv; import ballerina/test; import ballerina/csv_commons as common; diff --git a/ballerina-tests/union-type-tests/tests/test_with_union_types.bal b/ballerina-tests/union-type-tests/tests/test_with_union_types.bal index 10fc22a..4ed231a 100644 --- a/ballerina-tests/union-type-tests/tests/test_with_union_types.bal +++ b/ballerina-tests/union-type-tests/tests/test_with_union_types.bal @@ -1,4 +1,20 @@ -import ballerina/data.csv as csv; +// Copyright (c) 2024, WSO2 LLC. (https://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. + +import ballerina/data.csv; import ballerina/test; type RecA record {int a; string b; boolean c; decimal d; float e; () f;}; diff --git a/ballerina-tests/union-type-tests/tests/types.bal b/ballerina-tests/union-type-tests/tests/types.bal index a2b4b2b..b496d60 100644 --- a/ballerina-tests/union-type-tests/tests/types.bal +++ b/ballerina-tests/union-type-tests/tests/types.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + type BooleanRecord1 record { boolean b1; boolean|string b2; diff --git a/ballerina-tests/user-config-tests/Ballerina.toml b/ballerina-tests/user-config-tests/Ballerina.toml index 05c5773..b4d56ea 100644 --- a/ballerina-tests/user-config-tests/Ballerina.toml +++ b/ballerina-tests/user-config-tests/Ballerina.toml @@ -11,3 +11,6 @@ version = "0.1.0" [platform.java17] graalvmCompatible = true + +[build-options] +graalvmBuildOptions = "-H:IncludeLocales=en_US,fr_FR" diff --git a/ballerina-tests/user-config-tests/tests/test_data_values.bal b/ballerina-tests/user-config-tests/tests/test_data_values.bal index 360a493..a9698aa 100644 --- a/ballerina-tests/user-config-tests/tests/test_data_values.bal +++ b/ballerina-tests/user-config-tests/tests/test_data_values.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + boolean b1 = true; false b2 = false; boolean? b3 = (); diff --git a/ballerina-tests/user-config-tests/tests/types.bal b/ballerina-tests/user-config-tests/tests/types.bal index 7587492..f3b94e7 100644 --- a/ballerina-tests/user-config-tests/tests/types.bal +++ b/ballerina-tests/user-config-tests/tests/types.bal @@ -1,4 +1,20 @@ -import ballerina/data.csv as csv; +// Copyright (c) 2024, WSO2 LLC. (https://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. + +import ballerina/data.csv; type RecordWithCustomAnnotation record { @csv:Name { diff --git a/ballerina-tests/user-config-tests/tests/user_config_projection_tests.bal b/ballerina-tests/user-config-tests/tests/user_config_projection_tests.bal index 331ca64..662cb9f 100644 --- a/ballerina-tests/user-config-tests/tests/user_config_projection_tests.bal +++ b/ballerina-tests/user-config-tests/tests/user_config_projection_tests.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/user-config-tests/tests/user_config_with_parser_options_test.bal b/ballerina-tests/user-config-tests/tests/user_config_with_parser_options_test.bal index 26ed7bd..4453312 100644 --- a/ballerina-tests/user-config-tests/tests/user_config_with_parser_options_test.bal +++ b/ballerina-tests/user-config-tests/tests/user_config_with_parser_options_test.bal @@ -1,5 +1,21 @@ +// Copyright (c) 2024, WSO2 LLC. (https://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. + import ballerina/csv_commons as common; -import ballerina/data.csv as csv; +import ballerina/data.csv; import ballerina/test; @test:Config diff --git a/ballerina-tests/user-config-tests/tests/user_configs.bal b/ballerina-tests/user-config-tests/tests/user_configs.bal index 8e85183..deb2b4f 100644 --- a/ballerina-tests/user-config-tests/tests/user_configs.bal +++ b/ballerina-tests/user-config-tests/tests/user_configs.bal @@ -1,4 +1,20 @@ -import ballerina/data.csv as csv; +// Copyright (c) 2024, WSO2 LLC. (https://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. + +import ballerina/data.csv; // Valid parser options csv:ParseOption option1 = {delimiter: "@", nilValue: "null", lineTerminator: [csv:LF]}; diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml index e503c45..c4af7c4 100644 --- a/ballerina/CompilerPlugin.toml +++ b/ballerina/CompilerPlugin.toml @@ -1,6 +1,6 @@ [plugin] id = "constraint-compiler-plugin" -class = "io.ballerina.stdlib.data.csvdata.compiler.CsvDataCompilerPlugin" +class = "io.ballerina.lib.data.csvdata.compiler.CsvDataCompilerPlugin" [[dependency]] path = "../compiler-plugin/build/libs/data.csv-compiler-plugin-0.1.0-SNAPSHOT.jar" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index c995088..c07b540 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -12,8 +12,7 @@ org = "ballerina" name = "data.csv" version = "0.1.0" dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "test"} + {org = "ballerina", name = "jballerina.java"} ] modules = [ {org = "ballerina", packageName = "data.csv", moduleName = "data.csv"} @@ -27,52 +26,3 @@ modules = [ {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} ] -[[package]] -org = "ballerina" -name = "lang.__internal" -version = "0.0.0" -scope = "testOnly" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.object"} -] - -[[package]] -org = "ballerina" -name = "lang.array" -version = "0.0.0" -scope = "testOnly" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.__internal"} -] - -[[package]] -org = "ballerina" -name = "lang.error" -version = "0.0.0" -scope = "testOnly" -dependencies = [ - {org = "ballerina", name = "jballerina.java"} -] - -[[package]] -org = "ballerina" -name = "lang.object" -version = "0.0.0" -scope = "testOnly" - -[[package]] -org = "ballerina" -name = "test" -version = "0.0.0" -scope = "testOnly" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.array"}, - {org = "ballerina", name = "lang.error"} -] -modules = [ - {org = "ballerina", packageName = "test", moduleName = "test"} -] - diff --git a/ballerina/Package.md b/ballerina/Package.md index 26878a7..22ff65d 100644 --- a/ballerina/Package.md +++ b/ballerina/Package.md @@ -1 +1,197 @@ -# Ballerina CSV Data module +# Ballerina CSV Data Library + +[![Build](https://github.com/ballerina-platform/module-ballerina-data.csv/actions/workflows/build-timestamped-master.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerina-data.csv/actions/workflows/build-timestamped-master.yml) +[![codecov](https://codecov.io/gh/ballerina-platform/module-ballerina-data.csv/branch/main/graph/badge.svg)](https://codecov.io/gh/ballerina-platform/module-ballerina-data.csv) +[![Trivy](https://github.com/ballerina-platform/module-ballerina-data.csv/actions/workflows/trivy-scan.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerina-data.csv/actions/workflows/trivy-scan.yml) +[![GraalVM Check](https://github.com/ballerina-platform/module-ballerina-data.csv/actions/workflows/build-with-bal-test-graalvm.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerina-data.csv/actions/workflows/build-with-bal-test-graalvm.yml) +[![GitHub Last Commit](https://img.shields.io/github/last-commit/ballerina-platform/module-ballerina-data.csv.svg)](https://github.com/ballerina-platform/module-ballerina-data.csv/commits/master) +[![Github issues](https://img.shields.io/github/issues/ballerina-platform/ballerina-standard-library/module/data.csv.svg?label=Open%20Issues)](https://github.com/ballerina-platform/ballerina-standard-library/labels/module%2Fdata.csv) + +The Ballerina CSV Data Library is a comprehensive toolkit designed to facilitate the handling and manipulation of CSV data within Ballerina applications. It streamlines the process of converting CSV data to native Ballerina data types, enabling developers to work with CSV content seamlessly and efficiently. + +## Features + +- **Versatile CSV Data Input**: Accept CSV data as a string, byte array, or a stream and convert it into a subtype of ballerina records or lists. +- **CSV to anydata Value Conversion**: Transform CSV data into expected type which is subtype of ballerina records or lists. +- **Projection Support**: Perform selective conversion of CSV data subsets into ballerina records or lists values through projection. + +## Usage + +### Converting CSV string to a record array + +To convert a CSV string into a record value, you can use the `parseStringToRecord` function from the library. The following example demonstrates how to transform a CSV document into an array of records. + +```ballerina +import ballerina/data.csv; +import ballerina/io; + +type Book record { + string name; + string author; + int year; +}; + +public function main() returns error? { + string csvString = string `name,author,year + Clean Code,Robert C. Martin,2008 + The Pragmatic Programmer,Andrew Hunt and David Thomas,1999`; + + Book[] books = check csv:parseStringToRecord(csvString); + foreach var book in books { + io:println(book); + } +} +``` + +### Converting external CSV document to a record value + +For transforming CSV content from an external source into a record value, the `parseStringToRecord`, `parseBytesToRecord`, `parseStreamToRecord`, `parseStringToList`, `parseBytesToList`and `parseStreamToList` functions can be used. This external source can be in the form of a string or a byte array/byte-block-stream that houses the CSV data. This is commonly extracted from files or network sockets. The example below demonstrates the conversion of an CSV value from an external source into a record value. + +```ballerina +import ballerina/data.csv; +import ballerina/io; + +type Book record { + string name; + string author; + int year; +}; + +public function main() returns error? { + // Read the CSV content as a string + string csvContent = check io:fileReadString("path/to/file.csv"); + Book[] book = check csv:parseStringToRecord(csvContent); + io:println(book); + + // Read the CSV content as a stream + stream csvStream = check io:fileReadBlocksAsStream("path/to/file.csv"); + Book[] book2 = check csv:parseStreamToRecord(csvStream); + io:println(book2); +} +``` + +Make sure to handle possible errors that may arise during the file reading or CSV to record/array conversion process. The `check` keyword is utilized to handle these errors, but more sophisticated error handling can be implemented as per your requirements. + +## CSV to record array/anydata array of array representation + +The CSV Object can be represented as a value of type record/map array or string array of array in Ballerina which facilitates a structured and type-safe approach to handling CSV data. +The conversion of CSV data to subtype of record array or anydata array of array representation is a fundamental feature of the library. + +```ballerina +import ballerina/data.csv; +import ballerina/io; + +type Book record { + string name; + int year; +}; + +public function main() returns error? { + string[][] bookArray = [["Clean Code","2008"],["Clean Architecture","2017"]]; + + Book[] author = check csv:parseListAsRecordType(bookArray, customHeaders = ["name", "year"]); + io:println(author); +} +``` + +### Controlling the CSV value to record array conversion + +The library allows for selective conversion of CSV into closed record arrays. This is beneficial when the CSV data contains headers that are not necessary to be transformed into record fields. + +```ballerina +import ballerina/data.csv; +import ballerina/io; + +type Book record {| + string name; + string author; +|}; + +public function main() returns error? { + record{}[] csvContent = [{ + "name": "Clean Code", + "author": "Robert C. Martin", + "year": 2008, + "publisher": "Prentice Hall" + }, { + "name": "The Pragmatic Programmer", + "author": "Andrew Hunt and David Thomas", + "year": 1999, + "publisher": "Addison-Wesley" + }]; + + // The CSV data above contains publisher and year fields which are not + // required to be converted into a record field. + Book[] book = check csv:parseRecordAsRecordType(csvContent); + io:println(book); +} +``` + +However, if the rest field is utilized (or if the record type is defined as an open record), all members in the CSV data will be transformed into record fields: + +```ballerina +type Book record { + string name; + string author; +} +``` + +In this instance, all other CSV header values, such as `year` and `publisher` will be transformed into `anydata-typed` fields with the corresponding CSV header as the key-value pair. + +This behavior extends to arrays as well. + +The process of projecting CSV data into a record supports various use cases, including the filtering out of unnecessary members. This functionality is anticipated to be enhanced in the future to accommodate more complex scenarios, such as filtering values based on regular expressions, among others. + +## Issues and projects + +Issues and Projects tabs are disabled for this repository as this is part of the Ballerina library. To report bugs, request new features, start new discussions, view project boards, etc. please visit Ballerina library [parent repository](https://github.com/ballerina-platform/ballerina-library). + +This repository only contains the source code for the package. + +## Building from the source + +### Set up the prerequisites + +1. Download and install Java SE Development Kit (JDK) version 17 (from one of the following locations). + * [Oracle](https://www.oracle.com/java/technologies/downloads/) + * [OpenJDK](https://adoptium.net/) + +2. Export your GitHub personal access token with the read package permissions as follows. + + export packageUser= + export packagePAT= + +### Building the source + +Execute the commands below to build from source. + +1. To build the library: + + ./gradlew clean build + +2. Publish ZIP artifact to the local `.m2` repository: + + ./gradlew clean build publishToMavenLocal + +3. Publish the generated artifacts to the local Ballerina central repository: + + ./gradlew clean build -PpublishToLocalCentral=true + +4. Publish the generated artifacts to the Ballerina central repository: + + ./gradlew clean build -PpublishToCentral=true + +## Contributing to Ballerina + +As an open source project, Ballerina welcomes contributions from the community. + +For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md). + +## Code of conduct + +All contributors are encouraged to read the [Ballerina code of conduct](https://ballerina.io/code-of-conduct). + +## Useful links + +* Chat live with us via our [Discord server](https://discord.gg/ballerinalang). +* Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag. diff --git a/ballerina/build.gradle b/ballerina/build.gradle index 13aed2b..efa4833 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -60,7 +60,7 @@ def stripBallerinaExtensionVersion(String extVersion) { apply plugin: 'io.ballerina.plugin' ballerina { - testCoverageParam = "--code-coverage --coverage-format=xml --includes=io.ballerina.stdlib.data.*:ballerina.*" + testCoverageParam = "--code-coverage --coverage-format=xml --includes=io.ballerina.lib.data.*:ballerina.*" packageOrganization = packageOrg module = packageName langVersion = ballerinaLangVersion diff --git a/ballerina/csv_api.bal b/ballerina/csv_api.bal index 7355b09..3a51ab1 100644 --- a/ballerina/csv_api.bal +++ b/ballerina/csv_api.bal @@ -23,7 +23,7 @@ import ballerina/jballerina.java; # + t - Target type # + return - On success, value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseStringToRecord(string s, parseToRecordOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Converts byte[] to subtype of record array. # @@ -32,7 +32,7 @@ public isolated function parseStringToRecord(string s, parseToRecordOption optio # + t - Target type # + return - On success, value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseBytesToRecord(byte[] s, parseToRecordOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Converts CSV byte-block-stream to subtype of record array. # @@ -42,7 +42,7 @@ public isolated function parseBytesToRecord(byte[] s, parseToRecordOption option # + return - On success, value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseStreamToRecord(stream s, parseToRecordOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Converts CSV string to subtype of anydata[][]. # @@ -51,7 +51,7 @@ public isolated function parseStreamToRecord(stream s, # + t - Target type # + return - On success, value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseStringToList(string s, ParseOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Converts byte[] to subtype of anydata[][]. # @@ -60,7 +60,7 @@ public isolated function parseStringToList(string s, ParseOption options = {}, t # + t - Target type # + return - On success, value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseBytesToList(byte[] s, ParseOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Converts CSV byte-block-stream to subtype of anydata[][]. # @@ -70,7 +70,7 @@ public isolated function parseBytesToList(byte[] s, ParseOption options = {}, ty # + return - On success, value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseStreamToList(stream s, ParseOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Convert value of type record{}[] to subtype of record{}[]. # @@ -80,7 +80,7 @@ public isolated function parseStreamToList(stream s, # + return - On success, returns value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseRecordAsRecordType(record{}[] s, RecordAsRecordOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Convert value of type record{}[] to subtype of anydata[][]. # @@ -91,7 +91,7 @@ public isolated function parseRecordAsRecordType(record{}[] s, # + return - On success, returns value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseRecordAsListType(record{}[] s, string[] headerNames, Options options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Convert value of type string[][] to subtype of record{}[]. # @@ -102,7 +102,7 @@ public isolated function parseRecordAsListType(record{}[] s, string[] headerName # + return - On success, returns value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseListAsRecordType(string[][] s, string[]? customHeaders = (), ListAsRecordOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; # Convert value of type string[][] to subtype of anydata[][]. # @@ -111,4 +111,4 @@ public isolated function parseListAsRecordType(string[][] s, string[]? customHea # + t - Target type # + return - On success, returns value belonging to the given target type, else returns an `csv:Error` value. public isolated function parseListAsListType(string[][] s, ListAsListOption options = {}, typedesc t = <>) - returns t|Error = @java:Method {'class: "io.ballerina.stdlib.data.csvdata.csv.Native"} external; + returns t|Error = @java:Method {'class: "io.ballerina.lib.data.csvdata.csv.Native"} external; diff --git a/ballerina/init.bal b/ballerina/init.bal index a0a98cb..02fa1d9 100644 --- a/ballerina/init.bal +++ b/ballerina/init.bal @@ -21,5 +21,5 @@ isolated function init() { } isolated function setModule() = @java:Method { - 'class: "io.ballerina.stdlib.data.csvdata.utils.ModuleUtils" + 'class: "io.ballerina.lib.data.csvdata.utils.ModuleUtils" } external; diff --git a/build-config/checkstyle/build.gradle b/build-config/checkstyle/build.gradle index 857ad1e..62780e5 100644 --- a/build-config/checkstyle/build.gradle +++ b/build-config/checkstyle/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/build-config/resources/CompilerPlugin.toml b/build-config/resources/CompilerPlugin.toml index 10f4b4a..dd833b5 100644 --- a/build-config/resources/CompilerPlugin.toml +++ b/build-config/resources/CompilerPlugin.toml @@ -1,6 +1,6 @@ [plugin] id = "constraint-compiler-plugin" -class = "io.ballerina.stdlib.data.csvdata.compiler.CsvDataCompilerPlugin" +class = "io.ballerina.lib.data.csvdata.compiler.CsvDataCompilerPlugin" [[dependency]] path = "../compiler-plugin/build/libs/data.csv-compiler-plugin-@project.version@.jar" diff --git a/build-config/resources/CsvTestCommon.toml b/build-config/resources/CsvTestCommon.toml index 91de9a7..38b069a 100644 --- a/build-config/resources/CsvTestCommon.toml +++ b/build-config/resources/CsvTestCommon.toml @@ -2,3 +2,6 @@ org = "ballerina" name = "@package.name@" version = "@toml.version@" + +[platform.java17] +graalvmCompatible = true diff --git a/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTest.java b/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTest.java index 5d1bd17..d2d6664 100644 --- a/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTest.java +++ b/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTest.java @@ -29,6 +29,8 @@ /** * This class includes tests for Ballerina Csv Data compiler plugin. + * + * @since 0.1.0 */ public class CompilerPluginTest { @@ -65,4 +67,44 @@ public void testInvalidRecordFields() { Assert.assertEquals(errorDiagnosticsList.size(), 1); Assert.assertEquals(errorDiagnosticsList.get(0).diagnosticInfo().messageFormat(), DUPLICATE_FIELD); } + + @Test + public void testInvalidProgram() { + DiagnosticResult diagnosticResult = + CompilerPluginTestUtils.loadPackage("sample_package_3").getCompilation().diagnosticResult(); + List errorDiagnosticsList = diagnosticResult.diagnostics().stream() + .filter(r -> r.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) + .collect(Collectors.toList()); + Assert.assertEquals(errorDiagnosticsList.size(), 1); + } + + @Test + public void testModuleLevelInvalidExpectedUnionType() { + DiagnosticResult diagnosticResult = + CompilerPluginTestUtils.loadPackage("sample_package_4").getCompilation().diagnosticResult(); + List errorDiagnosticsList = diagnosticResult.diagnostics().stream() + .filter(r -> r.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) + .collect(Collectors.toList()); + Assert.assertEquals(errorDiagnosticsList.size(), 10); + Assert.assertEquals(errorDiagnosticsList.get(0).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(1).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(2).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(3).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(4).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(5).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(6).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(7).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(8).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + Assert.assertEquals(errorDiagnosticsList.get(9).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE); + } + + @Test + public void testEmptyProject() { + DiagnosticResult diagnosticResult = + CompilerPluginTestUtils.loadPackage("sample_package_5").getCompilation().diagnosticResult(); + List errorDiagnosticsList = diagnosticResult.diagnostics().stream() + .filter(r -> r.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) + .collect(Collectors.toList()); + Assert.assertEquals(errorDiagnosticsList.size(), 0); + } } diff --git a/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTestUtils.java b/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTestUtils.java index 13c34d1..a3f15c4 100644 --- a/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTestUtils.java +++ b/compiler-plugin-test/src/test/java/io/ballerina/lib/data/csvdata/compiler/CompilerPluginTestUtils.java @@ -29,6 +29,8 @@ /** * Utility functions related to compiler plugins tests. + * + * @since 0.1.0 */ public class CompilerPluginTestUtils { private static final Path RESOURCE_DIRECTORY = Paths.get("src", "test", "resources", "ballerina_sources") diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_1/Ballerina.toml b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_1/Ballerina.toml index 437bf7b..80bcadd 100644 --- a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_1/Ballerina.toml +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_1/Ballerina.toml @@ -1,6 +1,5 @@ [package] -org = "admin" +org = "ballerina" name = "sample_package_1" version = "0.1.0" distribution = "2201.9.0" - diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_2/Ballerina.toml b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_2/Ballerina.toml index 3b39d28..80bcadd 100644 --- a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_2/Ballerina.toml +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_2/Ballerina.toml @@ -1,6 +1,5 @@ [package] -org = "admin" -name = "sample_package_2" +org = "ballerina" +name = "sample_package_1" version = "0.1.0" distribution = "2201.9.0" - diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_3/Ballerina.toml b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_3/Ballerina.toml new file mode 100644 index 0000000..ee11d8e --- /dev/null +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_3/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "ballerina" +name = "sample_package_3" +version = "0.1.0" +distribution = "2201.9.0" diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_3/main.bal b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_3/main.bal new file mode 100644 index 0000000..3253727 --- /dev/null +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_3/main.bal @@ -0,0 +1,5 @@ +// test when there is a compiler time error. +type A [[int1, string], [int, string]]; + +public function main() returns error? { +} diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_4/Ballerina.toml b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_4/Ballerina.toml new file mode 100644 index 0000000..b42c32c --- /dev/null +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_4/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "ballerina" +name = "sample_package_4" +version = "0.1.0" +distribution = "2201.9.0" diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_4/main.bal b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_4/main.bal new file mode 100644 index 0000000..a8d1eb0 --- /dev/null +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_4/main.bal @@ -0,0 +1,17 @@ +import ballerina/data.csv; + +type A [[int, string], [int, string]]; +stream s = ( [[1, 2, 3, 4, 5]]).toStream(); + +[[int, string], [int, string]] val = check csv:parseStringToList(string `a,b`, {}); +[record{}, record{}, record{}, record{}] val2 = check csv:parseStringToRecord(string `a,b`, {}); +[[int, string], [int, string]] val3 = check csv:parseStreamToList(s, {}); +[record{}, record{}, record{}, record{}] val4 = check csv:parseStreamToRecord(s, {}); +A val5 = check csv:parseBytesToList([1,2,3], {}); +record{}[]|[record{}, record{}, record{}, record{}] val6 = check csv:parseBytesToRecord([1,2,3], {}); +int[][]|[[int, string], [int, string]] val7 = check csv:parseRecordAsListType([{}], [], {}); +[[int, string], [int, string]] val8 = check csv:parseListAsListType([], {}); +[record{}, record{}, record{}, record{}] val9 = check csv:parseRecordAsRecordType([{}], {}); +[record{}, record{}, record{}, record{}] val10 = check csv:parseListAsRecordType([], [], {}); +record{}[2] val11 = check csv:parseListAsRecordType([], [], {}); +int[3][2] val12 = check csv:parseListAsListType([], {}); diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_5/Ballerina.toml b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_5/Ballerina.toml new file mode 100644 index 0000000..d3bf9e5 --- /dev/null +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_5/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "ballerina" +name = "sample_package_5" +version = "0.1.0" +distribution = "2201.9.0" diff --git a/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_5/main.bal b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_5/main.bal new file mode 100644 index 0000000..0ecaab9 --- /dev/null +++ b/compiler-plugin-test/src/test/resources/ballerina_sources/sample_package_5/main.bal @@ -0,0 +1,3 @@ +public function main() { + // test scenario without module import +} diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/Constants.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/Constants.java similarity index 93% rename from compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/Constants.java rename to compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/Constants.java index 9dba404..00b8863 100644 --- a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/Constants.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/Constants.java @@ -16,14 +16,14 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.compiler; +package io.ballerina.lib.data.csvdata.compiler; /** * Constants for CsvData's compiler plugin. * * @since 0.1.0 */ -public class Constants { +public final class Constants { static final String PARSE_STRING_TO_RECORD = "parseStringToRecord"; static final String PARSE_BYTES_TO_RECORD = "parseBytesToRecord"; static final String PARSE_STREAM_TO_RECORD = "parseStreamToRecord"; @@ -38,4 +38,7 @@ public class Constants { static final String CSVDATA = "csv"; static final String BALLERINA = "ballerina"; static final String DATA_CSVDATA = "data.csv"; + + private Constants() { + } } diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataCodeAnalyzer.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataCodeAnalyzer.java similarity index 95% rename from compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataCodeAnalyzer.java rename to compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataCodeAnalyzer.java index 86d27f1..1e67372 100644 --- a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataCodeAnalyzer.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataCodeAnalyzer.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.compiler; +package io.ballerina.lib.data.csvdata.compiler; import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.projects.plugins.CodeAnalysisContext; diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataCompilerPlugin.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataCompilerPlugin.java similarity index 95% rename from compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataCompilerPlugin.java rename to compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataCompilerPlugin.java index 865eca3..430091e 100644 --- a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataCompilerPlugin.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataCompilerPlugin.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.compiler; +package io.ballerina.lib.data.csvdata.compiler; import io.ballerina.projects.plugins.CompilerPlugin; import io.ballerina.projects.plugins.CompilerPluginContext; diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataDiagnosticCodes.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataDiagnosticCodes.java similarity index 86% rename from compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataDiagnosticCodes.java rename to compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataDiagnosticCodes.java index 57c9cac..c47482b 100644 --- a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataDiagnosticCodes.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataDiagnosticCodes.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.compiler; +package io.ballerina.lib.data.csvdata.compiler; import io.ballerina.tools.diagnostics.DiagnosticSeverity; @@ -28,8 +28,8 @@ * @since 0.1.0 */ public enum CsvDataDiagnosticCodes { - DUPLICATE_FIELD("JSON_ERROR_202", "invalid field: duplicate field found", ERROR), - UNSUPPORTED_TYPE("JSON_ERROR_203", "unsupported type: type is not supported", ERROR); + DUPLICATE_FIELD("CSV_ERROR_1", "invalid field: duplicate field found", ERROR), + UNSUPPORTED_TYPE("CSV_ERROR_2", "unsupported type: type is not supported", ERROR); private final String code; private final String message; diff --git a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataTypeValidator.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataTypeValidator.java similarity index 92% rename from compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataTypeValidator.java rename to compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataTypeValidator.java index 7b36726..0efc318 100644 --- a/compiler-plugin/src/main/java/io/ballerina/stdlib/data/csvdata/compiler/CsvDataTypeValidator.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/csvdata/compiler/CsvDataTypeValidator.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.compiler; +package io.ballerina.lib.data.csvdata.compiler; import io.ballerina.compiler.api.ModuleID; import io.ballerina.compiler.api.SemanticModel; @@ -114,13 +114,11 @@ private void reset() { private void updateModulePrefix(ModulePartNode rootNode) { for (ImportDeclarationNode importDeclarationNode : rootNode.imports()) { Optional symbol = semanticModel.symbol(importDeclarationNode); - if (symbol.isPresent() && symbol.get().kind() == SymbolKind.MODULE) { - ModuleSymbol moduleSymbol = (ModuleSymbol) symbol.get(); - if (isCsvdataImport(moduleSymbol)) { - modulePrefix = moduleSymbol.id().modulePrefix(); - break; - } - } + symbol.filter(moduleSymbol -> moduleSymbol.kind() == SymbolKind.MODULE) + .filter(moduleSymbol -> isCsvdataImport((ModuleSymbol) moduleSymbol)) + .ifPresent(moduleSymbol -> { + modulePrefix = ((ModuleSymbol) moduleSymbol).id().modulePrefix(); + }); } } @@ -206,7 +204,7 @@ private void validateExpectedType(TypeSymbol typeSymbol, SyntaxNodeAnalysisConte typeSymbol.getLocation().ifPresent(location -> currentLocation = location); switch (typeSymbol.typeKind()) { - case UNION -> validateUnionType((UnionTypeSymbol) typeSymbol, typeSymbol.getLocation(), ctx); + case UNION -> validateUnionType((UnionTypeSymbol) typeSymbol, ctx); case ARRAY -> validateArrayType((ArrayTypeSymbol) typeSymbol, ctx); case TUPLE -> validateTupleType((TupleTypeSymbol) typeSymbol, ctx); case TYPE_REFERENCE -> validateExpectedType(((TypeReferenceTypeSymbol) typeSymbol).typeDescriptor(), ctx); @@ -224,33 +222,12 @@ private void validateArrayType(ArrayTypeSymbol typeSymbol, SyntaxNodeAnalysisCon } } - private void validateUnionType(UnionTypeSymbol unionTypeSymbol, Optional location, + private void validateUnionType(UnionTypeSymbol unionTypeSymbol, SyntaxNodeAnalysisContext ctx) { - boolean isHasUnsupportedType = false; List memberTypeSymbols = unionTypeSymbol.memberTypeDescriptors(); for (TypeSymbol memberTypeSymbol : memberTypeSymbols) { validateExpectedType(memberTypeSymbol, ctx); } - - if (isHasUnsupportedType) { - reportDiagnosticInfo(ctx, location, CsvDataDiagnosticCodes.UNSUPPORTED_TYPE); - } - } - - private boolean isSupportedUnionMemberType(TypeSymbol typeSymbol) { - TypeDescKind kind = typeSymbol.typeKind(); - if (kind == TypeDescKind.TYPE_REFERENCE) { - kind = ((TypeReferenceTypeSymbol) typeSymbol).typeDescriptor().typeKind(); - } - - switch (kind) { - case ARRAY, INTERSECTION -> { - return true; - } - default -> { - return false; - } - } } private boolean isSupportedArrayMemberType(TypeSymbol typeSymbol) { @@ -308,7 +285,7 @@ private void reportDiagnosticInfo(SyntaxNodeAnalysisContext ctx, Optional currentLocation); DiagnosticInfo diagnosticInfo = new DiagnosticInfo(diagnosticsCodes.getCode(), diagnosticsCodes.getMessage(), diagnosticsCodes.getSeverity()); - if (allDiagnosticInfo.containsKey(pos) && allDiagnosticInfo.get(pos).equals(diagnosticInfo)) { + if (pos == null || (allDiagnosticInfo.containsKey(pos) && allDiagnosticInfo.get(pos).equals(diagnosticInfo))) { return; } allDiagnosticInfo.put(pos, diagnosticInfo); @@ -318,19 +295,18 @@ private void reportDiagnosticInfo(SyntaxNodeAnalysisContext ctx, Optional initializer = moduleVariableDeclarationNode.initializer(); + currentLocation = moduleVariableDeclarationNode.typedBindingPattern().typeDescriptor().location(); if (initializer.isEmpty() || !isParseFunctionOfStringSource(initializer.get())) { return; } Optional symbol = semanticModel.symbol(moduleVariableDeclarationNode.typedBindingPattern()); - if (symbol.isEmpty()) { - return; - } - validateExpectedType(((VariableSymbol) symbol.get()).typeDescriptor(), ctx); + symbol.map(s -> (VariableSymbol) s).map(s -> s.typeDescriptor()).ifPresent(s -> validateExpectedType(s, ctx)); } private void processTypeDefinitionNode(TypeDefinitionNode typeDefinitionNode, SyntaxNodeAnalysisContext ctx) { Node typeDescriptor = typeDefinitionNode.typeDescriptor(); + currentLocation = typeDefinitionNode.typeDescriptor().location(); if (typeDescriptor.kind() != SyntaxKind.RECORD_TYPE_DESC) { return; } diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/FromString.java b/native/src/main/java/io/ballerina/lib/data/csvdata/FromString.java similarity index 84% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/FromString.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/FromString.java index 9ae99bf..bbea231 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/FromString.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/FromString.java @@ -16,8 +16,11 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata; +package io.ballerina.lib.data.csvdata; +import io.ballerina.lib.data.csvdata.utils.Constants; +import io.ballerina.lib.data.csvdata.utils.CsvConfig; +import io.ballerina.lib.data.csvdata.utils.CsvUtils; import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.TypeTags; import io.ballerina.runtime.api.creators.ErrorCreator; @@ -33,9 +36,6 @@ import io.ballerina.runtime.api.values.BDecimal; import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BString; -import io.ballerina.stdlib.data.csvdata.utils.Constants; -import io.ballerina.stdlib.data.csvdata.utils.CsvConfig; -import io.ballerina.stdlib.data.csvdata.utils.CsvUtils; import java.math.BigDecimal; import java.text.DecimalFormatSymbols; @@ -45,38 +45,15 @@ import java.util.Comparator; import java.util.List; import java.util.Locale; - -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.isNullValue; +import java.util.WeakHashMap; /** * Native implementation of data:fromStringWithType(string). * * @since 0.1.0 */ -public class FromString { - private static Locale locale = null; - private static String intRegex = "^[-+]?[0-9]+$"; - private static String doubleRegex = "^[-+]?[0-9]+(\\.[0-9]*)?(e[+-]?[0-9]+)?$"; - - public static void reset() { - FromString.locale = null; - } - - private static Locale getLocale(CsvConfig config) { - if (locale == null) { - locale = CsvUtils.createLocaleFromString(config.locale); - DecimalFormatSymbols dfs = new DecimalFormatSymbols(locale); - char decimalSeparator = dfs.getDecimalSeparator(); - char minusSign = dfs.getMinusSign(); - char zeroDigit = dfs.getZeroDigit(); - String exponentSeparator = dfs.getExponentSeparator(); - intRegex = "^[" + minusSign + "+]?[" + zeroDigit + "-9]+$"; - doubleRegex = "^[" + minusSign + "+]?[" + zeroDigit + "-9]+(" + - (decimalSeparator == '.' ? "\\." : decimalSeparator) - + "[" + zeroDigit + "-9]*)?(" + exponentSeparator + "[+-]?[" + zeroDigit + "-9]+)?$"; - } - return locale; - } +public final class FromString { + private static WeakHashMap localeAttributes = new WeakHashMap<>(); private static final List TYPE_PRIORITY_ORDER = List.of( TypeTags.INT_TAG, @@ -109,8 +86,12 @@ private static Locale getLocale(CsvConfig config) { public static final Integer UNSIGNED16_MAX_VALUE = 65535; public static final Integer UNSIGNED8_MAX_VALUE = 255; + private FromString() { + } + public static Object fromStringWithType(BString string, Type expType, CsvConfig config) { String value = string.getValue(); + try { return switch (expType.getTag()) { case TypeTags.INT_TAG -> stringToInt(value, config); @@ -160,7 +141,7 @@ private static Object convertToSingletonValue(String str, Object singletonValue, private static Long stringToInt(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { return number.longValue(); } throw new NumberFormatException(); @@ -168,7 +149,7 @@ private static Long stringToInt(String value, CsvConfig config) throws NumberFor private static int stringToByte(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { int intValue = parseNumberValue(value, config).intValue(); if (isByteLiteral(intValue)) { return intValue; @@ -180,7 +161,7 @@ private static int stringToByte(String value, CsvConfig config) throws NumberFor private static long stringToSigned8Int(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { long intValue = parseNumberValue(value, config).longValue(); if (isSigned8LiteralValue(intValue)) { return intValue; @@ -193,7 +174,7 @@ private static long stringToSigned16Int(String value, CsvConfig config) throws N ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { long intValue = parseNumberValue(value, config).longValue(); if (isSigned16LiteralValue(intValue)) { return intValue; @@ -205,7 +186,7 @@ private static long stringToSigned16Int(String value, CsvConfig config) throws N private static long stringToSigned32Int(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { long intValue = parseNumberValue(value, config).longValue(); if (isSigned32LiteralValue(intValue)) { return intValue; @@ -217,7 +198,7 @@ private static long stringToSigned32Int(String value, CsvConfig config) throws N private static long stringToUnsigned8Int(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { long intValue = parseNumberValue(value, config).longValue(); if (isUnsigned8LiteralValue(intValue)) { return intValue; @@ -229,7 +210,7 @@ private static long stringToUnsigned8Int(String value, CsvConfig config) private static long stringToUnsigned16Int(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { long intValue = parseNumberValue(value, config).longValue(); if (isUnsigned16LiteralValue(intValue)) { return intValue; @@ -241,7 +222,7 @@ private static long stringToUnsigned16Int(String value, CsvConfig config) private static long stringToUnsigned32Int(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isIntegerValue(value, number)) { + if (isIntegerValue(value, number, config.locale)) { long intValue = parseNumberValue(value, config).longValue(); if (isUnsigned32LiteralValue(intValue)) { return intValue; @@ -259,7 +240,7 @@ private static BString stringToChar(String value) throws NumberFormatException { private static Double stringToFloat(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isDoubleValue(value, number)) { + if (isDoubleValue(value, number, config.locale)) { return number.doubleValue(); } throw new NumberFormatException(); @@ -268,7 +249,7 @@ private static Double stringToFloat(String value, CsvConfig config) throws Numbe private static BDecimal stringToDecimal(String value, CsvConfig config) throws NumberFormatException, ParseException { Number number = parseNumberValue(value, config); - if (isDoubleValue(value, number)) { + if (isDoubleValue(value, number, config.locale)) { BigDecimal decimalValue = BigDecimal.valueOf(number.doubleValue()); return ValueCreator.createDecimalValue(decimalValue); } @@ -288,7 +269,7 @@ private static Object stringToBoolean(String value) throws NumberFormatException private static Object stringToNull(String value, CsvConfig config) throws NumberFormatException { Object nullValue = config.nilValue; - if (isNullValue(nullValue, value)) { + if (CsvUtils.isNullValue(nullValue, value)) { return null; } return returnError(value, nullValue == null ? Constants.Values.BALLERINA_NULL : nullValue.toString()); @@ -347,12 +328,13 @@ private static boolean isCharLiteralValue(String value) { return value.codePoints().count() == 1; } - private static boolean isIntegerValue(String value, Number number) { - return number instanceof Long && value.matches(intRegex); + private static boolean isIntegerValue(String value, Number number, String localeStr) { + return number instanceof Long && value.matches(getLocale(localeStr).intRegex()); } - private static boolean isDoubleValue(String value, Number number) { - return (number instanceof Double || number instanceof Long) && value.matches(doubleRegex); + private static boolean isDoubleValue(String value, Number number, String localeStr) { + return (number instanceof Double || number instanceof Long) + && value.matches(getLocale(localeStr).doubleRegex()); } private static BError returnError(String value, String expType) { @@ -361,7 +343,31 @@ private static BError returnError(String value, String expType) { } private static Number parseNumberValue(String numberString, CsvConfig config) throws ParseException { - NumberFormat numberFormat = NumberFormat.getInstance(getLocale(config)); + NumberFormat numberFormat = NumberFormat.getInstance(getLocale(config.locale).locale()); return numberFormat.parse(numberString); } + + private static LocaleInfo getLocale(String localeStr) { + if (!localeAttributes.containsKey(localeStr)) { + localeAttributes.put(localeStr, computeLocaleIfAbsent(localeStr)); + } + return localeAttributes.get(localeStr); + } + + private static LocaleInfo computeLocaleIfAbsent(String localeStr) { + Locale locale = CsvUtils.createLocaleFromString(localeStr); + DecimalFormatSymbols dfs = new DecimalFormatSymbols(locale); + char decimalSeparator = dfs.getDecimalSeparator(); + char minusSign = dfs.getMinusSign(); + char zeroDigit = dfs.getZeroDigit(); + String exponentSeparator = dfs.getExponentSeparator(); + String intRegex = "^[" + minusSign + "+]?[" + zeroDigit + "-9]+$"; + String doubleRegex = "^[" + minusSign + "+]?[" + zeroDigit + "-9]+(" + + (decimalSeparator == '.' ? "\\." : decimalSeparator) + + "[" + zeroDigit + "-9]*)?(" + exponentSeparator + "[+-]?[" + zeroDigit + "-9]+)?$"; + return new LocaleInfo(locale, intRegex, doubleRegex); + } + + private record LocaleInfo(Locale locale, String intRegex, String doubleRegex) { + } } diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvCreator.java b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvCreator.java similarity index 92% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvCreator.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvCreator.java index 77bc61f..2160923 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvCreator.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvCreator.java @@ -16,8 +16,13 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.csv; +package io.ballerina.lib.data.csvdata.csv; +import io.ballerina.lib.data.csvdata.FromString; +import io.ballerina.lib.data.csvdata.utils.CsvConfig; +import io.ballerina.lib.data.csvdata.utils.CsvUtils; +import io.ballerina.lib.data.csvdata.utils.DiagnosticErrorCode; +import io.ballerina.lib.data.csvdata.utils.DiagnosticLog; import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.TypeTags; import io.ballerina.runtime.api.creators.ValueCreator; @@ -34,23 +39,21 @@ import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BString; -import io.ballerina.stdlib.data.csvdata.FromString; -import io.ballerina.stdlib.data.csvdata.utils.CsvConfig; -import io.ballerina.stdlib.data.csvdata.utils.CsvUtils; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticErrorCode; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticLog; import org.ballerinalang.langlib.value.CloneReadOnly; import java.util.Map; import java.util.Optional; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.getUpdatedHeaders; +import static io.ballerina.lib.data.csvdata.utils.CsvUtils.getUpdatedHeaders; + /** * Create objects for partially parsed csv. * * @since 0.1.0 */ -public class CsvCreator { +public final class CsvCreator { + private CsvCreator() { + } static Object initRowValue(Type expectedType) { expectedType = TypeUtils.getReferredType(expectedType); @@ -134,7 +137,7 @@ public static String getHeaderValueForColumnIndex(CsvParser.StateMachine sm) { sm.fields.contains(header)); } - public static void checkAndAddCustomHeaders(CsvParser.StateMachine sm, Object customHeader) { + public static void addCustomHeadersIfNotNull(CsvParser.StateMachine sm, Object customHeader) { if (customHeader == null) { return; } diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvParser.java b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvParser.java similarity index 89% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvParser.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvParser.java index 8d42d56..6b8f60d 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvParser.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvParser.java @@ -16,8 +16,14 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.csv; - +package io.ballerina.lib.data.csvdata.csv; + +import io.ballerina.lib.data.csvdata.utils.Constants; +import io.ballerina.lib.data.csvdata.utils.CsvConfig; +import io.ballerina.lib.data.csvdata.utils.CsvUtils; +import io.ballerina.lib.data.csvdata.utils.DataUtils; +import io.ballerina.lib.data.csvdata.utils.DiagnosticErrorCode; +import io.ballerina.lib.data.csvdata.utils.DiagnosticLog; import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.TypeTags; import io.ballerina.runtime.api.creators.TypeCreator; @@ -34,13 +40,6 @@ import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BTypedesc; -import io.ballerina.stdlib.data.csvdata.FromString; -import io.ballerina.stdlib.data.csvdata.utils.Constants; -import io.ballerina.stdlib.data.csvdata.utils.CsvConfig; -import io.ballerina.stdlib.data.csvdata.utils.CsvUtils; -import io.ballerina.stdlib.data.csvdata.utils.DataUtils; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticErrorCode; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticLog; import org.apache.commons.lang3.StringEscapeUtils; import java.io.IOException; @@ -51,20 +50,22 @@ import java.util.List; import java.util.Map; -import static io.ballerina.stdlib.data.csvdata.csv.CsvCreator.checkAndAddCustomHeaders; -import static io.ballerina.stdlib.data.csvdata.csv.CsvCreator.getHeaderValueForColumnIndex; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.checkRequiredFieldsAndLogError; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.getSkipDataRows; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.isCharContainsInLineTerminatorUserConfig; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.processNameAnnotationsAndBuildCustomFieldMap; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.validateExpectedArraySize; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.BACKSLASH_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.BACKSPACE_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.CARRIAGE_RETURN_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.DOUBLE_QUOTES_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.FORM_FEED_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.NEWLINE_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.SLASH_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.TAB_CHAR; +import static io.ballerina.lib.data.csvdata.utils.Constants.EscapeChar.UNICODE_START_CHAR; /** * Convert Csv string to a ballerina record. * * @since 0.1.0 */ -public class CsvParser { +public final class CsvParser { private static final char CR = 0x000D; private static final char HZ_TAB = 0x0009; private static final char SPACE = 0x0020; @@ -76,6 +77,8 @@ public class CsvParser { private static final char EOF = (char) -1; private static final char NEWLINE = 0x000A; + private CsvParser() { + } private static final ThreadLocal LOCAL_THREAD_STATE_MACHINE = ThreadLocal.withInitial(StateMachine::new); @@ -94,6 +97,10 @@ public static Object parse(Reader reader, BTypedesc type, CsvConfig config) } } + /** + * Represents the state machine used for CSV parsing. + */ + static class StateMachine { private static final State HEADER_START_STATE = new HeaderStartState(); private static final State HEADER_END_STATE = new HeaderEndState(); @@ -172,12 +179,11 @@ public void reset() { isValueStart = false; prevState = null; arraySize = 0; - FromString.reset(); } private static boolean isWhitespace(char ch, Object lineTerminator) { return ch == SPACE || ch == HZ_TAB || ch == CR - || isCharContainsInLineTerminatorUserConfig(ch, lineTerminator); + || CsvUtils.isCharContainsInLineTerminatorUserConfig(ch, lineTerminator); } private static void throwExpected(String... chars) throws CsvParserException { @@ -238,7 +244,8 @@ public Object execute(Reader reader, Type type, CsvConfig config, BTypedesc bTyp restType = (recordType).getRestFieldType(); fieldHierarchy = new HashMap<>(recordType.getFields()); fields = new HashSet<>(recordType.getFields().keySet()); - updatedRecordFieldNames = processNameAnnotationsAndBuildCustomFieldMap(recordType, fieldHierarchy); + updatedRecordFieldNames = CsvUtils + .processNameAnnotationsAndBuildCustomFieldMap(recordType, fieldHierarchy); break; case TypeTags.TUPLE_TAG: restType = ((TupleType) expectedArrayElementType).getRestType(); @@ -277,7 +284,7 @@ public Object execute(Reader reader, Type type, CsvConfig config, BTypedesc bTyp currentState = HEADER_START_STATE; } else { if (config.customHeader != null) { - checkAndAddCustomHeaders(this, config.customHeader); + CsvCreator.addCustomHeadersIfNotNull(this, config.customHeader); } currentState = ROW_START_STATE; addFieldNamesForNonHeaderState(); @@ -304,9 +311,7 @@ public Object execute(Reader reader, Type type, CsvConfig config, BTypedesc bTyp } private void addFieldNamesForNonHeaderState() { - for (Map.Entry entry: this.fieldHierarchy.entrySet()) { - this.fieldNames.put(entry.getKey(), entry.getValue()); - } + this.fieldNames.putAll(this.fieldHierarchy); } private void append(char ch) { @@ -321,7 +326,7 @@ private void append(char ch) { } private boolean isNewLineOrEof(char ch) { - return ch == EOF || isCharContainsInLineTerminatorUserConfig(ch, config.lineTerminator); + return ch == EOF || CsvUtils.isCharContainsInLineTerminatorUserConfig(ch, config.lineTerminator); } private void growCharBuff() { @@ -331,12 +336,15 @@ private void growCharBuff() { } /** - * A specific state in the Csv parsing state machine. + * A specific state in the CSV parsing state machine. */ interface State { State transition(StateMachine sm, char[] buff, int i, int count) throws CsvParserException; } + /** + * Represents the CSV header start state. + */ private static class HeaderStartState implements State { @Override public State transition(StateMachine sm, char[] buff, int i, int count) throws CsvParserException { @@ -369,7 +377,7 @@ public State transition(StateMachine sm, char[] buff, int i, int count) throws C sm.isHeaderConfigExceedLineNumber = false; if (customHeader != null) { if (sm.isNewLineOrEof(ch)) { - checkAndAddCustomHeaders(sm, customHeader); + CsvCreator.addCustomHeadersIfNotNull(sm, customHeader); sm.lineNumber++; state = HEADER_END_STATE; break; @@ -417,9 +425,6 @@ public State transition(StateMachine sm, char[] buff, int i, int count) throws C } break; } - if (state == null) { - state = this; - } sm.index = i + 1; return state; } @@ -444,18 +449,18 @@ private static int getHeaderStartRowWhenHeaderIsPresent(Object header) { } private static void finalizeHeaders(StateMachine sm) throws CsvParserException { - if (sm.headers.size() == 0) { + if (sm.headers.isEmpty()) { throw DiagnosticLog.error(DiagnosticErrorCode.HEADER_CANNOT_BE_EMPTY); } Type expType = sm.expectedArrayElementType; if (expType instanceof RecordType) { validateRemainingRecordFields(sm); - } else if (expType instanceof ArrayType) { - validateExpectedArraySize(((ArrayType) expType).getSize(), sm.headers.size()); + } else if (expType instanceof ArrayType arrayType) { + CsvUtils.validateExpectedArraySize(arrayType.getSize(), sm.headers.size()); } else if (expType instanceof MapType) { //ignore - } else if (expType instanceof TupleType) { - validateTupleTypes((TupleType) expType, sm.restType, sm.headers.size()); + } else if (expType instanceof TupleType tupleType) { + validateTupleTypes(tupleType, sm.restType, sm.headers.size()); } else { throw new CsvParserException("Invalid expected type"); } @@ -502,6 +507,9 @@ private static void addHeader(StateMachine sm, boolean trim) { sm.headers.add(value); } + /** + * Represents the CSV header end state. + */ private static class HeaderEndState implements State { @Override public State transition(StateMachine sm, char[] buff, int i, int count) { @@ -509,6 +517,9 @@ public State transition(StateMachine sm, char[] buff, int i, int count) { } } + /** + * Represents the CSV row start state. + */ private static class RowStartState implements State { char ch; State state = ROW_START_STATE; @@ -516,7 +527,7 @@ private static class RowStartState implements State { @Override public State transition(StateMachine sm, char[] buff, int i, int count) throws CsvParserException { char separator = sm.config.delimiter; - long[] skipLines = getSkipDataRows(sm.config.skipLines); + long[] skipLines = CsvUtils.getSkipDataRows(sm.config.skipLines); for (; i < count; i++) { ch = buff[i]; @@ -607,7 +618,7 @@ private static void handleEndOfTheRow(StateMachine sm) throws CsvParserException private static void handleEndOfTheRow(StateMachine sm, boolean trim) throws CsvParserException { sm.isValueStart = false; handleCsvRow(sm, trim); - checkRequiredFieldsAndLogError(sm.fieldHierarchy, sm.config.absentAsNilableType); + CsvUtils.checkRequiredFieldsAndLogError(sm.fieldHierarchy, sm.config.absentAsNilableType); } private static void handleCsvRow(StateMachine sm, boolean trim) throws CsvParserException { @@ -678,12 +689,12 @@ private static void addRowValue(StateMachine sm, boolean trim) throws CsvParserE if (exptype instanceof RecordType) { type = getExpectedRowTypeOfRecord(sm); currentField = getCurrentField(sm); - } else if (exptype instanceof MapType) { - type = ((MapType) exptype).getConstrainedType(); - } else if (exptype instanceof ArrayType) { - type = getExpectedRowTypeOfArray(sm, (ArrayType) exptype); - } else if (exptype instanceof TupleType) { - type = getExpectedRowTypeOfTuple(sm, (TupleType) exptype); + } else if (exptype instanceof MapType mapType) { + type = (mapType.getConstrainedType()); + } else if (exptype instanceof ArrayType arrayType) { + type = getExpectedRowTypeOfArray(sm, arrayType); + } else if (exptype instanceof TupleType tupleType) { + type = getExpectedRowTypeOfTuple(sm, tupleType); } else { throw new CsvParserException("Unexpected expected type"); } @@ -725,7 +736,7 @@ private static Type getExpectedRowTypeOfArray(StateMachine sm, ArrayType arrayTy } private static Type getExpectedRowTypeOfRecord(StateMachine sm) { - String header = getHeaderValueForColumnIndex(sm); + String header = CsvCreator.getHeaderValueForColumnIndex(sm); Map fields = sm.fieldNames; if (fields.containsKey(header)) { return fields.get(header).getFieldType(); @@ -744,7 +755,7 @@ private static Type getExpectedRowTypeOfRecord(StateMachine sm) { } private static Field getCurrentField(StateMachine sm) { - String header = getHeaderValueForColumnIndex(sm); + String header = CsvCreator.getHeaderValueForColumnIndex(sm); Map fields = sm.fieldNames; if (fields.containsKey(header)) { return fields.get(header); @@ -752,6 +763,9 @@ private static Field getCurrentField(StateMachine sm) { return null; } + /** + * Represents the CSV row end state. + */ private static class RowEndState implements State { @Override public State transition(StateMachine sm, char[] buff, int i, int count) { @@ -759,6 +773,9 @@ public State transition(StateMachine sm, char[] buff, int i, int count) { } } + /** + * Represents the CSV row value with quote state. + */ private static class StringQuoteValueState implements State { @Override @@ -823,7 +840,10 @@ public State transition(StateMachine sm, char[] buff, int i, int count) return state; } } - + + /** + * Represents the CSV header value with quote state. + */ private static class HeaderQuoteValueState implements State { @Override @@ -887,6 +907,10 @@ public State transition(StateMachine sm, char[] buff, int i, int count) } } + /** + * Represents the state where an escaped unicode character in hex format is processed + * from a row value. + */ private static class StringValueUnicodeHexProcessingState extends UnicodeHexProcessingState { @Override @@ -898,7 +922,7 @@ protected State getSourceState() { /** * Represents the state where an escaped unicode character in hex format is processed - * from a field name. + * from a header name. */ private static class HeaderUnicodeHexProcessingState extends UnicodeHexProcessingState { @@ -967,6 +991,9 @@ private char extractUnicodeChar(StateMachine sm) { } + /** + * Represents the state where an escaped character is processed in a header value. + */ private static class HeaderEscapedCharacterProcessingState extends EscapedCharacterProcessingState { @Override @@ -975,6 +1002,9 @@ protected State getSourceState() { } } + /** + * Represents the state where an escaped character is processed in a row value. + */ private static class StringValueEscapedCharacterProcessingState extends EscapedCharacterProcessingState { @Override @@ -983,7 +1013,13 @@ protected State getSourceState() { } } + /** + * Represents the state where an escaped character is processed in a header or row value. + */ private abstract static class EscapedCharacterProcessingState implements State { + static final Map ESCAPE_CHAR_MAP = Map.of(DOUBLE_QUOTES_CHAR, QUOTES, + BACKSLASH_CHAR, REV_SOL, SLASH_CHAR, SOL, BACKSPACE_CHAR, BACKSPACE, FORM_FEED_CHAR, + FORMFEED, NEWLINE_CHAR, NEWLINE, CARRIAGE_RETURN_CHAR, CR, TAB_CHAR, HZ_TAB); protected abstract State getSourceState(); @@ -1004,39 +1040,18 @@ public State transition(StateMachine sm, char[] buff, int i, int count) throws C return ROW_END_STATE; } switch (ch) { - case '"': - sm.append(QUOTES); - state = sm.prevState; - break; - case '\\': - sm.append(REV_SOL); - state = sm.prevState; - break; - case '/': - sm.append(SOL); - state = sm.prevState; - break; - case 'b': - sm.append(BACKSPACE); - state = sm.prevState; - break; - case 'f': - sm.append(FORMFEED); - state = sm.prevState; - break; - case 'n': - sm.append(NEWLINE); - state = sm.prevState; - break; - case 'r': - sm.append(CR); - state = sm.prevState; - break; - case 't': - sm.append(HZ_TAB); + case DOUBLE_QUOTES_CHAR: + case BACKSLASH_CHAR: + case SLASH_CHAR: + case BACKSPACE_CHAR: + case FORM_FEED_CHAR: + case NEWLINE_CHAR: + case CARRIAGE_RETURN_CHAR: + case TAB_CHAR: + sm.append(ESCAPE_CHAR_MAP.get(ch)); state = sm.prevState; break; - case 'u': + case UNICODE_START_CHAR: if (this.getSourceState() == STRING_ESCAPE_VALUE_STATE) { state = STRING_UNICODE_CHAR_STATE; } else if (this.getSourceState() == HEADER_ESCAPE_CHAR_STATE) { diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvTraversal.java b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvTraversal.java similarity index 85% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvTraversal.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvTraversal.java index 091a4b8..5e2c630 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/CsvTraversal.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/CsvTraversal.java @@ -16,8 +16,13 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.csv; +package io.ballerina.lib.data.csvdata.csv; +import io.ballerina.lib.data.csvdata.utils.CsvConfig; +import io.ballerina.lib.data.csvdata.utils.CsvUtils; +import io.ballerina.lib.data.csvdata.utils.DataUtils; +import io.ballerina.lib.data.csvdata.utils.DiagnosticErrorCode; +import io.ballerina.lib.data.csvdata.utils.DiagnosticLog; import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.TypeTags; import io.ballerina.runtime.api.creators.TypeCreator; @@ -38,11 +43,6 @@ import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.api.values.BTypedesc; -import io.ballerina.stdlib.data.csvdata.utils.CsvConfig; -import io.ballerina.stdlib.data.csvdata.utils.CsvUtils; -import io.ballerina.stdlib.data.csvdata.utils.DataUtils; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticErrorCode; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticLog; import java.util.ArrayDeque; import java.util.ArrayList; @@ -53,27 +53,17 @@ import java.util.Map; import java.util.Optional; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.SkipMappedValue; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.UnMappedValue; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.checkRequiredFieldsAndLogError; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.checkTypeCompatibility; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.convertToBasicType; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.createHeaders; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.getMutableType; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.getSkipDataRows; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.getTheActualExpectedType; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.isBasicType; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.isHeaderFieldsEmpty; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.processNameAnnotationsAndBuildCustomFieldMap; -import static io.ballerina.stdlib.data.csvdata.utils.CsvUtils.validateExpectedArraySize; - /** * Convert Csv value to a ballerina record. * * @since 0.1.0 */ -public class CsvTraversal { +public final class CsvTraversal { private static final ThreadLocal tlCsvTree = ThreadLocal.withInitial(CsvTree::new); + + private CsvTraversal() { + } + public static Object traverse(BArray csv, CsvConfig config, BTypedesc type) { CsvTree csvTree = tlCsvTree.get(); try { @@ -120,7 +110,7 @@ void reset() { fieldHierarchy.clear(); updatedRecordFieldNames.clear(); headerFieldHierarchy.clear(); - fields.clear();; + fields.clear(); restType = null; fieldNames.clear(); rootCsvNode = null; @@ -138,7 +128,7 @@ void resetForUnionTypes() { fieldHierarchy.clear(); updatedRecordFieldNames.clear(); headerFieldHierarchy.clear(); - fields.clear();; + fields.clear(); restType = null; fieldNames.clear(); rootCsvNode = null; @@ -158,29 +148,20 @@ public Object traverseCsv(BArray csv, CsvConfig config, Type type) { Type referredType = TypeUtils.getReferredType(type); int sourceArraySize = (int) csv.getLength(); if (referredType.getTag() == TypeTags.INTERSECTION_TAG) { - Optional mutableType = getMutableType((IntersectionType) referredType); + Optional mutableType = CsvUtils.getMutableType((IntersectionType) referredType); if (mutableType.isPresent()) { return CsvCreator.constructReadOnlyValue(traverseCsv(csv, config, mutableType.get())); } } if (referredType.getTag() != TypeTags.UNION_TAG) { - if (referredType.getTag() == TypeTags.ARRAY_TAG) { - Type arrayElementType = TypeUtils.getReferredType(((ArrayType) referredType).getElementType()); - if (arrayElementType.getTag() == TypeTags.INTERSECTION_TAG) { - Optional mutableType = getMutableType((IntersectionType) arrayElementType); - if (mutableType.isPresent()) { - return CsvCreator.constructReadOnlyValue( - traverseCsv(csv, config, TypeCreator.createArrayType( - mutableType.get() - )) - ); - } - } + Optional intersectionValue = handleNonUnionIntersection(referredType, csv, config); + if (intersectionValue.isPresent()) { + return intersectionValue.get(); } int expectedArraySize = ((ArrayType) referredType).getSize(); setRootCsvNodeForNonUnionArrays(referredType, type); - validateExpectedArraySize(expectedArraySize, sourceArraySize); + CsvUtils.validateExpectedArraySize(expectedArraySize, sourceArraySize); traverseCsvWithExpectedType(sourceArraySize, csv, type); } else { traverseCsvWithUnionExpectedType(referredType, type, sourceArraySize, csv); @@ -188,6 +169,20 @@ public Object traverseCsv(BArray csv, CsvConfig config, Type type) { return rootCsvNode; } + private Optional handleNonUnionIntersection(Type referredType, BArray csv, CsvConfig config) { + if (referredType.getTag() == TypeTags.ARRAY_TAG) { + Type arrayElementType = TypeUtils.getReferredType(((ArrayType) referredType).getElementType()); + if (arrayElementType.getTag() == TypeTags.INTERSECTION_TAG) { + Optional mutableType = CsvUtils.getMutableType((IntersectionType) arrayElementType); + if (mutableType.isPresent()) { + return Optional.of(CsvCreator.constructReadOnlyValue(traverseCsv(csv, + config, TypeCreator.createArrayType(mutableType.get())))); + } + } + } + return Optional.empty(); + } + private void traverseCsvWithUnionExpectedType(Type referredType, Type type, int sourceArraySize, BArray csv) { for (Type memberType: ((UnionType) referredType).getMemberTypes()) { @@ -197,7 +192,7 @@ private void traverseCsvWithUnionExpectedType(Type referredType, Type type, int resetForUnionTypes(); try { setRootCsvNodeForNonUnionArrays(mType, mType); - validateExpectedArraySize(expectedArraySize, sourceArraySize); + CsvUtils.validateExpectedArraySize(expectedArraySize, sourceArraySize); traverseCsvWithExpectedType(sourceArraySize, csv, type); return; } catch (Exception ex) { @@ -212,7 +207,7 @@ private void traverseCsvWithExpectedType(int sourceArraySize, BArray csv, Type type) { boolean isIntersection = false; if (expectedArrayElementType.getTag() == TypeTags.INTERSECTION_TAG) { - Optional mutableType = getMutableType((IntersectionType) expectedArrayElementType); + Optional mutableType = CsvUtils.getMutableType((IntersectionType) expectedArrayElementType); if (mutableType.isPresent()) { isIntersection = true; expectedArrayElementType = mutableType.get(); @@ -313,7 +308,7 @@ public void traverseCsvArrayMembersWithUnionAsCsvElementType(long length, BArray try { memberType = TypeUtils.getReferredType(memberType); if (memberType.getTag() == TypeTags.INTERSECTION_TAG) { - Optional mutableType = getMutableType((IntersectionType) memberType); + Optional mutableType = CsvUtils.getMutableType((IntersectionType) memberType); if (mutableType.isPresent()) { isIntersection = true; memberType = mutableType.get(); @@ -337,7 +332,7 @@ public void traverseCsvArrayMembersWithUnionAsCsvElementType(long length, BArray isCompatible = true; break; } catch (Exception e) { - int a = 1; + // ignore } } if (!isCompatible) { @@ -347,7 +342,7 @@ public void traverseCsvArrayMembersWithUnionAsCsvElementType(long length, BArray } private static boolean ignoreRow(int index, Object skipLinesConfig) { - long[] skipLines = getSkipDataRows(skipLinesConfig); + long[] skipLines = CsvUtils.getSkipDataRows(skipLinesConfig); for (long skipLine: skipLines) { if (skipLine == index) { return true; @@ -363,7 +358,7 @@ public Object traverseCsvElementWithMapOrRecord(Object csvElement, Type expected RecordType recordType = (RecordType) expectedType; this.fieldHierarchy = new HashMap<>(recordType.getFields()); fields = new HashSet<>(recordType.getFields().keySet()); - this.updatedRecordFieldNames = processNameAnnotationsAndBuildCustomFieldMap( + this.updatedRecordFieldNames = CsvUtils.processNameAnnotationsAndBuildCustomFieldMap( recordType, fieldHierarchy); this.headerFieldHierarchy = new HashMap<>(recordType.getFields()); this.restType = recordType.getRestFieldType(); @@ -402,12 +397,10 @@ public Object traverseCsvElementWithArray(Object csvElement, Type expectedType) } private void traverseArrayValue(Object csvElement, Type type) { - int expectedTypeSize = getTheActualExpectedType(type); - if (csvElement instanceof BMap) { - BMap map = (BMap) csvElement; + int expectedTypeSize = CsvUtils.getTheActualExpectedType(type); + if (csvElement instanceof BMap map) { constructArrayValuesFromMap(map, type, expectedTypeSize == -1 ? map.size() : expectedTypeSize); - } else if (csvElement instanceof BArray) { - BArray array = (BArray) csvElement; + } else if (csvElement instanceof BArray array) { constructArrayValuesFromArray(array, type, expectedTypeSize == -1 ? array.size() : expectedTypeSize); } } @@ -420,8 +413,7 @@ private void constructArrayValuesFromArray(BArray csvElement, Type type, int exp } Type memberType = getArrayOrTupleMemberType(type, index); if (memberType != null) { - addValuesToArrayType(csvElement.get(i), memberType, index, - currentCsvNode, config); + addValuesToArrayType(csvElement.get(i), memberType, index, currentCsvNode); } index++; } @@ -443,7 +435,7 @@ private void constructArrayValuesFromMap(BMap map, Type type, i keys = map.getKeys(); } else { if (this.headers == null) { - this.headers = createHeaders(new String[size], config); + this.headers = CsvUtils.createHeaders(new String[size], config); } if (this.headers.length != size) { throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_CUSTOM_HEADER_LENGTH); @@ -462,23 +454,14 @@ private void constructArrayValuesFromMap(BMap map, Type type, i } Type memberType = getArrayOrTupleMemberType(type, index); if (memberType != null) { - addValuesToArrayType(v, memberType, index, - currentCsvNode, config); + addValuesToArrayType(v, memberType, index, currentCsvNode); } index++; } } - private boolean isArrayOrTupleRestTypeMember(Type type, int index) { - if (type instanceof ArrayType) { - return false; - } - return ((TupleType) type).getTupleTypes().size() < index + 1; - } - private Type getArrayOrTupleMemberType(Type type, int index) { - if (type instanceof TupleType) { - TupleType tupleType = (TupleType) type; + if (type instanceof TupleType tupleType) { List tupleTypes = tupleType.getTupleTypes(); if (tupleTypes.size() >= index + 1) { return tupleTypes.get(index); @@ -492,21 +475,21 @@ private Type getArrayOrTupleMemberType(Type type, int index) { throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_EXPECTED_TUPLE_SIZE, tupleTypes.size()); } } - ArrayType arrayType = (ArrayType) type; + ArrayType arrayType = (ArrayType) type; if (arrayType.getSize() != -1 && arrayType.getSize() <= index) { if (config.allowDataProjection) { return null; } throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_EXPECTED_ARRAY_SIZE, arrayType.getSize()); } - return ((ArrayType) type).getElementType(); + return arrayType.getElementType(); } private void traverseCsvMap(Object csvElement, Type expectedType, boolean mappingType) { if (csvElement instanceof BMap map) { traverseMapValueWithMapAsExpectedType(map, mappingType, expectedType); - } else if (csvElement instanceof BArray) { - traverseArrayValueWithMapAsExpectedType((BArray) csvElement, mappingType, expectedType); + } else if (csvElement instanceof BArray array) { + traverseArrayValueWithMapAsExpectedType(array, mappingType, expectedType); } else { throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_CSV_DATA_FORMAT); } @@ -520,8 +503,8 @@ private boolean checkExpectedTypeMatchWithHeaders(Type expectedType, BArray csvE return true; } Type type = csvElement.getType(); - if (type instanceof TupleType) { - return checkExpectedTypeMatchWithHeadersForTuple(expectedType, (TupleType) type); + if (type instanceof TupleType tupleType) { + return checkExpectedTypeMatchWithHeadersForTuple(expectedType, tupleType); } else { return checkExpectedTypeMatchWithHeadersForArray(expectedType); } @@ -549,7 +532,8 @@ private boolean checkExpectedTypeMatchWithHeadersForTuple(Type expectedType, Tup Field field = this.headerFieldHierarchy.remove(header); if (field != null) { - if (!config.stringConversion && type.getTag() != field.getFieldType().getTag()) { + if (!config.stringConversion && type != null + && type.getTag() != field.getFieldType().getTag()) { return false; } continue; @@ -559,7 +543,7 @@ private boolean checkExpectedTypeMatchWithHeadersForTuple(Type expectedType, Tup continue; } - if (isHeaderFieldsEmpty(this.headerFieldHierarchy)) { + if (CsvUtils.isHeaderFieldsEmpty(this.headerFieldHierarchy)) { continue; } return false; @@ -591,7 +575,7 @@ private void traverseArrayValueWithMapAsExpectedType(BArray csvElement, int arraySize = csvElement.size(); String[] headers = new String[arraySize]; if (this.headers == null) { - this.headers = createHeaders(headers, config); + this.headers = CsvUtils.createHeaders(headers, config); } boolean headersMatchWithExpType = checkExpectedTypeMatchWithHeaders(expectedType, csvElement, arraySize); if (!headersMatchWithExpType) { @@ -613,11 +597,11 @@ private void addValuesToMapType(BArray csvElement, int arraySize, boolean mappin fieldType = TypeUtils.getReferredType(currentField.getFieldType()); } else { addFieldInMapType(key); - fieldType = ((MapType) expectedType).getConstrainedType();; + fieldType = ((MapType) expectedType).getConstrainedType(); } addCurrentFieldValue(fieldType, csvElement.get(i - 1), key, mappingType); } - checkRequiredFieldsAndLogError(fieldHierarchy, config.absentAsNilableType); + CsvUtils.checkRequiredFieldsAndLogError(fieldHierarchy, config.absentAsNilableType); } private void traverseMapValueWithMapAsExpectedType( @@ -637,7 +621,7 @@ private void traverseMapValueWithMapAsExpectedType( } addCurrentFieldValue(currentFieldType, map.get(key), key, mappingType); } - checkRequiredFieldsAndLogError(fieldHierarchy, config.absentAsNilableType); + CsvUtils.checkRequiredFieldsAndLogError(fieldHierarchy, config.absentAsNilableType); } private boolean isKeyBelongsToNonRestType(Object value, BString key) { @@ -671,7 +655,7 @@ private Object getFieldValue(Type type, Object csvMember, boolean isRecursive) { if (!isRecursive && config.nilAsOptionalField && !fieldType.isNilable() && CsvUtils.isNullValue(nilValue, csvMember) && currentField != null && SymbolFlags.isFlagOn(currentField.getFlags(), SymbolFlags.OPTIONAL)) { - return SkipMappedValue.createSkippedValue(); + return CsvUtils.SkipMappedValue.createSkippedValue(); } if (config.stringConversion && csvMember instanceof BString str) { Object convertedValue = CsvCreator.convertToExpectedType(str, type, config); @@ -697,8 +681,8 @@ private Object getFieldValue(Type type, Object csvMember, boolean isRecursive) { case TypeTags.UNSIGNED16_INT_TAG: case TypeTags.UNSIGNED32_INT_TAG: case TypeTags.FINITE_TYPE_TAG: - if (checkTypeCompatibility(fieldType, csvMember, config.stringConversion)) { - Object value = convertToBasicType(csvMember, fieldType, config); + if (CsvUtils.checkTypeCompatibility(fieldType, csvMember, config.stringConversion)) { + Object value = CsvUtils.convertToBasicType(csvMember, fieldType, config); if (!(value instanceof BError)) { return value; } @@ -707,12 +691,12 @@ private Object getFieldValue(Type type, Object csvMember, boolean isRecursive) { case TypeTags.UNION_TAG: for (Type memberType : ((UnionType) fieldType).getMemberTypes()) { memberType = TypeUtils.getReferredType(memberType); - if (!isBasicType(memberType)) { + if (!CsvUtils.isBasicType(memberType)) { throw DiagnosticLog.error(DiagnosticErrorCode .EXPECTED_TYPE_CAN_ONLY_CONTAIN_BASIC_TYPES, memberType); } Object value = getFieldValue(memberType, csvMember, true); - if (!(value instanceof BError || value instanceof UnMappedValue)) { + if (!(value instanceof BError || value instanceof CsvUtils.UnMappedValue)) { return value; } } @@ -736,34 +720,33 @@ private Object getFieldValue(Type type, Object csvMember, boolean isRecursive) { throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_EXPECTED_TYPE, type); } } - return UnMappedValue.createUnMappedValue(); + return CsvUtils.UnMappedValue.createUnMappedValue(); } private void addRestField(Type type, BString key, Object csvMember) { Object value = getFieldValue(type, csvMember, false); - if (!(value instanceof UnMappedValue)) { + if (!(value instanceof CsvUtils.UnMappedValue)) { ((BMap) currentCsvNode).put(key, value); } } private void addCurrentFieldValue(Type type, Object recValue, BString key, boolean isMapType) { Object value = getFieldValue(type, recValue, false); - if (!(value instanceof UnMappedValue || value instanceof SkipMappedValue)) { + if (!(value instanceof CsvUtils.UnMappedValue || value instanceof CsvUtils.SkipMappedValue)) { ((BMap) currentCsvNode).put(StringUtils.fromString(fieldNames.pop()), value); return; } - if (isMapType || value instanceof SkipMappedValue) { + if (isMapType || value instanceof CsvUtils.SkipMappedValue) { return; } throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_TYPE_FOR_FIELD, recValue, key); } - public void addValuesToArrayType(Object arrayValue, Type type, int index, - Object currentCsvNode, CsvConfig config) { + public void addValuesToArrayType(Object arrayValue, Type type, int index, Object currentCsvNode) { Object value = getFieldValue(type, arrayValue, false); boolean isArrayType = type instanceof ArrayType; - if (!(value instanceof UnMappedValue)) { + if (!(value instanceof CsvUtils.UnMappedValue)) { if (isArrayType) { ArrayType arrayType = (ArrayType) TypeUtils.getType(type); if (arrayType.getState() == ArrayType.ArrayState.CLOSED && @@ -779,8 +762,7 @@ public void addValuesToArrayType(Object arrayValue, Type type, int index, private void setRootCsvNodeForNonUnionArrays(Type referredType, Type type) { referredType = TypeUtils.getReferredType(referredType); - if (referredType.getTag() == TypeTags.ARRAY_TAG) { - ArrayType arrayType = (ArrayType) referredType; + if (referredType instanceof ArrayType arrayType) { rootCsvNode = ValueCreator.createArrayValue(arrayType); expectedArrayElementType = TypeUtils.getReferredType((arrayType).getElementType()); return; @@ -789,11 +771,8 @@ private void setRootCsvNodeForNonUnionArrays(Type referredType, Type type) { } private Type getSourceElementTypeForTupleAndArrays(BArray csv) { - List memberTypes = new ArrayList<>(); if (csv.getType() instanceof TupleType tupleType) { - for (Type memberType: tupleType.getTupleTypes()) { - memberTypes.add(memberType); - } + List memberTypes = new ArrayList<>(tupleType.getTupleTypes()); return TypeCreator.createUnionType(memberTypes); } return csv.getElementType(); diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/Native.java b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/Native.java similarity index 94% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/Native.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/csv/Native.java index 98f5b3a..35a92bd 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/csv/Native.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/csv/Native.java @@ -16,8 +16,14 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.csv; +package io.ballerina.lib.data.csvdata.csv; +import io.ballerina.lib.data.csvdata.io.DataReaderTask; +import io.ballerina.lib.data.csvdata.io.DataReaderThreadPool; +import io.ballerina.lib.data.csvdata.utils.Constants; +import io.ballerina.lib.data.csvdata.utils.CsvConfig; +import io.ballerina.lib.data.csvdata.utils.DiagnosticErrorCode; +import io.ballerina.lib.data.csvdata.utils.DiagnosticLog; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.values.BArray; @@ -27,12 +33,6 @@ import io.ballerina.runtime.api.values.BStream; import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.api.values.BTypedesc; -import io.ballerina.stdlib.data.csvdata.io.DataReaderTask; -import io.ballerina.stdlib.data.csvdata.io.DataReaderThreadPool; -import io.ballerina.stdlib.data.csvdata.utils.Constants; -import io.ballerina.stdlib.data.csvdata.utils.CsvConfig; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticErrorCode; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticLog; import java.io.ByteArrayInputStream; import java.io.InputStreamReader; diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/io/BallerinaByteBlockInputStream.java b/native/src/main/java/io/ballerina/lib/data/csvdata/io/BallerinaByteBlockInputStream.java similarity index 98% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/io/BallerinaByteBlockInputStream.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/io/BallerinaByteBlockInputStream.java index b6705a2..63c3945 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/io/BallerinaByteBlockInputStream.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/io/BallerinaByteBlockInputStream.java @@ -16,8 +16,9 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.io; +package io.ballerina.lib.data.csvdata.io; +import io.ballerina.lib.data.csvdata.utils.DiagnosticLog; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.async.Callback; import io.ballerina.runtime.api.async.StrandMetadata; @@ -28,7 +29,6 @@ import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; import io.ballerina.runtime.api.values.BString; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticLog; import java.io.IOException; import java.io.InputStream; diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/io/DataReaderTask.java b/native/src/main/java/io/ballerina/lib/data/csvdata/io/DataReaderTask.java similarity index 94% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/io/DataReaderTask.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/io/DataReaderTask.java index 0f9e278..b4186bf 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/io/DataReaderTask.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/io/DataReaderTask.java @@ -15,8 +15,11 @@ * specific language governing permissions and limitations * under the License. */ -package io.ballerina.stdlib.data.csvdata.io; +package io.ballerina.lib.data.csvdata.io; +import io.ballerina.lib.data.csvdata.csv.CsvParser; +import io.ballerina.lib.data.csvdata.utils.CsvConfig; +import io.ballerina.lib.data.csvdata.utils.DiagnosticLog; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.types.MethodType; @@ -25,9 +28,6 @@ import io.ballerina.runtime.api.values.BObject; import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.api.values.BTypedesc; -import io.ballerina.stdlib.data.csvdata.csv.CsvParser; -import io.ballerina.stdlib.data.csvdata.utils.CsvConfig; -import io.ballerina.stdlib.data.csvdata.utils.DiagnosticLog; import java.io.InputStreamReader; import java.nio.charset.Charset; diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/io/DataReaderThreadPool.java b/native/src/main/java/io/ballerina/lib/data/csvdata/io/DataReaderThreadPool.java similarity index 93% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/io/DataReaderThreadPool.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/io/DataReaderThreadPool.java index 55e732f..ae54392 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/io/DataReaderThreadPool.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/io/DataReaderThreadPool.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package io.ballerina.stdlib.data.csvdata.io; +package io.ballerina.lib.data.csvdata.io; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; @@ -28,7 +28,7 @@ * * @since 0.1.0 */ -public class DataReaderThreadPool { +public final class DataReaderThreadPool { private static final int CORE_POOL_SIZE = 0; private static final int MAX_POOL_SIZE = 50; private static final long KEEP_ALIVE_TIME = 60L; @@ -36,6 +36,9 @@ public class DataReaderThreadPool { public static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new SynchronousQueue<>(), new DataThreadFactory()); + private DataReaderThreadPool() { + } + /** * Thread factory for data reader. */ diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/Constants.java b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/Constants.java similarity index 79% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/Constants.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/utils/Constants.java index a9dec36..987cc2b 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/Constants.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/Constants.java @@ -1,4 +1,4 @@ -package io.ballerina.stdlib.data.csvdata.utils; +package io.ballerina.lib.data.csvdata.utils; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BString; @@ -35,6 +35,18 @@ public static class LineTerminator { public static final String CRLF = "\r\n"; } + public static class EscapeChar { + public static final char DOUBLE_QUOTES_CHAR = '"'; + public static final char BACKSLASH_CHAR = '\\'; + public static final char SLASH_CHAR = '/'; + public static final char BACKSPACE_CHAR = 'b'; + public static final char FORM_FEED_CHAR = 'f'; + public static final char NEWLINE_CHAR = 'n'; + public static final char CARRIAGE_RETURN_CHAR = 'r'; + public static final char TAB_CHAR = 't'; + public static final char UNICODE_START_CHAR = 'u'; + } + public static final String SKIP_LINE_RANGE_SEP = "-"; public static final String FIELD = "$field$."; public static final String NAME = "Name"; diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/CsvConfig.java b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/CsvConfig.java similarity index 63% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/CsvConfig.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/utils/CsvConfig.java index 8e772e1..abfc9a5 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/CsvConfig.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/CsvConfig.java @@ -1,26 +1,10 @@ -package io.ballerina.stdlib.data.csvdata.utils; +package io.ballerina.lib.data.csvdata.utils; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BString; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.ABSENT_AS_NILABLE; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.ALLOW_DATA_PROJECTION; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.COMMENT_CHAR; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.CUSTOM_HEADERS; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.DELIMITER; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.ENABLE_CONSTRAINT_VALIDATION; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.ESCAPE_CHAR; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.HEADER; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.LINE_TERMINATOR; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.LOCALE; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.NIL_AS_OPTIONAL; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.NIL_VALUE; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.SKIP_LINES; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.STRING_CONVERSION; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.ConfigConstants.TEXT_ENCLOSURE; - public class CsvConfig { public char delimiter = ','; public char textEnclosure = '\\'; @@ -30,7 +14,7 @@ public class CsvConfig { public Object skipLines = null; public Object nilValue = null; public char comment = '#'; - public String locale = "EN/US"; + public String locale = "en_US"; public boolean nilAsOptionalField = false; public boolean absentAsNilableType = false; public boolean allowDataProjection = true; @@ -101,24 +85,24 @@ private CsvConfig(Object skipLines, boolean nilAsOptionalField, boolean absentAs public static CsvConfig createListTypeOptions(BMap options) { updateDataProjectOptions(options); return new CsvConfig( - options.get(SKIP_LINES), - options.getBooleanValue(NIL_AS_OPTIONAL).booleanValue(), - options.getBooleanValue(ABSENT_AS_NILABLE).booleanValue(), - options.getBooleanValue(ALLOW_DATA_PROJECTION).booleanValue(), - options.getBooleanValue(STRING_CONVERSION).booleanValue() + options.get(Constants.ConfigConstants.SKIP_LINES), + options.getBooleanValue(Constants.ConfigConstants.NIL_AS_OPTIONAL).booleanValue(), + options.getBooleanValue(Constants.ConfigConstants.ABSENT_AS_NILABLE).booleanValue(), + options.getBooleanValue(Constants.ConfigConstants.ALLOW_DATA_PROJECTION).booleanValue(), + options.getBooleanValue(Constants.ConfigConstants.STRING_CONVERSION).booleanValue() ); } public static CsvConfig createListAsRecordTypeOptions(BMap options) { updateDataProjectOptions(options); return new CsvConfig( - options.get(SKIP_LINES), - options.getBooleanValue(NIL_AS_OPTIONAL).booleanValue(), - options.getBooleanValue(ABSENT_AS_NILABLE).booleanValue(), - options.getBooleanValue(ALLOW_DATA_PROJECTION).booleanValue(), - options.getBooleanValue(STRING_CONVERSION).booleanValue(), - options.get(CUSTOM_HEADERS), - options.getBooleanValue(ENABLE_CONSTRAINT_VALIDATION).booleanValue() + options.get(Constants.ConfigConstants.SKIP_LINES), + options.getBooleanValue(Constants.ConfigConstants.NIL_AS_OPTIONAL).booleanValue(), + options.getBooleanValue(Constants.ConfigConstants.ABSENT_AS_NILABLE).booleanValue(), + options.getBooleanValue(Constants.ConfigConstants.ALLOW_DATA_PROJECTION).booleanValue(), + options.getBooleanValue(Constants.ConfigConstants.STRING_CONVERSION).booleanValue(), + options.get(Constants.ConfigConstants.CUSTOM_HEADERS), + options.getBooleanValue(Constants.ConfigConstants.ENABLE_CONSTRAINT_VALIDATION).booleanValue() ); } @@ -163,60 +147,60 @@ private CsvConfig(char delimiter, char textEnclosure, Object header, char escape public static CsvConfig createRecordAsRecordOption(BMap options) { updateDataProjectOptions(options); return new CsvConfig( - options.getBooleanValue(ENABLE_CONSTRAINT_VALIDATION), - options.get(SKIP_LINES), - options.getBooleanValue(NIL_AS_OPTIONAL), - options.getBooleanValue(ABSENT_AS_NILABLE), - options.getBooleanValue(ALLOW_DATA_PROJECTION) + options.getBooleanValue(Constants.ConfigConstants.ENABLE_CONSTRAINT_VALIDATION), + options.get(Constants.ConfigConstants.SKIP_LINES), + options.getBooleanValue(Constants.ConfigConstants.NIL_AS_OPTIONAL), + options.getBooleanValue(Constants.ConfigConstants.ABSENT_AS_NILABLE), + options.getBooleanValue(Constants.ConfigConstants.ALLOW_DATA_PROJECTION) ); } public static CsvConfig createParseOptions(BMap options) { updateDataProjectOptions(options); return new CsvConfig( - StringUtils.getStringValue(options.getStringValue(DELIMITER)).charAt(0), - StringUtils.getStringValue(options.getStringValue(TEXT_ENCLOSURE)).charAt(0), - options.get(HEADER), - StringUtils.getStringValue(options.getStringValue(ESCAPE_CHAR)).charAt(0), - options.get(LINE_TERMINATOR), - options.get(SKIP_LINES), - options.get(NIL_VALUE), - StringUtils.getStringValue(options.getStringValue(COMMENT_CHAR)).charAt(0), - StringUtils.getStringValue(options.getStringValue(LOCALE)), - options.getBooleanValue(NIL_AS_OPTIONAL), - options.getBooleanValue(ABSENT_AS_NILABLE), - options.getBooleanValue(ALLOW_DATA_PROJECTION) + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.DELIMITER)).charAt(0), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.TEXT_ENCLOSURE)).charAt(0), + options.get(Constants.ConfigConstants.HEADER), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.ESCAPE_CHAR)).charAt(0), + options.get(Constants.ConfigConstants.LINE_TERMINATOR), + options.get(Constants.ConfigConstants.SKIP_LINES), + options.get(Constants.ConfigConstants.NIL_VALUE), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.COMMENT_CHAR)).charAt(0), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.LOCALE)), + options.getBooleanValue(Constants.ConfigConstants.NIL_AS_OPTIONAL), + options.getBooleanValue(Constants.ConfigConstants.ABSENT_AS_NILABLE), + options.getBooleanValue(Constants.ConfigConstants.ALLOW_DATA_PROJECTION) ); } public static CsvConfig createParserToRecordOptions(BMap options) { updateDataProjectOptions(options); return new CsvConfig( - StringUtils.getStringValue(options.getStringValue(DELIMITER)).charAt(0), - StringUtils.getStringValue(options.getStringValue(TEXT_ENCLOSURE)).charAt(0), - options.get(HEADER), - StringUtils.getStringValue(options.getStringValue(ESCAPE_CHAR)).charAt(0), - options.get(LINE_TERMINATOR), - options.get(SKIP_LINES), - options.getStringValue(NIL_VALUE), - StringUtils.getStringValue(options.getStringValue(COMMENT_CHAR)).charAt(0), - StringUtils.getStringValue(options.getStringValue(LOCALE)), - options.getBooleanValue(NIL_AS_OPTIONAL), - options.getBooleanValue(ABSENT_AS_NILABLE), - options.getBooleanValue(ALLOW_DATA_PROJECTION), - options.get(CUSTOM_HEADERS), - options.getBooleanValue(ENABLE_CONSTRAINT_VALIDATION) + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.DELIMITER)).charAt(0), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.TEXT_ENCLOSURE)).charAt(0), + options.get(Constants.ConfigConstants.HEADER), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.ESCAPE_CHAR)).charAt(0), + options.get(Constants.ConfigConstants.LINE_TERMINATOR), + options.get(Constants.ConfigConstants.SKIP_LINES), + options.getStringValue(Constants.ConfigConstants.NIL_VALUE), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.COMMENT_CHAR)).charAt(0), + StringUtils.getStringValue(options.getStringValue(Constants.ConfigConstants.LOCALE)), + options.getBooleanValue(Constants.ConfigConstants.NIL_AS_OPTIONAL), + options.getBooleanValue(Constants.ConfigConstants.ABSENT_AS_NILABLE), + options.getBooleanValue(Constants.ConfigConstants.ALLOW_DATA_PROJECTION), + options.get(Constants.ConfigConstants.CUSTOM_HEADERS), + options.getBooleanValue(Constants.ConfigConstants.ENABLE_CONSTRAINT_VALIDATION) ); } public static CsvConfig createToRecordOptions(BMap options) { updateDataProjectOptions(options); return new CsvConfig( - options.get(SKIP_LINES), - options.getBooleanValue(NIL_AS_OPTIONAL), - options.getBooleanValue(ABSENT_AS_NILABLE), - options.getBooleanValue(ALLOW_DATA_PROJECTION), - options.get(CUSTOM_HEADERS) + options.get(Constants.ConfigConstants.SKIP_LINES), + options.getBooleanValue(Constants.ConfigConstants.NIL_AS_OPTIONAL), + options.getBooleanValue(Constants.ConfigConstants.ABSENT_AS_NILABLE), + options.getBooleanValue(Constants.ConfigConstants.ALLOW_DATA_PROJECTION), + options.get(Constants.ConfigConstants.CUSTOM_HEADERS) ); } @@ -226,15 +210,17 @@ public static CsvConfig createConfigOptionsForUnion(CsvConfig config) { } private static void updateDataProjectOptions(BMap options) { - Object allowProjections = options.get(ALLOW_DATA_PROJECTION); + Object allowProjections = options.get(Constants.ConfigConstants.ALLOW_DATA_PROJECTION); if (allowProjections instanceof Boolean) { - options.put(NIL_AS_OPTIONAL, false); - options.put(ABSENT_AS_NILABLE, false); + options.put(Constants.ConfigConstants.NIL_AS_OPTIONAL, false); + options.put(Constants.ConfigConstants.ABSENT_AS_NILABLE, false); return; } BMap projections = (BMap) allowProjections; - options.put(ALLOW_DATA_PROJECTION, true); - options.put(NIL_AS_OPTIONAL, projections.getBooleanValue(NIL_AS_OPTIONAL)); - options.put(ABSENT_AS_NILABLE, projections.getBooleanValue(ABSENT_AS_NILABLE)); + options.put(Constants.ConfigConstants.ALLOW_DATA_PROJECTION, true); + options.put(Constants.ConfigConstants.NIL_AS_OPTIONAL, projections.getBooleanValue( + Constants.ConfigConstants.NIL_AS_OPTIONAL)); + options.put(Constants.ConfigConstants.ABSENT_AS_NILABLE, projections.getBooleanValue( + Constants.ConfigConstants.ABSENT_AS_NILABLE)); } } diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/CsvUtils.java b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/CsvUtils.java similarity index 76% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/CsvUtils.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/utils/CsvUtils.java index 1a927b5..6a306dd 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/CsvUtils.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/CsvUtils.java @@ -1,4 +1,4 @@ -package io.ballerina.stdlib.data.csvdata.utils; +package io.ballerina.lib.data.csvdata.utils; import io.ballerina.runtime.api.TypeTags; import io.ballerina.runtime.api.flags.SymbolFlags; @@ -21,9 +21,10 @@ import java.util.Map; import java.util.Optional; -import static io.ballerina.stdlib.data.csvdata.utils.Constants.SKIP_LINE_RANGE_SEP; +import static io.ballerina.lib.data.csvdata.utils.Constants.SKIP_LINE_RANGE_SEP; public class CsvUtils { + private static final long[] EMPTY_LONG_ARRAY = new long[]{}; public static boolean isCarriageTokenPresent = false; public static void setCarriageTokenPresent(boolean isCarriageTokenPresent) { @@ -123,24 +124,45 @@ public static boolean isHeaderFieldsEmpty(Map currentField) { public static boolean checkTypeCompatibility(Type constraintType, Object csv, boolean stringConversion) { int tag = constraintType.getTag(); - if ((csv instanceof BString && (stringConversion || tag == TypeTags.STRING_TAG - || tag == TypeTags.CHAR_STRING_TAG || isJsonOrAnyDataOrAny(tag))) - || (csv instanceof Long && (tag == TypeTags.INT_TAG - || tag == TypeTags.FLOAT_TAG || tag == TypeTags.DECIMAL_TAG || tag == TypeTags.BYTE_TAG - || tag == TypeTags.SIGNED8_INT_TAG || tag == TypeTags.SIGNED16_INT_TAG - || tag == TypeTags.SIGNED32_INT_TAG || tag == TypeTags.UNSIGNED8_INT_TAG - || tag == TypeTags.UNSIGNED16_INT_TAG || tag == TypeTags.UNSIGNED32_INT_TAG - || isJsonOrAnyDataOrAny(tag))) - || (csv instanceof BDecimal && ((tag == TypeTags.DECIMAL_TAG - || tag == TypeTags.FLOAT_TAG || tag == TypeTags.INT_TAG) || isJsonOrAnyDataOrAny(tag))) - || (csv instanceof Double && ((tag == TypeTags.FLOAT_TAG - || tag == TypeTags.DECIMAL_TAG || tag == TypeTags.INT_TAG) || isJsonOrAnyDataOrAny(tag))) - || (Boolean.class.isInstance(csv) && (tag == TypeTags.BOOLEAN_TAG || isJsonOrAnyDataOrAny(tag))) - || (csv == null && (tag == TypeTags.NULL_TAG || isJsonOrAnyDataOrAny(tag)))) { - return true; - } else { - return false; + if (csv instanceof BString) { + if (stringConversion || tag == TypeTags.STRING_TAG + || tag == TypeTags.CHAR_STRING_TAG || isJsonOrAnyDataOrAny(tag)) { + return true; + } + } + if (csv instanceof Long) { + if (tag == TypeTags.INT_TAG + || tag == TypeTags.FLOAT_TAG || tag == TypeTags.DECIMAL_TAG || tag == TypeTags.BYTE_TAG + || tag == TypeTags.SIGNED8_INT_TAG || tag == TypeTags.SIGNED16_INT_TAG + || tag == TypeTags.SIGNED32_INT_TAG || tag == TypeTags.UNSIGNED8_INT_TAG + || tag == TypeTags.UNSIGNED16_INT_TAG || tag == TypeTags.UNSIGNED32_INT_TAG + || isJsonOrAnyDataOrAny(tag)) { + return true; + } + } + if (csv instanceof BDecimal) { + if ((tag == TypeTags.DECIMAL_TAG + || tag == TypeTags.FLOAT_TAG || tag == TypeTags.INT_TAG) || isJsonOrAnyDataOrAny(tag)) { + return true; + } } + if (csv instanceof Double) { + if ((tag == TypeTags.FLOAT_TAG + || tag == TypeTags.DECIMAL_TAG || tag == TypeTags.INT_TAG) || isJsonOrAnyDataOrAny(tag)) { + return true; + } + } + if (Boolean.class.isInstance(csv)) { + if (tag == TypeTags.BOOLEAN_TAG || isJsonOrAnyDataOrAny(tag)) { + return true; + } + } + if (csv == null) { + if (tag == TypeTags.NULL_TAG || isJsonOrAnyDataOrAny(tag)) { + return true; + } + } + return false; } private static boolean isJsonOrAnyDataOrAny(int tag) { @@ -159,8 +181,7 @@ public static int getTheActualExpectedType(Type type) { } } - public static HashMap - processNameAnnotationsAndBuildCustomFieldMap(RecordType recordType, + public static Map processNameAnnotationsAndBuildCustomFieldMap(RecordType recordType, Map fieldHierarchy) { BMap annotations = recordType.getAnnotations(); HashMap updatedRecordFieldNames = new HashMap<>(); @@ -240,12 +261,11 @@ public static long[] getSkipDataRows(Object skipLines) { if (skipLines == null) { return new long[]{}; } - if (skipLines instanceof BArray) { - BArray skipLinesArray = (BArray) skipLines; + if (skipLines instanceof BArray skipLinesArray) { if (skipLinesArray.getLength() == 0) { - return new long[]{}; + return EMPTY_LONG_ARRAY; } - skipDataRows = (skipLinesArray).getIntArray(); + skipDataRows = skipLinesArray.getIntArray(); return skipDataRows; } @@ -257,36 +277,35 @@ public static boolean isNullValue(Object nullValue, Object value) { if (value == null) { return true; } - if (value instanceof BString) { - value = StringUtils.getStringValue(value); + if (value instanceof BString bString) { + value = StringUtils.getStringValue(bString); } if (value instanceof String v) { - if ((nullValue == null) && (Constants.Values.NULL.equalsIgnoreCase(v) - || Constants.Values.BALLERINA_NULL.equalsIgnoreCase(v))) { - return true; - } - if (nullValue != null && value.equals(StringUtils.getStringValue(nullValue))) { - return true; - } - return false; + return handleStringNullValue(nullValue, v, value); + } + return false; + } + + private static boolean handleStringNullValue(Object nullValue, String v, Object value) { + if ((nullValue == null) && (Constants.Values.NULL.equalsIgnoreCase(v) + || Constants.Values.BALLERINA_NULL.equalsIgnoreCase(v))) { + return true; + } + if (nullValue != null && value.equals(StringUtils.getStringValue(nullValue))) { + return true; } return false; } public static boolean isCharContainsInLineTerminatorUserConfig(char c, Object lineTerminatorObj) { - if (lineTerminatorObj instanceof BArray) { - Object[] lineTerminators = ((BArray) lineTerminatorObj).getValues(); + if (lineTerminatorObj instanceof BArray array) { + Object[] lineTerminators = array.getValues(); for (Object lineTerminator: lineTerminators) { - if (lineTerminator != null && c == Constants.LineTerminator.LF) { - String lineTerminatorString = lineTerminator.toString(); - if (isCarriageTokenPresent) { - if (lineTerminatorString.equals(Constants.LineTerminator.CRLF)) { - return true; - } - continue; - } - return true; + Optional value = handleLineTerminator(lineTerminator, c); + if (value.isEmpty()) { + continue; } + return value.get(); } return false; } @@ -306,6 +325,20 @@ public static boolean isCharContainsInLineTerminatorUserConfig(char c, Object li return false; } + private static Optional handleLineTerminator(Object lineTerminator, char c) { + if (lineTerminator != null && c == Constants.LineTerminator.LF) { + String lineTerminatorString = lineTerminator.toString(); + if (isCarriageTokenPresent) { + if (lineTerminatorString.equals(Constants.LineTerminator.CRLF)) { + return Optional.of(true); + } + return Optional.empty(); + } + return Optional.of(true); + } + return Optional.empty(); + } + public static class SortConfigurations { protected Object columnName; protected Object sortOrder; diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DataUtils.java b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/DataUtils.java similarity index 95% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DataUtils.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/utils/DataUtils.java index 06c1488..d3ce960 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DataUtils.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/DataUtils.java @@ -1,4 +1,4 @@ -package io.ballerina.stdlib.data.csvdata.utils; +package io.ballerina.lib.data.csvdata.utils; import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BTypedesc; diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DiagnosticErrorCode.java b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/DiagnosticErrorCode.java similarity index 98% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DiagnosticErrorCode.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/utils/DiagnosticErrorCode.java index 20e7ac1..ce669fd 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DiagnosticErrorCode.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/DiagnosticErrorCode.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.utils; +package io.ballerina.lib.data.csvdata.utils; /** * Represents a diagnostic error code. diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DiagnosticLog.java b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/DiagnosticLog.java similarity index 92% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DiagnosticLog.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/utils/DiagnosticLog.java index 1836d4a..e4687d5 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/DiagnosticLog.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/DiagnosticLog.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.utils; +package io.ballerina.lib.data.csvdata.utils; import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.utils.StringUtils; @@ -48,7 +48,7 @@ private static String formatMessage(DiagnosticErrorCode code, Object[] args) { } public static BError getCsvError(String message, String errorType) { - return ErrorCreator.createError(io.ballerina.stdlib.data.csvdata.utils.ModuleUtils.getModule(), + return ErrorCreator.createError(ModuleUtils.getModule(), errorType, StringUtils.fromString(message), null, null); } diff --git a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/ModuleUtils.java b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/ModuleUtils.java similarity index 96% rename from native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/ModuleUtils.java rename to native/src/main/java/io/ballerina/lib/data/csvdata/utils/ModuleUtils.java index d9de709..486c9f3 100644 --- a/native/src/main/java/io/ballerina/stdlib/data/csvdata/utils/ModuleUtils.java +++ b/native/src/main/java/io/ballerina/lib/data/csvdata/utils/ModuleUtils.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.stdlib.data.csvdata.utils; +package io.ballerina.lib.data.csvdata.utils; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Module; diff --git a/native/src/main/java/module-info.java b/native/src/main/java/module-info.java index dfa31e5..de54042 100644 --- a/native/src/main/java/module-info.java +++ b/native/src/main/java/module-info.java @@ -22,6 +22,6 @@ requires junit; requires org.apache.commons.lang3; requires io.ballerina.stdlib.constraint; - exports io.ballerina.stdlib.data.csvdata.csv; - exports io.ballerina.stdlib.data.csvdata.utils; + exports io.ballerina.lib.data.csvdata.csv; + exports io.ballerina.lib.data.csvdata.utils; }