Repository: apollographql/apollo-codegen
Pull request #424 (2018-05-29 12:20:53)

[ts-modern] export generated input types
<!--**Pull Request Labels**

While not necessary, you can help organize our pull requests by labeling this issue when you open it.  To add a label automatically, simply [x] mark the appropriate box below:

- [x] bug
- [ ] blocking
- [ ] docs

To add a label not listed above, simply place `/label another-label-name` on a line by itself.
/label bug
-->

In `ts-modern` the generated input types are not exported and thus not usable from outside the generated module. (Similiar issue in Flow was #320 ). 

This PR adds the missing 'export's to the types.

*Example **before**:*
```
//==============================================================
// START Enums and Input Objects
// All enums and input objects are included in every output file
// for now, but this will be changed soon.
// TODO: Link to issue to fix this.
//==============================================================

// ===> SearchFilter is an input type and not exported:
interface SearchFilter {
  searchString?: string | null;
  maxHits?: number | null;
}
```

*Example **after**:*
```
//==============================================================
// START Enums and Input Objects
// All enums and input objects are included in every output file
// for now, but this will be changed soon.
// TODO: Link to issue to fix this.
//==============================================================

// ===> SearchFilter is an input type and with this PR now exported:
export interface SearchFilter {
  searchString?: string | null;
  maxHits?: number | null;
}
```


meteor-bot: @nilshartmann: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Meteor Contributor Agreement here: https://contribute.meteor.com/
smkhalsa: duplicate of #411? In any case, I'd love to see one of these merged as this is a blocker for me.
teijo: Hack in the meantime (`find`/`sed` flags might vary on GNU/Linux): `apollo-codegen generate '**/*.ts?(x)' --addTypename --schema ../../generated-graphql-schema.json --tag-name gql --target typescript-modern && find . -regex '.*/__generated__/.*.ts' -exec sed -i '' -e 's/^interface/export interface/g' {} \;`
lirbank: Another benefit of exporting all types is that you can enable `noUnusedLocals` TS compiler option if you like. Without exporting them, the compiler will complain since they are part of all generated files (and not used in all). I'm using `--target typescript-modern`.

Patch:
diff --git a/src/flow/types.js b/src/flow/types.js
index 21a92203..783607a8 100644
--- a/src/flow/types.js
+++ b/src/flow/types.js
@@ -36,7 +36,7 @@ export function typeNameFromGraphQLType(context, type, bareTypeName, nullable =
   if (type instanceof GraphQLList) {
     typeName = `Array< ${typeNameFromGraphQLType(context, type.ofType, bareTypeName)} >`;
   } else if (type instanceof GraphQLScalarType) {
-    typeName = builtInScalarMap[type.name] || (context.passthroughCustomScalars ? context.customScalarsPrefix + type.name : 'any');
+    typeName = builtInScalarMap[type.name] || (context.options.passthroughCustomScalars ? context.options.customScalarsPrefix + type.name : 'any');
   } else {
     typeName = bareTypeName || type.name;
   }
diff --git a/src/generate.ts b/src/generate.ts
index 017dfde4..81d9b184 100644
--- a/src/generate.ts
+++ b/src/generate.ts
@@ -103,7 +103,7 @@ export default function generate(
         output = generateFlowSource(context);
         break;
       case 'scala':
-        output = generateScalaSource(context, options);
+        output = generateScalaSource(context);
     }
 
     if (outputPath) {
diff --git a/src/javascript/typescript/language.ts b/src/javascript/typescript/language.ts
index fce3d652..446a8191 100644
--- a/src/javascript/typescript/language.ts
+++ b/src/javascript/typescript/language.ts
@@ -76,9 +76,9 @@ export default class TypescriptGenerator {
         }
       });
 
-    const inputType = this.interface(name, fields, {
+    const inputType = t.exportNamedDeclaration(this.interface(name, fields, {
       keyInheritsNullability: true
-    });
+    }), []);
 
     inputType.leadingComments = [{
       type: 'CommentLine',
diff --git a/src/scala/codeGeneration.js b/src/scala/codeGeneration.ts
similarity index 76%
rename from src/scala/codeGeneration.js
rename to src/scala/codeGeneration.ts
index 0dcc4803..a9dc0704 100644
--- a/src/scala/codeGeneration.js
+++ b/src/scala/codeGeneration.ts
@@ -2,13 +2,8 @@ import {
   GraphQLError,
   getNamedType,
   isCompositeType,
-  isAbstractType,
-  isEqualType,
-  GraphQLScalarType,
   GraphQLEnumType,
-  GraphQLList,
   GraphQLNonNull,
-  GraphQLID,
   GraphQLInputObjectType
 } from 'graphql'
 
@@ -16,15 +11,12 @@ import  { isTypeProperSuperTypeOf } from '../utilities/graphql'
 
 import {
   join,
-  wrap,
 } from '../utilities/printing';
 
 import {
   packageDeclaration,
   objectDeclaration,
   caseClassDeclaration,
-  propertyDeclaration,
-  propertyDeclarations,
   escapeIdentifierIfNeeded,
   comment
 } from './language';
@@ -35,16 +27,12 @@ import {
   caseClassNameForInlineFragment,
   operationClassName,
   enumCaseName,
-  propertiesFromSelectionSet,
-  propertyFromField,
-  propertyFromInlineFragment,
-  propertyFromFragmentSpread
+  propertyFromLegacyField,
+  propertyFromInputField,
 } from './naming';
 
 import {
-  escapedString,
   multilineString,
-  dictionaryLiteralForFieldArguments,
 } from './values';
 
 import {
@@ -53,15 +41,19 @@ import {
 } from './types';
 
 import CodeGenerator from '../utilities/CodeGenerator';
+import { LegacyCompilerContext, LegacyOperation, LegacyFragment, LegacyField, LegacyInlineFragment } from '../compiler/legacyIR';
+import { GraphQLType } from 'graphql';
+import { Property } from './language';
+import { GraphQLCompositeType } from 'graphql';
 
-export function generateSource(context, options) {
+export function generateSource(context: LegacyCompilerContext) {
   const generator = new CodeGenerator(context);
 
   generator.printOnNewline('//  This file was automatically generated and should not be edited.');
   generator.printNewline();
 
-  if (context.namespace) {
-    packageDeclaration(generator, context.namespace);
+  if (context.options.namespace) {
+    packageDeclaration(generator, context.options.namespace);
   }
 
   context.typesUsed.forEach(type => {
@@ -80,7 +72,7 @@ export function generateSource(context, options) {
 }
 
 export function classDeclarationForOperation(
-  generator,
+  generator: CodeGenerator<LegacyCompilerContext, any>,
   {
     operationName,
     operationType,
@@ -91,9 +83,8 @@ export function classDeclarationForOperation(
     fragmentSpreads,
     fragmentsReferenced,
     source,
-    sourceWithFragments,
     operationId
-  }
+  }: LegacyOperation
 ) {
   let objectName;
   let protocol;
@@ -113,8 +104,7 @@ export function classDeclarationForOperation(
 
   objectDeclaration(generator, {
     objectName,
-    modifiers: [],
-    superclass: protocol
+    superclass: protocol,
   }, () => {
     if (source) {
       generator.printOnNewline('val operationString =');
@@ -123,7 +113,9 @@ export function classDeclarationForOperation(
       });
     }
 
-    operationIdentifier(generator, { operationName, sourceWithFragments, operationId });
+    if (operationId) {
+      operationIdentifier(generator, operationId);
+    }
 
     if (fragmentsReferenced && fragmentsReferenced.length > 0) {
       generator.printNewlineIfNeeded();
@@ -144,7 +136,7 @@ export function classDeclarationForOperation(
       const properties = variables.map(({ name, type }) => {
         const propertyName = escapeIdentifierIfNeeded(name);
         const typeName = typeNameFromGraphQLType(generator.context, type);
-        const isOptional = !(type instanceof GraphQLNonNull || type.ofType instanceof GraphQLNonNull);
+        const isOptional = !(type instanceof GraphQLNonNull || type instanceof GraphQLNonNull);
         return { name, propertyName, type, typeName, isOptional };
       });
 
@@ -172,7 +164,7 @@ export function classDeclarationForOperation(
 }
 
 export function caseClassDeclarationForFragment(
-  generator,
+  generator: CodeGenerator<LegacyCompilerContext, any>,
   {
     fragmentName,
     typeCondition,
@@ -180,7 +172,7 @@ export function caseClassDeclarationForFragment(
     inlineFragments,
     fragmentSpreads,
     source
-  }
+  }: LegacyFragment
 ) {
   const caseClassName = caseClassNameForFragmentName(fragmentName);
 
@@ -190,7 +182,7 @@ export function caseClassDeclarationForFragment(
     fields,
     inlineFragments,
     fragmentSpreads
-  }, () => {}, () => {
+  }, () => {
     if (source) {
       generator.printOnNewline('val fragmentString =');
       generator.withIndent(() => {
@@ -201,7 +193,7 @@ export function caseClassDeclarationForFragment(
 }
 
 export function caseClassDeclarationForSelectionSet(
-  generator,
+  generator: CodeGenerator<LegacyCompilerContext, any>,
   {
     caseClassName,
     parentType,
@@ -209,17 +201,24 @@ export function caseClassDeclarationForSelectionSet(
     inlineFragments,
     fragmentSpreads,
     viewableAs
+  }: {
+    caseClassName: string,
+    parentType: GraphQLCompositeType,
+    fields: LegacyField[],
+    inlineFragments?: LegacyInlineFragment[],
+    fragmentSpreads?: string[],
+    viewableAs?: {
+      caseClassName: string,
+      properties: (LegacyField & Property)[]
+    }
   },
-  beforeClosure,
-  objectClosure,
+  objectClosure?: () => void,
 ) {
   const possibleTypes = parentType ? possibleTypesForType(generator.context, parentType) : null;
 
-  let properties;
-
   if (!possibleTypes || possibleTypes.length == 1) {
-    properties = fields
-      .map(field => propertyFromField(generator.context, field))
+    const properties = fields
+      .map(field => propertyFromLegacyField(generator.context, field, caseClassName))
       .filter(field => field.propertyName != "__typename");
 
     caseClassDeclaration(generator, { caseClassName, params: properties.map(p => {
@@ -231,7 +230,7 @@ export function caseClassDeclarationForSelectionSet(
   } else {
     generator.printNewlineIfNeeded();
     const properties = fields
-      .map(field => propertyFromField(generator.context, field))
+      .map(field => propertyFromLegacyField(generator.context, field, caseClassName))
       .filter(field => field.propertyName != "__typename");
 
     caseClassDeclaration(generator, { caseClassName, params: properties.map(p => {
@@ -239,14 +238,14 @@ export function caseClassDeclarationForSelectionSet(
         name: p.responseName,
         type: p.typeName,
       };
-    }), superclass: 'me.shadaj.slinky.core.WithRaw'}, () => {
+    }), superclass: 'slinky.readwrite.WithRaw'}, () => {
       if (inlineFragments && inlineFragments.length > 0) {
         inlineFragments.forEach((inlineFragment) => {
           const fragClass = caseClassNameForInlineFragment(inlineFragment);
           generator.printOnNewline(`def as${inlineFragment.typeCondition}`);
           generator.print(`: Option[${fragClass}] =`);
           generator.withinBlock(() => {
-            generator.printOnNewline(`if (${fragClass}.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[${fragClass}]].read(this.raw)) else None`);
+            generator.printOnNewline(`if (${fragClass}.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[${fragClass}]].read(this.raw)) else None`);
           });
         });
       }
@@ -259,7 +258,7 @@ export function caseClassDeclarationForSelectionSet(
             generator.printOnNewline(`def as${s}`);
             generator.print(`: Option[${s}] =`);
             generator.withinBlock(() => {
-              generator.printOnNewline(`if (${s}.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[${s}]].read(this.raw)) else None`);
+              generator.printOnNewline(`if (${s}.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[${s}]].read(this.raw)) else None`);
             });
           }
         })
@@ -275,7 +274,7 @@ export function caseClassDeclarationForSelectionSet(
             caseClassName: caseClassNameForInlineFragment(inlineFragment),
             parentType: inlineFragment.typeCondition,
             fields: inlineFragment.fields,
-            inlineFragments: inlineFragment.inlineFragments,
+            // inlineFragments: inlineFragment.inlineFragments,
             fragmentSpreads: inlineFragment.fragmentSpreads,
             viewableAs: {
               caseClassName,
@@ -309,27 +308,27 @@ export function caseClassDeclarationForSelectionSet(
       })
     }
 
+    fields.filter(field => isCompositeType(getNamedType(field.type))).forEach(field => {
+      caseClassDeclarationForSelectionSet(
+        generator,
+        {
+          caseClassName: caseClassNameForPropertyName(field.responseName),
+          parentType: getNamedType(field.type) as GraphQLCompositeType,
+          fields: field.fields || [],
+          inlineFragments: field.inlineFragments,
+          fragmentSpreads: field.fragmentSpreads
+        }
+      );
+    });
+
     if (objectClosure) {
       objectClosure();
     }
   });
-
-  fields.filter(field => isCompositeType(getNamedType(field.type))).forEach(field => {
-    caseClassDeclarationForSelectionSet(
-      generator,
-      {
-        caseClassName: caseClassNameForPropertyName(field.responseName),
-        parentType: getNamedType(field.type),
-        fields: field.fields,
-        inlineFragments: field.inlineFragments,
-        fragmentSpreads: field.fragmentSpreads
-      }
-    );
-  });
 }
 
-function operationIdentifier(generator,  { operationName, sourceWithFragments, operationId }) {
-  if (!generator.context.generateOperationIds) {
+function operationIdentifier(generator: CodeGenerator<LegacyCompilerContext, any>, operationId: string) {
+  if (!generator.context.options.generateOperationIds) {
     return
   }
 
@@ -337,7 +336,7 @@ function operationIdentifier(generator,  { operationName, sourceWithFragments, o
   generator.printOnNewline(`val operationIdentifier: String = "${operationId}"`);
 }
 
-export function typeDeclarationForGraphQLType(generator, type) {
+export function typeDeclarationForGraphQLType(generator: CodeGenerator<LegacyCompilerContext, any>, type: GraphQLType) {
   if (type instanceof GraphQLEnumType) {
     enumerationDeclaration(generator, type);
   } else if (type instanceof GraphQLInputObjectType) {
@@ -345,7 +344,7 @@ export function typeDeclarationForGraphQLType(generator, type) {
   }
 }
 
-function enumerationDeclaration(generator, type) {
+function enumerationDeclaration(generator: CodeGenerator<LegacyCompilerContext, any>, type: GraphQLEnumType) {
   const { name, description } = type;
   const values = type.getValues();
 
@@ -361,15 +360,16 @@ function enumerationDeclaration(generator, type) {
   generator.printNewline();
 }
 
-function caseClassDeclarationForInputObjectType(generator, type) {
+function caseClassDeclarationForInputObjectType(generator: CodeGenerator<LegacyCompilerContext, any>, type: GraphQLInputObjectType) {
   const { name: caseClassName, description } = type;
   const fields = Object.values(type.getFields());
-  const properties = fields.map(field => propertyFromField(generator.context, field));
+  const properties = fields.map(field => propertyFromInputField(generator.context, field, generator.context.options.namespace));
 
   caseClassDeclaration(generator, { caseClassName, description, params: properties.map(p => {
     return {
       name: p.propertyName,
-      type: p.typeName
+      type: p.typeName,
+      defaultValue: p.isOptional ? "scala.scalajs.js.undefined" : ""
     };
   })}, () => {});
 }
diff --git a/src/scala/index.js b/src/scala/index.ts
similarity index 100%
rename from src/scala/index.js
rename to src/scala/index.ts
diff --git a/src/scala/language.js b/src/scala/language.js
deleted file mode 100644
index 23fc67dc..00000000
--- a/src/scala/language.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import {
-  join,
-  wrap,
-} from '../utilities/printing';
-
-export function comment(generator, comment) {
-  const split = comment ? comment.split('\n') : [];
-  if (split.length > 0) {
-    generator.printOnNewline('/**')
-    split.forEach(line => {
-      generator.printOnNewline(` * ${line.trim()}`);
-    });
-
-    generator.printOnNewline(' */');
-  }
-}
-
-export function packageDeclaration(generator, pkg) {
-  generator.printNewlineIfNeeded();
-  generator.printOnNewline(`package ${pkg}`);
-  generator.popScope();
-}
-
-export function objectDeclaration(generator, { objectName, superclass, properties }, closure) {
-  generator.printNewlineIfNeeded();
-  generator.printOnNewline(`object ${objectName}` + (superclass ? ` extends ${superclass}` : ''));
-  generator.pushScope({ typeName: objectName });
-  generator.withinBlock(closure);
-  generator.popScope();
-}
-
-export function caseClassDeclaration(generator, { caseClassName, description, superclass, params }, closure) {
-  generator.printNewlineIfNeeded();
-  comment(generator, description);
-  generator.printOnNewline(`case class ${caseClassName}(${(params || []).map(v => v.name + ": " + v.type).join(', ')})` + (superclass ? ` extends ${superclass}` : ''));
-  generator.pushScope({ typeName: caseClassName });
-  generator.withinBlock(closure);
-  generator.popScope();
-}
-
-export function propertyDeclaration(generator, { propertyName, typeName, description}, closure) {
-  comment(generator, description);
-  generator.printOnNewline(`val ${propertyName}: ${typeName} =`);
-  generator.withinBlock(closure);
-}
-
-export function propertyDeclarations(generator, declarations) {
-  declarations.forEach(o => {
-    propertyDeclaration(generator, o);
-  });
-}
-
-const reservedKeywords = new Set(
-  'case', 'catch', 'class', 'def', 'do', 'else',
-  'extends', 'false', 'final', 'for', 'if', 'match',
-  'new', 'null', 'throw', 'trait', 'true', 'try', 'until',
-  'val', 'var', 'while', 'with'
-);
-
-export function escapeIdentifierIfNeeded(identifier) {
-  if (reservedKeywords.has(identifier)) {
-    return '`' + identifier + '`';
-  } else {
-    return identifier;
-  }
-}
diff --git a/src/scala/language.ts b/src/scala/language.ts
new file mode 100644
index 00000000..eff9830a
--- /dev/null
+++ b/src/scala/language.ts
@@ -0,0 +1,123 @@
+import CodeGenerator from "../utilities/CodeGenerator";
+import { LegacyCompilerContext } from "../compiler/legacyIR";
+
+export interface Property {
+  propertyName: string;
+  typeName: string;
+  caseClassName?: string;
+  isOptional?: boolean;
+  isList?: boolean;
+  description?: string;
+}
+
+export function comment(generator: CodeGenerator<LegacyCompilerContext, any>, comment: string) {
+  const split = comment ? comment.split('\n') : [];
+  if (split.length > 0) {
+    generator.printOnNewline('/**')
+    split.forEach(line => {
+      generator.printOnNewline(` * ${line.trim()}`);
+    });
+
+    generator.printOnNewline(' */');
+  }
+}
+
+export function packageDeclaration(generator: CodeGenerator<LegacyCompilerContext, any>, pkg: string) {
+  generator.printNewlineIfNeeded();
+  generator.printOnNewline(`package ${pkg}`);
+  generator.popScope();
+}
+
+export function objectDeclaration(
+  generator: CodeGenerator<LegacyCompilerContext, any>,
+  { objectName, superclass }: {
+    objectName: string,
+    superclass?: string
+  },
+  closure?: () => void
+) {
+  generator.printNewlineIfNeeded();
+  generator.printOnNewline(`object ${objectName}` + (superclass ? ` extends ${superclass}` : ''));
+  generator.pushScope({ typeName: objectName });
+  if (closure) {
+    generator.withinBlock(closure);
+  }
+  generator.popScope();
+}
+
+export function caseClassDeclaration(
+  generator: CodeGenerator<LegacyCompilerContext, any>,
+  { caseClassName, description, superclass, params }: {
+    caseClassName: string,
+    description?: string,
+    superclass?: string,
+    params?: {
+      name: string,
+      type: string,
+      defaultValue?: string
+    }[],
+  },
+  closure?: () => void
+) {
+  generator.printNewlineIfNeeded();
+
+  if (description) {
+    comment(generator, description);
+  }
+
+  const paramsSection = (params || []).map(v => {
+    return v.name + ": " + v.type + (v.defaultValue ? ` = ${v.defaultValue}` : "");
+  }).join(', ');
+
+  generator.printOnNewline(`case class ${caseClassName}(${paramsSection})` + (superclass ? ` extends ${superclass}` : ''));
+  generator.pushScope({ typeName: caseClassName });
+  if (closure) {
+    generator.withinBlock(closure);
+  }
+  generator.popScope();
+}
+
+export function propertyDeclaration(
+  generator: CodeGenerator<LegacyCompilerContext, any>,
+  { propertyName, typeName, description}: {
+    propertyName: string,
+    typeName: string,
+    description: string
+  },
+  closure?: () => void
+) {
+  comment(generator, description);
+  generator.printOnNewline(`val ${propertyName}: ${typeName} =`);
+
+  if (closure) {
+    generator.withinBlock(closure);
+  }
+}
+
+export function propertyDeclarations(
+  generator: CodeGenerator<LegacyCompilerContext, any>,
+  declarations: {
+    propertyName: string,
+    typeName: string,
+    description: string
+  }[]
+) {
+  declarations.forEach(o => {
+    propertyDeclaration(generator, o);
+  });
+}
+
+const reservedKeywords = new Set([
+  'case', 'catch', 'class', 'def', 'do', 'else',
+  'extends', 'false', 'final', 'for', 'if', 'match',
+  'new', 'null', 'throw', 'trait', 'true', 'try', 'until',
+  'val', 'var', 'while', 'with'
+]);
+
+export function escapeIdentifierIfNeeded(identifier: string) {
+  if (reservedKeywords.has(identifier)) {
+    return '`' + identifier + '`';
+  } else {
+    return identifier;
+  }
+}
diff --git a/src/scala/naming.js b/src/scala/naming.js
deleted file mode 100644
index 6399c7a0..00000000
--- a/src/scala/naming.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import { camelCase, pascalCase } from 'change-case';
-import * as Inflector from 'inflected';
-
-import {
-  join
-} from '../utilities/printing';
-
-import {
-  escapeIdentifierIfNeeded
-} from './language';
-
-import {
-  typeNameFromGraphQLType
-} from './types';
-
-import {
-  GraphQLError,
-  GraphQLList,
-  GraphQLNonNull,
-  getNamedType,
-  isCompositeType,
-} from 'graphql';
-
-export function enumCaseName(name) {
-  return camelCase(name);
-}
-
-export function operationClassName(name) {
-  return pascalCase(name);
-}
-
-export function caseClassNameForPropertyName(propertyName) {
-  return pascalCase(Inflector.singularize(propertyName));
-}
-
-export function caseClassNameForFragmentName(fragmentName) {
-  return pascalCase(fragmentName);
-}
-
-export function caseClassNameForInlineFragment(inlineFragment) {
-  return 'As' + pascalCase(String(inlineFragment.typeCondition));
-}
-
-export function propertyFromField(context, field, namespace) {
-  const name = field.name || field.responseName;
-  const unescapedPropertyName = isMetaFieldName(name) ? name : camelCase(name)
-  const propertyName = escapeIdentifierIfNeeded(unescapedPropertyName);
-
-  const type = field.type;
-  const isList = type instanceof GraphQLList || type.ofType instanceof GraphQLList
-  const isOptional = field.isConditional || !(type instanceof GraphQLNonNull);
-  const bareType = getNamedType(type);
-
-  if (isCompositeType(bareType)) {
-    const bareTypeName = join([
-      namespace,
-      escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name)))
-    ], '.');
-    const typeName = typeNameFromGraphQLType(context, type, bareTypeName, isOptional);
-    return { ...field, propertyName, typeName, bareTypeName, isOptional, isList, isComposite: true };
-  } else {
-    const typeName = typeNameFromGraphQLType(context, type, undefined, isOptional);
-    return { ...field, propertyName, typeName, isOptional, isList, isComposite: false };
-  }
-}
-
-export function propertyFromInlineFragment(context, inlineFragment) {
-  const structName = caseClassNameForInlineFragment(inlineFragment);
-  const propertyName = camelCase(structName);
-  const typeName = structName + '?'
-  return { propertyName, typeName, structName, isComposite: true, ...inlineFragment };
-}
-
-export function propertyFromFragmentSpread(context, fragmentSpread) {
-  const fragmentName = fragmentSpread;
-  const fragment = context.fragments[fragmentName];
-  if (!fragment) {
-    throw new GraphQLError(`Cannot find fragment "${fragmentName}"`);
-  }
-  const propertyName = camelCase(fragmentName);
-  const typeName = caseClassNameForFragmentName(fragmentName);
-  return { propertyName, typeName, fragment, isComposite: true };
-}
-
-function isMetaFieldName(name) {
-  return name.startsWith("__");
-}
\ No newline at end of file
diff --git a/src/scala/naming.ts b/src/scala/naming.ts
new file mode 100644
index 00000000..3576b0e2
--- /dev/null
+++ b/src/scala/naming.ts
@@ -0,0 +1,95 @@
+import { camelCase, pascalCase } from 'change-case';
+import * as Inflector from 'inflected';
+
+import {
+  join
+} from '../utilities/printing';
+
+import {
+  escapeIdentifierIfNeeded, Property
+} from './language';
+
+import {
+  typeNameFromGraphQLType
+} from './types';
+
+import {
+  GraphQLList,
+  GraphQLNonNull,
+  getNamedType,
+  isCompositeType,
+} from 'graphql';
+import { LegacyCompilerContext, LegacyField, LegacyInlineFragment } from '../compiler/legacyIR';
+import { GraphQLInputField } from 'graphql';
+
+export function enumCaseName(name: string) {
+  return camelCase(name);
+}
+
+export function operationClassName(name: string) {
+  return pascalCase(name);
+}
+
+export function caseClassNameForPropertyName(propertyName: string) {
+  return pascalCase(Inflector.singularize(propertyName));
+}
+
+export function caseClassNameForFragmentName(fragmentName: string) {
+  return pascalCase(fragmentName);
+}
+
+export function caseClassNameForInlineFragment(inlineFragment: LegacyInlineFragment) {
+  return 'As' + pascalCase(String(inlineFragment.typeCondition));
+}
+
+export function propertyFromInputField(context: LegacyCompilerContext, field: GraphQLInputField, namespace?: string, parentCaseClassName?: string): GraphQLInputField & Property {
+  const name = field.name;
+  const unescapedPropertyName = isMetaFieldName(name) ? name : camelCase(name)
+  const propertyName = escapeIdentifierIfNeeded(unescapedPropertyName);
+
+  const type = field.type;
+  const isList = type instanceof GraphQLList || type instanceof GraphQLList
+  const isOptional = !(type instanceof GraphQLNonNull);
+  const bareType = getNamedType(type);
+
+  if (isCompositeType(bareType)) {
+    const bareTypeName = join([
+      namespace,
+      parentCaseClassName,
+      escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name)))
+    ], '.');
+    const typeName = typeNameFromGraphQLType(context, type, bareTypeName, isOptional, true);
+    return { ...field, propertyName, typeName, isOptional, isList };
+  } else {
+    const typeName = typeNameFromGraphQLType(context, type, undefined, isOptional, true);
+    return { ...field, propertyName, typeName, isOptional, isList };
+  }
+}
+
+export function propertyFromLegacyField(context: LegacyCompilerContext, field: LegacyField, namespace?: string, parentCaseClassName?: string): LegacyField & Property {
+  const name = field.responseName;
+  const unescapedPropertyName = isMetaFieldName(name) ? name : camelCase(name)
+  const propertyName = escapeIdentifierIfNeeded(unescapedPropertyName);
+
+  const type = field.type;
+  const isList = type instanceof GraphQLList || type instanceof GraphQLList
+  const isOptional = field.isConditional || !(type instanceof GraphQLNonNull);
+  const bareType = getNamedType(type);
+
+  if (isCompositeType(bareType)) {
+    const bareTypeName = join([
+      namespace,
+      parentCaseClassName,
+      escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name)))
+    ], '.');
+    const typeName = typeNameFromGraphQLType(context, type, bareTypeName, isOptional);
+    return { ...field, propertyName, typeName, isOptional, isList };
+  } else {
+    const typeName = typeNameFromGraphQLType(context, type, undefined, isOptional);
+    return { ...field, propertyName, typeName, isOptional, isList };
+  }
+}
+
+function isMetaFieldName(name: string) {
+  return name.startsWith("__");
+}
diff --git a/src/scala/types.js b/src/scala/types.ts
similarity index 59%
rename from src/scala/types.js
rename to src/scala/types.ts
index ee182f85..70f9dc50 100644
--- a/src/scala/types.js
+++ b/src/scala/types.ts
@@ -1,12 +1,3 @@
-import {
-  join,
-  block,
-  wrap,
-  indent
-} from '../utilities/printing';
-
-import { camelCase } from 'change-case';
-
 import {
   GraphQLString,
   GraphQLInt,
@@ -17,9 +8,10 @@ import {
   GraphQLNonNull,
   GraphQLScalarType,
   GraphQLEnumType,
-  isCompositeType,
   isAbstractType
 } from 'graphql';
+import { LegacyCompilerContext } from '../compiler/legacyIR';
+import { GraphQLType } from 'graphql';
 
 const builtInScalarMap = {
   [GraphQLString.name]: 'String',
@@ -29,7 +21,7 @@ const builtInScalarMap = {
   [GraphQLID.name]: 'String',
 }
 
-export function possibleTypesForType(context, type) {
+export function possibleTypesForType(context: LegacyCompilerContext, type: GraphQLType) {
   if (isAbstractType(type)) {
     return context.schema.getPossibleTypes(type);
   } else {
@@ -37,7 +29,7 @@ export function possibleTypesForType(context, type) {
   }
 }
 
-export function typeNameFromGraphQLType(context, type, bareTypeName, isOptional) {
+export function typeNameFromGraphQLType(context: LegacyCompilerContext, type: GraphQLType, bareTypeName?: string, isOptional?: boolean, isInputObject?: boolean): string {
   if (type instanceof GraphQLNonNull) {
     return typeNameFromGraphQLType(context, type.ofType, bareTypeName, isOptional || false)
   } else if (isOptional === undefined) {
@@ -55,9 +47,9 @@ export function typeNameFromGraphQLType(context, type, bareTypeName, isOptional)
     typeName = bareTypeName || type.name;
   }
 
-  return isOptional ? `Option[${typeName}]` : typeName;
+  return isOptional ? (isInputObject ? `scala.scalajs.js.UndefOr[${typeName}]` : `Option[${typeName}]`) : typeName;
 }
 
-function typeNameForScalarType(context, type) {
-  return builtInScalarMap[type.name] || (context.passthroughCustomScalars ? context.customScalarsPrefix + type.name: GraphQLString)
+function typeNameForScalarType(context: LegacyCompilerContext, type: GraphQLScalarType): string {
+  return builtInScalarMap[type.name] || (context.options.passthroughCustomScalars ? context.options.customScalarsPrefix + type.name : GraphQLString.name)
 }
diff --git a/src/scala/values.js b/src/scala/values.js
deleted file mode 100644
index 0e24f9f4..00000000
--- a/src/scala/values.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import {
-  join,
-  wrap,
-} from '../utilities/printing';
-
-export function escapedString(string) {
-  return string.replace(/"/g, '\\"');
-}
-
-export function multilineString(context, string) {
-  const lines = string.split('\n');
-  lines.forEach((line, index) => {
-    const isLastLine = index != lines.length - 1;
-    context.printOnNewline(`"${escapedString(line)}"` + (isLastLine ? ' +' : ''));
-  });
-}
-
-export function dictionaryLiteralForFieldArguments(args) {
-  function expressionFromValue(value) {
-    if (value.kind === 'Variable') {
-      return `Variable("${value.variableName}")`;
-    } else if (Array.isArray(value)) {
-      return wrap('[', join(value.map(expressionFromValue), ', '), ']');
-    } else if (typeof value === 'object') {
-      return wrap('[', join(Object.entries(value).map(([key, value]) => {
-        return `"${key}": ${expressionFromValue(value)}`;
-      }), ', ') || ':', ']');
-    } else {
-      return JSON.stringify(value);
-    }
-  }
-
-  return wrap('[', join(args.map(arg => {
-    return `"${arg.name}": ${expressionFromValue(arg.value)}`;
-  }), ', ') || ':', ']');
-}
diff --git a/src/scala/values.ts b/src/scala/values.ts
new file mode 100644
index 00000000..fd69513a
--- /dev/null
+++ b/src/scala/values.ts
@@ -0,0 +1,14 @@
+import { LegacyCompilerContext } from '../compiler/legacyIR';
+import CodeGenerator from '../utilities/CodeGenerator';
+
+export function escapedString(string: string) {
+  return string.replace(/"/g, '\\"');
+}
+
+export function multilineString(generator: CodeGenerator<LegacyCompilerContext, any>, string: string) {
+  const lines = string.split('\n');
+  lines.forEach((line, index) => {
+    const isLastLine = index != lines.length - 1;
+    generator.printOnNewline(`"${escapedString(line)}"` + (isLastLine ? ' +' : ''));
+  });
+}
diff --git a/src/typescript/codeGeneration.ts b/src/typescript/codeGeneration.ts
index afe02aef..b12bea4e 100644
--- a/src/typescript/codeGeneration.ts
+++ b/src/typescript/codeGeneration.ts
@@ -14,10 +14,6 @@ import {
   GraphQLObjectType
 } from 'graphql'
 
-import {
-  wrap
-} from '../utilities/printing';
-
 import {
   sortEnumValues
 } from '../utilities/graphql';
@@ -70,25 +66,11 @@ function enumerationDeclaration(generator: CodeGenerator, type: GraphQLEnumType)
   const values = type.getValues();
 
   generator.printNewlineIfNeeded();
-  if (description) {
-    description.split('\n')
-      .forEach(line => {
-        generator.printOnNewline(`// ${line.trim()}`);
-      })
-  }
+  printDocComment(generator, description);
   generator.printOnNewline(`export enum ${name} {`);
   sortEnumValues(values).forEach((value) => {
-    if (!value.description || value.description.indexOf('\n') === -1) {
-      generator.printOnNewline(`  ${value.value} = "${value.value}",${wrap(' // ', value.description)}`)
-    } else {
-      if (value.description) {
-        value.description.split('\n')
-          .forEach((line: string) => {
-            generator.printOnNewline(`  // ${line.trim()}`);
-          })
-      }
-      generator.printOnNewline(`  ${value.value} = "${value.value}",`)
-    }
+    printDocComment(generator, value.description, 1);
+    generator.printOnNewline(`  ${value.value} = "${value.value}",`)
   });
   generator.printOnNewline(`}`);
   generator.printNewline();
@@ -431,3 +413,18 @@ function getPossibleTypeNames(generator: CodeGenerator<LegacyCompilerContext>, p
 
   return [];
 }
+
+export function printDocComment(generator: CodeGenerator, description?: string, depth: number = 0): void {
+  if (!description) {
+    return;
+  }
+
+  const leadingSpace = ' '.repeat(2 * depth);
+
+  generator.printOnNewline(`${leadingSpace}/**`);
+  description.split('\n')
+    .forEach(line => {
+      generator.printOnNewline(`${leadingSpace} * ${line.trim()}`);
+    });
+  generator.printOnNewline(`${leadingSpace} */`);
+}
diff --git a/src/typescript/language.ts b/src/typescript/language.ts
index b82b8084..df381599 100644
--- a/src/typescript/language.ts
+++ b/src/typescript/language.ts
@@ -1,6 +1,6 @@
 import { LegacyInlineFragment } from '../compiler/legacyIR';
 
-import { propertyDeclarations } from './codeGeneration';
+import { propertyDeclarations, printDocComment } from './codeGeneration';
 import { typeNameFromGraphQLType } from './types';
 
 import CodeGenerator from "../utilities/CodeGenerator";
@@ -59,12 +59,7 @@ export function propertyDeclaration(generator: CodeGenerator, {
 }: Property, closure?: () => void) {
   const name = fieldName || propertyName;
 
-  if (description) {
-    description.split('\n')
-      .forEach(line => {
-        generator.printOnNewline(`// ${line.trim()}`);
-      })
-  }
+  printDocComment(generator, description);
 
   if (closure) {
     generator.printOnNewline(name);
@@ -111,12 +106,7 @@ export function propertySetsDeclaration(generator: CodeGenerator, property: Prop
   } = property;
   const name = fieldName || propertyName;
 
-  if (description) {
-    description.split('\n')
-      .forEach(line => {
-        generator.printOnNewline(`// ${line.trim()}`);
-      })
-  }
+  printDocComment(generator, description);
 
   if (!standalone) {
     generator.printOnNewline(`${name}: `);


Test patch:
diff --git a/src/javascript/typescript/__tests__/__snapshots__/codeGeneration.ts.snap b/src/javascript/typescript/__tests__/__snapshots__/codeGeneration.ts.snap
index f57240a0..efb2f230 100644
--- a/src/javascript/typescript/__tests__/__snapshots__/codeGeneration.ts.snap
+++ b/src/javascript/typescript/__tests__/__snapshots__/codeGeneration.ts.snap
@@ -544,14 +544,14 @@ export enum Episode {
 }
 
 // The input object sent when someone is creating a new review
-interface ReviewInput {
+export interface ReviewInput {
   stars: number;
   commentary?: string | null;
   favorite_color?: ColorInput | null;
 }
 
 // The input object sent when passing in a color
-interface ColorInput {
+export interface ColorInput {
   red: number;
   green: number;
   blue: number;
@@ -605,14 +605,14 @@ export enum Episode {
 }
 
 // The input object sent when someone is creating a new review
-interface ReviewInput {
+export interface ReviewInput {
   stars: number;
   commentary?: string | null;
   favorite_color?: ColorInput | null;
 }
 
 // The input object sent when passing in a color
-interface ColorInput {
+export interface ColorInput {
   red: number;
   green: number;
   blue: number;
@@ -667,14 +667,14 @@ export enum Episode {
 }
 
 // The input object sent when someone is creating a new review
-interface ReviewInput {
+export interface ReviewInput {
   stars: number;
   commentary?: string | null;
   favorite_color?: ColorInput | null;
 }
 
 // The input object sent when passing in a color
-interface ColorInput {
+export interface ColorInput {
   red: number;
   green: number;
   blue: number;
@@ -719,14 +719,14 @@ export enum Episode {
 }
 
 // The input object sent when someone is creating a new review
-interface ReviewInput {
+export interface ReviewInput {
   stars: number;
   commentary?: string | null;
   favorite_color?: ColorInput | null;
 }
 
 // The input object sent when passing in a color
-interface ColorInput {
+export interface ColorInput {
   red: number;
   green: number;
   blue: number;
@@ -938,14 +938,14 @@ export enum Episode {
 }
 
 // The input object sent when someone is creating a new review
-interface ReviewInput {
+export interface ReviewInput {
   stars: number;
   commentary?: string | null;
   favorite_color?: ColorInput | null;
 }
 
 // The input object sent when passing in a color
-interface ColorInput {
+export interface ColorInput {
   red: number;
   green: number;
   blue: number;
diff --git a/test/scala/__snapshots__/codeGeneration.js.snap b/test/scala/__snapshots__/codeGeneration.js.snap
index 3c246851..072b70dd 100644
--- a/test/scala/__snapshots__/codeGeneration.js.snap
+++ b/test/scala/__snapshots__/codeGeneration.js.snap
@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Scala code generation #caseClassDeclarationForFragment() should generate a caseClass declaration for a fragment that includes a fragment spread 1`] = `
-"case class HeroDetails(name: String, appearsIn: Seq[Option[String]]) extends me.shadaj.slinky.core.WithRaw {
+"case class HeroDetails(name: String, appearsIn: Seq[Option[String]]) extends slinky.readwrite.WithRaw {
 }
 
 object HeroDetails {
@@ -30,11 +30,19 @@ object DroidDetails {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForFragment() should generate a caseClass declaration for a fragment with a subselection 1`] = `
-"case class HeroDetails(name: String, friends: Option[Seq[Option[Friend]]]) extends me.shadaj.slinky.core.WithRaw {
+"case class HeroDetails(name: String, friends: Option[Seq[Option[HeroDetails.Friend]]]) extends slinky.readwrite.WithRaw {
 }
 
 object HeroDetails {
   val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+
+
+  case class Friend(name: String) extends slinky.readwrite.WithRaw {
+  }
+
+  object Friend {
+    val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+  }
   val fragmentString =
     \\"fragment HeroDetails on Character {\\" +
     \\"  name\\" +
@@ -42,19 +50,11 @@ object HeroDetails {
     \\"    name\\" +
     \\"  }\\" +
     \\"}\\"
-}
-
-
-case class Friend(name: String) extends me.shadaj.slinky.core.WithRaw {
-}
-
-object Friend {
-  val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
 }"
 `;
 
 exports[`Scala code generation #caseClassDeclarationForFragment() should generate a caseClass declaration for a fragment with an abstract type condition 1`] = `
-"case class HeroDetails(name: String, appearsIn: Seq[Option[String]]) extends me.shadaj.slinky.core.WithRaw {
+"case class HeroDetails(name: String, appearsIn: Seq[Option[String]]) extends slinky.readwrite.WithRaw {
 }
 
 object HeroDetails {
@@ -68,7 +68,7 @@ object HeroDetails {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForSelectionSet() should escape reserved keywords in a caseClass declaration for a selection set 1`] = `
-"case class Hero(private: Option[String]) extends me.shadaj.slinky.core.WithRaw {
+"case class Hero(private: Option[String]) extends slinky.readwrite.WithRaw {
 }
 
 object Hero {
@@ -77,9 +77,9 @@ object Hero {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForSelectionSet() should generate a caseClass declaration for a fragment spread nested in an inline fragment 1`] = `
-"case class Hero() extends me.shadaj.slinky.core.WithRaw {
+"case class Hero() extends slinky.readwrite.WithRaw {
   def asDroid: Option[AsDroid] = {
-    if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[AsDroid]].read(this.raw)) else None
+    if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[AsDroid]].read(this.raw)) else None
   }
 }
 
@@ -98,7 +98,7 @@ object Hero {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForSelectionSet() should generate a caseClass declaration for a selection set 1`] = `
-"case class Hero(name: Option[String]) extends me.shadaj.slinky.core.WithRaw {
+"case class Hero(name: Option[String]) extends slinky.readwrite.WithRaw {
 }
 
 object Hero {
@@ -107,7 +107,7 @@ object Hero {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForSelectionSet() should generate a caseClass declaration for a selection set with a fragment spread that matches the parent type 1`] = `
-"case class Hero(name: Option[String]) extends me.shadaj.slinky.core.WithRaw {
+"case class Hero(name: Option[String]) extends slinky.readwrite.WithRaw {
 }
 
 object Hero {
@@ -117,9 +117,9 @@ object Hero {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForSelectionSet() should generate a caseClass declaration for a selection set with a fragment spread with a more specific type condition 1`] = `
-"case class Hero(name: Option[String]) extends me.shadaj.slinky.core.WithRaw {
+"case class Hero(name: Option[String]) extends slinky.readwrite.WithRaw {
   def asDroidDetails: Option[DroidDetails] = {
-    if (DroidDetails.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[DroidDetails]].read(this.raw)) else None
+    if (DroidDetails.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[DroidDetails]].read(this.raw)) else None
   }
 }
 
@@ -129,9 +129,9 @@ object Hero {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForSelectionSet() should generate a caseClass declaration for a selection set with an inline fragment 1`] = `
-"case class Hero(name: String) extends me.shadaj.slinky.core.WithRaw {
+"case class Hero(name: String) extends slinky.readwrite.WithRaw {
   def asDroid: Option[AsDroid] = {
-    if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[AsDroid]].read(this.raw)) else None
+    if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[AsDroid]].read(this.raw)) else None
   }
 }
 
@@ -149,19 +149,19 @@ object Hero {
 `;
 
 exports[`Scala code generation #caseClassDeclarationForSelectionSet() should generate a nested caseClass declaration for a selection set with subselections 1`] = `
-"case class Hero(friends: Option[Seq[Option[Friend]]]) extends me.shadaj.slinky.core.WithRaw {
+"case class Hero(friends: Option[Seq[Option[Hero.Friend]]]) extends slinky.readwrite.WithRaw {
 }
 
 object Hero {
   val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
-}
 
 
-case class Friend(name: Option[String]) extends me.shadaj.slinky.core.WithRaw {
-}
+  case class Friend(name: Option[String]) extends slinky.readwrite.WithRaw {
+  }
 
-object Friend {
-  val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+  object Friend {
+    val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+  }
 }"
 `;
 
@@ -180,18 +180,18 @@ exports[`Scala code generation #classDeclarationForOperation() should generate a
   case class Variables(episode: Option[String]) {
   }
 
-  case class Data(createReview: Option[CreateReview]) {
+  case class Data(createReview: Option[Data.CreateReview]) {
   }
 
   object Data {
     val possibleTypes = scala.collection.Set(\\"Mutation\\")
-  }
 
-  case class CreateReview(stars: Int, commentary: Option[String]) {
-  }
+    case class CreateReview(stars: Int, commentary: Option[String]) {
+    }
 
-  object CreateReview {
-    val possibleTypes = scala.collection.Set(\\"Review\\")
+    object CreateReview {
+      val possibleTypes = scala.collection.Set(\\"Review\\")
+    }
   }
 }"
 `;
@@ -212,31 +212,31 @@ exports[`Scala code generation #classDeclarationForOperation() should generate a
 
   type Variables = Unit
 
-  case class Data(hero: Option[Hero]) {
+  case class Data(hero: Option[Data.Hero]) {
   }
 
   object Data {
     val possibleTypes = scala.collection.Set(\\"Query\\")
-  }
 
 
-  case class Hero() extends me.shadaj.slinky.core.WithRaw {
-    def asDroid: Option[AsDroid] = {
-      if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[AsDroid]].read(this.raw)) else None
+    case class Hero() extends slinky.readwrite.WithRaw {
+      def asDroid: Option[AsDroid] = {
+        if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[AsDroid]].read(this.raw)) else None
+      }
     }
-  }
 
-  case class AsDroid(name: String) {
-  }
+    case class AsDroid(name: String) {
+    }
 
-  object AsDroid {
-    val possibleTypes = scala.collection.Set(\\"Droid\\")
-    implicit def toHero(a: AsDroid): Hero = Hero()
-    implicit def toHeroDetails(a: AsDroid): HeroDetails = HeroDetails(a.name)
-  }
+    object AsDroid {
+      val possibleTypes = scala.collection.Set(\\"Droid\\")
+      implicit def toHero(a: AsDroid): Hero = Hero()
+      implicit def toHeroDetails(a: AsDroid): HeroDetails = HeroDetails(a.name)
+    }
 
-  object Hero {
-    val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+    object Hero {
+      val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+    }
   }
 }"
 `;
@@ -255,34 +255,34 @@ exports[`Scala code generation #classDeclarationForOperation() should generate a
 
   type Variables = Unit
 
-  case class Data(hero: Option[Hero]) {
+  case class Data(hero: Option[Data.Hero]) {
   }
 
   object Data {
     val possibleTypes = scala.collection.Set(\\"Query\\")
-  }
 
 
-  case class Hero() extends me.shadaj.slinky.core.WithRaw {
-    def asDroid: Option[AsDroid] = {
-      if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[AsDroid]].read(this.raw)) else None
-    }
-    def asDroidDetails: Option[DroidDetails] = {
-      if (DroidDetails.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[me.shadaj.slinky.core.Reader[DroidDetails]].read(this.raw)) else None
+    case class Hero() extends slinky.readwrite.WithRaw {
+      def asDroid: Option[AsDroid] = {
+        if (AsDroid.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[AsDroid]].read(this.raw)) else None
+      }
+      def asDroidDetails: Option[DroidDetails] = {
+        if (DroidDetails.possibleTypes.contains(this.raw.__typename.asInstanceOf[String])) Some(implicitly[slinky.readwrite.Reader[DroidDetails]].read(this.raw)) else None
+      }
     }
-  }
 
-  case class AsDroid(primaryFunction: Option[String]) {
-  }
+    case class AsDroid(primaryFunction: Option[String]) {
+    }
 
-  object AsDroid {
-    val possibleTypes = scala.collection.Set(\\"Droid\\")
-    implicit def toHero(a: AsDroid): Hero = Hero()
-    implicit def toDroidDetails(a: AsDroid): DroidDetails = DroidDetails(a.primaryFunction)
-  }
+    object AsDroid {
+      val possibleTypes = scala.collection.Set(\\"Droid\\")
+      implicit def toHero(a: AsDroid): Hero = Hero()
+      implicit def toDroidDetails(a: AsDroid): DroidDetails = DroidDetails(a.primaryFunction)
+    }
 
-  object Hero {
-    val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+    object Hero {
+      val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+    }
   }
 }"
 `;
@@ -301,20 +301,20 @@ exports[`Scala code generation #classDeclarationForOperation() should generate a
 
   type Variables = Unit
 
-  case class Data(hero: Option[Hero]) {
+  case class Data(hero: Option[Data.Hero]) {
   }
 
   object Data {
     val possibleTypes = scala.collection.Set(\\"Query\\")
-  }
 
 
-  case class Hero(name: String) extends me.shadaj.slinky.core.WithRaw {
-  }
+    case class Hero(name: String) extends slinky.readwrite.WithRaw {
+    }
 
-  object Hero {
-    val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
-    implicit def toHeroDetails(a: Hero): HeroDetails = HeroDetails(a.name)
+    object Hero {
+      val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+      implicit def toHeroDetails(a: Hero): HeroDetails = HeroDetails(a.name)
+    }
   }
 }"
 `;
@@ -333,19 +333,19 @@ exports[`Scala code generation #classDeclarationForOperation() should generate a
   case class Variables(episode: Option[String]) {
   }
 
-  case class Data(hero: Option[Hero]) {
+  case class Data(hero: Option[Data.Hero]) {
   }
 
   object Data {
     val possibleTypes = scala.collection.Set(\\"Query\\")
-  }
 
 
-  case class Hero(name: String) extends me.shadaj.slinky.core.WithRaw {
-  }
+    case class Hero(name: String) extends slinky.readwrite.WithRaw {
+    }
 
-  object Hero {
-    val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+    object Hero {
+      val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+    }
   }
 }"
 `;
@@ -366,20 +366,20 @@ exports[`Scala code generation #classDeclarationForOperation() when generateOper
 
   type Variables = Unit
 
-  case class Data(hero: Option[Hero]) {
+  case class Data(hero: Option[Data.Hero]) {
   }
 
   object Data {
     val possibleTypes = scala.collection.Set(\\"Query\\")
-  }
 
 
-  case class Hero(name: String) extends me.shadaj.slinky.core.WithRaw {
-  }
+    case class Hero(name: String) extends slinky.readwrite.WithRaw {
+    }
 
-  object Hero {
-    val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
-    implicit def toHeroDetails(a: Hero): HeroDetails = HeroDetails(a.name)
+    object Hero {
+      val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+      implicit def toHeroDetails(a: Hero): HeroDetails = HeroDetails(a.name)
+    }
   }
 }"
 `;
@@ -399,6 +399,61 @@ fragment HeroName on Character {
 }"
 `;
 
+exports[`Scala code generation #generateSource() should emit a package declaration when the namespace option is specified 1`] = `
+"//  This file was automatically generated and should not be edited.
+
+
+package hello.world
+
+/**
+ * The episodes in the Star Wars trilogy
+ */
+object Episode {
+  /**
+   * Star Wars Episode IV: A New Hope, released in 1977.
+   */
+  val newhope = \\"NEWHOPE\\"
+  /**
+   * Star Wars Episode V: The Empire Strikes Back, released in 1980.
+   */
+  val empire = \\"EMPIRE\\"
+  /**
+   * Star Wars Episode VI: Return of the Jedi, released in 1983.
+   */
+  val jedi = \\"JEDI\\"
+}
+
+
+object HeroNameQuery extends com.apollographql.scalajs.GraphQLQuery {
+  val operationString =
+    \\"query HeroName($episode: Episode) {\\" +
+    \\"  hero(episode: $episode) {\\" +
+    \\"    name\\" +
+    \\"  }\\" +
+    \\"}\\"
+  val operation = com.apollographql.scalajs.gql(operationString)
+
+
+  case class Variables(episode: Option[String]) {
+  }
+
+  case class Data(hero: Option[Data.Hero]) {
+  }
+
+  object Data {
+    val possibleTypes = scala.collection.Set(\\"Query\\")
+
+
+    case class Hero(name: String) extends slinky.readwrite.WithRaw {
+    }
+
+    object Hero {
+      val possibleTypes = scala.collection.Set(\\"Human\\", \\"Droid\\")
+    }
+  }
+}"
+`;
+
 exports[`Scala code generation #typeDeclarationForGraphQLType() should escape identifiers in cases of enum declaration for a GraphQLEnumType 1`] = `
 "object AlbumPrivacies {
   val public = \\"PUBLIC\\"
@@ -411,7 +466,7 @@ exports[`Scala code generation #typeDeclarationForGraphQLType() should generate
 "/**
  * The input object sent when someone is creating a new review
  */
-case class ReviewInput(stars: Int, commentary: Option[String], favoriteColor: Option[ColorInput]) {
+case class ReviewInput(stars: Int, commentary: scala.scalajs.js.UndefOr[String] = scala.scalajs.js.undefined, favoriteColor: scala.scalajs.js.UndefOr[ColorInput] = scala.scalajs.js.undefined) {
 }"
 `;
 
diff --git a/test/scala/codeGeneration.js b/test/scala/codeGeneration.js
index 1a4d4216..65b8f30d 100644
--- a/test/scala/codeGeneration.js
+++ b/test/scala/codeGeneration.js
@@ -13,16 +13,13 @@ import {
 } from 'graphql';
 
 import {
+  generateSource,
   classDeclarationForOperation,
   caseClassDeclarationForFragment,
   caseClassDeclarationForSelectionSet,
   typeDeclarationForGraphQLType,
 } from '../../src/scala/codeGeneration';
 
-import {
-  dictionaryLiteralForFieldArguments,
-} from '../../src/scala/values';
-
 import { loadSchema } from '../../src/loading';
 const schema = loadSchema(require.resolve('../fixtures/starwars/schema.json'));
 
@@ -51,7 +48,8 @@ describe('Scala code generation', function() {
     compileFromSource = (source, options = { generateOperationIds: false }) => {
       const document = parse(source);
       let context = compileToLegacyIR(schema, document);
-      options.generateOperationIds && Object.assign(context, { generateOperationIds: true, operationIdsMap: {} });
+      options.generateOperationIds && Object.assign(context.options, { generateOperationIds: true, operationIdsMap: {} });
+      options.namespace && Object.assign(context.options, { namespace: options.namespace });
       generator.context = context;
       return context;
     };
@@ -63,6 +61,20 @@ describe('Scala code generation', function() {
     resetGenerator();
   });
 
+  describe('#generateSource()', function() {
+    test(`should emit a package declaration when the namespace option is specified`, function() {
+      const context = compileFromSource(`
+        query HeroName($episode: Episode) {
+          hero(episode: $episode) {
+            name
+          }
+        }
+      `, { namespace: "hello.world" });
+
+      expect(generateSource(context)).toMatchSnapshot();
+    });
+  });
+
   describe('#classDeclarationForOperation()', function() {
     test(`should generate a class declaration for a query with variables`, function() {
       const { operations, fragments } = compileFromSource(`
@@ -504,26 +516,9 @@ describe('Scala code generation', function() {
     });
   });
 
-  describe('#dictionaryLiteralForFieldArguments()', function() {
-    test('should include expressions for input objects with variables', function() {
-      const { operations } = compileFromSource(`
-        mutation FieldArgumentsWithInputObjects($commentary: String!, $red: Int!) {
-          createReview(episode: JEDI, review: { stars: 2, commentary: $commentary, favorite_color: { red: $red, blue: 100, green: 50 } }) {
-            commentary
-          }
-        }
-      `);
-
-      const fieldArguments = operations['FieldArgumentsWithInputObjects'].fields[0].args;
-      const dictionaryLiteral = dictionaryLiteralForFieldArguments(fieldArguments);
-
-      expect(dictionaryLiteral).toBe('["episode": "JEDI", "review": ["stars": 2, "commentary": Variable("commentary"), "favorite_color": ["red": Variable("red"), "blue": 100, "green": 50]]]');
-    });
-  });
-
   describe('#typeDeclarationForGraphQLType()', function() {
     test('should generate an enum declaration for a GraphQLEnumType', function() {
-      const generator = new CodeGenerator();
+      const generator = new CodeGenerator({options: {}});
 
       typeDeclarationForGraphQLType(generator, schema.getType('Episode'));
 
@@ -531,7 +526,7 @@ describe('Scala code generation', function() {
     });
 
     test('should escape identifiers in cases of enum declaration for a GraphQLEnumType', function() {
-      const generator = new CodeGenerator();
+      const generator = new CodeGenerator({options: {}});
 
       const albumPrivaciesEnum = new GraphQLEnumType({
         name: 'AlbumPrivacies',
@@ -544,7 +539,7 @@ describe('Scala code generation', function() {
     });
 
     test('should generate a caseClass declaration for a GraphQLInputObjectType', function() {
-      const generator = new CodeGenerator();
+      const generator = new CodeGenerator({options: {}});
 
       typeDeclarationForGraphQLType(generator, schema.getType('ReviewInput'));
 
diff --git a/test/scala/types.js b/test/scala/types.js
index 0139cfea..68ce1bb4 100644
--- a/test/scala/types.js
+++ b/test/scala/types.js
@@ -21,63 +21,63 @@ import { typeNameFromGraphQLType } from '../../src/scala/types'
 describe('Scala code generation: Types', function() {
   describe('#typeNameFromGraphQLType()', function() {
     test('should return Option[String] for GraphQLString', function() {
-      expect(typeNameFromGraphQLType({}, GraphQLString)).toBe('Option[String]');
+      expect(typeNameFromGraphQLType({options:{}}, GraphQLString)).toBe('Option[String]');
     });
 
     test('should return String for GraphQLNonNull(GraphQLString)', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLNonNull(GraphQLString))).toBe('String');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLNonNull(GraphQLString))).toBe('String');
     });
 
     test('should return Option[Seq[Option[String]]] for GraphQLList(GraphQLString)', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLList(GraphQLString))).toBe('Option[Seq[Option[String]]]');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLList(GraphQLString))).toBe('Option[Seq[Option[String]]]');
     });
 
     test('should return Seq[String] for GraphQLNonNull(GraphQLList(GraphQLString))', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLNonNull(new GraphQLList(GraphQLString)))).toBe('Seq[Option[String]]');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLNonNull(new GraphQLList(GraphQLString)))).toBe('Seq[Option[String]]');
     });
 
     test('should return Option[Seq[String]] for GraphQLList(GraphQLNonNull(GraphQLString))', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLList(new GraphQLNonNull(GraphQLString)))).toBe('Option[Seq[String]]');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLList(new GraphQLNonNull(GraphQLString)))).toBe('Option[Seq[String]]');
     });
 
     test('should return Seq[String] for GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString)))', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLString))))).toBe('Seq[String]');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLString))))).toBe('Seq[String]');
     });
 
     test('should return Option[Seq[Option[Seq[Option[String]]]]] for GraphQLList(GraphQLList(GraphQLString))', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLList(new GraphQLList(GraphQLString)))).toBe('Option[Seq[Option[Seq[Option[String]]]]]');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLList(new GraphQLList(GraphQLString)))).toBe('Option[Seq[Option[Seq[Option[String]]]]]');
     });
 
     test('should return Option[Seq[Seq[Option[String]]]] for GraphQLList(GraphQLNonNull(GraphQLList(GraphQLString)))', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLList(new GraphQLNonNull(new GraphQLList(GraphQLString))))).toBe('Option[Seq[Seq[Option[String]]]]');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLList(new GraphQLNonNull(new GraphQLList(GraphQLString))))).toBe('Option[Seq[Seq[Option[String]]]]');
     });
 
     test('should return Option[Int] for GraphQLInt', function() {
-      expect(typeNameFromGraphQLType({}, GraphQLInt)).toBe('Option[Int]');
+      expect(typeNameFromGraphQLType({options:{}}, GraphQLInt)).toBe('Option[Int]');
     });
 
     test('should return Option[Double] for GraphQLFloat', function() {
-      expect(typeNameFromGraphQLType({}, GraphQLFloat)).toBe('Option[Double]');
+      expect(typeNameFromGraphQLType({options:{}}, GraphQLFloat)).toBe('Option[Double]');
     });
 
     test('should return Option[Boolean] for GraphQLBoolean', function() {
-      expect(typeNameFromGraphQLType({}, GraphQLBoolean)).toBe('Option[Boolean]');
+      expect(typeNameFromGraphQLType({options:{}}, GraphQLBoolean)).toBe('Option[Boolean]');
     });
 
     test('should return Option[String] for GraphQLID', function() {
-      expect(typeNameFromGraphQLType({}, GraphQLID)).toBe('Option[String]');
+      expect(typeNameFromGraphQLType({options:{}}, GraphQLID)).toBe('Option[String]');
     });
 
     test('should return Option[String] for a custom scalar type', function() {
-      expect(typeNameFromGraphQLType({}, new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe('Option[String]');
+      expect(typeNameFromGraphQLType({options:{}}, new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe('Option[String]');
     });
 
     test('should return a passed through custom scalar type with the passthroughCustomScalars option', function() {
-      expect(typeNameFromGraphQLType({ passthroughCustomScalars: true, customScalarsPrefix: '' }, new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe('Option[CustomScalarType]');
+      expect(typeNameFromGraphQLType({options: { passthroughCustomScalars: true, customScalarsPrefix: '' } }, new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe('Option[CustomScalarType]');
     });
 
     test('should return a passed through custom scalar type with a prefix with the customScalarsPrefix option', function() {
-      expect(typeNameFromGraphQLType({ passthroughCustomScalars: true, customScalarsPrefix: 'My' }, new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe('Option[MyCustomScalarType]');
+      expect(typeNameFromGraphQLType({options: { passthroughCustomScalars: true, customScalarsPrefix: 'My' } }, new GraphQLScalarType({ name: 'CustomScalarType', serialize: String }))).toBe('Option[MyCustomScalarType]');
     });
   });
 });
diff --git a/test/typescript/__snapshots__/codeGeneration.js.snap b/test/typescript/__snapshots__/codeGeneration.js.snap
index cfde0282..99ede263 100644
--- a/test/typescript/__snapshots__/codeGeneration.js.snap
+++ b/test/typescript/__snapshots__/codeGeneration.js.snap
@@ -4,11 +4,22 @@ exports[`TypeScript code generation #generateSource() should generate correct li
 "/* tslint:disable */
 //  This file was automatically generated and should not be edited.
 
-// The episodes in the Star Wars trilogy
+/**
+ * The episodes in the Star Wars trilogy
+ */
 export enum Episode {
-  EMPIRE = \\"EMPIRE\\", // Star Wars Episode V: The Empire Strikes Back, released in 1980.
-  JEDI = \\"JEDI\\", // Star Wars Episode VI: Return of the Jedi, released in 1983.
-  NEWHOPE = \\"NEWHOPE\\", // Star Wars Episode IV: A New Hope, released in 1977.
+  /**
+   * Star Wars Episode V: The Empire Strikes Back, released in 1980.
+   */
+  EMPIRE = \\"EMPIRE\\",
+  /**
+   * Star Wars Episode VI: Return of the Jedi, released in 1983.
+   */
+  JEDI = \\"JEDI\\",
+  /**
+   * Star Wars Episode IV: A New Hope, released in 1977.
+   */
+  NEWHOPE = \\"NEWHOPE\\",
 }
 
 
@@ -19,31 +30,47 @@ export interface HeroAndFriendsNamesQueryVariables {
 export interface HeroAndFriendsNamesQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
@@ -53,11 +80,15 @@ export interface HeroAndFriendsNamesQuery {
 
 export type FriendFragment = ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     }
   );
@@ -71,31 +102,47 @@ exports[`TypeScript code generation #generateSource() should generate fragmented
 export interface HeroAndFriendsNamesQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
@@ -105,27 +152,39 @@ export interface HeroAndFriendsNamesQuery {
 
 export type heroFriendsFragment = ( {
       __typename: \\"Human\\",
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
     } | {
       __typename: \\"Droid\\",
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
@@ -138,20 +197,37 @@ exports[`TypeScript code generation #generateSource() should generate mutation o
 "/* tslint:disable */
 //  This file was automatically generated and should not be edited.
 
-// The episodes in the Star Wars trilogy
+/**
+ * The episodes in the Star Wars trilogy
+ */
 export enum Episode {
-  EMPIRE = \\"EMPIRE\\", // Star Wars Episode V: The Empire Strikes Back, released in 1980.
-  JEDI = \\"JEDI\\", // Star Wars Episode VI: Return of the Jedi, released in 1983.
-  NEWHOPE = \\"NEWHOPE\\", // Star Wars Episode IV: A New Hope, released in 1977.
+  /**
+   * Star Wars Episode V: The Empire Strikes Back, released in 1980.
+   */
+  EMPIRE = \\"EMPIRE\\",
+  /**
+   * Star Wars Episode VI: Return of the Jedi, released in 1983.
+   */
+  JEDI = \\"JEDI\\",
+  /**
+   * Star Wars Episode IV: A New Hope, released in 1977.
+   */
+  NEWHOPE = \\"NEWHOPE\\",
 }
 
 
 export interface ReviewInput {
-  // 0-5 stars
+  /**
+   * 0-5 stars
+   */
   stars: number,
-  // Comment about the movie, optional
+  /**
+   * Comment about the movie, optional
+   */
   commentary?: string | null,
-  // Favorite color, optional
+  /**
+   * Favorite color, optional
+   */
   favorite_color?: ColorInput | null,
 };
 
@@ -169,9 +245,13 @@ export interface ReviewMovieMutationVariables {
 export interface ReviewMovieMutation {
   createReview:  {
     __typename: \\"Review\\",
-    // The number of stars this review gave, 1-5
+    /**
+     * The number of stars this review gave, 1-5
+     */
     stars: number,
-    // Comment about the movie
+    /**
+     * Comment about the movie
+     */
     commentary: string | null,
   } | null,
 };
@@ -185,15 +265,23 @@ exports[`TypeScript code generation #generateSource() should generate query oper
 export interface HeroAndDetailsQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // What this human calls themselves
+      /**
+       * What this human calls themselves
+       */
       name: string,
-      // Height in the preferred unit, default is meters
+      /**
+       * Height in the preferred unit, default is meters
+       */
       height: number | null,
     } | {
       __typename: \\"Droid\\",
-      // What others call this droid
+      /**
+       * What others call this droid
+       */
       name: string,
-      // This droid's primary function
+      /**
+       * This droid's primary function
+       */
       primaryFunction: string | null,
     }
   ) | null,
@@ -201,11 +289,15 @@ export interface HeroAndDetailsQuery {
 
 export type HeroDetailsFragment = ( {
       __typename: \\"Human\\",
-      // Height in the preferred unit, default is meters
+      /**
+       * Height in the preferred unit, default is meters
+       */
       height: number | null,
     } | {
       __typename: \\"Droid\\",
-      // This droid's primary function
+      /**
+       * This droid's primary function
+       */
       primaryFunction: string | null,
     }
   );
@@ -216,11 +308,22 @@ exports[`TypeScript code generation #generateSource() should generate simple nes
 "/* tslint:disable */
 //  This file was automatically generated and should not be edited.
 
-// The episodes in the Star Wars trilogy
+/**
+ * The episodes in the Star Wars trilogy
+ */
 export enum Episode {
-  EMPIRE = \\"EMPIRE\\", // Star Wars Episode V: The Empire Strikes Back, released in 1980.
-  JEDI = \\"JEDI\\", // Star Wars Episode VI: Return of the Jedi, released in 1983.
-  NEWHOPE = \\"NEWHOPE\\", // Star Wars Episode IV: A New Hope, released in 1977.
+  /**
+   * Star Wars Episode V: The Empire Strikes Back, released in 1980.
+   */
+  EMPIRE = \\"EMPIRE\\",
+  /**
+   * Star Wars Episode VI: Return of the Jedi, released in 1983.
+   */
+  JEDI = \\"JEDI\\",
+  /**
+   * Star Wars Episode IV: A New Hope, released in 1977.
+   */
+  NEWHOPE = \\"NEWHOPE\\",
 }
 
 
@@ -231,31 +334,47 @@ export interface HeroAndFriendsNamesQueryVariables {
 export interface HeroAndFriendsNamesQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
-      // The friends of the character, or an empty list if they have none
+      /**
+       * The friends of the character, or an empty list if they have none
+       */
       friends:  Array<( {
           __typename: \\"Human\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         } | {
           __typename: \\"Droid\\",
-          // The name of the character
+          /**
+           * The name of the character
+           */
           name: string,
         }
       ) | null > | null,
@@ -285,11 +404,15 @@ exports[`TypeScript code generation #generateSource() should generate simple que
 export interface HeroNameQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     }
   ) | null,
@@ -301,11 +424,22 @@ exports[`TypeScript code generation #generateSource() should generate simple que
 "/* tslint:disable */
 //  This file was automatically generated and should not be edited.
 
-// The episodes in the Star Wars trilogy
+/**
+ * The episodes in the Star Wars trilogy
+ */
 export enum Episode {
-  EMPIRE = \\"EMPIRE\\", // Star Wars Episode V: The Empire Strikes Back, released in 1980.
-  JEDI = \\"JEDI\\", // Star Wars Episode VI: Return of the Jedi, released in 1983.
-  NEWHOPE = \\"NEWHOPE\\", // Star Wars Episode IV: A New Hope, released in 1977.
+  /**
+   * Star Wars Episode V: The Empire Strikes Back, released in 1980.
+   */
+  EMPIRE = \\"EMPIRE\\",
+  /**
+   * Star Wars Episode VI: Return of the Jedi, released in 1983.
+   */
+  JEDI = \\"JEDI\\",
+  /**
+   * Star Wars Episode IV: A New Hope, released in 1977.
+   */
+  NEWHOPE = \\"NEWHOPE\\",
 }
 
 
@@ -316,11 +450,15 @@ export interface HeroNameQueryVariables {
 export interface HeroNameQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     }
   ) | null,
@@ -333,10 +471,15 @@ exports[`TypeScript code generation #generateSource() should handle comments in
 //  This file was automatically generated and should not be edited.
 
 export enum EnumCommentTestCase {
-  first = \\"first\\", // This is a single-line comment
-  // This is a
-  // multi-line
-  // comment.
+  /**
+   * This is a single-line comment
+   */
+  first = \\"first\\",
+  /**
+   * This is a
+   * multi-line
+   * comment.
+   */
   second = \\"second\\",
 }
 
@@ -376,9 +519,11 @@ exports[`TypeScript code generation #generateSource() should handle multi-line c
 export interface CustomScalarQuery {
   commentTest:  {
     __typename: \\"CommentTest\\",
-    // This is a
-    // multi-line
-    // comment.
+    /**
+     * This is a
+     * multi-line
+     * comment.
+     */
     multiLine: string | null,
   } | null,
 };
@@ -392,7 +537,9 @@ exports[`TypeScript code generation #generateSource() should handle single line
 export interface CustomScalarQuery {
   commentTest:  {
     __typename: \\"CommentTest\\",
-    // This is a single-line comment
+    /**
+     * This is a single-line comment
+     */
     singleLine: string | null,
   } | null,
 };
@@ -423,47 +570,71 @@ exports[`TypeScript code generation #generateSource() should have __typename val
 export interface HeroNameQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // The friends of the human exposed as a connection with edges
+      /**
+       * The friends of the human exposed as a connection with edges
+       */
       friendsConnection:  {
         __typename: \\"FriendsConnection\\",
-        // The edges for each of the character's friends.
+        /**
+         * The edges for each of the character's friends.
+         */
         edges:  Array< {
           __typename: \\"FriendsEdge\\",
-          // The character represented by this friendship edge
+          /**
+           * The character represented by this friendship edge
+           */
           node: ( {
               __typename: \\"Human\\",
-              // The name of the character
+              /**
+               * The name of the character
+               */
               name: string,
             } | {
               __typename: \\"Droid\\",
-              // The name of the character
+              /**
+               * The name of the character
+               */
               name: string,
             }
           ) | null,
         } | null > | null,
       },
-      // A list of starships this person has piloted, or an empty list if none
+      /**
+       * A list of starships this person has piloted, or an empty list if none
+       */
       starships:  Array< {
         __typename: \\"Starship\\",
-        // The name of the starship
+        /**
+         * The name of the starship
+         */
         name: string,
       } | null > | null,
     } | {
       __typename: \\"Droid\\",
-      // The friends of the character exposed as a connection with edges
+      /**
+       * The friends of the character exposed as a connection with edges
+       */
       friendsConnection:  {
         __typename: \\"FriendsConnection\\",
-        // The edges for each of the character's friends.
+        /**
+         * The edges for each of the character's friends.
+         */
         edges:  Array< {
           __typename: \\"FriendsEdge\\",
-          // The character represented by this friendship edge
+          /**
+           * The character represented by this friendship edge
+           */
           node: ( {
               __typename: \\"Human\\",
-              // The name of the character
+              /**
+               * The name of the character
+               */
               name: string,
             } | {
               __typename: \\"Droid\\",
-              // The name of the character
+              /**
+               * The name of the character
+               */
               name: string,
             }
           ) | null,
@@ -482,11 +653,15 @@ exports[`TypeScript code generation #generateSource() should have __typename val
 export interface HeroNameQuery {
   hero: ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     }
   ) | null,
@@ -494,11 +669,15 @@ export interface HeroNameQuery {
 
 export type HeroWithNameFragment = ( {
       __typename: \\"Human\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     } | {
       __typename: \\"Droid\\",
-      // The name of the character
+      /**
+       * The name of the character
+       */
       name: string,
     }
   );
@@ -512,14 +691,18 @@ exports[`TypeScript code generation #generateSource() should have __typename val
 export interface DroidNameQuery {
   droid:  {
     __typename: \\"Droid\\",
-    // What others call this droid
+    /**
+     * What others call this droid
+     */
     name: string,
   } | null,
 };
 
 export interface DroidWithNameFragment {
   __typename: \\"Droid\\",
-  // What others call this droid
+  /**
+   * What others call this droid
+   */
   name: string,
 };
 "