From b3c01bb43d9a5badd899d481dafdeed79de03090 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Sun, 17 Aug 2025 16:35:52 +0200 Subject: [PATCH 01/20] feat: whole bunch of shit --- examples/Article/A dress a day.md | 28 ++++ examples/Books/Minimal.md | 19 +++ examples/Books/NoAuthor.md | 18 +++ examples/Books/NoBody.md | 19 +++ examples/Books/NoRating.md | 28 ++++ examples/Books/TheGreatGatsby.md | 17 +++ examples/Movies/Minimal.md | 16 +++ examples/Movies/Negative.md | 23 ++++ examples/Movies/NoBody.md | 22 +++ examples/Movies/Structured.md | 24 ++++ examples/Recipes/baguette.md | 16 +++ examples/Recipes/cake.md | 21 +++ examples/Recipes/caprese-salad.md | 20 +++ examples/Recipes/cheese-sandwich.md | 18 +++ examples/Recipes/complex.md | 20 +++ examples/Recipes/lentil-curry.md | 21 +++ examples/Recipes/multiline.md | 23 ++++ examples/Recipes/optional-fields.md | 17 +++ examples/Recipes/pancakes.md | 21 +++ examples/Recipes/salad.md | 22 +++ examples/Recipes/spaghetti-carbonara.md | 21 +++ examples/Recipes/stir-fry.md | 21 +++ examples/Recipes/tomato-soup.md | 21 +++ examples/Recipes/unicode.md | 21 +++ examples/Recipes/water.md | 11 ++ go.work | 1 + registry/schema-org/Recipe.schema.json | 54 ++++++-- registry/templates/Recipe.marka | 4 + registry/templates/_default.marka | 2 - server/cmd/marka-server/main.go | 37 +++++ server/go.mod | 3 + server/internal/fsx/contenttype.go | 23 ++++ server/internal/fsx/path.go | 56 ++++++++ server/internal/handlers/file.go | 171 ++++++++++++++++++++++++ server/internal/httpx/error.go | 20 +++ server/internal/httpx/router.go | 11 ++ 36 files changed, 878 insertions(+), 12 deletions(-) create mode 100644 examples/Article/A dress a day.md create mode 100644 examples/Books/Minimal.md create mode 100644 examples/Books/NoAuthor.md create mode 100644 examples/Books/NoBody.md create mode 100644 examples/Books/NoRating.md create mode 100644 examples/Books/TheGreatGatsby.md create mode 100644 examples/Movies/Minimal.md create mode 100644 examples/Movies/Negative.md create mode 100644 examples/Movies/NoBody.md create mode 100644 examples/Movies/Structured.md create mode 100644 examples/Recipes/baguette.md create mode 100644 examples/Recipes/cake.md create mode 100644 examples/Recipes/caprese-salad.md create mode 100644 examples/Recipes/cheese-sandwich.md create mode 100644 examples/Recipes/complex.md create mode 100644 examples/Recipes/lentil-curry.md create mode 100644 examples/Recipes/multiline.md create mode 100644 examples/Recipes/optional-fields.md create mode 100644 examples/Recipes/pancakes.md create mode 100644 examples/Recipes/salad.md create mode 100644 examples/Recipes/spaghetti-carbonara.md create mode 100644 examples/Recipes/stir-fry.md create mode 100644 examples/Recipes/tomato-soup.md create mode 100644 examples/Recipes/unicode.md create mode 100644 examples/Recipes/water.md create mode 100644 server/cmd/marka-server/main.go create mode 100644 server/go.mod create mode 100644 server/internal/fsx/contenttype.go create mode 100644 server/internal/fsx/path.go create mode 100644 server/internal/handlers/file.go create mode 100644 server/internal/httpx/error.go create mode 100644 server/internal/httpx/router.go diff --git a/examples/Article/A dress a day.md b/examples/Article/A dress a day.md new file mode 100644 index 0000000..7025759 --- /dev/null +++ b/examples/Article/A dress a day.md @@ -0,0 +1,28 @@ +--- +@type: Article +author.name: Erin Mckean +url: https://dressaday.com/2006/10/20/you-dont-have-to-be-pretty/ +rating: 5 +date: December 7, 2023 +image: https://i0.wp.com/old-dressaday-images.s3-website-us-west-2.amazonaws.com/6a0133ed1b1479970b0134809d9f8b970c.jpg +--- + +# You Dont Have to Be Pretty – A Dress A Day + +#positivity + +![Vreeland](https://i0.wp.com/old-dressaday-images.s3-website-us-west-2.amazonaws.com/6a0133ed1b1479970b0134809d9f8b970c.jpg) + +*image is by [Andy Warhol](http://www.warholfoundation.org/) © 2015 The Andy Warhol Foundation for the Visual Arts, Inc. / Artists Rights Society (ARS), New York* + +So the other day, folks in the comments were [talking about leggings](http://www.dressaday.com/2006/10/open-letter-to-mr-mizrahi.html). I’m pretty agnostic about leggings, but the whole discussion (which centered on the fact that it can be \*really\* hard to look good in leggings) got me thinking about the pervasive idea that women owe it to onlookers to maintain a certain standard of decorativeness. + +Now, this may seem strange from someone who writes about pretty dresses (mostly) every day, but: You Don’t Have to Be Pretty. You don’t _owe_ prettiness to anyone. Not to your boyfriend/spouse/partner, not to your co-workers, especially not to random men on the street. You don’t owe it to your mother, you don’t owe it to your children, you don’t owe it to civilization in general. Prettiness is not a rent you pay for occupying a space marked “female”. + +I’m not saying that you SHOULDN’T be pretty if you want to. (You don’t owe UN-prettiness to feminism, in other words.) Pretty is pleasant, and fun, and satisfying, and makes people smile, often even at you. But in the hierarchy of importance, _pretty_ stands several rungs down from _happy_, is way below _healthy_, and if done as a penance, or an obligation, can be so far away from _independent_ that you may have to squint really hard to see it in the haze. + +But what does you-don’t-have-to-be-pretty mean in practical, everyday terms? It means that you don’t have to apologize for wearing things that are held to be “unflattering” or “unfashionable” — especially if, in fact, they make you happy on some level deeper than just being pretty does. So what if your favorite color isn’t a “good” color on you? So what if you are “too fat” (by some arbitrary measure) for a sleeveless top? If you are clean, are covered enough to avoid a citation for public indecency, and have bandaged any open wounds, you can wear any color or style you please, if it makes you happy. + +I was going to make a handy prettiness decision tree, but pretty much the end of every branch was a bubble that said “tell complainers to go to hell” so it wasn’t much of a tool. + +Pretty, it’s sad to say, can have a shelf life. It’s so tied up with youth that, at some point (if you’re lucky), you’re going to have to graduate from pretty. Sometimes (as in the case with Diana Vreeland, above, you can go so far past pretty that you end up in _stylish_, or even _striking_ (or the fashion-y term _jolie laide_) before you know it. But you won’t get there if you think you have to follow all the signs that say “this way to _Pretty_.” You get there by traveling the route you find most interesting. (And to hell with the naysayers who say “But that’s not PRETTY”!) diff --git a/examples/Books/Minimal.md b/examples/Books/Minimal.md new file mode 100644 index 0000000..2a03152 --- /dev/null +++ b/examples/Books/Minimal.md @@ -0,0 +1,19 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Alice +datePublished: 2025-08-01 +itemReviewed: + @type: Book + name: Untitled + author: + @type: Person + name: Unknown +--- + +# Untitled + +## Review +A mysterious book that leaves everything to the imagination. diff --git a/examples/Books/NoAuthor.md b/examples/Books/NoAuthor.md new file mode 100644 index 0000000..fece565 --- /dev/null +++ b/examples/Books/NoAuthor.md @@ -0,0 +1,18 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Eve +datePublished: 2025-08-15 +itemReviewed: + @type: Book + name: Anonymous Poems +reviewBody: "Short, haunting, and powerful verses." +reviewRating: 4/5 +--- + +# Anonymous Poems + +## Review +Short, haunting, and powerful verses. diff --git a/examples/Books/NoBody.md b/examples/Books/NoBody.md new file mode 100644 index 0000000..0953908 --- /dev/null +++ b/examples/Books/NoBody.md @@ -0,0 +1,19 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Clara +datePublished: 2025-08-10 +itemReviewed: + @type: Book + name: 1984 + author: + @type: Person + name: George Orwell +reviewRating: 10/10 +--- + +# 1984 + +## Review diff --git a/examples/Books/NoRating.md b/examples/Books/NoRating.md new file mode 100644 index 0000000..94571b4 --- /dev/null +++ b/examples/Books/NoRating.md @@ -0,0 +1,28 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Bob +datePublished: 2025-08-05 +itemReviewed: + @type: Book + name: War and Peace + author: + @type: Person + name: Leo Tolstoy +reviewAspect: + - Length + - Complexity + - Characters +positiveNotes: + - Rich storytelling + - Deep philosophical themes +negativeNotes: + - Overwhelmingly long +--- + +# War and Peace + +## Review +An epic novel that rewards patient readers but can feel exhausting at times. diff --git a/examples/Books/TheGreatGatsby.md b/examples/Books/TheGreatGatsby.md new file mode 100644 index 0000000..b32be88 --- /dev/null +++ b/examples/Books/TheGreatGatsby.md @@ -0,0 +1,17 @@ +--- +@type: Review +author: + name: Max Richter +itemReviewed: + @type: Book + author: + name: F. Scott Fitzgerald +reviewRating: 5 +--- + +# The Great Gatsby + +## Review +A brilliant novel that captures the glamour and disillusionment of the Jazz Age. +The writing is lyrical and immersive, and the themes of wealth, love, and loss remain relevant today. +While some characters come across as emotionally flat, the overall impact is unforgettable. diff --git a/examples/Movies/Minimal.md b/examples/Movies/Minimal.md new file mode 100644 index 0000000..90c95f6 --- /dev/null +++ b/examples/Movies/Minimal.md @@ -0,0 +1,16 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Frank +datePublished: 2025-08-01 +itemReviewed: + @type: Movie + name: Untitled Film +--- + +# Untitled Film + +## Review +Unclear, experimental, and strange. diff --git a/examples/Movies/Negative.md b/examples/Movies/Negative.md new file mode 100644 index 0000000..0447d31 --- /dev/null +++ b/examples/Movies/Negative.md @@ -0,0 +1,23 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Grace +datePublished: 2025-08-02 +itemReviewed: + @type: Movie + name: The Room + author: + @type: Person + name: Tommy Wiseau +negativeNotes: + - Awkward dialogue + - Strange pacing + - Inconsistent acting +--- + +# The Room + +## Review +So bad it’s fascinating. diff --git a/examples/Movies/NoBody.md b/examples/Movies/NoBody.md new file mode 100644 index 0000000..524bbc4 --- /dev/null +++ b/examples/Movies/NoBody.md @@ -0,0 +1,22 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Jack +datePublished: 2025-08-06 +itemReviewed: + @type: Movie + name: Blade Runner + author: + @type: Person + name: Ridley Scott +reviewRating: 4.5/5 +reviewAspect: + - Atmosphere + - Visual style +--- + +# Blade Runner + +## Review diff --git a/examples/Movies/Structured.md b/examples/Movies/Structured.md new file mode 100644 index 0000000..ca851e8 --- /dev/null +++ b/examples/Movies/Structured.md @@ -0,0 +1,24 @@ +--- +@context: https://schema.org +@type: Review +author: + @type: Person + name: Henry +datePublished: 2025-08-03 +itemReviewed: + @type: Movie + name: Inception + author: + @type: Person + name: Christopher Nolan +reviewAspect: + - Story + - Visuals + - Soundtrack +reviewRating: 9/10 +--- + +# Inception + +## Review +A mind-bending thriller that keeps you hooked. diff --git a/examples/Recipes/baguette.md b/examples/Recipes/baguette.md new file mode 100644 index 0000000..28c932b --- /dev/null +++ b/examples/Recipes/baguette.md @@ -0,0 +1,16 @@ +--- +author.name: Max Richter +--- + +# Baguette + +My favourite baguette recipe + +## Ingredients +- Flour +- Water +- Salt + +## Steps +1. Mix Flour Water and Salt +2. Bake the bread diff --git a/examples/Recipes/cake.md b/examples/Recipes/cake.md new file mode 100644 index 0000000..bd961ff --- /dev/null +++ b/examples/Recipes/cake.md @@ -0,0 +1,21 @@ +--- +author.name: Max Richter +--- + +# Chocolate Cake + +A moist, rich cake for any occasion. + +## Ingredients +- 200 g flour +- 200 g sugar +- 100 g cocoa powder +- 3 eggs +- 200 ml milk + +## Steps +1. Preheat oven to 180°C. +2. Mix dry ingredients in a bowl. +3. Add eggs and milk, stir until smooth. +4. Pour into a cake tin. +5. Bake for 35 minutes. diff --git a/examples/Recipes/caprese-salad.md b/examples/Recipes/caprese-salad.md new file mode 100644 index 0000000..57b1a60 --- /dev/null +++ b/examples/Recipes/caprese-salad.md @@ -0,0 +1,20 @@ +--- +author.name: Max Richter +--- + +# Caprese Salad + +A simple Italian starter with tomato, mozzarella, and basil. + +## Ingredients +- 2 tomatoes +- 125 g mozzarella +- Fresh basil +- Olive oil +- Balsamic vinegar + +## Steps +1. Slice tomatoes and mozzarella. +2. Arrange on a plate with basil leaves. +3. Drizzle with olive oil and balsamic vinegar. +4. Serve immediately. diff --git a/examples/Recipes/cheese-sandwich.md b/examples/Recipes/cheese-sandwich.md new file mode 100644 index 0000000..3be4fab --- /dev/null +++ b/examples/Recipes/cheese-sandwich.md @@ -0,0 +1,18 @@ +--- +author.name: Max Richter +--- + +# Grilled Cheese Sandwich + +Crispy, golden bread filled with melted cheese. + +## Ingredients +- 2 slices bread +- 2 slices cheddar +- Butter + +## Steps +1. Butter the bread slices. +2. Place cheese between bread. +3. Grill in a pan until golden on both sides. +4. Serve hot. diff --git a/examples/Recipes/complex.md b/examples/Recipes/complex.md new file mode 100644 index 0000000..91a49b3 --- /dev/null +++ b/examples/Recipes/complex.md @@ -0,0 +1,20 @@ +--- +author.name: Jane Doe +author.@type: Organization +recipeCategory: ["Dessert", "Vegan", "Quick"] +--- + +# Vegan Brownies + +Rich chocolate brownies with no animal products. + +## Ingredients +- 200 g flour +- 100 g cocoa powder +- 150 g sugar +- 250 ml almond milk + +## Steps +1. Mix all dry ingredients. +2. Add almond milk and stir into batter. +3. Bake at 180°C for 30 minutes. diff --git a/examples/Recipes/lentil-curry.md b/examples/Recipes/lentil-curry.md new file mode 100644 index 0000000..51a3391 --- /dev/null +++ b/examples/Recipes/lentil-curry.md @@ -0,0 +1,21 @@ +--- +author.name: Max Richter +--- + +# Lentil Curry + +A hearty Indian-inspired curry with red lentils. + +## Ingredients +- 200 g red lentils +- 1 onion +- 2 cloves garlic +- 1 tbsp curry powder +- 400 ml coconut milk + +## Steps +1. Sauté onion and garlic with curry powder. +2. Add lentils and coconut milk. +3. Simmer for 20 minutes. +4. Stir occasionally until thick. +5. Serve with rice. diff --git a/examples/Recipes/multiline.md b/examples/Recipes/multiline.md new file mode 100644 index 0000000..39977c0 --- /dev/null +++ b/examples/Recipes/multiline.md @@ -0,0 +1,23 @@ +--- +author.name: Max Richter +--- + +# Ramen Broth + +A rich broth requiring multiple steps in one ingredient description. + +## Ingredients +- Chicken bones, roasted until golden +- Water, enough to cover bones +- Aromatics: + - Onion + - Ginger + - Garlic +- Soy sauce +- Mirin + +## Steps +1. Roast bones until golden brown. +2. Simmer bones with aromatics and water for 4–6 hours. +3. Strain broth. +4. Add soy sauce and mirin before serving. diff --git a/examples/Recipes/optional-fields.md b/examples/Recipes/optional-fields.md new file mode 100644 index 0000000..5513842 --- /dev/null +++ b/examples/Recipes/optional-fields.md @@ -0,0 +1,17 @@ +--- +author.name: Max Richter +prepTime: +cookTime: +recipeYield: +cookingMethod: +--- + +# Mystery Dish + +A recipe with missing optional metadata. + +## Ingredients +- ??? + +## Steps +1. ??? diff --git a/examples/Recipes/pancakes.md b/examples/Recipes/pancakes.md new file mode 100644 index 0000000..ce0f13d --- /dev/null +++ b/examples/Recipes/pancakes.md @@ -0,0 +1,21 @@ +--- +author.name: Max Richter +--- + +# Pancakes + +Fluffy breakfast pancakes perfect with maple syrup. + +## Ingredients +- 200 g flour +- 2 eggs +- 300 ml milk +- 1 tsp baking powder +- Butter for frying + +## Steps +1. Mix flour, baking powder, eggs, and milk into a smooth batter. +2. Heat butter in a pan. +3. Pour in batter and cook until bubbles form. +4. Flip and cook the other side. +5. Serve with syrup or fruit. diff --git a/examples/Recipes/salad.md b/examples/Recipes/salad.md new file mode 100644 index 0000000..182b38a --- /dev/null +++ b/examples/Recipes/salad.md @@ -0,0 +1,22 @@ +--- +author.name: Max Richter +--- + +# Greek Salad + +A fresh salad with feta, olives, and crisp vegetables. + +## Ingredients +- 2 tomatoes +- 1 cucumber +- 1 red onion +- 100 g feta cheese +- Olives +- Olive oil and oregano + +## Steps +1. Chop tomatoes, cucumber, and onion. +2. Mix with olives in a bowl. +3. Crumble feta on top. +4. Drizzle with olive oil and sprinkle oregano. +5. Serve chilled. diff --git a/examples/Recipes/spaghetti-carbonara.md b/examples/Recipes/spaghetti-carbonara.md new file mode 100644 index 0000000..cf5e206 --- /dev/null +++ b/examples/Recipes/spaghetti-carbonara.md @@ -0,0 +1,21 @@ +--- +author.name: Max Richter +--- + +# Spaghetti Carbonara + +A creamy Roman pasta classic with pancetta, eggs, and cheese. + +## Ingredients +- 200 g spaghetti +- 100 g pancetta +- 2 eggs +- 50 g pecorino romano +- Black pepper + +## Steps +1. Boil the pasta until al dente. +2. Fry pancetta until crisp. +3. Whisk eggs and cheese in a bowl. +4. Combine hot pasta, pancetta, and egg mixture. +5. Season generously with pepper and serve. diff --git a/examples/Recipes/stir-fry.md b/examples/Recipes/stir-fry.md new file mode 100644 index 0000000..0e1986d --- /dev/null +++ b/examples/Recipes/stir-fry.md @@ -0,0 +1,21 @@ +--- +author.name: Max Richter +--- + +# Chicken Stir-Fry + +Quick stir-fried chicken with vegetables and soy sauce. + +## Ingredients +- 200 g chicken breast +- 1 bell pepper +- 1 carrot +- 2 tbsp soy sauce +- 1 tbsp sesame oil + +## Steps +1. Slice chicken and vegetables. +2. Heat oil in a wok. +3. Stir-fry chicken until browned. +4. Add vegetables and soy sauce. +5. Cook until tender-crisp. diff --git a/examples/Recipes/tomato-soup.md b/examples/Recipes/tomato-soup.md new file mode 100644 index 0000000..7ac890e --- /dev/null +++ b/examples/Recipes/tomato-soup.md @@ -0,0 +1,21 @@ +--- +author.name: Max Richter +--- + +# Tomato Soup + +A simple, comforting soup made from fresh tomatoes. + +## Ingredients +- 800 g tomatoes +- 1 onion +- 2 cloves garlic +- Olive oil +- Salt and pepper + +## Steps +1. Sauté onion and garlic in olive oil. +2. Add chopped tomatoes and cook until softened. +3. Blend until smooth. +4. Simmer for 10 minutes. +5. Season and serve warm. diff --git a/examples/Recipes/unicode.md b/examples/Recipes/unicode.md new file mode 100644 index 0000000..f5cdfcc --- /dev/null +++ b/examples/Recipes/unicode.md @@ -0,0 +1,21 @@ +--- +author.name: Max Richter +datePublished: 2025-08-17 +--- + +# Crème brûlée + +A French dessert with tricky accents and formatting. + +## Ingredients +- 500 ml cream +- 100 g sugar +- 4 egg yolks +- 1 vanilla pod + +## Steps +1. Heat cream & vanilla until steaming. +2. Whisk yolks + sugar until pale. +3. Combine gently → do not curdle! +4. Bake in water bath at 150 °C. +5. Chill, then caramelize sugar with a torch 🔥. diff --git a/examples/Recipes/water.md b/examples/Recipes/water.md new file mode 100644 index 0000000..84ac2bf --- /dev/null +++ b/examples/Recipes/water.md @@ -0,0 +1,11 @@ +--- +author.name: Max +--- + +# Water + +## Ingredients +- Water + +## Steps +1. Drink it diff --git a/go.work b/go.work index 13c90e5..3fa22ab 100644 --- a/go.work +++ b/go.work @@ -4,6 +4,7 @@ use ( ./parser ./registry ./renderer + ./server ./template ./testdata ./validator diff --git a/registry/schema-org/Recipe.schema.json b/registry/schema-org/Recipe.schema.json index 73a967d..0c1668a 100644 --- a/registry/schema-org/Recipe.schema.json +++ b/registry/schema-org/Recipe.schema.json @@ -23,8 +23,15 @@ "ingredients": { "description": "A single ingredient used in the recipe, e.g. sugar, flour or garlic.", "oneOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } ] }, "nutrition": { @@ -42,27 +49,54 @@ "recipeIngredient": { "description": "A single ingredient used in the recipe, e.g. sugar, flour or garlic.", "oneOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } ] }, "recipeInstructions": { "description": "A step in making the recipe, in the form of a single item (document, video, etc.) or an ordered list with HowToStep and/or HowToSection items.", "anyOf": [ - { "type": "string" }, - { "$ref": "schema:CreativeWork" }, - { "$ref": "schema:ItemList" } + { + "type": "string" + }, + { + "$ref": "schema:CreativeWork" + }, + { + "$ref": "schema:ItemList" + } ] }, "recipeYield": { "description": "The quantity produced by the recipe (for example, number of people served, number of servings, etc).", - "anyOf": [{ "type": "string" }, { "$ref": "schema:QuantitativeValue" }] + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "schema:QuantitativeValue" + } + ] }, "suitableForDiet": { "description": "Indicates a dietary restriction or guideline for which this recipe or menu item is suitable, e.g. diabetic, halal etc.", "oneOf": [ - { "$ref": "schema:RestrictedDiet" }, - { "type": "array", "items": { "$ref": "schema:RestrictedDiet" } } + { + "$ref": "schema:RestrictedDiet" + }, + { + "type": "array", + "items": { + "$ref": "schema:RestrictedDiet" + } + } ] } } diff --git a/registry/templates/Recipe.marka b/registry/templates/Recipe.marka index 94e83ce..12436a1 100644 --- a/registry/templates/Recipe.marka +++ b/registry/templates/Recipe.marka @@ -25,6 +25,10 @@ - path: prepTime - path: cookTime - path: recipeYield + - path: cookingMethod + - path: nutrition + - path: recipeCategory + - path: suitableForDiet } --- diff --git a/registry/templates/_default.marka b/registry/templates/_default.marka index 92d86bb..dee840e 100644 --- a/registry/templates/_default.marka +++ b/registry/templates/_default.marka @@ -4,7 +4,5 @@ codec: yaml fields: - path: "@type" - codec: const - value: Recipe } --- diff --git a/server/cmd/marka-server/main.go b/server/cmd/marka-server/main.go new file mode 100644 index 0000000..ee01e49 --- /dev/null +++ b/server/cmd/marka-server/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "flag" + "log" + "net/http" + "os" + "path/filepath" + + "git.max-richter.dev/max/marka/server/internal/handlers" +) + +func main() { + root := flag.String("root", ".", "filesystem root to serve") + addr := flag.String("addr", ":8080", "listen address") + flag.Parse() + + absRoot, err := filepath.Abs(*root) + must(err) + info, err := os.Stat(absRoot) + must(err) + if !info.IsDir() { + log.Fatal("root is not a directory") + } + + // Catch-all route from "/" → serve files rooted in absRoot + http.Handle("/", handlers.NewFile(absRoot)) + + log.Printf("listening on %s, root=%s", *addr, absRoot) + log.Fatal(http.ListenAndServe(*addr, nil)) +} + +func must(err error) { + if err != nil { + log.Fatal(err) + } +} diff --git a/server/go.mod b/server/go.mod new file mode 100644 index 0000000..85f4d32 --- /dev/null +++ b/server/go.mod @@ -0,0 +1,3 @@ +module git.max-richter.dev/max/marka/server + +go 1.24.3 diff --git a/server/internal/fsx/contenttype.go b/server/internal/fsx/contenttype.go new file mode 100644 index 0000000..87a9d8b --- /dev/null +++ b/server/internal/fsx/contenttype.go @@ -0,0 +1,23 @@ +package fsx + +import ( + "mime" + "path/filepath" + "strings" +) + +func ContentTypeFor(name string) string { + ext := strings.ToLower(filepath.Ext(name)) + switch ext { + case ".md", ".markdown", ".mdown": + return "application/markdown" + } + if ct := mime.TypeByExtension(ext); ct != "" { + return ct + } + switch ext { + case ".txt", ".log", ".json", ".yaml", ".yml", ".toml", ".xml", ".csv": + return "text/plain; charset=utf-8" + } + return "application/octet-stream" +} diff --git a/server/internal/fsx/path.go b/server/internal/fsx/path.go new file mode 100644 index 0000000..3d8d089 --- /dev/null +++ b/server/internal/fsx/path.go @@ -0,0 +1,56 @@ +package fsx + +import ( + "errors" + "path/filepath" + "strings" +) + +func CleanURLLike(p string) string { + p = strings.TrimSpace(p) + if p == "" || p == "/" { + return "/" + } + parts := []string{} + for _, seg := range strings.Split(strings.ReplaceAll(p, "\\", "/"), "/") { + switch seg { + case "", ".": + continue + case "..": + if len(parts) > 0 { + parts = parts[:len(parts)-1] + } + default: + parts = append(parts, seg) + } + } + return "/" + strings.Join(parts, "/") +} + +func SafeRel(root, requested string) (string, error) { + s := CleanURLLike(requested) + if strings.HasPrefix(s, "/") { + s = strings.TrimPrefix(s, "/") + } + full := filepath.Join(root, filepath.FromSlash(s)) + rel, err := filepath.Rel(root, full) + if err != nil { + return "", err + } + if rel == "." { + return "/", nil + } + sep := string(filepath.Separator) + if strings.HasPrefix(rel, "..") || strings.Contains(rel, ".."+sep) { + return "", errors.New("path escapes root") + } + return "/" + filepath.ToSlash(rel), nil +} + +func ResponsePath(root, full string) string { + rel, err := filepath.Rel(root, full) + if err != nil || rel == "." { + return "/" + } + return "/" + filepath.ToSlash(rel) +} diff --git a/server/internal/handlers/file.go b/server/internal/handlers/file.go new file mode 100644 index 0000000..cd7f8e1 --- /dev/null +++ b/server/internal/handlers/file.go @@ -0,0 +1,171 @@ +// Package handlers provides HTTP handlers for the file system. +package handlers + +import ( + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "time" + + "git.max-richter.dev/max/marka/parser" + "git.max-richter.dev/max/marka/server/internal/fsx" + "git.max-richter.dev/max/marka/server/internal/httpx" +) + +type File struct{ root string } + +func NewFile(root string) http.Handler { return &File{root: root} } + +func (h *File) ServeHTTP(w http.ResponseWriter, r *http.Request) { + reqPath := r.URL.Path + if reqPath == "" { + reqPath = "/" + } + cleanRel, err := fsx.SafeRel(h.root, reqPath) + if err != nil { + httpx.WriteError(w, http.StatusBadRequest, err) + return + } + target := filepath.Join(h.root, filepath.FromSlash(cleanRel)) + + switch r.Method { + case http.MethodGet: + h.get(w, r, target) + case http.MethodPost: + h.post(w, r, target) + default: + httpx.WriteError(w, http.StatusMethodNotAllowed, errors.New("method not allowed")) + } +} + +func read(path string) any { + data, err := os.ReadFile(path) + if err != nil { + return nil + } + res, err := parser.ParseFile(string(data)) + if err != nil { + return nil + } + + return res +} + +func (h *File) get(w http.ResponseWriter, r *http.Request, target string) { + fi, err := os.Stat(target) + if err != nil { + if os.IsNotExist(err) { + httpx.WriteError(w, http.StatusNotFound, errors.New("not found")) + } else { + httpx.WriteError(w, http.StatusInternalServerError, err) + } + return + } + + if fi.IsDir() { + entries, err := os.ReadDir(target) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + type item struct { + Name string `json:"name"` + Path string `json:"path"` + Content any `json:"content"` + IsDir bool `json:"isDir"` + Size int64 `json:"size"` + ModTime time.Time `json:"modTime"` + } + out := make([]item, 0, len(entries)) + for _, e := range entries { + info, _ := e.Info() + out = append(out, item{ + Name: e.Name(), + Path: fsx.ResponsePath(h.root, filepath.Join(target, e.Name())), + IsDir: e.IsDir(), + Content: read(filepath.Join(target, e.Name())), + Size: sizeOrZero(info), + ModTime: modTimeOrZero(info), + }) + } + httpx.WriteJSON(w, http.StatusOK, out) + return + } + + f, err := os.Open(target) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + defer f.Close() + + contentType := fsx.ContentTypeFor(target) + + if contentType == "application/markdown" { + data, err := io.ReadAll(f) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + res, err := parser.ParseFile(string(data)) + if err != nil { + fmt.Println(err) + } + w.Header().Set("Content-Type", "application/json") + httpx.WriteJSON(w, http.StatusOK, res) + return + } + + w.Header().Set("Content-Type", contentType) + http.ServeContent(w, r, filepath.Base(target), fi.ModTime(), f) +} + +func (h *File) post(w http.ResponseWriter, r *http.Request, target string) { + if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + tmp := target + ".tmp~" + f, err := os.Create(tmp) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + + if _, err := io.Copy(f, r.Body); err != nil { + _ = f.Close() + _ = os.Remove(tmp) + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + if err := f.Close(); err != nil { + _ = os.Remove(tmp) + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + if err := os.Rename(tmp, target); err != nil { + _ = os.Remove(tmp) + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + + w.Header().Set("Location", r.URL.Path) + w.WriteHeader(http.StatusCreated) +} + +func sizeOrZero(fi os.FileInfo) int64 { + if fi == nil { + return 0 + } + return fi.Size() +} + +func modTimeOrZero(fi os.FileInfo) time.Time { + if fi == nil { + return time.Time{} + } + return fi.ModTime() +} diff --git a/server/internal/httpx/error.go b/server/internal/httpx/error.go new file mode 100644 index 0000000..7c88320 --- /dev/null +++ b/server/internal/httpx/error.go @@ -0,0 +1,20 @@ +package httpx + +import ( + "encoding/json" + "net/http" +) + +type ErrorResponse struct { + Error string `json:"error"` +} + +func WriteJSON(w http.ResponseWriter, code int, v any) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + _ = json.NewEncoder(w).Encode(v) +} + +func WriteError(w http.ResponseWriter, code int, err error) { + WriteJSON(w, code, ErrorResponse{Error: err.Error()}) +} diff --git a/server/internal/httpx/router.go b/server/internal/httpx/router.go new file mode 100644 index 0000000..dfdeec7 --- /dev/null +++ b/server/internal/httpx/router.go @@ -0,0 +1,11 @@ +package httpx + +import "net/http" + +type Router struct{ mux *http.ServeMux } + +func NewRouter() *Router { return &Router{mux: http.NewServeMux()} } +func (r *Router) Handle(pattern string, h http.Handler) { r.mux.Handle(pattern, h) } +func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { + r.mux.ServeHTTP(w, req) +} From 26c303d9cfa6911953379f2c1f1a79864127b782 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Wed, 24 Sep 2025 18:18:57 +0200 Subject: [PATCH 02/20] feat: some updates --- examples/Article/A dress a day.md | 1 + examples/Books/NoAuthor.md | 2 +- examples/Books/NoBody.md | 2 +- parser/decoders/hashtags.go | 5 ++ parser/go.mod | 4 +- parser/go.sum | 4 + registry/go.mod | 2 +- registry/go.sum | 4 - registry/templates/Article.marka | 10 +++ registry/templates/Review.marka | 1 + renderer/go.mod | 17 +++- renderer/go.sum | 20 +++++ server/.air.toml | 32 +++++++ server/.gitignore | 1 + server/cmd/marka-server/main.go | 2 +- server/go.mod | 15 +++- server/go.sum | 22 +++++ server/http/.env | 1 + server/http/post-recipe.http | 5 ++ server/internal/fsx/contenttype.go | 14 ++- server/internal/fsx/path.go | 6 +- server/internal/handlers/file.go | 133 ---------------------------- server/internal/handlers/get.go | 93 +++++++++++++++++++ server/internal/handlers/helpers.go | 30 +++++++ server/internal/handlers/post.go | 47 ++++++++++ template/blocks.go | 112 +---------------------- template/blocks_short.go | 38 ++++++++ template/blocks_yaml.go | 86 ++++++++++++++++++ template/go.mod | 7 +- template/go.sum | 2 + validator/go.mod | 5 +- validator/go.sum | 4 + 32 files changed, 464 insertions(+), 263 deletions(-) create mode 100644 renderer/go.sum create mode 100644 server/.air.toml create mode 100644 server/.gitignore create mode 100644 server/go.sum create mode 100644 server/http/.env create mode 100644 server/http/post-recipe.http create mode 100644 server/internal/handlers/get.go create mode 100644 server/internal/handlers/helpers.go create mode 100644 server/internal/handlers/post.go create mode 100644 template/blocks_short.go create mode 100644 template/blocks_yaml.go diff --git a/examples/Article/A dress a day.md b/examples/Article/A dress a day.md index 7025759..668aa2f 100644 --- a/examples/Article/A dress a day.md +++ b/examples/Article/A dress a day.md @@ -5,6 +5,7 @@ url: https://dressaday.com/2006/10/20/you-dont-have-to-be-pretty/ rating: 5 date: December 7, 2023 image: https://i0.wp.com/old-dressaday-images.s3-website-us-west-2.amazonaws.com/6a0133ed1b1479970b0134809d9f8b970c.jpg +reviewRating.ratingValue: 5 --- # You Dont Have to Be Pretty – A Dress A Day diff --git a/examples/Books/NoAuthor.md b/examples/Books/NoAuthor.md index fece565..af24dc7 100644 --- a/examples/Books/NoAuthor.md +++ b/examples/Books/NoAuthor.md @@ -9,7 +9,7 @@ itemReviewed: @type: Book name: Anonymous Poems reviewBody: "Short, haunting, and powerful verses." -reviewRating: 4/5 +reviewRating.ratingValue: 4 --- # Anonymous Poems diff --git a/examples/Books/NoBody.md b/examples/Books/NoBody.md index 0953908..fc0bc0b 100644 --- a/examples/Books/NoBody.md +++ b/examples/Books/NoBody.md @@ -11,7 +11,7 @@ itemReviewed: author: @type: Person name: George Orwell -reviewRating: 10/10 +reviewRating: 5 --- # 1984 diff --git a/parser/decoders/hashtags.go b/parser/decoders/hashtags.go index d9e7f94..e0e63fa 100644 --- a/parser/decoders/hashtags.go +++ b/parser/decoders/hashtags.go @@ -15,5 +15,10 @@ func Keywords(input string, block template.Block) (value any, error error) { tags = append(tags, tag) } } + + if len(tags) == 0 { + return nil, nil + } + return tags, nil } diff --git a/parser/go.mod b/parser/go.mod index 8dba3bf..fe539c6 100644 --- a/parser/go.mod +++ b/parser/go.mod @@ -1,6 +1,6 @@ module git.max-richter.dev/max/marka/parser -go 1.24.3 +go 1.24.5 require ( git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567 @@ -14,6 +14,8 @@ require ( ) require ( + git.max-richter.dev/max/marka/renderer v0.0.0-20250819170608-69c2550f448e + git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a github.com/google/go-cmp v0.7.0 go.yaml.in/yaml/v4 v4.0.0-rc.1 ) diff --git a/parser/go.sum b/parser/go.sum index f65191b..7468956 100644 --- a/parser/go.sum +++ b/parser/go.sum @@ -1,7 +1,11 @@ git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567 h1:oe7Xb8dE43S8mRla5hfEqagMnvhvEVHsvRlzl2v540w= git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567/go.mod h1:qGWl42P8mgEktfor/IjQp0aS9SqmpeIlhSuVTlUOXLQ= +git.max-richter.dev/max/marka/renderer v0.0.0-20250819170608-69c2550f448e h1:9Eg81l8YMTXWZC3xlZ5L/NJRuK26bksrVtEHyCTV4sM= +git.max-richter.dev/max/marka/renderer v0.0.0-20250819170608-69c2550f448e/go.mod h1:mjJqEqALg4YJoiebk3V21yJVUVEs3K2RiLO/IW6DGCM= git.max-richter.dev/max/marka/template v0.0.0-20250817132016-6db87db32567 h1:XIx89KqTgd/h14oe5mLvT9E8+jGEAjWgudqiMtQdcec= git.max-richter.dev/max/marka/template v0.0.0-20250817132016-6db87db32567/go.mod h1:Uxi5xcxtnjopsIZjjMlFaWJGuglB9JNL++FuaSbOf6U= +git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a h1:LAU2LlLZ96s8hcg1OEGD5HBshDspWVwWTa7YG5+A70w= +git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a/go.mod h1:88SkY5pTONkgfBy1FT10LoqRC8rt36iF1fk/rupjuJY= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= diff --git a/registry/go.mod b/registry/go.mod index 61e060e..7364278 100644 --- a/registry/go.mod +++ b/registry/go.mod @@ -1,3 +1,3 @@ module git.max-richter.dev/max/marka/registry -go 1.24.3 +go 1.24.5 diff --git a/registry/go.sum b/registry/go.sum index b46b517..e69de29 100644 --- a/registry/go.sum +++ b/registry/go.sum @@ -1,4 +0,0 @@ -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= diff --git a/registry/templates/Article.marka b/registry/templates/Article.marka index f6175f3..4be4c66 100644 --- a/registry/templates/Article.marka +++ b/registry/templates/Article.marka @@ -22,6 +22,16 @@ hidden: true - path: datePublished - path: articleSection + - path: reviewRating.ratingValue + pathAlias: rating + - path: reviewRating.bestRating + codec: const + value: 5 + hidden: true + - path: reviewRating.worstRating + codec: const + value: 1 + hidden: true } --- diff --git a/registry/templates/Review.marka b/registry/templates/Review.marka index cf49de2..d3f94db 100644 --- a/registry/templates/Review.marka +++ b/registry/templates/Review.marka @@ -39,4 +39,5 @@ # { itemReviewed.name } { keywords | hashtags } +## Review { reviewBody } diff --git a/renderer/go.mod b/renderer/go.mod index 2594145..558a176 100644 --- a/renderer/go.mod +++ b/renderer/go.mod @@ -1,3 +1,18 @@ module git.max-richter.dev/max/marka/renderer -go 1.24.3 +go 1.24.5 + +require ( + git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e + git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e + git.max-richter.dev/max/marka/template v0.0.0-20250819170608-69c2550f448e + git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a + git.max-richter.dev/max/marka/validator v0.0.0-20250819170608-69c2550f448e + github.com/google/go-cmp v0.7.0 + go.yaml.in/yaml/v4 v4.0.0-rc.1 +) + +require ( + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + golang.org/x/text v0.14.0 // indirect +) diff --git a/renderer/go.sum b/renderer/go.sum new file mode 100644 index 0000000..11e46b8 --- /dev/null +++ b/renderer/go.sum @@ -0,0 +1,20 @@ +git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e h1:enZufetD3UoIVTnTNTQSFlr1Ir0jG7wObUAxb6+xwWg= +git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e/go.mod h1:xQK6tsgr9BOoeFw8JxjBwDkVENlOqapmcRkYyf/L+SQ= +git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e h1:eXAE0JHDvLGqtYSSlX5mw1XAuK+Cmu74c52PyveRhlE= +git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e/go.mod h1:n793S7TENIfgHpZLz0lm0qorM7eCx3zBLby3Fb++hZA= +git.max-richter.dev/max/marka/template v0.0.0-20250819170608-69c2550f448e h1:6327yeKE0dYbwsEBhIFcXOJEWTxBUWGBeB0uj9BTJqA= +git.max-richter.dev/max/marka/template v0.0.0-20250819170608-69c2550f448e/go.mod h1:Uxi5xcxtnjopsIZjjMlFaWJGuglB9JNL++FuaSbOf6U= +git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a h1:LAU2LlLZ96s8hcg1OEGD5HBshDspWVwWTa7YG5+A70w= +git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a/go.mod h1:88SkY5pTONkgfBy1FT10LoqRC8rt36iF1fk/rupjuJY= +git.max-richter.dev/max/marka/validator v0.0.0-20250819170608-69c2550f448e h1:MBxIk3jvbjSmpZk7xlR6Yog61375PMya3FzOxZ5TuYs= +git.max-richter.dev/max/marka/validator v0.0.0-20250819170608-69c2550f448e/go.mod h1:qdGfCFRzsGedmnd77vb7pu/EMx0W0DcQBMEfvNxMYsw= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +go.yaml.in/yaml/v4 v4.0.0-rc.1 h1:4J1+yLKUIPGexM/Si+9d3pij4hdc7aGO04NhrElqXbY= +go.yaml.in/yaml/v4 v4.0.0-rc.1/go.mod h1:CBdeces52/nUXndfQ5OY8GEQuNR9uEEOJPZj/Xq5IzU= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= diff --git a/server/.air.toml b/server/.air.toml new file mode 100644 index 0000000..c8e2c18 --- /dev/null +++ b/server/.air.toml @@ -0,0 +1,32 @@ +# Config file for Air - https://github.com/air-verse/air +# This file is for the marka-server application. + +root = "." +tmp_dir = "tmp" + +[build] +# Command to build the application. +cmd = "go build -o ./tmp/marka-server ./cmd/marka-server" + +# The binary to run. +bin = "./tmp/marka-server" + +# Command to run the application with arguments. +full_bin = "./tmp/marka-server -root=../examples -addr=:8080" + +# Watch these file extensions. +include_ext = ["go", "http"] + +# Ignore these directories. +exclude_dir = ["tmp"] + +# Log file for build errors. +log = "air_errors.log" + +[log] +# Show time in logs. +time = true + +[misc] +# Delete tmp directory on exit. +clean_on_exit = true diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..3fec32c --- /dev/null +++ b/server/.gitignore @@ -0,0 +1 @@ +tmp/ diff --git a/server/cmd/marka-server/main.go b/server/cmd/marka-server/main.go index ee01e49..ef8a90a 100644 --- a/server/cmd/marka-server/main.go +++ b/server/cmd/marka-server/main.go @@ -17,13 +17,13 @@ func main() { absRoot, err := filepath.Abs(*root) must(err) + info, err := os.Stat(absRoot) must(err) if !info.IsDir() { log.Fatal("root is not a directory") } - // Catch-all route from "/" → serve files rooted in absRoot http.Handle("/", handlers.NewFile(absRoot)) log.Printf("listening on %s, root=%s", *addr, absRoot) diff --git a/server/go.mod b/server/go.mod index 85f4d32..250391c 100644 --- a/server/go.mod +++ b/server/go.mod @@ -1,3 +1,16 @@ module git.max-richter.dev/max/marka/server -go 1.24.3 +go 1.24.5 + +require git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e + +require ( + git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567 // indirect + git.max-richter.dev/max/marka/renderer v0.0.0-20250819170608-69c2550f448e // indirect + git.max-richter.dev/max/marka/template v0.0.0-20250817132016-6db87db32567 // indirect + git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a // indirect + github.com/agext/levenshtein v1.2.3 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.1 // indirect + golang.org/x/text v0.14.0 // indirect +) diff --git a/server/go.sum b/server/go.sum new file mode 100644 index 0000000..8678458 --- /dev/null +++ b/server/go.sum @@ -0,0 +1,22 @@ +git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e h1:enZufetD3UoIVTnTNTQSFlr1Ir0jG7wObUAxb6+xwWg= +git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e/go.mod h1:xQK6tsgr9BOoeFw8JxjBwDkVENlOqapmcRkYyf/L+SQ= +git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567 h1:oe7Xb8dE43S8mRla5hfEqagMnvhvEVHsvRlzl2v540w= +git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567/go.mod h1:qGWl42P8mgEktfor/IjQp0aS9SqmpeIlhSuVTlUOXLQ= +git.max-richter.dev/max/marka/renderer v0.0.0-20250819170608-69c2550f448e h1:9Eg81l8YMTXWZC3xlZ5L/NJRuK26bksrVtEHyCTV4sM= +git.max-richter.dev/max/marka/renderer v0.0.0-20250819170608-69c2550f448e/go.mod h1:mjJqEqALg4YJoiebk3V21yJVUVEs3K2RiLO/IW6DGCM= +git.max-richter.dev/max/marka/template v0.0.0-20250817132016-6db87db32567 h1:XIx89KqTgd/h14oe5mLvT9E8+jGEAjWgudqiMtQdcec= +git.max-richter.dev/max/marka/template v0.0.0-20250817132016-6db87db32567/go.mod h1:Uxi5xcxtnjopsIZjjMlFaWJGuglB9JNL++FuaSbOf6U= +git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a h1:LAU2LlLZ96s8hcg1OEGD5HBshDspWVwWTa7YG5+A70w= +git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a/go.mod h1:88SkY5pTONkgfBy1FT10LoqRC8rt36iF1fk/rupjuJY= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +go.yaml.in/yaml/v4 v4.0.0-rc.1 h1:4J1+yLKUIPGexM/Si+9d3pij4hdc7aGO04NhrElqXbY= +go.yaml.in/yaml/v4 v4.0.0-rc.1/go.mod h1:CBdeces52/nUXndfQ5OY8GEQuNR9uEEOJPZj/Xq5IzU= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= diff --git a/server/http/.env b/server/http/.env new file mode 100644 index 0000000..d417754 --- /dev/null +++ b/server/http/.env @@ -0,0 +1 @@ +SERVER_URL=http://localhost:8080 diff --git a/server/http/post-recipe.http b/server/http/post-recipe.http new file mode 100644 index 0000000..45154e2 --- /dev/null +++ b/server/http/post-recipe.http @@ -0,0 +1,5 @@ +POST {{SERVER_URL}}/Recipes/bolognaise.md + +{ + +} diff --git a/server/internal/fsx/contenttype.go b/server/internal/fsx/contenttype.go index 87a9d8b..2288c93 100644 --- a/server/internal/fsx/contenttype.go +++ b/server/internal/fsx/contenttype.go @@ -6,6 +6,17 @@ import ( "strings" ) +var textPlainExtensions = map[string]bool{ + ".txt": true, + ".log": true, + ".json": true, + ".yaml": true, + ".yml": true, + ".toml": true, + ".xml": true, + ".csv": true, +} + func ContentTypeFor(name string) string { ext := strings.ToLower(filepath.Ext(name)) switch ext { @@ -15,8 +26,7 @@ func ContentTypeFor(name string) string { if ct := mime.TypeByExtension(ext); ct != "" { return ct } - switch ext { - case ".txt", ".log", ".json", ".yaml", ".yml", ".toml", ".xml", ".csv": + if textPlainExtensions[ext] { return "text/plain; charset=utf-8" } return "application/octet-stream" diff --git a/server/internal/fsx/path.go b/server/internal/fsx/path.go index 3d8d089..6916a16 100644 --- a/server/internal/fsx/path.go +++ b/server/internal/fsx/path.go @@ -12,7 +12,7 @@ func CleanURLLike(p string) string { return "/" } parts := []string{} - for _, seg := range strings.Split(strings.ReplaceAll(p, "\\", "/"), "/") { + for seg := range strings.SplitSeq(strings.ReplaceAll(p, "/", "/"), "/") { switch seg { case "", ".": continue @@ -29,8 +29,8 @@ func CleanURLLike(p string) string { func SafeRel(root, requested string) (string, error) { s := CleanURLLike(requested) - if strings.HasPrefix(s, "/") { - s = strings.TrimPrefix(s, "/") + if after, ok := strings.CutPrefix(s, "/"); ok { + s = after } full := filepath.Join(root, filepath.FromSlash(s)) rel, err := filepath.Rel(root, full) diff --git a/server/internal/handlers/file.go b/server/internal/handlers/file.go index cd7f8e1..dac05bb 100644 --- a/server/internal/handlers/file.go +++ b/server/internal/handlers/file.go @@ -3,14 +3,9 @@ package handlers import ( "errors" - "fmt" - "io" "net/http" - "os" "path/filepath" - "time" - "git.max-richter.dev/max/marka/parser" "git.max-richter.dev/max/marka/server/internal/fsx" "git.max-richter.dev/max/marka/server/internal/httpx" ) @@ -41,131 +36,3 @@ func (h *File) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } -func read(path string) any { - data, err := os.ReadFile(path) - if err != nil { - return nil - } - res, err := parser.ParseFile(string(data)) - if err != nil { - return nil - } - - return res -} - -func (h *File) get(w http.ResponseWriter, r *http.Request, target string) { - fi, err := os.Stat(target) - if err != nil { - if os.IsNotExist(err) { - httpx.WriteError(w, http.StatusNotFound, errors.New("not found")) - } else { - httpx.WriteError(w, http.StatusInternalServerError, err) - } - return - } - - if fi.IsDir() { - entries, err := os.ReadDir(target) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - type item struct { - Name string `json:"name"` - Path string `json:"path"` - Content any `json:"content"` - IsDir bool `json:"isDir"` - Size int64 `json:"size"` - ModTime time.Time `json:"modTime"` - } - out := make([]item, 0, len(entries)) - for _, e := range entries { - info, _ := e.Info() - out = append(out, item{ - Name: e.Name(), - Path: fsx.ResponsePath(h.root, filepath.Join(target, e.Name())), - IsDir: e.IsDir(), - Content: read(filepath.Join(target, e.Name())), - Size: sizeOrZero(info), - ModTime: modTimeOrZero(info), - }) - } - httpx.WriteJSON(w, http.StatusOK, out) - return - } - - f, err := os.Open(target) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - defer f.Close() - - contentType := fsx.ContentTypeFor(target) - - if contentType == "application/markdown" { - data, err := io.ReadAll(f) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - res, err := parser.ParseFile(string(data)) - if err != nil { - fmt.Println(err) - } - w.Header().Set("Content-Type", "application/json") - httpx.WriteJSON(w, http.StatusOK, res) - return - } - - w.Header().Set("Content-Type", contentType) - http.ServeContent(w, r, filepath.Base(target), fi.ModTime(), f) -} - -func (h *File) post(w http.ResponseWriter, r *http.Request, target string) { - if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - tmp := target + ".tmp~" - f, err := os.Create(tmp) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - - if _, err := io.Copy(f, r.Body); err != nil { - _ = f.Close() - _ = os.Remove(tmp) - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - if err := f.Close(); err != nil { - _ = os.Remove(tmp) - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - if err := os.Rename(tmp, target); err != nil { - _ = os.Remove(tmp) - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - - w.Header().Set("Location", r.URL.Path) - w.WriteHeader(http.StatusCreated) -} - -func sizeOrZero(fi os.FileInfo) int64 { - if fi == nil { - return 0 - } - return fi.Size() -} - -func modTimeOrZero(fi os.FileInfo) time.Time { - if fi == nil { - return time.Time{} - } - return fi.ModTime() -} diff --git a/server/internal/handlers/get.go b/server/internal/handlers/get.go new file mode 100644 index 0000000..e1fc5cc --- /dev/null +++ b/server/internal/handlers/get.go @@ -0,0 +1,93 @@ +package handlers + +import ( + "errors" + "fmt" + "net/http" + "os" + "path/filepath" + "time" + + "git.max-richter.dev/max/marka/server/internal/fsx" + "git.max-richter.dev/max/marka/server/internal/httpx" +) + +func (h *File) get(w http.ResponseWriter, r *http.Request, target string) { + fi, err := os.Stat(target) + if err != nil { + if os.IsNotExist(err) { + httpx.WriteError(w, http.StatusNotFound, errors.New("not found")) + } else { + httpx.WriteError(w, http.StatusInternalServerError, err) + } + return + } + + if fi.IsDir() { + h.handleDir(w, r, target) + } else { + h.handleFile(w, r, target, fi) + } +} + +func (h *File) handleDir(w http.ResponseWriter, r *http.Request, dirPath string) { + entries, err := os.ReadDir(dirPath) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + + type item struct { + Name string `json:"name"` + Path string `json:"path"` + Content any `json:"content,omitempty"` + IsDir bool `json:"isDir"` + Size int64 `json:"size"` + ModTime time.Time `json:"modTime"` + } + + out := make([]item, 0, len(entries)) + for _, e := range entries { + info, _ := e.Info() // As in original, ignore error to get partial info + entryPath := filepath.Join(dirPath, e.Name()) + + var content any + if !e.IsDir() && fsx.ContentTypeFor(e.Name()) == "application/markdown" { + content, _ = parseMarkdownFile(entryPath) // As in original, ignore error + } + + out = append(out, item{ + Name: e.Name(), + Path: fsx.ResponsePath(h.root, entryPath), + IsDir: e.IsDir(), + Content: content, + Size: sizeOrZero(info), + ModTime: modTimeOrZero(info), + }) + } + httpx.WriteJSON(w, http.StatusOK, out) +} + +func (h *File) handleFile(w http.ResponseWriter, r *http.Request, target string, fi os.FileInfo) { + contentType := fsx.ContentTypeFor(target) + + if contentType == "application/markdown" { + res, err := parseMarkdownFile(target) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, fmt.Errorf("failed to parse markdown: %w", err)) + return + } + httpx.WriteJSON(w, http.StatusOK, res) + return + } + + f, err := os.Open(target) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + defer f.Close() + + w.Header().Set("Content-Type", contentType) + http.ServeContent(w, r, filepath.Base(target), fi.ModTime(), f) +} diff --git a/server/internal/handlers/helpers.go b/server/internal/handlers/helpers.go new file mode 100644 index 0000000..8cca076 --- /dev/null +++ b/server/internal/handlers/helpers.go @@ -0,0 +1,30 @@ +package handlers + +import ( + "os" + "time" + + "git.max-richter.dev/max/marka/parser" +) + +func parseMarkdownFile(path string) (any, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + return parser.ParseFile(string(data)) +} + +func sizeOrZero(fi os.FileInfo) int64 { + if fi == nil { + return 0 + } + return fi.Size() +} + +func modTimeOrZero(fi os.FileInfo) time.Time { + if fi == nil { + return time.Time{} + } + return fi.ModTime() +} diff --git a/server/internal/handlers/post.go b/server/internal/handlers/post.go new file mode 100644 index 0000000..d7d23bc --- /dev/null +++ b/server/internal/handlers/post.go @@ -0,0 +1,47 @@ +package handlers + +import ( + "io" + "net/http" + "os" + "path/filepath" + + "git.max-richter.dev/max/marka/server/internal/httpx" +) + +func (h *File) post(w http.ResponseWriter, r *http.Request, target string) { + if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + + tmpPath := target + ".tmp~" + f, err := os.Create(tmpPath) + if err != nil { + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + + _, copyErr := io.Copy(f, r.Body) + closeErr := f.Close() + + if copyErr != nil { + os.Remove(tmpPath) + httpx.WriteError(w, http.StatusInternalServerError, copyErr) + return + } + if closeErr != nil { + os.Remove(tmpPath) + httpx.WriteError(w, http.StatusInternalServerError, closeErr) + return + } + + if err := os.Rename(tmpPath, target); err != nil { + os.Remove(tmpPath) + httpx.WriteError(w, http.StatusInternalServerError, err) + return + } + + w.Header().Set("Location", r.URL.Path) + w.WriteHeader(http.StatusCreated) +} diff --git a/template/blocks.go b/template/blocks.go index 37a5c87..37273bf 100644 --- a/template/blocks.go +++ b/template/blocks.go @@ -1,11 +1,9 @@ -// Package template contains the logic for parsing template blocks. +// Package blocks contains the logic for parsing template blocks. package template import ( "fmt" "strings" - - "go.yaml.in/yaml/v4" ) // TemplateType represents whether a template is short, long, or invalid. @@ -53,114 +51,6 @@ func cleanTemplate(input string) string { return s } -func parseShortTemplate(input string) (Block, error) { - split := strings.Split(cleanTemplate(input), "|") - if len(split) < 1 { - return Block{}, fmt.Errorf("invalid short template") - } - - block := Block{ - Type: DataBlock, - Path: strings.TrimSpace(split[0]), - Codec: CodecText, - content: input, - } - - if len(split) > 1 { - optionSplit := strings.SplitSeq(split[1], ",") - for option := range optionSplit { - switch strings.TrimSpace(option) { - case "number": - block.Codec = CodecNumber - case "text": - block.Codec = CodecText - case "hashtags": - block.Codec = CodecHashtags - default: - return block, fmt.Errorf("unknown codec option: %s", option) - } - } - } - - return block, nil -} - -type yamlBlock struct { - Path string `yaml:"path"` - Codec string `yaml:"codec"` - Value any `yaml:"value,omitempty"` - Fields []yamlField `yaml:"fields"` - ListTemplate string `yaml:"listTemplate,omitempty"` - Hidden bool `yaml:"hidden,omitempty"` -} - -type yamlField struct { - Path string `yaml:"path"` - Value any `yaml:"value,omitempty"` - Codec string `yaml:"codec"` - Hidden bool `yaml:"hidden,omitempty"` -} - -func parseYamlTemplate(input string) (block Block, err error) { - var blk yamlBlock - - cleaned := cleanTemplate(input) - - dec := yaml.NewDecoder(strings.NewReader(cleaned)) - dec.KnownFields(true) - - if err := dec.Decode(&blk); err != nil { - return block, fmt.Errorf("content '%q': %w", cleaned, err) - } - - if blk.Path == "" { - return block, fmt.Errorf("missing top-level 'path'") - } - - if blk.Codec == "" { - blk.Codec = "text" - } - - codec, err := parseCodecType(blk.Codec) - if err != nil { - return block, fmt.Errorf("failed to parse codec: %w", err) - } - - var fields []BlockField - - for _, field := range blk.Fields { - if field.Path == "" { - return block, fmt.Errorf("failed to parse field: %v", field) - } - - if field.Codec == "" { - field.Codec = "text" - } - - fieldCodec, err := parseCodecType(field.Codec) - if err != nil { - return block, fmt.Errorf("failed to parse codec: %w", err) - } - - fields = append(fields, BlockField{ - Path: field.Path, - CodecType: fieldCodec, - Value: field.Value, - Hidden: field.Hidden, - }) - - } - - return Block{ - Type: DataBlock, - Path: blk.Path, - Codec: codec, - Fields: fields, - ListTemplate: blk.ListTemplate, - content: input, - }, nil -} - func ParseTemplateBlock(template string, blockType BlockType) (block Block, err error) { if blockType == MatchingBlock { return Block{ diff --git a/template/blocks_short.go b/template/blocks_short.go new file mode 100644 index 0000000..08fb7fd --- /dev/null +++ b/template/blocks_short.go @@ -0,0 +1,38 @@ +package template + +import ( + "fmt" + "strings" +) + +func parseShortTemplate(input string) (Block, error) { + split := strings.Split(cleanTemplate(input), "|") + if len(split) < 1 { + return Block{}, fmt.Errorf("invalid short template") + } + + block := Block{ + Type: DataBlock, + Path: strings.TrimSpace(split[0]), + Codec: CodecText, + content: input, + } + + if len(split) > 1 { + optionSplit := strings.SplitSeq(split[1], ",") + for option := range optionSplit { + switch strings.TrimSpace(option) { + case "number": + block.Codec = CodecNumber + case "text": + block.Codec = CodecText + case "hashtags": + block.Codec = CodecHashtags + default: + return block, fmt.Errorf("unknown codec option: %s", option) + } + } + } + + return block, nil +} diff --git a/template/blocks_yaml.go b/template/blocks_yaml.go new file mode 100644 index 0000000..226a0ef --- /dev/null +++ b/template/blocks_yaml.go @@ -0,0 +1,86 @@ +package template + +import ( + "fmt" + "strings" + + "go.yaml.in/yaml/v4" +) + +type yamlBlock struct { + Path string `yaml:"path"` + Codec string `yaml:"codec"` + Value any `yaml:"value,omitempty"` + Fields []yamlField `yaml:"fields"` + ListTemplate string `yaml:"listTemplate,omitempty"` + Hidden bool `yaml:"hidden,omitempty"` + PathAlias []string `yaml:"pathAlias,omitempty"` +} + +type yamlField struct { + Path string `yaml:"path"` + Value any `yaml:"value,omitempty"` + Codec string `yaml:"codec"` + Hidden bool `yaml:"hidden,omitempty"` + PathAlias []string `yaml:"pathAlias,omitempty"` +} + +func parseYamlTemplate(input string) (block Block, err error) { + var blk yamlBlock + + cleaned := cleanTemplate(input) + + dec := yaml.NewDecoder(strings.NewReader(cleaned)) + dec.KnownFields(true) + + if err := dec.Decode(&blk); err != nil { + return block, fmt.Errorf("content '%q': %w", cleaned, err) + } + + if blk.Path == "" { + return block, fmt.Errorf("missing top-level 'path'") + } + + if blk.Codec == "" { + blk.Codec = "text" + } + + codec, err := parseCodecType(blk.Codec) + if err != nil { + return block, fmt.Errorf("failed to parse codec: %w", err) + } + + var fields []BlockField + + for _, field := range blk.Fields { + if field.Path == "" { + return block, fmt.Errorf("failed to parse field: %v", field) + } + + if field.Codec == "" { + field.Codec = "text" + } + + fieldCodec, err := parseCodecType(field.Codec) + if err != nil { + return block, fmt.Errorf("failed to parse codec: %w", err) + } + + fields = append(fields, BlockField{ + Path: field.Path, + CodecType: fieldCodec, + Value: field.Value, + Hidden: field.Hidden, + }) + + } + + return Block{ + Type: DataBlock, + Path: blk.Path, + Codec: codec, + Fields: fields, + ListTemplate: blk.ListTemplate, + content: input, + }, nil +} diff --git a/template/go.mod b/template/go.mod index 2a9c7a9..169d84c 100644 --- a/template/go.mod +++ b/template/go.mod @@ -1,5 +1,8 @@ module git.max-richter.dev/max/marka/template -go 1.24.3 +go 1.24.5 -require go.yaml.in/yaml/v4 v4.0.0-rc.1 +require ( + git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e + go.yaml.in/yaml/v4 v4.0.0-rc.1 +) diff --git a/template/go.sum b/template/go.sum index 1dd5057..b6217d4 100644 --- a/template/go.sum +++ b/template/go.sum @@ -1,2 +1,4 @@ +git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e h1:eXAE0JHDvLGqtYSSlX5mw1XAuK+Cmu74c52PyveRhlE= +git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e/go.mod h1:n793S7TENIfgHpZLz0lm0qorM7eCx3zBLby3Fb++hZA= go.yaml.in/yaml/v4 v4.0.0-rc.1 h1:4J1+yLKUIPGexM/Si+9d3pij4hdc7aGO04NhrElqXbY= go.yaml.in/yaml/v4 v4.0.0-rc.1/go.mod h1:CBdeces52/nUXndfQ5OY8GEQuNR9uEEOJPZj/Xq5IzU= diff --git a/validator/go.mod b/validator/go.mod index 36391e1..f278b87 100644 --- a/validator/go.mod +++ b/validator/go.mod @@ -2,6 +2,9 @@ module git.max-richter.dev/max/marka/validator go 1.24.5 -require github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 +require ( + git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 +) require golang.org/x/text v0.14.0 // indirect diff --git a/validator/go.sum b/validator/go.sum index b46b517..3ed7dc1 100644 --- a/validator/go.sum +++ b/validator/go.sum @@ -1,3 +1,7 @@ +git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e h1:eXAE0JHDvLGqtYSSlX5mw1XAuK+Cmu74c52PyveRhlE= +git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e/go.mod h1:n793S7TENIfgHpZLz0lm0qorM7eCx3zBLby3Fb++hZA= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= From 733ae876b989a2d04e40c69d146694c2cf48c20b Mon Sep 17 00:00:00 2001 From: Max Richter Date: Wed, 24 Sep 2025 21:32:27 +0200 Subject: [PATCH 03/20] WIP --- go.work | 4 +- go.work.sum | 6 +- parser/go.mod | 2 +- parser/parser.go | 4 + registry/go.mod | 2 +- renderer/go.mod | 2 +- {server => server-new}/.air.toml | 3 - {server => server-new}/.gitignore | 0 .../cmd/marka-server/main.go | 8 +- server-new/go.mod | 3 + {server => server-new}/go.sum | 0 {server => server-new}/http/.env | 0 {server => server-new}/http/post-recipe.http | 0 server-new/internal/adapters/errors.go | 5 + server-new/internal/adapters/fs.go | 97 ++++++++++++++++ server-new/internal/adapters/fs_utils.go | 78 +++++++++++++ server-new/internal/adapters/interface.go | 34 ++++++ .../internal/handler}/error.go | 12 +- server-new/internal/handler/handler.go | 104 ++++++++++++++++++ server-new/internal/handler/utils.go | 24 ++++ server/internal/handlers/get.go | 93 ---------------- server/internal/handlers/helpers.go | 30 ----- server/internal/handlers/post.go | 47 -------- server/internal/httpx/router.go | 11 -- template/go.mod | 2 +- testdata/go.mod | 2 +- validator/go.mod | 2 +- 27 files changed, 374 insertions(+), 201 deletions(-) rename {server => server-new}/.air.toml (83%) rename {server => server-new}/.gitignore (100%) rename {server => server-new}/cmd/marka-server/main.go (69%) create mode 100644 server-new/go.mod rename {server => server-new}/go.sum (100%) rename {server => server-new}/http/.env (100%) rename {server => server-new}/http/post-recipe.http (100%) create mode 100644 server-new/internal/adapters/errors.go create mode 100644 server-new/internal/adapters/fs.go create mode 100644 server-new/internal/adapters/fs_utils.go create mode 100644 server-new/internal/adapters/interface.go rename {server/internal/httpx => server-new/internal/handler}/error.go (52%) create mode 100644 server-new/internal/handler/handler.go create mode 100644 server-new/internal/handler/utils.go delete mode 100644 server/internal/handlers/get.go delete mode 100644 server/internal/handlers/helpers.go delete mode 100644 server/internal/handlers/post.go delete mode 100644 server/internal/httpx/router.go diff --git a/go.work b/go.work index 3fa22ab..bda2fb4 100644 --- a/go.work +++ b/go.work @@ -1,10 +1,10 @@ -go 1.24.5 +go 1.25.1 use ( ./parser ./registry ./renderer - ./server + ./server-new ./template ./testdata ./validator diff --git a/go.work.sum b/go.work.sum index 213f195..e2e1c0a 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,4 +1,8 @@ -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e/go.mod h1:xQK6tsgr9BOoeFw8JxjBwDkVENlOqapmcRkYyf/L+SQ= +git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e/go.mod h1:n793S7TENIfgHpZLz0lm0qorM7eCx3zBLby3Fb++hZA= +git.max-richter.dev/max/marka/template v0.0.0-20250819170608-69c2550f448e/go.mod h1:Uxi5xcxtnjopsIZjjMlFaWJGuglB9JNL++FuaSbOf6U= +git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a/go.mod h1:88SkY5pTONkgfBy1FT10LoqRC8rt36iF1fk/rupjuJY= +git.max-richter.dev/max/marka/validator v0.0.0-20250819170608-69c2550f448e/go.mod h1:qdGfCFRzsGedmnd77vb7pu/EMx0W0DcQBMEfvNxMYsw= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= diff --git a/parser/go.mod b/parser/go.mod index fe539c6..769354b 100644 --- a/parser/go.mod +++ b/parser/go.mod @@ -1,6 +1,6 @@ module git.max-richter.dev/max/marka/parser -go 1.24.5 +go 1.25.1 require ( git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567 diff --git a/parser/parser.go b/parser/parser.go index 74150a7..b80065b 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -23,6 +23,8 @@ func DetectType(markdownContent string) (string, error) { return "", fmt.Errorf("failed to compile template: %w", err) } + fmt.Println("Content:", markdownContent) + blocks := matcher.MatchBlocksFuzzy(markdownContent, defaultSchema, 0.3) result, err := decoders.Parse(blocks) @@ -30,6 +32,8 @@ func DetectType(markdownContent string) (string, error) { return "", fmt.Errorf("failed to parse blocks: %w", err) } + fmt.Println("Result: ", result) + if result, ok := result.(map[string]any); ok { if contentType, ok := result["@type"]; ok { return contentType.(string), nil diff --git a/registry/go.mod b/registry/go.mod index 7364278..94c016b 100644 --- a/registry/go.mod +++ b/registry/go.mod @@ -1,3 +1,3 @@ module git.max-richter.dev/max/marka/registry -go 1.24.5 +go 1.25.1 diff --git a/renderer/go.mod b/renderer/go.mod index 558a176..b14358a 100644 --- a/renderer/go.mod +++ b/renderer/go.mod @@ -1,6 +1,6 @@ module git.max-richter.dev/max/marka/renderer -go 1.24.5 +go 1.25.1 require ( git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e diff --git a/server/.air.toml b/server-new/.air.toml similarity index 83% rename from server/.air.toml rename to server-new/.air.toml index c8e2c18..b2eced4 100644 --- a/server/.air.toml +++ b/server-new/.air.toml @@ -1,6 +1,3 @@ -# Config file for Air - https://github.com/air-verse/air -# This file is for the marka-server application. - root = "." tmp_dir = "tmp" diff --git a/server/.gitignore b/server-new/.gitignore similarity index 100% rename from server/.gitignore rename to server-new/.gitignore diff --git a/server/cmd/marka-server/main.go b/server-new/cmd/marka-server/main.go similarity index 69% rename from server/cmd/marka-server/main.go rename to server-new/cmd/marka-server/main.go index ef8a90a..b001bfd 100644 --- a/server/cmd/marka-server/main.go +++ b/server-new/cmd/marka-server/main.go @@ -7,7 +7,8 @@ import ( "os" "path/filepath" - "git.max-richter.dev/max/marka/server/internal/handlers" + "git.max-richter.dev/max/marka/server-new/internal/adapters" + "git.max-richter.dev/max/marka/server-new/internal/handler" ) func main() { @@ -24,7 +25,10 @@ func main() { log.Fatal("root is not a directory") } - http.Handle("/", handlers.NewFile(absRoot)) + fsAdapter, err := adapters.NewLocalFsAdapter(absRoot) + must(err) + + http.Handle("/", handler.NewHandler(fsAdapter)) log.Printf("listening on %s, root=%s", *addr, absRoot) log.Fatal(http.ListenAndServe(*addr, nil)) diff --git a/server-new/go.mod b/server-new/go.mod new file mode 100644 index 0000000..341a24f --- /dev/null +++ b/server-new/go.mod @@ -0,0 +1,3 @@ +module git.max-richter.dev/max/marka/server-new + +go 1.25.1 diff --git a/server/go.sum b/server-new/go.sum similarity index 100% rename from server/go.sum rename to server-new/go.sum diff --git a/server/http/.env b/server-new/http/.env similarity index 100% rename from server/http/.env rename to server-new/http/.env diff --git a/server/http/post-recipe.http b/server-new/http/post-recipe.http similarity index 100% rename from server/http/post-recipe.http rename to server-new/http/post-recipe.http diff --git a/server-new/internal/adapters/errors.go b/server-new/internal/adapters/errors.go new file mode 100644 index 0000000..c121579 --- /dev/null +++ b/server-new/internal/adapters/errors.go @@ -0,0 +1,5 @@ +package adapters + +import "errors" + +var ErrNotFound = errors.New("not found") diff --git a/server-new/internal/adapters/fs.go b/server-new/internal/adapters/fs.go new file mode 100644 index 0000000..cfe95dd --- /dev/null +++ b/server-new/internal/adapters/fs.go @@ -0,0 +1,97 @@ +package adapters + +import ( + "os" + "path/filepath" +) + +type LocalFsAdapter struct { + root string +} + +func (l LocalFsAdapter) readDir(path string) (FsResponse, error) { + dirInfo, _ := os.Stat(path) + + entries, err := os.ReadDir(path) + if err != nil { + return FsResponse{}, err + } + + out := make([]FsDirEntry, 0, len(entries)) + for _, e := range entries { + info, _ := e.Info() + + entryType := "dir" + if !e.IsDir() { + entryType = contentTypeFor(e.Name()) + } + + out = append(out, FsDirEntry{ + Name: e.Name(), + Type: entryType, + ModTime: info.ModTime(), + }) + } + + return FsResponse{ + Dir: &FsDir{ + Files: out, + Name: ResponsePath(l.root, path), + ModTime: dirInfo.ModTime(), + }, + }, nil +} + +func (l LocalFsAdapter) readFile(path string) (FsResponse, error) { + fi, err := os.Stat(path) + if err != nil { + return FsResponse{}, err + } + + data, err := os.ReadFile(path) + if err != nil { + return FsResponse{}, err + } + + return FsResponse{ + File: &FsFile{ + Name: ResponsePath(l.root, path), + Type: contentTypeFor(path), + ModTime: fi.ModTime(), + Content: data, + }, + }, nil +} + +func (l LocalFsAdapter) Read(path string) (FsResponse, error) { + cleanRel, err := SafeRel(l.root, path) + if err != nil { + return FsResponse{}, err + } + target := filepath.Join(l.root, filepath.FromSlash(cleanRel)) + + fi, err := os.Stat(target) + if err != nil { + if os.IsNotExist(err) { + return FsResponse{}, ErrNotFound + } + + return FsResponse{}, err + } + + if fi.IsDir() { + return l.readDir(target) + } + + return l.readFile(target) +} + +func (LocalFsAdapter) Write(path string, content []byte) error { + return nil +} + +func NewLocalFsAdapter(root string) (FileAdapter, error) { + return LocalFsAdapter{ + root: root, + }, nil +} diff --git a/server-new/internal/adapters/fs_utils.go b/server-new/internal/adapters/fs_utils.go new file mode 100644 index 0000000..8ebdcde --- /dev/null +++ b/server-new/internal/adapters/fs_utils.go @@ -0,0 +1,78 @@ +package adapters + +import ( + "errors" + "mime" + "os" + "path/filepath" + "strings" + "time" +) + +func SafeRel(root, requested string) (string, error) { + s := requested + if after, ok := strings.CutPrefix(s, "/"); ok { + s = after + } + full := filepath.Join(root, filepath.FromSlash(s)) + rel, err := filepath.Rel(root, full) + if err != nil { + return "", err + } + if rel == "." { + return "/", nil + } + sep := string(filepath.Separator) + if strings.HasPrefix(rel, "..") || strings.Contains(rel, ".."+sep) { + return "", errors.New("path escapes root") + } + return "/" + filepath.ToSlash(rel), nil +} + +func ResponsePath(root, full string) string { + rel, err := filepath.Rel(root, full) + if err != nil || rel == "." { + return "/" + } + return "/" + filepath.ToSlash(rel) +} + +func sizeOrZero(fi os.FileInfo) int64 { + if fi == nil { + return 0 + } + return fi.Size() +} + +func modTimeOrZero(fi os.FileInfo) time.Time { + if fi == nil { + return time.Time{} + } + return fi.ModTime() +} + +var textPlainExtensions = map[string]bool{ + ".txt": true, + ".log": true, + ".json": true, + ".yaml": true, + ".yml": true, + ".toml": true, + ".xml": true, + ".csv": true, +} + +func contentTypeFor(name string) string { + ext := strings.ToLower(filepath.Ext(name)) + switch ext { + case ".md", ".markdown", ".mdown": + return "application/markdown" + } + if ct := mime.TypeByExtension(ext); ct != "" { + return ct + } + if textPlainExtensions[ext] { + return "text/plain; charset=utf-8" + } + return "application/octet-stream" +} diff --git a/server-new/internal/adapters/interface.go b/server-new/internal/adapters/interface.go new file mode 100644 index 0000000..a482676 --- /dev/null +++ b/server-new/internal/adapters/interface.go @@ -0,0 +1,34 @@ +// Package adapters are the backend to that connects the marka server to a storage +package adapters + +import "time" + +type FileAdapter interface { + Read(path string) (FsResponse, error) + Write(path string, content []byte) error +} + +type FsFile struct { + Name string `json:"name"` + Type string `json:"type"` + Content []byte `json:"content"` + ModTime time.Time `json:"modTime"` +} + +type FsDirEntry struct { + Name string `json:"name"` + Type string `json:"type"` + IsDir bool `json:"isDir,omitempty"` + ModTime time.Time `json:"modTime"` +} + +type FsDir struct { + Files []FsDirEntry `json:"files"` + Name string `json:"name"` + ModTime time.Time `json:"modTime"` +} + +type FsResponse struct { + Dir *FsDir `json:"dir,omitempty"` + File *FsFile `json:"file,omitempty"` +} diff --git a/server/internal/httpx/error.go b/server-new/internal/handler/error.go similarity index 52% rename from server/internal/httpx/error.go rename to server-new/internal/handler/error.go index 7c88320..37fcc3d 100644 --- a/server/internal/httpx/error.go +++ b/server-new/internal/handler/error.go @@ -1,4 +1,4 @@ -package httpx +package handler import ( "encoding/json" @@ -9,12 +9,12 @@ type ErrorResponse struct { Error string `json:"error"` } -func WriteJSON(w http.ResponseWriter, code int, v any) { +func writeError(w http.ResponseWriter, code int, err error) { + writeJSON(w, code, ErrorResponse{Error: err.Error()}) +} + +func writeJSON(w http.ResponseWriter, code int, v any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) _ = json.NewEncoder(w).Encode(v) } - -func WriteError(w http.ResponseWriter, code int, err error) { - WriteJSON(w, code, ErrorResponse{Error: err.Error()}) -} diff --git a/server-new/internal/handler/handler.go b/server-new/internal/handler/handler.go new file mode 100644 index 0000000..9a1f13e --- /dev/null +++ b/server-new/internal/handler/handler.go @@ -0,0 +1,104 @@ +// Package handler provides the HTTP handler for the marka server +package handler + +import ( + "errors" + "net/http" + "time" + + "git.max-richter.dev/max/marka/parser" + "git.max-richter.dev/max/marka/server-new/internal/adapters" +) + +type ResponseItem struct { + Name string `json:"name"` + Content any `json:"content,omitempty"` + Type string `json:"type,omitempty"` + IsDir bool `json:"isDir"` + Size int64 `json:"size,omitempty"` + ModTime time.Time `json:"modTime"` +} + +type Handler struct { + adapter adapters.FileAdapter +} + +func (h *Handler) get(w http.ResponseWriter, target string) { + fsEntry, err := h.adapter.Read(target) + if err != nil { + writeError(w, 500, err) + return + } + + if fsEntry.File != nil { + + if fsEntry.File.Content != nil && fsEntry.File.Type == "application/markdown" { + data, err := parser.ParseFile(string(fsEntry.File.Content)) + if err != nil { + writeError(w, 500, err) + return + } + + res := ResponseItem{ + Name: fsEntry.File.Name, + Type: fsEntry.File.Type, + Content: data, + IsDir: false, + Size: int64(len(fsEntry.File.Content)), + ModTime: fsEntry.File.ModTime, + } + + writeJSON(w, 200, res) + return + } + + res := ResponseItem{ + Name: fsEntry.File.Name, + Content: fsEntry.File.Content, + Type: fsEntry.File.Type, + IsDir: false, + Size: int64(len(fsEntry.File.Content)), + ModTime: fsEntry.File.ModTime, + } + writeJSON(w, 200, res) + return + } + + if fsEntry.Dir != nil { + res := ResponseItem{ + Name: fsEntry.Dir.Name, + Content: fsEntry.Dir.Files, + IsDir: true, + ModTime: fsEntry.Dir.ModTime, + } + writeJSON(w, 200, res) + return + } +} + +func (h *Handler) post(w http.ResponseWriter, target string) { +} + +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + reqPath := r.URL.Path + if reqPath == "" { + reqPath = "/" + } + + target := cleanURLLike(reqPath) + + switch r.Method { + case http.MethodGet: + h.get(w, target) + case http.MethodPost: + h.post(w, target) + default: + writeError(w, http.StatusMethodNotAllowed, errors.New("method not allowed")) + } +} + +func NewHandler(adapter adapters.FileAdapter) http.Handler { + return &Handler{ + adapter: adapter, + } +} diff --git a/server-new/internal/handler/utils.go b/server-new/internal/handler/utils.go new file mode 100644 index 0000000..1869ced --- /dev/null +++ b/server-new/internal/handler/utils.go @@ -0,0 +1,24 @@ +package handler + +import "strings" + +func cleanURLLike(p string) string { + p = strings.TrimSpace(p) + if p == "" || p == "/" { + return "/" + } + parts := []string{} + for seg := range strings.SplitSeq(p, "/") { + switch seg { + case "", ".": + continue + case "..": + if len(parts) > 0 { + parts = parts[:len(parts)-1] + } + default: + parts = append(parts, seg) + } + } + return "/" + strings.Join(parts, "/") +} diff --git a/server/internal/handlers/get.go b/server/internal/handlers/get.go deleted file mode 100644 index e1fc5cc..0000000 --- a/server/internal/handlers/get.go +++ /dev/null @@ -1,93 +0,0 @@ -package handlers - -import ( - "errors" - "fmt" - "net/http" - "os" - "path/filepath" - "time" - - "git.max-richter.dev/max/marka/server/internal/fsx" - "git.max-richter.dev/max/marka/server/internal/httpx" -) - -func (h *File) get(w http.ResponseWriter, r *http.Request, target string) { - fi, err := os.Stat(target) - if err != nil { - if os.IsNotExist(err) { - httpx.WriteError(w, http.StatusNotFound, errors.New("not found")) - } else { - httpx.WriteError(w, http.StatusInternalServerError, err) - } - return - } - - if fi.IsDir() { - h.handleDir(w, r, target) - } else { - h.handleFile(w, r, target, fi) - } -} - -func (h *File) handleDir(w http.ResponseWriter, r *http.Request, dirPath string) { - entries, err := os.ReadDir(dirPath) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - - type item struct { - Name string `json:"name"` - Path string `json:"path"` - Content any `json:"content,omitempty"` - IsDir bool `json:"isDir"` - Size int64 `json:"size"` - ModTime time.Time `json:"modTime"` - } - - out := make([]item, 0, len(entries)) - for _, e := range entries { - info, _ := e.Info() // As in original, ignore error to get partial info - entryPath := filepath.Join(dirPath, e.Name()) - - var content any - if !e.IsDir() && fsx.ContentTypeFor(e.Name()) == "application/markdown" { - content, _ = parseMarkdownFile(entryPath) // As in original, ignore error - } - - out = append(out, item{ - Name: e.Name(), - Path: fsx.ResponsePath(h.root, entryPath), - IsDir: e.IsDir(), - Content: content, - Size: sizeOrZero(info), - ModTime: modTimeOrZero(info), - }) - } - httpx.WriteJSON(w, http.StatusOK, out) -} - -func (h *File) handleFile(w http.ResponseWriter, r *http.Request, target string, fi os.FileInfo) { - contentType := fsx.ContentTypeFor(target) - - if contentType == "application/markdown" { - res, err := parseMarkdownFile(target) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, fmt.Errorf("failed to parse markdown: %w", err)) - return - } - httpx.WriteJSON(w, http.StatusOK, res) - return - } - - f, err := os.Open(target) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - defer f.Close() - - w.Header().Set("Content-Type", contentType) - http.ServeContent(w, r, filepath.Base(target), fi.ModTime(), f) -} diff --git a/server/internal/handlers/helpers.go b/server/internal/handlers/helpers.go deleted file mode 100644 index 8cca076..0000000 --- a/server/internal/handlers/helpers.go +++ /dev/null @@ -1,30 +0,0 @@ -package handlers - -import ( - "os" - "time" - - "git.max-richter.dev/max/marka/parser" -) - -func parseMarkdownFile(path string) (any, error) { - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - return parser.ParseFile(string(data)) -} - -func sizeOrZero(fi os.FileInfo) int64 { - if fi == nil { - return 0 - } - return fi.Size() -} - -func modTimeOrZero(fi os.FileInfo) time.Time { - if fi == nil { - return time.Time{} - } - return fi.ModTime() -} diff --git a/server/internal/handlers/post.go b/server/internal/handlers/post.go deleted file mode 100644 index d7d23bc..0000000 --- a/server/internal/handlers/post.go +++ /dev/null @@ -1,47 +0,0 @@ -package handlers - -import ( - "io" - "net/http" - "os" - "path/filepath" - - "git.max-richter.dev/max/marka/server/internal/httpx" -) - -func (h *File) post(w http.ResponseWriter, r *http.Request, target string) { - if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - - tmpPath := target + ".tmp~" - f, err := os.Create(tmpPath) - if err != nil { - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - - _, copyErr := io.Copy(f, r.Body) - closeErr := f.Close() - - if copyErr != nil { - os.Remove(tmpPath) - httpx.WriteError(w, http.StatusInternalServerError, copyErr) - return - } - if closeErr != nil { - os.Remove(tmpPath) - httpx.WriteError(w, http.StatusInternalServerError, closeErr) - return - } - - if err := os.Rename(tmpPath, target); err != nil { - os.Remove(tmpPath) - httpx.WriteError(w, http.StatusInternalServerError, err) - return - } - - w.Header().Set("Location", r.URL.Path) - w.WriteHeader(http.StatusCreated) -} diff --git a/server/internal/httpx/router.go b/server/internal/httpx/router.go deleted file mode 100644 index dfdeec7..0000000 --- a/server/internal/httpx/router.go +++ /dev/null @@ -1,11 +0,0 @@ -package httpx - -import "net/http" - -type Router struct{ mux *http.ServeMux } - -func NewRouter() *Router { return &Router{mux: http.NewServeMux()} } -func (r *Router) Handle(pattern string, h http.Handler) { r.mux.Handle(pattern, h) } -func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { - r.mux.ServeHTTP(w, req) -} diff --git a/template/go.mod b/template/go.mod index 169d84c..2cd6cd1 100644 --- a/template/go.mod +++ b/template/go.mod @@ -1,6 +1,6 @@ module git.max-richter.dev/max/marka/template -go 1.24.5 +go 1.25.1 require ( git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e diff --git a/testdata/go.mod b/testdata/go.mod index dd01c9b..6515ee9 100644 --- a/testdata/go.mod +++ b/testdata/go.mod @@ -1,3 +1,3 @@ module git.max-richter.dev/max/marka/testdata -go 1.24.5 +go 1.25.1 diff --git a/validator/go.mod b/validator/go.mod index f278b87..358e582 100644 --- a/validator/go.mod +++ b/validator/go.mod @@ -1,6 +1,6 @@ module git.max-richter.dev/max/marka/validator -go 1.24.5 +go 1.25.1 require ( git.max-richter.dev/max/marka/registry v0.0.0-20250819170608-69c2550f448e From 3f0d25f935c3df9e0748fcbcd6dfb89f8b3e7d04 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Wed, 24 Sep 2025 22:39:14 +0200 Subject: [PATCH 04/20] wrip --- server-new/go.mod | 3 - {server-new => server}/.air.toml | 0 {server-new => server}/.gitignore | 0 .../cmd/marka-server/main.go | 0 server/go.mod | 17 +----- {server-new => server}/go.sum | 0 {server-new => server}/http/.env | 0 {server-new => server}/http/post-recipe.http | 0 .../internal/adapters/errors.go | 0 .../internal/adapters/fs.go | 0 .../internal/adapters/fs_utils.go | 0 .../internal/adapters/interface.go | 0 server/internal/fsx/contenttype.go | 33 ----------- server/internal/fsx/path.go | 56 ------------------- .../internal/handler/error.go | 0 .../internal/handler/handler.go | 0 .../internal/handler/utils.go | 0 server/internal/handlers/file.go | 38 ------------- 18 files changed, 2 insertions(+), 145 deletions(-) delete mode 100644 server-new/go.mod rename {server-new => server}/.air.toml (100%) rename {server-new => server}/.gitignore (100%) rename {server-new => server}/cmd/marka-server/main.go (100%) rename {server-new => server}/go.sum (100%) rename {server-new => server}/http/.env (100%) rename {server-new => server}/http/post-recipe.http (100%) rename {server-new => server}/internal/adapters/errors.go (100%) rename {server-new => server}/internal/adapters/fs.go (100%) rename {server-new => server}/internal/adapters/fs_utils.go (100%) rename {server-new => server}/internal/adapters/interface.go (100%) delete mode 100644 server/internal/fsx/contenttype.go delete mode 100644 server/internal/fsx/path.go rename {server-new => server}/internal/handler/error.go (100%) rename {server-new => server}/internal/handler/handler.go (100%) rename {server-new => server}/internal/handler/utils.go (100%) delete mode 100644 server/internal/handlers/file.go diff --git a/server-new/go.mod b/server-new/go.mod deleted file mode 100644 index 341a24f..0000000 --- a/server-new/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module git.max-richter.dev/max/marka/server-new - -go 1.25.1 diff --git a/server-new/.air.toml b/server/.air.toml similarity index 100% rename from server-new/.air.toml rename to server/.air.toml diff --git a/server-new/.gitignore b/server/.gitignore similarity index 100% rename from server-new/.gitignore rename to server/.gitignore diff --git a/server-new/cmd/marka-server/main.go b/server/cmd/marka-server/main.go similarity index 100% rename from server-new/cmd/marka-server/main.go rename to server/cmd/marka-server/main.go diff --git a/server/go.mod b/server/go.mod index 250391c..341a24f 100644 --- a/server/go.mod +++ b/server/go.mod @@ -1,16 +1,3 @@ -module git.max-richter.dev/max/marka/server +module git.max-richter.dev/max/marka/server-new -go 1.24.5 - -require git.max-richter.dev/max/marka/parser v0.0.0-20250819170608-69c2550f448e - -require ( - git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567 // indirect - git.max-richter.dev/max/marka/renderer v0.0.0-20250819170608-69c2550f448e // indirect - git.max-richter.dev/max/marka/template v0.0.0-20250817132016-6db87db32567 // indirect - git.max-richter.dev/max/marka/testdata v0.0.0-20250819195334-b3c01bb43d9a // indirect - github.com/agext/levenshtein v1.2.3 // indirect - github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect - go.yaml.in/yaml/v4 v4.0.0-rc.1 // indirect - golang.org/x/text v0.14.0 // indirect -) +go 1.25.1 diff --git a/server-new/go.sum b/server/go.sum similarity index 100% rename from server-new/go.sum rename to server/go.sum diff --git a/server-new/http/.env b/server/http/.env similarity index 100% rename from server-new/http/.env rename to server/http/.env diff --git a/server-new/http/post-recipe.http b/server/http/post-recipe.http similarity index 100% rename from server-new/http/post-recipe.http rename to server/http/post-recipe.http diff --git a/server-new/internal/adapters/errors.go b/server/internal/adapters/errors.go similarity index 100% rename from server-new/internal/adapters/errors.go rename to server/internal/adapters/errors.go diff --git a/server-new/internal/adapters/fs.go b/server/internal/adapters/fs.go similarity index 100% rename from server-new/internal/adapters/fs.go rename to server/internal/adapters/fs.go diff --git a/server-new/internal/adapters/fs_utils.go b/server/internal/adapters/fs_utils.go similarity index 100% rename from server-new/internal/adapters/fs_utils.go rename to server/internal/adapters/fs_utils.go diff --git a/server-new/internal/adapters/interface.go b/server/internal/adapters/interface.go similarity index 100% rename from server-new/internal/adapters/interface.go rename to server/internal/adapters/interface.go diff --git a/server/internal/fsx/contenttype.go b/server/internal/fsx/contenttype.go deleted file mode 100644 index 2288c93..0000000 --- a/server/internal/fsx/contenttype.go +++ /dev/null @@ -1,33 +0,0 @@ -package fsx - -import ( - "mime" - "path/filepath" - "strings" -) - -var textPlainExtensions = map[string]bool{ - ".txt": true, - ".log": true, - ".json": true, - ".yaml": true, - ".yml": true, - ".toml": true, - ".xml": true, - ".csv": true, -} - -func ContentTypeFor(name string) string { - ext := strings.ToLower(filepath.Ext(name)) - switch ext { - case ".md", ".markdown", ".mdown": - return "application/markdown" - } - if ct := mime.TypeByExtension(ext); ct != "" { - return ct - } - if textPlainExtensions[ext] { - return "text/plain; charset=utf-8" - } - return "application/octet-stream" -} diff --git a/server/internal/fsx/path.go b/server/internal/fsx/path.go deleted file mode 100644 index 6916a16..0000000 --- a/server/internal/fsx/path.go +++ /dev/null @@ -1,56 +0,0 @@ -package fsx - -import ( - "errors" - "path/filepath" - "strings" -) - -func CleanURLLike(p string) string { - p = strings.TrimSpace(p) - if p == "" || p == "/" { - return "/" - } - parts := []string{} - for seg := range strings.SplitSeq(strings.ReplaceAll(p, "/", "/"), "/") { - switch seg { - case "", ".": - continue - case "..": - if len(parts) > 0 { - parts = parts[:len(parts)-1] - } - default: - parts = append(parts, seg) - } - } - return "/" + strings.Join(parts, "/") -} - -func SafeRel(root, requested string) (string, error) { - s := CleanURLLike(requested) - if after, ok := strings.CutPrefix(s, "/"); ok { - s = after - } - full := filepath.Join(root, filepath.FromSlash(s)) - rel, err := filepath.Rel(root, full) - if err != nil { - return "", err - } - if rel == "." { - return "/", nil - } - sep := string(filepath.Separator) - if strings.HasPrefix(rel, "..") || strings.Contains(rel, ".."+sep) { - return "", errors.New("path escapes root") - } - return "/" + filepath.ToSlash(rel), nil -} - -func ResponsePath(root, full string) string { - rel, err := filepath.Rel(root, full) - if err != nil || rel == "." { - return "/" - } - return "/" + filepath.ToSlash(rel) -} diff --git a/server-new/internal/handler/error.go b/server/internal/handler/error.go similarity index 100% rename from server-new/internal/handler/error.go rename to server/internal/handler/error.go diff --git a/server-new/internal/handler/handler.go b/server/internal/handler/handler.go similarity index 100% rename from server-new/internal/handler/handler.go rename to server/internal/handler/handler.go diff --git a/server-new/internal/handler/utils.go b/server/internal/handler/utils.go similarity index 100% rename from server-new/internal/handler/utils.go rename to server/internal/handler/utils.go diff --git a/server/internal/handlers/file.go b/server/internal/handlers/file.go deleted file mode 100644 index dac05bb..0000000 --- a/server/internal/handlers/file.go +++ /dev/null @@ -1,38 +0,0 @@ -// Package handlers provides HTTP handlers for the file system. -package handlers - -import ( - "errors" - "net/http" - "path/filepath" - - "git.max-richter.dev/max/marka/server/internal/fsx" - "git.max-richter.dev/max/marka/server/internal/httpx" -) - -type File struct{ root string } - -func NewFile(root string) http.Handler { return &File{root: root} } - -func (h *File) ServeHTTP(w http.ResponseWriter, r *http.Request) { - reqPath := r.URL.Path - if reqPath == "" { - reqPath = "/" - } - cleanRel, err := fsx.SafeRel(h.root, reqPath) - if err != nil { - httpx.WriteError(w, http.StatusBadRequest, err) - return - } - target := filepath.Join(h.root, filepath.FromSlash(cleanRel)) - - switch r.Method { - case http.MethodGet: - h.get(w, r, target) - case http.MethodPost: - h.post(w, r, target) - default: - httpx.WriteError(w, http.StatusMethodNotAllowed, errors.New("method not allowed")) - } -} - From b13d5015f4f9f5d89707074573cd8c21d9ac83c1 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Thu, 25 Sep 2025 16:41:26 +0200 Subject: [PATCH 05/20] wip --- examples/Article/A dress a day.md | 2 +- examples/Books/Minimal.md | 9 +- examples/Books/NoAuthor.md | 7 +- examples/Books/NoBody.md | 9 +- examples/Books/NoRating.md | 9 +- examples/Books/TheGreatGatsby.md | 4 +- examples/Movies/Minimal.md | 7 +- examples/Movies/Negative.md | 9 +- examples/Movies/NoBody.md | 9 +- examples/Movies/Structured.md | 9 +- examples/Recipes/baguette.md | 1 + examples/Recipes/complex.md | 2 +- go.work | 5 +- mise.toml | 2 + parser/go.mod | 2 +- parser/matcher/matcher_test.go | 4 +- parser/parser.go | 48 +- playground/.gitignore | 23 + playground/.npmrc | 1 + playground/.prettierignore | 9 + playground/.prettierrc | 16 + playground/README.md | 38 + playground/eslint.config.js | 41 + playground/package.json | 43 + playground/pnpm-lock.yaml | 2599 +++++++++++++++++ playground/src/app.css | 1 + playground/src/app.d.ts | 22 + playground/src/app.html | 12 + playground/src/lib/assets/favicon.svg | 1 + .../src/lib/components/EditorPanel.svelte | 35 + playground/src/lib/components/Header.svelte | 26 + .../src/lib/components/Playground.svelte | 84 + .../src/lib/components/StatusBar.svelte | 25 + playground/src/lib/index.ts | 1 + playground/src/routes/+layout.svelte | 12 + playground/src/routes/+page.svelte | 33 + playground/src/routes/+page.svelte2 | 47 + playground/static/main.wasm | Bin 0 -> 486216 bytes playground/static/robots.txt | 3 + playground/static/wasm_exec.js | 553 ++++ playground/svelte.config.js | 18 + playground/tsconfig.json | 19 + playground/vite.config.ts | 7 + playground/wasm/build.sh | 21 + playground/wasm/go.mod | 3 + playground/wasm/main.go | 59 + registry/go.mod | 2 +- registry/templates/Article.marka | 10 +- registry/templates/Recipe.marka | 13 +- registry/templates/Review.marka | 10 +- registry/templates/_default.marka | 2 +- renderer/encoders/encoders.go | 3 +- renderer/go.mod | 2 +- renderer/renderer.go | 6 +- renderer/renderer_test.go | 6 +- server/go.mod | 2 +- template/blocks_short.go | 5 +- template/compile_test.go | 4 +- template/go.mod | 2 +- template/structs.go | 1 + testdata/data/article_simple/input.md | 2 +- testdata/data/article_simple/output.json | 7 +- testdata/data/baguette/input.md | 2 +- testdata/data/baguette/output.json | 5 +- testdata/data/complex_front_matter/input.md | 6 +- .../data/complex_front_matter/output.json | 7 +- testdata/data/recipe_no_description/input.md | 2 +- .../data/recipe_no_description/output.json | 7 +- testdata/data/recipe_salad/input.md | 2 +- testdata/data/recipe_salad/output.json | 7 +- testdata/data/typo_section_header/input.md | 4 +- testdata/data/typo_section_header/output.json | 5 +- testdata/go.mod | 2 +- validator/go.mod | 2 +- validator/validator_test.go | 4 +- 75 files changed, 3881 insertions(+), 141 deletions(-) create mode 100644 mise.toml create mode 100644 playground/.gitignore create mode 100644 playground/.npmrc create mode 100644 playground/.prettierignore create mode 100644 playground/.prettierrc create mode 100644 playground/README.md create mode 100644 playground/eslint.config.js create mode 100644 playground/package.json create mode 100644 playground/pnpm-lock.yaml create mode 100644 playground/src/app.css create mode 100644 playground/src/app.d.ts create mode 100644 playground/src/app.html create mode 100644 playground/src/lib/assets/favicon.svg create mode 100644 playground/src/lib/components/EditorPanel.svelte create mode 100644 playground/src/lib/components/Header.svelte create mode 100644 playground/src/lib/components/Playground.svelte create mode 100644 playground/src/lib/components/StatusBar.svelte create mode 100644 playground/src/lib/index.ts create mode 100644 playground/src/routes/+layout.svelte create mode 100644 playground/src/routes/+page.svelte create mode 100644 playground/src/routes/+page.svelte2 create mode 100644 playground/static/main.wasm create mode 100644 playground/static/robots.txt create mode 100644 playground/static/wasm_exec.js create mode 100644 playground/svelte.config.js create mode 100644 playground/tsconfig.json create mode 100644 playground/vite.config.ts create mode 100755 playground/wasm/build.sh create mode 100644 playground/wasm/go.mod create mode 100644 playground/wasm/main.go diff --git a/examples/Article/A dress a day.md b/examples/Article/A dress a day.md index 668aa2f..6ad95d1 100644 --- a/examples/Article/A dress a day.md +++ b/examples/Article/A dress a day.md @@ -1,5 +1,5 @@ --- -@type: Article +_type: Article author.name: Erin Mckean url: https://dressaday.com/2006/10/20/you-dont-have-to-be-pretty/ rating: 5 diff --git a/examples/Books/Minimal.md b/examples/Books/Minimal.md index 2a03152..80be6dd 100644 --- a/examples/Books/Minimal.md +++ b/examples/Books/Minimal.md @@ -1,15 +1,14 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Alice datePublished: 2025-08-01 itemReviewed: - @type: Book + _type: Book name: Untitled author: - @type: Person + _type: Person name: Unknown --- diff --git a/examples/Books/NoAuthor.md b/examples/Books/NoAuthor.md index af24dc7..be07361 100644 --- a/examples/Books/NoAuthor.md +++ b/examples/Books/NoAuthor.md @@ -1,12 +1,11 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Eve datePublished: 2025-08-15 itemReviewed: - @type: Book + _type: Book name: Anonymous Poems reviewBody: "Short, haunting, and powerful verses." reviewRating.ratingValue: 4 diff --git a/examples/Books/NoBody.md b/examples/Books/NoBody.md index fc0bc0b..42cfad4 100644 --- a/examples/Books/NoBody.md +++ b/examples/Books/NoBody.md @@ -1,15 +1,14 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Clara datePublished: 2025-08-10 itemReviewed: - @type: Book + _type: Book name: 1984 author: - @type: Person + _type: Person name: George Orwell reviewRating: 5 --- diff --git a/examples/Books/NoRating.md b/examples/Books/NoRating.md index 94571b4..33cb9ca 100644 --- a/examples/Books/NoRating.md +++ b/examples/Books/NoRating.md @@ -1,15 +1,14 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Bob datePublished: 2025-08-05 itemReviewed: - @type: Book + _type: Book name: War and Peace author: - @type: Person + _type: Person name: Leo Tolstoy reviewAspect: - Length diff --git a/examples/Books/TheGreatGatsby.md b/examples/Books/TheGreatGatsby.md index b32be88..bbb476d 100644 --- a/examples/Books/TheGreatGatsby.md +++ b/examples/Books/TheGreatGatsby.md @@ -1,9 +1,9 @@ --- -@type: Review +_type: Review author: name: Max Richter itemReviewed: - @type: Book + _type: Book author: name: F. Scott Fitzgerald reviewRating: 5 diff --git a/examples/Movies/Minimal.md b/examples/Movies/Minimal.md index 90c95f6..fa55f06 100644 --- a/examples/Movies/Minimal.md +++ b/examples/Movies/Minimal.md @@ -1,12 +1,11 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Frank datePublished: 2025-08-01 itemReviewed: - @type: Movie + _type: Movie name: Untitled Film --- diff --git a/examples/Movies/Negative.md b/examples/Movies/Negative.md index 0447d31..84dd303 100644 --- a/examples/Movies/Negative.md +++ b/examples/Movies/Negative.md @@ -1,15 +1,14 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Grace datePublished: 2025-08-02 itemReviewed: - @type: Movie + _type: Movie name: The Room author: - @type: Person + _type: Person name: Tommy Wiseau negativeNotes: - Awkward dialogue diff --git a/examples/Movies/NoBody.md b/examples/Movies/NoBody.md index 524bbc4..4040c5a 100644 --- a/examples/Movies/NoBody.md +++ b/examples/Movies/NoBody.md @@ -1,15 +1,14 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Jack datePublished: 2025-08-06 itemReviewed: - @type: Movie + _type: Movie name: Blade Runner author: - @type: Person + _type: Person name: Ridley Scott reviewRating: 4.5/5 reviewAspect: diff --git a/examples/Movies/Structured.md b/examples/Movies/Structured.md index ca851e8..7a37859 100644 --- a/examples/Movies/Structured.md +++ b/examples/Movies/Structured.md @@ -1,15 +1,14 @@ --- -@context: https://schema.org -@type: Review +_type: Review author: - @type: Person + _type: Person name: Henry datePublished: 2025-08-03 itemReviewed: - @type: Movie + _type: Movie name: Inception author: - @type: Person + _type: Person name: Christopher Nolan reviewAspect: - Story diff --git a/examples/Recipes/baguette.md b/examples/Recipes/baguette.md index 28c932b..b1fb4bd 100644 --- a/examples/Recipes/baguette.md +++ b/examples/Recipes/baguette.md @@ -1,4 +1,5 @@ --- +_type: Recipe author.name: Max Richter --- diff --git a/examples/Recipes/complex.md b/examples/Recipes/complex.md index 91a49b3..49178d1 100644 --- a/examples/Recipes/complex.md +++ b/examples/Recipes/complex.md @@ -1,6 +1,6 @@ --- author.name: Jane Doe -author.@type: Organization +author._type: Organization recipeCategory: ["Dessert", "Vegan", "Quick"] --- diff --git a/go.work b/go.work index bda2fb4..3fa1c33 100644 --- a/go.work +++ b/go.work @@ -1,10 +1,11 @@ -go 1.25.1 +go 1.24.7 use ( ./parser + ./playground/wasm ./registry ./renderer - ./server-new + ./server ./template ./testdata ./validator diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..d076463 --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +go = "1.24.7" diff --git a/parser/go.mod b/parser/go.mod index 769354b..fe9bbaf 100644 --- a/parser/go.mod +++ b/parser/go.mod @@ -1,6 +1,6 @@ module git.max-richter.dev/max/marka/parser -go 1.25.1 +go 1.24.7 require ( git.max-richter.dev/max/marka/registry v0.0.0-20250817132016-6db87db32567 diff --git a/parser/matcher/matcher_test.go b/parser/matcher/matcher_test.go index cae1b6c..02ce1f6 100644 --- a/parser/matcher/matcher_test.go +++ b/parser/matcher/matcher_test.go @@ -55,7 +55,7 @@ func TestFuzzyBlockMatch(t *testing.T) { value string }{ { - value: "@type: Recipe\nauthor.name: Max Richter", + value: "_type: Recipe\nauthor.name: Max Richter", }, { value: "Baguette", @@ -105,7 +105,7 @@ func TestFuzzyBlockMatchSalad(t *testing.T) { value string }{ { - value: "@type: Recipe\nauthor.name: Alex Chef\ncookTime: PT0M\nimage: https://example.com/salad.jpg\nprepTime: PT10M\nrecipeYield: 2 servings", + value: "_type: Recipe\nauthor.name: Alex Chef\ncookTime: PT0M\nimage: https://example.com/salad.jpg\nprepTime: PT10M\nrecipeYield: 2 servings", }, { value: "Simple Salad", diff --git a/parser/parser.go b/parser/parser.go index b80065b..ce1553b 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -23,8 +23,6 @@ func DetectType(markdownContent string) (string, error) { return "", fmt.Errorf("failed to compile template: %w", err) } - fmt.Println("Content:", markdownContent) - blocks := matcher.MatchBlocksFuzzy(markdownContent, defaultSchema, 0.3) result, err := decoders.Parse(blocks) @@ -32,28 +30,17 @@ func DetectType(markdownContent string) (string, error) { return "", fmt.Errorf("failed to parse blocks: %w", err) } - fmt.Println("Result: ", result) - if result, ok := result.(map[string]any); ok { - if contentType, ok := result["@type"]; ok { + if contentType, ok := result["_type"]; ok { return contentType.(string), nil - } else { - return "", fmt.Errorf("frontmatter did not contain '@type'") } - } else { - return "", fmt.Errorf("could not parse frontmatter") + return "", fmt.Errorf("frontmatter did not contain '_type'") } + return "", fmt.Errorf("could not parse frontmatter") } -func prepareMarkdown(input string) string { - input = strings.TrimSuffix(input, "\n") - input = strings.ReplaceAll(input, "@type:", `"@type":`) - input = strings.ReplaceAll(input, "@context:", `"@context":`) - return input -} - -func ParseFile(markdownContent string) (any, error) { - markdownContent = prepareMarkdown(markdownContent) +func MatchBlocks(markdownContent string) ([]matcher.Block, error) { + markdownContent = strings.TrimSuffix(markdownContent, "\n") contentType, err := DetectType(markdownContent) if err != nil { @@ -65,12 +52,33 @@ func ParseFile(markdownContent string) (any, error) { return nil, fmt.Errorf("could not get schema: %w", err) } - template, err := template.CompileTemplate(templateContent) + tpl, err := template.CompileTemplate(templateContent) if err != nil { return nil, fmt.Errorf("failed to compile template: %w", err) } - blocks := matcher.MatchBlocksFuzzy(markdownContent, template, 0.3) + return matcher.MatchBlocksFuzzy(markdownContent, tpl, 0.3), nil +} + +func ParseFile(markdownContent string) (any, error) { + markdownContent = strings.TrimSuffix(markdownContent, "\n") + + contentType, err := DetectType(markdownContent) + if err != nil { + return nil, fmt.Errorf("could not detect type: %w", err) + } + + templateContent, err := registry.GetTemplate(contentType) + if err != nil { + return nil, fmt.Errorf("could not get schema: %w", err) + } + + tpl, err := template.CompileTemplate(templateContent) + if err != nil { + return nil, fmt.Errorf("failed to compile template: %w", err) + } + + blocks := matcher.MatchBlocksFuzzy(markdownContent, tpl, 0.3) result, err := decoders.Parse(blocks) if err != nil { diff --git a/playground/.gitignore b/playground/.gitignore new file mode 100644 index 0000000..3b462cb --- /dev/null +++ b/playground/.gitignore @@ -0,0 +1,23 @@ +node_modules + +# Output +.output +.vercel +.netlify +.wrangler +/.svelte-kit +/build + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.* +!.env.example +!.env.test + +# Vite +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/playground/.npmrc b/playground/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/playground/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/playground/.prettierignore b/playground/.prettierignore new file mode 100644 index 0000000..7d74fe2 --- /dev/null +++ b/playground/.prettierignore @@ -0,0 +1,9 @@ +# Package Managers +package-lock.json +pnpm-lock.yaml +yarn.lock +bun.lock +bun.lockb + +# Miscellaneous +/static/ diff --git a/playground/.prettierrc b/playground/.prettierrc new file mode 100644 index 0000000..8103a0b --- /dev/null +++ b/playground/.prettierrc @@ -0,0 +1,16 @@ +{ + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], + "overrides": [ + { + "files": "*.svelte", + "options": { + "parser": "svelte" + } + } + ], + "tailwindStylesheet": "./src/app.css" +} diff --git a/playground/README.md b/playground/README.md new file mode 100644 index 0000000..75842c4 --- /dev/null +++ b/playground/README.md @@ -0,0 +1,38 @@ +# sv + +Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```sh +# create a new project in the current directory +npx sv create + +# create a new project in my-app +npx sv create my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```sh +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```sh +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment. diff --git a/playground/eslint.config.js b/playground/eslint.config.js new file mode 100644 index 0000000..2c49fa6 --- /dev/null +++ b/playground/eslint.config.js @@ -0,0 +1,41 @@ +import prettier from 'eslint-config-prettier'; +import { fileURLToPath } from 'node:url'; +import { includeIgnoreFile } from '@eslint/compat'; +import js from '@eslint/js'; +import svelte from 'eslint-plugin-svelte'; +import { defineConfig } from 'eslint/config'; +import globals from 'globals'; +import ts from 'typescript-eslint'; +import svelteConfig from './svelte.config.js'; + +const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url)); + +export default defineConfig( + includeIgnoreFile(gitignorePath), + js.configs.recommended, + ...ts.configs.recommended, + ...svelte.configs.recommended, + prettier, + ...svelte.configs.prettier, + { + languageOptions: { + globals: { ...globals.browser, ...globals.node } + }, + rules: { + // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. + // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors + 'no-undef': 'off' + } + }, + { + files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], + languageOptions: { + parserOptions: { + projectService: true, + extraFileExtensions: ['.svelte'], + parser: ts.parser, + svelteConfig + } + } + } +); diff --git a/playground/package.json b/playground/package.json new file mode 100644 index 0000000..9a1e976 --- /dev/null +++ b/playground/package.json @@ -0,0 +1,43 @@ +{ + "name": "playground", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "prepare": "svelte-kit sync || echo ''", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "format": "prettier --write .", + "lint": "prettier --check . && eslint ." + }, + "devDependencies": { + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.22.0", + "@sveltejs/adapter-auto": "^6.0.0", + "@sveltejs/kit": "^2.22.0", + "@sveltejs/vite-plugin-svelte": "^6.0.0", + "@tailwindcss/vite": "^4.0.0", + "@types/node": "^22", + "eslint": "^9.22.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-svelte": "^3.0.0", + "globals": "^16.0.0", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.11", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.0.0", + "typescript-eslint": "^8.20.0", + "vite": "^7.0.4" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild" + ] + } +} diff --git a/playground/pnpm-lock.yaml b/playground/pnpm-lock.yaml new file mode 100644 index 0000000..65dfcec --- /dev/null +++ b/playground/pnpm-lock.yaml @@ -0,0 +1,2599 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@eslint/compat': + specifier: ^1.2.5 + version: 1.4.0(eslint@9.36.0(jiti@2.6.0)) + '@eslint/js': + specifier: ^9.22.0 + version: 9.36.0 + '@sveltejs/adapter-auto': + specifier: ^6.0.0 + version: 6.1.0(@sveltejs/kit@2.43.4(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1))) + '@sveltejs/kit': + specifier: ^2.22.0 + version: 2.43.4(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + '@sveltejs/vite-plugin-svelte': + specifier: ^6.0.0 + version: 6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + '@tailwindcss/vite': + specifier: ^4.0.0 + version: 4.1.13(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + '@types/node': + specifier: ^22 + version: 22.18.6 + eslint: + specifier: ^9.22.0 + version: 9.36.0(jiti@2.6.0) + eslint-config-prettier: + specifier: ^10.0.1 + version: 10.1.8(eslint@9.36.0(jiti@2.6.0)) + eslint-plugin-svelte: + specifier: ^3.0.0 + version: 3.12.4(eslint@9.36.0(jiti@2.6.0))(svelte@5.39.6) + globals: + specifier: ^16.0.0 + version: 16.4.0 + prettier: + specifier: ^3.4.2 + version: 3.6.2 + prettier-plugin-svelte: + specifier: ^3.3.3 + version: 3.4.0(prettier@3.6.2)(svelte@5.39.6) + prettier-plugin-tailwindcss: + specifier: ^0.6.11 + version: 0.6.14(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.39.6))(prettier@3.6.2) + svelte: + specifier: ^5.0.0 + version: 5.39.6 + svelte-check: + specifier: ^4.0.0 + version: 4.3.2(picomatch@4.0.3)(svelte@5.39.6)(typescript@5.9.2) + tailwindcss: + specifier: ^4.0.0 + version: 4.1.13 + typescript: + specifier: ^5.0.0 + version: 5.9.2 + typescript-eslint: + specifier: ^8.20.0 + version: 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + vite: + specifier: ^7.0.4 + version: 7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1) + +packages: + + '@esbuild/aix-ppc64@0.25.10': + resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.10': + resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.10': + resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.10': + resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.10': + resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.10': + resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.10': + resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.10': + resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.10': + resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.10': + resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.10': + resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.10': + resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.10': + resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.10': + resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.10': + resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.10': + resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.10': + resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.10': + resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.10': + resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.10': + resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.10': + resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.10': + resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.10': + resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.10': + resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.10': + resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.10': + resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/compat@1.4.0': + resolution: {integrity: sha512-DEzm5dKeDBPm3r08Ixli/0cmxr8LkRdwxMRUIJBlSCpAwSrvFEJpVBzV+66JhDxiaqKxnRzCXhtiMiczF7Hglg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.40 || 9 + peerDependenciesMeta: + eslint: + optional: true + + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.3.1': + resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.16.0': + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.36.0': + resolution: {integrity: sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + + '@rollup/rollup-android-arm-eabi@4.52.2': + resolution: {integrity: sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.52.2': + resolution: {integrity: sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.52.2': + resolution: {integrity: sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.52.2': + resolution: {integrity: sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.52.2': + resolution: {integrity: sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.52.2': + resolution: {integrity: sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.2': + resolution: {integrity: sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.52.2': + resolution: {integrity: sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.52.2': + resolution: {integrity: sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.52.2': + resolution: {integrity: sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.2': + resolution: {integrity: sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.52.2': + resolution: {integrity: sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.52.2': + resolution: {integrity: sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.52.2': + resolution: {integrity: sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.52.2': + resolution: {integrity: sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.52.2': + resolution: {integrity: sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.52.2': + resolution: {integrity: sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.52.2': + resolution: {integrity: sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.52.2': + resolution: {integrity: sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.2': + resolution: {integrity: sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.2': + resolution: {integrity: sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.2': + resolution: {integrity: sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==} + cpu: [x64] + os: [win32] + + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@sveltejs/acorn-typescript@1.0.5': + resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==} + peerDependencies: + acorn: ^8.9.0 + + '@sveltejs/adapter-auto@6.1.0': + resolution: {integrity: sha512-shOuLI5D2s+0zTv2ab5M5PqfknXqWbKi+0UwB9yLTRIdzsK1R93JOO8jNhIYSHdW+IYXIYnLniu+JZqXs7h9Wg==} + peerDependencies: + '@sveltejs/kit': ^2.0.0 + + '@sveltejs/kit@2.43.4': + resolution: {integrity: sha512-GfvOq3A/qMRhj2L9eKjxaI8FLqZDh5SY74YzhRKT//u2AvQw96ksEfjuHviC4jg9U08mBVB0Y47EwEJHO4BB4Q==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.0.0 + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@sveltejs/vite-plugin-svelte-inspector@5.0.1': + resolution: {integrity: sha512-ubWshlMk4bc8mkwWbg6vNvCeT7lGQojE3ijDh3QTR6Zr/R+GXxsGbyH4PExEPpiFmqPhYiVSVmHBjUcVc1JIrA==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0 + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + + '@sveltejs/vite-plugin-svelte@6.2.1': + resolution: {integrity: sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + + '@tailwindcss/node@4.1.13': + resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} + + '@tailwindcss/oxide-android-arm64@4.1.13': + resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.13': + resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.13': + resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.13': + resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.13': + resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.13': + resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.13': + resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.13': + resolution: {integrity: sha512-0PmqLQ010N58SbMTJ7BVJ4I2xopiQn/5i6nlb4JmxzQf8zcS5+m2Cv6tqh+sfDwtIdjoEnOvwsGQ1hkUi8QEHQ==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@22.18.6': + resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} + + '@typescript-eslint/eslint-plugin@8.44.1': + resolution: {integrity: sha512-molgphGqOBT7t4YKCSkbasmu1tb1MgrZ2szGzHbclF7PNmOkSTQVHy+2jXOSnxvR3+Xe1yySHFZoqMpz3TfQsw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.44.1 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.44.1': + resolution: {integrity: sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.44.1': + resolution: {integrity: sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.44.1': + resolution: {integrity: sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.44.1': + resolution: {integrity: sha512-B5OyACouEjuIvof3o86lRMvyDsFwZm+4fBOqFHccIctYgBjqR3qT39FBYGN87khcgf0ExpdCBeGKpKRhSFTjKQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.44.1': + resolution: {integrity: sha512-KdEerZqHWXsRNKjF9NYswNISnFzXfXNDfPxoTh7tqohU/PRIbwTmsjGK6V9/RTYWau7NZvfo52lgVk+sJh0K3g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.44.1': + resolution: {integrity: sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.44.1': + resolution: {integrity: sha512-qnQJ+mVa7szevdEyvfItbO5Vo+GfZ4/GZWWDRRLjrxYPkhM+6zYB2vRYwCsoJLzqFCdZT4mEqyJoyzkunsZ96A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.44.1': + resolution: {integrity: sha512-DpX5Fp6edTlocMCwA+mHY8Mra+pPjRZ0TfHkXI8QFelIKcbADQz1LUPNtzOFUriBB2UYqw4Pi9+xV4w9ZczHFg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.44.1': + resolution: {integrity: sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-libc@2.1.1: + resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} + engines: {node: '>=8'} + + devalue@5.3.2: + resolution: {integrity: sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + esbuild@0.25.10: + resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@10.1.8: + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-svelte@3.12.4: + resolution: {integrity: sha512-hD7wPe+vrPgx3U2X2b/wyTMtWobm660PygMGKrWWYTc9lvtY8DpNFDaU2CJQn1szLjGbn/aJ3g8WiXuKakrEkw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.1 || ^9.0.0 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + svelte: + optional: true + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.36.0: + resolution: {integrity: sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrap@2.1.0: + resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.6.0: + resolution: {integrity: sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + known-css-properties@0.37.0: + resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss-load-config@3.1.4: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + + postcss-selector-parser@7.1.0: + resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} + engines: {node: '>=4'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-plugin-svelte@3.4.0: + resolution: {integrity: sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==} + peerDependencies: + prettier: ^3.0.0 + svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 + + prettier-plugin-tailwindcss@0.6.14: + resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==} + engines: {node: '>=14.21.3'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-hermes': '*' + '@prettier/plugin-oxc': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-import-sort: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-style-order: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-hermes': + optional: true + '@prettier/plugin-oxc': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-import-sort: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-style-order: + optional: true + prettier-plugin-svelte: + optional: true + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.52.2: + resolution: {integrity: sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + svelte-check@4.3.2: + resolution: {integrity: sha512-71udP5w2kaSTcX8iV0hn3o2FWlabQHhJTJLIQrCqMsrcOeDUO2VhCQKKCA8AMVHSPwdxLEWkUWh9OKxns5PD9w==} + engines: {node: '>= 18.0.0'} + hasBin: true + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: '>=5.0.0' + + svelte-eslint-parser@1.3.3: + resolution: {integrity: sha512-oTrDR8Z7Wnguut7QH3YKh7JR19xv1seB/bz4dxU5J/86eJtZOU4eh0/jZq4dy6tAlz/KROxnkRQspv5ZEt7t+Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + svelte: + optional: true + + svelte@5.39.6: + resolution: {integrity: sha512-bOJXmuwLNaoqPCTWO8mPu/fwxI5peGE5Efe7oo6Cakpz/G60vsnVF6mxbGODaxMUFUKEnjm6XOwHEqOht6cbvw==} + engines: {node: '>=18'} + + tailwindcss@4.1.13: + resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==} + + tapable@2.2.3: + resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + engines: {node: '>=6'} + + tar@7.5.1: + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.44.1: + resolution: {integrity: sha512-0ws8uWGrUVTjEeN2OM4K1pLKHK/4NiNP/vz6ns+LjT/6sqpaYzIVFajZb1fj/IDwpsrrHb3Jy0Qm5u9CPcKaeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@7.1.7: + resolution: {integrity: sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.1: + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zimmerframe@1.1.4: + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + +snapshots: + + '@esbuild/aix-ppc64@0.25.10': + optional: true + + '@esbuild/android-arm64@0.25.10': + optional: true + + '@esbuild/android-arm@0.25.10': + optional: true + + '@esbuild/android-x64@0.25.10': + optional: true + + '@esbuild/darwin-arm64@0.25.10': + optional: true + + '@esbuild/darwin-x64@0.25.10': + optional: true + + '@esbuild/freebsd-arm64@0.25.10': + optional: true + + '@esbuild/freebsd-x64@0.25.10': + optional: true + + '@esbuild/linux-arm64@0.25.10': + optional: true + + '@esbuild/linux-arm@0.25.10': + optional: true + + '@esbuild/linux-ia32@0.25.10': + optional: true + + '@esbuild/linux-loong64@0.25.10': + optional: true + + '@esbuild/linux-mips64el@0.25.10': + optional: true + + '@esbuild/linux-ppc64@0.25.10': + optional: true + + '@esbuild/linux-riscv64@0.25.10': + optional: true + + '@esbuild/linux-s390x@0.25.10': + optional: true + + '@esbuild/linux-x64@0.25.10': + optional: true + + '@esbuild/netbsd-arm64@0.25.10': + optional: true + + '@esbuild/netbsd-x64@0.25.10': + optional: true + + '@esbuild/openbsd-arm64@0.25.10': + optional: true + + '@esbuild/openbsd-x64@0.25.10': + optional: true + + '@esbuild/openharmony-arm64@0.25.10': + optional: true + + '@esbuild/sunos-x64@0.25.10': + optional: true + + '@esbuild/win32-arm64@0.25.10': + optional: true + + '@esbuild/win32-ia32@0.25.10': + optional: true + + '@esbuild/win32-x64@0.25.10': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.36.0(jiti@2.6.0))': + dependencies: + eslint: 9.36.0(jiti@2.6.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/compat@1.4.0(eslint@9.36.0(jiti@2.6.0))': + dependencies: + '@eslint/core': 0.16.0 + optionalDependencies: + eslint: 9.36.0(jiti@2.6.0) + + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.3.1': {} + + '@eslint/core@0.15.2': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/core@0.16.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.36.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.3.5': + dependencies: + '@eslint/core': 0.15.2 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@polka/url@1.0.0-next.29': {} + + '@rollup/rollup-android-arm-eabi@4.52.2': + optional: true + + '@rollup/rollup-android-arm64@4.52.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.52.2': + optional: true + + '@rollup/rollup-darwin-x64@4.52.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.52.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.52.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.52.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.52.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.52.2': + optional: true + + '@standard-schema/spec@1.0.0': {} + + '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)': + dependencies: + acorn: 8.15.0 + + '@sveltejs/adapter-auto@6.1.0(@sveltejs/kit@2.43.4(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))': + dependencies: + '@sveltejs/kit': 2.43.4(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + + '@sveltejs/kit@2.43.4(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1))': + dependencies: + '@standard-schema/spec': 1.0.0 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + '@types/cookie': 0.6.0 + acorn: 8.15.0 + cookie: 0.6.0 + devalue: 5.3.2 + esm-env: 1.2.2 + kleur: 4.1.5 + magic-string: 0.30.19 + mrmime: 2.0.1 + sade: 1.8.1 + set-cookie-parser: 2.7.1 + sirv: 3.0.2 + svelte: 5.39.6 + vite: 7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1) + + '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1))': + dependencies: + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + debug: 4.4.3 + svelte: 5.39.6 + vite: 7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)))(svelte@5.39.6)(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + debug: 4.4.3 + deepmerge: 4.3.1 + magic-string: 0.30.19 + svelte: 5.39.6 + vite: 7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1) + vitefu: 1.1.1(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)) + transitivePeerDependencies: + - supports-color + + '@tailwindcss/node@4.1.13': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.0 + lightningcss: 1.30.1 + magic-string: 0.30.19 + source-map-js: 1.2.1 + tailwindcss: 4.1.13 + + '@tailwindcss/oxide-android-arm64@4.1.13': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.13': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.13': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.13': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.13': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + optional: true + + '@tailwindcss/oxide@4.1.13': + dependencies: + detect-libc: 2.1.1 + tar: 7.5.1 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-x64': 4.1.13 + '@tailwindcss/oxide-freebsd-x64': 4.1.13 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.13 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-x64-musl': 4.1.13 + '@tailwindcss/oxide-wasm32-wasi': 4.1.13 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 + + '@tailwindcss/vite@4.1.13(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1))': + dependencies: + '@tailwindcss/node': 4.1.13 + '@tailwindcss/oxide': 4.1.13 + tailwindcss: 4.1.13 + vite: 7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1) + + '@types/cookie@0.6.0': {} + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@22.18.6': + dependencies: + undici-types: 6.21.0 + + '@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.44.1 + '@typescript-eslint/type-utils': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.1 + eslint: 9.36.0(jiti@2.6.0) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.44.1 + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.44.1 + debug: 4.4.3 + eslint: 9.36.0(jiti@2.6.0) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.44.1(typescript@5.9.2)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.44.1(typescript@5.9.2) + '@typescript-eslint/types': 8.44.1 + debug: 4.4.3 + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.44.1': + dependencies: + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/visitor-keys': 8.44.1 + + '@typescript-eslint/tsconfig-utils@8.44.1(typescript@5.9.2)': + dependencies: + typescript: 5.9.2 + + '@typescript-eslint/type-utils@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + dependencies: + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + debug: 4.4.3 + eslint: 9.36.0(jiti@2.6.0) + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.44.1': {} + + '@typescript-eslint/typescript-estree@8.44.1(typescript@5.9.2)': + dependencies: + '@typescript-eslint/project-service': 8.44.1(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.44.1(typescript@5.9.2) + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/visitor-keys': 8.44.1 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.6.0)) + '@typescript-eslint/scope-manager': 8.44.1 + '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) + eslint: 9.36.0(jiti@2.6.0) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.44.1': + dependencies: + '@typescript-eslint/types': 8.44.1 + eslint-visitor-keys: 4.2.1 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chownr@3.0.0: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + cookie@0.6.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + detect-libc@2.1.1: {} + + devalue@5.3.2: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.3 + + esbuild@0.25.10: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@10.1.8(eslint@9.36.0(jiti@2.6.0)): + dependencies: + eslint: 9.36.0(jiti@2.6.0) + + eslint-plugin-svelte@3.12.4(eslint@9.36.0(jiti@2.6.0))(svelte@5.39.6): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.6.0)) + '@jridgewell/sourcemap-codec': 1.5.5 + eslint: 9.36.0(jiti@2.6.0) + esutils: 2.0.3 + globals: 16.4.0 + known-css-properties: 0.37.0 + postcss: 8.5.6 + postcss-load-config: 3.1.4(postcss@8.5.6) + postcss-safe-parser: 7.0.1(postcss@8.5.6) + semver: 7.7.2 + svelte-eslint-parser: 1.3.3(svelte@5.39.6) + optionalDependencies: + svelte: 5.39.6 + transitivePeerDependencies: + - ts-node + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.36.0(jiti@2.6.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@2.6.0)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.3.1 + '@eslint/core': 0.15.2 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.36.0 + '@eslint/plugin-kit': 0.3.5 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.0 + transitivePeerDependencies: + - supports-color + + esm-env@1.2.2: {} + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrap@2.1.0: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + fsevents@2.3.3: + optional: true + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.4.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + isexe@2.0.0: {} + + jiti@2.6.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@4.1.5: {} + + known-css-properties@0.37.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.1.1 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + lilconfig@2.1.0: {} + + locate-character@3.0.0: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minipass@7.1.2: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.2 + + mri@1.2.0: {} + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + postcss-load-config@3.1.4(postcss@8.5.6): + dependencies: + lilconfig: 2.1.0 + yaml: 1.10.2 + optionalDependencies: + postcss: 8.5.6 + + postcss-safe-parser@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-scss@4.0.9(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-selector-parser@7.1.0: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.39.6): + dependencies: + prettier: 3.6.2 + svelte: 5.39.6 + + prettier-plugin-tailwindcss@0.6.14(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.39.6))(prettier@3.6.2): + dependencies: + prettier: 3.6.2 + optionalDependencies: + prettier-plugin-svelte: 3.4.0(prettier@3.6.2)(svelte@5.39.6) + + prettier@3.6.2: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + readdirp@4.1.2: {} + + resolve-from@4.0.0: {} + + reusify@1.1.0: {} + + rollup@4.52.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.2 + '@rollup/rollup-android-arm64': 4.52.2 + '@rollup/rollup-darwin-arm64': 4.52.2 + '@rollup/rollup-darwin-x64': 4.52.2 + '@rollup/rollup-freebsd-arm64': 4.52.2 + '@rollup/rollup-freebsd-x64': 4.52.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.2 + '@rollup/rollup-linux-arm-musleabihf': 4.52.2 + '@rollup/rollup-linux-arm64-gnu': 4.52.2 + '@rollup/rollup-linux-arm64-musl': 4.52.2 + '@rollup/rollup-linux-loong64-gnu': 4.52.2 + '@rollup/rollup-linux-ppc64-gnu': 4.52.2 + '@rollup/rollup-linux-riscv64-gnu': 4.52.2 + '@rollup/rollup-linux-riscv64-musl': 4.52.2 + '@rollup/rollup-linux-s390x-gnu': 4.52.2 + '@rollup/rollup-linux-x64-gnu': 4.52.2 + '@rollup/rollup-linux-x64-musl': 4.52.2 + '@rollup/rollup-openharmony-arm64': 4.52.2 + '@rollup/rollup-win32-arm64-msvc': 4.52.2 + '@rollup/rollup-win32-ia32-msvc': 4.52.2 + '@rollup/rollup-win32-x64-gnu': 4.52.2 + '@rollup/rollup-win32-x64-msvc': 4.52.2 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + semver@7.7.2: {} + + set-cookie-parser@2.7.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + + source-map-js@1.2.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + svelte-check@4.3.2(picomatch@4.0.3)(svelte@5.39.6)(typescript@5.9.2): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + chokidar: 4.0.3 + fdir: 6.5.0(picomatch@4.0.3) + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.39.6 + typescript: 5.9.2 + transitivePeerDependencies: + - picomatch + + svelte-eslint-parser@1.3.3(svelte@5.39.6): + dependencies: + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + postcss: 8.5.6 + postcss-scss: 4.0.9(postcss@8.5.6) + postcss-selector-parser: 7.1.0 + optionalDependencies: + svelte: 5.39.6 + + svelte@5.39.6: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) + '@types/estree': 1.0.8 + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + esm-env: 1.2.2 + esrap: 2.1.0 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.19 + zimmerframe: 1.1.4 + + tailwindcss@4.1.13: {} + + tapable@2.2.3: {} + + tar@7.5.1: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + totalist@3.0.1: {} + + ts-api-utils@2.1.0(typescript@5.9.2): + dependencies: + typescript: 5.9.2 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2): + dependencies: + '@typescript-eslint/eslint-plugin': 8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2) + eslint: 9.36.0(jiti@2.6.0) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + typescript@5.9.2: {} + + undici-types@6.21.0: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1): + dependencies: + esbuild: 0.25.10 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.52.2 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.18.6 + fsevents: 2.3.3 + jiti: 2.6.0 + lightningcss: 1.30.1 + + vitefu@1.1.1(vite@7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1)): + optionalDependencies: + vite: 7.1.7(@types/node@22.18.6)(jiti@2.6.0)(lightningcss@1.30.1) + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yallist@5.0.0: {} + + yaml@1.10.2: {} + + yocto-queue@0.1.0: {} + + zimmerframe@1.1.4: {} diff --git a/playground/src/app.css b/playground/src/app.css new file mode 100644 index 0000000..d4b5078 --- /dev/null +++ b/playground/src/app.css @@ -0,0 +1 @@ +@import 'tailwindcss'; diff --git a/playground/src/app.d.ts b/playground/src/app.d.ts new file mode 100644 index 0000000..5db8a6a --- /dev/null +++ b/playground/src/app.d.ts @@ -0,0 +1,22 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } + + export interface Window { + Go: { + new(): { + run: (inst: WebAssembly.Instance) => Promise; + importObject: WebAssembly.Imports; + }; + }; + } +} + +export { }; diff --git a/playground/src/app.html b/playground/src/app.html new file mode 100644 index 0000000..83c25bb --- /dev/null +++ b/playground/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/playground/src/lib/assets/favicon.svg b/playground/src/lib/assets/favicon.svg new file mode 100644 index 0000000..cc5dc66 --- /dev/null +++ b/playground/src/lib/assets/favicon.svg @@ -0,0 +1 @@ +svelte-logo \ No newline at end of file diff --git a/playground/src/lib/components/EditorPanel.svelte b/playground/src/lib/components/EditorPanel.svelte new file mode 100644 index 0000000..b736bf6 --- /dev/null +++ b/playground/src/lib/components/EditorPanel.svelte @@ -0,0 +1,35 @@ + + +
+
+

