Skip to content

Commit

Permalink
Fix parsing intersection types and heritage clauses
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilafsar committed Oct 7, 2022
1 parent 097f70e commit e28c92e
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,64 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Parsers extend an intersection of two interfaces 1`] = `
"export class MyModelParser {
static parse(data: any): ParseResult<MyModel> {
const errors: ValidationError[] = [];
let result: any;
{
const intersectionResult: any = {};
{
const parseResult = CParser.parse(data);
if (!parseResult.ok) {
errors.push({
path: \\"data\\",
message: \`not a MyModel\`
});
}
else
result = parseResult.result;
}
Object.assign(intersectionResult, result);
if (typeof data !== \\"object\\" || data === null) {
errors.push({
path: \\"data\\",
message: \`null or not an object\`
});
}
else {
result = {};
if (typeof data[\\"c\\"] !== \\"number\\") {
errors.push({
path: \\"data.c\\",
message: \`not a number\`
});
}
else if (isNaN(data[\\"c\\"])) {
errors.push({
path: \\"data.c\\",
message: \`invalid number\`
});
}
else
result[\\"c\\"] = data[\\"c\\"];
}
Object.assign(intersectionResult, result);
result = intersectionResult;
}
if (errors.length) {
return {
ok: false,
errors
};
}
return {
ok: true,
result: result as MyModel
};
}
}"
`;
exports[`Parsers for an interface boolean array member 1`] = `
"export class MyModelParser {
static parse(data: any): ParseResult<MyModel> {
Expand Down
119 changes: 119 additions & 0 deletions packages/core/src/code-gen/__snapshots__/parser.typealias.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -855,12 +855,120 @@ exports[`Parsers for a type alias index types union string keys 1`] = `
}"
`;

exports[`Parsers for a type alias intersection intersection with two interfaces 1`] = `
"export class MyModelParser {
static parse(data: any): ParseResult<MyModel> {
const errors: ValidationError[] = [];
let result: any;
{
const intersectionResult: any = {};
{
const parseResult = AParser.parse(data);
if (!parseResult.ok) {
errors.push({
path: \\"data\\",
message: \`not a A\`
});
}
else
result = parseResult.result;
}
Object.assign(intersectionResult, result);
{
const parseResult = BParser.parse(data);
if (!parseResult.ok) {
errors.push({
path: \\"data\\",
message: \`not a B\`
});
}
else
result = parseResult.result;
}
Object.assign(intersectionResult, result);
result = intersectionResult;
}
if (errors.length) {
return {
ok: false,
errors
};
}
return {
ok: true,
result: result as MyModel
};
}
}"
`;

exports[`Parsers for a type alias intersection intersection with two types 1`] = `
"export class MyModelParser {
static parse(data: any): ParseResult<MyModel> {
const errors: ValidationError[] = [];
let result: any;
{
const errLength = errors.length;
{
{
const parseResult = AParser.parse(data);
if (!parseResult.ok) {
errors.push({
path: \\"data\\",
message: \`not a A\`
});
}
else
result = parseResult.result;
}
if (errors.length !== errLength) {
errors.splice(errLength, errors.length - errLength);
{
{
const parseResult = BParser.parse(data);
if (!parseResult.ok) {
errors.push({
path: \\"data\\",
message: \`not a B\`
});
}
else
result = parseResult.result;
}
if (errors.length !== errLength) {
errors.splice(errLength, errors.length - errLength);
{
errors.push({
path: \\"data\\",
message: \`is none of the options of union\`
});
}
}
}
}
}
}
if (errors.length) {
return {
ok: false,
errors
};
}
return {
ok: true,
result: result as MyModel
};
}
}"
`;

exports[`Parsers for a type alias intersection object literal with complex union 1`] = `
"export class MyModelParser {
static parse(data: any): ParseResult<MyModel> {
const errors: ValidationError[] = [];
let result: any;
{
const intersectionResult: any = {};
if (typeof data !== \\"object\\" || data === null) {
errors.push({
path: \\"data\\",
Expand All @@ -878,6 +986,7 @@ exports[`Parsers for a type alias intersection object literal with complex union
else
result[\\"a\\"] = data[\\"a\\"];
}
Object.assign(intersectionResult, result);
{
const errLength = errors.length;
{
Expand Down Expand Up @@ -962,6 +1071,8 @@ exports[`Parsers for a type alias intersection object literal with complex union
}
}
}
Object.assign(intersectionResult, result);
result = intersectionResult;
}
if (errors.length) {
return {
Expand All @@ -983,6 +1094,7 @@ exports[`Parsers for a type alias intersection object literal with union 1`] = `
const errors: ValidationError[] = [];
let result: any;
{
const intersectionResult: any = {};
if (typeof data !== \\"object\\" || data === null) {
errors.push({
path: \\"data\\",
Expand All @@ -1000,6 +1112,7 @@ exports[`Parsers for a type alias intersection object literal with union 1`] = `
else
result[\\"a\\"] = data[\\"a\\"];
}
Object.assign(intersectionResult, result);
{
const errLength = errors.length;
{
Expand Down Expand Up @@ -1059,6 +1172,8 @@ exports[`Parsers for a type alias intersection object literal with union 1`] = `
}
}
}
Object.assign(intersectionResult, result);
result = intersectionResult;
}
if (errors.length) {
return {
Expand All @@ -1080,6 +1195,7 @@ exports[`Parsers for a type alias intersection simple 1`] = `
const errors: ValidationError[] = [];
let result: any;
{
const intersectionResult: any = {};
if (typeof data !== \\"object\\" || data === null) {
errors.push({
path: \\"data\\",
Expand All @@ -1097,6 +1213,7 @@ exports[`Parsers for a type alias intersection simple 1`] = `
else
result[\\"a\\"] = data[\\"a\\"];
}
Object.assign(intersectionResult, result);
if (typeof data !== \\"object\\" || data === null) {
errors.push({
path: \\"data\\",
Expand All @@ -1114,6 +1231,8 @@ exports[`Parsers for a type alias intersection simple 1`] = `
else
result[\\"b\\"] = data[\\"b\\"];
}
Object.assign(intersectionResult, result);
result = intersectionResult;
}
if (errors.length) {
return {
Expand Down
29 changes: 28 additions & 1 deletion packages/core/src/code-gen/parser.interface.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript"
import { compileStatement, printCode } from "../tsTestUtils"
import { compileStatement, compileStatements, printCode } from "../tsTestUtils"
import generateParser from "./parsers/generateParser"

describe("Parsers", () => {
Expand Down Expand Up @@ -263,4 +263,31 @@ describe("Parsers", () => {
expect(printCode(parserDeclaration)).toMatchSnapshot()
})
})
test("extend an intersection of two interfaces", () => {
const {
statements: [model],
typeChecker,
} = compileStatements(
`
interface MyModel extends C {
c: number
}
type C = A & B
interface A {
a: number
}
interface B {
b: number
}
`,
)

const parserDeclaration = generateParser(
model as ts.TypeAliasDeclaration,
typeChecker,
)
expect(printCode(parserDeclaration)).toMatchSnapshot()
})
})
47 changes: 47 additions & 0 deletions packages/core/src/code-gen/parser.typealias.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,53 @@ describe("Parsers", () => {
const parserDeclaration = generateParser(model, typeChecker)
expect(printCode(parserDeclaration)).toMatchSnapshot()
})

test("intersection with two types", () => {
const {
statements: [model],
typeChecker,
} = compileStatements(
`
type MyModel = A | B
type A = {
a: number
}
type B = {
b: number
}
`,
)

const parserDeclaration = generateParser(
model as ts.TypeAliasDeclaration,
typeChecker,
)
expect(printCode(parserDeclaration)).toMatchSnapshot()
})
test("intersection with two interfaces", () => {
const {
statements: [model],
typeChecker,
} = compileStatements(
`
type MyModel = A & B
interface A {
a: number
}
interface B {
b: number
}
`,
)

const parserDeclaration = generateParser(
model as ts.TypeAliasDeclaration,
typeChecker,
)
expect(printCode(parserDeclaration)).toMatchSnapshot()
})
})
describe("typescript utility types", () => {
test("Pick", () => {
Expand Down
24 changes: 21 additions & 3 deletions packages/core/src/code-gen/parsers/generateIntersectionParser.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import ts from "typescript"
import * as tsx from "../../tsx"
import generateParserFromModel from "./generateParserFromModel"
import { IntersectionParserModel } from "./generateParserModel"
import Pointer from "./Pointer"

export default function generateIntersectionParser(
pointer: Pointer<IntersectionParserModel>,
): ts.Statement {
return ts.factory.createBlock(
pointer.model.parsers.map((parser) =>
return ts.factory.createBlock([
tsx.const({
name: "intersectionResult",
init: tsx.literal.object(),
type: tsx.type.any,
}),
...pointer.model.parsers.flatMap((parser) => [
generateParserFromModel(parser, pointer.path),
tsx.statement.expression(
tsx.expression.call(tsx.expression.propertyAccess("Object", "assign"), {
args: ["intersectionResult", "result"],
}),
),
]),
tsx.statement.expression(
tsx.expression.binary(
tsx.expression.identifier("result"),
"=",
tsx.expression.identifier("intersectionResult"),
),
),
)
])
}
Loading

0 comments on commit e28c92e

Please sign in to comment.