feat: intial commit

This commit is contained in:
Jonas Juselius
2022-04-11 11:58:12 +02:00
commit 681f872c65
22 changed files with 10915 additions and 0 deletions

69
.build/Build.fs Normal file
View 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
View 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
View 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
View 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

View 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"
]
}

View File

@@ -0,0 +1,3 @@
{
"FSharp.fsacRuntime":"netcore"
}

32
.editorconfig Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,9 @@
# Oceanbox.GeoJson
## Run
`dotnet run`
## Build
`dotnet run Bundle`

1
RELEASE_NOTES.md Normal file
View File

@@ -0,0 +1 @@
# Changelog

10009
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

11
package.json Normal file
View 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
View 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>

View 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
View 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
View 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
View 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>