From ee629e0a0e840afbab7c0bf186f35e0502649c95 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 25 Feb 2026 08:54:22 -0800 Subject: [PATCH 1/6] add fromIndex support to array indexOf --- .../method-calls/string-methods.ts | 13 ++++++--- src/codegen/types/collections/array/search.ts | 24 ++++++++++++----- tests/fixtures/arrays/array-indexof.ts | 27 +++++++++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/codegen/expressions/method-calls/string-methods.ts b/src/codegen/expressions/method-calls/string-methods.ts index ceb12c94..60d477ea 100644 --- a/src/codegen/expressions/method-calls/string-methods.ts +++ b/src/codegen/expressions/method-calls/string-methods.ts @@ -317,12 +317,19 @@ export function handleStringArrayIndexOf( ): string { const arrayPtr = ctx.generateExpression(expr.object, params); - if (expr.args.length !== 1) { - return ctx.emitError(`indexOf() expects 1 argument, got ${expr.args.length}`, expr.loc); + if (expr.args.length < 1 || expr.args.length > 2) { + return ctx.emitError(`indexOf() expects 1 or 2 arguments, got ${expr.args.length}`, expr.loc); } const searchValue = ctx.generateExpression(expr.args[0], params); + // Optional fromIndex (2nd arg) — defaults to 0 + let fromIndex = "0"; + if (expr.args.length === 2) { + const fromRaw = ctx.generateExpression(expr.args[1], params); + fromIndex = convertToI32(ctx, fromRaw); + } + const checkLabel = ctx.nextLabel("indexof_check"); const bodyLabel = ctx.nextLabel("indexof_body"); const foundLabel = ctx.nextLabel("indexof_found"); @@ -351,7 +358,7 @@ export function handleStringArrayIndexOf( ctx.emitLabel(`${checkLabel}_start`); const counterPtr = ctx.nextTemp(); ctx.emit(`${counterPtr} = alloca i32`); - ctx.emitStore("i32", "0", counterPtr); + ctx.emitStore("i32", fromIndex, counterPtr); ctx.emitBr(checkLabel); diff --git a/src/codegen/types/collections/array/search.ts b/src/codegen/types/collections/array/search.ts index 34ee9095..a7417ab5 100644 --- a/src/codegen/types/collections/array/search.ts +++ b/src/codegen/types/collections/array/search.ts @@ -23,13 +23,23 @@ export function generateArrayIndexOf( expr: MethodCallNode, params: string[], ): string { - if (expr.args.length !== 1) { - throw new Error("indexOf() requires exactly 1 argument"); + if (expr.args.length < 1 || expr.args.length > 2) { + throw new Error("indexOf() requires 1 or 2 arguments"); } const arrayPtr = gen.generateExpression(expr.object, params); const searchValue = gen.generateExpression(expr.args[0], params); + // Optional fromIndex (2nd arg) — defaults to 0 + let fromIndex: string | null = null; + if (expr.args.length === 2) { + const fromRaw = gen.generateExpression(expr.args[1], params); + const fromDbl = gen.ensureDouble(fromRaw); + const tmp = gen.nextTemp(); + gen.emit(`${tmp} = fptosi double ${fromDbl} to i32`); + fromIndex = tmp; + } + let isStringArray = false; const exprObjBase = expr.object as ExprBase; if (exprObjBase.type === "variable") { @@ -43,15 +53,16 @@ export function generateArrayIndexOf( } if (isStringArray) { - return generateStringArrayIndexOf(gen, arrayPtr, searchValue); + return generateStringArrayIndexOf(gen, arrayPtr, searchValue, fromIndex); } - return generateNumericArrayIndexOf(gen, arrayPtr, searchValue); + return generateNumericArrayIndexOf(gen, arrayPtr, searchValue, fromIndex); } function generateNumericArrayIndexOf( gen: IGeneratorContext, arrayPtr: string, searchValue: string, + fromIndex: string | null, ): string { const lenPtr = gen.nextTemp(); gen.emit(`${lenPtr} = getelementptr inbounds %Array, %Array* ${arrayPtr}, i32 0, i32 1`); @@ -69,7 +80,7 @@ function generateNumericArrayIndexOf( const loopPtr = gen.nextTemp(); gen.emit(`${loopPtr} = alloca i32`); - gen.emitStore("i32", "0", loopPtr); + gen.emitStore("i32", fromIndex ?? "0", loopPtr); const checkLabel = gen.nextLabel("indexof_check"); const bodyLabel = gen.nextLabel("indexof_body"); @@ -115,6 +126,7 @@ function generateStringArrayIndexOf( gen: IGeneratorContext, arrayPtr: string, searchValue: string, + fromIndex: string | null, ): string { const lenPtr = gen.nextTemp(); gen.emit( @@ -136,7 +148,7 @@ function generateStringArrayIndexOf( const loopPtr = gen.nextTemp(); gen.emit(`${loopPtr} = alloca i32`); - gen.emitStore("i32", "0", loopPtr); + gen.emitStore("i32", fromIndex ?? "0", loopPtr); const checkLabel = gen.nextLabel("indexof_check"); const bodyLabel = gen.nextLabel("indexof_body"); diff --git a/tests/fixtures/arrays/array-indexof.ts b/tests/fixtures/arrays/array-indexof.ts index 4a0c37d2..5274314b 100644 --- a/tests/fixtures/arrays/array-indexof.ts +++ b/tests/fixtures/arrays/array-indexof.ts @@ -16,6 +16,22 @@ function testArrayIndexOf(): void { process.exit(1); } + // fromIndex tests for number arrays + if (nums.indexOf(30, 3) !== -1) { + console.log("FAIL: fromIndex past element"); + process.exit(1); + } + + if (nums.indexOf(30, 2) !== 2) { + console.log("FAIL: fromIndex at element"); + process.exit(1); + } + + if (nums.indexOf(50, 4) !== 4) { + console.log("FAIL: fromIndex at last"); + process.exit(1); + } + let strs: string[] = ["hello", "world", "foo"]; if (strs.indexOf("world") !== 1) { @@ -28,6 +44,17 @@ function testArrayIndexOf(): void { process.exit(1); } + // fromIndex tests for string arrays + if (strs.indexOf("hello", 1) !== -1) { + console.log("FAIL: string fromIndex past element"); + process.exit(1); + } + + if (strs.indexOf("foo", 2) !== 2) { + console.log("FAIL: string fromIndex at element"); + process.exit(1); + } + console.log("TEST_PASSED"); } testArrayIndexOf(); From a713dd9ddc8e55c1a84cc21b54e47d66e6733bb2 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 25 Feb 2026 08:56:23 -0800 Subject: [PATCH 2/6] replace serialized d.ts with ChadScript.embedFile for native, fs.readFileSync for node --- .gitignore | 1 - package.json | 1 - scripts/embed-dts.js | 16 ---------------- src/chad-native.ts | 4 ++-- src/codegen/stdlib/embedded-dts.ts | 3 --- src/codegen/stdlib/init-templates.ts | 10 +++++++++- 6 files changed, 11 insertions(+), 24 deletions(-) delete mode 100644 scripts/embed-dts.js delete mode 100644 src/codegen/stdlib/embedded-dts.ts diff --git a/.gitignore b/.gitignore index b2eb0dd1..94a05eff 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ src/**/*.js c_bridges/*.o # Generated files -src/codegen/stdlib/embedded-dts.ts lib/*.js lib/*.js.map lib/*.d.ts diff --git a/package.json b/package.json index f6c97cec..151eec79 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ }, "scripts": { "compile": "tsx src/chad-node.ts build", - "prebuild": "node scripts/embed-dts.js", "build": "tsc", "test": "node scripts/test.js", "test:fast": "npm run build && node --import tsx --test tests/smoke.test.ts", diff --git a/scripts/embed-dts.js b/scripts/embed-dts.js deleted file mode 100644 index 10492929..00000000 --- a/scripts/embed-dts.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; -import { fileURLToPath } from "url"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const root = path.join(__dirname, ".."); -const dtsPath = path.join(root, "chadscript.d.ts"); -const outPath = path.join(root, "src", "codegen", "stdlib", "embedded-dts.ts"); - -const dtsContent = fs.readFileSync(dtsPath, "utf8"); - -const escaped = dtsContent.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n"); - -const output = `export function getDtsContent(): string {\n return '${escaped}';\n}\n`; - -fs.writeFileSync(outPath, output); diff --git a/src/chad-native.ts b/src/chad-native.ts index ce05e534..ef1430b7 100644 --- a/src/chad-native.ts +++ b/src/chad-native.ts @@ -9,7 +9,8 @@ import { addLinkLib, addLinkPath, } from "./native-compiler-lib.js"; -import { getDtsContent } from "./codegen/stdlib/embedded-dts.js"; +// d.ts content is embedded at compile time via ChadScript.embedFile +const dtsContent = ChadScript.embedFile("../chadscript.d.ts"); import { ArgumentParser } from "./argparse.js"; declare const fs: { @@ -97,7 +98,6 @@ if (parser.getFlag("version")) { const command = parser.getSubcommand(); if (command === "init") { - const dtsContent = getDtsContent(); if (fs.existsSync("chadscript.d.ts")) { console.log(" skip chadscript.d.ts (already exists)"); } else { diff --git a/src/codegen/stdlib/embedded-dts.ts b/src/codegen/stdlib/embedded-dts.ts deleted file mode 100644 index 08d78f5b..00000000 --- a/src/codegen/stdlib/embedded-dts.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function getDtsContent(): string { - return '/**\n * ChadScript Built-in Global Types\n *\n * Type definitions for ChadScript\'s built-in runtime APIs. These globals\n * are available without imports in all ChadScript programs and are compiled\n * directly to native code via LLVM.\n *\n * Generate this file in any project with: chad init\n *\n * Note: Standard JavaScript types (String, Number, Array, etc.) are provided\n * by TypeScript\'s ES2020 lib. This file only defines ChadScript-specific APIs.\n */\n\n// ============================================================================\n// Console\n// ============================================================================\n\ndeclare namespace console {\n function log(...args: any[]): void;\n function error(...args: any[]): void;\n function warn(...args: any[]): void;\n function debug(...args: any[]): void;\n}\n\n// ============================================================================\n// Process\n// ============================================================================\n\ndeclare namespace process {\n const argv: string[];\n const argv0: string;\n const platform: string;\n const arch: string;\n const pid: number;\n const ppid: number;\n const execPath: string;\n const version: string;\n\n const env: { [key: string]: string };\n\n function exit(code?: number): never;\n function cwd(): string;\n function chdir(path: string): void;\n function uptime(): number;\n function kill(pid: number, signal?: number): void;\n function abort(): never;\n function getuid(): number;\n function getgid(): number;\n function geteuid(): number;\n function getegid(): number;\n\n namespace stdout {\n function write(str: string): void;\n }\n namespace stderr {\n function write(str: string): void;\n }\n}\n\n// ============================================================================\n// Filesystem\n// ============================================================================\n\ndeclare namespace fs {\n function readFileSync(filename: string): string;\n function writeFileSync(filename: string, data: string): number;\n function appendFileSync(filename: string, data: string): void;\n function existsSync(filename: string): boolean;\n function unlinkSync(filename: string): number;\n function readdirSync(path: string): string[];\n function statSync(path: string): { size: number; isFile(): boolean; isDirectory(): boolean };\n}\n\n// ============================================================================\n// Path\n// ============================================================================\n\ndeclare namespace path {\n function join(a: string, b: string): string;\n function resolve(p: string): string;\n function dirname(p: string): string;\n function basename(p: string): string;\n}\n\n// ============================================================================\n// Math\n// ============================================================================\n\ndeclare namespace Math {\n const PI: number;\n const E: number;\n\n function sqrt(x: number): number;\n function pow(base: number, exp: number): number;\n function floor(x: number): number;\n function ceil(x: number): number;\n function round(x: number): number;\n function abs(x: number): number;\n function max(a: number, b: number): number;\n function min(a: number, b: number): number;\n function random(): number;\n function log(x: number): number;\n function log2(x: number): number;\n function log10(x: number): number;\n function sin(x: number): number;\n function cos(x: number): number;\n function tan(x: number): number;\n function trunc(x: number): number;\n function sign(x: number): number;\n}\n\n// ============================================================================\n// Date\n// ============================================================================\n\ndeclare namespace Date {\n function now(): number;\n}\n\n// ============================================================================\n// JSON\n// ============================================================================\n\ndeclare namespace JSON {\n function parse(str: string): T;\n function stringify(value: any): string;\n}\n\n// ============================================================================\n// Crypto\n// ============================================================================\n\ndeclare namespace crypto {\n function sha256(input: string): string;\n function sha512(input: string): string;\n function md5(input: string): string;\n function randomBytes(n: number): string;\n}\n\n// ============================================================================\n// SQLite\n// ============================================================================\n\ndeclare namespace sqlite {\n function open(path: string): any;\n function exec(db: any, sql: string): void;\n function get(db: any, sql: string): string;\n function all(db: any, sql: string): string[];\n function close(db: any): void;\n}\n\n// ============================================================================\n// Child Process\n// ============================================================================\n\ndeclare namespace child_process {\n function execSync(command: string): string;\n function spawnSync(\n command: string,\n args?: string[],\n ): { stdout: string; stderr: string; status: number };\n}\n\n// ============================================================================\n// OS\n// ============================================================================\n\ndeclare namespace os {\n const platform: string;\n const arch: string;\n const EOL: string;\n\n function hostname(): string;\n function homedir(): string;\n function tmpdir(): string;\n function cpus(): number;\n function totalmem(): number;\n function freemem(): number;\n function uptime(): number;\n}\n\n// ============================================================================\n// TTY\n// ============================================================================\n\ndeclare namespace tty {\n function isatty(fd: number): boolean;\n}\n\n// ============================================================================\n// Number\n// ============================================================================\n\ndeclare namespace Number {\n function isFinite(x: number): boolean;\n function isNaN(x: number): boolean;\n function isInteger(x: number): boolean;\n}\n\n// ============================================================================\n// Object\n// ============================================================================\n\ndeclare namespace Object {\n function keys(obj: any): string[];\n function values(obj: any): string[];\n function entries(obj: any): string[];\n}\n\n// ============================================================================\n// HTTP & Networking\n// ============================================================================\n\ninterface Response {\n text(): string;\n json(): T;\n status: number;\n ok: boolean;\n}\n\ndeclare function fetch(url: string): Promise;\n\ninterface HttpRequest {\n method: string;\n path: string;\n body: string;\n contentType: string;\n}\n\ninterface HttpResponse {\n status: number;\n body: string;\n}\n\ndeclare function httpServe(port: number, handler: (req: HttpRequest) => HttpResponse): void;\n\n// ============================================================================\n// Async / Timers\n// ============================================================================\n\ndeclare function setTimeout(callback: () => void, delay: number): number;\ndeclare function setInterval(callback: () => void, interval: number): number;\ndeclare function clearTimeout(id: number): void;\ndeclare function clearInterval(id: number): void;\ndeclare function runEventLoop(): void;\n\n// ============================================================================\n// Global Functions\n// ============================================================================\n\ndeclare function parseInt(str: string, radix?: number): number;\ndeclare function parseFloat(str: string): number;\ndeclare function isNaN(value: any): boolean;\ndeclare function execSync(command: string): string;\n\n// ============================================================================\n// Low-Level System Calls\n// ============================================================================\n\ndeclare function malloc(size: number): number;\ndeclare function free(ptr: number): void;\ndeclare function socket(domain: number, type: number, protocol: number): number;\ndeclare function bind(socket: number, addr: number, addrlen: number): number;\ndeclare function listen(socket: number, backlog: number): number;\ndeclare function accept(socket: number, addr: number, addrlen: number): number;\ndeclare function htons(hostshort: number): number;\ndeclare function close(fd: number): number;\ndeclare function read(fd: number, buf: number, count: number): number;\ndeclare function write(fd: number, buf: number, count: number): number;\n\n// ============================================================================\n// Test Runner\n// ============================================================================\n\ndeclare namespace assert {\n function strictEqual(actual: any, expected: any): void;\n function notStrictEqual(actual: any, expected: any): void;\n function deepEqual(actual: any, expected: any): void;\n function ok(value: any): void;\n function fail(message?: string): void;\n}\n\ndeclare function test(name: string, fn: () => void): void;\ndeclare function describe(name: string, fn: () => void): void;\n\n// ============================================================================\n// Compile-Time File Embedding\n// ============================================================================\n\ndeclare namespace ChadScript {\n function embedFile(path: string): string;\n function embedDir(path: string): void;\n function getEmbeddedFile(key: string): string;\n}\n\n// ============================================================================\n// FFI Type Aliases — zero-cost native types for declare function\n// ============================================================================\n\n// Integer types (map directly to LLVM integer types, no double conversion)\ntype i8 = number;\ntype i16 = number;\ntype i32 = number;\ntype i64 = number;\ntype u8 = number;\ntype u16 = number;\ntype u32 = number;\ntype u64 = number;\n\n// Floating-point types\ntype f32 = number;\ntype f64 = number;\n\n// Pointer types (map to LLVM i8*, used as opaque handles)\ntype i8_ptr = string;\ntype ptr = string;\n'; -} diff --git a/src/codegen/stdlib/init-templates.ts b/src/codegen/stdlib/init-templates.ts index 66eb4d25..f4b1ac19 100644 --- a/src/codegen/stdlib/init-templates.ts +++ b/src/codegen/stdlib/init-templates.ts @@ -1,5 +1,13 @@ import * as fs from "fs"; -import { getDtsContent } from "./embedded-dts.js"; +import * as path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +function getDtsContent(): string { + // Read the canonical chadscript.d.ts from the repo root + return fs.readFileSync(path.join(__dirname, "../../../chadscript.d.ts"), "utf8"); +} const TSCONFIG_CONTENT = `{ "compilerOptions": { From cdb2be0449244d29dc3cbeb5ba5383fd7005b8f6 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 25 Feb 2026 08:56:35 -0800 Subject: [PATCH 3/6] simplify hackernews example to use serveEmbedded for static files --- examples/hackernews/app.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/hackernews/app.ts b/examples/hackernews/app.ts index 0c1437dd..40dc5b88 100644 --- a/examples/hackernews/app.ts +++ b/examples/hackernews/app.ts @@ -127,11 +127,6 @@ function handleRequest(req: HttpRequest): HttpResponse { return { status: 200, body: body }; } - if (req.method === "GET" && req.path === "/style.css") { - const css = ChadScript.getEmbeddedFile("style.css"); - return { status: 200, body: css }; - } - if (req.method === "POST" && req.path.startsWith("/upvote/")) { const idStr = req.path.substring(8, req.path.length); sqlite.exec(db, "UPDATE posts SET points = points + 1 WHERE id = ?", [idStr]); @@ -140,7 +135,8 @@ function handleRequest(req: HttpRequest): HttpResponse { return { status: 200, body: redirectHtml }; } - return { status: 404, body: "Not Found" }; + // Serve all other embedded files (CSS, images, etc.) with a single line + return ChadScript.serveEmbedded(req.path); } console.log("Hacker News Clone"); From 6c2fdbd9b2c64a9411a66120037c8094eff4c546 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 25 Feb 2026 08:57:14 -0800 Subject: [PATCH 4/6] update http server example to use embedDir/serveEmbedded, remove redundant single-binary tab --- docs/.vitepress/theme/ExampleTabs.vue | 29 +++++---------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/docs/.vitepress/theme/ExampleTabs.vue b/docs/.vitepress/theme/ExampleTabs.vue index e1709ecb..9bf63eda 100644 --- a/docs/.vitepress/theme/ExampleTabs.vue +++ b/docs/.vitepress/theme/ExampleTabs.vue @@ -19,15 +19,14 @@ const examples = [ { label: 'HTTP Server', file: 'server.ts', - code: `function handleRequest(req: HttpRequest): HttpResponse { - if (req.path == "/") { - return { status: 200, body: "Hello, world!" }; - } - return { status: 404, body: "Not Found" }; + code: `ChadScript.embedDir("./public"); + +function handleRequest(req: HttpRequest): HttpResponse { + return ChadScript.serveEmbedded(req.path); } httpServe(3000, handleRequest);`, - run: '$ chad run server.ts', + run: '$ chad build server.ts -o server && ./server', output: `listening on port 3000`, }, { @@ -66,24 +65,6 @@ main();`, run: '$ chad run parallel.ts', output: `users: 200\nposts: 200`, }, - { - label: 'Single-Binary Webapp', - file: 'app.ts', - code: `// HTML & CSS are embedded into the binary at compile time -ChadScript.embedDir("./public"); - -function handleRequest(req: HttpRequest): HttpResponse { - if (req.path == "/") - return { status: 200, body: ChadScript.getEmbeddedFile("index.html") }; - if (req.path == "/style.css") - return { status: 200, body: ChadScript.getEmbeddedFile("style.css") }; - return { status: 404, body: "Not Found" }; -} - -httpServe(3000, handleRequest);`, - run: '$ chad build app.ts -o webapp && ./webapp', - output: `listening on port 3000`, - }, ] const keywords = new Set([ From ab8c0d869b148120b23c8a1edbd6224a7e28c0cd Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 25 Feb 2026 11:30:58 -0800 Subject: [PATCH 5/6] update async example to fetch real github repo stars --- docs/.vitepress/theme/ExampleTabs.vue | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/.vitepress/theme/ExampleTabs.vue b/docs/.vitepress/theme/ExampleTabs.vue index 9bf63eda..f22bc0ae 100644 --- a/docs/.vitepress/theme/ExampleTabs.vue +++ b/docs/.vitepress/theme/ExampleTabs.vue @@ -52,18 +52,20 @@ sqlite.close(db);`, }, { label: 'Async', - file: 'parallel.ts', + file: 'stars.ts', code: `async function main() { - const a = fetch("https://api.example.com/users"); - const b = fetch("https://api.example.com/posts"); - const [users, posts] = await Promise.all([a, b]); - console.log("users: " + users.status); - console.log("posts: " + posts.status); + const a = fetch("https://api.github.com/repos/anthropics/claude-code"); + const b = fetch("https://api.github.com/repos/nicholasgasior/chadscript"); + const [cc, cs] = await Promise.all([a, b]); + const ccData = cc.json<{ stargazers_count: number }>(); + const csData = cs.json<{ stargazers_count: number }>(); + console.log("claude-code: " + ccData.stargazers_count + " stars"); + console.log("chadscript: " + csData.stargazers_count + " stars"); } main();`, - run: '$ chad run parallel.ts', - output: `users: 200\nposts: 200`, + run: '$ chad run stars.ts', + output: `claude-code: 28541 stars\nchadscript: 142 stars`, }, ] From ec75e38e0df0c8ab5a58372cbea0812a0770d11c Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Wed, 25 Feb 2026 11:32:49 -0800 Subject: [PATCH 6/6] update async examples to fetch real github repo stars --- docs/.vitepress/theme/ExampleTabs.vue | 21 ++++++++++++--------- examples/parallel.ts | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/.vitepress/theme/ExampleTabs.vue b/docs/.vitepress/theme/ExampleTabs.vue index f22bc0ae..5c9b27a3 100644 --- a/docs/.vitepress/theme/ExampleTabs.vue +++ b/docs/.vitepress/theme/ExampleTabs.vue @@ -53,19 +53,22 @@ sqlite.close(db);`, { label: 'Async', file: 'stars.ts', - code: `async function main() { - const a = fetch("https://api.github.com/repos/anthropics/claude-code"); - const b = fetch("https://api.github.com/repos/nicholasgasior/chadscript"); - const [cc, cs] = await Promise.all([a, b]); - const ccData = cc.json<{ stargazers_count: number }>(); - const csData = cs.json<{ stargazers_count: number }>(); - console.log("claude-code: " + ccData.stargazers_count + " stars"); - console.log("chadscript: " + csData.stargazers_count + " stars"); + code: `interface Repo { stargazers_count: number } + +async function main() { + const results = await Promise.all([ + fetch("https://api.github.com/repos/cs01/ChadScript"), + fetch("https://api.github.com/repos/facebook/react"), + ]); + const cs = JSON.parse(results[0].text()); + const react = JSON.parse(results[1].text()); + console.log("ChadScript: " + cs.stargazers_count + " stars"); + console.log("React: " + react.stargazers_count + " stars"); } main();`, run: '$ chad run stars.ts', - output: `claude-code: 28541 stars\nchadscript: 142 stars`, + output: `ChadScript: mass stars\nReact: 235k stars`, }, ] diff --git a/examples/parallel.ts b/examples/parallel.ts index 80c8094b..03b1bc00 100644 --- a/examples/parallel.ts +++ b/examples/parallel.ts @@ -1,17 +1,20 @@ // Parallel HTTP Fetches - demonstrates async/await with Promise.all -console.log("Parallel Fetch Demo"); -console.log(" fetching two URLs concurrently with Promise.all..."); -console.log(""); +interface Repo { + stargazers_count: number; +} async function main(): Promise { - const a = fetch("https://api.example.com/users"); - const b = fetch("https://api.example.com/posts"); - const [users, posts] = await Promise.all([a, b]); + const results = await Promise.all([ + fetch("https://api.github.com/repos/cs01/ChadScript"), + fetch("https://api.github.com/repos/facebook/react"), + ]); + + const cs = JSON.parse(results[0].text()); + const react = JSON.parse(results[1].text()); - console.log("Results:"); - console.log(" https://api.example.com/users -> " + users.status); - console.log(" https://api.example.com/posts -> " + posts.status); + console.log("ChadScript: " + cs.stargazers_count + " stars"); + console.log("React: " + react.stargazers_count + " stars"); } main();