{title}

+
+
+ {#if readonly} +
+
{value}
+
+ {:else} + + {/if} + + +
+
+ + {#if children} + {@render children()} + {/if} +
diff --git a/playground/src/lib/components/Header.svelte b/playground/src/lib/components/Header.svelte new file mode 100644 index 0000000..d41a817 --- /dev/null +++ b/playground/src/lib/components/Header.svelte @@ -0,0 +1,26 @@ + + +
+
+
+
+
+ +
+
+

Marka

+

Bidirectional Markdown ↔ JSON Parser

+
+
+ +
+
+
diff --git a/playground/src/lib/components/Playground.svelte b/playground/src/lib/components/Playground.svelte new file mode 100644 index 0000000..47f1f64 --- /dev/null +++ b/playground/src/lib/components/Playground.svelte @@ -0,0 +1,84 @@ + + +
+ + + + + + {#snippet children()} +
+
+ Auto-generated JSON +
+
+ {/snippet} +
+
diff --git a/playground/src/lib/components/StatusBar.svelte b/playground/src/lib/components/StatusBar.svelte new file mode 100644 index 0000000..c73527e --- /dev/null +++ b/playground/src/lib/components/StatusBar.svelte @@ -0,0 +1,25 @@ + + +
+
+
+ {#if status === 'success'} + + {message} + {:else if status === 'error'} + + {message} + {:else} +
+ Ready + {/if} +
+ +
Schema.org validation enabled
+
+
diff --git a/playground/src/lib/index.ts b/playground/src/lib/index.ts new file mode 100644 index 0000000..856f2b6 --- /dev/null +++ b/playground/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/playground/src/routes/+layout.svelte b/playground/src/routes/+layout.svelte new file mode 100644 index 0000000..8c56a3c --- /dev/null +++ b/playground/src/routes/+layout.svelte @@ -0,0 +1,12 @@ + + + + + + +{@render children?.()} diff --git a/playground/src/routes/+page.svelte b/playground/src/routes/+page.svelte new file mode 100644 index 0000000..21aaa30 --- /dev/null +++ b/playground/src/routes/+page.svelte @@ -0,0 +1,33 @@ + + +
+
+ + +
+ + diff --git a/playground/src/routes/+page.svelte2 b/playground/src/routes/+page.svelte2 new file mode 100644 index 0000000..b469209 --- /dev/null +++ b/playground/src/routes/+page.svelte2 @@ -0,0 +1,47 @@ + + + + diff --git a/playground/static/main.wasm b/playground/static/main.wasm new file mode 100644 index 0000000000000000000000000000000000000000..4b52302f2ed61502c9d5d531c71adb68d1a9c588 GIT binary patch literal 486216 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/j5?au{`$tT5a!DYPDszuPsL0ttVF7T`U-~ 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 z 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