diff --git a/package.json b/package.json index 0c2ec71..be949e2 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "fp-ts": "^0.4.5", "lodash": "^4.17.4", "read-pkg-up": "^2.0.0", - "rosie": "^1.6.0" + "rosie": "^1.6.0", + "unquoted-property-validator": "^1.0.0" }, "jest": { "moduleFileExtensions": [ diff --git a/src/writers/types.ts b/src/writers/types.ts index c9e333b..e313122 100644 --- a/src/writers/types.ts +++ b/src/writers/types.ts @@ -1,5 +1,6 @@ import { groupBy, keys, toPairs } from "lodash"; import * as path from "path"; +import unquotedValidator = require("unquoted-property-validator"); import { Config } from "../config"; import { hasOptionalField, @@ -57,13 +58,16 @@ const fieldToString = (field: Field): string => { return field.type.name; }; +const encodeFieldKey = (key: string): string => unquotedValidator(key).quotedValue; + const interfaceToString = (config: Config, type: VisitedType): string => { const iface = type.class as InterfaceType; const fields = iface.fields .map(field => { + const encodedKey = encodeFieldKey(field.key); const key = config.nullableMode === "option" || field.required - ? field.key - : `${field.key}?`; + ? encodedKey + : `${encodedKey}?`; const fieldType = fieldToString(field); const maybeFieldType = config.nullableMode === "option" && !field.required ? `Option<${fieldType}>` @@ -97,7 +101,7 @@ ${alternatives}; `; }; -const typeToString = (config: Config) => (type: VisitedType): string => { +export const typeToString = (config: Config) => (type: VisitedType): string => { if (isArray(type.class)) { return arrayToString(type); } diff --git a/src/writers/unquoted-property-validator.d.ts b/src/writers/unquoted-property-validator.d.ts new file mode 100644 index 0000000..b3771e8 --- /dev/null +++ b/src/writers/unquoted-property-validator.d.ts @@ -0,0 +1,9 @@ +declare module "unquoted-property-validator" { + function unquotedValidator(propertyName: string): { + needsQuotes: boolean, + needsBrackets: boolean, + es3Warning: boolean, + quotedValue: string, + }; + export = unquotedValidator; +} diff --git a/test/types.test.ts b/test/types.test.ts new file mode 100644 index 0000000..963644f --- /dev/null +++ b/test/types.test.ts @@ -0,0 +1,56 @@ +import { Config } from "../src/config"; +import { VisitedType } from "../src/schemaVisitor/types"; +import { typeToString } from "../src/writers/types"; + +const config: Config = { + nullableMode: "nullable", + paths: { + input: "dummy", + library: "dummy", + project: "dummy", + types: "dummy", + utils: "dummy", + }, + typeImports: {}, +}; + +describe("an interface member with special characters", () => { + test("it is quoted correctly", () => { + const inputType: VisitedType = { + class: { + fields: [ + { + key: "foo", + required: true, + type: { + class: { + kind: "basic", + type: "string", + }, + name: "string", + }, + }, + { + key: "foo-dashed", + required: true, + type: { + class: { + kind: "basic", + type: "string", + }, + name: "string", + }, + }, + ], + kind: "interface", + }, + name: "Test", + }; + const outputDecl = typeToString(config)(inputType); + expect(outputDecl).toBe("" + + "export interface Test {\n" + + " foo: string;\n" + + " 'foo-dashed': string;\n" + + "}\n"); + }); +}); diff --git a/yarn.lock b/yarn.lock index e96389d..1e34c56 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2235,6 +2235,10 @@ universalify@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.0.tgz#9eb1c4651debcc670cc94f1a75762332bb967778" +unquoted-property-validator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unquoted-property-validator/-/unquoted-property-validator-1.0.0.tgz#e63618c9cadd25ce82f0e33db951ffdfa694fc3a" + user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"