feat: intial commit
This commit is contained in:
69
.build/Build.fs
Normal file
69
.build/Build.fs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
open Fake.Core
|
||||||
|
open Fake.IO
|
||||||
|
open Farmer
|
||||||
|
open Farmer.Builders
|
||||||
|
|
||||||
|
open Helpers
|
||||||
|
|
||||||
|
initializeContext()
|
||||||
|
|
||||||
|
let srcPath = Path.getFullName "src"
|
||||||
|
let testPath = Path.getFullName "test"
|
||||||
|
let libPath = Some srcPath
|
||||||
|
|
||||||
|
let deployPath = Path.getFullName "deploy"
|
||||||
|
let packPath = Path.getFullName "packages"
|
||||||
|
let versionFile = Path.getFullName ".version"
|
||||||
|
|
||||||
|
Target.create "Clean" (fun _ -> Shell.cleanDir deployPath)
|
||||||
|
|
||||||
|
Target.create "InstallClient" (fun _ ->
|
||||||
|
run npm "install" "."
|
||||||
|
run dotnet "tool restore" "."
|
||||||
|
)
|
||||||
|
|
||||||
|
Target.create "Bundle" (fun _ ->
|
||||||
|
run dotnet $"publish -c Release -o \"{deployPath}\"" srcPath
|
||||||
|
)
|
||||||
|
|
||||||
|
Target.create "BundleDebug" (fun _ ->
|
||||||
|
run dotnet $"publish -c Debug -o \"{deployPath}\"" srcPath
|
||||||
|
)
|
||||||
|
|
||||||
|
Target.create "Pack" (fun _ ->
|
||||||
|
match libPath with
|
||||||
|
| Some p -> run dotnet $"pack -c Release -o \"{packPath}\"" p
|
||||||
|
| None -> ()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Target.create "Format" (fun _ ->
|
||||||
|
run dotnet "fantomas . -r" "src"
|
||||||
|
)
|
||||||
|
|
||||||
|
Target.create "Test" (fun _ ->
|
||||||
|
if System.IO.Directory.Exists testPath then
|
||||||
|
run dotnet "run" testPath
|
||||||
|
else ()
|
||||||
|
)
|
||||||
|
|
||||||
|
open Fake.Core.TargetOperators
|
||||||
|
|
||||||
|
let dependencies = [
|
||||||
|
"Clean"
|
||||||
|
==> "InstallClient"
|
||||||
|
==> "Bundle"
|
||||||
|
|
||||||
|
"Clean"
|
||||||
|
==> "BundleDebug"
|
||||||
|
|
||||||
|
"Clean"
|
||||||
|
==> "Test"
|
||||||
|
|
||||||
|
|
||||||
|
"Clean"
|
||||||
|
==> "Pack"
|
||||||
|
]
|
||||||
|
|
||||||
|
[<EntryPoint>]
|
||||||
|
let main args = runOrDefault args
|
||||||
105
.build/Helpers.fs
Normal file
105
.build/Helpers.fs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
module Helpers
|
||||||
|
|
||||||
|
open Fake.Core
|
||||||
|
|
||||||
|
let initializeContext () =
|
||||||
|
let execContext = Context.FakeExecutionContext.Create false "build.fsx" [ ]
|
||||||
|
Context.setExecutionContext (Context.RuntimeContext.Fake execContext)
|
||||||
|
|
||||||
|
module Proc =
|
||||||
|
module Parallel =
|
||||||
|
open System
|
||||||
|
|
||||||
|
let locker = obj()
|
||||||
|
|
||||||
|
let colors =
|
||||||
|
[| ConsoleColor.Blue
|
||||||
|
ConsoleColor.Yellow
|
||||||
|
ConsoleColor.Magenta
|
||||||
|
ConsoleColor.Cyan
|
||||||
|
ConsoleColor.DarkBlue
|
||||||
|
ConsoleColor.DarkYellow
|
||||||
|
ConsoleColor.DarkMagenta
|
||||||
|
ConsoleColor.DarkCyan |]
|
||||||
|
|
||||||
|
let print color (colored: string) (line: string) =
|
||||||
|
lock locker
|
||||||
|
(fun () ->
|
||||||
|
let currentColor = Console.ForegroundColor
|
||||||
|
Console.ForegroundColor <- color
|
||||||
|
Console.Write colored
|
||||||
|
Console.ForegroundColor <- currentColor
|
||||||
|
Console.WriteLine line)
|
||||||
|
|
||||||
|
let onStdout index name (line: string) =
|
||||||
|
let color = colors.[index % colors.Length]
|
||||||
|
if isNull line then
|
||||||
|
print color $"{name}: --- END ---" ""
|
||||||
|
else if String.isNotNullOrEmpty line then
|
||||||
|
print color $"{name}: " line
|
||||||
|
|
||||||
|
let onStderr name (line: string) =
|
||||||
|
let color = ConsoleColor.Red
|
||||||
|
if isNull line |> not then
|
||||||
|
print color $"{name}: " line
|
||||||
|
|
||||||
|
let redirect (index, (name, createProcess)) =
|
||||||
|
createProcess
|
||||||
|
|> CreateProcess.redirectOutputIfNotRedirected
|
||||||
|
|> CreateProcess.withOutputEvents (onStdout index name) (onStderr name)
|
||||||
|
|
||||||
|
let printStarting indexed =
|
||||||
|
for (index, (name, c: CreateProcess<_>)) in indexed do
|
||||||
|
let color = colors.[index % colors.Length]
|
||||||
|
let wd =
|
||||||
|
c.WorkingDirectory
|
||||||
|
|> Option.defaultValue ""
|
||||||
|
let exe = c.Command.Executable
|
||||||
|
let args = c.Command.Arguments.ToStartInfo
|
||||||
|
print color $"{name}: {wd}> {exe} {args}" ""
|
||||||
|
|
||||||
|
let run cs =
|
||||||
|
cs
|
||||||
|
|> Seq.toArray
|
||||||
|
|> Array.indexed
|
||||||
|
|> fun x -> printStarting x; x
|
||||||
|
|> Array.map redirect
|
||||||
|
|> Array.Parallel.map Proc.run
|
||||||
|
|
||||||
|
let createProcess exe arg dir =
|
||||||
|
CreateProcess.fromRawCommandLine exe arg
|
||||||
|
|> CreateProcess.withWorkingDirectory dir
|
||||||
|
|> CreateProcess.ensureExitCode
|
||||||
|
|
||||||
|
let dotnet = createProcess "dotnet"
|
||||||
|
let npm =
|
||||||
|
let npmPath =
|
||||||
|
match ProcessUtils.tryFindFileOnPath "npm" with
|
||||||
|
| Some path -> path
|
||||||
|
| None ->
|
||||||
|
"npm was not found in path. Please install it and make sure it's available from your path. " +
|
||||||
|
"See https://safe-stack.github.io/docs/quickstart/#install-pre-requisites for more info"
|
||||||
|
|> failwith
|
||||||
|
|
||||||
|
createProcess npmPath
|
||||||
|
|
||||||
|
let run proc arg dir =
|
||||||
|
proc arg dir
|
||||||
|
|> Proc.run
|
||||||
|
|> ignore
|
||||||
|
|
||||||
|
let runParallel processes =
|
||||||
|
processes
|
||||||
|
|> Proc.Parallel.run
|
||||||
|
|> ignore
|
||||||
|
|
||||||
|
let runOrDefault args =
|
||||||
|
try
|
||||||
|
match args with
|
||||||
|
| [| target |] -> Target.runOrDefault target
|
||||||
|
| _ ->
|
||||||
|
Target.runOrDefault "Pack"
|
||||||
|
0
|
||||||
|
with e ->
|
||||||
|
printfn "%A" e
|
||||||
|
1
|
||||||
18
.config/dotnet-tools.json
Normal file
18
.config/dotnet-tools.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"fable": {
|
||||||
|
"version": "3.7.0",
|
||||||
|
"commands": [
|
||||||
|
"fable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"fantomas-tool": {
|
||||||
|
"version": "4.6.4",
|
||||||
|
"commands": [
|
||||||
|
"fantomas"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
.devcontainer/Dockerfile
Normal file
29
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0
|
||||||
|
|
||||||
|
# Add keys and sources lists
|
||||||
|
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash
|
||||||
|
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||||
|
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" \
|
||||||
|
| tee /etc/apt/sources.list.d/yarn.list
|
||||||
|
|
||||||
|
# Install node, 7zip, yarn, git, process tools
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y nodejs p7zip-full git procps ssh-client
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
RUN apt-get autoremove -y \
|
||||||
|
&& apt-get clean -y \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install dotnet tools
|
||||||
|
RUN dotnet tool install fable -g
|
||||||
|
|
||||||
|
# Trouble brewing
|
||||||
|
RUN rm /etc/ssl/openssl.cnf
|
||||||
|
|
||||||
|
# add dotnet tools to path to pick up fake and paket installation
|
||||||
|
ENV PATH="/root/.dotnet/tools:${PATH}"
|
||||||
|
|
||||||
|
# Copy endpoint specific user settings into container to specify
|
||||||
|
# .NET Core should be used as the runtime.
|
||||||
|
COPY settings.vscode.json /root/.vscode-remote/data/Machine/settings.json
|
||||||
11
.devcontainer/devcontainer.json
Normal file
11
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "SAFE",
|
||||||
|
"dockerFile": "Dockerfile",
|
||||||
|
"appPort": [8080, 8085],
|
||||||
|
"extensions": [
|
||||||
|
"ionide.ionide-fsharp",
|
||||||
|
"ms-dotnettools.csharp",
|
||||||
|
"editorconfig.editorconfig",
|
||||||
|
"msjsdiag.debugger-for-chrome"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
.devcontainer/settings.vscode.json
Normal file
3
.devcontainer/settings.vscode.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"FSharp.fsacRuntime":"netcore"
|
||||||
|
}
|
||||||
32
.editorconfig
Normal file
32
.editorconfig
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
[*.fs]
|
||||||
|
max_line_length=120
|
||||||
|
# Feliz style
|
||||||
|
fsharp_single_argument_web_mode=true
|
||||||
|
fsharp_space_before_colon=false
|
||||||
|
fsharp_max_if_then_else_short_width=60
|
||||||
|
fsharp_max_infix_operator_expression=50
|
||||||
|
fsharp_max_record_width=70
|
||||||
|
fsharp_max_record_number_of_items=1
|
||||||
|
fsharp_max_array_or_list_width=70
|
||||||
|
fsharp_max_array_or_list_number_of_items=1
|
||||||
|
fsharp_max_value_binding_width=70
|
||||||
|
fsharp_max_function_binding_width=40
|
||||||
|
fsharp_max_dot_get_expression_width=50
|
||||||
|
fsharp_multiline_block_brackets_on_same_column=true
|
||||||
|
fsharp_newline_between_type_definition_and_members=false
|
||||||
|
fsharp_max_elmish_width=40
|
||||||
|
fsharp_align_function_signature_to_indentation=false
|
||||||
|
fsharp_alternative_long_member_definitions=false
|
||||||
|
fsharp_multi_line_lambda_closing_newline=false
|
||||||
|
fsharp_disable_elmish_syntax=false
|
||||||
|
fsharp_keep_indent_in_branch=false
|
||||||
|
fsharp_blank_lines_around_nested_multiline_expressions=false
|
||||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.fable/
|
||||||
|
.fake/
|
||||||
|
.vs/
|
||||||
|
obj/
|
||||||
|
bin/
|
||||||
|
packages/
|
||||||
|
node_modules/
|
||||||
|
src/Client/public/js/
|
||||||
|
release.cmd
|
||||||
|
release.sh
|
||||||
|
.idea/
|
||||||
|
*.orig
|
||||||
|
*.DotSettings.user
|
||||||
|
deploy
|
||||||
|
.ionide/
|
||||||
|
*.db
|
||||||
|
build.fsx.lock
|
||||||
9
.gitlab-ci.yml
Normal file
9
.gitlab-ci.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
variables:
|
||||||
|
DEPLOY_NAME: default
|
||||||
|
DEPLOY_NAMESPACE: default
|
||||||
|
|
||||||
|
include:
|
||||||
|
- project: oceanbox/gitlab-ci
|
||||||
|
ref: main
|
||||||
|
file: DotnetPackage.gitlab-ci.yml
|
||||||
|
|
||||||
41
.releaserc.yaml
Normal file
41
.releaserc.yaml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- name: develop
|
||||||
|
prerelease: true
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- '@semantic-release/commit-analyzer'
|
||||||
|
- '@semantic-release/release-notes-generator'
|
||||||
|
- - '@semantic-release/changelog'
|
||||||
|
- changelogFile: RELEASE_NOTES.md
|
||||||
|
changelogTitle: "# Changelog"
|
||||||
|
- - 'semantic-release-dotnet'
|
||||||
|
- paths: [ "src/*.fsproj", "src/*/*.fsproj" ]
|
||||||
|
- - '@semantic-release/exec'
|
||||||
|
- generateNotesCmd: "echo ${nextRelease.version} > .version"
|
||||||
|
- - '@semantic-release/git'
|
||||||
|
- message: "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
|
||||||
|
assets: [ "RELEASE_NOTES.md", ".version", "src/*.fsproj", "src/*/*.fsproj" ]
|
||||||
|
- - '@semantic-release/gitlab'
|
||||||
|
- assets: []
|
||||||
|
|
||||||
|
analyzeCommits:
|
||||||
|
- path: "@semantic-release/commit-analyzer"
|
||||||
|
releaseRules:
|
||||||
|
- type: "fix"
|
||||||
|
release: "patch"
|
||||||
|
- type: "patch"
|
||||||
|
release: "patch"
|
||||||
|
- type: "feat"
|
||||||
|
release: "minor"
|
||||||
|
- type: "feature"
|
||||||
|
release: "minor"
|
||||||
|
- type: "minor"
|
||||||
|
release: "minor"
|
||||||
|
- type: "breaking"
|
||||||
|
release: "major"
|
||||||
|
- type: "major"
|
||||||
|
release: "major"
|
||||||
|
|
||||||
|
|
||||||
16
Build.fsproj
Normal file
16
Build.fsproj
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include=".build/Helpers.fs" />
|
||||||
|
<Compile Include=".build/Build.fs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Fake.Core.Target" Version="5.20.4" />
|
||||||
|
<PackageReference Include="Fake.DotNet.Cli" Version="5.20.4" />
|
||||||
|
<PackageReference Include="Fake.IO.FileSystem" Version="5.20.4" />
|
||||||
|
<PackageReference Include="Farmer" Version="1.6.26" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Serit Tromsø AS
|
||||||
|
|
||||||
|
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.
|
||||||
77
Oceanbox.GeoJson.sln
Normal file
77
Oceanbox.GeoJson.sln
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.27004.2005
|
||||||
|
MinimumVisualStudioVersion = 15.0.26124.0
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{328C82EA-D5C5-49E0-B3FB-490A12B2A8F6}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
README.md = README.md
|
||||||
|
LICENSE = LICENSE
|
||||||
|
Dockerfile = Dockerfile
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Build", "Build.fsproj", "{A83C8399-5D81-4860-BDF4-591741374D6C}"
|
||||||
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "src", "src/Oceanbox.GeoJson.fsproj", "{2D24D8A5-68FC-41BC-942D-DE23DB627E54}"
|
||||||
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "test", "test\Tests.fsproj", "{56D31E48-612D-4761-B7B7-549C5E5EAA64}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A83C8399-5D81-4860-BDF4-591741374D6C}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{2D24D8A5-68FC-41BC-942D-DE23DB627E54}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{56D31E48-612D-4761-B7B7-549C5E5EAA64}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {1385CB14-A9DD-4F05-8508-AB04EF45EAFA}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Oceanbox.GeoJson
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
`dotnet run`
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
`dotnet run Bundle`
|
||||||
1
RELEASE_NOTES.md
Normal file
1
RELEASE_NOTES.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Changelog
|
||||||
10009
package-lock.json
generated
Normal file
10009
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
package.json
Normal file
11
package.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"@semantic-release/changelog": "^6.0.1",
|
||||||
|
"@semantic-release/exec": "^6.0.3",
|
||||||
|
"@semantic-release/git": "^10.0.1",
|
||||||
|
"@semantic-release/gitlab": "^7.0.4",
|
||||||
|
"semantic-release-dotnet": "^1.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
313
src/GeoJson.fs
Normal file
313
src/GeoJson.fs
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
module Oceanbox.GeoJson
|
||||||
|
|
||||||
|
open System
|
||||||
|
#if FABLE_COMPILER
|
||||||
|
open Thoth.Json
|
||||||
|
#else
|
||||||
|
open Thoth.Json.Net
|
||||||
|
#endif
|
||||||
|
|
||||||
|
type Coord =
|
||||||
|
| C2 of float * float
|
||||||
|
| C3 of float * float * float
|
||||||
|
with
|
||||||
|
member __.get () =
|
||||||
|
match __ with
|
||||||
|
| C2 (x, y) -> x, y, 0.0
|
||||||
|
| C3 (x, y, z) -> x, y, z
|
||||||
|
|
||||||
|
member __.getXY () =
|
||||||
|
match __ with
|
||||||
|
| C2 (x, y) -> x, y
|
||||||
|
| C3 (x, y, _) -> x, y
|
||||||
|
|
||||||
|
member __.getZ () =
|
||||||
|
match __ with
|
||||||
|
| C2 _ -> 0.0
|
||||||
|
| C3 (_, _, z) -> z
|
||||||
|
|
||||||
|
static member apply f =
|
||||||
|
function
|
||||||
|
| C2 (x, y) -> C2 (f (x, y))
|
||||||
|
| C3 (x, y, z) ->
|
||||||
|
let x', y' = (f (x, y))
|
||||||
|
C3 (x', y', z)
|
||||||
|
|
||||||
|
static member apply (f, g) =
|
||||||
|
function
|
||||||
|
| C2 (x, y) -> C2 (f x, g y)
|
||||||
|
| C3 (x, y, z) -> C3 (f x, g y, z)
|
||||||
|
|
||||||
|
type MultiPoint = Coord []
|
||||||
|
type LineString = Coord []
|
||||||
|
type Polygon = Coord [] []
|
||||||
|
type MultiLineString = LineString []
|
||||||
|
type MultiPolygon = Polygon []
|
||||||
|
|
||||||
|
type GeometryObject =
|
||||||
|
| Point of Coord
|
||||||
|
| MultiPoint of MultiPoint
|
||||||
|
| LineString of LineString
|
||||||
|
| Polygon of Polygon
|
||||||
|
| MultiLineString of MultiLineString
|
||||||
|
| MultiPolygon of MultiPolygon
|
||||||
|
| GeometryCollection of GeometryObject []
|
||||||
|
with
|
||||||
|
member __.Encoder () =
|
||||||
|
let encodePos p =
|
||||||
|
match p with
|
||||||
|
| C2 (x, y) -> (Encode.array << Array.map Encode.float) [| x; y |]
|
||||||
|
| C3 (x, y, z) -> (Encode.array << Array.map Encode.float) [| x; y; z |]
|
||||||
|
let encodeCoord = Encode.array << Array.map encodePos
|
||||||
|
let encodePoints = Encode.array << Array.map encodeCoord
|
||||||
|
let encodeSegments = encodePoints
|
||||||
|
let encodePolygons = Encode.array << Array.map encodePoints
|
||||||
|
// let encodeSegments = Encode.array << Array.map encodePoints
|
||||||
|
match __ with
|
||||||
|
| Point x -> Encode.object [
|
||||||
|
"type", Encode.string "Point"
|
||||||
|
"coordinates", encodeCoord [| x |]
|
||||||
|
]
|
||||||
|
| MultiPoint x -> Encode.object [
|
||||||
|
"type", Encode.string "MultiPoint"
|
||||||
|
"coordinates", encodePoints [| x |]
|
||||||
|
]
|
||||||
|
| LineString x -> Encode.object [
|
||||||
|
"type", Encode.string "LineString"
|
||||||
|
"coordinates", encodePoints [| x |]
|
||||||
|
]
|
||||||
|
| Polygon x -> Encode.object [
|
||||||
|
"type", Encode.string "Polygon"
|
||||||
|
"coordinates", encodeSegments x
|
||||||
|
]
|
||||||
|
| MultiLineString x -> Encode.object [
|
||||||
|
"type", Encode.string "MultiLineString"
|
||||||
|
"coordinates", encodeSegments x
|
||||||
|
]
|
||||||
|
| MultiPolygon x -> Encode.object [
|
||||||
|
"type", Encode.string "MultiPolygon"
|
||||||
|
"coordinates", encodePolygons x
|
||||||
|
]
|
||||||
|
| GeometryCollection x -> Encode.object [
|
||||||
|
"type", Encode.string "GeometryCollection"
|
||||||
|
"geometries", Array.map (fun (g : GeometryObject) ->
|
||||||
|
g.Encoder ()) x
|
||||||
|
|> Encode.array
|
||||||
|
]
|
||||||
|
|
||||||
|
static member Decoder : Decoder<_> =
|
||||||
|
let decodeCoord = Decode.array Decode.float
|
||||||
|
let decodePoints = Decode.array decodeCoord
|
||||||
|
let decodeSegments = Decode.array decodePoints
|
||||||
|
let rec decoder () =
|
||||||
|
Decode.object (fun get ->
|
||||||
|
let inline getCoords (f :
|
||||||
|
string ->
|
||||||
|
JsonValue ->
|
||||||
|
Result<'T array, DecoderError>) =
|
||||||
|
get.Required.Field "coordinates" f
|
||||||
|
|
||||||
|
let toCoord c =
|
||||||
|
c
|
||||||
|
|> List.ofArray
|
||||||
|
|> function
|
||||||
|
| [x; y] -> C2 (x, y)
|
||||||
|
| [x; y; z] -> C3 (x, y, z)
|
||||||
|
| _ -> failwith "invalid coordinate data"
|
||||||
|
let coord () = getCoords decodeCoord |> toCoord
|
||||||
|
let points () = getCoords decodePoints |> Array.map toCoord
|
||||||
|
let segments () =
|
||||||
|
getCoords decodeSegments
|
||||||
|
|> Array.map (Array.map toCoord)
|
||||||
|
match get.Required.Field "type" Decode.string with
|
||||||
|
| "Point" -> coord () |> Point
|
||||||
|
| "MultiPoint" -> points () |> MultiPoint
|
||||||
|
| "LineString" -> points () |> LineString
|
||||||
|
| "Polygon" -> segments () |> Polygon
|
||||||
|
| "MultiLineString" -> segments () |> MultiLineString
|
||||||
|
| "MultiPolygon" -> segments () |> MultiLineString
|
||||||
|
| "GeometryCollection" ->
|
||||||
|
get.Required.Field "geometries" (Decode.array (decoder ()))
|
||||||
|
|> GeometryCollection
|
||||||
|
| _ -> failwith "error"
|
||||||
|
)
|
||||||
|
decoder ()
|
||||||
|
|
||||||
|
member __.Encode () =
|
||||||
|
let x = __.Encoder ()
|
||||||
|
Fable.Core.JS.console.log x
|
||||||
|
__.Encoder () |> Encode.toString 2
|
||||||
|
static member Decode x = Decode.fromString GeometryObject.Decoder x
|
||||||
|
|
||||||
|
static member apply f geo =
|
||||||
|
let t1 = Array.map f
|
||||||
|
let t2 = Array.map t1
|
||||||
|
match geo with
|
||||||
|
| Point x -> Point (f x)
|
||||||
|
| MultiPoint x -> MultiPoint (t1 x)
|
||||||
|
| LineString x -> LineString (t1 x)
|
||||||
|
| Polygon x -> Polygon (t2 x)
|
||||||
|
| MultiLineString x -> MultiLineString (t2 x)
|
||||||
|
| MultiPolygon x -> MultiPolygon (Array.map t2 x)
|
||||||
|
| GeometryCollection x ->
|
||||||
|
GeometryCollection (x |> Array.map (GeometryObject.apply f))
|
||||||
|
|
||||||
|
type BBox =
|
||||||
|
{
|
||||||
|
MinX: float
|
||||||
|
MinY: float
|
||||||
|
MaxX: float
|
||||||
|
MaxY: float
|
||||||
|
}
|
||||||
|
with
|
||||||
|
static member initial =
|
||||||
|
{
|
||||||
|
MinX = infinity
|
||||||
|
MinY = infinity
|
||||||
|
MaxX = -infinity
|
||||||
|
MaxY = -infinity
|
||||||
|
}
|
||||||
|
static member infinite =
|
||||||
|
{
|
||||||
|
MinX = -infinity
|
||||||
|
MinY = -infinity
|
||||||
|
MaxX = infinity
|
||||||
|
MaxY = infinity
|
||||||
|
}
|
||||||
|
static member create (box: float array) =
|
||||||
|
{
|
||||||
|
MinX = box.[0]
|
||||||
|
MinY = box.[1]
|
||||||
|
MaxX = box.[2]
|
||||||
|
MaxY = box.[3]
|
||||||
|
}
|
||||||
|
static member amend box1 box2 =
|
||||||
|
{
|
||||||
|
MinX = Math.Min (box1.MinX, box2.MinX)
|
||||||
|
MinY = Math.Min (box1.MinY, box2.MinY)
|
||||||
|
MaxX = Math.Max (box1.MaxX, box2.MaxX)
|
||||||
|
MaxY = Math.Max (box1.MaxY, box2.MaxY)
|
||||||
|
}
|
||||||
|
static member toArray box =
|
||||||
|
[|
|
||||||
|
box.MinX
|
||||||
|
box.MinY
|
||||||
|
box.MaxX
|
||||||
|
box.MaxY
|
||||||
|
|]
|
||||||
|
|
||||||
|
type Feature<'T> =
|
||||||
|
{
|
||||||
|
Geometry : GeometryObject
|
||||||
|
Properties : 'T option
|
||||||
|
BBox : BBox option
|
||||||
|
Id : int option
|
||||||
|
Size: float []
|
||||||
|
}
|
||||||
|
with
|
||||||
|
member __.Encoder (?propEncoder : 'T -> JsonValue) =
|
||||||
|
let props =
|
||||||
|
match __.Properties, propEncoder with
|
||||||
|
| Some props, Some encode -> [ "properties", encode props ]
|
||||||
|
| _ -> []
|
||||||
|
let bbox =
|
||||||
|
match __.BBox with
|
||||||
|
| Some b -> [ "bbox", Array.map Encode.float (BBox.toArray b) |> Encode.array ]
|
||||||
|
| _ -> []
|
||||||
|
let id =
|
||||||
|
match __.Id with
|
||||||
|
| Some id -> [ "id", Encode.int id ]
|
||||||
|
| _ -> []
|
||||||
|
let feature = [
|
||||||
|
"type", Encode.string "Feature"
|
||||||
|
"geometry", __.Geometry.Encoder ()
|
||||||
|
]
|
||||||
|
let all = List.concat [ feature; bbox; id; props ]
|
||||||
|
Encode.object all
|
||||||
|
|
||||||
|
static member Decoder (?propDecoder : Decoder<'T>) =
|
||||||
|
Decode.object (fun get ->
|
||||||
|
{
|
||||||
|
Geometry = get.Required.Field "geometry" GeometryObject.Decoder
|
||||||
|
BBox = get.Optional.Field "bbox" (Decode.array Decode.float) |> Option.map BBox.create
|
||||||
|
Id = get.Optional.Field "id" Decode.int
|
||||||
|
|
||||||
|
Properties =
|
||||||
|
if propDecoder.IsSome then
|
||||||
|
get.Optional.Field "properties" propDecoder.Value
|
||||||
|
else
|
||||||
|
None
|
||||||
|
Size = Array.empty
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
member __.Encode (?propEncoder : 'T -> JsonValue) =
|
||||||
|
match propEncoder with
|
||||||
|
| Some e -> __.Encoder e
|
||||||
|
| None -> __.Encoder ()
|
||||||
|
|> Encode.toString 2
|
||||||
|
|
||||||
|
static member Decode (x, ?propDecoder : Decoder<'T>) =
|
||||||
|
let d =
|
||||||
|
match propDecoder with
|
||||||
|
| Some x -> Feature<'T>.Decoder x
|
||||||
|
| None -> Feature<'T>.Decoder ()
|
||||||
|
Decode.fromString d x
|
||||||
|
|
||||||
|
static member apply f x =
|
||||||
|
{
|
||||||
|
x with Geometry = GeometryObject.apply f x.Geometry
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeatureCollection<'T> =
|
||||||
|
{
|
||||||
|
Features : Feature<'T> []
|
||||||
|
BBox : BBox option
|
||||||
|
}
|
||||||
|
with
|
||||||
|
member __.Encoder (?propEncoder : 'T -> JsonValue) =
|
||||||
|
let fencoder (f : Feature<'T>) =
|
||||||
|
match propEncoder with
|
||||||
|
| Some x -> f.Encoder x
|
||||||
|
| None -> f.Encoder ()
|
||||||
|
Encode.object [
|
||||||
|
"type", Encode.string "FeatureCollection"
|
||||||
|
"bbox", Encode.option (fun (a : BBox) ->
|
||||||
|
Array.map Encode.float (BBox.toArray a)
|
||||||
|
|> Encode.array
|
||||||
|
) __.BBox
|
||||||
|
"features", Encode.array (Array.map fencoder __.Features)
|
||||||
|
]
|
||||||
|
|
||||||
|
static member Decoder (?propDecoder : Decoder<'T>) : Decoder<FeatureCollection<'T>> =
|
||||||
|
let fdecoder =
|
||||||
|
match propDecoder with
|
||||||
|
| Some x -> Feature<'T>.Decoder x
|
||||||
|
| None -> Feature<'T>.Decoder ()
|
||||||
|
Decode.object (fun get ->
|
||||||
|
{
|
||||||
|
Features = get.Required.Field "features" (Decode.array fdecoder)
|
||||||
|
BBox =
|
||||||
|
get.Optional.Field "bbox" (Decode.array Decode.float)
|
||||||
|
|> Option.map BBox.create
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
member __.Encode (?propEncoder : 'T -> JsonValue) =
|
||||||
|
match propEncoder with
|
||||||
|
| Some e -> __.Encoder e
|
||||||
|
| None -> __.Encoder ()
|
||||||
|
|> Encode.toString 2
|
||||||
|
|
||||||
|
static member Decode (x, ?propDecoder : Decoder<'T>) =
|
||||||
|
let d =
|
||||||
|
match propDecoder with
|
||||||
|
| Some x -> FeatureCollection<'T>.Decoder x
|
||||||
|
| None -> FeatureCollection<'T>.Decoder ()
|
||||||
|
Decode.fromString d x
|
||||||
|
|
||||||
|
static member apply f = Array.map (Feature<_>.apply f)
|
||||||
|
|
||||||
|
type Feature = Feature<unit>
|
||||||
|
|
||||||
|
type FeatureCollection = FeatureCollection<unit>
|
||||||
25
src/Oceanbox.GeoJson.fsproj
Normal file
25
src/Oceanbox.GeoJson.fsproj
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
<IsPackable>true</IsPackable>
|
||||||
|
<PackageId>Oceanbox.GeoJson</PackageId>
|
||||||
|
<Authors></Authors>
|
||||||
|
<Company></Company>
|
||||||
|
<Version>0.0.1</Version>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="GeoJson.fs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FSharp.Data" Version="4.2.7" />
|
||||||
|
<PackageReference Include="FSharpPlus" Version="1.2.2" />
|
||||||
|
<PackageReference Include="Thoth.Json" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Thoth.Json.Net" Version="8.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="*.fsproj; *.fs" PackagePath="fable/" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
65
src/packages.lock.json
Normal file
65
src/packages.lock.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"net6.0": {
|
||||||
|
"FSharp.Core": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[6.0.1, )",
|
||||||
|
"resolved": "6.0.1",
|
||||||
|
"contentHash": "VrFAiW8dEEekk+0aqlbvMNZzDvYXmgWZwAt68AUBqaWK8RnoEVUNglj66bZzhs4/U63q0EfXlhcEKnH1sTYLjw=="
|
||||||
|
},
|
||||||
|
"FSharp.Data": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[4.2.7, )",
|
||||||
|
"resolved": "4.2.7",
|
||||||
|
"contentHash": "gQO0u0q1z9wXOkSmL7TVQLspAGR/S2Vm3CDPStEHCcTQyivkgoZie0IsB2Zyl2inC+hmQa/jcVQNQjo7XB7Ujg==",
|
||||||
|
"dependencies": {
|
||||||
|
"FSharp.Core": "4.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FSharpPlus": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.2.2, )",
|
||||||
|
"resolved": "1.2.2",
|
||||||
|
"contentHash": "YzWFuAua/OCevT05FoWSInP3i6DGAwRqyJd0DtFWSisPI6LAqCMTWaj5hT4BDLDabvricVZ5VD/FWfSNubL6Gg==",
|
||||||
|
"dependencies": {
|
||||||
|
"FSharp.Core": "4.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Thoth.Json": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[7.0.0, )",
|
||||||
|
"resolved": "7.0.0",
|
||||||
|
"contentHash": "0aJtAcjK8Ljx8tSUxHUxZQDInOGtPwGkB+fD9MSrBooe0eqseQAHNSD51CttK5kytqXM6YHPXPN6UFW65GdZFg==",
|
||||||
|
"dependencies": {
|
||||||
|
"FSharp.Core": "4.7.2",
|
||||||
|
"Fable.Core": "3.1.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Thoth.Json.Net": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[8.0.0, )",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "C/b+8g/xUTJTn7pbKC4bMAOy2tyolXAuHTXguT5TNzDKQ6sjnUfFa9B81fTt9PuUOdWFLyRKlXASuFhSQciJGQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"FSharp.Core": "4.7.2",
|
||||||
|
"Fable.Core": "[3.0.0, 4.0.0)",
|
||||||
|
"Newtonsoft.Json": "11.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Fable.Core": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "3.1.6",
|
||||||
|
"contentHash": "w6M1F0zoLk4kTFc1Lx6x1Ft6BD3QwRe0eaLiinAqbjVkcF+iK+NiXGJO+a6q9RAF9NCg0vI48Xku7aNeqG4JVw==",
|
||||||
|
"dependencies": {
|
||||||
|
"FSharp.Core": "4.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "11.0.2",
|
||||||
|
"contentHash": "IvJe1pj7JHEsP8B8J8DwlMEx8UInrs/x+9oVY+oCD13jpLu4JbJU2WCIsMRn5C4yW9+DgkaO8uiVE5VHKjpmdQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
test/Tests.fs
Normal file
18
test/Tests.fs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
module Tests
|
||||||
|
|
||||||
|
open Expecto
|
||||||
|
|
||||||
|
let server =
|
||||||
|
testList
|
||||||
|
"Server"
|
||||||
|
[
|
||||||
|
testCase "Adding valid Todo"
|
||||||
|
<| fun _ ->
|
||||||
|
let expectedResult = Ok()
|
||||||
|
Expect.equal (Ok()) expectedResult "Result should be ok"
|
||||||
|
]
|
||||||
|
|
||||||
|
let all = testList "All" [ server ]
|
||||||
|
|
||||||
|
[<EntryPoint>]
|
||||||
|
let main _ = runTests defaultConfig all
|
||||||
16
test/Tests.fsproj
Normal file
16
test/Tests.fsproj
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Tests.fs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\src\Oceanbox.GeoJson.fsproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Expecto" Version="9.0.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user