Skip to content

Commit

Permalink
Merge pull request #50 from mistlog/feature/context
Browse files Browse the repository at this point in the history
feature: support context type
  • Loading branch information
mistlog committed Oct 30, 2021
2 parents b1709c3 + 7c80e5f commit 9902c3d
Show file tree
Hide file tree
Showing 26 changed files with 312 additions and 21 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "@mistlog/typetype",
"version": "0.0.29",
"version": "0.0.30",
"description": "A programming language designed for typescript type generation",
"keywords": [
"peg",
Expand All @@ -17,8 +17,8 @@
"type": "git",
"url": "https://github.com/mistlog/typetype"
},
"main": "build/index.js",
"types": "build/index.d.ts",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"files": [
"build"
],
Expand All @@ -42,6 +42,6 @@
"fs-extra": "^9.1.0",
"node-watch": "^0.7.1",
"pegjs-backtrace": "^0.2.0",
"react-peg": "^0.1.7"
"react-peg": "^0.1.8"
}
}
9 changes: 6 additions & 3 deletions src/core/core.tsx
@@ -1,29 +1,32 @@
import { ReactPeg } from "react-peg";
import { TypeFile } from "../parser";
import { ITypeFile, TypeFile } from "../parser";
import { TSFile } from "../generator";
import generate from "@babel/generator";
import { default as Tracer } from "pegjs-backtrace";
import { IRenderConfig } from "react-peg/build/renderer/renderer";

export interface ITypeTypeConfig {
debug?: boolean
context?: any
}

export interface ITypeTypeResult {
code: string
ast: ITypeFile
}

