Add docs and move stuff to internal
This commit is contained in:
parent
fd2a376387
commit
289d4d647d
26 changed files with 78 additions and 125 deletions
|
@ -20,6 +20,7 @@ lustre_ssg = "~> 0.5.0"
|
||||||
gleam_javascript = "~> 0.8"
|
gleam_javascript = "~> 0.8"
|
||||||
ranged_int = "~> 2.0"
|
ranged_int = "~> 2.0"
|
||||||
bigi = "~> 3.0"
|
bigi = "~> 3.0"
|
||||||
|
simplifile = "~> 1.7"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
gleeunit = "~> 1.0"
|
gleeunit = "~> 1.0"
|
||||||
|
|
|
@ -27,3 +27,4 @@ gleeunit = { version = "~> 1.0" }
|
||||||
lustre = { version = "~> 4.1" }
|
lustre = { version = "~> 4.1" }
|
||||||
lustre_ssg = { version = "~> 0.5.0" }
|
lustre_ssg = { version = "~> 0.5.0" }
|
||||||
ranged_int = { version = "~> 2.0" }
|
ranged_int = { version = "~> 2.0" }
|
||||||
|
simplifile = { version = "~> 1.7"}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export function to_string(buffer) {
|
|
||||||
return buffer.toString("utf8");
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { Ok, Error } from "./gleam.mjs";
|
|
||||||
|
|
||||||
export function resultify(callback) {
|
|
||||||
try {
|
|
||||||
return new Ok(callback());
|
|
||||||
} catch (err) {
|
|
||||||
return new Error(err);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
import { mkdirSync } from "node:fs";
|
|
||||||
|
|
||||||
export function mkdirP(path) {
|
|
||||||
return mkdirSync(path, { recursive: true });
|
|
||||||
}
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
//// The builder contains convenience functions to interface with the different
|
||||||
|
//// parts of gloss, using the configuration to control what is done.
|
||||||
|
|
||||||
import gleam/result
|
import gleam/result
|
||||||
import gloss/parser
|
import gloss/parser
|
||||||
import gloss/rendering/database as render_database
|
import gloss/rendering/database as render_database
|
||||||
|
@ -5,24 +8,29 @@ import gloss/config.{type Configuration}
|
||||||
import gloss/models/database.{type Database}
|
import gloss/models/database.{type Database}
|
||||||
import gloss/compiler.{type CompileDatabase}
|
import gloss/compiler.{type CompileDatabase}
|
||||||
|
|
||||||
|
/// Something failed when building the blog.
|
||||||
pub type BuildError {
|
pub type BuildError {
|
||||||
ParseError(err: parser.ParseError)
|
ParseError(err: parser.ParseError)
|
||||||
WriteError(err: config.WriteError)
|
WriteError(err: config.WriteError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the blog's input files.
|
||||||
pub fn parse(config: Configuration) {
|
pub fn parse(config: Configuration) {
|
||||||
config.parser()
|
config.parser()
|
||||||
|> result.map_error(ParseError)
|
|> result.map_error(ParseError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compile the post and page content into HTML strings.
|
||||||
pub fn compile(db: Database, config: Configuration) {
|
pub fn compile(db: Database, config: Configuration) {
|
||||||
config.compiling.database_compiler(db, config.compiling.item_compiler)
|
config.compiling.database_compiler(db, config.compiling.item_compiler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Render the content into HTML pages.
|
||||||
pub fn render(db: Database, compiled: CompileDatabase, config: Configuration) {
|
pub fn render(db: Database, compiled: CompileDatabase, config: Configuration) {
|
||||||
config.rendering.renderer(db, compiled, config)
|
config.rendering.renderer(db, compiled, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the render database into files.
|
||||||
pub fn write(posts: render_database.RenderDatabase, config: Configuration) {
|
pub fn write(posts: render_database.RenderDatabase, config: Configuration) {
|
||||||
config.writer(posts, config)
|
config.writer(posts, config)
|
||||||
|> result.map_error(WriteError)
|
|> result.map_error(WriteError)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
//// Compiling means turning post and page content into HTML. By default this
|
||||||
|
//// content is Markdown that is compiled with Marked.js.
|
||||||
|
|
||||||
import gleam/option
|
import gleam/option
|
||||||
import gleam/dict.{type Dict}
|
import gleam/dict.{type Dict}
|
||||||
import gleam/list
|
import gleam/list
|
||||||
|
@ -7,29 +10,36 @@ import gloss/models/page.{type Page}
|
||||||
import gloss/models/database.{type Database, type PostID}
|
import gloss/models/database.{type Database, type PostID}
|
||||||
import gloss/utils/marked
|
import gloss/utils/marked
|
||||||
|
|
||||||
|
/// Compiled post content: strings that contain HTML.
|
||||||
pub type PostContent {
|
pub type PostContent {
|
||||||
PostContent(full: String, short: option.Option(String))
|
PostContent(full: String, short: option.Option(String))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A post and its compiled content.
|
||||||
pub type CompiledPost {
|
pub type CompiledPost {
|
||||||
CompiledPost(orig: Post, content: PostContent)
|
CompiledPost(orig: Post, content: PostContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A page and its compiled content.
|
||||||
pub type CompiledPage {
|
pub type CompiledPage {
|
||||||
CompiledPage(orig: Page, content: String)
|
CompiledPage(orig: Page, content: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A function to compile the given string content into an HTML string.
|
||||||
pub type Compiler =
|
pub type Compiler =
|
||||||
fn(String, Database) -> String
|
fn(String, Database) -> String
|
||||||
|
|
||||||
|
/// Structure where the compilation results are stored.
|
||||||
pub type CompileDatabase {
|
pub type CompileDatabase {
|
||||||
CompileDatabase(posts: Dict(PostID, CompiledPost), pages: List(CompiledPage))
|
CompileDatabase(posts: Dict(PostID, CompiledPost), pages: List(CompiledPage))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The default compiler that uses Marked.js with default settings.
|
||||||
pub fn default_compiler(content: String, _db: Database) {
|
pub fn default_compiler(content: String, _db: Database) {
|
||||||
marked.default_parse(content)
|
marked.default_parse(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compile contents of the database using the given compiler.
|
||||||
pub fn compile(db: Database, compiler: Compiler) {
|
pub fn compile(db: Database, compiler: Compiler) {
|
||||||
CompileDatabase(
|
CompileDatabase(
|
||||||
posts: compile_posts(db, compiler),
|
posts: compile_posts(db, compiler),
|
||||||
|
@ -37,6 +47,7 @@ pub fn compile(db: Database, compiler: Compiler) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compile all posts in the database using the given compiler.
|
||||||
pub fn compile_posts(
|
pub fn compile_posts(
|
||||||
db: Database,
|
db: Database,
|
||||||
compiler: Compiler,
|
compiler: Compiler,
|
||||||
|
@ -59,6 +70,7 @@ pub fn compile_posts(
|
||||||
dict.from_list(posts)
|
dict.from_list(posts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compile all pages in the database using the given compiler.
|
||||||
pub fn compile_pages(db: Database, compiler: Compiler) {
|
pub fn compile_pages(db: Database, compiler: Compiler) {
|
||||||
database.pages(db)
|
database.pages(db)
|
||||||
|> list.map(fn(page) {
|
|> list.map(fn(page) {
|
||||||
|
|
2
src/gloss/internal/utils/meta_url.gleam
Normal file
2
src/gloss/internal/utils/meta_url.gleam
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
@external(javascript, "../../../ffi_meta_url.mjs", "metaURL")
|
||||||
|
pub fn get() -> String
|
|
@ -1,10 +1,10 @@
|
||||||
pub type Object
|
pub type Object
|
||||||
|
|
||||||
@external(javascript, "../../ffi_object.mjs", "create")
|
@external(javascript, "../../../ffi_object.mjs", "create")
|
||||||
pub fn new() -> Object
|
pub fn new() -> Object
|
||||||
|
|
||||||
@external(javascript, "../../ffi_object.mjs", "set")
|
@external(javascript, "../../../ffi_object.mjs", "set")
|
||||||
pub fn set(object object: Object, prop prop: String, value value: a) -> Object
|
pub fn set(object object: Object, prop prop: String, value value: a) -> Object
|
||||||
|
|
||||||
@external(javascript, "../../ffi_object.mjs", "get")
|
@external(javascript, "../../../ffi_object.mjs", "get")
|
||||||
pub fn get(object object: Object, prop prop: String) -> b
|
pub fn get(object object: Object, prop prop: String) -> b
|
|
@ -2,7 +2,7 @@ import gleam/result
|
||||||
import gleam/list
|
import gleam/list
|
||||||
import gleam/regex
|
import gleam/regex
|
||||||
import gleam/string
|
import gleam/string
|
||||||
import gloss/utils/fs
|
import simplifile
|
||||||
import gloss/models/database.{type Database}
|
import gloss/models/database.{type Database}
|
||||||
import gloss/parser/common
|
import gloss/parser/common
|
||||||
import gloss/parser/post
|
import gloss/parser/post
|
||||||
|
@ -15,7 +15,7 @@ pub type Parser =
|
||||||
fn() -> Result(Database, ParseError)
|
fn() -> Result(Database, ParseError)
|
||||||
|
|
||||||
pub type ParseError {
|
pub type ParseError {
|
||||||
FileError(path: String, err: fs.FSError)
|
FileError(path: String, err: simplifile.FileError)
|
||||||
PostParseError(filename: String, err: common.ParseError)
|
PostParseError(filename: String, err: common.ParseError)
|
||||||
MenuParseError
|
MenuParseError
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ pub fn default_parse() -> Result(Database, ParseError) {
|
||||||
|
|
||||||
pub fn parse_posts(db: Database, path: String) -> Result(Database, ParseError) {
|
pub fn parse_posts(db: Database, path: String) -> Result(Database, ParseError) {
|
||||||
use filenames <- result.try(
|
use filenames <- result.try(
|
||||||
fs.readdir(path)
|
simplifile.read_directory(path)
|
||||||
|> result.map_error(fn(err) { FileError(path, err) }),
|
|> result.map_error(fn(err) { FileError(path, err) }),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ pub fn parse_posts(db: Database, path: String) -> Result(Database, ParseError) {
|
||||||
result.all(
|
result.all(
|
||||||
list.map(filenames, fn(file) {
|
list.map(filenames, fn(file) {
|
||||||
use contents <- result.try(
|
use contents <- result.try(
|
||||||
fs.read_file(path <> "/" <> file)
|
simplifile.read(path <> "/" <> file)
|
||||||
|> result.map_error(fn(err) { FileError(file, err) }),
|
|> result.map_error(fn(err) { FileError(file, err) }),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ pub fn parse_posts(db: Database, path: String) -> Result(Database, ParseError) {
|
||||||
|
|
||||||
pub fn parse_pages(db: Database, path: String) -> Result(Database, ParseError) {
|
pub fn parse_pages(db: Database, path: String) -> Result(Database, ParseError) {
|
||||||
use filenames <- result.try(
|
use filenames <- result.try(
|
||||||
fs.readdir(path)
|
simplifile.read_directory(path)
|
||||||
|> result.map_error(fn(err) { FileError(path, err) }),
|
|> result.map_error(fn(err) { FileError(path, err) }),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ pub fn parse_pages(db: Database, path: String) -> Result(Database, ParseError) {
|
||||||
})
|
})
|
||||||
|> list.map(fn(file) {
|
|> list.map(fn(file) {
|
||||||
use contents <- result.try(
|
use contents <- result.try(
|
||||||
fs.read_file(path <> "/" <> file)
|
simplifile.read(path <> "/" <> file)
|
||||||
|> result.map_error(fn(err) { FileError(file, err) }),
|
|> result.map_error(fn(err) { FileError(file, err) }),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -87,10 +87,10 @@ pub fn parse_pages(db: Database, path: String) -> Result(Database, ParseError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_menu(db: Database, file: String) -> Result(Database, ParseError) {
|
pub fn parse_menu(db: Database, file: String) -> Result(Database, ParseError) {
|
||||||
case fs.exists(file) {
|
case simplifile.verify_is_file(file) {
|
||||||
Ok(True) -> {
|
Ok(True) -> {
|
||||||
use contents <- result.try(
|
use contents <- result.try(
|
||||||
fs.read_file(file)
|
simplifile.read(file)
|
||||||
|> result.map_error(fn(err) { FileError(file, err) }),
|
|> result.map_error(fn(err) { FileError(file, err) }),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
pub type Buffer
|
|
||||||
|
|
||||||
@external(javascript, "../../ffi_buffer.mjs", "to_string")
|
|
||||||
pub fn to_string(buf buf: Buffer) -> String
|
|
|
@ -19,14 +19,15 @@ pub type Month {
|
||||||
Dec
|
Dec
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All months in order
|
/// All months in order.
|
||||||
pub const months = [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
|
pub const months = [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
|
||||||
|
|
||||||
/// A date with 1-indexed years and days
|
/// A date with 1-indexed years and days.
|
||||||
pub type Date {
|
pub type Date {
|
||||||
Date(year: Int, month: Month, day: Day)
|
Date(year: Int, month: Month, day: Day)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an integer into a month.
|
||||||
pub fn parse_month(month_int: Int) -> Result(Month, Nil) {
|
pub fn parse_month(month_int: Int) -> Result(Month, Nil) {
|
||||||
case month_int {
|
case month_int {
|
||||||
1 -> Ok(Jan)
|
1 -> Ok(Jan)
|
||||||
|
@ -45,6 +46,7 @@ pub fn parse_month(month_int: Int) -> Result(Month, Nil) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the number of days in a month in a given year.
|
||||||
pub fn days_in_month(month: Month, year: Int) {
|
pub fn days_in_month(month: Month, year: Int) {
|
||||||
case month {
|
case month {
|
||||||
Jan -> 31
|
Jan -> 31
|
||||||
|
@ -77,6 +79,7 @@ pub fn days_in_month(month: Month, year: Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a given date is valid.
|
||||||
pub fn is_valid_date(date: Date) -> Bool {
|
pub fn is_valid_date(date: Date) -> Bool {
|
||||||
let day = day.to_int(date.day)
|
let day = day.to_int(date.day)
|
||||||
use <- bool.guard(day < 1, False)
|
use <- bool.guard(day < 1, False)
|
||||||
|
@ -97,6 +100,7 @@ pub fn compare(a: Date, b: Date) -> Order {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a month to a 1-indexed int.
|
||||||
pub fn month_to_int(month: Month) -> Int {
|
pub fn month_to_int(month: Month) -> Int {
|
||||||
case month {
|
case month {
|
||||||
Jan -> 1
|
Jan -> 1
|
||||||
|
@ -114,6 +118,7 @@ pub fn month_to_int(month: Month) -> Int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a month to an English month name string.
|
||||||
pub fn month_to_string(month: Month) -> String {
|
pub fn month_to_string(month: Month) -> String {
|
||||||
case month {
|
case month {
|
||||||
Jan -> "January"
|
Jan -> "January"
|
||||||
|
@ -131,6 +136,7 @@ pub fn month_to_string(month: Month) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format a date in the format "2 Aug 2024".
|
||||||
pub fn format(date: Date) -> String {
|
pub fn format(date: Date) -> String {
|
||||||
int.to_string(day.to_int(date.day))
|
int.to_string(day.to_int(date.day))
|
||||||
<> " "
|
<> " "
|
||||||
|
@ -139,6 +145,7 @@ pub fn format(date: Date) -> String {
|
||||||
<> int.to_string(date.year)
|
<> int.to_string(date.year)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format a date in the ISO 8601 format.
|
||||||
pub fn format_iso(date: Date) -> String {
|
pub fn format_iso(date: Date) -> String {
|
||||||
int.to_string(date.year)
|
int.to_string(date.year)
|
||||||
<> "-"
|
<> "-"
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
/// A result (of type a) from an external function that can also raise an error
|
|
||||||
/// (of type b).
|
|
||||||
pub type CanRaise(a, b) {
|
|
||||||
CanRaise(value: a, error: b)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert a callback function (that should call an external function) from one
|
|
||||||
/// that can raise to one that will return a Result.
|
|
||||||
@external(javascript, "../../ffi_exceptions.mjs", "resultify")
|
|
||||||
pub fn resultify(callback callback: fn() -> CanRaise(a, b)) -> Result(a, b)
|
|
|
@ -1,63 +0,0 @@
|
||||||
import gleam/result
|
|
||||||
import gleam/list
|
|
||||||
import gleam/javascript/array.{type Array}
|
|
||||||
import gloss/utils/buffer.{type Buffer}
|
|
||||||
import gloss/utils/exceptions.{type CanRaise}
|
|
||||||
|
|
||||||
pub type FSError
|
|
||||||
|
|
||||||
pub fn read_file(path: String) -> Result(String, FSError) {
|
|
||||||
use contents <- result.try(exceptions.resultify(fn() { do_read_file(path) }))
|
|
||||||
|
|
||||||
Ok(buffer.to_string(contents))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn readdir(path: String) -> Result(List(String), FSError) {
|
|
||||||
use files <- result.try(exceptions.resultify(fn() { do_readdir(path) }))
|
|
||||||
|
|
||||||
Ok(list.map(array.to_list(files), buffer.to_string))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mkdir(path: String) -> Result(Nil, FSError) {
|
|
||||||
use _undefined <- result.try(exceptions.resultify(fn() { do_mkdir(path) }))
|
|
||||||
|
|
||||||
Ok(Nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mkdir_p(path: String) -> Result(String, FSError) {
|
|
||||||
use created <- result.try(exceptions.resultify(fn() { do_mkdir_p(path) }))
|
|
||||||
|
|
||||||
Ok(created)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exists(path: String) -> Result(Bool, FSError) {
|
|
||||||
use created <- result.try(exceptions.resultify(fn() { do_exists(path) }))
|
|
||||||
|
|
||||||
Ok(created)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_file(path: String, data: String) -> Result(Nil, FSError) {
|
|
||||||
use _undefined <- result.try(
|
|
||||||
exceptions.resultify(fn() { do_write_file(path, data) }),
|
|
||||||
)
|
|
||||||
|
|
||||||
Ok(Nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
@external(javascript, "fs", "readFileSync")
|
|
||||||
fn do_read_file(path: String) -> CanRaise(Buffer, FSError)
|
|
||||||
|
|
||||||
@external(javascript, "fs", "readdirSync")
|
|
||||||
fn do_readdir(path: String) -> CanRaise(Array(Buffer), FSError)
|
|
||||||
|
|
||||||
@external(javascript, "fs", "mkdirSync")
|
|
||||||
fn do_mkdir(path: String) -> CanRaise(Nil, FSError)
|
|
||||||
|
|
||||||
@external(javascript, "../../ffi_fs.mjs", "mkdirP")
|
|
||||||
fn do_mkdir_p(path: String) -> CanRaise(String, FSError)
|
|
||||||
|
|
||||||
@external(javascript, "fs", "existsSync")
|
|
||||||
fn do_exists(path: String) -> CanRaise(Bool, FSError)
|
|
||||||
|
|
||||||
@external(javascript, "fs", "writeFileSync")
|
|
||||||
fn do_write_file(path: String, data: String) -> CanRaise(Nil, FSError)
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//// A day is a ranged integer from 1 to 31.
|
||||||
|
|
||||||
import bigi.{type BigInt}
|
import bigi.{type BigInt}
|
||||||
import ranged_int/interface.{type Interface, Interface}
|
import ranged_int/interface.{type Interface, Interface}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//// An hour is a ranged integer from 0 to 23.
|
||||||
|
|
||||||
import bigi.{type BigInt}
|
import bigi.{type BigInt}
|
||||||
import ranged_int/interface.{type Interface, Interface}
|
import ranged_int/interface.{type Interface, Interface}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//// A minute is a ranged integer from 0 to 59.
|
||||||
|
|
||||||
import bigi.{type BigInt}
|
import bigi.{type BigInt}
|
||||||
import ranged_int/interface.{type Interface, Interface}
|
import ranged_int/interface.{type Interface, Interface}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
|
//// Bindings to the Luxon library.
|
||||||
|
|
||||||
import gloss/utils/date.{type Date}
|
import gloss/utils/date.{type Date}
|
||||||
import gloss/utils/time.{type Time}
|
import gloss/utils/time.{type Time}
|
||||||
|
|
||||||
|
/// Luxon DateTime.
|
||||||
pub type DateTime
|
pub type DateTime
|
||||||
|
|
||||||
|
/// Get a Luxon DateTime in the given timezone.
|
||||||
pub fn date_time_in_zone(date: Date, time: Time, tz: String) {
|
pub fn date_time_in_zone(date: Date, time: Time, tz: String) {
|
||||||
let datetime_str = date.format_iso(date) <> "T" <> time.format(time)
|
let datetime_str = date.format_iso(date) <> "T" <> time.format(time)
|
||||||
do_date_time_in_zone(datetime_str, tz)
|
do_date_time_in_zone(datetime_str, tz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the current time as UTC.
|
||||||
@external(javascript, "../../ffi_luxon.mjs", "utcNow")
|
@external(javascript, "../../ffi_luxon.mjs", "utcNow")
|
||||||
pub fn utc_now() -> DateTime
|
pub fn utc_now() -> DateTime
|
||||||
|
|
||||||
|
@ -17,8 +22,6 @@ fn do_date_time_in_zone(
|
||||||
tz: String,
|
tz: String,
|
||||||
) -> Result(DateTime, Nil)
|
) -> Result(DateTime, Nil)
|
||||||
|
|
||||||
@external(javascript, "../../ffi_luxon.mjs", "toRFC2822")
|
/// Format the DateTime as an ISO 8601 format string.
|
||||||
pub fn to_rfc_2822(dt: DateTime) -> String
|
|
||||||
|
|
||||||
@external(javascript, "../../ffi_luxon.mjs", "toISO")
|
@external(javascript, "../../ffi_luxon.mjs", "toISO")
|
||||||
pub fn to_iso(dt: DateTime) -> String
|
pub fn to_iso(dt: DateTime) -> String
|
||||||
|
|
|
@ -1,24 +1,32 @@
|
||||||
import gloss/utils/object.{type Object}
|
//// Bindings to the marked.js library.
|
||||||
|
|
||||||
|
import gloss/internal/utils/object.{type Object}
|
||||||
|
|
||||||
|
/// Marked.js options object.
|
||||||
pub type Options =
|
pub type Options =
|
||||||
Object
|
Object
|
||||||
|
|
||||||
|
/// Create a new options object.
|
||||||
pub fn new_options() -> Options {
|
pub fn new_options() -> Options {
|
||||||
object.new()
|
object.new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the `mangle` option on or off.
|
||||||
pub fn set_mangle(options: Options, do_mangle: Bool) -> Options {
|
pub fn set_mangle(options: Options, do_mangle: Bool) -> Options {
|
||||||
object.set(options, "mangle", do_mangle)
|
object.set(options, "mangle", do_mangle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the `headerIds` option on or off.
|
||||||
pub fn set_header_ids(options: Options, ids: Bool) -> Options {
|
pub fn set_header_ids(options: Options, ids: Bool) -> Options {
|
||||||
object.set(options, "headerIds", ids)
|
object.set(options, "headerIds", ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the `headerPrefix` option.
|
||||||
pub fn set_header_prefix(options: Options, prefix: String) -> Options {
|
pub fn set_header_prefix(options: Options, prefix: String) -> Options {
|
||||||
object.set(options, "headerPrefix", prefix)
|
object.set(options, "headerPrefix", prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a string containing Markdown using the default options.
|
||||||
pub fn default_parse(content: String) -> String {
|
pub fn default_parse(content: String) -> String {
|
||||||
let options =
|
let options =
|
||||||
new_options()
|
new_options()
|
||||||
|
@ -29,5 +37,6 @@ pub fn default_parse(content: String) -> String {
|
||||||
parse(content, options)
|
parse(content, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a string containing Markdown using Marked.js.
|
||||||
@external(javascript, "../../priv/vendor/marked.esm.mjs", "parse")
|
@external(javascript, "../../priv/vendor/marked.esm.mjs", "parse")
|
||||||
pub fn parse(content content: String, options options: Options) -> String
|
pub fn parse(content content: String, options options: Options) -> String
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
@external(javascript, "../../ffi_meta_url.mjs", "metaURL")
|
|
||||||
pub fn get() -> String
|
|
|
@ -1,7 +1,8 @@
|
||||||
import gleam/uri
|
import gleam/uri
|
||||||
import gloss/utils/meta_url
|
import gloss/internal/utils/meta_url
|
||||||
import gloss/utils/path
|
import gloss/internal/utils/path
|
||||||
|
|
||||||
|
/// Get the path to the `priv` directory of `gloss`.
|
||||||
pub fn path() -> String {
|
pub fn path() -> String {
|
||||||
let assert Ok(meta_url) = uri.parse(meta_url.get())
|
let assert Ok(meta_url) = uri.parse(meta_url.get())
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import gleam/string
|
|
||||||
|
|
||||||
/// Split the given string at the given index
|
|
||||||
pub fn split_at(str: String, index: Int) -> #(String, String) {
|
|
||||||
let len = string.length(str)
|
|
||||||
let first = string.slice(str, 0, index)
|
|
||||||
let rest = string.slice(str, index, len - index)
|
|
||||||
#(first, rest)
|
|
||||||
}
|
|
|
@ -16,6 +16,7 @@ pub fn compare(a: Time, b: Time) -> Order {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a time from an `hh:mm` format string.
|
||||||
pub fn parse(str: String) {
|
pub fn parse(str: String) {
|
||||||
case string.split(str, ":") {
|
case string.split(str, ":") {
|
||||||
[hours, minutes] ->
|
[hours, minutes] ->
|
||||||
|
@ -31,12 +32,14 @@ pub fn parse(str: String) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format a time to an `hh:mm` format string.
|
||||||
pub fn format(time: Time) -> String {
|
pub fn format(time: Time) -> String {
|
||||||
pad(int.to_string(hour.to_int(time.hours)))
|
pad(int.to_string(hour.to_int(time.hours)))
|
||||||
<> ":"
|
<> ":"
|
||||||
<> pad(int.to_string(minute.to_int(time.minutes)))
|
<> pad(int.to_string(minute.to_int(time.minutes)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a time at hour 0 and minute 0.
|
||||||
pub fn nil_time() {
|
pub fn nil_time() {
|
||||||
let assert Ok(h) = hour.from_int(0)
|
let assert Ok(h) = hour.from_int(0)
|
||||||
let assert Ok(m) = minute.from_int(0)
|
let assert Ok(m) = minute.from_int(0)
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
import bigi.{type BigInt}
|
import bigi.{type BigInt}
|
||||||
|
|
||||||
|
/// A unique ID.
|
||||||
pub type UniqID =
|
pub type UniqID =
|
||||||
BigInt
|
BigInt
|
||||||
|
|
||||||
|
/// Unique ID generator.
|
||||||
pub opaque type Generator {
|
pub opaque type Generator {
|
||||||
Generator(id: BigInt)
|
Generator(id: BigInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a new generator.
|
||||||
pub fn new() -> Generator {
|
pub fn new() -> Generator {
|
||||||
Generator(bigi.zero())
|
Generator(bigi.zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a unique ID and a new generator, that can be used to generate a new ID.
|
||||||
pub fn get(gen: Generator) -> #(UniqID, Generator) {
|
pub fn get(gen: Generator) -> #(UniqID, Generator) {
|
||||||
let new = bigi.add(gen.id, bigi.from_int(1))
|
let new = bigi.add(gen.id, bigi.from_int(1))
|
||||||
#(new, Generator(new))
|
#(new, Generator(new))
|
||||||
|
|
|
@ -7,11 +7,12 @@ import lustre/ssg/xml
|
||||||
import lustre/element
|
import lustre/element
|
||||||
import gloss/rendering/database.{type RenderDatabase} as _
|
import gloss/rendering/database.{type RenderDatabase} as _
|
||||||
import gloss/config.{type Configuration, WriteError}
|
import gloss/config.{type Configuration, WriteError}
|
||||||
|
import gloss/utils/priv
|
||||||
|
|
||||||
pub fn write(db: RenderDatabase, config: Configuration) {
|
pub fn write(db: RenderDatabase, config: Configuration) {
|
||||||
let site =
|
let site =
|
||||||
ssg.new(config.output_path)
|
ssg.new(config.output_path)
|
||||||
|> ssg.add_static_dir("./build/dev/javascript/gloss/priv/assets")
|
|> ssg.add_static_dir(priv.path() <> "/assets")
|
||||||
|
|
||||||
let single_posts =
|
let single_posts =
|
||||||
db.single_posts
|
db.single_posts
|
||||||
|
|
Loading…
Reference in a new issue