@shd101wyy/yo 0.1.13 → 0.1.15

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.
Files changed (42) hide show
  1. package/README.md +40 -1
  2. package/out/cjs/index.cjs +514 -514
  3. package/out/cjs/yo-cli.cjs +809 -686
  4. package/out/cjs/yo-lsp.cjs +11635 -0
  5. package/out/esm/index.mjs +359 -359
  6. package/out/types/src/cache.d.ts +2 -0
  7. package/out/types/src/doc/extractor.d.ts +4 -0
  8. package/out/types/src/doc/render-html.d.ts +5 -1
  9. package/out/types/src/evaluator/values/impl.d.ts +9 -1
  10. package/out/types/src/lsp/completion.d.ts +3 -0
  11. package/out/types/src/lsp/definition.d.ts +3 -0
  12. package/out/types/src/lsp/diagnostics.d.ts +6 -0
  13. package/out/types/src/lsp/document-manager.d.ts +31 -0
  14. package/out/types/src/lsp/folding.d.ts +3 -0
  15. package/out/types/src/lsp/hover.d.ts +3 -0
  16. package/out/types/src/lsp/inlay-hints.d.ts +3 -0
  17. package/out/types/src/lsp/references.d.ts +3 -0
  18. package/out/types/src/lsp/rename.d.ts +16 -0
  19. package/out/types/src/lsp/server.d.ts +1 -0
  20. package/out/types/src/lsp/signature-help.d.ts +3 -0
  21. package/out/types/src/lsp/symbols.d.ts +3 -0
  22. package/out/types/src/lsp/utils.d.ts +11 -0
  23. package/out/types/src/tests/lsp.test.d.ts +1 -0
  24. package/out/types/src/tests/version.test.d.ts +1 -0
  25. package/out/types/src/types/definitions.d.ts +2 -0
  26. package/out/types/src/version-cache.d.ts +7 -0
  27. package/out/types/src/version.d.ts +5 -0
  28. package/out/types/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +3 -1
  30. package/scripts/build-site.ts +69 -15
  31. package/scripts/check-liburing.js +2 -2
  32. package/std/build.yo +8 -4
  33. package/std/encoding/base64.yo +7 -4
  34. package/std/encoding/hex.yo +7 -4
  35. package/std/encoding/html.yo +7 -4
  36. package/std/encoding/json.yo +9 -6
  37. package/std/encoding/punycode.yo +9 -6
  38. package/std/encoding/toml.yo +7 -4
  39. package/std/encoding/utf16.yo +7 -4
  40. package/std/fs/dir.yo +16 -13
  41. package/std/fs/file.yo +19 -16
  42. package/std/http/client.yo +12 -6
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.15",
5
5
  "main": "./out/cjs/index.cjs",
6
6
  "module": "./out/esm/index.mjs",
7
7
  "types": "./out/types/src/index.d.ts",
@@ -48,6 +48,8 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "markdown_yo": "0.0.4",
51
+ "vscode-languageserver": "^9.0.1",
52
+ "vscode-languageserver-textdocument": "^1.0.12",
51
53
  "yargs": "^17.7.2"
52
54
  },