export function transform(source: string, config: ITypeTypeConfig = { debug: false }): ITypeTypeResult {
export function transform(source: string, config: ITypeTypeConfig = { debug: false, context: {} }): ITypeTypeResult {
const tracer = new Tracer(source, { useColor: false });
const options: IRenderConfig = { tracer: config.debug ? tracer : null };
const parser = ReactPeg.render(<TypeFile />, options);
try {
const ast = parser.parse(source);
const ast = parser.parse(source, config.context);
const tsFile = TSFile(ast);
const code = generate(tsFile).code;

const result: ITypeTypeResult = {
code,
ast
}

return result;
Expand Down
17 changes: 16 additions & 1 deletion src/generator/generator.ts
@@ -1,6 +1,6 @@

import * as t from "@babel/types";
import { IInferType, IIdentifier, ITypeExpression, ITypeIfStatement, IStringTypeLiteral, IStringType, INeverType, ITypeReference, ITypeCallExpression, INumberTypeLiteral, ITupleType, INumberType, IConditionalTypeExpression, ITemplateTypeLiteral, ITypeFile, IDeclaration, ITypeFunctionDeclaration, IUnionType, IKeyOfType, IIndexType, IArrayType, IFunctionType, IMappedTypeExpression, ITypeForInStatement, IIntersectionType, ITypeObjectProperty, IAnyType, IReadonlyArray, IOperatorType, IReadonlyTuple, IRestType, IObjectTypeLiteral, ITypeArrowFunctionExpression, ITypeExpressionParam, IParamList, IBigIntType, IImportDeclaration, ITypeVariableDeclaration, IParenthesizedType, ICallSignature, IFunctionTypeParam, IConstructSignature } from "../parser";
import { IInferType, IIdentifier, ITypeExpression, ITypeIfStatement, IStringTypeLiteral, IStringType, INeverType, ITypeReference, ITypeCallExpression, INumberTypeLiteral, ITupleType, INumberType, IConditionalTypeExpression, ITemplateTypeLiteral, ITypeFile, ITypeFunctionDeclaration, IUnionType, IKeyOfType, IIndexType, IArrayType, IFunctionType, IMappedTypeExpression, ITypeForInStatement, IIntersectionType, ITypeObjectProperty, IAnyType, IReadonlyArray, IOperatorType, IReadonlyTuple, IRestType, IObjectTypeLiteral, ITypeArrowFunctionExpression, ITypeExpressionParam, IParamList, IBigIntType, IImportDeclaration, ITypeVariableDeclaration, IParenthesizedType, ICallSignature, IFunctionTypeParam, IConstructSignature, IContextType } from "../parser";

export function TSFile(ast: ITypeFile): t.File {
const body = ast.body.map(each => {
Expand Down Expand Up @@ -63,6 +63,9 @@ function tsCallSignature(ast: ITypeObjectProperty) {
function tsPropertySignature(ast: ITypeObjectProperty) {
const key = Identifier(ast.name as IIdentifier);
const value = TSType(ast.value);
if (/\s/g.test(key.name)) {
key.name = `"${key.name}"`;
}
const prop = t.tsPropertySignature(key, t.tsTypeAnnotation(value));
return {
...prop,
Expand All @@ -77,6 +80,13 @@ function tsTypeLiteral(ast: IObjectTypeLiteral) {
case "TypeObjectProperty": {
switch (each.name.kind) {
case "Identifier": return tsPropertySignature(each);
case "StringLiteral": return tsPropertySignature({
...each,
name: {
kind: "Identifier",
name: each.name.value
}
});
case "CallSignature": return tsCallSignature(each);
case "ConstructSignature": return tsConstrucSignature(each);
}
Expand Down Expand Up @@ -248,6 +258,7 @@ type TypeInTS<T extends ITypeType> =
Kind<T> extends Kind<IStringTypeLiteral> ? t.TSLiteralType :
Kind<T> extends Kind<INumberTypeLiteral> ? t.TSLiteralType :
Kind<T> extends Kind<ITemplateTypeLiteral> ? t.TemplateLiteral :
Kind<T> extends Kind<IContextType> ? t.TSTupleType :
/**
*/
Kind<T> extends Kind<IStringType> ? t.TSStringKeyword :
Expand Down Expand Up @@ -291,6 +302,10 @@ export function TSType(ast: ITypeType): TypeInTS<typeof ast> {
type: "TSLiteralType",
literal: templateLiteral(ast)
} as any as t.TSLiteralType; /** TODO: use t.tsLiteralType to create it */
case "ContextType": return t.tsTupleType([
t.tsLiteralType(t.stringLiteral(ast.body.context)),
t.tsLiteralType(t.stringLiteral(ast.body.source)),
]);
/**
*/
case "StringType": return t.tsStringKeyword();
Expand Down
22 changes: 21 additions & 1 deletion src/parser/basic/basic-type.tsx
Expand Up @@ -229,6 +229,25 @@ export function Number() {
);
}

export interface IStringLiteral {
kind: "StringLiteral"
value: string
}

export function StringLiteral() {
const action = ({ value }): IStringLiteral => {
return {
kind: "StringLiteral",
value
}
}
return (
<pattern action={action}>
<String label="value" />
</pattern>
)
}

export interface IStringTypeLiteral {
kind: "StringTypeLiteral"
value: string
Expand Down Expand Up @@ -471,7 +490,7 @@ export function RestType() {

export interface ITypeObjectProperty {
kind: "TypeObjectProperty"
name: IIdentifier | ICallSignature | IConstructSignature
name: IIdentifier | ICallSignature | IConstructSignature | IStringLiteral
value: ITypeExpression
readonly: boolean
optional: boolean
Expand Down Expand Up @@ -502,6 +521,7 @@ export function TypeObjectProperty() {
<or label="name">
<ConstructSignature />
<CallSignature />
<StringLiteral />
<Identifier />
</or>
<opt label="optional">
Expand Down
3 changes: 2 additions & 1 deletion src/parser/basic/index.ts
@@ -1,3 +1,4 @@
export * from "./basic-type";
export * from "./identifier";
export * from "./comment";
export * from "./comment";
export * from "./string";
18 changes: 18 additions & 0 deletions src/parser/basic/string.tsx
Expand Up @@ -7,6 +7,24 @@ export function SourceCharacter() {
)
}

export function Source() {
const action = ({ chars }) => {
return chars.map((each: [undefined, string]) => each[1]).join("");
}

return (
<pattern action={action}>
<repeat type="*" label="chars">
<assert type="without">
<text>```</text>
</assert>
<SourceCharacter />
</repeat>
</pattern>

)
}

/**
* string-literal:
encoding-prefixopt" s-char-sequenceopt"
Expand Down
35 changes: 34 additions & 1 deletion src/parser/expression/expression.tsx
@@ -1,6 +1,6 @@
import { ReactPeg } from "react-peg";
import { _, Text } from "../common";
import { IBasicType, BasicType, ITypeReference, TypeReference, IIdentifier, Identifier, IArrayType, ArrayType, ITupleType, TupleType, RestType } from "../basic";
import { String, IBasicType, BasicType, ITypeReference, TypeReference, IIdentifier, Identifier, IArrayType, ArrayType, ITupleType, TupleType, RestType, Source } from "../basic";
import { ITypeForInStatement, ITypeIfStatement, TypeForInStatement, TypeIfStatement } from "../statement";
import { FunctionType, IFunctionType } from "../function";

Expand All @@ -17,10 +17,12 @@ export type ITypeExpression =
| IIndexType
| IFunctionType
| IParenthesizedType
| IContextType

export function TypeExpression() {
return (
<or>
<ContextType />
<ParenthesizedType />
<FunctionType />
<OperatorType />
Expand Down Expand Up @@ -419,4 +421,35 @@ export function MappedTypeExpression() {
{Text("}")}
</pattern>
)
}

export interface IContextType {
kind: "ContextType"
body: {
context: string
source: string
}
}

export function ContextType() {
const action = ({ context, source, globalContext }): IContextType => {
const ast: IContextType = {
kind: "ContextType",
body: {
context,
source
}
};

return globalContext.resolveContextType ? globalContext.resolveContextType(ast) : ast;
}

return (
<pattern action={action}>
{Text("```")}
<String label="context" />
<Source label="source" />
{Text("```")}
</pattern>
)
}
6 changes: 2 additions & 4 deletions test/__snapshots__/core.test.ts.snap
@@ -1,14 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`transform 1`] = `
Object {
"code": "import { Temp } from \\"./temp\\";
"import { Temp } from \\"./temp\\";
type temp = string;
type func<T> = {
a: T;
b: Temp;
};",
}
};"
`;
exports[`transform: backtrace 1`] = `
Expand Down
8 changes: 8 additions & 0 deletions test/__snapshots__/generator.test.ts.snap
Expand Up @@ -10,6 +10,8 @@ exports[`declaration TypeVariableDeclaration 1`] = `"type result = string;"`;
exports[`declaration TypeVariableDeclaration: conditional type 1`] = `"type result = string extends string ? string : number;"`;
exports[`declaration TypeVariableDeclaration: context type 1`] = `"type result = [\\"use js\\", \\"() => {\\\\n const type = \\\\\\"1\\\\\\";\\\\n return type;\\\\n }\\\\n \\"];"`;
exports[`declaration TypeVariableDeclaration: export 1`] = `"export type result = string;"`;
exports[`declaration TypeVariableDeclaration: function 1`] = `"type result = (a: number, b: string) => void;"`;
Expand Down Expand Up @@ -144,6 +146,12 @@ exports[`ts-type ObjectType: spread 1`] = `
}, obj]>"
`;
exports[`ts-type ObjectType: whitespace in key 1`] = `
"{
\\"temp value\\": number;
}"
`;
exports[`ts-type ParenthesizedType 1`] = `"((value: number) => void)"`;
exports[`ts-type StringTypeLiteral 1`] = `"\\"\\\\n\\""`;
Expand Down
25 changes: 25 additions & 0 deletions test/__snapshots__/parser.test.tsx.snap
Expand Up @@ -1546,6 +1546,31 @@ Object {
}
`;

exports[`TypeVariableDeclaration: context type 1`] = `
Object {
"declarator": Object {
"initializer": Object {
"body": Object {
"context": "use js",
"source": "() => {
const type = \\"1\\";
return type;
}
",
},
"kind": "ContextType",
},
"kind": "TypeVariableDeclarator",
"name": Object {
"kind": "Identifier",
"name": "result",
},
},
"export": false,
"kind": "TypeVariableDeclaration",
}
`;

exports[`TypeVariableDeclaration: export 1`] = `
Object {
"declarator": Object {
Expand Down
7 changes: 7 additions & 0 deletions test/assets/ast/ContextExpression.json
@@ -0,0 +1,7 @@
{
"kind": "ContextType",
"body": {
"context": "use js",
"source": "const type = \"1\";\r\nreturn type;\r\n\r\n"
}
}
7 changes: 7 additions & 0 deletions test/assets/ast/ContextType.json
@@ -0,0 +1,7 @@
{
"kind": "ContextType",
"body": {
"context": "use js",
"source": "const type = \"1\";\r\nreturn type;\r\n\r\n"
}
}
4 changes: 4 additions & 0 deletions test/assets/ast/ContextType2.json
@@ -0,0 +1,4 @@
{
"kind": "StringTypeLiteral",
"value": "resolved"
}
18 changes: 18 additions & 0 deletions test/assets/ast/ObjectType-Key-WhiteSpace.json
@@ -0,0 +1,18 @@
{
"kind": "ObjectTypeLiteral",
"props": [
{
"kind": "TypeObjectProperty",
"name": {
"kind": "StringLiteral",
"value": "temp value"
},
"value": {
"kind": "NumberType",
"value": "number"
},
"optional": false,
"readonly": false
}
]
}

0 comments on commit 9902c3d

Please sign in to comment.