MCPcopy Index your code
hub / github.com/ariesclark/tanu.js

github.com/ariesclark/tanu.js @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
65 symbols 145 edges 30 files 4 documented · 6%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Tanu 🦝

A simplified abstraction of the TypeScript Compiler API for defining and generating source files.

npm GitHub issues GitHub Repo stars

Why?

I've always hated the fact that the majority of packages generate TypeScript files from a ridiculously long template literal string, It's not type safe or even readable at all, and I saw a cool tweet.

Yes Matt, It does exist now.

What does Tanu mean? 🦝

Tanuki (a cute animal) but I removed the last two characters cause tanuki was already taken on npm, and sounded cool enough for me. Naming things is hard, okay?

How do I use this?

const User = t.interface("User", {
  id: t.number(),
  email: t.string(),
  name: t.optional({
    first: t.string(),
    last: t.string(),
  }),
});

const MemberRole = t.enum("MemberRole", [
  "DEFAULT",
  "PRIVILEGED",
  "ADMINISTRATOR",
]);

const Member = t.interface("Member", {
  user: User,
  role: MemberRole,
});

const Organization = t.interface("Organization", {
  name: t.comment(t.string(), [
    "The organization name.",
    "@see https://example.com/organization-name",
  ]),
  description: t.optional(t.string()),
  members: t.array(Member),
});

const result = await t.generate([User, MemberRole, Member, Organization]);
console.log(result);
// the generated result.

export interface User {
  id: number;
  email: string;
  name?:
    | {
        first: string;
        last: string;
      }
    | undefined;
}
export enum MemberRole {
  DEFAULT,
  PRIVILEGED,
  ADMINISTRATOR,
}
export interface Member {
  user: User;
  role: MemberRole;
}
export interface Organization {
  /**
   * The organization name.
   * @see https://example.com/organization-name
   */
  name: string;
  description?: string | undefined;
  members: Array<Member>;
}

What about interfaces that reference themselves, or cross-reference each other?

Passing in a callback to the t.interface method will lazily populate the interface with its returned values. This will ensure that you can self-reference or cross-reference the interface, and it will be available by generation.

import { t } from "tanu.js";

const User = t.interface("User", () => ({
  users: t.array(User),
  posts: t.array(Post),
  authoredComments: t.array(Comment),
}));

const Post = t.interface("Post", () => ({
  author: User,
  text: t.string(),
  images: t.array(t.string()),
  postComments: t.array(Comment),
}));

const Comment = t.interface("Comment", {
  author: User,
  post: Post,
  text: t.string(),
});

const CommentReply = t.type("CommentReply", () => ({
  parent: CommentReply,
  author: User,
  post: Post,
  text: t.string(),
}));

const result = await t.generate([User, Post, Comment, CommentReply]);
console.log(result);
// the generated result

export interface User {
  users: Array<User>;
  posts: Array<Post>;
  authoredComments: Array<Comment>;
}
export interface Post {
  author: User;
  text: string;
  images: Array<string>;
  postComments: Array<Comment>;
}
export interface Comment {
  author: User;
  post: Post;
  text: string;
}
export type CommentReply = {
  parent: CommentReply;
  author: User;
  post: Post;
  text: string;
};

Extension points exported contracts — how you extend this code

GenerateOptions (Interface)
(no doc)
src/generate.ts
User (Interface)
(no doc)
src/example.out.ts
TypeDefinitionObject (Interface)
(no doc)
src/type/index.ts
RuntimeDefinitionObject (Interface)
(no doc)
src/runtime/index.ts
Member (Interface)
(no doc)
src/example.out.ts
ModuleOptions (Interface)
(no doc)
src/type/declarations/module.ts
VariableStatementOptions (Interface)
(no doc)
src/runtime/statements.ts
Organization (Interface)
(no doc)
src/example.out.ts

Core symbols most depended-on inside this repo

runtimeLiteral
called by 15
src/runtime/utils.ts
toTypeNode
called by 7
src/type/utils.ts
toRuntimeNode
called by 5
src/runtime/utils.ts
reference
called by 4
src/type/index.ts
runtimeReference
called by 4
src/runtime/utils.ts
isPrimitive
called by 3
src/utils.ts
isNode
called by 3
src/utils.ts
constructType
called by 3
src/type/declarations/type.ts

Shape

Function 55
Interface 9
Enum 1

Languages

TypeScript100%

Modules by API surface

src/type/primitives/index.ts10 symbols
src/runtime/utils.ts7 symbols
src/type/utils.ts6 symbols
src/type/index.ts5 symbols
src/runtime/statements.ts5 symbols
src/example.out.ts5 symbols
src/utils.ts4 symbols
src/generate.ts4 symbols
src/type/declarations/module.ts3 symbols
src/runtime/index.ts3 symbols
src/type/declarations/type.ts2 symbols
src/type/declarations/interface.ts2 symbols

For agents

$ claude mcp add tanu.js \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact