-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(typescript): support inlined types (and initialize an AST) #4937
base: main
Are you sure you want to change the base?
Changes from 9 commits
011a6b3
c3268d4
f14a819
3148d58
e26fc6f
317470c
cac09ea
3917b09
8358c5a
d74dccc
ec83aec
083e5b8
74fb4d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { AbstractAstNode } from "@fern-api/generator-commons"; | ||
import { Writer } from "./Writer"; | ||
import * as prettier from "prettier"; | ||
|
||
export abstract class AstNode extends AbstractAstNode { | ||
/** | ||
* Writes the node to a string. | ||
*/ | ||
public toString(): string { | ||
const writer = new Writer(); | ||
this.write(writer); | ||
return writer.toString(); | ||
} | ||
|
||
public toStringFormatted(): string { | ||
return prettier.format(this.toString(), { parser: "typescript", tabWidth: 4, printWidth: 120 }); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,18 @@ | ||
import { CodeBlock as CommonCodeBlock } from "@fern-api/generator-commons"; | ||
import { AstNode, Writer } from "../typescript"; | ||
import { AbstractAstNode, CodeBlock as CommonCodeBlock } from "@fern-api/generator-commons"; | ||
import { Writer } from "./Writer"; | ||
|
||
export declare namespace CodeBlock { | ||
/* Write arbitrary code */ | ||
type Args = CommonCodeBlock.Arg<Writer>; | ||
} | ||
|
||
export class CodeBlock extends AstNode { | ||
private args: CodeBlock.Args; | ||
|
||
public constructor(args: CodeBlock.Args) { | ||
export class CodeBlock extends AbstractAstNode { | ||
public constructor(private readonly arg: CodeBlock.Args) { | ||
super(); | ||
this.args = args; | ||
} | ||
|
||
public write(writer: Writer): void { | ||
const commonCodeBlock = new CommonCodeBlock(this.args); | ||
const commonCodeBlock = new CommonCodeBlock(this.arg); | ||
return commonCodeBlock.write(writer); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { AstNode } from "./AstNode"; | ||
import { CodeBlock } from "./CodeBlock"; | ||
import { Writer } from "./Writer"; | ||
|
||
export class DocString extends AstNode { | ||
public constructor(private readonly docs: string) { | ||
super(); | ||
} | ||
|
||
public write(writer: Writer): void { | ||
if (!this.docs.includes("\n")) { | ||
writer.writeLine(`/* ${this.docs} */`); | ||
} else { | ||
writer.writeLine(`/**`); | ||
this.docs.split("\n").forEach((line) => { | ||
writer.writeLine(` * ${line}`); | ||
}); | ||
writer.writeLine(" */"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,79 @@ | ||||||
import { AstNode } from "./AstNode"; | ||||||
import { Writer } from "./Writer"; | ||||||
import { Type } from "./Type"; | ||||||
import { Reference } from "./Reference"; | ||||||
import { DocString } from "./DocString"; | ||||||
|
||||||
export declare namespace Interface { | ||||||
interface Args { | ||||||
/* Whether to export */ | ||||||
export?: boolean; | ||||||
/* The name of the variable */ | ||||||
name: string; | ||||||
/* Properties on the interface */ | ||||||
properties: Property[]; | ||||||
/* The interfaces that this extends */ | ||||||
extends?: Reference[]; | ||||||
|
||||||
docs?: string; | ||||||
} | ||||||
|
||||||
interface Property { | ||||||
/* The name of the property */ | ||||||
name: string; | ||||||
/* The type of the property */ | ||||||
type: Type; | ||||||
/* Quesiton mark */ | ||||||
questionMark?: boolean; | ||||||
|
||||||
docs?: string; | ||||||
} | ||||||
} | ||||||
|
||||||
export class Interface extends AstNode { | ||||||
public constructor(private readonly args: Interface.Args) { | ||||||
super(); | ||||||
} | ||||||
|
||||||
public write(writer: Writer): void { | ||||||
if (this.args.docs != null) { | ||||||
writer.writeNode(new DocString(this.args.docs)); | ||||||
writer.writeLine(); | ||||||
} | ||||||
if (this.args.export) { | ||||||
writer.write("export "); | ||||||
} | ||||||
writer.write(` interface ${this.args.name}`); | ||||||
if (this.args.extends != null && this.args.extends.length > 0) { | ||||||
const numBaseInterfaces = this.args.extends.length; | ||||||
|
||||||
writer.write(` extends `); | ||||||
this.args.extends.forEach((extend, idx) => { | ||||||
writer.writeNode(extend); | ||||||
if (idx < numBaseInterfaces - 1) { | ||||||
writer.write(", "); | ||||||
} else { | ||||||
writer.write(" "); | ||||||
} | ||||||
dsinghvi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
}); | ||||||
} | ||||||
|
||||||
writer.writeLine("{"); | ||||||
|
||||||
writer.indent(); | ||||||
for (const property of this.args.properties) { | ||||||
if (property.docs != null) { | ||||||
writer.writeNode(new DocString(property.docs)); | ||||||
} | ||||||
writer.write(`"${property.name}\"`); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary escape character in template string The backslash before the closing quote in the template string is unnecessary and may cause incorrect output. Update the line to remove the escape character: -writer.write(`"${property.name}\"`);
+writer.write(`"${property.name}"`); 📝 Committable suggestion
Suggested change
|
||||||
if (property.questionMark) { | ||||||
writer.write("?"); | ||||||
} | ||||||
writer.write(": "); | ||||||
writer.writeNodeStatement(property.type); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use In the context of writing property types within an interface, Update the line as follows: -writer.writeNodeStatement(property.type);
+writer.writeNode(property.type);
writer.write(";");
writer.writeLine(); This ensures that each property ends with a semicolon and that the formatting is consistent.
|
||||||
} | ||||||
writer.dedent(); | ||||||
|
||||||
writer.writeLine("}"); | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { AstNode } from "./AstNode"; | ||
import { Writer } from "./Writer"; | ||
import { Interface } from "./Interface"; | ||
|
||
export declare namespace Namespace { | ||
interface Args { | ||
/* Whether to export */ | ||
export?: boolean; | ||
/* Namespace of the name */ | ||
name?: string; | ||
} | ||
} | ||
|
||
export class Namespace extends AstNode { | ||
/** | ||
* The ordered elements inside of a namespace | ||
*/ | ||
private elements: (Interface | Namespace)[] = []; | ||
|
||
public constructor(private readonly args: Namespace.Args) { | ||
super(); | ||
} | ||
|
||
public addNamespace(interface_: Namespace): void { | ||
this.elements.push(interface_); | ||
} | ||
|
||
public addInterface(interface_: Interface): void { | ||
this.elements.push(interface_); | ||
} | ||
|
||
public write(writer: Writer): void { | ||
if (this.args.export) { | ||
writer.write("export "); | ||
} | ||
|
||
let setAmbience = false; | ||
if (!writer.isAmbient) { | ||
writer.write("declare "); | ||
writer.setAmbient(true); | ||
dsinghvi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
setAmbience = true; | ||
} | ||
|
||
writer.writeLine(`namespace ${this.args.name} {`); | ||
|
||
writer.indent(); | ||
for (const element of this.elements) { | ||
writer.writeNode(element); | ||
writer.writeLine(); | ||
writer.writeLine(); | ||
} | ||
writer.dedent(); | ||
|
||
writer.writeLine(`}`); | ||
|
||
if (setAmbience) { | ||
dsinghvi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
writer.setAmbient(false); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,56 @@ | ||||||
import { assertNever } from "@fern-api/core-utils"; | ||||||
import { AstNode } from "./AstNode"; | ||||||
import { Writer } from "./Writer"; | ||||||
|
||||||
export declare namespace Reference { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using the The Apply this diff to fix the issue: -export declare namespace Reference {
+export namespace Reference { 📝 Committable suggestion
Suggested change
|
||||||
type Args = NamedImport | ModuleImport; | ||||||
|
||||||
interface NamedImport { | ||||||
type: "named"; | ||||||
/* The package or path to import from */ | ||||||
source: string; | ||||||
/* Name of the reference to import */ | ||||||
name: string; | ||||||
} | ||||||
|
||||||
interface ModuleImport { | ||||||
type: "module"; | ||||||
/* The package or path to import from */ | ||||||
source: string; | ||||||
/* The module to import from */ | ||||||
module: string; | ||||||
/** | ||||||
* The path to access the reference from the module. | ||||||
* [module, ...name].join(".") is the reference | ||||||
*/ | ||||||
name: string[]; | ||||||
dsinghvi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
} | ||||||
|
||||||
export class Reference extends AstNode { | ||||||
private constructor(public readonly args: Reference.Args) { | ||||||
super(); | ||||||
} | ||||||
|
||||||
public write(writer: Writer): void { | ||||||
writer.addReference(this); | ||||||
switch (this.args.type) { | ||||||
case "module": | ||||||
writer.write([this.args.module, ...this.args.name].join(".")); | ||||||
break; | ||||||
case "named": | ||||||
writer.write(this.args.name); | ||||||
break; | ||||||
default: | ||||||
assertNever(this.args); | ||||||
} | ||||||
} | ||||||
|
||||||
public static module(import_: Omit<Reference.ModuleImport, "type">): Reference { | ||||||
return new Reference({ ...import_, type: "module" }); | ||||||
} | ||||||
|
||||||
public static named(import_: Omit<Reference.NamedImport, "type">): Reference { | ||||||
return new Reference({ ...import_, type: "named" }); | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typographical error in comment
There's a typo in the comment on line 23. "Quesiton" should be "Question".
Apply this diff to fix the typo:
📝 Committable suggestion