From f69910b2fa03d2d5a37809acccc3d46d1e44d3e9 Mon Sep 17 00:00:00 2001
From: david-swift
Date: Fri, 4 Oct 2024 00:35:31 +0200
Subject: [PATCH] Initial commit
---
.github/ISSUE_TEMPLATE/bug_report.yml | 40 +++++
.github/ISSUE_TEMPLATE/feature_request.yml | 36 ++++
.github/PULL_REQUEST_TEMPLATE.md | 11 ++
.github/workflows/docs.yml | 45 +++++
.github/workflows/swiftlint.yml | 30 ++++
.gitignore | 14 ++
.swiftlint.yml | 163 +++++++++++++++++++
LICENSE.md | 21 +++
Package.swift | 41 +++++
README.md | 28 ++++
Sources/State.swift | 93 +++++++++++
Sources/meta-sqlite.docc/MetaSQLite.md | 4 +
Sources/meta-sqlite.docc/theme-settings.json | 45 +++++
Tests/Test.swift | 23 +++
14 files changed, 594 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml
create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
create mode 100644 .github/workflows/docs.yml
create mode 100644 .github/workflows/swiftlint.yml
create mode 100644 .gitignore
create mode 100644 .swiftlint.yml
create mode 100644 LICENSE.md
create mode 100644 Package.swift
create mode 100644 README.md
create mode 100644 Sources/State.swift
create mode 100644 Sources/meta-sqlite.docc/MetaSQLite.md
create mode 100644 Sources/meta-sqlite.docc/theme-settings.json
create mode 100644 Tests/Test.swift
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..ee1a591
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,40 @@
+name: Bug report
+description: Something is not working as expected.
+title: Description of the bug
+labels: bug
+
+body:
+ - type: textarea
+ attributes:
+ label: Describe the bug
+ description: >-
+ A clear and concise description of what the bug is.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: To Reproduce
+ description: >-
+ Steps to reproduce the behavior.
+ placeholder: |
+ 1. Go to '...'
+ 2. Click on '....'
+ 3. Scroll down to '....'
+ 4. See error
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Expected behavior
+ description: >-
+ A clear and concise description of what you expected to happen.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Additional context
+ description: >-
+ Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..c244dbb
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,36 @@
+name: Feature request
+description: Suggest an idea for this project
+title: Description of the feature request
+labels: enhancement
+
+body:
+ - type: input
+ attributes:
+ label: Is your feature request related to a problem? Please describe.
+ placeholder: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+ validations:
+ required: false
+
+ - type: textarea
+ attributes:
+ label: Describe the solution you'd like
+ placeholder: >-
+ A clear and concise description of what you want to happen.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Describe alternatives you've considered
+ placeholder: >-
+ A clear and concise description of any alternative solutions or features you've considered.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Additional context
+ placeholder: >-
+ Add any other context or screenshots about the feature request here.
+ validations:
+ required: true
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..cce03ae
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,11 @@
+## Steps
+- [ ] Build the project on your machine. If it does not compile, fix the errors.
+- [ ] Describe the purpose and approach of your pull request below.
+- [ ] Submit the pull request. Thank you very much for your contribution!
+
+## Purpose
+_Describe the problem or feature._
+_If there is a related issue, add the link._
+
+## Approach
+_Describe how this pull request solves the problem or adds the feature._
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..6491463
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,45 @@
+name: Deploy Docs
+
+on:
+ push:
+ branches: ["main"]
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: true
+
+jobs:
+ Deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: macos-15
+ steps:
+ - uses: actions/checkout@v4
+ - name: Build Docs
+ run: |
+ xcrun xcodebuild docbuild \
+ -scheme Meta \
+ -destination 'generic/platform=macOS' \
+ -derivedDataPath "$PWD/.derivedData" \
+ -skipPackagePluginValidation
+ xcrun docc process-archive transform-for-static-hosting \
+ "$PWD/.derivedData/Build/Products/Debug/Meta.doccarchive" \
+ --output-path "docs" \
+ --hosting-base-path "Meta"
+ - name: Modify Docs
+ run: |
+ echo "" > docs/index.html;
+ sed -i '' 's/,2px/,10px/g' docs/css/index.*.css
+ - name: Upload Artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: 'docs'
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/swiftlint.yml b/.github/workflows/swiftlint.yml
new file mode 100644
index 0000000..5348bdb
--- /dev/null
+++ b/.github/workflows/swiftlint.yml
@@ -0,0 +1,30 @@
+name: SwiftLint
+
+on:
+ push:
+ paths:
+ - '.github/workflows/swiftlint.yml'
+ - '.swiftlint.yml'
+ - '**/*.swift'
+ pull_request:
+ paths:
+ - '.github/workflows/swiftlint.yml'
+ - '.swiftlint.yml'
+ - '**/*.swift'
+ workflow_dispatch:
+ paths:
+ - '.github/workflows/swiftlint.yml'
+ - '.swiftlint.yml'
+ - '**/*.swift'
+
+jobs:
+ SwiftLint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - name: SwiftLint
+ uses: norio-nomura/action-swiftlint@3.2.1
+ with:
+ args: --strict
+ env:
+ WORKING_DIRECTORY: Source
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e1c5612
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
+xcuserdata/
+DerivedData/
+.swiftpm/config/registries.json
+.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+.netrc
+/Package.resolved
+.Ulysses-Group.plist
+/.docc-build
+/io.github.AparokshaUI.Generation.json
+/.vscode
\ No newline at end of file
diff --git a/.swiftlint.yml b/.swiftlint.yml
new file mode 100644
index 0000000..8de0e3f
--- /dev/null
+++ b/.swiftlint.yml
@@ -0,0 +1,163 @@
+# Opt-In Rules
+opt_in_rules:
+ - anonymous_argument_in_multiline_closure
+ - array_init
+ - attributes
+ - closure_body_length
+ - closure_end_indentation
+ - closure_spacing
+ - collection_alignment
+ - comma_inheritance
+ - conditional_returns_on_newline
+ - contains_over_filter_count
+ - contains_over_filter_is_empty
+ - contains_over_first_not_nil
+ - contains_over_range_nil_comparison
+ - convenience_type
+ - discouraged_none_name
+ - discouraged_object_literal
+ - discouraged_optional_boolean
+ - discouraged_optional_collection
+ - empty_collection_literal
+ - empty_count
+ - empty_string
+ - enum_case_associated_values_count
+ - explicit_init
+ - fallthrough
+ - file_header
+ - file_name
+ - file_name_no_space
+ - first_where
+ - flatmap_over_map_reduce
+ - force_unwrapping
+ - function_default_parameter_at_end
+ - identical_operands
+ - implicit_return
+ - implicitly_unwrapped_optional
+ - joined_default_parameter
+ - last_where
+ - legacy_multiple
+ - let_var_whitespace
+ - literal_expression_end_indentation
+ - local_doc_comment
+ - lower_acl_than_parent
+ - missing_docs
+ - modifier_order
+ - multiline_arguments
+ - multiline_arguments_brackets
+ - multiline_function_chains
+ - multiline_literal_brackets
+ - multiline_parameters
+ - multiline_parameters_brackets
+ - no_extension_access_modifier
+ - no_grouping_extension
+ - no_magic_numbers
+ - number_separator
+ - operator_usage_whitespace
+ - optional_enum_case_matching
+ - prefer_self_in_static_references
+ - prefer_self_type_over_type_of_self
+ - prefer_zero_over_explicit_init
+ - prohibited_interface_builder
+ - redundant_nil_coalescing
+ - redundant_type_annotation
+ - return_value_from_void_function
+ - shorthand_optional_binding
+ - sorted_first_last
+ - sorted_imports
+ - static_operator
+ - strict_fileprivate
+ - switch_case_on_newline
+ - toggle_bool
+ - trailing_closure
+ - type_contents_order
+ - unneeded_parentheses_in_closure_argument
+ - yoda_condition
+
+# Disabled Rules
+disabled_rules:
+ - block_based_kvo
+ - class_delegate_protocol
+ - dynamic_inline
+ - is_disjoint
+ - no_fallthrough_only
+ - notification_center_detachment
+ - ns_number_init_as_function_reference
+ - nsobject_prefer_isequal
+ - private_over_fileprivate
+ - redundant_objc_attribute
+ - self_in_property_initialization
+ - todo
+ - unavailable_condition
+ - valid_ibinspectable
+ - xctfail_message
+
+# Custom Rules
+custom_rules:
+ github_issue:
+ name: 'GitHub Issue'
+ regex: '//.(TODO|FIXME):.(?!.*(https://github\.com/AparokshaUI/meta-sqlite/issues/\d))'
+ message: 'The related GitHub issue must be included in a TODO or FIXME.'
+ severity: warning
+
+ fatal_error:
+ name: 'Fatal Error'
+ regex: 'fatalError.*\(.*\)'
+ message: 'Fatal error should not be used.'
+ severity: error
+
+ enum_case_parameter:
+ name: 'Enum Case Parameter'
+ regex: 'case [a-zA-Z0-9]*\([a-zA-Z0-9\.<>?,\n\t =]+\)'
+ message: 'The associated values of an enum case should have parameters.'
+ severity: warning
+
+ tab:
+ name: 'Whitespaces Instead of Tab'
+ regex: '\t'
+ message: 'Spaces should be used instead of tabs.'
+ severity: warning
+
+ # Thanks to the creator of the SwiftLint rule
+ # "empty_first_line"
+ # https://github.com/coteditor/CotEditor/blob/main/.swiftlint.yml
+ # in the GitHub repository
+ # "CotEditor"
+ # https://github.com/coteditor/CotEditor
+ empty_first_line:
+ name: 'Empty First Line'
+ regex: '(^[ a-zA-Z ]*(?:protocol|extension|class|struct) (?!(?:var|let))[ a-zA-Z:]*\{\n *\S+)'
+ message: 'There should be an empty line after a declaration'
+ severity: error
+
+# Analyzer Rules
+analyzer_rules:
+ - unused_declaration
+ - unused_import
+
+# Options
+file_header:
+ required_pattern: '(// swift-tools-version: .+)?//\n// .*.swift\n// meta-sqlite\n//\n// Created by .* on .*\.(\n// Edited by (.*,)+\.)*\n(\n// Thanks to .* for the .*:\n// ".*"\n// https://.* \(\d\d.\d\d.\d\d\))*//\n'
+missing_docs:
+ warning: [internal, private]
+ error: [open, public]
+ excludes_inherited_types: false
+type_contents_order:
+ order:
+ - case
+ - type_alias
+ - associated_type
+ - type_property
+ - instance_property
+ - ib_inspectable
+ - ib_outlet
+ - subscript
+ - initializer
+ - deinitializer
+ - subtype
+ - type_method
+ - view_life_cycle_method
+ - ib_action
+ - other_method
+excluded:
+ - .build/
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..626e124
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 david-swift
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..f3e24ba
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,41 @@
+// swift-tools-version: 6.0
+//
+// Package.swift
+// meta-sqlite
+//
+// Created by david-swift on 04.10.24.
+//
+
+import PackageDescription
+
+/// The meta-sqlite package is part of the Aparoksha project.
+let package = Package(
+ name: "meta-sqlite",
+ platforms: [
+ .macOS(.v10_15),
+ .iOS(.v13)
+ ],
+ products: [
+ .library(
+ name: "MetaSQLite",
+ targets: ["MetaSQLite"]
+ )
+ ],
+ dependencies: [
+ .package(url: "https://github.com/AparokshaUI/Meta", branch: "main"),
+ .package(url: "https://github.com/stephencelis/SQLite.swift", from: "0.15.3")
+ ],
+ targets: [
+ .target(
+ name: "MetaSQLite",
+ dependencies: ["Meta", .product(name: "SQLite", package: "SQLite.swift")],
+ path: "Sources"
+ ),
+ .executableTarget(
+ name: "Tests",
+ dependencies: ["MetaSQLite"],
+ path: "Tests"
+ )
+ ],
+ swiftLanguageModes: [.v5]
+)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..305e506
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+
+
SQLite for Meta
+
+
+
+
+ Documentation
+
+ ยท
+
+ GitHub
+
+
+
+_SQLite for Meta_ is a simple extension for the [Meta](https://aparokshaui.github.io/Meta) framework remembering state data between app launches.
+
+## Thanks
+
+### Dependencies
+
+- [Meta](https://github.com/AparokshaUI/Meta) licensed under the [MIT License](https://github.com/AparokshaUI/Meta/blob/main/LICENSE.md)
+- [SQLite.swift](https://github.com/stephencelis/SQLite.swift) licensed under the [MIT License](https://github.com/stephencelis/SQLite.swift/blob/master/LICENSE.txt)
+
+### Other Thanks
+
+- [DocC](https://github.com/apple/swift-docc) used for the documentation
+- [SwiftLint](https://github.com/realm/SwiftLint) for checking whether code style conventions are violated
+- The programming language [Swift](https://github.com/swiftlang/swift)
diff --git a/Sources/State.swift b/Sources/State.swift
new file mode 100644
index 0000000..d3490ea
--- /dev/null
+++ b/Sources/State.swift
@@ -0,0 +1,93 @@
+//
+// State.swift
+// meta-sqlite
+//
+// Created by david-swift on 04.10.24.
+//
+
+import Foundation
+import Meta
+import SQLite
+
+extension State where Value: Codable {
+
+ /// Initialize a property being remembered between launches of the app.
+ /// - Parameters:
+ /// - wrappedValue: The wrapped value, used as an initial value if no stored value is found.
+ /// - stateID: The identifier for the stored value.
+ /// - forceUpdates: Whether to force update all available views when the property gets modified.
+ ///
+ /// Define a custom path for storing the data with ``DatabaseInformation/setPath(_:)``.
+ public init(wrappedValue: @autoclosure @escaping () -> Value, _ stateID: String, forceUpdates: Bool = false) {
+ self.init(
+ wrappedValue: {
+ let query = DatabaseInformation.table
+ .filter(DatabaseInformation.id == stateID)
+ .limit(1)
+ var data: Data?
+ guard let rows = try? DatabaseInformation.connection?.prepare(query) else {
+ return wrappedValue()
+ }
+ for row in rows {
+ data = row[DatabaseInformation.data]
+ }
+ guard let data else {
+ return wrappedValue()
+ }
+ let value = try? JSONDecoder().decode(Value.self, from: data)
+ return value ?? wrappedValue()
+ },
+ writeValue: { value in
+ if let data = try? JSONEncoder().encode(value) {
+ _ = try? DatabaseInformation.connection?.run(
+ DatabaseInformation.table.insert(
+ or: .replace,
+ DatabaseInformation.id <- stateID,
+ DatabaseInformation.data <- data
+ )
+ )
+ }
+ },
+ forceUpdates: forceUpdates
+ )
+ }
+
+}
+
+/// Information about the database.
+public enum DatabaseInformation {
+
+ /// The path.
+ static var path = "./database.sqlite"
+ /// The table.
+ static let table = Table("data")
+ /// The ID field.
+ static let id = SQLite.Expression("id")
+ /// The data field.
+ static let data = SQLite.Expression("data")
+ /// The SQLite connection.
+ private static var privateConnection: Connection?
+
+ /// The SQLite connection.
+ static var connection: Connection? {
+ if let privateConnection {
+ return privateConnection
+ }
+ let connection = try? Connection(path)
+ privateConnection = connection
+ _ = try? connection?.run(table.create { table in
+ table.column(id, primaryKey: true)
+ table.column(data)
+ })
+ return connection
+ }
+
+ /// Set the path to the SQLite file.
+ /// - Parameter path: The path.
+ ///
+ /// Call this function before accessing any state values (when setting up the app storage).
+ public static func setPath(_ path: String) {
+ self.path = path
+ }
+
+}
diff --git a/Sources/meta-sqlite.docc/MetaSQLite.md b/Sources/meta-sqlite.docc/MetaSQLite.md
new file mode 100644
index 0000000..8fb7461
--- /dev/null
+++ b/Sources/meta-sqlite.docc/MetaSQLite.md
@@ -0,0 +1,4 @@
+# ``MetaSQLite``
+
+_SQLite for Meta_ is a simple extension for the [Meta](https://aparokshaui.github.io/Meta) framework remembering state data between app launches.
+
diff --git a/Sources/meta-sqlite.docc/theme-settings.json b/Sources/meta-sqlite.docc/theme-settings.json
new file mode 100644
index 0000000..8d4aafc
--- /dev/null
+++ b/Sources/meta-sqlite.docc/theme-settings.json
@@ -0,0 +1,45 @@
+{
+ "theme": {
+ "border-radius": "10px",
+ "button": {
+ "border-radius": "20px"
+ },
+ "color": {
+ "button-background": "#ea3358",
+ "button-background-active": "#ea3358",
+ "button-background-hover": "#fc557a",
+ "button-text": "#ffffff",
+ "header": "#7f313b",
+ "documentation-intro-accent": "var(--color-header)",
+ "link": "#ea3358",
+ "nav-link-color": "#ea3358",
+ "nav-dark-link-color": "#ea3358",
+ "tutorials-overview-link": "#fb4469",
+ "step-background": {
+ "light": "#fffaff",
+ "dark": "#302c2d"
+ },
+ "step-focused": "#ea3358",
+ "tabnav-item-border-color": "#ea3358",
+ "tutorial-background": {
+ "light": "",
+ "dark": "#1d1d1f"
+ },
+ "tutorials-overview-background": "linear-gradient(180deg, rgba(43,20,23,1) 0%, rgba(41, 3, 8, 0.808) 60%, rgba(0,0,0,1) 100%)",
+ "fill-light-blue-secondary": "#ea3358",
+ "fill-blue": "#ea3358",
+ "figure-blue": "#ea3358",
+ "standard-blue-documentation-intro-fill": "#ea3358",
+ "figure-blue": "#ea3358",
+ "tutorial-hero-background": "#100a0b",
+ "navigator-item-hover": {
+ "light": "#ea335815",
+ "dark": "#7f313b"
+ }
+ },
+ "additionalProperties": "#ea3358",
+ "tutorial-step": {
+ "border-radius": "15px"
+ }
+ }
+}
diff --git a/Tests/Test.swift b/Tests/Test.swift
new file mode 100644
index 0000000..868dd88
--- /dev/null
+++ b/Tests/Test.swift
@@ -0,0 +1,23 @@
+//
+// Test.swift
+// meta-sqlite
+//
+// Created by david-swift on 04.10.24.
+//
+
+import Meta
+import MetaSQLite
+
+/// The test function.
+func main() {
+ @State("test")
+ var test = 0
+ @State("other")
+ var other = 3
+ print(test)
+ print(other)
+ test = 1
+ other = 0
+}
+
+main()