Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
schani committed Jun 26, 2018
1 parent f6b4d97 commit fbd1fe1
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 1 deletion.
29 changes: 29 additions & 0 deletions doc/Transformers.md
@@ -0,0 +1,29 @@
# Transformed string types

quicktype has facilities for transforming JSON strings into other data types, provided a given target language implementation supports it. Right now the most advanced target language in that regard is C#, which supports data/time types and stringified integers.

There are two different sorts of transformed string types:

- Those that transform strings into other JSON-representable types, such as stringified integers.

- Those that transform into types that are not directly representable in JSON (other than as strings), such as date/time types.

Several pieces need to be implemented to add a new transformed string type:

1. `TransformedStringTypeTargets` have to be added for the new type kind in the object `transformedStringTypeTargetTypeKinds` in `Type.ts`. The property names of that object are the internal primitive type names. Adding a new property automatically adds a new type.

2. `inferTransformedStringTypeKindForString` in `StringTypes.ts` can optionally be amended to automatically infer the new transformed type from a given string in JSON input. If this isn't done, the only way to use the new type is through JSON Schema. If it is done, a CLI option to turn it off has to be added. This is currently still more complicated than it needs to be, since it also involves changing the options to `quicktype-core`.

3. The target languages that should support the new type have to be amended. Currently C# is the only one that allows this easily. See `CSharp.ts` and search for `date-time`.

4. Test cases have to be added. See `test/inputs/schema/date-time*`, for example. If JSON inference is implemented, there should be at least one JSON test file with a string of that type.

5. In `fixtures.ts`, `ajv`, which we use to validate JSON against schemas, has to be told about the new JSON Schema string format. Search for `date-time`.

## Stuff we need to improve

- Automatic generation of tests. We should have a test generator that produces test files with all string types in all reasonable combinations.

- One CLI option for all string types. No CLI option work should be necessary to implement a new string type.

- The AJV thing should be automated, too. We have almost all the validation code necessary in `StringTypes.ts` anyway.
2 changes: 2 additions & 0 deletions src/cli/index.ts
Expand Up @@ -385,6 +385,8 @@ function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinit
type: Boolean,
description: "Don't infer enums, always use strings."
},
// We're getting to the point where we should have just one CLI option for
// disabling transformed string types, but right now we have one per type.
{
name: "no-date-times",
type: Boolean,
Expand Down
7 changes: 7 additions & 0 deletions src/quicktype-core/StringTypes.ts
Expand Up @@ -177,6 +177,13 @@ function isIntegerString(s: string): boolean {
return i >= MIN_INTEGER_STRING && i <= MAX_INTEGER_STRING;
}

/**
* JSON inference calls this function to figure out whether a given string is to be
* transformed into a higher level type. Must return undefined if not, otherwise the
* type kind of the transformed string type.
*
* @param s The string for which to determine the transformed string type kind.
*/
export function inferTransformedStringTypeKindForString(s: string): TransformedStringTypeKind | undefined {
if (s.length === 0 || "0123456789-".indexOf(s[0]) < 0) return undefined;

Expand Down
8 changes: 8 additions & 0 deletions src/quicktype-core/Type.ts
Expand Up @@ -28,6 +28,14 @@ import { TypeAttributes } from "./TypeAttributes";
import { messageAssert } from "./Messages";
import { TypeRef, attributesForTypeRef, derefTypeRef, TypeGraph, typeRefIndex } from "./TypeGraph";

/**
* `jsonSchema` is the `format` to be used to represent this string type in
* JSON Schema. It's ok to "invent" a new one if the JSON Schema standard doesn't
* have that particular type yet.
*
* For transformed type kinds that map to an existing primitive type, `primitive`
* must specify that type kind.
*/
export type TransformedStringTypeTargets = {
jsonSchema: string;
primitive: PrimitiveNonStringTypeKind | undefined;
Expand Down
4 changes: 4 additions & 0 deletions src/quicktype-core/language/CSharp.ts
Expand Up @@ -89,6 +89,10 @@ function alwaysApplyTransformation(xf: Transformation): boolean {
return false;
}

/**
* The C# type for a given transformed string type. The function can
* assume that it will only be called for type kinds that
*/
function csTypeForTransformedStringType(t: PrimitiveType): Sourcelike {
if (t.kind === "date-time") {
return "DateTimeOffset";
Expand Down
5 changes: 4 additions & 1 deletion test/fixtures.ts
Expand Up @@ -369,7 +369,10 @@ class JSONSchemaJSONFixture extends JSONToXToYFixture {
let schema = JSON.parse(fs.readFileSync(this.language.output, "utf8"));

let ajv = new Ajv({ format: "full", unknownFormats: ["integer"] });
// Make Ajv's date-time compatible with what we recognize
// Make Ajv's date-time compatible with what we recognize. All non-standard
// JSON formats that we use for transformed type kinds must be registered here
// with a validation function.
// FIXME: Unify this with what's in StringTypes.ts.
ajv.addFormat("date-time", isDateTime);
let valid = ajv.validate(schema, input);
if (!valid) {
Expand Down

0 comments on commit fbd1fe1

Please sign in to comment.