mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-16 04:44:49 -07:00
kibo: part 1
This commit is contained in:
88
Cargo.lock
generated
88
Cargo.lock
generated
@@ -639,9 +639,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.16"
|
version = "1.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1789,9 +1789,9 @@ checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc"
|
name = "oxc"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e398ac9650c77d6a43e7f5ed5315c3cae33fd1f84666acd0a55719c8da1555b3"
|
checksum = "d6f2d8bbd880aaaf838456ce101c59d926a762b6a891ef91402794e9dc8d2c2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1832,9 +1832,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_allocator"
|
name = "oxc_allocator"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "36dd2ba553043fd1cf1f92fb4d685a9a58afcc4f2692e85ebf84e242e6492909"
|
checksum = "fe07aea78e1e1a860d92cfe1b712f81ba10960dee847c6231fa4e9b0665ec5ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
@@ -1846,9 +1846,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_ast"
|
name = "oxc_ast"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd0607fb00e5f2413b5a99b36eff638b7db57e69149e98ac693d2aaa500d1d26"
|
checksum = "062ec80f1ed9471bc05f57bd481bd4921285373b57018f3028aed49cb3ac353f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cow-utils",
|
"cow-utils",
|
||||||
@@ -1863,9 +1863,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_ast_macros"
|
name = "oxc_ast_macros"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf0d4b6faf22509c64f78d4a0a0bb760f6ba34fe7acdcb421b57fdc32482867e"
|
checksum = "41e79130c01eaddff0274d504404f80d88835ed70fcc1e91f9c9fd42fd718202"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1874,9 +1874,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_ast_visit"
|
name = "oxc_ast_visit"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "421e72f280ed323f63ad7ca5e4700577ca51f7946fdc9868baeb7e23eeb1c6b1"
|
checksum = "1c0476717291544c614de9ffc1c34c29b06025008c2e604505e67248234725ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast",
|
"oxc_ast",
|
||||||
@@ -1886,9 +1886,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_cfg"
|
name = "oxc_cfg"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c213a97298278d4f9a7e3a4e6bce0c5eba416aed5b291a6296bbb8c26ca1e65"
|
checksum = "243535bf553c8d399f20a392eabb6eff5990818eac8519a930a1c345497a8ea7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"itertools",
|
"itertools",
|
||||||
@@ -1901,9 +1901,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_codegen"
|
name = "oxc_codegen"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a61b0ca6f9d8e9fb6a5a5390ecae8bbd98283cfb38d24ce77979b77ab28fc65"
|
checksum = "4ebcbed8d477c4b9142c895a762be0afd16bd0838f64237e2c006fd9f8ec7e1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cow-utils",
|
"cow-utils",
|
||||||
@@ -1922,15 +1922,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_data_structures"
|
name = "oxc_data_structures"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a47c43341de573281bc1883b4cdb36dd9c8c11e56a7d6fda0b8335471add52d2"
|
checksum = "e4c79e0d91ca11d4add13d94f802096564babb2c609956a8e19eb6f83b7f0fb1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_diagnostics"
|
name = "oxc_diagnostics"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f5ce8bc7ebc0fa2c2bd94d526a92636e8622f879a9dd9a41b6c77c12a2b2408"
|
checksum = "b127d339db14984b22bf4255a2583c1be2cd709b1b14f64e3ce4cb5fe87c699d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cow-utils",
|
"cow-utils",
|
||||||
"oxc-miette",
|
"oxc-miette",
|
||||||
@@ -1938,9 +1938,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_ecmascript"
|
name = "oxc_ecmascript"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ce89c6c2764fa6ad1f929a91e09614943fe7a25df1d288d38acae0302581b8f"
|
checksum = "522b7c4d6db500536be627e1d3952cf26705328e77a4d819a2543c2392b702eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cow-utils",
|
"cow-utils",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
@@ -1952,9 +1952,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_estree"
|
name = "oxc_estree"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a4f605c6f6460d2cb659bb1c2273244ebf8c07bae4155274fa2461d7e0ec35"
|
checksum = "7190d1db8c149324345b14588f24a318712498fde1741513c3a129731ef6b4f9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_index"
|
name = "oxc_index"
|
||||||
@@ -1964,9 +1964,9 @@ checksum = "2fa07b0cfa997730afed43705766ef27792873fdf5215b1391949fec678d2392"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_mangler"
|
name = "oxc_mangler"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73d8be639f09e7c62e4503a5cbe3a802d78265c490b09ebaa1fb905d5b9d8bb0"
|
checksum = "cddde40dd8422c56c07eecd370d5c221626afb5cb5966824c1884a8b929305cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
"itertools",
|
"itertools",
|
||||||
@@ -1981,9 +1981,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_minifier"
|
name = "oxc_minifier"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea781d79be82fd4e1cd94fe6a6da4517edf075cc604d52f9785a0153157736d8"
|
checksum = "513dd618e9016cb00cc52e547bcbdb160a0379025206f8cce14287c1c624b57a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cow-utils",
|
"cow-utils",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -2003,9 +2003,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_parser"
|
name = "oxc_parser"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b633fe51f19c4da6f3cd6fd0885e3a9e12f19317487a477fea0f73892713083"
|
checksum = "afda2c4a47704ff4c68990248be9f693f606626cff1c6d1760034638b54c5413"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cow-utils",
|
"cow-utils",
|
||||||
@@ -2026,9 +2026,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_regular_expression"
|
name = "oxc_regular_expression"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b35b1a9babb738e4d99cfc0ef8ad242806d261de028b400a3205afdf7a9a1c03"
|
checksum = "a4354d5b5f48d53cc0d4d000425ec062b12e9b3fbcf395e765064c8eab113921"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
"oxc_ast_macros",
|
"oxc_ast_macros",
|
||||||
@@ -2042,9 +2042,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_semantic"
|
name = "oxc_semantic"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78fcfacfa8a2bb020326c37011b86f423c41e776516c197e6c162ac85b6a1e7a"
|
checksum = "e1346102f3550e6b0417fe84f8fb397f976c351e21bcb98b75ff018cc3877bd3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"oxc_allocator",
|
"oxc_allocator",
|
||||||
@@ -2078,9 +2078,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_span"
|
name = "oxc_span"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c2940d9a7446ddbe554bf0aa3cd111e6bf7c2dd29460da6673cde9b1c7be77f"
|
checksum = "77b073cb1349f33e04d821e4fd1e51c860a010d74fea0b4660504cb05a87968a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compact_str",
|
"compact_str",
|
||||||
"oxc-miette",
|
"oxc-miette",
|
||||||
@@ -2091,9 +2091,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_syntax"
|
name = "oxc_syntax"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd9d42c1d620a1da919ec6b56c4476054d4d2c71423c08effbc3a0519c516b61"
|
checksum = "488a2404fca5b741255b8b875e8f6515f5b08df6046a0767b2368d6182e055cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cow-utils",
|
"cow-utils",
|
||||||
@@ -2112,9 +2112,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxc_traverse"
|
name = "oxc_traverse"
|
||||||
version = "0.61.0"
|
version = "0.61.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f389b5904bc2294fe53ee6b0f6b3b15e395b71079168d8e8204626c4aede3c32"
|
checksum = "02102521f55df8330e9393d425e746e21d9badc5a78650769e645db40102f3c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compact_str",
|
"compact_str",
|
||||||
"itoa",
|
"itoa",
|
||||||
@@ -3473,18 +3473,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zstd-safe"
|
name = "zstd-safe"
|
||||||
version = "7.2.3"
|
version = "7.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722"
|
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zstd-sys",
|
"zstd-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zstd-sys"
|
name = "zstd-sys"
|
||||||
version = "2.0.14+zstd.1.5.7"
|
version = "2.0.15+zstd.1.5.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5"
|
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub use stores::*;
|
|||||||
pub use vecs::*;
|
pub use vecs::*;
|
||||||
|
|
||||||
const SNAPSHOT_BLOCK_RANGE: usize = 1000;
|
const SNAPSHOT_BLOCK_RANGE: usize = 1000;
|
||||||
const COLLISIONS_CHECKED_UP_TO: u32 = 870_000;
|
const COLLISIONS_CHECKED_UP_TO: u32 = 888_000;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Indexer {
|
pub struct Indexer {
|
||||||
|
|||||||
@@ -162,17 +162,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl<I, T> Deref for StorableVec<I, T> {
|
|
||||||
// type Target = brk_vec::StorableVec<I, T>;
|
|
||||||
// fn deref(&self) -> &Self::Target {
|
|
||||||
// &self.vec
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// impl<I, T> DerefMut for StorableVec<I, T> {
|
|
||||||
// fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
// &mut self.vec
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
impl<I, T> Clone for StorableVec<I, T>
|
impl<I, T> Clone for StorableVec<I, T>
|
||||||
where
|
where
|
||||||
I: StoredIndex,
|
I: StoredIndex,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ color-eyre = { workspace = true }
|
|||||||
jiff = { workspace = true }
|
jiff = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
minreq = { workspace = true }
|
minreq = { workspace = true }
|
||||||
oxc = { version = "0.61.0", features = ["codegen", "minifier"] }
|
oxc = { version = "0.61.1", features = ["codegen", "minifier"] }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
tokio = { version = "1.44.1", features = ["full"] }
|
tokio = { version = "1.44.1", features = ["full"] }
|
||||||
tower-http = { version = "0.6.2", features = ["compression-full"] }
|
tower-http = { version = "0.6.2", features = ["compression-full"] }
|
||||||
|
|||||||
@@ -1518,7 +1518,6 @@
|
|||||||
"
|
"
|
||||||
>希望</small
|
>希望</small
|
||||||
>
|
>
|
||||||
希望.お金
|
|
||||||
</a>
|
</a>
|
||||||
<small style="display: block">
|
<small style="display: block">
|
||||||
<strong>Bitcoin</strong> is
|
<strong>Bitcoin</strong> is
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* @import { DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, SingleValueData, ISeriesApi, Time, LogicalRange, SeriesType, BaselineStyleOptions, SeriesOptionsCommon, createChart as CreateClassicChart, createChartEx as CreateCustomChart } from "./v4.2.2/types"
|
* @import { DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, SingleValueData, ISeriesApi, Time, LogicalRange, SeriesType, BaselineStyleOptions, SeriesOptionsCommon, createChart as CreateClassicChart, createChartEx as CreateCustomChart } from "./v4.2.2/types"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export default import("./v4.2.2/script.js").then((lightweightCharts) => {
|
||||||
const ids = {
|
const ids = {
|
||||||
from: "from",
|
from: "from",
|
||||||
to: "to",
|
to: "to",
|
||||||
@@ -16,7 +17,6 @@ const ids = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default import("./v4.2.2/script.js").then((lightweightCharts) => {
|
|
||||||
const createClassicChart = /** @type {CreateClassicChart} */ (
|
const createClassicChart = /** @type {CreateClassicChart} */ (
|
||||||
lightweightCharts.createChart
|
lightweightCharts.createChart
|
||||||
);
|
);
|
||||||
@@ -357,6 +357,7 @@ export default import("./v4.2.2/script.js").then((lightweightCharts) => {
|
|||||||
* @param {TimeScale} param0.scale
|
* @param {TimeScale} param0.scale
|
||||||
* @param {"static" | "moveable"} param0.kind
|
* @param {"static" | "moveable"} param0.kind
|
||||||
* @param {Utilities} param0.utils
|
* @param {Utilities} param0.utils
|
||||||
|
* @param {Constants} param0.consts
|
||||||
* @param {Owner | null} [param0.owner]
|
* @param {Owner | null} [param0.owner]
|
||||||
* @param {CreatePaneParameters[]} [param0.config]
|
* @param {CreatePaneParameters[]} [param0.config]
|
||||||
*/
|
*/
|
||||||
@@ -368,6 +369,7 @@ export default import("./v4.2.2/script.js").then((lightweightCharts) => {
|
|||||||
kind,
|
kind,
|
||||||
scale,
|
scale,
|
||||||
config,
|
config,
|
||||||
|
consts,
|
||||||
utils,
|
utils,
|
||||||
owner: _owner,
|
owner: _owner,
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
* @param {Signals} args.signals
|
* @param {Signals} args.signals
|
||||||
* @param {Utilities} args.utils
|
* @param {Utilities} args.utils
|
||||||
* @param {Datasets} args.datasets
|
* @param {Datasets} args.datasets
|
||||||
|
* @param {Constants} args.consts
|
||||||
* @param {WebSockets} args.webSockets
|
* @param {WebSockets} args.webSockets
|
||||||
* @param {Elements} args.elements
|
* @param {Elements} args.elements
|
||||||
*/
|
*/
|
||||||
@@ -19,6 +20,7 @@ export function init({
|
|||||||
selected,
|
selected,
|
||||||
signals,
|
signals,
|
||||||
utils,
|
utils,
|
||||||
|
consts,
|
||||||
webSockets,
|
webSockets,
|
||||||
}) {
|
}) {
|
||||||
console.log("init chart state");
|
console.log("init chart state");
|
||||||
@@ -43,6 +45,7 @@ export function init({
|
|||||||
id: "chart",
|
id: "chart",
|
||||||
scale: scale(),
|
scale: scale(),
|
||||||
kind: "moveable",
|
kind: "moveable",
|
||||||
|
consts,
|
||||||
utils,
|
utils,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/**
|
/**
|
||||||
* @param {Object} args
|
* @param {Object} args
|
||||||
* @param {Colors} args.colors
|
* @param {Colors} args.colors
|
||||||
* @param {Consts} args.consts
|
* @param {Constants} args.consts
|
||||||
* @param {LightweightCharts} args.lightweightCharts
|
* @param {LightweightCharts} args.lightweightCharts
|
||||||
* @param {Signals} args.signals
|
* @param {Signals} args.signals
|
||||||
* @param {Utilities} args.utils
|
* @param {Utilities} args.utils
|
||||||
|
|||||||
@@ -68,34 +68,35 @@ function initPackages() {
|
|||||||
ufuzzy: importPackage("ufuzzy"),
|
ufuzzy: importPackage("ufuzzy"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const packages = initPackages();
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Awaited<ReturnType<typeof packages.lightweightCharts>>} LightweightCharts
|
* @typedef {ReturnType<typeof initPackages>} Packages
|
||||||
|
* @typedef {Awaited<ReturnType<Packages["lightweightCharts"]>>} LightweightCharts
|
||||||
* @typedef {ReturnType<LightweightCharts['createChart']>} Chart
|
* @typedef {ReturnType<LightweightCharts['createChart']>} Chart
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const options = import("./options.js");
|
function createUtils() {
|
||||||
|
|
||||||
const utils = {
|
|
||||||
/**
|
/**
|
||||||
* @param {string} serialized
|
* @param {string} serialized
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isSerializedBooleanTrue(serialized) {
|
function isSerializedBooleanTrue(serialized) {
|
||||||
return serialized === "true" || serialized === "1";
|
return serialized === "true" || serialized === "1";
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} ms
|
* @param {number} ms
|
||||||
*/
|
*/
|
||||||
sleep(ms) {
|
function sleep(ms) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(resolve, ms);
|
setTimeout(resolve, ms);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
yield() {
|
|
||||||
return this.sleep(0);
|
function next() {
|
||||||
},
|
return sleep(0);
|
||||||
array: {
|
}
|
||||||
|
|
||||||
|
const array = {
|
||||||
/**
|
/**
|
||||||
* @param {number} start
|
* @param {number} start
|
||||||
* @param {number} end
|
* @param {number} end
|
||||||
@@ -108,8 +109,9 @@ const utils = {
|
|||||||
}
|
}
|
||||||
return range;
|
return range;
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
dom: {
|
|
||||||
|
const dom = {
|
||||||
/**
|
/**
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
@@ -121,8 +123,9 @@ const utils = {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
|
* @param {Elements} elements
|
||||||
*/
|
*/
|
||||||
queryOrCreateMetaElement(name) {
|
queryOrCreateMetaElement(name, elements) {
|
||||||
let meta = /** @type {HTMLMetaElement | null} */ (
|
let meta = /** @type {HTMLMetaElement | null} */ (
|
||||||
window.document.querySelector(`meta[name="${name}"]`)
|
window.document.querySelector(`meta[name="${name}"]`)
|
||||||
);
|
);
|
||||||
@@ -289,9 +292,10 @@ const utils = {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
|
* @param {Elements} elements
|
||||||
* @param {boolean} [targetBlank]
|
* @param {boolean} [targetBlank]
|
||||||
*/
|
*/
|
||||||
open(url, targetBlank) {
|
open(url, elements, targetBlank) {
|
||||||
console.log(`open: ${url}`);
|
console.log(`open: ${url}`);
|
||||||
const a = window.document.createElement("a");
|
const a = window.document.createElement("a");
|
||||||
elements.body.append(a);
|
elements.body.append(a);
|
||||||
@@ -322,7 +326,8 @@ const utils = {
|
|||||||
link.type = "text/css";
|
link.type = "text/css";
|
||||||
link.rel = "stylesheet";
|
link.rel = "stylesheet";
|
||||||
link.media = "screen,print";
|
link.media = "screen,print";
|
||||||
elements.head.appendChild(link);
|
const head = window.document.getElementsByTagName("head")[0];
|
||||||
|
head.appendChild(link);
|
||||||
return link;
|
return link;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -362,7 +367,7 @@ const utils = {
|
|||||||
|
|
||||||
choices.forEach((choice) => {
|
choices.forEach((choice) => {
|
||||||
const inputValue = choice.toLowerCase();
|
const inputValue = choice.toLowerCase();
|
||||||
const { label } = utils.dom.createLabeledInput({
|
const { label } = this.createLabeledInput({
|
||||||
inputId: `${id}-${choice.toLowerCase()}`,
|
inputId: `${id}-${choice.toLowerCase()}`,
|
||||||
inputName: id,
|
inputName: id,
|
||||||
inputValue,
|
inputValue,
|
||||||
@@ -476,7 +481,7 @@ const utils = {
|
|||||||
const min = "2011-01-01";
|
const min = "2011-01-01";
|
||||||
const minDate = new Date(min);
|
const minDate = new Date(min);
|
||||||
const maxDate = new Date();
|
const maxDate = new Date();
|
||||||
const max = utils.date.toString(maxDate);
|
const max = date.toString(maxDate);
|
||||||
input.min = min;
|
input.min = min;
|
||||||
input.max = max;
|
input.max = max;
|
||||||
|
|
||||||
@@ -484,8 +489,8 @@ const utils = {
|
|||||||
|
|
||||||
signals.createEffect(
|
signals.createEffect(
|
||||||
() => {
|
() => {
|
||||||
const date = signal();
|
const dateSignal = signal();
|
||||||
return date ? utils.date.toString(date) : "";
|
return dateSignal ? date.toString(dateSignal) : "";
|
||||||
},
|
},
|
||||||
(value) => {
|
(value) => {
|
||||||
if (stateValue !== value) {
|
if (stateValue !== value) {
|
||||||
@@ -663,8 +668,9 @@ const utils = {
|
|||||||
div.classList.add(`shadow-${position}`);
|
div.classList.add(`shadow-${position}`);
|
||||||
return div;
|
return div;
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
url: {
|
|
||||||
|
const url = {
|
||||||
chartParamsWhitelist: ["from", "to"],
|
chartParamsWhitelist: ["from", "to"],
|
||||||
/**
|
/**
|
||||||
* @param {string} pathname
|
* @param {string} pathname
|
||||||
@@ -736,7 +742,7 @@ const utils = {
|
|||||||
const parameter = this.readParam(key);
|
const parameter = this.readParam(key);
|
||||||
|
|
||||||
if (parameter) {
|
if (parameter) {
|
||||||
return utils.isSerializedBooleanTrue(parameter);
|
return isSerializedBooleanTrue(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -767,20 +773,23 @@ const utils = {
|
|||||||
pathnameToSelectedId() {
|
pathnameToSelectedId() {
|
||||||
return window.document.location.pathname.substring(1);
|
return window.document.location.pathname.substring(1);
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
locale: {
|
|
||||||
/**
|
/**
|
||||||
* @param {number} value
|
* @param {number} value
|
||||||
* @param {number} [digits]
|
* @param {number} [digits]
|
||||||
* @param {Intl.NumberFormatOptions} [options]
|
* @param {Intl.NumberFormatOptions} [options]
|
||||||
*/
|
*/
|
||||||
numberToUSFormat(value, digits, options) {
|
function numberToUSFormat(value, digits, options) {
|
||||||
return value.toLocaleString("en-us", {
|
return value.toLocaleString("en-us", {
|
||||||
...options,
|
...options,
|
||||||
minimumFractionDigits: digits,
|
minimumFractionDigits: digits,
|
||||||
maximumFractionDigits: digits,
|
maximumFractionDigits: digits,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
|
const locale = {
|
||||||
|
numberToUSFormat,
|
||||||
/** @param {number} value */
|
/** @param {number} value */
|
||||||
numberToShortUSFormat(value) {
|
numberToShortUSFormat(value) {
|
||||||
const absoluteValue = Math.abs(value);
|
const absoluteValue = Math.abs(value);
|
||||||
@@ -788,15 +797,15 @@ const utils = {
|
|||||||
if (isNaN(value)) {
|
if (isNaN(value)) {
|
||||||
return "";
|
return "";
|
||||||
} else if (absoluteValue < 10) {
|
} else if (absoluteValue < 10) {
|
||||||
return utils.locale.numberToUSFormat(value, 3);
|
return numberToUSFormat(value, 3);
|
||||||
} else if (absoluteValue < 100) {
|
} else if (absoluteValue < 100) {
|
||||||
return utils.locale.numberToUSFormat(value, 2);
|
return numberToUSFormat(value, 2);
|
||||||
} else if (absoluteValue < 1_000) {
|
} else if (absoluteValue < 1_000) {
|
||||||
return utils.locale.numberToUSFormat(value, 1);
|
return numberToUSFormat(value, 1);
|
||||||
} else if (absoluteValue < 100_000) {
|
} else if (absoluteValue < 100_000) {
|
||||||
return utils.locale.numberToUSFormat(value, 0);
|
return numberToUSFormat(value, 0);
|
||||||
} else if (absoluteValue < 1_000_000) {
|
} else if (absoluteValue < 1_000_000) {
|
||||||
return `${utils.locale.numberToUSFormat(value / 1_000, 1)}K`;
|
return `${numberToUSFormat(value / 1_000, 1)}K`;
|
||||||
} else if (absoluteValue >= 9_000_000_000_000_000) {
|
} else if (absoluteValue >= 9_000_000_000_000_000) {
|
||||||
return "Inf.";
|
return "Inf.";
|
||||||
}
|
}
|
||||||
@@ -810,24 +819,25 @@ const utils = {
|
|||||||
const modulused = log % 3;
|
const modulused = log % 3;
|
||||||
|
|
||||||
if (modulused === 0) {
|
if (modulused === 0) {
|
||||||
return `${utils.locale.numberToUSFormat(
|
return `${numberToUSFormat(
|
||||||
value / (1_000_000 * 1_000 ** letterIndex),
|
value / (1_000_000 * 1_000 ** letterIndex),
|
||||||
3,
|
3,
|
||||||
)}${letter}`;
|
)}${letter}`;
|
||||||
} else if (modulused === 1) {
|
} else if (modulused === 1) {
|
||||||
return `${utils.locale.numberToUSFormat(
|
return `${numberToUSFormat(
|
||||||
value / (1_000_000 * 1_000 ** letterIndex),
|
value / (1_000_000 * 1_000 ** letterIndex),
|
||||||
2,
|
2,
|
||||||
)}${letter}`;
|
)}${letter}`;
|
||||||
} else {
|
} else {
|
||||||
return `${utils.locale.numberToUSFormat(
|
return `${numberToUSFormat(
|
||||||
value / (1_000_000 * 1_000 ** letterIndex),
|
value / (1_000_000 * 1_000 ** letterIndex),
|
||||||
1,
|
1,
|
||||||
)}${letter}`;
|
)}${letter}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
storage: {
|
|
||||||
|
const storage = {
|
||||||
/**
|
/**
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
*/
|
*/
|
||||||
@@ -844,7 +854,7 @@ const utils = {
|
|||||||
readBool(key) {
|
readBool(key) {
|
||||||
const saved = this.read(key);
|
const saved = this.read(key);
|
||||||
if (saved) {
|
if (saved) {
|
||||||
return utils.isSerializedBooleanTrue(saved);
|
return isSerializedBooleanTrue(saved);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@@ -869,8 +879,9 @@ const utils = {
|
|||||||
remove(key) {
|
remove(key) {
|
||||||
this.write(key, undefined);
|
this.write(key, undefined);
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
serde: {
|
|
||||||
|
const serde = {
|
||||||
number: {
|
number: {
|
||||||
/**
|
/**
|
||||||
* @param {number} v
|
* @param {number} v
|
||||||
@@ -890,7 +901,7 @@ const utils = {
|
|||||||
* @param {Date} v
|
* @param {Date} v
|
||||||
*/
|
*/
|
||||||
serialize(v) {
|
serialize(v) {
|
||||||
return utils.date.toString(v);
|
return date.toString(v);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param {string} v
|
* @param {string} v
|
||||||
@@ -919,8 +930,9 @@ const utils = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
formatters: {
|
|
||||||
|
const formatters = {
|
||||||
dollars: new Intl.NumberFormat("en-US", {
|
dollars: new Intl.NumberFormat("en-US", {
|
||||||
style: "currency",
|
style: "currency",
|
||||||
currency: "USD",
|
currency: "USD",
|
||||||
@@ -932,8 +944,9 @@ const utils = {
|
|||||||
minimumFractionDigits: 2,
|
minimumFractionDigits: 2,
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
}),
|
}),
|
||||||
},
|
};
|
||||||
date: {
|
|
||||||
|
const date = {
|
||||||
ONE_DAY_IN_MS: 1000 * 60 * 60 * 24,
|
ONE_DAY_IN_MS: 1000 * 60 * 60 * 24,
|
||||||
todayUTC() {
|
todayUTC() {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@@ -991,8 +1004,9 @@ const utils = {
|
|||||||
differenceBetween(date1, date2) {
|
differenceBetween(date1, date2) {
|
||||||
return Math.abs(date1.valueOf() - date2.valueOf()) / this.ONE_DAY_IN_MS;
|
return Math.abs(date1.valueOf() - date2.valueOf()) / this.ONE_DAY_IN_MS;
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
color: {
|
|
||||||
|
const color = {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {readonly [number, number, number, number, number, number, number, number, number]} A
|
* @param {readonly [number, number, number, number, number, number, number, number, number]} A
|
||||||
@@ -1086,14 +1100,15 @@ const utils = {
|
|||||||
});
|
});
|
||||||
return `#${r}${g}${b}`;
|
return `#${r}${g}${b}`;
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @template {(...args: any[]) => any} F
|
* @template {(...args: any[]) => any} F
|
||||||
* @param {F} callback
|
* @param {F} callback
|
||||||
* @param {number} [wait=250]
|
* @param {number} [wait=250]
|
||||||
*/
|
*/
|
||||||
debounce(callback, wait = 250) {
|
function debounce(callback, wait = 250) {
|
||||||
/** @type {number | undefined} */
|
/** @type {number | undefined} */
|
||||||
let timeoutId;
|
let timeoutId;
|
||||||
/** @type {Parameters<F>} */
|
/** @type {Parameters<F>} */
|
||||||
@@ -1110,45 +1125,69 @@ const utils = {
|
|||||||
}, wait);
|
}, wait);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {VoidFunction} callback
|
* @param {VoidFunction} callback
|
||||||
* @param {number} [timeout = 1]
|
* @param {number} [timeout = 1]
|
||||||
*/
|
*/
|
||||||
runWhenIdle(callback, timeout = 1) {
|
function runWhenIdle(callback, timeout = 1) {
|
||||||
if ("requestIdleCallback" in window) {
|
if ("requestIdleCallback" in window) {
|
||||||
requestIdleCallback(callback);
|
requestIdleCallback(callback);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(callback, timeout);
|
setTimeout(callback, timeout);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Date} oldest
|
* @param {Date} oldest
|
||||||
* @param {Date} youngest
|
* @param {Date} youngest
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
getNumberOfDaysBetweenTwoDates(oldest, youngest) {
|
function getNumberOfDaysBetweenTwoDates(oldest, youngest) {
|
||||||
|
const ONE_DAY_IN_MS = 1000 * 60 * 60 * 24;
|
||||||
return Math.round(
|
return Math.round(
|
||||||
Math.abs((youngest.getTime() - oldest.getTime()) / consts.ONE_DAY_IN_MS),
|
Math.abs((youngest.getTime() - oldest.getTime()) / ONE_DAY_IN_MS),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} s
|
||||||
|
*/
|
||||||
|
function stringToId(s) {
|
||||||
|
return s.replace(/\W/g, " ").trim().replace(/ +/g, "-").toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {TimeScale} scale
|
* @param {TimeScale} scale
|
||||||
* @param {number} id
|
* @param {number} id
|
||||||
*/
|
*/
|
||||||
chunkIdToIndex(scale, id) {
|
function chunkIdToIndex(scale, id) {
|
||||||
return scale === "date"
|
const HEIGHT_CHUNK_SIZE = 10_000;
|
||||||
? id - 2009
|
return scale === "date" ? id - 2009 : Math.floor(id / HEIGHT_CHUNK_SIZE);
|
||||||
: Math.floor(id / consts.HEIGHT_CHUNK_SIZE);
|
}
|
||||||
},
|
|
||||||
/**
|
return {
|
||||||
* @param {string} s
|
isSerializedBooleanTrue,
|
||||||
*/
|
sleep,
|
||||||
stringToId(s) {
|
next,
|
||||||
return s.replace(/\W/g, " ").trim().replace(/ +/g, "-").toLowerCase();
|
array,
|
||||||
},
|
dom,
|
||||||
|
url,
|
||||||
|
locale,
|
||||||
|
storage,
|
||||||
|
serde,
|
||||||
|
formatters,
|
||||||
|
date,
|
||||||
|
color,
|
||||||
|
debounce,
|
||||||
|
runWhenIdle,
|
||||||
|
getNumberOfDaysBetweenTwoDates,
|
||||||
|
chunkIdToIndex,
|
||||||
|
stringToId,
|
||||||
};
|
};
|
||||||
/** @typedef {typeof utils} Utilities */
|
}
|
||||||
|
/** @typedef {ReturnType<typeof createUtils>} Utilities */
|
||||||
|
|
||||||
function initEnv() {
|
function initEnv() {
|
||||||
const standalone =
|
const standalone =
|
||||||
@@ -1175,8 +1214,7 @@ function initEnv() {
|
|||||||
localhost: window.location.hostname === "localhost",
|
localhost: window.location.hostname === "localhost",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const env = initEnv();
|
/** @typedef {ReturnType<typeof initEnv>} Env */
|
||||||
/** @typedef {typeof env} Env */
|
|
||||||
|
|
||||||
function createConstants() {
|
function createConstants() {
|
||||||
const ONE_SECOND_IN_MS = 1_000;
|
const ONE_SECOND_IN_MS = 1_000;
|
||||||
@@ -1207,152 +1245,62 @@ function createConstants() {
|
|||||||
MEDIUM_WIDTH,
|
MEDIUM_WIDTH,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const consts = createConstants();
|
/** @typedef {ReturnType<typeof createConstants>} Constants */
|
||||||
/** @typedef {typeof consts} Consts */
|
|
||||||
|
|
||||||
const ids = /** @type {const} */ ({
|
function createIds() {
|
||||||
|
return /** @type {const} */ ({
|
||||||
selectedId: `selected-id`,
|
selectedId: `selected-id`,
|
||||||
asideSelectorLabel: `aside-selector-label`,
|
asideSelectorLabel: `aside-selector-label`,
|
||||||
checkedFrameSelectorLabel: "checked-frame-selector-label",
|
checkedFrameSelectorLabel: "checked-frame-selector-label",
|
||||||
});
|
});
|
||||||
/** @typedef {typeof ids} Ids */
|
}
|
||||||
|
/** @typedef {ReturnType<typeof createIds>} Ids */
|
||||||
|
|
||||||
const elements = {
|
/**
|
||||||
|
* @param {Ids} ids
|
||||||
|
*/
|
||||||
|
function getElements(ids) {
|
||||||
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
*/
|
||||||
|
function getElementById(id) {
|
||||||
|
const element = window.document.getElementById(id);
|
||||||
|
if (!element) throw `Element with id = "${id}" should exist`;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
head: window.document.getElementsByTagName("head")[0],
|
head: window.document.getElementsByTagName("head")[0],
|
||||||
body: window.document.body,
|
body: window.document.body,
|
||||||
main: utils.dom.getElementById("main"),
|
main: getElementById("main"),
|
||||||
aside: utils.dom.getElementById("aside"),
|
aside: getElementById("aside"),
|
||||||
asideLabel: utils.dom.getElementById(ids.asideSelectorLabel),
|
asideLabel: getElementById(ids.asideSelectorLabel),
|
||||||
navLabel: utils.dom.getElementById(`nav-selector-label`),
|
navLabel: getElementById(`nav-selector-label`),
|
||||||
searchLabel: utils.dom.getElementById(`search-selector-label`),
|
searchLabel: getElementById(`search-selector-label`),
|
||||||
search: utils.dom.getElementById("search"),
|
search: getElementById("search"),
|
||||||
nav: utils.dom.getElementById("nav"),
|
nav: getElementById("nav"),
|
||||||
navHeader: utils.dom.getElementById("nav-header"),
|
navHeader: getElementById("nav-header"),
|
||||||
searchInput: /** @type {HTMLInputElement} */ (
|
searchInput: /** @type {HTMLInputElement} */ (
|
||||||
utils.dom.getElementById("search-input")
|
getElementById("search-input")
|
||||||
),
|
),
|
||||||
searchSmall: utils.dom.getElementById("search-small"),
|
searchSmall: getElementById("search-small"),
|
||||||
searchResults: utils.dom.getElementById("search-results"),
|
searchResults: getElementById("search-results"),
|
||||||
selectors: utils.dom.getElementById("frame-selectors"),
|
selectors: getElementById("frame-selectors"),
|
||||||
style: getComputedStyle(window.document.documentElement),
|
style: getComputedStyle(window.document.documentElement),
|
||||||
charts: utils.dom.getElementById("charts"),
|
charts: getElementById("charts"),
|
||||||
simulation: utils.dom.getElementById("simulation"),
|
simulation: getElementById("simulation"),
|
||||||
livePrice: utils.dom.getElementById("live-price"),
|
livePrice: getElementById("live-price"),
|
||||||
moscowTime: utils.dom.getElementById("moscow-time"),
|
moscowTime: getElementById("moscow-time"),
|
||||||
};
|
};
|
||||||
/** @typedef {typeof elements} Elements */
|
|
||||||
|
|
||||||
const urlSelected = utils.url.pathnameToSelectedId();
|
|
||||||
|
|
||||||
function initFrameSelectors() {
|
|
||||||
const children = Array.from(elements.selectors.children);
|
|
||||||
|
|
||||||
/** @type {HTMLElement | undefined} */
|
|
||||||
let focusedFrame = undefined;
|
|
||||||
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
|
||||||
const element = children[i];
|
|
||||||
|
|
||||||
switch (element.tagName) {
|
|
||||||
case "LABEL": {
|
|
||||||
element.addEventListener("click", () => {
|
|
||||||
const inputId = element.getAttribute("for");
|
|
||||||
|
|
||||||
if (!inputId) {
|
|
||||||
console.log(element, element.getAttribute("for"));
|
|
||||||
throw "Input id in label not found";
|
|
||||||
}
|
}
|
||||||
|
/** @typedef {ReturnType<typeof getElements>} Elements */
|
||||||
const input = window.document.getElementById(inputId);
|
|
||||||
|
|
||||||
if (!input || !("value" in input)) {
|
|
||||||
throw "Not input or no value";
|
|
||||||
}
|
|
||||||
|
|
||||||
const frame = window.document.getElementById(
|
|
||||||
/** @type {string} */ (input.value),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!frame) {
|
|
||||||
console.log(input.value);
|
|
||||||
throw "Frame element doesn't exist";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame === focusedFrame) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.hidden = false;
|
|
||||||
if (focusedFrame) {
|
|
||||||
focusedFrame.hidden = true;
|
|
||||||
}
|
|
||||||
focusedFrame = frame;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.asideLabel.click();
|
|
||||||
|
|
||||||
// When going from mobile view to desktop view, if selected frame was open, go to the nav frame
|
|
||||||
new IntersectionObserver((entries) => {
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
|
||||||
if (
|
|
||||||
!entries[i].isIntersecting &&
|
|
||||||
entries[i].target === elements.asideLabel &&
|
|
||||||
focusedFrame == elements.aside
|
|
||||||
) {
|
|
||||||
elements.navLabel.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).observe(elements.asideLabel);
|
|
||||||
|
|
||||||
function setAsideParent() {
|
|
||||||
const { clientWidth } = window.document.documentElement;
|
|
||||||
const { aside, body, main } = elements;
|
|
||||||
if (clientWidth >= consts.MEDIUM_WIDTH) {
|
|
||||||
aside.parentElement !== body && body.append(aside);
|
|
||||||
} else {
|
|
||||||
aside.parentElement !== main && main.append(aside);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setAsideParent();
|
|
||||||
|
|
||||||
window.addEventListener("resize", setAsideParent);
|
|
||||||
}
|
|
||||||
initFrameSelectors();
|
|
||||||
|
|
||||||
function createKeyDownEventListener() {
|
|
||||||
window.document.addEventListener("keydown", (event) => {
|
|
||||||
switch (event.key) {
|
|
||||||
case "Escape": {
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
elements.navLabel.click();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "/": {
|
|
||||||
if (window.document.activeElement === elements.searchInput) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
elements.searchLabel.click();
|
|
||||||
elements.searchInput.focus();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
createKeyDownEventListener();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Accessor<boolean>} dark
|
* @param {Accessor<boolean>} dark
|
||||||
|
* @param {Elements} elements
|
||||||
|
* @param {Utilities} utils
|
||||||
*/
|
*/
|
||||||
function createColors(dark) {
|
function createColors(dark, elements, utils) {
|
||||||
/**
|
/**
|
||||||
* @param {string} color
|
* @param {string} color
|
||||||
*/
|
*/
|
||||||
@@ -1568,8 +1516,10 @@ function createColors(dark) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Signals} signals
|
* @param {Signals} signals
|
||||||
|
* @param {Constants} consts
|
||||||
|
* @param {Utilities} utils
|
||||||
*/
|
*/
|
||||||
function createDatasets(signals) {
|
function createDatasets(signals, consts, utils) {
|
||||||
/** @type {Map<DatePath, ResourceDataset<"date">>} */
|
/** @type {Map<DatePath, ResourceDataset<"date">>} */
|
||||||
const date = new Map();
|
const date = new Map();
|
||||||
/** @type {Map<HeightPath, ResourceDataset<"height">>} */
|
/** @type {Map<HeightPath, ResourceDataset<"height">>} */
|
||||||
@@ -1932,8 +1882,9 @@ function createDatasets(signals) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Signals} signals
|
* @param {Signals} signals
|
||||||
|
* @param {Utilities} utils
|
||||||
*/
|
*/
|
||||||
function initWebSockets(signals) {
|
function initWebSockets(signals, utils) {
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
* @param {(callback: (value: T) => void) => WebSocket} creator
|
* @param {(callback: (value: T) => void) => WebSocket} creator
|
||||||
@@ -2072,13 +2023,129 @@ function initWebSockets(signals) {
|
|||||||
}
|
}
|
||||||
/** @typedef {ReturnType<typeof initWebSockets>} WebSockets */
|
/** @typedef {ReturnType<typeof initWebSockets>} WebSockets */
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const packages = initPackages();
|
||||||
|
const options = import("./options.js");
|
||||||
|
const env = initEnv();
|
||||||
|
const consts = createConstants();
|
||||||
|
const utils = createUtils();
|
||||||
|
const ids = createIds();
|
||||||
|
const elements = getElements(ids);
|
||||||
|
|
||||||
|
function initFrameSelectors() {
|
||||||
|
const children = Array.from(elements.selectors.children);
|
||||||
|
|
||||||
|
/** @type {HTMLElement | undefined} */
|
||||||
|
let focusedFrame = undefined;
|
||||||
|
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
const element = children[i];
|
||||||
|
|
||||||
|
switch (element.tagName) {
|
||||||
|
case "LABEL": {
|
||||||
|
element.addEventListener("click", () => {
|
||||||
|
const inputId = element.getAttribute("for");
|
||||||
|
|
||||||
|
if (!inputId) {
|
||||||
|
console.log(element, element.getAttribute("for"));
|
||||||
|
throw "Input id in label not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
const input = window.document.getElementById(inputId);
|
||||||
|
|
||||||
|
if (!input || !("value" in input)) {
|
||||||
|
throw "Not input or no value";
|
||||||
|
}
|
||||||
|
|
||||||
|
const frame = window.document.getElementById(
|
||||||
|
/** @type {string} */ (input.value),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!frame) {
|
||||||
|
console.log(input.value);
|
||||||
|
throw "Frame element doesn't exist";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame === focusedFrame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.hidden = false;
|
||||||
|
if (focusedFrame) {
|
||||||
|
focusedFrame.hidden = true;
|
||||||
|
}
|
||||||
|
focusedFrame = frame;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.asideLabel.click();
|
||||||
|
|
||||||
|
// When going from mobile view to desktop view, if selected frame was open, go to the nav frame
|
||||||
|
new IntersectionObserver((entries) => {
|
||||||
|
for (let i = 0; i < entries.length; i++) {
|
||||||
|
if (
|
||||||
|
!entries[i].isIntersecting &&
|
||||||
|
entries[i].target === elements.asideLabel &&
|
||||||
|
focusedFrame == elements.aside
|
||||||
|
) {
|
||||||
|
elements.navLabel.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).observe(elements.asideLabel);
|
||||||
|
|
||||||
|
function setAsideParent() {
|
||||||
|
const { clientWidth } = window.document.documentElement;
|
||||||
|
const { aside, body, main } = elements;
|
||||||
|
if (clientWidth >= consts.MEDIUM_WIDTH) {
|
||||||
|
aside.parentElement !== body && body.append(aside);
|
||||||
|
} else {
|
||||||
|
aside.parentElement !== main && main.append(aside);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAsideParent();
|
||||||
|
|
||||||
|
window.addEventListener("resize", setAsideParent);
|
||||||
|
}
|
||||||
|
initFrameSelectors();
|
||||||
|
|
||||||
|
function createKeyDownEventListener() {
|
||||||
|
window.document.addEventListener("keydown", (event) => {
|
||||||
|
switch (event.key) {
|
||||||
|
case "Escape": {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
elements.navLabel.click();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "/": {
|
||||||
|
if (window.document.activeElement === elements.searchInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
elements.searchLabel.click();
|
||||||
|
elements.searchInput.focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createKeyDownEventListener();
|
||||||
|
|
||||||
packages.signals().then((signals) =>
|
packages.signals().then((signals) =>
|
||||||
options.then(({ initOptions }) => {
|
options.then(({ initOptions }) => {
|
||||||
function initDark() {
|
function initDark() {
|
||||||
const preferredColorSchemeMatchMedia = window.matchMedia(
|
const preferredColorSchemeMatchMedia = window.matchMedia(
|
||||||
"(prefers-color-scheme: dark)",
|
"(prefers-color-scheme: dark)",
|
||||||
);
|
);
|
||||||
const dark = signals.createSignal(preferredColorSchemeMatchMedia.matches);
|
const dark = signals.createSignal(
|
||||||
|
preferredColorSchemeMatchMedia.matches,
|
||||||
|
);
|
||||||
preferredColorSchemeMatchMedia.addEventListener(
|
preferredColorSchemeMatchMedia.addEventListener(
|
||||||
"change",
|
"change",
|
||||||
({ matches }) => {
|
({ matches }) => {
|
||||||
@@ -2129,9 +2196,9 @@ packages.signals().then((signals) =>
|
|||||||
}
|
}
|
||||||
createFetchLastValuesWhenNeededEffect();
|
createFetchLastValuesWhenNeededEffect();
|
||||||
|
|
||||||
const webSockets = initWebSockets(signals);
|
const webSockets = initWebSockets(signals, utils);
|
||||||
|
|
||||||
const colors = createColors(dark);
|
const colors = createColors(dark, elements, utils);
|
||||||
|
|
||||||
const options = initOptions({
|
const options = initOptions({
|
||||||
colors,
|
colors,
|
||||||
@@ -2144,22 +2211,23 @@ packages.signals().then((signals) =>
|
|||||||
qrcode,
|
qrcode,
|
||||||
});
|
});
|
||||||
|
|
||||||
function createWindowPopStateEvent() {
|
// const urlSelected = utils.url.pathnameToSelectedId();
|
||||||
window.addEventListener("popstate", (event) => {
|
// function createWindowPopStateEvent() {
|
||||||
const urlSelected = utils.url.pathnameToSelectedId();
|
// window.addEventListener("popstate", (event) => {
|
||||||
const option = options.list.find((option) => urlSelected === option.id);
|
// const urlSelected = utils.url.pathnameToSelectedId();
|
||||||
if (option) {
|
// const option = options.list.find((option) => urlSelected === option.id);
|
||||||
options.selected.set(option);
|
// if (option) {
|
||||||
}
|
// options.selected.set(option);
|
||||||
});
|
// }
|
||||||
}
|
// });
|
||||||
|
// }
|
||||||
// createWindowPopStateEvent();
|
// createWindowPopStateEvent();
|
||||||
|
|
||||||
function initSelected() {
|
function initSelected() {
|
||||||
function initSelectedFrame() {
|
function initSelectedFrame() {
|
||||||
console.log("selected: init");
|
console.log("selected: init");
|
||||||
|
|
||||||
const datasets = createDatasets(signals);
|
const datasets = createDatasets(signals, consts, utils);
|
||||||
|
|
||||||
function createApplyOptionEffect() {
|
function createApplyOptionEffect() {
|
||||||
const lastChartOption = signals.createSignal(
|
const lastChartOption = signals.createSignal(
|
||||||
@@ -2214,6 +2282,7 @@ packages.signals().then((signals) =>
|
|||||||
colors,
|
colors,
|
||||||
datasets,
|
datasets,
|
||||||
elements,
|
elements,
|
||||||
|
consts,
|
||||||
lightweightCharts,
|
lightweightCharts,
|
||||||
selected: /** @type {any} */ (lastChartOption),
|
selected: /** @type {any} */ (lastChartOption),
|
||||||
signals,
|
signals,
|
||||||
@@ -2249,6 +2318,7 @@ packages.signals().then((signals) =>
|
|||||||
lightweightCharts,
|
lightweightCharts,
|
||||||
signals,
|
signals,
|
||||||
utils,
|
utils,
|
||||||
|
consts,
|
||||||
lastValues,
|
lastValues,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -2304,7 +2374,9 @@ packages.signals().then((signals) =>
|
|||||||
const lightweightCharts = packages.lightweightCharts();
|
const lightweightCharts = packages.lightweightCharts();
|
||||||
const script = import("./moscow-time.js");
|
const script = import("./moscow-time.js");
|
||||||
|
|
||||||
utils.dom.importStyleAndThen("/styles/moscow-time.css", () =>
|
utils.dom.importStyleAndThen(
|
||||||
|
"/styles/moscow-time.css",
|
||||||
|
() =>
|
||||||
script.then(({ init }) =>
|
script.then(({ init }) =>
|
||||||
signals.runWithOwner(owner, () =>
|
signals.runWithOwner(owner, () =>
|
||||||
init({
|
init({
|
||||||
@@ -2431,13 +2503,15 @@ packages.signals().then((signals) =>
|
|||||||
details.open = true;
|
details.open = true;
|
||||||
i++;
|
i++;
|
||||||
} catch {
|
} catch {
|
||||||
await utils.yield();
|
await utils.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await utils.yield();
|
await utils.next();
|
||||||
|
|
||||||
utils.dom.getElementById(`${selectedId}-nav-selector`).scrollIntoView({
|
utils.dom
|
||||||
|
.getElementById(`${selectedId}-nav-selector`)
|
||||||
|
.scrollIntoView({
|
||||||
behavior: "instant",
|
behavior: "instant",
|
||||||
block: "center",
|
block: "center",
|
||||||
});
|
});
|
||||||
@@ -2532,7 +2606,9 @@ packages.signals().then((signals) =>
|
|||||||
|
|
||||||
function inputEvent() {
|
function inputEvent() {
|
||||||
signals.createRoot((_dispose) => {
|
signals.createRoot((_dispose) => {
|
||||||
const needle = /** @type {string} */ (elements.searchInput.value);
|
const needle = /** @type {string} */ (
|
||||||
|
elements.searchInput.value
|
||||||
|
);
|
||||||
|
|
||||||
dispose?.();
|
dispose?.();
|
||||||
|
|
||||||
@@ -2695,3 +2771,5 @@ packages.signals().then((signals) =>
|
|||||||
initDesktopResizeBar();
|
initDesktopResizeBar();
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
main();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/**
|
/**
|
||||||
* @param {Object} args
|
* @param {Object} args
|
||||||
* @param {Colors} args.colors
|
* @param {Colors} args.colors
|
||||||
* @param {Consts} args.consts
|
* @param {Constants} args.consts
|
||||||
* @param {Signals} args.signals
|
* @param {Signals} args.signals
|
||||||
* @param {Utilities} args.utils
|
* @param {Utilities} args.utils
|
||||||
* @param {Options} args.options
|
* @param {Options} args.options
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
* @import {AnySpecificSeriesBlueprint, SplitSeriesBlueprint} from '../packages/lightweight-charts/types';
|
* @import {AnySpecificSeriesBlueprint, SplitSeriesBlueprint} from '../packages/lightweight-charts/types';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const DATE_TO_PREFIX = "date-to-";
|
|
||||||
const HEIGHT_TO_PREFIX = "height-to-";
|
|
||||||
|
|
||||||
function initGroups() {
|
function initGroups() {
|
||||||
const xTermHolders = /** @type {const} */ ([
|
const xTermHolders = /** @type {const} */ ([
|
||||||
{
|
{
|
||||||
@@ -5204,8 +5201,8 @@ export function initOptions({
|
|||||||
if (!blueprint) return undefined;
|
if (!blueprint) return undefined;
|
||||||
|
|
||||||
const id = blueprint.datasetPath
|
const id = blueprint.datasetPath
|
||||||
.replace(DATE_TO_PREFIX, "")
|
.replace("date-to-", "")
|
||||||
.replace(HEIGHT_TO_PREFIX, "");
|
.replace("height-to-", "");
|
||||||
|
|
||||||
return /** @type {LastPath} */ (id);
|
return /** @type {LastPath} */ (id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
* @param {Utilities} args.utils
|
* @param {Utilities} args.utils
|
||||||
* @param {Datasets} args.datasets
|
* @param {Datasets} args.datasets
|
||||||
* @param {Elements} args.elements
|
* @param {Elements} args.elements
|
||||||
|
* @param {Constants} args.consts
|
||||||
* @param {Signal<LastValues>} args.lastValues
|
* @param {Signal<LastValues>} args.lastValues
|
||||||
*/
|
*/
|
||||||
export function init({
|
export function init({
|
||||||
@@ -22,6 +23,7 @@ export function init({
|
|||||||
lightweightCharts,
|
lightweightCharts,
|
||||||
signals,
|
signals,
|
||||||
utils,
|
utils,
|
||||||
|
consts,
|
||||||
lastValues,
|
lastValues,
|
||||||
}) {
|
}) {
|
||||||
const simulationElement = elements.simulation;
|
const simulationElement = elements.simulation;
|
||||||
@@ -31,6 +33,120 @@ export function init({
|
|||||||
const resultsElement = window.document.createElement("div");
|
const resultsElement = window.document.createElement("div");
|
||||||
simulationElement.append(resultsElement);
|
simulationElement.append(resultsElement);
|
||||||
|
|
||||||
|
function computeFrequencies() {
|
||||||
|
const weekDays = [
|
||||||
|
"Monday",
|
||||||
|
"Tuesday",
|
||||||
|
"Wednesday",
|
||||||
|
"Thursday",
|
||||||
|
"Friday",
|
||||||
|
"Saturday",
|
||||||
|
"Sunday",
|
||||||
|
];
|
||||||
|
const maxDays = 28;
|
||||||
|
|
||||||
|
/** @param {number} day */
|
||||||
|
function getOrdinalDay(day) {
|
||||||
|
const rest = (day % 30) % 20;
|
||||||
|
|
||||||
|
return `${day}${
|
||||||
|
rest === 1 ? "st" : rest === 2 ? "nd" : rest === 3 ? "rd" : "th"
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @satisfies {([Frequency, Frequencies, Frequencies, Frequencies])} */
|
||||||
|
const list = [
|
||||||
|
{
|
||||||
|
name: "Every day",
|
||||||
|
value: "every-day",
|
||||||
|
/** @param {Date} _ */
|
||||||
|
isTriggerDay(_) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Once a week",
|
||||||
|
list: weekDays.map((day, index) => ({
|
||||||
|
name: day,
|
||||||
|
value: day.toLowerCase(),
|
||||||
|
/** @param {Date} date */
|
||||||
|
isTriggerDay(date) {
|
||||||
|
let day = date.getUTCDay() - 1;
|
||||||
|
if (day === -1) {
|
||||||
|
day = 6;
|
||||||
|
}
|
||||||
|
return day === index;
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Every two weeks",
|
||||||
|
list: [...Array(Math.round(maxDays / 2)).keys()].map((day) => {
|
||||||
|
const day1 = day + 1;
|
||||||
|
const day2 = day + 15;
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: `${day1}+${day2}`,
|
||||||
|
name: `The ${getOrdinalDay(day1)} and the ${getOrdinalDay(day2)}`,
|
||||||
|
/** @param {Date} date */
|
||||||
|
isTriggerDay(date) {
|
||||||
|
const d = date.getUTCDate();
|
||||||
|
return d === day1 || d === day2;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Once a month",
|
||||||
|
list: [...Array(maxDays).keys()].map((day) => {
|
||||||
|
day++;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: `The ${getOrdinalDay(day)}`,
|
||||||
|
value: String(day),
|
||||||
|
/** @param {Date} date */
|
||||||
|
isTriggerDay(date) {
|
||||||
|
const d = date.getUTCDate();
|
||||||
|
return d === day;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @type {Record<string, Frequency>} */
|
||||||
|
const idToFrequency = {};
|
||||||
|
|
||||||
|
list.forEach((anyFreq, index) => {
|
||||||
|
if ("list" in anyFreq) {
|
||||||
|
anyFreq.list?.forEach((freq) => {
|
||||||
|
idToFrequency[freq.value] = freq;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
idToFrequency[anyFreq.value] = anyFreq;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const serde = {
|
||||||
|
/**
|
||||||
|
* @param {Frequency} v
|
||||||
|
*/
|
||||||
|
serialize(v) {
|
||||||
|
return v.value;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @param {string} v
|
||||||
|
*/
|
||||||
|
deserialize(v) {
|
||||||
|
const freq = idToFrequency[v];
|
||||||
|
if (!freq) throw "Freq not found";
|
||||||
|
return freq;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return { list, serde };
|
||||||
|
}
|
||||||
|
|
||||||
const frequencies = computeFrequencies();
|
const frequencies = computeFrequencies();
|
||||||
|
|
||||||
const keyPrefix = "save-in-bitcoin";
|
const keyPrefix = "save-in-bitcoin";
|
||||||
@@ -437,6 +553,7 @@ export function init({
|
|||||||
kind: "static",
|
kind: "static",
|
||||||
scale: "date",
|
scale: "date",
|
||||||
utils,
|
utils,
|
||||||
|
consts,
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
unit: "US Dollars",
|
unit: "US Dollars",
|
||||||
@@ -478,6 +595,7 @@ export function init({
|
|||||||
scale: "date",
|
scale: "date",
|
||||||
kind: "static",
|
kind: "static",
|
||||||
utils,
|
utils,
|
||||||
|
consts,
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
unit: "US Dollars",
|
unit: "US Dollars",
|
||||||
@@ -501,6 +619,7 @@ export function init({
|
|||||||
scale: "date",
|
scale: "date",
|
||||||
kind: "static",
|
kind: "static",
|
||||||
utils,
|
utils,
|
||||||
|
consts,
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
unit: "US Dollars",
|
unit: "US Dollars",
|
||||||
@@ -530,6 +649,7 @@ export function init({
|
|||||||
scale: "date",
|
scale: "date",
|
||||||
kind: "static",
|
kind: "static",
|
||||||
utils,
|
utils,
|
||||||
|
consts,
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
unit: "US Dollars",
|
unit: "US Dollars",
|
||||||
@@ -563,6 +683,7 @@ export function init({
|
|||||||
scale: "date",
|
scale: "date",
|
||||||
utils,
|
utils,
|
||||||
owner,
|
owner,
|
||||||
|
consts,
|
||||||
config: [
|
config: [
|
||||||
{
|
{
|
||||||
unit: "Percentage",
|
unit: "Percentage",
|
||||||
@@ -879,117 +1000,3 @@ export function init({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {number} day */
|
|
||||||
function getOrdinalDay(day) {
|
|
||||||
const rest = (day % 30) % 20;
|
|
||||||
|
|
||||||
return `${day}${
|
|
||||||
rest === 1 ? "st" : rest === 2 ? "nd" : rest === 3 ? "rd" : "th"
|
|
||||||
}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function computeFrequencies() {
|
|
||||||
const weekDays = [
|
|
||||||
"Monday",
|
|
||||||
"Tuesday",
|
|
||||||
"Wednesday",
|
|
||||||
"Thursday",
|
|
||||||
"Friday",
|
|
||||||
"Saturday",
|
|
||||||
"Sunday",
|
|
||||||
];
|
|
||||||
const maxDays = 28;
|
|
||||||
|
|
||||||
/** @satisfies {([Frequency, Frequencies, Frequencies, Frequencies])} */
|
|
||||||
const list = [
|
|
||||||
{
|
|
||||||
name: "Every day",
|
|
||||||
value: "every-day",
|
|
||||||
/** @param {Date} _ */
|
|
||||||
isTriggerDay(_) {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Once a week",
|
|
||||||
list: weekDays.map((day, index) => ({
|
|
||||||
name: day,
|
|
||||||
value: day.toLowerCase(),
|
|
||||||
/** @param {Date} date */
|
|
||||||
isTriggerDay(date) {
|
|
||||||
let day = date.getUTCDay() - 1;
|
|
||||||
if (day === -1) {
|
|
||||||
day = 6;
|
|
||||||
}
|
|
||||||
return day === index;
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Every two weeks",
|
|
||||||
list: [...Array(Math.round(maxDays / 2)).keys()].map((day) => {
|
|
||||||
const day1 = day + 1;
|
|
||||||
const day2 = day + 15;
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: `${day1}+${day2}`,
|
|
||||||
name: `The ${getOrdinalDay(day1)} and the ${getOrdinalDay(day2)}`,
|
|
||||||
/** @param {Date} date */
|
|
||||||
isTriggerDay(date) {
|
|
||||||
const d = date.getUTCDate();
|
|
||||||
return d === day1 || d === day2;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Once a month",
|
|
||||||
list: [...Array(maxDays).keys()].map((day) => {
|
|
||||||
day++;
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: `The ${getOrdinalDay(day)}`,
|
|
||||||
value: String(day),
|
|
||||||
/** @param {Date} date */
|
|
||||||
isTriggerDay(date) {
|
|
||||||
const d = date.getUTCDate();
|
|
||||||
return d === day;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @type {Record<string, Frequency>} */
|
|
||||||
const idToFrequency = {};
|
|
||||||
|
|
||||||
list.forEach((anyFreq, index) => {
|
|
||||||
if ("list" in anyFreq) {
|
|
||||||
anyFreq.list?.forEach((freq) => {
|
|
||||||
idToFrequency[freq.value] = freq;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
idToFrequency[anyFreq.value] = anyFreq;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const serde = {
|
|
||||||
/**
|
|
||||||
* @param {Frequency} v
|
|
||||||
*/
|
|
||||||
serialize(v) {
|
|
||||||
return v.value;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @param {string} v
|
|
||||||
*/
|
|
||||||
deserialize(v) {
|
|
||||||
const freq = idToFrequency[v];
|
|
||||||
if (!freq) throw "Freq not found";
|
|
||||||
return freq;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return { list, serde };
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user