Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

apollo-codegen-typescript

Package Overview
Dependencies
Maintainers
1
Versions
167
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

apollo-codegen-typescript - npm Package Compare versions

Comparing version 0.26.0 to 0.27.0

16

lib/codeGeneration.d.ts

@@ -20,2 +20,13 @@ import { GraphQLEnumType, GraphQLInputObjectType } from 'graphql';

};
interface IGeneratedFileOptions {
outputPath?: string;
globalSourcePath?: string;
}
interface IGeneratedFile {
sourcePath: string;
fileName: string;
content: (options?: IGeneratedFileOptions) => TypescriptGeneratedFile;
}
export declare function generateLocalSource(context: CompilerContext): IGeneratedFile[];
export declare function generateGlobalSource(context: CompilerContext): TypescriptGeneratedFile;
export declare class TypescriptAPIGenerator extends TypescriptGenerator {

@@ -31,2 +42,7 @@ context: CompilerContext;

interfacesForFragment(fragment: Fragment): void;
getGlobalTypesUsedForOperation: (doc: Operation) => GraphQLType[];
getGlobalTypesUsedForFragment: (doc: Fragment) => GraphQLType[];
private reduceSelection;
private isGlobalType;
private getUnderlyingType;
getTypesUsedForOperation(doc: Operation | Fragment, context: CompilerContext): GraphQLType[];

@@ -33,0 +49,0 @@ private reduceTypesUsed;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const t = require("@babel/types");

@@ -42,2 +43,8 @@ const common_tags_1 = require("common-tags");

}
function printGlobalImport(generator, typesUsed, outputPath, globalSourcePath) {
if (typesUsed.length > 0) {
const relative = path.relative(path.dirname(outputPath), path.join(path.dirname(globalSourcePath), path.basename(globalSourcePath, '.ts')));
generator.printer.enqueue(generator.import(typesUsed, relative));
}
}
function generateSource(context) {

@@ -77,5 +84,84 @@ const generator = new TypescriptAPIGenerator(context);

exports.generateSource = generateSource;
function generateLocalSource(context) {
const generator = new TypescriptAPIGenerator(context);
const operations = Object.values(context.operations)
.map((operation) => ({
sourcePath: operation.filePath,
fileName: `${operation.operationName}.ts`,
content: (options) => {
generator.fileHeader();
if (options && options.outputPath && options.globalSourcePath) {
printGlobalImport(generator, generator.getGlobalTypesUsedForOperation(operation), options.outputPath, options.globalSourcePath);
}
generator.interfacesForOperation(operation);
const output = generator.printer.printAndClear();
return new TypescriptGeneratedFile(output);
},
}));
const fragments = Object.values(context.fragments)
.map((fragment) => ({
sourcePath: fragment.filePath,
fileName: `${fragment.fragmentName}.ts`,
content: (options) => {
generator.fileHeader();
if (options && options.outputPath && options.globalSourcePath) {
printGlobalImport(generator, generator.getGlobalTypesUsedForFragment(fragment), options.outputPath, options.globalSourcePath);
}
generator.interfacesForFragment(fragment);
const output = generator.printer.printAndClear();
return new TypescriptGeneratedFile(output);
},
}));
return operations.concat(fragments);
}
exports.generateLocalSource = generateLocalSource;
function generateGlobalSource(context) {
const generator = new TypescriptAPIGenerator(context);
generator.fileHeader();
printEnumsAndInputObjects(generator, context.typesUsed);
const output = generator.printer.printAndClear();
return new TypescriptGeneratedFile(output);
}
exports.generateGlobalSource = generateGlobalSource;
class TypescriptAPIGenerator extends language_1.default {
constructor(context) {
super(context.options);
this.getGlobalTypesUsedForOperation = (doc) => {
const typesUsed = doc.variables
.reduce((acc, { type }) => {
const t = this.getUnderlyingType(type);
if (this.isGlobalType(t)) {
return array_1.maybePush(acc, t);
}
return acc;
}, []);
return doc.selectionSet.selections.reduce(this.reduceSelection, typesUsed);
};
this.getGlobalTypesUsedForFragment = (doc) => {
return doc.selectionSet.selections.reduce(this.reduceSelection, []);
};
this.reduceSelection = (acc, selection) => {
if (selection.kind === 'Field' || selection.kind === 'TypeCondition') {
const type = this.getUnderlyingType(selection.type);
if (this.isGlobalType(type)) {
acc = array_1.maybePush(acc, type);
}
}
if (selection.selectionSet) {
return selection.selectionSet.selections.reduce(this.reduceSelection, acc);
}
return acc;
};
this.isGlobalType = (type) => {
return type instanceof graphql_1.GraphQLEnumType || type instanceof graphql_1.GraphQLInputObjectType;
};
this.getUnderlyingType = (type) => {
if (type instanceof graphql_2.GraphQLNonNull) {
return this.getUnderlyingType(graphql_2.getNullableType(type));
}
if (type instanceof graphql_2.GraphQLList) {
return this.getUnderlyingType(type.ofType);
}
return type;
};
this.reduceTypesUsed = (acc, type) => {

@@ -82,0 +168,0 @@ if (type instanceof graphql_2.GraphQLNonNull) {

2

lib/index.d.ts

@@ -1,1 +0,1 @@

export { generateSource } from './codeGeneration';
export { generateSource, generateLocalSource, generateGlobalSource } from './codeGeneration';

@@ -5,2 +5,4 @@ "use strict";

exports.generateSource = codeGeneration_1.generateSource;
exports.generateLocalSource = codeGeneration_1.generateLocalSource;
exports.generateGlobalSource = codeGeneration_1.generateGlobalSource;
//# sourceMappingURL=index.js.map

@@ -1,2 +0,2 @@

import { GraphQLEnumType, GraphQLInputObjectType } from 'graphql';
import { GraphQLEnumType, GraphQLInputObjectType, GraphQLType } from 'graphql';
import { CompilerOptions } from 'apollo-codegen-core/lib/compiler';

@@ -28,2 +28,3 @@ import * as t from '@babel/types';

isNullableType(type: t.TSType): boolean;
import(types: GraphQLType[], source: string): t.ImportDeclaration;
}

@@ -40,6 +40,8 @@ "use strict";

}), []);
inputType.leadingComments = [{
type: 'CommentBlock',
value: printing_1.commentBlockContent(description || "")
}];
if (description) {
inputType.leadingComments = [{
type: 'CommentBlock',
value: printing_1.commentBlockContent(description)
}];
}
return inputType;

@@ -83,4 +85,7 @@ }

}
import(types, source) {
return t.importDeclaration(types.map((type) => t.importSpecifier(t.identifier(type.toString()), t.identifier(type.toString()))), t.stringLiteral(source));
}
}
exports.default = TypescriptGenerator;
//# sourceMappingURL=language.js.map

