Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ jobs:
- name: Install scala
if: ${{ contains(matrix.fixture, 'scala3') }}
uses: VirtusLab/scala-cli-setup@main

- run: echo '@main def hello() = println("We need this spam print statement for bloop to exit correctly...")' | scala-cli _
if: ${{ contains(matrix.fixture, 'scala3') }}

Expand Down
159 changes: 134 additions & 25 deletions packages/quicktype-core/src/language/Scala3/CirceRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from "../../Type/TypeUtils";

import { Scala3Renderer } from "./Scala3Renderer";
import { wrapOption } from "./utils";
import { shouldAddBacktick, wrapOption } from "./utils";

export class CirceRenderer extends Scala3Renderer {
private seenUnionTypes: string[] = [];
Expand Down Expand Up @@ -55,7 +55,13 @@ export class CirceRenderer extends Scala3Renderer {
paramName,
")",
],
(_) => ["Encoder.encodeString(", paramName, ")"],
(enumType) => [
"summon[Encoder[",
this.scalaType(enumType),
"]].apply(",
paramName,
")",
],
(unionType) => {
const nullable = nullableFromUnion(unionType);
if (nullable !== null) {
Expand Down Expand Up @@ -104,24 +110,127 @@ export class CirceRenderer extends Scala3Renderer {
protected emitEnumDefinition(e: EnumType, enumName: Name): void {
this.emitDescription(this.descriptionForType(e));

this.ensureBlankLine();
this.emitItem(["type ", enumName, " = "]);
let count = e.cases.size;
let hasBlank = false;
this.forEachEnumCase(e, "none", (_, jsonName) => {
// if (!(jsonName == "")) {
/* const backticks =
shouldAddBacktick(jsonName) ||
jsonName.includes(" ") ||
!isNaN(parseInt(jsonName.charAt(0)))
if (backticks) {this.emitItem("`")} else */
this.emitItem(['"', jsonName, '"']);
// if (backticks) {this.emitItem("`")}
if (--count > 0) this.emitItem([" | "]);
// } else {
// --count
// }
if (jsonName.trim() === "") {
hasBlank = true;
}
});
this.ensureBlankLine();

const isBlank = (str: string): boolean => !str.trim();

if (hasBlank) {
//console.log("enumName: " + enumName + " has blank");
this.emitItem(["type ", enumName, ' = "" | ', enumName, "NonBlank"]);
this.ensureBlankLine();
this.emitLine([
"given ",
enumName,
"Enc: Encoder[",
enumName,
"] = Encoder.encodeString.contramap(_.toString())",
]);
this.emitLine([
"given ",
enumName,
"Dec: Decoder[",
enumName,
"] = List[Decoder[",
enumName,
"]](",
]);
this.indent(() => {
this.emitLine('Decoder[""].widen,');
this.emitLine(["Decoder[", enumName, "NonBlank].widen"]);
});
this.emitLine(").reduceLeft(_ or _)");

this.ensureBlankLine();
//let count = e.cases.size;
this.ensureBlankLine();
this.emitLine(["enum ", enumName, "NonBlank :"]);
this.indent(() => {
//let count = e.cases.size;

this.forEachEnumCase(e, "none", (_, jsonName) => {
let strBuild = "";
const backticks =
shouldAddBacktick(jsonName) ||
jsonName.includes(" ") ||
!Number.isNaN(Number.parseInt(jsonName.charAt(0)));
if (!isBlank(jsonName)) {
this.emitItem(["case "]);
}

if (backticks) {
strBuild = strBuild + "`";
}

strBuild = strBuild + jsonName;
if (backticks) {
strBuild = strBuild + "`";
}

//if (--count > 0) strBuild + ",";
// don't emit the blank case
if (!isBlank(jsonName)) {
this.emitLine([strBuild]);
}
});
});

this.emitLine([
"given Decoder[",
enumName,
"NonBlank] = Decoder.decodeString.emapTry(x => Try(",
enumName,
"NonBlank.valueOf(x) ))",
]);
this.emitLine(
"given Encoder[",
enumName,
"NonBlank] = Encoder.encodeString.contramap(_.toString())",
);
} else {
//console.log("enumName: " + enumName + " has non blank");
this.emitLine(["enum ", enumName, " : "]);

this.indent(() => {
this.forEachEnumCase(e, "none", (_, jsonName) => {
let strBuild = "";
const backticks =
shouldAddBacktick(jsonName) ||
jsonName.includes(" ") ||
!Number.isNaN(Number.parseInt(jsonName.charAt(0)));
this.emitItem(["case "]);
if (backticks) {
strBuild = strBuild + "`";
}

strBuild = strBuild + jsonName;
if (backticks) {
strBuild = strBuild + "`";
}

// if (--count > 0) strBuild + ",";
this.emitLine([strBuild]);
});
});
this.emitLine([
"given Decoder[",
enumName,
"] = Decoder.decodeString.emapTry(x => Try(",
enumName,
".valueOf(x) )) ",
]);
this.emitLine([
"given Encoder[",
enumName,
"] = Encoder.encodeString.contramap(_.toString())",
]);
this.ensureBlankLine();
}
}

protected emitHeader(): void {
Expand All @@ -134,12 +243,12 @@ export class CirceRenderer extends Scala3Renderer {
this.ensureBlankLine();

this.emitLine("// For serialising string unions");
this.emitLine(
"given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) ",
);
this.emitLine(
"given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) ",
);
// this.emitLine(
// "given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) "
// );
// this.emitLine(
// "given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) "
// );
this.ensureBlankLine();
this.emitLine(
"// If a union has a null in, then we'll need this too... ",
Expand All @@ -153,9 +262,9 @@ export class CirceRenderer extends Scala3Renderer {
this.emitLine([
"given (using ev : ",
elementType,
"): Encoder[Map[String,",
"): Encoder[Seq[",
elementType,
"]] = Encoder.encodeMap[String, ",
"]] = Encoder.encodeSeq[",
elementType,
"]",
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class Scala3Renderer extends ConvenienceRenderer {
_: EnumType,
_enumName: Name,
): ForbiddenWordsInfo {
return { names: [], includeGlobalForbidden: true };
return { names: ["_"], includeGlobalForbidden: true };
}

protected forbiddenForUnionMembers(
Expand Down Expand Up @@ -238,6 +238,7 @@ export class Scala3Renderer extends ConvenienceRenderer {
let count = c.getProperties().size;
let first = true;
this.forEachClassProperty(c, "none", (_, jsonName, p) => {
//console.log(jsonName); // Why is this in different order!!!!!!
const nullable =
p.type.kind === "union" &&
nullableFromUnion(p.type as UnionType) !== null;
Expand Down Expand Up @@ -296,6 +297,7 @@ export class Scala3Renderer extends ConvenienceRenderer {
}

protected emitEnumDefinition(e: EnumType, enumName: Name): void {
//console.log("vanilla");
this.emitDescription(this.descriptionForType(e));

this.emitBlock(
Expand All @@ -307,6 +309,7 @@ export class Scala3Renderer extends ConvenienceRenderer {
}

this.forEachEnumCase(e, "none", (name, jsonName) => {
//console.log(jsonName);
if (!(jsonName === "")) {
const backticks =
shouldAddBacktick(jsonName) ||
Expand Down
Loading
Loading