@shd101wyy/yo 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shd101wyy/yo",
3
3
  "displayName": "Yo",
4
- "version": "0.1.13",
4
+ "version": "0.1.14",
5
5
  "main": "./out/cjs/index.cjs",
6
6
  "module": "./out/esm/index.mjs",
7
7
  "types": "./out/types/src/index.d.ts",
@@ -75,6 +75,42 @@ function escapeHtml(s: string): string {
75
75
  * - `https://shd101wyy.github.io/Yo/` → `std/index.html` (relative, same site)
76
76
  * - `#anchor` links → kept as-is
77
77
  */
78
+ /**
79
+ * Generate a GitHub-compatible slug from heading text.
80
+ * - Strip HTML tags
81
+ * - Lowercase
82
+ * - Replace spaces with hyphens
83
+ * - Remove non-alphanumeric characters (except hyphens)
84
+ */
85
+ function slugify(text: string): string {
86
+ return text
87
+ .replace(/<[^>]+>/g, "") // strip HTML tags
88
+ .trim()
89
+ .toLowerCase()
90
+ .replace(/\s+/g, "-")
91
+ .replace(/[^a-z0-9-]/g, "")
92
+ .replace(/-+/g, "-")
93
+ .replace(/^-|-$/g, "");
94
+ }
95
+
96
+ /**
97
+ * Add `id` attributes to heading elements so that #anchor links work.
98
+ * Handles duplicate slugs by appending `-1`, `-2`, etc.
99
+ */
100
+ function injectHeadingIds(html: string): string {
101
+ const slugCounts = new Map<string, number>();
102
+ return html.replace(
103
+ /<(h[1-6])>([\s\S]*?)<\/\1>/gi,
104
+ (_match: string, tag: string, content: string) => {
105
+ let slug = slugify(content);
106
+ const count = slugCounts.get(slug) ?? 0;
107
+ slugCounts.set(slug, count + 1);
108
+ if (count > 0) slug = `${slug}-${count}`;
109
+ return `<${tag} id="${slug}">${content}</${tag}>`;
110
+ }
111
+ );
112
+ }
113
+
78
114
  function rewriteReadmeLinks(html: string): string {
79
115
  // Rewrite the generated docs link to relative std/ path (same site)
80
116
  html = html.replace(
@@ -383,6 +419,7 @@ async function main(): Promise<void> {
383
419
  });
384
420
 
385
421
  let readmeHtml = md.render(readmeSrc);
422
+ readmeHtml = injectHeadingIds(readmeHtml);
386
423
  readmeHtml = rewriteReadmeLinks(readmeHtml);
387
424
 
388
425
  const css = generateHomepageCSS();
package/std/build.yo CHANGED
@@ -18,13 +18,17 @@
18
18
 
19
19
  /// Optimization level for compiled artifacts.
20
20
  Optimize :: enum(
21
- /// No optimizations, full debug info.
21
+ /// No optimizations, full debug info.
22
+ /// Compiler Flags: `-O0 -g`
22
23
  Debug,
23
- /// Optimized with safety checks.
24
+ /// Optimized with safety checks.
25
+ /// Compiler Flags: `-O2 -g`
24
26
  ReleaseSafe,
25
- /// Maximum speed optimizations.
27
+ /// Maximum speed optimizations.
28
+ /// Compiler Flags: `-O3`
26
29
  ReleaseFast,
27
- /// Optimize for binary size.
30
+ /// Optimize for binary size.
31
+ /// Compiler Flags `-O2`
28
32
  ReleaseSmall
29
33
  );
30
34
  export Optimize;
@@ -1,10 +1,13 @@
1
1
  //! Base64 encoding and decoding (RFC 4648) with standard and URL-safe variants.
2
2
  //!
3
- //! Example:
4
- //! { base64_encode, base64_decode } :: import "std/encoding/base64";
3
+ //! # Example
5
4
  //!
6
- //! s := base64_encode(data);
7
- //! b := base64_decode(s.to_str()).unwrap();
5
+ //! ```rust
6
+ //! { base64_encode, base64_decode } :: import "std/encoding/base64";
7
+ //!
8
+ //! s := base64_encode(data);
9
+ //! b := base64_decode(s.to_str()).unwrap();
10
+ //! ```
8
11
 
9
12
  open import "../string";
10
13
  { ArrayList } :: import "../collections/array_list";
@@ -2,11 +2,14 @@
2
2
  //!
3
3
  //! Converts between raw bytes (`ArrayList(u8)`) and hex strings.
4
4
  //!
5
- //! Example:
6
- //! { hex_encode, hex_decode } :: import "std/encoding/hex";
5
+ //! # Example
7
6
  //!
8
- //! s := hex_encode(data); // "deadbeef"
9
- //! b := hex_decode("deadbeef");
7
+ //! ```rust
8
+ //! { hex_encode, hex_decode } :: import "std/encoding/hex";
9
+ //!
10
+ //! s := hex_encode(data); // "deadbeef"
11
+ //! b := hex_decode("deadbeef");
12
+ //! ```
10
13
 
11
14
  open import "../string";
12
15
  { ArrayList } :: import "../collections/array_list";
@@ -3,11 +3,14 @@
3
3
  //! Decodes named (&amp;), decimal (&#38;), and hex (&#x26;) HTML character references.
4
4
  //! Uses Legacy mode — entities without trailing semicolon are also decoded.
5
5
  //!
6
- //! Example:
7
- //! { decode_html } :: import "std/encoding/html";
6
+ //! # Example
8
7
  //!
9
- //! result := decode_html(`&amp; &lt; &#38; &#x26;`);
10
- //! assert((result == `& < & &`), "decoded entities");
8
+ //! ```rust
9
+ //! { decode_html } :: import "std/encoding/html";
10
+ //!
11
+ //! result := decode_html(`&amp; &lt; &#38; &#x26;`);
12
+ //! assert((result == `& < & &`), "decoded entities");
13
+ //! ```
11
14
 
12
15
  open import "../string";
13
16
  { HashMap } :: import "../collections/hash_map";
@@ -2,13 +2,16 @@
2
2
  //!
3
3
  //! Provides a dynamically-typed JSON value tree.
4
4
  //!
5
- //! Example:
6
- //! { json_parse, json_stringify, JsonValue } :: import "std/encoding/json";
7
- //! { Exception } :: import "std/error";
5
+ //! # Example
8
6
  //!
9
- //! given(exn) := Exception(throw : ((err) -> { escape (); }));
10
- //! v := json_parse(`{"x": 1}`);
11
- //! println(json_stringify(v));
7
+ //! ```rust
8
+ //! { json_parse, json_stringify, JsonValue } :: import "std/encoding/json";
9
+ //! { Exception } :: import "std/error";
10
+ //!
11
+ //! given(exn) := Exception(throw : ((err) -> { escape (); }));
12
+ //! v := json_parse(`{"x": 1}`);
13
+ //! println(json_stringify(v));
14
+ //! ```
12
15
 
13
16
  open import "../string";
14
17
  { ArrayList } :: import "../collections/array_list";
@@ -2,13 +2,16 @@
2
2
  //!
3
3
  //! Provides punycode encoding/decoding and IDN hostname conversion.
4
4
  //!
5
- //! Example:
6
- //! { punycode_decode, punycode_encode, to_unicode, to_ascii } :: import "std/encoding/punycode";
5
+ //! # Example
7
6
  //!
8
- //! encoded := punycode_encode(`München`);
9
- //! decoded := punycode_decode(encoded);
10
- //! ascii_domain := to_ascii(`münchen.de`); // "xn--mnchen-3ya.de"
11
- //! unicode_domain := to_unicode(ascii_domain); // "münchen.de"
7
+ //! ```rust
8
+ //! { punycode_decode, punycode_encode, to_unicode, to_ascii } :: import "std/encoding/punycode";
9
+ //!
10
+ //! encoded := punycode_encode(`München`);
11
+ //! decoded := punycode_decode(encoded);
12
+ //! ascii_domain := to_ascii(`münchen.de`); // "xn--mnchen-3ya.de"
13
+ //! unicode_domain := to_unicode(ascii_domain); // "münchen.de"
14
+ //! ```
12
15
 
13
16
  open import "../string";
14
17
  { ArrayList } :: import "../collections/array_list";
@@ -3,10 +3,13 @@
3
3
  //! Parses a subset of TOML into a `TomlValue` tree.
4
4
  //! Supports: strings, integers, booleans, table sections, comments.
5
5
  //!
6
- //! Example:
7
- //! { toml_parse, TomlValue } :: import "std/encoding/toml";
8
- //! // Or via the encoding index:
9
- //! { toml_parse, TomlValue } :: import "std/encoding";
6
+ //! # Example
7
+ //!
8
+ //! ```rust
9
+ //! { toml_parse, TomlValue } :: import "std/encoding/toml";
10
+ //! // Or via the encoding index:
11
+ //! { toml_parse, TomlValue } :: import "std/encoding";
12
+ //! ```
10
13
 
11
14
  open import "../string";
12
15
  { ArrayList } :: import "../collections/array_list";
@@ -2,11 +2,14 @@
2
2
  //!
3
3
  //! Converts between Yo's UTF-8 `str` and UTF-16 code units (`ArrayList(u16)`).
4
4
  //!
5
- //! Example:
6
- //! { utf8_to_utf16, utf16_to_utf8 } :: import "std/encoding/utf16";
5
+ //! # Example
7
6
  //!
8
- //! words := utf8_to_utf16("hello");
9
- //! s := utf16_to_utf8(words);
7
+ //! ```rust
8
+ //! { utf8_to_utf16, utf16_to_utf8 } :: import "std/encoding/utf16";
9
+ //!
10
+ //! words := utf8_to_utf16("hello");
11
+ //! s := utf16_to_utf8(words);
12
+ //! ```
10
13
 
11
14
  open import "../string";
12
15
  { ArrayList } :: import "../collections/array_list";
package/std/fs/dir.yo CHANGED
@@ -2,21 +2,24 @@
2
2
  //!
3
3
  //! Wraps low-level `std/sys/dir` with typed APIs using the `Exception` effect.
4
4
  //!
5
- //! Example:
6
- //! { create_dir, remove_dir, read_dir } :: import "std/fs/dir";
7
- //! { Path } :: import "std/path";
5
+ //! # Example
8
6
  //!
9
- //! main :: (fn(using(io : IO)) -> unit)({
10
- //! given(exn) : Exception = {
11
- //! throw : (fn(forall(T : Type), error: AnyError) -> T)(
12
- //! { println(error.to_string()); exit(i32(1)); }
13
- //! )
14
- //! };
7
+ //! ```rust
8
+ //! { create_dir, remove_dir, read_dir } :: import "std/fs/dir";
9
+ //! { Path } :: import "std/path";
15
10
  //!
16
- //! io.await(create_dir(Path.new(`/tmp/yo_test`)));
17
- //! entries := io.await(read_dir(Path.new(`/tmp/yo_test`)));
18
- //! io.await(remove_dir(Path.new(`/tmp/yo_test`)));
19
- //! });
11
+ //! main :: (fn(using(io : IO)) -> unit)({
12
+ //! given(exn) : Exception = {
13
+ //! throw : (fn(forall(T : Type), error: AnyError) -> T)(
14
+ //! { println(error.to_string()); exit(i32(1)); }
15
+ //! )
16
+ //! };
17
+ //!
18
+ //! io.await(create_dir(Path.new(`/tmp/yo_test`)));
19
+ //! entries := io.await(read_dir(Path.new(`/tmp/yo_test`)));
20
+ //! io.await(remove_dir(Path.new(`/tmp/yo_test`)));
21
+ //! });
22
+ //! ```
20
23
 
21
24
  { GlobalAllocator } :: import "../allocator";
22
25
  { malloc, free } :: GlobalAllocator;
package/std/fs/file.yo CHANGED
@@ -3,26 +3,29 @@
3
3
  //! Wraps a file descriptor with typed async I/O operations.
4
4
  //! Uses the `Exception` effect for error handling.
5
5
  //!
6
- //! Example:
7
- //! { File, read_string, write_file, OpenMode } :: import "std/fs/file";
6
+ //! # Example
8
7
  //!
9
- //! main :: (fn(using(io : IO)) -> unit)({
10
- //! given(exn) := Exception(
11
- //! throw : (fn(forall(T : Type), error: AnyError) -> T)(
12
- //! { println(error); panic("Exception found."); }
13
- //! )
14
- //! );
8
+ //! ```rust
9
+ //! { File, read_string, write_file, OpenMode } :: import "std/fs/file";
15
10
  //!
16
- //! // Write a file
17
- //! io.await(write_file(Path.new(`test.txt`), `hello world`));
11
+ //! main :: (fn(using(io : IO)) -> unit)({
12
+ //! given(exn) := Exception(
13
+ //! throw : (fn(forall(T : Type), error: AnyError) -> T)(
14
+ //! { println(error); panic("Exception found."); }
15
+ //! )
16
+ //! );
18
17
  //!
19
- //! // Read it back
20
- //! content := io.await(read_string(Path.new(`test.txt`)));
21
- //! println(content);
18
+ //! // Write a file
19
+ //! io.await(write_file(Path.new(`test.txt`), `hello world`));
22
20
  //!
23
- //! // Open with OpenMode
24
- //! f := io.await(File.open(Path.new(`test.txt`), .Read));
25
- //! });
21
+ //! // Read it back
22
+ //! content := io.await(read_string(Path.new(`test.txt`)));
23
+ //! println(content);
24
+ //!
25
+ //! // Open with OpenMode
26
+ //! f := io.await(File.open(Path.new(`test.txt`), .Read));
27
+ //! });
28
+ //! ```
26
29
 
27
30
  { GlobalAllocator } :: import "../allocator";
28
31
  { malloc, free } :: GlobalAllocator;
@@ -245,9 +245,12 @@ _read_http_response :: (fn(stream: TcpStream, using(io : IO, exn : Exception)) -
245
245
 
246
246
  /// Perform an HTTP request with custom options.
247
247
  ///
248
- /// Example:
249
- /// opts := FetchOptions.new().with_method(.POST).with_body(`{"key": "value"}`);
250
- /// resp := io.await(fetch_with(`http://example.com/api`, opts, using(io)));
248
+ /// # Example
249
+ ///
250
+ /// ```rust
251
+ /// opts := FetchOptions.new().with_method(.POST).with_body(`{"key": "value"}`);
252
+ /// resp := io.await(fetch_with(`http://example.com/api`, opts, using(io)));
253
+ /// ```
251
254
  fetch_with :: (fn(url_str: String, opts: FetchOptions, using(io : IO)) ->
252
255
  Impl(Future(HttpResponse, IO, Exception))
253
256
  )(
@@ -359,9 +362,12 @@ export fetch_with;
359
362
  /// Perform an HTTP GET request to the given URL string.
360
363
  /// Returns the `HttpResponse` on success.
361
364
  ///
362
- /// Example:
363
- /// resp := io.await(fetch(`http://example.com`, using(io)));
364
- /// cond(resp.is_ok() => println(resp.body), true => println(`Error`));
365
+ /// # Example
366
+ ///
367
+ /// ```rust
368
+ /// resp := io.await(fetch(`http://example.com`, using(io)));
369
+ /// cond(resp.is_ok() => println(resp.body), true => println(`Error`));
370
+ /// ```
365
371
  fetch :: (fn(url_str: String, using(io : IO)) ->
366
372
  Impl(Future(HttpResponse, IO, Exception))
367
373
  )(