53
55
  "devDependencies": {
@@ -20,18 +20,19 @@ import * as fs from "fs";
20
20
  import * as path from "path";
21
21
  import { createRenderer } from "markdown_yo";
22
22
  import type { MarkdownRenderer } from "markdown_yo";
23
- import { execSync } from "child_process";
23
+ import { execFileSync } from "child_process";
24
24
 
25
25
  const ROOT = path.resolve(import.meta.dir, "..");
26
26
  const GITHUB_REPO = "https://github.com/shd101wyy/Yo";
27
27
 
28
28
  // Detect the latest release tag for stable links.
29
29
  // Falls back to "main" if no tags exist or git fails.
30
- function getLatestTag(): string {
30
+ export function getLatestTag(rootDir: string = ROOT): string {
31
31
  try {
32
- const result = execSync("git describe --tags --abbrev=0 2>/dev/null", {
33
- cwd: ROOT,
32
+ const result = execFileSync("git", ["describe", "--tags", "--abbrev=0"], {
33
+ cwd: rootDir,
34
34
  encoding: "utf-8",
35
+ stdio: ["ignore", "pipe", "ignore"],
35
36
  timeout: 5000,
36
37
  }).trim();
37
38
  return result || "main";
@@ -43,6 +44,16 @@ function getLatestTag(): string {
43
44
  const GITHUB_REF = getLatestTag();
44
45
  const GITHUB_BLOB = `${GITHUB_REPO}/blob/${GITHUB_REF}`;
45
46
 
47
+ export function getStdDocCommand(rootDir: string = ROOT): {
48
+ command: string;
49
+ args: string[];
50
+ } {
51
+ return {
52
+ command: "node",
53
+ args: [path.join(rootDir, "out", "cjs", "yo-cli.cjs"), "doc", "std/"],
54
+ };
55
+ }
56
+
46
57
  // ── Parse args ───────────────────────────────────────────────────────
47
58
 
48
59
  let outputDir = path.join(ROOT, "site");
@@ -75,6 +86,42 @@ function escapeHtml(s: string): string {
75
86
  * - `https://shd101wyy.github.io/Yo/` → `std/index.html` (relative, same site)
76
87
  * - `#anchor` links → kept as-is
77
88
  */
89
+ /**
90
+ * Generate a GitHub-compatible slug from heading text.
91
+ * - Strip HTML tags
92
+ * - Lowercase
93
+ * - Replace spaces with hyphens
94
+ * - Remove non-alphanumeric characters (except hyphens)
95
+ */
96
+ function slugify(text: string): string {
97
+ return text
98
+ .replace(/<[^>]+>/g, "") // strip HTML tags
99
+ .trim()
100
+ .toLowerCase()
101
+ .replace(/\s+/g, "-")
102
+ .replace(/[^a-z0-9-]/g, "")
103
+ .replace(/-+/g, "-")
104
+ .replace(/^-|-$/g, "");
105
+ }
106
+
107
+ /**
108
+ * Add `id` attributes to heading elements so that #anchor links work.
109
+ * Handles duplicate slugs by appending `-1`, `-2`, etc.
110
+ */
111
+ function injectHeadingIds(html: string): string {
112
+ const slugCounts = new Map<string, number>();
113
+ return html.replace(
114
+ /<(h[1-6])>([\s\S]*?)<\/\1>/gi,
115
+ (_match: string, tag: string, content: string) => {
116
+ let slug = slugify(content);
117
+ const count = slugCounts.get(slug) ?? 0;
118
+ slugCounts.set(slug, count + 1);
119
+ if (count > 0) slug = `${slug}-${count}`;
120
+ return `<${tag} id="${slug}">${content}</${tag}>`;
121
+ }
122
+ );
123
+ }
124
+
78
125
  function rewriteReadmeLinks(html: string): string {
79
126
  // Rewrite the generated docs link to relative std/ path (same site)
80
127
  html = html.replace(
@@ -363,7 +410,7 @@ function injectHomeLinks(stdDir: string): void {
363
410
 
364
411
  // ── Main ─────────────────────────────────────────────────────────────
365
412
 
366
- async function main(): Promise<void> {
413
+ export async function main(): Promise<void> {
367
414
  console.log("Building documentation site...");
368
415
  console.log(` Output: ${outputDir}`);
369
416
 
@@ -383,6 +430,7 @@ async function main(): Promise<void> {
383
430
  });
384
431
 
385
432
  let readmeHtml = md.render(readmeSrc);
433
+ readmeHtml = injectHeadingIds(readmeHtml);
386
434
  readmeHtml = rewriteReadmeLinks(readmeHtml);
387
435
 
388
436
  const css = generateHomepageCSS();
@@ -412,12 +460,16 @@ async function main(): Promise<void> {
412
460
  const stdOutputDir = path.join(outputDir, "std");
413
461
 
414
462
  try {
415
- const yoCli = path.join(ROOT, "yo-cli");
416
- execSync(`${yoCli} doc std/ --output "${stdOutputDir}"`, {
417
- cwd: ROOT,
418
- stdio: ["pipe", "pipe", "inherit"],
419
- timeout: 120_000,
420
- });
463
+ const stdDocCommand = getStdDocCommand();
464
+ execFileSync(
465
+ stdDocCommand.command,
466
+ [...stdDocCommand.args, "--output", stdOutputDir],
467
+ {
468
+ cwd: ROOT,
469
+ stdio: ["ignore", "inherit", "inherit"],
470
+ timeout: 600_000,
471
+ }
472
+ );
421
473
  console.log(" ✓ Standard library docs generated");
422
474
  } catch (err) {
423
475
  console.error(
@@ -455,7 +507,9 @@ function getTotalSize(dir: string): number {
455
507
  return Math.round(total / 1024);
456
508
  }
457
509
 
458
- main().catch((err) => {
459
- console.error("Fatal error:", err);
460
- process.exit(1);
461
- });
510
+ if (import.meta.main) {
511
+ main().catch((err) => {
512
+ console.error("Fatal error:", err);
513
+ process.exit(1);
514
+ });
515
+ }
@@ -9,9 +9,9 @@ const fs = require("fs");
9
9
  function checkLiburing() {
10
10
  const platform = os.platform();
11
11
 
12
- // Only check on Linux
12
+ // Only check on Linux. Other platforms don't use io_uring, so keep postinstall
13
+ // quiet instead of printing a Linux-specific note.
13
14
  if (platform !== "linux") {
14
- console.log("ℹ️ Async I/O with io_uring is only supported on Linux.");
15
15
  return;
16
16
  }
17
17
 
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
  )(