@@ -18,11 +18,10 @@ "use strict";

}
}, '');
}, '') + '\n';
}
enqueue(printable) {
this.printQueue = [
...this.printQueue,
'\n',
'\n',
printable
];
if (this.printQueue.length > 0) {
this.printQueue.push('\n');
this.printQueue.push('\n');
}
this.printQueue.push(printable);
}

@@ -29,0 +28,0 @@ printAndClear() {

{
"name": "apollo-codegen-typescript",
"description": "TypeScript generator module for Apollo Codegen",
"version": "0.26.0",
"version": "0.27.0",
"main": "./lib/index.js",

@@ -36,3 +36,3 @@ "scripts": {

"@babel/types": "7.0.0-beta.38",
"apollo-codegen-core": "^0.26.0",
"apollo-codegen-core": "^0.27.0",
"change-case": "^3.0.1",

@@ -39,0 +39,0 @@ "inflected": "^2.0.3"

@@ -5,2 +5,3 @@ import { parse } from 'graphql';

const schema = loadSchema(require.resolve('../../../common-test/fixtures/starwars/schema.json'));
const miscSchema = loadSchema(require.resolve('../../../common-test/fixtures/misc/schema.json'));

@@ -13,3 +14,3 @@ import {

import { generateSource } from '../codeGeneration';
import { generateSource, generateLocalSource, generateGlobalSource } from '../codeGeneration';

@@ -21,3 +22,3 @@ function compile(

addTypename: true
}
},
): CompilerContext {

@@ -28,2 +29,13 @@ const document = parse(source);

function compileMisc(
source: string,
options: CompilerOptions = {
mergeInFieldsFromFragmentSpreads: true,
addTypename: true
},
): CompilerContext {
const document = parse(source);
return compileToIR(miscSchema, document, options);
}
describe('Typescript codeGeneration', () => {

@@ -263,5 +275,283 @@ test('multiple files', () => {

test('handles multiline graphql comments', () => {
const miscSchema = loadSchema(require.resolve('../../../common-test/fixtures/misc/schema.json'));
const context = compileMisc(`
query CustomScalar {
commentTest {
multiLine
}
}
`);
const document = parse(`
const output = generateSource(context);
expect(output).toMatchSnapshot();
});
});
describe('Typescript codeGeneration local / global', () => {
test('simple hero query', () => {
const context = compile(`
query HeroName($episode: Episode) {
hero(episode: $episode) {
name
id
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('simple mutation', () => {
const context = compile(`
mutation ReviewMovie($episode: Episode, $review: ReviewInput) {
createReview(episode: $episode, review: $review) {
stars
commentary
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('simple fragment', () => {
const context = compile(`
fragment SimpleFragment on Character{
name
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('fragment with fragment spreads', () => {
const context = compile(`
fragment simpleFragment on Character {
name
}
fragment anotherFragment on Character {
id
...simpleFragment
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('fragment with fragment spreads with inline fragment', () => {
const context = compile(`
fragment simpleFragment on Character {
name
}
fragment anotherFragment on Character {
id
...simpleFragment
... on Human {
appearsIn
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('query with fragment spreads', () => {
const context = compile(`
fragment simpleFragment on Character {
name
}
query HeroFragment($episode: Episode) {
hero(episode: $episode) {
...simpleFragment
id
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('inline fragment', () => {
const context = compile(`
query HeroInlineFragment($episode: Episode) {
hero(episode: $episode) {
... on Character {
name
}
id
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
})
test('inline fragment on type conditions', () => {
const context = compile(`
query HeroName($episode: Episode) {
hero(episode: $episode) {
name
id
... on Human {
homePlanet
friends {
name
}
}
... on Droid {
appearsIn
}
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('inline fragment on type conditions with differing inner fields', () => {
const context = compile(`
query HeroName($episode: Episode) {
hero(episode: $episode) {
name
id
... on Human {
homePlanet
friends {
name
}
}
... on Droid {
appearsIn
friends {
id
}
}
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('fragment spreads with inline fragments', () => {
const context = compile(`
query HeroName($episode: Episode) {
hero(episode: $episode) {
name
id
...humanFragment
...droidFragment
}
}
fragment humanFragment on Human {
homePlanet
friends {
... on Human {
name
}
... on Droid {
id
}
}
}
fragment droidFragment on Droid {
appearsIn
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('handles multiline graphql comments', () => {
const context = compileMisc(`
query CustomScalar {

@@ -274,11 +564,73 @@ commentTest {

const output = generateSource(
compileToIR(miscSchema, document, {
mergeInFieldsFromFragmentSpreads: true,
addTypename: true
})
);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('multiple nested non-null list enum', () => {
const context = compileMisc(`
query nesting {
nesting {
propA
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('multiple nested list enum', () => {
const context = compileMisc(`
query nesting {
nesting {
propB
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
test('duplicates', () => {
const context = compileMisc(`
mutation duplicates($a: EnumCommentTestCase!, $b: EnumCommentTestCase!, $c: Duplicate!) {
duplicates(a: $a, b: $b, c: $c) {
propA
propB
}
}
`);
const output = generateLocalSource(context).map((f) => ({
...f,
content: f.content({
outputPath: '/some/file/ComponentA.tsx',
globalSourcePath: '/__generated__/globalTypes.ts'
}),
}));
expect(output).toMatchSnapshot();
expect(generateGlobalSource(context)).toMatchSnapshot();
});
});

@@ -0,1 +1,2 @@

import * as path from "path";
import * as t from '@babel/types';

@@ -12,2 +13,3 @@ import { stripIndent } from 'common-tags';

Fragment,
Selection,
SelectionSet,

@@ -71,2 +73,21 @@ Field,

function printGlobalImport(
generator: TypescriptAPIGenerator,
typesUsed: GraphQLType[],
outputPath: string,
globalSourcePath: string,
) {
if (typesUsed.length > 0) {
const relative = path.relative(
path.dirname(outputPath),
path.join(
path.dirname(globalSourcePath),
path.basename(globalSourcePath, '.ts')
)
);
generator.printer.enqueue(generator.import(typesUsed, relative));
}
}
// TODO: deprecate this, use generateLocalSource and generateGlobalSource instead.
export function generateSource(

@@ -116,2 +137,71 @@ context: CompilerContext,

interface IGeneratedFileOptions {
outputPath?: string;
globalSourcePath?: string;
}
interface IGeneratedFile {
sourcePath: string;
fileName: string;
content: (options?: IGeneratedFileOptions) => TypescriptGeneratedFile;
}
export function generateLocalSource(
context: CompilerContext,
): IGeneratedFile[] {
const generator = new TypescriptAPIGenerator(context);
const operations = Object.values(context.operations)
.map((operation) => ({
sourcePath: operation.filePath,
fileName: `${operation.operationName}.ts`,
content: (options?: IGeneratedFileOptions) => {
generator.fileHeader();
if (options && options.outputPath && options.globalSourcePath) {
printGlobalImport(
generator,
generator.getGlobalTypesUsedForOperation(operation),
options.outputPath,
options.globalSourcePath
);
}
generator.interfacesForOperation(operation);
const output = generator.printer.printAndClear();
return new TypescriptGeneratedFile(output);
},
}));
const fragments = Object.values(context.fragments)
.map((fragment) => ({
sourcePath: fragment.filePath,
fileName: `${fragment.fragmentName}.ts`,
content: (options?: IGeneratedFileOptions) => {
generator.fileHeader();
if (options && options.outputPath && options.globalSourcePath) {
printGlobalImport(
generator,
generator.getGlobalTypesUsedForFragment(fragment),
options.outputPath,
options.globalSourcePath
);
}
generator.interfacesForFragment(fragment);
const output = generator.printer.printAndClear();
return new TypescriptGeneratedFile(output);
},
}));
return operations.concat(fragments);
}
export function generateGlobalSource(
context: CompilerContext,
): TypescriptGeneratedFile {
const generator = new TypescriptAPIGenerator(context);
generator.fileHeader();
printEnumsAndInputObjects(generator, context.typesUsed);
const output = generator.printer.printAndClear();
return new TypescriptGeneratedFile(output);
}
export class TypescriptAPIGenerator extends TypescriptGenerator {

@@ -252,2 +342,47 @@ context: CompilerContext

public getGlobalTypesUsedForOperation = (doc: Operation) => {
const typesUsed = doc.variables
.reduce((acc: GraphQLType[], { type } : { type : GraphQLType }) => {
const t = this.getUnderlyingType(type);
if (this.isGlobalType(t)) {
return maybePush(acc, t);
}
return acc;
}, []);
return doc.selectionSet.selections.reduce(this.reduceSelection, typesUsed);
}
public getGlobalTypesUsedForFragment = (doc: Fragment) => {
return doc.selectionSet.selections.reduce(this.reduceSelection, []);
}
private reduceSelection = (acc: GraphQLType[], selection: Selection): GraphQLType[] => {
if (selection.kind === 'Field' || selection.kind === 'TypeCondition') {
const type = this.getUnderlyingType(selection.type);
if (this.isGlobalType(type)) {
acc = maybePush(acc, type);
}
}
if (selection.selectionSet) {
return selection.selectionSet.selections.reduce(this.reduceSelection, acc);
}
return acc;
}
private isGlobalType = (type: GraphQLType) => {
return type instanceof GraphQLEnumType || type instanceof GraphQLInputObjectType;
}
private getUnderlyingType = (type: GraphQLType): GraphQLType => {
if (type instanceof GraphQLNonNull) {
return this.getUnderlyingType(getNullableType(type));
}
if (type instanceof GraphQLList) {
return this.getUnderlyingType(type.ofType);
}
return type;
}
public getTypesUsedForOperation(doc: Operation | Fragment, context: CompilerContext) {

@@ -254,0 +389,0 @@ let docTypesUsed: GraphQLType[] = [];

@@ -1,1 +0,1 @@

export { generateSource } from './codeGeneration';
export { generateSource, generateLocalSource, generateGlobalSource } from './codeGeneration';
import {
GraphQLEnumType,
GraphQLInputObjectType
GraphQLInputObjectType,
GraphQLType
} from 'graphql';

@@ -84,6 +85,8 @@

inputType.leadingComments = [{
type: 'CommentBlock',
value: commentBlockContent(description || "")
} as t.CommentBlock]
if (description) {
inputType.leadingComments = [{
type: 'CommentBlock',
value: commentBlockContent(description)
} as t.CommentBlock]
}

@@ -165,2 +168,12 @@ return inputType;

}
public import(types: GraphQLType[], source: string) {
return t.importDeclaration(
types.map((type) => t.importSpecifier(
t.identifier(type.toString()),
t.identifier(type.toString()),
)),
t.stringLiteral(source)
);
}
}

@@ -21,12 +21,11 @@ import * as t from '@babel/types';

''
);
) + '\n';
}
public enqueue(printable: Printable) {
this.printQueue = [
...this.printQueue,
'\n',
'\n',
printable
];
if (this.printQueue.length > 0) {
this.printQueue.push('\n');
this.printQueue.push('\n');
}
this.printQueue.push(printable);
}

@@ -33,0 +32,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc