Skip to content
This repository has been archived by the owner on Sep 24, 2021. It is now read-only.

Commit

Permalink
Fixes #1 and fixes #2
Browse files Browse the repository at this point in the history
  • Loading branch information
kaleidawave committed Oct 6, 2020
1 parent 92dd5d9 commit f0f9d52
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 12 deletions.
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "@kaleidawave/prism",
"version": "1.0.2",
"version": "1.0.3",
"description": "Isomorphic web app compiler",
"main": "out/index.js",
"scripts": {
Expand Down
44 changes: 35 additions & 9 deletions src/chef/javascript/components/types/type-signature.ts
Expand Up @@ -3,10 +3,11 @@ import { JSToken } from "../../javascript";
import { tokenAsIdent } from "../value/variable";
import { IStatement } from "../statements/statement";
import { parseFunctionParams } from "../constructs/function";
import { open } from "fs";
import { literalTypes, Value } from "../value/value";

interface TypeWithArgs {
name: string,
name?: string,
value?: Value
typeArguments?: Array<TypeSignature>
}

Expand All @@ -18,8 +19,9 @@ interface FunctionSignature {
/**
* Represents a type declaration. Used by class to parse generics
*/
export class TypeSignature implements IStatement {
export class TypeSignature implements IStatement, TypeWithArgs {
name?: string;
value?: Value;
typeArguments?: Array<TypeSignature>;
functionParameters?: Map<string, TypeSignature>;
functionReturnType?: TypeSignature;
Expand All @@ -30,22 +32,26 @@ export class TypeSignature implements IStatement {
constructor(options: string | TypeWithArgs | FunctionSignature | Map<string, TypeSignature>) {
if (typeof options === "string") {
this.name = options;
} else if ("value" in options) {
this.value = options.value;
} else if ("name" in options) {
this.name = options.name;
if (options.typeArguments) this.typeArguments = options.typeArguments;
} else if (options instanceof Map) {
this.mappedTypes = options;
} else {
this.functionParameters = options.parameters;
this.functionReturnType = options.returnType;
this.functionParameters = (options as FunctionSignature).parameters;
this.functionReturnType = (options as FunctionSignature).returnType;
}
}

render(settings: IRenderSettings = defaultRenderSettings): string {
if (settings.scriptLanguage !== ScriptLanguages.Typescript) {
return "";
}
if (this.functionParameters) {
if (this.value) {
return this.value.render(settings);
} else if (this.functionParameters) {
let acc = "(";
let part = 1;
for (const [paramName, paramType] of this.functionParameters) {
Expand Down Expand Up @@ -89,6 +95,16 @@ export class TypeSignature implements IStatement {
}
}
return acc;
} else if (this.name === "Intersection") {
let acc = "";
const members = this.typeArguments!;
for (let i = 0; i < members.length; i++) {
acc += members[i].render(settings);
if (i + 1 < members.length) {
acc += " & "
}
}
return acc;
} else {
let acc = this.name!;
if (this.typeArguments) {
Expand Down Expand Up @@ -150,12 +166,15 @@ export class TypeSignature implements IStatement {
reader.expectNext(JSToken.CloseCurly);
typeSignature = new TypeSignature(members);
}

// Value
else if (literalTypes.has(reader.current.type)) {
const value: Value = Value.fromTokens(reader);
typeSignature = new TypeSignature({ value });
}
// Name
else {
let name: string;
try {
// TODO typeSignature.value if its 0 or "thing" e.g.
name = reader.current.value || tokenAsIdent(reader.current.type);
} catch {
reader.throwExpect("Expected value type signature name");
Expand Down Expand Up @@ -199,8 +218,15 @@ export class TypeSignature implements IStatement {
typeArguments.push(unionType);
}
typeSignature = new TypeSignature({ name: "Union", typeArguments });
} else if (reader.current.type as JSToken === JSToken.BitwiseAnd && !skipBar) {
const typeArguments = [typeSignature];
while (reader.current.type === JSToken.BitwiseAnd) {
reader.move();
const intersectionType = TypeSignature.fromTokens(reader, true);
typeArguments.push(intersectionType);
}
typeSignature = new TypeSignature({ name: "Intersection", typeArguments });
}

return typeSignature;
}
}
20 changes: 19 additions & 1 deletion src/chef/javascript/components/value/value.ts
@@ -1,4 +1,4 @@
import { IRenderSettings, defaultRenderSettings, IConstruct } from "../../../helpers";
import { IRenderSettings, defaultRenderSettings, IConstruct, TokenReader } from "../../../helpers";
import type { TemplateLiteral } from "./template-literal";
import type { Expression } from "./expression";
import type { ObjectLiteral } from "./object";
Expand All @@ -8,6 +8,7 @@ import type { Group } from "./group";
import type { VariableReference } from "./variable";
import type { FunctionDeclaration } from "../constructs/function";
import type { ClassDeclaration } from "../constructs/class";
import { JSToken } from "../../javascript";

// All constructs that can be used as values:
export type IValue = Value
Expand All @@ -32,6 +33,8 @@ export enum Type {
function,
}

export const literalTypes = new Set([JSToken.NumberLiteral, JSToken.StringLiteral, JSToken.True, JSToken.False]);

/**
* Represents string literals, number literals (inc bigint), boolean literals, "null" and "undefined"
*/
Expand All @@ -52,6 +55,21 @@ export class Value implements IConstruct {
}
}

static fromTokens(reader: TokenReader<JSToken>) {
let value: Value;
if (reader.current.type === JSToken.NumberLiteral) {
value = new Value(reader.current.value!, Type.number);
} else if (reader.current.type === JSToken.StringLiteral) {
value = new Value(reader.current.value!, Type.string);
} else if (reader.current.type === JSToken.True || reader.current.type === JSToken.False) {
value = new Value(reader.current.type === JSToken.True, Type.string);
} else {
throw reader.throwExpect("Expected literal value");
}
reader.move();
return value;
}

render(settings: IRenderSettings = defaultRenderSettings): string {
if (this.type === Type.string) {
// Place string value + escape double quotes
Expand Down
29 changes: 29 additions & 0 deletions tests/chef/javascript/javascript.parse.test.ts
Expand Up @@ -2025,6 +2025,35 @@ describe("Typescript", () => {
{ name: "string" },
]);
});

test("Literal types", () => {
const typeAlias = Module.fromString("type abcString = 'abc'").statements[0] as TypeStatement;

expect(typeAlias.value.value).toBeDefined();
expect(typeAlias.value.value).toBeInstanceOf(Value);
expect(typeAlias.value.value!.type).toBe(Type.string);
expect(typeAlias.value.value!.value).toBe("abc");
});

test("Union types", () => {
const typeAlias = Module.fromString("type aOrB = a | b").statements[0] as TypeStatement;

expect(typeAlias.value.name).toBe("Union");
expect(typeAlias.value.typeArguments).toMatchObject([
{ name: "a" },
{ name: "b" },
]);
});

test("Intersection types", () => {
const typeAlias = Module.fromString("type aAndBIntersection = a & b").statements[0] as TypeStatement;

expect(typeAlias.value.name).toBe("Intersection");
expect(typeAlias.value.typeArguments).toMatchObject([
{ name: "a" },
{ name: "b" },
]);
});
});
});

Expand Down
20 changes: 19 additions & 1 deletion tests/chef/javascript/javascript.render.test.ts
Expand Up @@ -747,7 +747,7 @@ describe("Type signatures", () => {
expect(ts.render(typescriptSettings)).toBe("Array<string>");
});

test("Type union", () => {
test("Union type", () => {
const ts = new TypeSignature({
name: "Union", typeArguments: [
new TypeSignature("string"),
Expand All @@ -757,6 +757,24 @@ describe("Type signatures", () => {
expect(ts.render(typescriptSettings)).toBe("string | number");
});

test("Intersection type", () => {
const ts = new TypeSignature({
name: "Intersection", typeArguments: [
new TypeSignature("a"),
new TypeSignature("b")]
});

expect(ts.render(typescriptSettings)).toBe("a & b");
});

test("Literal type", () => {
const ts = new TypeSignature({
value: new Value("abc", Type.string)
});

expect(ts.render(typescriptSettings)).toBe(`"abc"`);
});

test("Tuple type", () => {
const ts = new TypeSignature({
name: "Tuple", typeArguments: [
Expand Down

0 comments on commit f0f9d52

Please sign in to comment.