├── .prettierrc ├── .npmignore ├── README.md ├── packages ├── apollo-env │ ├── src │ │ ├── fetch │ │ │ ├── global.ts │ │ │ ├── url.js │ │ │ ├── index.d.ts │ │ │ ├── index.ts │ │ │ ├── fetch.js │ │ │ ├── tsconfig.json │ │ │ ├── global.d.ts │ │ │ ├── url.d.ts │ │ │ └── fetch.d.ts │ │ ├── polyfills │ │ │ ├── index.ts │ │ │ ├── object.ts │ │ │ └── array.ts │ │ ├── utils │ │ │ ├── index.ts │ │ │ ├── isNodeLike.ts │ │ │ └── createHash.ts │ │ ├── index.ts │ │ └── typescript-utility-types.ts │ ├── tsconfig.json │ ├── package.json │ └── clone-types.js ├── apollo-graphql │ ├── README.md │ ├── CHANGELOG.md │ ├── .npmignore │ ├── src │ │ ├── index.ts │ │ └── __tests__ │ │ │ ├── tsconfig.json │ │ │ ├── __snapshots__ │ │ │ └── operationId.test.ts.snap │ │ │ └── transforms.test.ts │ ├── tsconfig.test.json │ ├── tsconfig.json │ └── package.json ├── vscode-apollo │ ├── .vscodeignore │ ├── .gitignore │ ├── images │ │ ├── engine-stats.png │ │ ├── query-with-vars.gif │ │ ├── marketplace │ │ │ ├── stats.gif │ │ │ ├── type-info.png │ │ │ ├── autocomplete.gif │ │ │ ├── jump-to-def.gif │ │ │ ├── perf-annotation.png │ │ │ └── warnings-and-errors.gif │ │ ├── icon-apollo-blue-400x400.png │ │ └── variable-argument-completion.gif │ ├── tsconfig.test.json │ ├── graphql.configuration.json │ ├── CHANGELOG.md │ ├── create-server-symlink.js │ ├── tsconfig.json │ ├── src │ │ ├── __tests__ │ │ │ └── statusBar.test.ts │ │ ├── testRunner │ │ │ ├── jest-vscode-framework-setup.ts │ │ │ ├── jest-config.ts │ │ │ ├── jest-vscode-environment.ts │ │ │ ├── vscode-test-script.ts │ │ │ ├── jest.d.ts │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── languageServerClient.ts │ │ ├── statusBar.ts │ │ └── utils.ts │ └── syntaxes │ │ ├── graphql.js.json │ │ └── graphql.py.json ├── apollo │ ├── @types │ │ ├── env-ci.d.ts │ │ ├── gaze.d.ts │ │ ├── memfs.d.ts │ │ ├── fs-monkey.ts │ │ ├── decode-html.d.ts │ │ ├── git-parse.d.ts │ │ ├── git-rev-sync.d.ts │ │ └── heroku-cli-util.d.ts │ ├── .prettierignore │ ├── bin │ │ ├── run.cmd │ │ └── run │ ├── src │ │ ├── utils │ │ │ ├── index.ts │ │ │ ├── validateHistoricParams.ts │ │ │ └── __tests__ │ │ │ │ └── validateHistoricParams.test.ts │ │ ├── commands │ │ │ ├── client │ │ │ │ ├── __tests__ │ │ │ │ │ └── fixtures │ │ │ │ │ │ ├── otherQuery.graphql │ │ │ │ │ │ ├── simpleQuery.graphql │ │ │ │ │ │ ├── clientSideOnlyQuery.graphql │ │ │ │ │ │ ├── clientSideOnlySchema.graphql │ │ │ │ │ │ ├── clientSideSchema.graphql │ │ │ │ │ │ └── clientSideSchemaQuery.graphql │ │ │ │ └── extract.ts │ │ │ └── service │ │ │ │ ├── __tests__ │ │ │ │ ├── fixtures │ │ │ │ │ ├── introspection-result.json │ │ │ │ │ ├── next.graphql │ │ │ │ │ └── schema.graphql │ │ │ │ └── download.test.ts │ │ │ │ ├── download.ts │ │ │ │ ├── info.ts │ │ │ │ └── push.ts │ │ ├── index.ts │ │ ├── __tests__ │ │ │ └── git.test.ts │ │ ├── OclifLoadingHandler.ts │ │ └── git.ts │ ├── .gitignore │ ├── tsconfig.test.json │ ├── todo.md │ ├── CHANGELOG.md │ ├── tsconfig.json │ ├── __mocks__ │ │ └── apollo-cli-test.ts │ └── package.json ├── apollo-codegen-core │ ├── src │ │ ├── index.ts │ │ ├── localfs.ts │ │ ├── __tests__ │ │ │ ├── __fixtures__ │ │ │ │ ├── invalid.js │ │ │ │ ├── normal.js │ │ │ │ ├── comments.js │ │ │ │ └── commentedOut.js │ │ │ ├── valueFromValueNode.ts │ │ │ └── loading.ts │ │ ├── utilities │ │ │ ├── array.ts │ │ │ ├── printing.ts │ │ │ ├── __tests__ │ │ │ │ └── graphql.test.ts │ │ │ └── CodeGenerator.ts │ │ ├── compiler │ │ │ └── visitors │ │ │ │ ├── __tests__ │ │ │ │ └── test-utils │ │ │ │ │ └── helpers.ts │ │ │ │ ├── inlineRedundantTypeConditions.ts │ │ │ │ ├── generateOperationId.ts │ │ │ │ └── collectFragmentsReferenced.ts │ │ └── serializeToJSON.ts │ ├── tsconfig.test.json │ ├── test-utils │ │ ├── tsconfig.json │ │ └── matchers.ts │ ├── tsconfig.json │ └── package.json ├── apollo-codegen-flow │ ├── src │ │ ├── index.ts │ │ ├── helpers.ts │ │ └── printer.ts │ ├── tsconfig.test.json │ ├── tsconfig.json │ └── package.json ├── apollo-codegen-scala │ ├── src │ │ ├── index.ts │ │ ├── values.ts │ │ ├── __tests__ │ │ │ └── language.ts │ │ ├── types.ts │ │ └── naming.ts │ ├── tsconfig.test.json │ ├── tsconfig.json │ └── package.json ├── apollo-codegen-swift │ ├── src │ │ ├── index.ts │ │ └── __tests__ │ │ │ └── __snapshots__ │ │ │ └── language.ts.snap │ ├── tsconfig.test.json │ ├── tsconfig.json │ └── package.json ├── apollo-tools │ ├── src │ │ ├── __tests__ │ │ │ ├── tsconfig.json │ │ │ └── snapshotSerializers │ │ │ │ ├── graphQLTypeSerializer.ts │ │ │ │ └── astSerializer.ts │ │ ├── schema │ │ │ ├── index.ts │ │ │ ├── resolverMap.ts │ │ │ └── resolveObject.ts │ │ ├── utilities │ │ │ ├── index.ts │ │ │ ├── invariant.ts │ │ │ ├── predicates.ts │ │ │ └── graphql.ts │ │ └── index.ts │ ├── tsconfig.test.json │ ├── tsconfig.json │ └── package.json ├── apollo-language-server │ ├── src │ │ ├── config │ │ │ ├── index.ts │ │ │ ├── utils.ts │ │ │ └── __tests__ │ │ │ │ └── utils.ts │ │ ├── engine │ │ │ ├── operations │ │ │ │ ├── registerOperations.ts │ │ │ │ ├── schemaTagInfo.ts │ │ │ │ ├── schemaTagsAndFieldStats.ts │ │ │ │ ├── uploadSchema.ts │ │ │ │ ├── validateOperations.ts │ │ │ │ └── checkSchema.ts │ │ │ └── GraphQLDataSource.ts │ │ ├── schema │ │ │ └── providers │ │ │ │ ├── base.ts │ │ │ │ ├── index.ts │ │ │ │ ├── file.ts │ │ │ │ └── introspection.ts │ │ ├── index.ts │ │ ├── typings │ │ │ ├── graphql-language-service.d.ts │ │ │ └── graphql.d.ts │ │ ├── format.ts │ │ ├── project │ │ │ └── service.ts │ │ ├── errors │ │ │ ├── logger.ts │ │ │ └── validation.ts │ │ ├── loadingHandler.ts │ │ ├── fileSet.ts │ │ ├── __tests__ │ │ │ └── diagnostics.ts │ │ ├── diagnostics.ts │ │ └── utilities │ │ │ └── source.ts │ ├── tsconfig.test.json │ ├── CHANGELOG.md │ ├── tsconfig.json │ └── package.json └── apollo-codegen-typescript │ ├── src │ ├── index.ts │ ├── helpers.ts │ └── printer.ts │ ├── tsconfig.test.json │ ├── tsconfig.json │ └── package.json ├── .prettierignore ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── question-discussion.md │ ├── feature-request.md │ └── bug.md └── PULL_REQUEST_TEMPLATE.md ├── __fixtures__ ├── starwars │ ├── AnonymousQuery.graphql │ ├── HeroName.graphql │ ├── TypenameAlias.graphql │ ├── UnknownDirective.graphql │ ├── ExplicitTypename.graphql │ ├── HeroAppearsIn.graphql │ ├── TwoHeroes.graphql │ ├── HeroAndFriendsNames.graphql │ ├── HeroAndFriends.graphql │ └── gqlQueries.js └── misc │ └── schema.graphql ├── lerna.json ├── tsconfig.test.base.json ├── apollo.config.js ├── .vscode ├── tasks.json ├── settings.json └── launch.json ├── types ├── @babel │ └── types │ │ └── index.d.ts └── pretty-format │ └── index.d.ts ├── renovate.json ├── tsconfig.json ├── .gitignore ├── tsconfig.base.json ├── LICENSE └── azure-pipelines.yml /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | packages/apollo/README.md -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/global.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.snap 2 | graphqlTypes.ts 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jbaxleyiii @trevor-scheer 2 | -------------------------------------------------------------------------------- /packages/apollo-graphql/README.md: -------------------------------------------------------------------------------- 1 | # `apollo-graphql` 2 | -------------------------------------------------------------------------------- /packages/vscode-apollo/.vscodeignore: -------------------------------------------------------------------------------- 1 | lib/testRunner/** 2 | -------------------------------------------------------------------------------- /packages/apollo/@types/env-ci.d.ts: -------------------------------------------------------------------------------- 1 | declare module "env-ci"; 2 | -------------------------------------------------------------------------------- /packages/apollo/@types/gaze.d.ts: -------------------------------------------------------------------------------- 1 | declare module "gaze"; 2 | -------------------------------------------------------------------------------- /packages/apollo/@types/memfs.d.ts: -------------------------------------------------------------------------------- 1 | declare module "memfs"; 2 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/index.ts: -------------------------------------------------------------------------------- 1 | import "./polyfills"; 2 | -------------------------------------------------------------------------------- /packages/apollo/@types/fs-monkey.ts: -------------------------------------------------------------------------------- 1 | declare module "fs-monkey"; 2 | -------------------------------------------------------------------------------- /packages/vscode-apollo/.gitignore: -------------------------------------------------------------------------------- 1 | yarn.lock 2 | .vscode-test 3 | -------------------------------------------------------------------------------- /packages/apollo/.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | package.json 3 | -------------------------------------------------------------------------------- /packages/apollo/@types/decode-html.d.ts: -------------------------------------------------------------------------------- 1 | declare module "decode-html"; 2 | -------------------------------------------------------------------------------- /packages/apollo/@types/git-parse.d.ts: -------------------------------------------------------------------------------- 1 | declare module "git-parse"; 2 | -------------------------------------------------------------------------------- /packages/apollo/bin/run.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\run" %* 4 | -------------------------------------------------------------------------------- /packages/apollo-graphql/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ### vNEXT 4 | 5 | -------------------------------------------------------------------------------- /packages/apollo/@types/git-rev-sync.d.ts: -------------------------------------------------------------------------------- 1 | declare module "git-rev-sync"; 2 | -------------------------------------------------------------------------------- /packages/apollo/@types/heroku-cli-util.d.ts: -------------------------------------------------------------------------------- 1 | declare module "heroku-cli-util"; 2 | -------------------------------------------------------------------------------- /packages/apollo/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./validateHistoricParams"; 2 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/url.js: -------------------------------------------------------------------------------- 1 | export { URL, URLSearchParams } from "url"; 2 | -------------------------------------------------------------------------------- /packages/apollo-env/src/polyfills/index.ts: -------------------------------------------------------------------------------- 1 | import "./array"; 2 | import "./object"; 3 | -------------------------------------------------------------------------------- /__fixtures__/starwars/AnonymousQuery.graphql: -------------------------------------------------------------------------------- 1 | { 2 | hero { 3 | name 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo-codegen-flow/src/index.ts: -------------------------------------------------------------------------------- 1 | export { generateSource } from "./codeGeneration"; 2 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/src/index.ts: -------------------------------------------------------------------------------- 1 | export { generateSource } from "./codeGeneration"; 2 | -------------------------------------------------------------------------------- /packages/apollo-codegen-swift/src/index.ts: -------------------------------------------------------------------------------- 1 | export { generateSource } from "./codeGeneration"; 2 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./fetch"; 2 | export * from "./url"; 3 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./fetch"; 2 | export * from "./url"; 3 | -------------------------------------------------------------------------------- /__fixtures__/starwars/HeroName.graphql: -------------------------------------------------------------------------------- 1 | query HeroName { 2 | hero { 3 | name 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "independent" 6 | } 7 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/__tests__/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test" 3 | } 4 | -------------------------------------------------------------------------------- /packages/apollo-env/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./createHash"; 2 | export * from "./isNodeLike"; 3 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/schema/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./resolverMap"; 2 | export * from "./resolveObject"; 3 | -------------------------------------------------------------------------------- /__fixtures__/starwars/TypenameAlias.graphql: -------------------------------------------------------------------------------- 1 | query HeroName { 2 | hero { 3 | __typename: name 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/fetch.js: -------------------------------------------------------------------------------- 1 | export { default as fetch, Request, Response, Headers } from "node-fetch"; 2 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/client/__tests__/fixtures/otherQuery.graphql: -------------------------------------------------------------------------------- 1 | query OtherQuery { 2 | hello 3 | } 4 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/client/__tests__/fixtures/simpleQuery.graphql: -------------------------------------------------------------------------------- 1 | query SimpleQuery { 2 | hello 3 | } 4 | -------------------------------------------------------------------------------- /__fixtures__/starwars/UnknownDirective.graphql: -------------------------------------------------------------------------------- 1 | query HeroName { 2 | hero @connection { 3 | name 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo-graphql/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !src/**/* 3 | !lib/**/* 4 | lib/**/*.test.* 5 | !package.json 6 | !README.md 7 | -------------------------------------------------------------------------------- /__fixtures__/starwars/ExplicitTypename.graphql: -------------------------------------------------------------------------------- 1 | query HeroName { 2 | hero { 3 | __typename 4 | name 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /__fixtures__/starwars/HeroAppearsIn.graphql: -------------------------------------------------------------------------------- 1 | query HeroAppearsIn { 2 | hero { 3 | name 4 | appearsIn 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/apollo/bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('@oclif/command').run() 4 | .catch(require('@oclif/errors/handle')) 5 | -------------------------------------------------------------------------------- /packages/apollo/.gitignore: -------------------------------------------------------------------------------- 1 | *-debug.log 2 | *-error.log 3 | /.nyc_output 4 | /dist 5 | /lib 6 | /tmp 7 | /yarn.lock 8 | node_modules 9 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/utilities/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./invariant"; 2 | export * from "./predicates"; 3 | export * from "./graphql"; 4 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./utils"; 2 | export * from "./config"; 3 | export * from "./loadConfig"; 4 | -------------------------------------------------------------------------------- /packages/apollo/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/vscode-apollo/images/engine-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/engine-stats.png -------------------------------------------------------------------------------- /packages/vscode-apollo/images/query-with-vars.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/query-with-vars.gif -------------------------------------------------------------------------------- /packages/vscode-apollo/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/apollo-codegen-flow/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/vscode-apollo/images/marketplace/stats.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/marketplace/stats.gif -------------------------------------------------------------------------------- /__fixtures__/starwars/TwoHeroes.graphql: -------------------------------------------------------------------------------- 1 | query TwoHeroes { 2 | r2: hero { 3 | name 4 | } 5 | luke: hero(episode: EMPIRE) { 6 | name 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/apollo-codegen-swift/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/apollo-language-server/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/apollo-codegen-typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | generateSource, 3 | generateLocalSource, 4 | generateGlobalSource 5 | } from "./codeGeneration"; 6 | -------------------------------------------------------------------------------- /packages/apollo-codegen-typescript/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "include": ["**/__tests__/*", "**/__mocks__/*"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/vscode-apollo/images/marketplace/type-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/marketplace/type-info.png -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/localfs.ts: -------------------------------------------------------------------------------- 1 | export const fs = require("fs"); 2 | 3 | export function withGlobalFS(thunk: () => T): T { 4 | return thunk(); 5 | } 6 | -------------------------------------------------------------------------------- /packages/vscode-apollo/graphql.configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "#" 4 | }, 5 | "brackets": [["{", "}"], ["[", "]"], ["(", ")"]] 6 | } 7 | -------------------------------------------------------------------------------- /packages/vscode-apollo/images/icon-apollo-blue-400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/icon-apollo-blue-400x400.png -------------------------------------------------------------------------------- /packages/vscode-apollo/images/marketplace/autocomplete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/marketplace/autocomplete.gif -------------------------------------------------------------------------------- /packages/vscode-apollo/images/marketplace/jump-to-def.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/marketplace/jump-to-def.gif -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/__tests__/__fixtures__/invalid.js: -------------------------------------------------------------------------------- 1 | const query = gql` 2 | query UserProfileView { 3 | me { 4 | id 5 | uuid 6 | role 7 | } 8 | `; 9 | -------------------------------------------------------------------------------- /packages/apollo-env/src/index.ts: -------------------------------------------------------------------------------- 1 | import "./polyfills"; 2 | 3 | export * from "./typescript-utility-types"; 4 | export * from "../lib/fetch"; 5 | export * from "./utils"; 6 | -------------------------------------------------------------------------------- /packages/apollo-graphql/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | defaultEngineReportingSignature, 3 | defaultOperationRegistrySignature, 4 | operationHash 5 | } from "./operationId"; 6 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/index.ts: -------------------------------------------------------------------------------- 1 | import "apollo-env"; 2 | 3 | export * from "./utilities"; 4 | 5 | export * from "./schema"; 6 | export * from "./buildServiceDefinition"; 7 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/service/__tests__/fixtures/introspection-result.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "__schema": { 4 | "fakeSchema": true 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/apollo/todo.md: -------------------------------------------------------------------------------- 1 | 2 | ## CLI 3 | - write tests for check method 4 | - clean up error handling 5 | 6 | ## Shared 7 | - export diff tooling 8 | - export idl generation 9 | -------------------------------------------------------------------------------- /packages/vscode-apollo/images/marketplace/perf-annotation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/marketplace/perf-annotation.png -------------------------------------------------------------------------------- /tsconfig.test.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "types": ["node", "apollo-env", "jest"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/vscode-apollo/images/variable-argument-completion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/variable-argument-completion.gif -------------------------------------------------------------------------------- /packages/apollo-tools/src/utilities/invariant.ts: -------------------------------------------------------------------------------- 1 | export function invariant(condition: any, message: string) { 2 | if (!condition) { 3 | throw new Error(message); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | To see release notes and changes for `apollo`, See the [apollo-tooling changelog](https://github.com/apollographql/apollo-tooling/blob/master/CHANGELOG.md) 2 | -------------------------------------------------------------------------------- /packages/vscode-apollo/images/marketplace/warnings-and-errors.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js/apollo-tooling/master/packages/vscode-apollo/images/marketplace/warnings-and-errors.gif -------------------------------------------------------------------------------- /packages/apollo/src/commands/client/__tests__/fixtures/clientSideOnlyQuery.graphql: -------------------------------------------------------------------------------- 1 | query SimpleQuery { 2 | localState @client 3 | complexLocalState @client { 4 | someData 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /__fixtures__/starwars/HeroAndFriendsNames.graphql: -------------------------------------------------------------------------------- 1 | query HeroAndFriendsNames($episode: Episode) { 2 | hero(episode: $episode) { 3 | name 4 | friends { 5 | name 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/apollo-env/src/typescript-utility-types.ts: -------------------------------------------------------------------------------- 1 | export type WithRequired = T & Required>; 2 | export type DeepPartial = { [P in keyof T]?: DeepPartial }; 3 | -------------------------------------------------------------------------------- /packages/apollo-graphql/src/__tests__/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.test.base", 3 | "include": ["**/*"], 4 | "references": [ 5 | { "path": "../../" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /packages/vscode-apollo/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | To see release notes and changes for `vscode-apollo`, See the [apollo-tooling changelog](https://github.com/apollographql/apollo-tooling/blob/master/CHANGELOG.md) 2 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/__tests__/__fixtures__/normal.js: -------------------------------------------------------------------------------- 1 | const query = gql` 2 | query UserProfileView { 3 | me { 4 | id 5 | uuid 6 | role 7 | } 8 | } 9 | `; 10 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/utilities/predicates.ts: -------------------------------------------------------------------------------- 1 | export function isNotNullOrUndefined( 2 | value: T | null | undefined 3 | ): value is T { 4 | return value !== null && typeof value !== "undefined"; 5 | } 6 | -------------------------------------------------------------------------------- /packages/apollo-graphql/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "compilerOptions": { 4 | "esModuleInterop": true, 5 | }, 6 | "include": ["**/__tests__/*", "**/__mocks__/*"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/apollo-language-server/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | To see release notes and changes for `apollo-language-server`, See the [apollo-tooling changelog](https://github.com/apollographql/apollo-tooling/blob/master/CHANGELOG.md) 2 | -------------------------------------------------------------------------------- /packages/apollo/src/index.ts: -------------------------------------------------------------------------------- 1 | // run the CLI 2 | export { run } from "@oclif/command"; 3 | 4 | // export Command base for plugins 5 | export * from "./Command"; 6 | 7 | // export git utils 8 | export * from "./git"; 9 | -------------------------------------------------------------------------------- /packages/apollo-env/src/utils/isNodeLike.ts: -------------------------------------------------------------------------------- 1 | export const isNodeLike = 2 | typeof process === "object" && 3 | process && 4 | process.release && 5 | process.versions && 6 | typeof process.versions.node === "string"; 7 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/client/__tests__/fixtures/clientSideOnlySchema.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | localState: String! 3 | complexLocalState: LocalType! 4 | } 5 | 6 | type LocalType { 7 | someData: String! 8 | } 9 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/service/__tests__/fixtures/next.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | me: User 3 | } 4 | 5 | type User { 6 | id: ID! 7 | firstName: String 8 | } 9 | 10 | type RemovedField { 11 | id: ID! 12 | } 13 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/test-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "./**/*", 5 | "../src/**/*" 6 | ], 7 | "exclude": [ 8 | "./fixtures/**/*" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-env/src/polyfills/object.ts: -------------------------------------------------------------------------------- 1 | import "core-js/features/object/from-entries"; 2 | 3 | declare global { 4 | interface ObjectConstructor { 5 | fromEntries(map: [K, V][]): Record; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/vscode-apollo/create-server-symlink.js: -------------------------------------------------------------------------------- 1 | const symlinkDir = require("symlink-dir"); 2 | 3 | symlinkDir( 4 | "../apollo-language-server", 5 | "./node_modules/apollo-language-server" 6 | ).then(result => { 7 | console.log(result); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/apollo-tools/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.base", 3 | "compilerOptions": { 4 | "composite": true 5 | }, 6 | "include": ["**/__tests__/*", "**/__mocks__/*"], 7 | "references": [{ "path": "./tsconfig.json" }] 8 | } 9 | -------------------------------------------------------------------------------- /packages/apollo-env/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib", 6 | "types": ["node"] 7 | }, 8 | "include": ["src/**/*"], 9 | "exclude": ["src/fetch/**/*"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-tools/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "include": ["./src/**/*"], 8 | "exclude": ["**/__tests__/*", "**/__mocks__/*"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/__tests__/__fixtures__/comments.js: -------------------------------------------------------------------------------- 1 | const query = gql` 2 | query UserProfileView { 3 | me { 4 | id 5 | # TODO: https://www.fast.com/sdf/sdf 6 | uuid 7 | # Some other comment 8 | role 9 | } 10 | } 11 | `; 12 | -------------------------------------------------------------------------------- /__fixtures__/starwars/HeroAndFriends.graphql: -------------------------------------------------------------------------------- 1 | query HeroAndFriends($episode: Episode) { 2 | hero(episode: $episode) { 3 | ...heroDetails 4 | } 5 | } 6 | 7 | fragment heroDetails on Character { 8 | name 9 | ... on Droid { 10 | primaryFunction 11 | } 12 | ... on Human { 13 | height 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/apollo-codegen-flow/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "include": ["./src/**/*"], 8 | "exclude": ["**/__tests__/*", "**/__mocks__/*"], 9 | "references": [{ "path": "../apollo-codegen-core" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "include": ["./src/**/*"], 8 | "exclude": ["**/__tests__/*", "**/__mocks__/*"], 9 | "references": [{ "path": "../apollo-codegen-core" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-codegen-swift/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "include": ["./src/**/*"], 8 | "exclude": ["**/__tests__/*", "**/__mocks__/*"], 9 | "references": [{ "path": "../apollo-codegen-core" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "include": ["./src/**/*"], 8 | "exclude": ["**/__tests__/*", "**/__mocks__/*"], 9 | "references": [{ "path": "../apollo-language-server" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-codegen-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "include": ["./src/**/*"], 8 | "exclude": ["**/__tests__/*", "**/__mocks__/*"], 9 | "references": [{ "path": "../apollo-codegen-core" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-language-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "include": ["./src/**/*"], 8 | "exclude": ["**/__tests__/*", "**/__mocks__/*"], 9 | "references": [{ "path": "../apollo-tools" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/client/__tests__/fixtures/clientSideSchema.graphql: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | localState: String! 3 | complexLocalState: LocalType! 4 | localServerModel: ServerField! 5 | } 6 | 7 | type LocalType { 8 | someData: String! 9 | } 10 | 11 | extend type ServerField { 12 | addedLocalData: String! 13 | } 14 | -------------------------------------------------------------------------------- /packages/apollo-graphql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib", 6 | "esModuleInterop": true, 7 | "target": "es2016" 8 | }, 9 | "include": ["src/**/*"], 10 | "exclude": ["**/__tests__", "**/__mocks__"], 11 | "references": [] 12 | } 13 | -------------------------------------------------------------------------------- /packages/vscode-apollo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib" 6 | }, 7 | "exclude": ["**/__tests__/*", "**/__mocks__/*", "./lib"], 8 | "references": [ 9 | { 10 | "path": "../apollo-language-server" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /apollo.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | client: { 3 | name: "Apollo CLI", 4 | service: "engine@master", 5 | includes: ["./packages/apollo-language-server/**/*.ts"] 6 | }, 7 | engine: { 8 | frontend: "https://engine-staging.apollographql.com", 9 | endpoint: "https://engine-staging-graphql.apollographql.com/api/graphql" 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/__tests__/__fixtures__/commentedOut.js: -------------------------------------------------------------------------------- 1 | // const query = gql` 2 | // query UserProfileView { 3 | // me { 4 | // id 5 | // # TODO https://app.asana.com/0/52068106376728/221203365474362 6 | // uuid 7 | // # TODO https://app.asana.com/0/52068106376728/221203365474362 8 | // role 9 | // } 10 | // } 11 | // ` 12 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base", 3 | "compilerOptions": { 4 | "composite": false, 5 | "rootDir": ".", 6 | "outDir": "../../lib/fetch", 7 | "allowJs": true, 8 | "declaration": false, 9 | "declarationMap": false, 10 | "types": ["node"] 11 | }, 12 | "include": ["**/*"] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "watch", 7 | "problemMatcher": "$tsc-watch", 8 | "isBackground": true, 9 | "presentation": { 10 | "reveal": "never" 11 | }, 12 | "group": { 13 | "kind": "build", 14 | "isDefault": true 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question-discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🤗 Question / Discussion 3 | about: Questions / discussions are best posted in Apollo's Spectrum community. 4 | --- 5 | 6 | Need help or want to talk all things Apollo Tooling? Issues here are reserved for bugs or feature requests, but you ask for help in our Spectrum community: 7 | 8 | - Apollo's Spectrum community: https://spectrum.chat/apollo 9 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/schema/resolverMap.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLFieldResolver } from "graphql"; 2 | 3 | export interface GraphQLResolverMap { 4 | [typeName: string]: { 5 | [fieldName: string]: 6 | | GraphQLFieldResolver 7 | | { 8 | requires?: string; 9 | resolve: GraphQLFieldResolver; 10 | }; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /packages/apollo-env/src/polyfills/array.ts: -------------------------------------------------------------------------------- 1 | import "core-js/features/array/flat"; 2 | import "core-js/features/array/flat-map"; 3 | 4 | declare global { 5 | interface Array { 6 | flat(this: ReadonlyArray[], depth?: 1): U[]; 7 | flatMap( 8 | callbackfn: (value: T, index: number, array: T[]) => ReadonlyArray | U, 9 | thisArg?: this 10 | ): U[]; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/utilities/array.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | interface Array { 3 | flatMap( 4 | callbackfn: (value: T, index: number, array: T[]) => U[] | undefined, 5 | thisArg?: any 6 | ): U[]; 7 | } 8 | } 9 | 10 | export function maybePush(list: T[], item: T) { 11 | if (!list.includes(item)) { 12 | list.push(item); 13 | } 14 | return list; 15 | } 16 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/client/__tests__/fixtures/clientSideSchemaQuery.graphql: -------------------------------------------------------------------------------- 1 | query SimpleQuery { 2 | hello 3 | localState @client 4 | complexLocalState @client { 5 | someData 6 | } 7 | 8 | serverSideField { 9 | serverData 10 | addedLocalData @client 11 | } 12 | 13 | localServerModel @client { 14 | serverData # this is actually stored in the client though 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/service/__tests__/fixtures/schema.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | hello: String! 3 | serverSideField: ServerField! 4 | someEnum: SomeEnum! 5 | } 6 | 7 | type ServerField { 8 | serverData: String! 9 | } 10 | 11 | type RemovedField { 12 | id: ID! 13 | name: RemovedType 14 | } 15 | 16 | type RemovedType { 17 | fieldName: String 18 | } 19 | 20 | enum SomeEnum { 21 | foo 22 | bar 23 | } 24 | -------------------------------------------------------------------------------- /packages/apollo-env/src/utils/createHash.ts: -------------------------------------------------------------------------------- 1 | import { isNodeLike } from "./isNodeLike"; 2 | 3 | export function createHash(kind: string): import("crypto").Hash { 4 | if (isNodeLike) { 5 | // Use module.require instead of just require to avoid bundling whatever 6 | // crypto polyfills a non-Node bundler might fall back to. 7 | return module.require("crypto").createHash(kind); 8 | } 9 | return require("sha.js")(kind); 10 | } 11 | -------------------------------------------------------------------------------- /packages/apollo-codegen-swift/src/__tests__/__snapshots__/language.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Swift code generation: Basic language constructs should handle multi-line descriptions 1`] = ` 4 | "/// A hero 5 | public struct Hero { 6 | /// A multiline comment 7 | /// on the hero's name. 8 | public var name: String 9 | /// A multiline comment 10 | /// on the hero's age. 11 | public var age: String 12 | }" 13 | `; 14 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/engine/operations/registerOperations.ts: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const REGISTER_OPERATIONS = gql` 4 | mutation RegisterOperations( 5 | $id: ID! 6 | $clientIdentity: RegisteredClientIdentityInput! 7 | $operations: [RegisteredOperationInput!]! 8 | ) { 9 | service(id: $id) { 10 | registerOperations( 11 | clientIdentity: $clientIdentity 12 | operations: $operations 13 | ) 14 | } 15 | } 16 | `; 17 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/__tests__/statusBar.test.ts: -------------------------------------------------------------------------------- 1 | import StatusBar from "../statusBar"; 2 | 3 | describe("statusBar", () => { 4 | it("only shows loaded state when it's supposed to", () => { 5 | const statusBar = new StatusBar({ hasActiveTextEditor: true }); 6 | 7 | expect(statusBar.statusBarItem.text).toEqual(StatusBar.loadingStateText); 8 | statusBar.showLoadedState({ hasActiveTextEditor: true }); 9 | expect(statusBar.statusBarItem.text).toEqual(StatusBar.loadedStateText); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /types/@babel/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "babel-types"; 2 | 3 | declare module "babel-types" { 4 | export function stringLiteralTypeAnnotation( 5 | value: string 6 | ): StringLiteralTypeAnnotation; 7 | 8 | export interface StringLiteralTypeAnnotation { 9 | value: string; 10 | } 11 | 12 | export interface ObjectTypeAnnotation { 13 | exact: boolean; 14 | } 15 | 16 | export interface ObjectTypeProperty { 17 | variance?: { kind: "plus" | "minus" }; 18 | optional: boolean; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/engine/operations/schemaTagInfo.ts: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const SCHEMA_TAG_INFO_QUERY = gql` 4 | query SchemaTagInfo($service: ID!, $tag: String = "current") { 5 | service(id: $service) { 6 | schema(tag: $tag) { 7 | hash 8 | gitContext { 9 | committer 10 | commit 11 | } 12 | introspection { 13 | fieldCount 14 | typeCount 15 | } 16 | createdAt 17 | } 18 | } 19 | } 20 | `; 21 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/testRunner/jest-vscode-framework-setup.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Takes the Visual Studio Code extension API which was exposed on the sandbox's 3 | * global object and uses it to create a virtual mock. This replaces vscode 4 | * module imports with the vscode extension instance from the test runner's 5 | * environment. 6 | * 7 | * @see https://github.com/Unibeautify/vscode/blob/61897cd6cd0567db2c8688c3c0b835f9b5c5b446/test/jest-vscode-framework-setup.ts 8 | */ 9 | 10 | jest.mock("vscode", () => global.vscode, { virtual: true }); 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "editor.tabSize": 2, 4 | "editor.insertSpaces": true, 5 | "editor.rulers": [110], 6 | "editor.wordWrapColumn": 110, 7 | "files.trimTrailingWhitespace": true, 8 | "files.insertFinalNewline": true, 9 | "files.exclude": { 10 | "**/.git": true, 11 | "**/.DS_Store": true, 12 | "node_modules": false, 13 | "lib": true 14 | }, 15 | "typescript.tsdk": "node_modules/typescript/lib", 16 | "debug.node.autoAttach": "on" 17 | } 18 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/__tests__/snapshotSerializers/graphQLTypeSerializer.ts: -------------------------------------------------------------------------------- 1 | import { isNamedType, GraphQLNamedType, printType } from "graphql"; 2 | import { Plugin, Config, Refs, Printer } from "pretty-format"; 3 | 4 | export = { 5 | test(value: any) { 6 | return value && isNamedType(value); 7 | }, 8 | 9 | serialize( 10 | value: GraphQLNamedType, 11 | config: Config, 12 | indentation: string, 13 | depth: number, 14 | refs: Refs, 15 | printer: Printer 16 | ): string { 17 | return printType(value); 18 | } 19 | } as Plugin; 20 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/schema/providers/base.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLSchema } from "graphql"; 2 | import { NotificationHandler } from "vscode-languageserver"; 3 | 4 | export interface SchemaResolveConfig { 5 | tag?: string; 6 | force?: boolean; 7 | } 8 | export type SchemaChangeUnsubscribeHandler = () => void; 9 | export interface GraphQLSchemaProvider { 10 | resolveSchema(config?: SchemaResolveConfig): Promise; 11 | onSchemaChange( 12 | handler: NotificationHandler 13 | ): SchemaChangeUnsubscribeHandler; 14 | } 15 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/engine/operations/schemaTagsAndFieldStats.ts: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const SCHEMA_TAGS_AND_FIELD_STATS = gql` 4 | query SchemaTagsAndFieldStats($id: ID!) { 5 | service(id: $id) { 6 | schemaTags { 7 | tag 8 | } 9 | stats(from: "-86400", to: "-0") { 10 | fieldStats { 11 | groupBy { 12 | field 13 | } 14 | metrics { 15 | fieldHistogram { 16 | durationMs(percentile: 0.95) 17 | } 18 | } 19 | } 20 | } 21 | } 22 | } 23 | `; 24 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/engine/operations/uploadSchema.ts: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const UPLOAD_SCHEMA = gql` 4 | mutation UploadSchema( 5 | $id: ID! 6 | $schema: IntrospectionSchemaInput! 7 | $tag: String! 8 | $gitContext: GitContextInput 9 | ) { 10 | service(id: $id) { 11 | uploadSchema(schema: $schema, tag: $tag, gitContext: $gitContext) { 12 | code 13 | message 14 | success 15 | tag { 16 | tag 17 | schema { 18 | hash 19 | } 20 | } 21 | } 22 | } 23 | } 24 | `; 25 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/schema/resolveObject.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLResolveInfo, FieldNode } from "graphql"; 2 | 3 | export type GraphQLObjectResolver = ( 4 | source: TSource, 5 | fields: Record>, 6 | context: TContext, 7 | info: GraphQLResolveInfo 8 | ) => any; 9 | 10 | declare module "graphql/type/definition" { 11 | interface GraphQLObjectType { 12 | resolveObject?: GraphQLObjectResolver; 13 | } 14 | 15 | interface GraphQLObjectTypeConfig { 16 | resolveObject?: GraphQLObjectResolver; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/compiler/visitors/__tests__/test-utils/helpers.ts: -------------------------------------------------------------------------------- 1 | import { parse, GraphQLSchema } from "graphql"; 2 | import { compileToIR, CompilerOptions } from "../../.."; 3 | import { loadSchema } from "../../../../loading"; 4 | 5 | export const starWarsSchema = loadSchema( 6 | require.resolve("../../../../../../../__fixtures__/starwars/schema.json") 7 | ); 8 | 9 | export function compile( 10 | source: string, 11 | schema: GraphQLSchema = starWarsSchema, 12 | options: CompilerOptions = {} 13 | ) { 14 | const document = parse(source); 15 | return compileToIR(schema, document, options); 16 | } 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | TODO: 9 | 10 | - [ ] Update CHANGELOG.md\* with your change (include reference to issue & this PR) 11 | - [ ] Make sure all of the significant new logic is covered by tests 12 | - [ ] Rebase your changes on master so that they can be merged easily 13 | - [ ] Make sure all tests and linter rules pass 14 | 15 | \*Make sure changelog entries note which project(s) has been affected. See older entries for examples on what this looks like. 16 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/__tests__/snapshotSerializers/astSerializer.ts: -------------------------------------------------------------------------------- 1 | import { ASTNode, print } from "graphql"; 2 | import { Plugin, Config, Refs, Printer } from "pretty-format"; 3 | 4 | export = { 5 | test(value: any) { 6 | return value && typeof value.kind === "string"; 7 | }, 8 | 9 | serialize( 10 | value: ASTNode, 11 | config: Config, 12 | indentation: string, 13 | depth: number, 14 | refs: Refs, 15 | printer: Printer 16 | ): string { 17 | return ( 18 | indentation + 19 | print(value) 20 | .trim() 21 | .replace(/\n/g, "\n" + indentation) 22 | ); 23 | } 24 | } as Plugin; 25 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/testRunner/jest-config.ts: -------------------------------------------------------------------------------- 1 | // Config to be handed off to jest 2 | // @see: https://jestjs.io/docs/en/configuration.html 3 | import { resolve } from "path"; 4 | 5 | export const config = { 6 | preset: "ts-jest", 7 | moduleFileExtensions: ["ts", "js"], 8 | rootDir: resolve(__dirname, "..", "..", "src"), 9 | testEnvironment: resolve(__dirname, "jest-vscode-environment.js"), 10 | setupFilesAfterEnv: [resolve(__dirname, "jest-vscode-framework-setup.js")], 11 | globals: { 12 | "ts-jest": { 13 | tsConfig: resolve(__dirname, "..", "..", "tsconfig.test.json"), 14 | diagnostics: false 15 | } 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["apollo-open-source"], 3 | "packageRules": [ 4 | { 5 | "paths": ["packages/apollo/package.json"], 6 | "extends": [":pinAllExceptPeerDependencies"], 7 | "packageRules": [ 8 | { 9 | "packageNames": ["graphql"], 10 | "rangeStrategy": "widen", 11 | "allowedVersions": "^14.0.0" 12 | } 13 | ] 14 | }, 15 | { 16 | "packageNames": ["@types/node"], 17 | "allowedVersions": "8.x" 18 | }, 19 | { 20 | "packageNames": ["core-js"], 21 | "rangeStrategy": "pin", 22 | "allowedVersions": ["=3.0.0-beta.13"] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true 4 | }, 5 | "files": [], 6 | "include": [], 7 | "references": [ 8 | { "path": "./packages/apollo" }, 9 | { "path": "./packages/apollo-codegen-core" }, 10 | { "path": "./packages/apollo-codegen-flow" }, 11 | { "path": "./packages/apollo-codegen-scala" }, 12 | { "path": "./packages/apollo-codegen-swift" }, 13 | { "path": "./packages/apollo-codegen-typescript" }, 14 | { "path": "./packages/apollo-graphql" }, 15 | { "path": "./packages/apollo-language-server" }, 16 | { "path": "./packages/vscode-apollo" }, 17 | { "path": "./packages/apollo-tools" } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | 4 | # TypeScript incremental compilation cache 5 | *.tsbuildinfo 6 | 7 | # Only the top-level of the monorepo should govern package locks, 8 | # not the individual package directories. (Keep in mind that currently 9 | # `npm install` should not be run within the `packages/*` directories.) 10 | packages/*/package-lock.json 11 | 12 | # Visual Studio Code workspace settings 13 | .vscode/* 14 | !.vscode/settings.json 15 | !.vscode/tasks.json 16 | !.vscode/launch.json 17 | !.vscode/extensions.json 18 | 19 | .DS_Store 20 | 21 | lerna-debug.log 22 | 23 | vscode-apollo-*.vsix 24 | 25 | .env 26 | 27 | # files generated from tests 28 | __tmp__* 29 | .vscode-test 30 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/src/values.ts: -------------------------------------------------------------------------------- 1 | import { LegacyCompilerContext } from "apollo-codegen-core/lib/compiler/legacyIR"; 2 | import CodeGenerator from "apollo-codegen-core/lib/utilities/CodeGenerator"; 3 | 4 | export function escapedString(string: string) { 5 | return string.replace(/"/g, '\\"'); 6 | } 7 | 8 | export function multilineString( 9 | generator: CodeGenerator, 10 | string: string 11 | ) { 12 | const lines = string.split("\n"); 13 | lines.forEach((line, index) => { 14 | const isLastLine = index != lines.length - 1; 15 | generator.printOnNewline( 16 | `"${escapedString(line)}"` + (isLastLine ? " +" : "") 17 | ); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/engine/operations/validateOperations.ts: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const VALIDATE_OPERATIONS = gql` 4 | mutation ValidateOperations( 5 | $id: ID! 6 | $operations: [OperationDocumentInput!]! 7 | $tag: String 8 | $gitContext: GitContextInput 9 | ) { 10 | service(id: $id) { 11 | validateOperations( 12 | tag: $tag 13 | operations: $operations 14 | gitContext: $gitContext 15 | ) { 16 | validationResults { 17 | type 18 | code 19 | description 20 | operation { 21 | name 22 | } 23 | } 24 | } 25 | } 26 | } 27 | `; 28 | -------------------------------------------------------------------------------- /__fixtures__/starwars/gqlQueries.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { gql, graphql } from "react-apollo"; 3 | 4 | const Query = gql` 5 | query HeroAndFriends($episode: Episode) { 6 | hero(episode: $episode) { 7 | ...heroDetails 8 | } 9 | } 10 | 11 | fragment heroDetails on Character { 12 | name 13 | ... on Droid { 14 | primaryFunction 15 | } 16 | ... on Human { 17 | height 18 | } 19 | } 20 | 21 | ${"this should be ignored"} 22 | `; 23 | 24 | const AnotherQuery = gql` 25 | query HeroName { 26 | hero { 27 | name 28 | } 29 | } 30 | `; 31 | 32 | function Component() { 33 | return
; 34 | } 35 | 36 | export default graphql(Query)(Component); 37 | -------------------------------------------------------------------------------- /packages/apollo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./lib", 6 | "esModuleInterop": true, 7 | "noImplicitAny": false, 8 | "baseUrl": ".", 9 | "paths": { 10 | "*": ["./@types/*", "../../types/*"] 11 | } 12 | }, 13 | "include": ["./src/**/*"], 14 | "exclude": ["**/__tests__/*", "**/__mocks__/*"], 15 | "references": [ 16 | { "path": "../apollo-codegen-flow" }, 17 | { "path": "../apollo-codegen-scala" }, 18 | { "path": "../apollo-codegen-swift" }, 19 | { "path": "../apollo-codegen-typescript" }, 20 | { "path": "../apollo-language-server" }, 21 | { "path": "../apollo-tools" } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature Request 3 | about: Propose new features or changes to existing features. 4 | --- 5 | 6 | 15 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "target": "es2017", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "esModuleInterop": true, 8 | "sourceMap": true, 9 | "declaration": true, 10 | "declarationMap": true, 11 | "removeComments": true, 12 | "strict": true, 13 | "noImplicitAny": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "noUnusedParameters": false, 17 | "noUnusedLocals": false, 18 | "forceConsistentCasingInFileNames": true, 19 | "lib": ["es2017", "esnext.asynciterable"], 20 | "types": ["node", "apollo-env"], 21 | "baseUrl": ".", 22 | "paths": { 23 | "*": ["types/*"] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/apollo-tools/src/utilities/graphql.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTNode, 3 | TypeDefinitionNode, 4 | TypeExtensionNode, 5 | DocumentNode, 6 | Kind 7 | } from "graphql"; 8 | 9 | // FIXME: We should add proper type guards for these predicate functions 10 | // to `@types/graphql`. 11 | declare module "graphql/language/predicates" { 12 | function isTypeDefinitionNode(node: ASTNode): node is TypeDefinitionNode; 13 | function isTypeExtensionNode(node: ASTNode): node is TypeExtensionNode; 14 | } 15 | 16 | export function isNode(maybeNode: any): maybeNode is ASTNode { 17 | return maybeNode && typeof maybeNode.kind === "string"; 18 | } 19 | 20 | export function isDocumentNode(node: ASTNode): node is DocumentNode { 21 | return isNode(node) && node.kind === Kind.DOCUMENT; 22 | } 23 | -------------------------------------------------------------------------------- /packages/apollo/src/__tests__/git.test.ts: -------------------------------------------------------------------------------- 1 | import { gitInfo } from "../git"; 2 | 3 | describe("Git integration", () => { 4 | it("Returns commit, branch, message, committer, and remoteUrl", async () => { 5 | // Currently these tests are too granular and would be better as 6 | // service:push tests when they are uncommented 7 | const info = await gitInfo(console.log); 8 | 9 | expect(info.commit).toBeDefined(); 10 | expect(info.committer).toBeDefined(); 11 | expect(info.remoteUrl).toBeDefined(); 12 | // Match both ssh and http/s remotes 13 | expect(info.remoteUrl).toMatch( 14 | /(https?:\/\/|git@)github.com(\/|:)apollographql\/apollo-tooling(.git)?/ 15 | ); 16 | expect(info.message).toBeDefined(); 17 | expect(info.branch).toBeDefined(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/index.ts: -------------------------------------------------------------------------------- 1 | // Exports for consuming APIs 2 | 3 | export { getValidationErrors } from "./errors/validation"; 4 | export { ToolError } from "./errors/logger"; 5 | export { LoadingHandler } from "./loadingHandler"; 6 | 7 | // projects 8 | export { GraphQLProject } from "./project/base"; 9 | export { isClientProject, GraphQLClientProject } from "./project/client"; 10 | export { isServiceProject, GraphQLServiceProject } from "./project/service"; 11 | 12 | // GraphQLSchemaProvider 13 | export { 14 | GraphQLSchemaProvider, 15 | schemaProviderFromConfig 16 | } from "./schema/providers"; 17 | 18 | // Engine 19 | export * from "./engine"; 20 | 21 | // Config 22 | export * from "./config"; 23 | 24 | // Generated types 25 | import * as graphqlTypes from "./graphqlTypes"; 26 | export { graphqlTypes }; 27 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/compiler/visitors/inlineRedundantTypeConditions.ts: -------------------------------------------------------------------------------- 1 | import { SelectionSet, Selection } from "../"; 2 | 3 | export function inlineRedundantTypeConditions( 4 | selectionSet: SelectionSet 5 | ): SelectionSet { 6 | const selections: Selection[] = []; 7 | 8 | for (const selection of selectionSet.selections) { 9 | if ( 10 | selection.kind === "TypeCondition" && 11 | selectionSet.possibleTypes.every(type => 12 | selection.selectionSet.possibleTypes.includes(type) 13 | ) 14 | ) { 15 | selections.push( 16 | ...inlineRedundantTypeConditions(selection.selectionSet).selections 17 | ); 18 | } else { 19 | selections.push(selection); 20 | } 21 | } 22 | 23 | return { 24 | possibleTypes: selectionSet.possibleTypes, 25 | selections 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /packages/apollo-env/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-env", 3 | "version": "0.4.0", 4 | "author": "opensource@apollographql.com", 5 | "license": "MIT", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 9 | }, 10 | "homepage": "https://github.com/apollographql/apollo-tooling", 11 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 12 | "main": "lib/index.js", 13 | "types": "lib/index.d.ts", 14 | "scripts": { 15 | "clean": "npx rimraf lib", 16 | "prebuild": "npm run clean", 17 | "build": "tsc --project ./src/fetch && node clone-types.js && cd src && tsc" 18 | }, 19 | "engines": { 20 | "node": ">=8" 21 | }, 22 | "dependencies": { 23 | "core-js": "3.0.0-beta.13", 24 | "node-fetch": "^2.2.0", 25 | "sha.js": "^2.4.11" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/typings/graphql-language-service.d.ts: -------------------------------------------------------------------------------- 1 | declare module "@apollographql/graphql-language-service-interface" { 2 | import { DocumentNode, GraphQLSchema, Location } from "graphql"; 3 | import { 4 | Diagnostic, 5 | Position, 6 | Range, 7 | CompletionItem 8 | } from "vscode-languageserver"; 9 | 10 | function getAutocompleteSuggestions( 11 | schema: GraphQLSchema, 12 | queryText: string, 13 | position: Position 14 | ): CompletionItem[]; 15 | } 16 | 17 | declare module "@apollographql/graphql-language-service-interface/dist/getAutocompleteSuggestions"; 18 | 19 | declare module "@apollographql/graphql-language-service-interface/dist/getDiagnostics" { 20 | import { Location } from "graphql"; 21 | import { Range } from "vscode-languageserver"; 22 | 23 | function getRange(location: Location, queryText: string): Range; 24 | } 25 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/testRunner/jest-vscode-environment.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Exposes the Visual Studio Code extension API to the Jest testing environment. 3 | * For custom environments reference: 4 | * @see https://jestjs.io/docs/en/configuration.html#testenvironment-string 5 | */ 6 | 7 | // Using import here results in `jest_environment_node_1.default` 8 | // The `.default` in this case doesn't exist. Interop issue with the built 9 | // version of the package? 10 | const NodeEnvironment = require("jest-environment-node"); 11 | import vscode from "vscode"; 12 | 13 | class VsCodeEnvironment extends NodeEnvironment { 14 | public async setup() { 15 | await super.setup(); 16 | this.global.vscode = vscode; 17 | } 18 | 19 | public async teardown() { 20 | this.global.vscode = {}; 21 | return await super.teardown(); 22 | } 23 | } 24 | 25 | module.exports = VsCodeEnvironment; 26 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/testRunner/vscode-test-script.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | import { spawn } from "child_process"; 3 | 4 | const cp = spawn( 5 | `node ${resolve( 6 | process.cwd(), 7 | "..", 8 | "..", 9 | "node_modules", 10 | "vscode", 11 | "bin", 12 | "test" 13 | )}`, 14 | [], 15 | { 16 | shell: true, 17 | env: { 18 | CODE_TESTS_PATH: `${process.cwd()}/lib/testRunner`, 19 | CODE_TESTS_WORKSPACE: process.cwd(), 20 | DISPLAY: process.env.DISPLAY 21 | } 22 | } 23 | ); 24 | 25 | cp.stdout.on("data", data => { 26 | console.log(data.toString()); 27 | }); 28 | 29 | cp.stderr.on("data", err => { 30 | // Useful for debugging, but generally more noisy than useful 31 | // console.error({ err: err.toString() }); 32 | }); 33 | 34 | cp.on("close", code => { 35 | if (code !== 0) { 36 | process.exit(code); 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/typings/graphql.d.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTNode, 3 | TypeSystemDefinitionNode, 4 | TypeSystemExtensionNode, 5 | FragmentDefinitionNode, 6 | OperationDefinitionNode 7 | } from "graphql"; 8 | 9 | // FIXME: We should add proper type guards for these predicate functions 10 | // to `@types/graphql`. 11 | declare module "graphql/language/predicates" { 12 | function isExecutableDefinitionNode( 13 | node: ASTNode 14 | ): node is OperationDefinitionNode | FragmentDefinitionNode; 15 | function isTypeSystemDefinitionNode( 16 | node: ASTNode 17 | ): node is TypeSystemDefinitionNode; 18 | function isTypeSystemExtensionNode( 19 | node: ASTNode 20 | ): node is TypeSystemExtensionNode; 21 | } 22 | 23 | declare module "graphql/validation/validate" { 24 | interface ValidationContext { 25 | _fragments: { [fragmentName: string]: FragmentDefinitionNode }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/apollo/src/OclifLoadingHandler.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "@oclif/command"; 2 | import { LoadingHandler } from "apollo-language-server"; 3 | export class OclifLoadingHandler implements LoadingHandler { 4 | constructor(private command: Command) {} 5 | async handle(message: string, value: Promise): Promise { 6 | // this.command.log(message); 7 | try { 8 | const ret = await value; 9 | return ret; 10 | } catch (e) { 11 | this.showError(`Error in "${message}": ${e}`); 12 | throw e; 13 | } 14 | } 15 | handleSync(message: string, value: () => T): T { 16 | // this.command.log(message); 17 | try { 18 | const ret = value(); 19 | return ret; 20 | } catch (e) { 21 | this.showError(`Error in "${message}": ${e}`); 22 | throw e; 23 | } 24 | } 25 | showError(message: string) { 26 | this.command.error(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/testRunner/jest.d.ts: -------------------------------------------------------------------------------- 1 | declare module "jest" { 2 | /** 3 | * Execute Jest and return a promise with the results. 4 | * 5 | * @see https://github.com/facebook/jest/blob/master/packages/jest-cli/src/cli/index.js 6 | * @param jestConfig Jest configuration options. 7 | * @param projects Paths to projects to run tests on. 8 | */ 9 | export function runCLI( 10 | jestConfig: object, 11 | projects: string[] 12 | ): Promise<{ globalConfig: object; results: ResultsObject }>; 13 | 14 | export interface ResultsObject { 15 | testResults: { 16 | failureMessage?: string; 17 | }[]; 18 | } 19 | } 20 | 21 | declare module "jest-environment-node" { 22 | export default class NodeEnvironment { 23 | public global: any; 24 | 25 | constructor(config: any); 26 | 27 | public setup(): Promise; 28 | public teardown(): Promise; 29 | public runScript(script: any): any; 30 | } 31 | } 32 | 33 | declare namespace NodeJS { 34 | interface Global { 35 | vscode: any; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/src/__tests__/language.ts: -------------------------------------------------------------------------------- 1 | import { stripIndent } from "common-tags"; 2 | 3 | import CodeGenerator from "apollo-codegen-core/lib/utilities/CodeGenerator"; 4 | 5 | import { objectDeclaration, propertyDeclaration } from "../language"; 6 | 7 | describe("Scala code generation: Basic language constructs", function() { 8 | let generator; 9 | 10 | beforeEach(function() { 11 | generator = new CodeGenerator(); 12 | }); 13 | 14 | test(`should generate a object declaration`, function() { 15 | objectDeclaration(generator, { objectName: "Hero" }, () => { 16 | propertyDeclaration( 17 | generator, 18 | { propertyName: "name", typeName: "String" }, 19 | () => {} 20 | ); 21 | propertyDeclaration( 22 | generator, 23 | { propertyName: "age", typeName: "Int" }, 24 | () => {} 25 | ); 26 | }); 27 | 28 | expect(generator.output).toBe(stripIndent` 29 | object Hero { 30 | val name: String = { 31 | } 32 | val age: Int = { 33 | } 34 | } 35 | `); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/engine/operations/checkSchema.ts: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const CHECK_SCHEMA = gql` 4 | mutation CheckSchema( 5 | $id: ID! 6 | $schema: IntrospectionSchemaInput! 7 | $tag: String 8 | $gitContext: GitContextInput 9 | $historicParameters: HistoricQueryParameters 10 | $frontend: String 11 | ) { 12 | service(id: $id) { 13 | checkSchema( 14 | proposedSchema: $schema 15 | baseSchemaTag: $tag 16 | gitContext: $gitContext 17 | historicParameters: $historicParameters 18 | frontend: $frontend 19 | ) { 20 | targetUrl 21 | diffToPrevious { 22 | type 23 | affectedQueries { 24 | __typename 25 | } 26 | changes { 27 | type 28 | code 29 | description 30 | } 31 | validationConfig { 32 | from 33 | to 34 | queryCountThreshold 35 | queryCountThresholdPercentage 36 | } 37 | } 38 | } 39 | } 40 | } 41 | `; 42 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/compiler/visitors/generateOperationId.ts: -------------------------------------------------------------------------------- 1 | import { Operation, Fragment } from "../"; 2 | import { collectFragmentsReferenced } from "./collectFragmentsReferenced"; 3 | import { createHash } from "crypto"; 4 | 5 | export function generateOperationId( 6 | operation: Operation, 7 | fragments: { [fragmentName: string]: Fragment }, 8 | fragmentsReferenced?: Iterable 9 | ) { 10 | if (!fragmentsReferenced) { 11 | fragmentsReferenced = collectFragmentsReferenced( 12 | operation.selectionSet, 13 | fragments 14 | ); 15 | } 16 | 17 | const sourceWithFragments = [ 18 | operation.source, 19 | ...Array.from(fragmentsReferenced).map(fragmentName => { 20 | const fragment = fragments[fragmentName]; 21 | if (!fragment) { 22 | throw new Error(`Cannot find fragment "${fragmentName}"`); 23 | } 24 | return fragment.source; 25 | }) 26 | ].join("\n"); 27 | 28 | const hash = createHash("sha256"); 29 | hash.update(sourceWithFragments); 30 | const operationId = hash.digest("hex"); 31 | 32 | return { operationId, sourceWithFragments }; 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Meteor Development Group, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/global.d.ts: -------------------------------------------------------------------------------- 1 | declare function fetch( 2 | input?: RequestInfo, 3 | init?: RequestInit 4 | ): Promise; 5 | 6 | declare interface GlobalFetch { 7 | fetch(input: RequestInfo, init?: RequestInit): Promise; 8 | } 9 | 10 | type RequestInfo = import("./fetch").RequestInfo; 11 | type Headers = import("./fetch").Headers; 12 | type HeadersInit = import("./fetch").HeadersInit; 13 | type Body = import("./fetch").Body; 14 | type Request = import("./fetch").Request; 15 | type RequestAgent = import("./fetch").RequestAgent; 16 | type RequestInit = import("./fetch").RequestInit; 17 | type RequestMode = import("./fetch").RequestMode; 18 | type RequestCredentials = import("./fetch").RequestCredentials; 19 | type RequestCache = import("./fetch").RequestCache; 20 | type RequestRedirect = import("./fetch").RequestRedirect; 21 | type ReferrerPolicy = import("./fetch").ReferrerPolicy; 22 | type Response = import("./fetch").Response; 23 | type ResponseInit = import("./fetch").ResponseInit; 24 | type BodyInit = import("./fetch").BodyInit; 25 | type URLSearchParams = import("./url").URLSearchParams; 26 | type URLSearchParamsInit = import("./url").URLSearchParamsInit; 27 | -------------------------------------------------------------------------------- /types/pretty-format/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "pretty-format" { 2 | export interface Plugin { 3 | test(value: any): boolean; 4 | serialize( 5 | val: any, 6 | config: Config, 7 | indentation: string, 8 | depth: number, 9 | refs: Refs, 10 | printer: Printer 11 | ): string; 12 | } 13 | 14 | export interface Config { 15 | callToJSON: boolean; 16 | colors: Colors; 17 | escapeRegex: boolean; 18 | escapeString: boolean; 19 | indent: string; 20 | maxDepth: number; 21 | min: boolean; 22 | plugins: Plugin[]; 23 | printFunctionName: boolean; 24 | spacingInner: string; 25 | spacingOuter: string; 26 | } 27 | 28 | export type Printer = ( 29 | val: any, 30 | config: Config, 31 | indentation: string, 32 | depth: number, 33 | refs: Refs, 34 | hasCalledToJSON?: boolean 35 | ) => string; 36 | 37 | export type Refs = any[]; 38 | 39 | export interface Colors { 40 | comment: { close: string; open: string }; 41 | content: { close: string; open: string }; 42 | prop: { close: string; open: string }; 43 | tag: { close: string; open: string }; 44 | value: { close: string; open: string }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/compiler/visitors/collectFragmentsReferenced.ts: -------------------------------------------------------------------------------- 1 | import { SelectionSet, Fragment } from "../"; 2 | 3 | export function collectFragmentsReferenced( 4 | selectionSet: SelectionSet, 5 | fragments: { [fragmentName: string]: Fragment }, 6 | fragmentsReferenced: Set = new Set() 7 | ): Set { 8 | for (const selection of selectionSet.selections) { 9 | switch (selection.kind) { 10 | case "FragmentSpread": 11 | fragmentsReferenced.add(selection.fragmentName); 12 | 13 | const fragment = fragments[selection.fragmentName]; 14 | if (!fragment) { 15 | throw new Error(`Cannot find fragment "${selection.fragmentName}"`); 16 | } 17 | 18 | collectFragmentsReferenced( 19 | fragment.selectionSet, 20 | fragments, 21 | fragmentsReferenced 22 | ); 23 | break; 24 | case "Field": 25 | case "TypeCondition": 26 | case "BooleanCondition": 27 | if (selection.selectionSet) { 28 | collectFragmentsReferenced( 29 | selection.selectionSet, 30 | fragments, 31 | fragmentsReferenced 32 | ); 33 | } 34 | break; 35 | } 36 | } 37 | 38 | return fragmentsReferenced; 39 | } 40 | -------------------------------------------------------------------------------- /packages/apollo-graphql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-graphql", 3 | "version": "0.2.0", 4 | "description": "Apollo GraphQL utility library", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "keywords": [], 8 | "author": "Apollo ", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">=6" 12 | }, 13 | "dependencies": { 14 | "apollo-env": "file:../apollo-env", 15 | "lodash.sortby": "^4.7.0" 16 | }, 17 | "peerDependencies": { 18 | "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" 19 | }, 20 | "jest": { 21 | "preset": "ts-jest", 22 | "transformIgnorePatterns": [ 23 | "/node_modules/", 24 | "/apollo-env/" 25 | ], 26 | "testEnvironment": "node", 27 | "testMatch": [ 28 | "**/__tests__/*.(js|ts)" 29 | ], 30 | "setupFiles": [ 31 | "/../apollo-env/lib/index.js" 32 | ], 33 | "testPathIgnorePatterns": [ 34 | "/node_modules/", 35 | "/lib/", 36 | "/test/fixtures/", 37 | "/test/test-utils" 38 | ], 39 | "moduleFileExtensions": [ 40 | "ts", 41 | "js" 42 | ], 43 | "globals": { 44 | "ts-jest": { 45 | "tsConfig": "/tsconfig.test.json", 46 | "diagnostics": false 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/url.d.ts: -------------------------------------------------------------------------------- 1 | export declare class URL { 2 | constructor(input: string, base?: string | URL); 3 | hash: string; 4 | host: string; 5 | hostname: string; 6 | href: string; 7 | readonly origin: string; 8 | password: string; 9 | pathname: string; 10 | port: string; 11 | protocol: string; 12 | search: string; 13 | readonly searchParams: URLSearchParams; 14 | username: string; 15 | toString(): string; 16 | toJSON(): string; 17 | } 18 | 19 | export declare class URLSearchParams implements Iterable<[string, string]> { 20 | constructor(init?: URLSearchParamsInit); 21 | append(name: string, value: string): void; 22 | delete(name: string): void; 23 | entries(): IterableIterator<[string, string]>; 24 | forEach(callback: (value: string, name: string) => void): void; 25 | get(name: string): string | null; 26 | getAll(name: string): string[]; 27 | has(name: string): boolean; 28 | keys(): IterableIterator; 29 | set(name: string, value: string): void; 30 | sort(): void; 31 | toString(): string; 32 | values(): IterableIterator; 33 | [Symbol.iterator](): IterableIterator<[string, string]>; 34 | } 35 | 36 | export type URLSearchParamsInit = 37 | | URLSearchParams 38 | | string 39 | | { [key: string]: Object | Object[] | undefined } 40 | | Iterable<[string, Object]> 41 | | Array<[string, Object]>; 42 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/testRunner/README.md: -------------------------------------------------------------------------------- 1 | # Jest TestRunner 2 | 3 | Huge thanks to Unibeautify for their initial work on this. Most of the code in `/testRunner` is utilizing their work, barring some changes to configuration. 4 | 5 | For reference, see: 6 | https://github.com/Unibeautify/vscode/tree/master/test 7 | 8 | ## Notes 9 | 10 | ### .vscodeignore 11 | 12 | The test runner itself must be compiled for VSCode to run it, so it lives in `src` and gets compiled to js. However, it's not included in the final build via the [.vscodeignore](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#.vscodeignore) file. 13 | 14 | ### ts-jest 15 | 16 | The tests themselves don't need to be compiled due to `ts-jest`, so they're ignored in the `tsconfig.json` 17 | 18 | ### jest-config.ts 19 | 20 | This is a standard Jest configuration object which is passed to the CLI. For a full reference, see [Jest Config](https://jestjs.io/docs/en/configuration.html). A couple noteworthy configuration options that are used: 21 | 22 | - `testEnvironment`: This points to the custom test environment that's provided in order to run vscode. The environment extends `NodeEnvironment`, however it also adds `vscode` to the `global` object. 23 | - `setupFilesAfterEnv`: Script to run for any initialization before tests are run. This mocks requests for the vscode module with the vscode object we've provided on the `global` object in the custom test environment. 24 | -------------------------------------------------------------------------------- /packages/vscode-apollo/syntaxes/graphql.js.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["js", "jsx", "ts", "tsx", "vue"], 3 | "injectionSelector": "L:source -string -comment", 4 | "patterns": [ 5 | { 6 | "name": "taggedTemplates", 7 | "contentName": "meta.embedded.block.graphql", 8 | "begin": "(Relay\\.QL|gql|graphql(\\.experimental)?)(`)", 9 | "beginCaptures": { 10 | "1": { 11 | "name": "entity.name.function.tagged-template.js" 12 | }, 13 | "2": { 14 | "name": "punctuation.definition.string.template.begin.js" 15 | } 16 | }, 17 | "end": "`", 18 | "endCaptures": { 19 | "0": { 20 | "name": "punctuation.definition.string.template.end.js" 21 | } 22 | }, 23 | "patterns": [{ "include": "source.graphql" }] 24 | }, 25 | { 26 | "name": "taggedTemplates", 27 | "contentName": "meta.embedded.block.graphql", 28 | "begin": "(`)(#graphql)", 29 | "beginCaptures": { 30 | "1": { 31 | "name": "punctuation.definition.string.template.begin.js" 32 | }, 33 | "2": { 34 | "name": "comment.line.graphql.js" 35 | } 36 | }, 37 | "end": "`", 38 | "endCaptures": { 39 | "0": { 40 | "name": "punctuation.definition.string.template.end.js" 41 | } 42 | }, 43 | "patterns": [{ "include": "source.graphql" }] 44 | } 45 | ], 46 | "scopeName": "inline.graphql" 47 | } 48 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/format.ts: -------------------------------------------------------------------------------- 1 | import moment from "moment"; 2 | 3 | export function formatMS( 4 | ms: number, 5 | d: number, 6 | allowMicros = false, 7 | allowNanos = true 8 | ) { 9 | if (ms === 0 || ms === null) return "0"; 10 | const bounds = [ 11 | moment.duration(1, "hour").asMilliseconds(), 12 | moment.duration(1, "minute").asMilliseconds(), 13 | moment.duration(1, "second").asMilliseconds(), 14 | 1, 15 | 0.001, 16 | 0.000001 17 | ]; 18 | const units = ["hr", "min", "s", "ms", "μs", "ns"]; 19 | 20 | const makeSmallNumbersNice = (f: number) => { 21 | if (f >= 100) return f.toFixed(0); 22 | if (f >= 10) return f.toFixed(1); 23 | if (f === 0) return "0"; 24 | return f.toFixed(2); 25 | }; 26 | 27 | const bound = bounds.find(b => b <= ms) || bounds[bounds.length - 1]; 28 | const boundIndex = bounds.indexOf(bound); 29 | const unit = boundIndex >= 0 ? units[boundIndex] : ""; 30 | 31 | if ((unit === "μs" || unit === "ns") && !allowMicros) { 32 | return "< 1ms"; 33 | } 34 | if (unit === "ns" && !allowNanos) { 35 | return "< 1µs"; 36 | } 37 | const value = 38 | typeof d !== "undefined" 39 | ? (ms / bound).toFixed(d) 40 | : makeSmallNumbersNice(ms / bound); 41 | 42 | // if something is rounded to 1000 and not reduced this will catch and reduce it 43 | if ((value === "1000" || value === "1000.0") && boundIndex >= 1) { 44 | return `1${units[boundIndex - 1]}`; 45 | } 46 | 47 | return `${value}${unit}`; 48 | } 49 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/service/download.ts: -------------------------------------------------------------------------------- 1 | import { flags } from "@oclif/command"; 2 | import { introspectionFromSchema } from "graphql"; 3 | import { writeFileSync } from "fs"; 4 | 5 | import { ProjectCommand } from "../../Command"; 6 | 7 | export default class ServiceDownload extends ProjectCommand { 8 | static aliases = ["schema:download"]; 9 | static description = "Download the schema from your GraphQL endpoint."; 10 | 11 | static flags = { 12 | ...ProjectCommand.flags, 13 | tag: flags.string({ 14 | char: "t", 15 | description: "The published tag to check this service against", 16 | default: "current" 17 | }), 18 | skipSSLValidation: flags.boolean({ 19 | char: "k", 20 | description: "Allow connections to an SSL site without certs" 21 | }) 22 | }; 23 | 24 | static args = [ 25 | { 26 | name: "output", 27 | description: "Path to write the introspection result to", 28 | required: true, 29 | default: "schema.json" 30 | } 31 | ]; 32 | 33 | async run() { 34 | let result; 35 | let gitContext; 36 | await this.runTasks(({ args, project, flags }) => [ 37 | { 38 | title: `Saving schema to ${args.output}`, 39 | task: async () => { 40 | const schema = await project.resolveSchema({ tag: flags.tag }); 41 | writeFileSync( 42 | args.output, 43 | JSON.stringify(introspectionFromSchema(schema), null, 2) 44 | ); 45 | } 46 | } 47 | ]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/project/service.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLProject } from "./base"; 2 | import { LoadingHandler } from "../loadingHandler"; 3 | import { FileSet } from "../fileSet"; 4 | import { ServiceConfig } from "../config"; 5 | import { ClientIdentity } from "../engine"; 6 | import URI from "vscode-uri"; 7 | 8 | export function isServiceProject( 9 | project: GraphQLProject 10 | ): project is GraphQLServiceProject { 11 | return project instanceof GraphQLServiceProject; 12 | } 13 | 14 | export interface GraphQLServiceProjectConfig { 15 | clientIdentity?: ClientIdentity; 16 | config: ServiceConfig; 17 | rootURI: URI; 18 | loadingHandler: LoadingHandler; 19 | } 20 | export class GraphQLServiceProject extends GraphQLProject { 21 | constructor({ 22 | clientIdentity, 23 | config, 24 | rootURI, 25 | loadingHandler 26 | }: GraphQLServiceProjectConfig) { 27 | const fileSet = new FileSet({ 28 | rootURI: config.configDirURI || rootURI, 29 | includes: [...config.service.includes, ".env", "apollo.config.js"], 30 | excludes: config.service.excludes, 31 | configURI: config.configURI 32 | }); 33 | 34 | super({ config, fileSet, loadingHandler, clientIdentity }); 35 | this.config = config; 36 | } 37 | 38 | get displayName() { 39 | return this.config.name || "Unnamed Project"; 40 | } 41 | 42 | initialize() { 43 | return []; 44 | } 45 | 46 | validate() {} 47 | 48 | getProjectStats() { 49 | return { loaded: true, type: "service" }; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/apollo-tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apollographql/apollo-tools", 3 | "version": "0.3.5", 4 | "author": "Apollo GraphQL ", 5 | "license": "MIT", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 9 | }, 10 | "homepage": "https://github.com/apollographql/apollo-tooling", 11 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 12 | "main": "lib/index.js", 13 | "types": "lib/index.d.ts", 14 | "engines": { 15 | "node": ">=8", 16 | "npm": ">=6" 17 | }, 18 | "dependencies": { 19 | "apollo-env": "file:../apollo-env" 20 | }, 21 | "jest": { 22 | "preset": "ts-jest", 23 | "testEnvironment": "node", 24 | "setupFiles": [ 25 | "/../apollo-env/lib/index.js" 26 | ], 27 | "testMatch": null, 28 | "testRegex": "/__tests__/.*\\.test\\.(js|ts)$", 29 | "testPathIgnorePatterns": [ 30 | "/node_modules/", 31 | "/lib/" 32 | ], 33 | "moduleFileExtensions": [ 34 | "ts", 35 | "js" 36 | ], 37 | "transformIgnorePatterns": [ 38 | "/node_modules/", 39 | "/apollo-env/" 40 | ], 41 | "snapshotSerializers": [ 42 | "/src/__tests__/snapshotSerializers/astSerializer.ts", 43 | "/src/__tests__/snapshotSerializers/graphQLTypeSerializer.ts" 44 | ], 45 | "globals": { 46 | "ts-jest": { 47 | "tsConfig": "/tsconfig.test.json", 48 | "diagnostics": true 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/config/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApolloConfig, 3 | ClientConfig, 4 | ClientServiceConfig, 5 | LocalServiceConfig, 6 | ServiceConfig, 7 | ApolloConfigFormat 8 | } from "./config"; 9 | import { ServiceSpecifier, ServiceIDAndTag } from "../engine"; 10 | 11 | export function isClientConfig(config: ApolloConfig): config is ClientConfig { 12 | return config.isClient; 13 | } 14 | 15 | // checks the `config.client.service` object for a localSchemaFile 16 | export function isLocalServiceConfig( 17 | config: ClientServiceConfig 18 | ): config is LocalServiceConfig { 19 | return !!(config as LocalServiceConfig).localSchemaFile; 20 | } 21 | 22 | export function isServiceConfig(config: ApolloConfig): config is ServiceConfig { 23 | return config.isService; 24 | } 25 | 26 | export function getServiceFromKey(key?: string) { 27 | if (key) { 28 | const [type, service] = key.split(":"); 29 | if (type === "service") return service; 30 | } 31 | return; 32 | } 33 | 34 | export function getServiceName(config: ApolloConfigFormat) { 35 | if (config.service) return config.service.name; 36 | if (config.client) { 37 | if (typeof config.client.service === "string") { 38 | return parseServiceSpecifier(config.client 39 | .service as ServiceSpecifier)[0]; 40 | } 41 | return config.client.service && config.client.service.name; 42 | } else { 43 | return undefined; 44 | } 45 | } 46 | 47 | export function parseServiceSpecifier(specifier: ServiceSpecifier) { 48 | const [id, tag] = specifier.split("@").map(x => x.trim()); 49 | return [id, tag] as ServiceIDAndTag; 50 | } 51 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-codegen-scala", 3 | "description": "Scala generator module for Apollo Codegen", 4 | "version": "0.33.6", 5 | "author": "Apollo GraphQL ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 10 | }, 11 | "homepage": "https://github.com/apollographql/apollo-tooling", 12 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 13 | "main": "lib/index.js", 14 | "types": "lib/index.d.ts", 15 | "engines": { 16 | "node": ">=8", 17 | "npm": ">=6" 18 | }, 19 | "dependencies": { 20 | "apollo-codegen-core": "file:../apollo-codegen-core", 21 | "apollo-env": "file:../apollo-env", 22 | "change-case": "^3.0.1", 23 | "common-tags": "^1.5.1", 24 | "inflected": "^2.0.3" 25 | }, 26 | "jest": { 27 | "preset": "ts-jest", 28 | "transformIgnorePatterns": [ 29 | "/node_modules/", 30 | "/apollo-env/" 31 | ], 32 | "testEnvironment": "node", 33 | "testMatch": [ 34 | "**/__tests__/*.(js|ts)" 35 | ], 36 | "setupFiles": [ 37 | "/../apollo-env/lib/index.js" 38 | ], 39 | "testPathIgnorePatterns": [ 40 | "/node_modules/", 41 | "/lib/", 42 | "/test/fixtures/", 43 | "/test/test-utils" 44 | ], 45 | "moduleFileExtensions": [ 46 | "ts", 47 | "js" 48 | ], 49 | "globals": { 50 | "ts-jest": { 51 | "tsConfig": "/tsconfig.test.json", 52 | "diagnostics": false 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/apollo-codegen-swift/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-codegen-swift", 3 | "description": "Swift generator module for Apollo Codegen", 4 | "version": "0.32.10", 5 | "author": "Apollo GraphQL ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 10 | }, 11 | "homepage": "https://github.com/apollographql/apollo-tooling", 12 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 13 | "main": "lib/index.js", 14 | "types": "lib/index.d.ts", 15 | "engines": { 16 | "node": ">=8", 17 | "npm": ">=6" 18 | }, 19 | "dependencies": { 20 | "apollo-codegen-core": "file:../apollo-codegen-core", 21 | "apollo-env": "file:../apollo-env", 22 | "change-case": "^3.0.1", 23 | "common-tags": "^1.5.1", 24 | "inflected": "^2.0.3" 25 | }, 26 | "jest": { 27 | "preset": "ts-jest", 28 | "transformIgnorePatterns": [ 29 | "/node_modules/", 30 | "/apollo-env/" 31 | ], 32 | "testEnvironment": "node", 33 | "testMatch": [ 34 | "**/__tests__/*.(js|ts)" 35 | ], 36 | "setupFiles": [ 37 | "/../apollo-env/lib/index.js" 38 | ], 39 | "testPathIgnorePatterns": [ 40 | "/node_modules/", 41 | "/lib/", 42 | "/test/fixtures/", 43 | "/test/test-utils" 44 | ], 45 | "moduleFileExtensions": [ 46 | "ts", 47 | "js" 48 | ], 49 | "globals": { 50 | "ts-jest": { 51 | "tsConfig": "/tsconfig.test.json", 52 | "diagnostics": false 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /__fixtures__/misc/schema.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutation 4 | } 5 | 6 | scalar Date 7 | 8 | type doubleHump { 9 | humpOne: String 10 | humpTwo: String 11 | } 12 | 13 | type OddType { 14 | date: Date 15 | camel: doubleHump 16 | } 17 | 18 | # This is a type to test comments 19 | type CommentTest { 20 | "This is a single-line comment" 21 | singleLine: String 22 | """ 23 | This is a 24 | multi-line 25 | comment. 26 | """ 27 | multiLine: String 28 | enumCommentTest: EnumCommentTestCase 29 | } 30 | 31 | enum EnumCommentTestCase { 32 | "This is a single-line comment" 33 | first 34 | """ 35 | This is a 36 | multi-line 37 | comment. 38 | """ 39 | second 40 | } 41 | 42 | interface InterfaceTestCase { 43 | prop: String! 44 | } 45 | 46 | type ImplA implements InterfaceTestCase { 47 | prop: String! 48 | propA: String! 49 | } 50 | 51 | type ImplB implements InterfaceTestCase { 52 | prop: String! 53 | propB: Int 54 | } 55 | 56 | type PartialA { 57 | prop: String! 58 | } 59 | 60 | type PartialB { 61 | prop: String! 62 | } 63 | 64 | type Nesting { 65 | propA: [[EnumCommentTestCase!]!]! 66 | propB: [[EnumCommentTestCase]] 67 | } 68 | 69 | input Duplicate { 70 | propA: EnumCommentTestCase! 71 | propB: [EnumCommentTestCase!]! 72 | } 73 | 74 | union UnionTestCase = PartialA | PartialB 75 | 76 | type Query { 77 | misc: OddType 78 | commentTest: CommentTest 79 | interfaceTest: InterfaceTestCase 80 | unionTest: UnionTestCase 81 | scalarTest: Boolean! 82 | nesting: Nesting! 83 | } 84 | 85 | type Mutation { 86 | duplicates(a: EnumCommentTestCase!, b: EnumCommentTestCase!, c: Duplicate!): Nesting! 87 | } 88 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/languageServerClient.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ServerOptions, 3 | TransportKind, 4 | LanguageClientOptions, 5 | LanguageClient 6 | } from "vscode-languageclient"; 7 | import { workspace, OutputChannel } from "vscode"; 8 | 9 | const { version, referenceID } = require("../package.json"); 10 | 11 | export function getLanguageServerClient( 12 | serverModule: string, 13 | outputChannel: OutputChannel 14 | ) { 15 | const env = { 16 | APOLLO_CLIENT_NAME: "Apollo VS Code", 17 | APOLLO_CLIENT_VERSION: version, 18 | APOLLO_CLIENT_REFERENCE_ID: referenceID 19 | }; 20 | 21 | const debugOptions = { 22 | execArgv: ["--nolazy", "--inspect=6009"], 23 | env 24 | }; 25 | 26 | const serverOptions: ServerOptions = { 27 | run: { 28 | module: serverModule, 29 | transport: TransportKind.ipc, 30 | options: { 31 | env 32 | } 33 | }, 34 | debug: { 35 | module: serverModule, 36 | transport: TransportKind.ipc, 37 | options: debugOptions 38 | } 39 | }; 40 | 41 | const clientOptions: LanguageClientOptions = { 42 | documentSelector: [ 43 | "graphql", 44 | "javascript", 45 | "typescript", 46 | "javascriptreact", 47 | "typescriptreact", 48 | "python" 49 | ], 50 | synchronize: { 51 | fileEvents: [ 52 | workspace.createFileSystemWatcher("**/.env"), 53 | workspace.createFileSystemWatcher("**/*.{graphql,js,ts,jsx,tsx,py}") 54 | ] 55 | }, 56 | outputChannel 57 | }; 58 | 59 | return new LanguageClient( 60 | "apollographql", 61 | "Apollo GraphQL", 62 | serverOptions, 63 | clientOptions 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /packages/vscode-apollo/syntaxes/graphql.py.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": ["python"], 3 | "injectionSelector": "L:source -string -comment", 4 | "patterns": [ 5 | { 6 | "name": "meta.function-call.python", 7 | "begin": "\\b(gql)\\s*(\\()", 8 | "beginCaptures": { 9 | "1": { 10 | "name": "meta.function-call.generic.python" 11 | }, 12 | "2": { 13 | "name": "punctuation.definition.arguments.begin.python" 14 | } 15 | }, 16 | "end": "(\\))", 17 | "endCaptures": { 18 | "1": { 19 | "name": "punctuation.definition.arguments.end.python" 20 | } 21 | }, 22 | "patterns": [ 23 | { 24 | "name": "taggedTemplates", 25 | "contentName": "meta.embedded.block.graphql", 26 | "begin": "([bfru]*)((\"(?:\"\")?|'(?:'')?))", 27 | "beginCaptures": { 28 | "1": { 29 | "name": "storage.type.string.python" 30 | }, 31 | "2": { 32 | "name": "string.quoted.multi.python" 33 | }, 34 | "3": { 35 | "name": "punctuation.definition.string.begin.python" 36 | } 37 | }, 38 | "end": "((\\3))", 39 | "endCaptures": { 40 | "1": { 41 | "name": "string.quoted.multi.python" 42 | }, 43 | "2": { 44 | "name": "punctuation.definition.string.end.python" 45 | } 46 | }, 47 | "patterns": [ 48 | { 49 | "include": "source.graphql" 50 | } 51 | ] 52 | } 53 | ] 54 | } 55 | ], 56 | "scopeName": "inline.graphql.python" 57 | } 58 | -------------------------------------------------------------------------------- /packages/apollo-codegen-flow/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-codegen-flow", 3 | "description": "Flow generator module for Apollo Codegen", 4 | "version": "0.32.10", 5 | "author": "Apollo GraphQL ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 10 | }, 11 | "homepage": "https://github.com/apollographql/apollo-tooling", 12 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 13 | "main": "lib/index.js", 14 | "types": "lib/index.d.ts", 15 | "engines": { 16 | "node": ">=8", 17 | "npm": ">=6" 18 | }, 19 | "dependencies": { 20 | "@babel/generator": "7.4.0", 21 | "@babel/types": "7.4.0", 22 | "apollo-codegen-core": "file:../apollo-codegen-core", 23 | "apollo-env": "file:../apollo-env", 24 | "change-case": "^3.0.1", 25 | "common-tags": "^1.5.1", 26 | "inflected": "^2.0.3" 27 | }, 28 | "jest": { 29 | "preset": "ts-jest", 30 | "transformIgnorePatterns": [ 31 | "/node_modules/", 32 | "/apollo-env/" 33 | ], 34 | "testEnvironment": "node", 35 | "testMatch": [ 36 | "**/__tests__/*.(js|ts)" 37 | ], 38 | "setupFiles": [ 39 | "/../apollo-env/lib/index.js" 40 | ], 41 | "testPathIgnorePatterns": [ 42 | "/node_modules/", 43 | "/lib/", 44 | "/test/fixtures/", 45 | "/test/test-utils" 46 | ], 47 | "moduleFileExtensions": [ 48 | "ts", 49 | "js" 50 | ], 51 | "globals": { 52 | "ts-jest": { 53 | "tsConfig": "/tsconfig.test.json", 54 | "diagnostics": false 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/apollo-codegen-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-codegen-typescript", 3 | "description": "TypeScript generator module for Apollo Codegen", 4 | "version": "0.32.11", 5 | "author": "Apollo GraphQL ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 10 | }, 11 | "homepage": "https://github.com/apollographql/apollo-tooling", 12 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 13 | "main": "lib/index.js", 14 | "types": "lib/index.d.ts", 15 | "engines": { 16 | "node": ">=8", 17 | "npm": ">=6" 18 | }, 19 | "dependencies": { 20 | "@babel/generator": "7.4.0", 21 | "@babel/types": "7.4.0", 22 | "apollo-codegen-core": "file:../apollo-codegen-core", 23 | "apollo-env": "file:../apollo-env", 24 | "change-case": "^3.0.1", 25 | "common-tags": "^1.5.1", 26 | "inflected": "^2.0.3" 27 | }, 28 | "jest": { 29 | "preset": "ts-jest", 30 | "transformIgnorePatterns": [ 31 | "/node_modules/", 32 | "/apollo-env/" 33 | ], 34 | "testEnvironment": "node", 35 | "testMatch": [ 36 | "**/__tests__/*.(js|ts)" 37 | ], 38 | "setupFiles": [ 39 | "/../apollo-env/lib/index.js" 40 | ], 41 | "testPathIgnorePatterns": [ 42 | "/node_modules/", 43 | "/lib/", 44 | "/test/fixtures/", 45 | "/test/test-utils" 46 | ], 47 | "moduleFileExtensions": [ 48 | "ts", 49 | "js" 50 | ], 51 | "globals": { 52 | "ts-jest": { 53 | "tsConfig": "/tsconfig.test.json", 54 | "diagnostics": false 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/utilities/printing.ts: -------------------------------------------------------------------------------- 1 | import { sep } from "path"; 2 | 3 | // Code generation helper functions copied from graphql-js (https://github.com/graphql/graphql-js) 4 | 5 | /** 6 | * Given maybeArray, print an empty string if it is null or empty, otherwise 7 | * print all items together separated by separator if provided 8 | */ 9 | export function join(maybeArray?: any[], separator?: string) { 10 | return maybeArray ? maybeArray.filter(x => x).join(separator || "") : ""; 11 | } 12 | 13 | /** 14 | * Given array, print each item on its own line, wrapped in an 15 | * indented "{ }" block. 16 | */ 17 | export function block(array: any[]) { 18 | return array && array.length !== 0 19 | ? indent("{\n" + join(array, "\n")) + "\n}" 20 | : "{}"; 21 | } 22 | 23 | /** 24 | * If maybeString is not null or empty, then wrap with start and end, otherwise 25 | * print an empty string. 26 | */ 27 | export function wrap(start: string, maybeString?: string, end?: string) { 28 | return maybeString ? start + maybeString + (end || "") : ""; 29 | } 30 | 31 | export function indent(maybeString?: string) { 32 | return maybeString && maybeString.replace(/\n/g, "\n "); 33 | } 34 | 35 | /** 36 | * Generates the body of a JSDoc style comment 37 | */ 38 | export function commentBlockContent(commentString: string) { 39 | return ( 40 | "*\n" + 41 | commentString 42 | .split("\n") 43 | .map(line => ` * ${line.replace("*/", "")}`) 44 | .join("\n") + 45 | "\n " 46 | ); 47 | } 48 | /** 49 | * Because different OS's have different file separators, and we don't want those for 50 | * codegen files, we can take a uri and replace the OS separators with the "universal" separator (/) 51 | * @param uri 52 | */ 53 | export function unifyPaths(uri: string) { 54 | return uri.split(sep).join("/"); 55 | } 56 | -------------------------------------------------------------------------------- /packages/apollo-env/clone-types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Goal 3 | * - recursively search the src/ dir for any *.d.ts files 4 | * - copy those d.ts files to the lib/ dir, while keeping the same folder 5 | * structure found in src/ 6 | */ 7 | const fs = require("fs"); 8 | const path = require("path"); 9 | 10 | // get list of all files that match filter 11 | const walk = (dir, filter) => { 12 | let fileList = []; 13 | const files = fs.readdirSync(dir); 14 | 15 | for (file of files) { 16 | const filePath = path.join(dir, file); 17 | const stat = fs.statSync(filePath); 18 | 19 | if (stat.isDirectory()) { 20 | const subFileList = walk(filePath, filter); 21 | fileList = [...fileList, ...subFileList]; 22 | } else { 23 | if (filter && filter.test) { 24 | if (filter.test(filePath)) fileList.push(filePath); 25 | } else { 26 | fileList.push(filePath); 27 | } 28 | } 29 | } 30 | 31 | return fileList; 32 | }; 33 | 34 | const makeNestedDir = dir => { 35 | if (fs.existsSync(dir)) return; 36 | 37 | try { 38 | fs.mkdirSync(dir); 39 | } catch (err) { 40 | if (err.code == "ENOENT") { 41 | makeNestedDir(path.dirname(dir)); //create parent dir 42 | makeNestedDir(dir); //create dir 43 | } 44 | } 45 | }; 46 | 47 | copyFilesWithDirStructure = (files, outputDir) => { 48 | for (file of files) { 49 | // strip off the src dir 50 | const finalPath = path.join(outputDir, file.replace(/src./, "")); 51 | 52 | // if it's in a nested dir, we need to create the full path to the file 53 | // before creating the file 54 | makeNestedDir(path.dirname(finalPath)); 55 | 56 | fs.copyFileSync(file, finalPath); 57 | console.log(`copied: ${file} -> ${finalPath}`); 58 | } 59 | }; 60 | 61 | const files = walk("./src", /.*\.d\.ts/); 62 | copyFilesWithDirStructure(files, "lib"); 63 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-codegen-core", 3 | "description": "Core generator APIs for Apollo Codegen", 4 | "version": "0.32.10", 5 | "author": "Apollo GraphQL ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 10 | }, 11 | "homepage": "https://github.com/apollographql/apollo-tooling", 12 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 13 | "main": "lib/index.js", 14 | "types": "lib/index.d.ts", 15 | "engines": { 16 | "node": ">=8", 17 | "npm": ">=6" 18 | }, 19 | "dependencies": { 20 | "@babel/generator": "7.4.0", 21 | "@babel/parser": "^7.1.3", 22 | "@babel/types": "7.4.0", 23 | "apollo-env": "file:../apollo-env", 24 | "apollo-language-server": "file:../apollo-language-server", 25 | "ast-types": "^0.12.0", 26 | "common-tags": "^1.5.1", 27 | "recast": "^0.17.0" 28 | }, 29 | "jest": { 30 | "preset": "ts-jest", 31 | "transformIgnorePatterns": [ 32 | "/node_modules/", 33 | "/apollo-env/" 34 | ], 35 | "testEnvironment": "node", 36 | "setupFiles": [ 37 | "/../apollo-env/lib/index.js" 38 | ], 39 | "setupFilesAfterEnv": [ 40 | "/test-utils/matchers.ts" 41 | ], 42 | "testMatch": [ 43 | "**/__tests__/*.(js|ts)" 44 | ], 45 | "testPathIgnorePatterns": [ 46 | "/node_modules/", 47 | "/lib/", 48 | "/test/fixtures/", 49 | "/test/test-utils" 50 | ], 51 | "moduleFileExtensions": [ 52 | "ts", 53 | "js" 54 | ], 55 | "globals": { 56 | "ts-jest": { 57 | "tsConfig": "/tsconfig.test.json", 58 | "diagnostics": false 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/statusBar.ts: -------------------------------------------------------------------------------- 1 | import { window, StatusBarAlignment } from "vscode"; 2 | 3 | interface LoadingInput { 4 | hasActiveTextEditor: boolean; 5 | } 6 | 7 | interface StateChangeInput extends LoadingInput { 8 | text: string; 9 | tooltip?: string; 10 | } 11 | 12 | export default class ApolloStatusBar { 13 | public statusBarItem = window.createStatusBarItem(StatusBarAlignment.Right); 14 | 15 | static loadingStateText = "Apollo GraphQL $(rss)"; 16 | static loadedStateText = "ApolloGraphQL $(rocket)"; 17 | static warningText = "Apollo GraphQL $(alert)"; 18 | 19 | constructor({ hasActiveTextEditor }: LoadingInput) { 20 | this.showLoadingState({ hasActiveTextEditor }); 21 | this.statusBarItem.command = "apollographql/showStats"; 22 | } 23 | 24 | protected changeState({ 25 | hasActiveTextEditor, 26 | text, 27 | tooltip 28 | }: StateChangeInput) { 29 | if (!hasActiveTextEditor) { 30 | this.statusBarItem.hide(); 31 | return; 32 | } 33 | 34 | this.statusBarItem.text = text; 35 | this.statusBarItem.tooltip = tooltip; 36 | this.statusBarItem.show(); 37 | } 38 | 39 | public showLoadingState({ hasActiveTextEditor }: LoadingInput) { 40 | this.changeState({ 41 | hasActiveTextEditor, 42 | text: ApolloStatusBar.loadingStateText 43 | }); 44 | } 45 | 46 | public showLoadedState({ hasActiveTextEditor }: LoadingInput) { 47 | this.changeState({ 48 | hasActiveTextEditor, 49 | text: ApolloStatusBar.loadedStateText 50 | }); 51 | } 52 | 53 | public showWarningState({ 54 | hasActiveTextEditor, 55 | tooltip 56 | }: LoadingInput & { tooltip: string }) { 57 | this.changeState({ 58 | hasActiveTextEditor, 59 | text: ApolloStatusBar.warningText, 60 | tooltip 61 | }); 62 | } 63 | 64 | public dispose() { 65 | this.statusBarItem.dispose(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Reporting a Bug 3 | about: Open a new issue here if something isn't working as expected. 4 | --- 5 | 6 | 13 | 14 | **Intended outcome:** 15 | 16 | 19 | 20 | **Actual outcome:** 21 | 22 | 25 | 26 | **How to reproduce the issue:** 27 | 28 | 33 | 34 | **Versions** 35 | 36 | 39 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/schema/providers/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLSchemaProvider, 3 | SchemaChangeUnsubscribeHandler, 4 | SchemaResolveConfig 5 | } from "./base"; 6 | import { 7 | ApolloConfig, 8 | isClientConfig, 9 | isServiceConfig, 10 | isLocalServiceConfig 11 | } from "../../config"; 12 | 13 | import { IntrospectionSchemaProvider } from "./introspection"; 14 | import { EngineSchemaProvider } from "./engine"; 15 | import { FileSchemaProvider } from "./file"; 16 | import { ClientIdentity } from "../../engine"; 17 | 18 | export { 19 | GraphQLSchemaProvider, 20 | SchemaChangeUnsubscribeHandler, 21 | SchemaResolveConfig 22 | }; 23 | 24 | export function schemaProviderFromConfig( 25 | config: ApolloConfig, 26 | clientIdentity?: ClientIdentity // engine provider needs this 27 | ): GraphQLSchemaProvider { 28 | if (isServiceConfig(config)) { 29 | if (config.service.localSchemaFile) { 30 | return new FileSchemaProvider({ path: config.service.localSchemaFile }); 31 | } 32 | 33 | if (config.service.endpoint) { 34 | return new IntrospectionSchemaProvider(config.service.endpoint); 35 | } 36 | } 37 | 38 | if (isClientConfig(config)) { 39 | if (typeof config.client.service === "string") { 40 | return new EngineSchemaProvider(config, clientIdentity); 41 | } 42 | 43 | if (config.client.service) { 44 | if (isLocalServiceConfig(config.client.service)) { 45 | return new FileSchemaProvider({ 46 | path: config.client.service.localSchemaFile 47 | }); 48 | } 49 | 50 | return new IntrospectionSchemaProvider(config.client.service); 51 | } 52 | } 53 | 54 | throw new Error( 55 | "No schema provider was created, because the project type was unable to be resolved from your config. Please add either a client or service config. For more information, please refer to https://bit.ly/2ByILPj" 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | // List of configurations. Add new configurations or edit existing ones. 4 | "configurations": [ 5 | { 6 | "name": "Launch VS Code Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "preLaunchTask": "npm: watch", 10 | "runtimeExecutable": "${execPath}", 11 | "args": [ 12 | "--extensionDevelopmentPath=${workspaceRoot}/packages/vscode-apollo" 13 | ], 14 | "stopOnEntry": false, 15 | "sourceMaps": true, 16 | "outFiles": ["${workspaceRoot}/packages/vscode-apollo/lib/**/*.js"] 17 | }, 18 | { 19 | "name": "Attach to TS Server", 20 | "type": "node", 21 | "request": "attach", 22 | "protocol": "inspector", 23 | "port": 6009, 24 | "sourceMaps": true 25 | }, 26 | { 27 | "name": "Extension Tests", 28 | "type": "extensionHost", 29 | "request": "launch", 30 | "runtimeExecutable": "${execPath}", 31 | "args": [ 32 | "--disable-extensions", 33 | "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-apollo", 34 | "--extensionTestsPath=${workspaceFolder}/packages/vscode-apollo/lib/testRunner" 35 | ], 36 | "outFiles": ["${workspaceFolder}/packages/vscode-apollo/lib/**/*.js"], 37 | "preLaunchTask": "npm: watch" 38 | }, 39 | { 40 | "name": "Attach to Test Debugger", 41 | "type": "node", 42 | "request": "attach", 43 | "protocol": "inspector", 44 | "port": 9001, 45 | "sourceMaps": true 46 | }, 47 | { 48 | "name": "Attach to CLI Debugger", 49 | "type": "node", 50 | "request": "attach", 51 | "protocol": "inspector", 52 | "port": 9002, 53 | "sourceMaps": true 54 | } 55 | ], 56 | "compounds": [ 57 | { 58 | "name": "Extension + Server", 59 | "configurations": ["Launch VS Code Extension", "Attach to TS Server"] 60 | } 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/errors/logger.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import path from "path"; 3 | 4 | // ToolError is used for errors that are part of the expected flow 5 | // and for which a stack trace should not be printed 6 | 7 | export class ToolError extends Error { 8 | name: string = "ToolError"; 9 | 10 | constructor(message: string) { 11 | super(message); 12 | this.message = message; 13 | } 14 | } 15 | 16 | const isRunningFromXcodeScript = process.env.XCODE_VERSION_ACTUAL; 17 | 18 | export function logError(error: Error) { 19 | if (error instanceof ToolError) { 20 | logErrorMessage(error.message); 21 | } else if (error instanceof GraphQLError) { 22 | const fileName = error.source && error.source.name; 23 | if (error.locations) { 24 | for (const location of error.locations) { 25 | logErrorMessage(error.message, fileName, location.line); 26 | } 27 | } else { 28 | logErrorMessage(error.message, fileName); 29 | } 30 | } else { 31 | console.error(error.stack); 32 | } 33 | } 34 | 35 | export function logErrorMessage( 36 | message: string, 37 | fileName?: string, 38 | lineNumber?: number 39 | ) { 40 | if (isRunningFromXcodeScript) { 41 | if (fileName && lineNumber) { 42 | // Prefixing error output with file name, line and 'error: ', 43 | // so Xcode will associate it with the right file and display the error inline 44 | console.error(`${fileName}:${lineNumber}: error: ${message}`); 45 | } else { 46 | // Prefixing error output with 'error: ', so Xcode will display it as an error 47 | console.error(`error: ${message}`); 48 | } 49 | } else { 50 | if (fileName) { 51 | const truncatedFileName = 52 | "/" + 53 | fileName 54 | .split(path.sep) 55 | .slice(-4) 56 | .join(path.sep); 57 | console.error(`...${truncatedFileName}: ${message}`); 58 | } else { 59 | console.error(`error: ${message}`); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/service/info.ts: -------------------------------------------------------------------------------- 1 | import { flags } from "@oclif/command"; 2 | import { table } from "heroku-cli-util"; 3 | import gql from "graphql-tag"; 4 | 5 | import { ProjectCommand } from "../../Command"; 6 | 7 | export default class ServiceDownload extends ProjectCommand { 8 | static description = "Download the info of your service from Engine"; 9 | static hidden = true; 10 | static flags = { 11 | ...ProjectCommand.flags, 12 | tag: flags.string({ 13 | char: "t", 14 | description: "The published tag of the schema", 15 | default: "current" 16 | }) 17 | }; 18 | 19 | async run() { 20 | const { results }: any = await this.runTasks(({ args, project, flags }) => [ 21 | { 22 | title: `Getting information about service`, 23 | task: async ctx => { 24 | if (!project.config.name) { 25 | throw new Error("A service name is required but wasn't found"); 26 | } 27 | 28 | const { data, errors } = await project.engine.schemaTagInfo({ 29 | tag: flags.tag, 30 | service: project.config.name 31 | }); 32 | 33 | if (errors) { 34 | throw new Error(errors.map(error => error.message).join("\n")); 35 | } 36 | 37 | if (!(data && data.service)) { 38 | throw new Error(`Error loading service information`); 39 | } 40 | 41 | ctx.results = data.service.schema; 42 | } 43 | } 44 | ]); 45 | const { hash, introspection, createdAt } = results; 46 | const { fieldCount, typeCount } = introspection; 47 | this.log("\n"); 48 | table([{ hash, types: typeCount, fields: fieldCount, createdAt }], { 49 | columns: [ 50 | { 51 | key: "hash", 52 | label: "id", 53 | format: (hash: string) => hash.slice(0, 6) 54 | }, 55 | { key: "types" }, 56 | { key: "fields" }, 57 | { key: "createdAt", label: "created date" } 58 | ] 59 | }); 60 | this.log("\n"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/schema/providers/file.ts: -------------------------------------------------------------------------------- 1 | // FileSchemaProvider (FileProvider (SDL || IntrospectionResult) => schema) 2 | import { GraphQLSchema, buildClientSchema, Source, buildSchema } from "graphql"; 3 | import { readFileSync } from "fs"; 4 | import { extname, resolve } from "path"; 5 | import { GraphQLSchemaProvider, SchemaChangeUnsubscribeHandler } from "./base"; 6 | import { NotificationHandler } from "vscode-languageserver"; 7 | 8 | export interface FileSchemaProviderConfig { 9 | path: string; 10 | } 11 | // XXX file subscription 12 | export class FileSchemaProvider implements GraphQLSchemaProvider { 13 | private schema?: GraphQLSchema; 14 | 15 | constructor(private config: FileSchemaProviderConfig) {} 16 | 17 | async resolveSchema() { 18 | if (this.schema) return this.schema; 19 | const { path } = this.config; 20 | let result; 21 | try { 22 | result = readFileSync(path, { 23 | encoding: "utf-8" 24 | }); 25 | } catch (err) { 26 | throw new Error(`Unable to read file ${path}. ${err.message}`); 27 | } 28 | 29 | const ext = extname(path); 30 | 31 | // an actual introspectionQuery result 32 | if (ext === ".json") { 33 | const parsed = JSON.parse(result); 34 | const __schema = parsed.data 35 | ? parsed.data.__schema 36 | : parsed.__schema 37 | ? parsed.__schema 38 | : parsed; 39 | 40 | this.schema = buildClientSchema({ __schema }); 41 | } else if (ext === ".graphql" || ext === ".graphqls" || ext === ".gql") { 42 | const uri = `file://${resolve(path)}`; 43 | this.schema = buildSchema(new Source(result, uri)); 44 | } 45 | if (!this.schema) throw new Error(`Schema could not be loaded for ${path}`); 46 | return this.schema; 47 | } 48 | 49 | onSchemaChange( 50 | _handler: NotificationHandler 51 | ): SchemaChangeUnsubscribeHandler { 52 | throw new Error("File watching not implemented yet"); 53 | return () => {}; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/schema/providers/introspection.ts: -------------------------------------------------------------------------------- 1 | // IntrospectionSchemaProvider (http => IntrospectionResult => schema) 2 | import { NotificationHandler } from "vscode-languageserver"; 3 | import { execute as linkExecute, toPromise } from "apollo-link"; 4 | import { createHttpLink, HttpLink } from "apollo-link-http"; 5 | import { 6 | GraphQLSchema, 7 | buildClientSchema, 8 | getIntrospectionQuery, 9 | ExecutionResult, 10 | IntrospectionQuery, 11 | parse 12 | } from "graphql"; 13 | import { Agent } from "http"; 14 | import { fetch } from "apollo-env"; 15 | import { RemoteServiceConfig } from "../../config"; 16 | import { GraphQLSchemaProvider, SchemaChangeUnsubscribeHandler } from "./base"; 17 | 18 | export class IntrospectionSchemaProvider implements GraphQLSchemaProvider { 19 | private schema?: GraphQLSchema; 20 | constructor(private config: Exclude) {} 21 | async resolveSchema() { 22 | if (this.schema) return this.schema; 23 | const { skipSSLValidation, url, headers } = this.config; 24 | const options: HttpLink.Options = { 25 | uri: url, 26 | fetch, 27 | ...(skipSSLValidation && { fetchOptions: { agent: new Agent() } }) 28 | }; 29 | 30 | const { data, errors } = (await toPromise( 31 | linkExecute(createHttpLink(options), { 32 | query: parse(getIntrospectionQuery()), 33 | context: { headers } 34 | }) 35 | )) as ExecutionResult; 36 | 37 | if (errors && errors.length) { 38 | // XXX better error handling of GraphQL errors 39 | throw new Error(errors.map(({ message }: Error) => message).join("\n")); 40 | } 41 | 42 | if (!data) { 43 | throw new Error("No data received from server introspection."); 44 | } 45 | 46 | this.schema = buildClientSchema(data); 47 | return this.schema; 48 | } 49 | onSchemaChange( 50 | _handler: NotificationHandler 51 | ): SchemaChangeUnsubscribeHandler { 52 | throw new Error("Polling of endpoint not implemented yet"); 53 | return () => {}; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/testRunner/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Wrapper around Jest's runCLI function. Responsible for passing in the config, 3 | * executing, and passing along failures. 4 | */ 5 | import { ResultsObject, runCLI } from "jest"; 6 | import { resolve } from "path"; 7 | import { config } from "./jest-config"; 8 | 9 | export async function run(_testRoot: string, callback: TestRunnerCallback) { 10 | const writeStreamRefs = forwardWriteStreams(); 11 | 12 | try { 13 | const testDirectory = resolve(__dirname, "..", "..", "src"); 14 | const { results } = await runCLI(config, [testDirectory]); 15 | 16 | restoreWriteStreams(writeStreamRefs); 17 | 18 | const failures = collectTestFailureMessages(results); 19 | 20 | if (failures.length > 0) { 21 | callback(null, failures); 22 | process.exit(1); 23 | } 24 | 25 | callback(null); 26 | } catch (e) { 27 | callback(e); 28 | process.exit(1); 29 | } 30 | } 31 | 32 | /** 33 | * Collect failure messages from Jest test results. 34 | * 35 | * @param results Jest test results. 36 | */ 37 | function collectTestFailureMessages(results: ResultsObject): string[] { 38 | const failures = results.testResults.reduce((acc, testResult) => { 39 | if (testResult.failureMessage) acc.push(testResult.failureMessage); 40 | return acc; 41 | }, []); 42 | 43 | return failures; 44 | } 45 | 46 | /** 47 | * Forward writes to process.stdout and process.stderr to console.log. 48 | * 49 | * For some reason this seems to be required for the Jest output to be streamed 50 | * to the Debug Console. 51 | */ 52 | function forwardWriteStreams() { 53 | const outRef = process.stdout.write; 54 | const errRef = process.stderr.write; 55 | 56 | process.stdout.write = logger; 57 | process.stderr.write = logger; 58 | 59 | return { outRef, errRef }; 60 | } 61 | 62 | function restoreWriteStreams(refs: { outRef: any; errRef: any }) { 63 | process.stdout.write = refs.outRef; 64 | process.stderr.write = refs.errRef; 65 | } 66 | 67 | function logger(line: string) { 68 | console.log(line); 69 | return true; 70 | } 71 | 72 | export type TestRunnerCallback = (error: Error | null, failures?: any) => void; 73 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/loadingHandler.ts: -------------------------------------------------------------------------------- 1 | import { IConnection, NotificationType } from "vscode-languageserver"; 2 | 3 | // XXX I think we want to combine this into an interface 4 | // with the errors tooling as well 5 | 6 | export interface LoadingHandler { 7 | handle(message: string, value: Promise): Promise; 8 | handleSync(message: string, value: () => T): T; 9 | showError(message: string): void; 10 | } 11 | 12 | export class LanguageServerLoadingHandler implements LoadingHandler { 13 | constructor(private connection: IConnection) {} 14 | private latestLoadingToken = 0; 15 | async handle(message: string, value: Promise): Promise { 16 | const token = this.latestLoadingToken; 17 | this.latestLoadingToken += 1; 18 | this.connection.sendNotification( 19 | new NotificationType("apollographql/loading"), 20 | { message, token } 21 | ); 22 | try { 23 | const ret = await value; 24 | this.connection.sendNotification( 25 | new NotificationType("apollographql/loadingComplete"), 26 | token 27 | ); 28 | return ret; 29 | } catch (e) { 30 | this.connection.sendNotification( 31 | new NotificationType("apollographql/loadingComplete"), 32 | token 33 | ); 34 | this.showError(`Error in "${message}": ${e}`); 35 | throw e; 36 | } 37 | } 38 | handleSync(message: string, value: () => T): T { 39 | const token = this.latestLoadingToken; 40 | this.latestLoadingToken += 1; 41 | this.connection.sendNotification( 42 | new NotificationType("apollographql/loading"), 43 | { message, token } 44 | ); 45 | try { 46 | const ret = value(); 47 | this.connection.sendNotification( 48 | new NotificationType("apollographql/loadingComplete"), 49 | token 50 | ); 51 | return ret; 52 | } catch (e) { 53 | this.connection.sendNotification( 54 | new NotificationType("apollographql/loadingComplete"), 55 | token 56 | ); 57 | this.showError(`Error in "${message}": ${e}`); 58 | throw e; 59 | } 60 | } 61 | showError(message: string) { 62 | this.connection.window.showErrorMessage(message); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/apollo-graphql/src/__tests__/__snapshots__/operationId.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`defaultEngineReportingSignature basic test 1`] = `"{user{name}}"`; 4 | 5 | exports[`defaultEngineReportingSignature basic test with query 1`] = `"{user{name}}"`; 6 | 7 | exports[`defaultEngineReportingSignature basic with operation name 1`] = `"query OpName{user{name}}"`; 8 | 9 | exports[`defaultEngineReportingSignature fragment 1`] = `"fragment Bar on User{asd}{user{name...Bar}}"`; 10 | 11 | exports[`defaultEngineReportingSignature fragments in various order 1`] = `"fragment Bar on User{asd}{user{name...Bar}}"`; 12 | 13 | exports[`defaultEngineReportingSignature full test 1`] = `"fragment Bar on User{age@skip(if:$a)...Nested}fragment Nested on User{blah}query Foo($a:Boolean,$b:Int){user(age:0,name:\\"\\"){name tz...Bar...on User{bee hello}}}"`; 14 | 15 | exports[`defaultEngineReportingSignature with various argument types 1`] = `"query OpName($a:[[Boolean!]!],$b:EnumType,$c:Int!){user{name(apple:$a,bag:$b,cat:$c)}}"`; 16 | 17 | exports[`defaultEngineReportingSignature with various inline types 1`] = `"query OpName{user{name(apple:[],bag:{},cat:ENUM_VALUE)}}"`; 18 | 19 | exports[`defaultOperationRegistrySignature basic test 1`] = `"{user{name}}"`; 20 | 21 | exports[`defaultOperationRegistrySignature basic test with query 1`] = `"{user{name}}"`; 22 | 23 | exports[`defaultOperationRegistrySignature basic with operation name 1`] = `"query OpName{user{name}}"`; 24 | 25 | exports[`defaultOperationRegistrySignature fragment 1`] = `"fragment Bar on User{asd}{user{name...Bar}}"`; 26 | 27 | exports[`defaultOperationRegistrySignature fragments in various order 1`] = `"fragment Bar on User{asd}{user{name...Bar}}"`; 28 | 29 | exports[`defaultOperationRegistrySignature full test 1`] = `"fragment Bar on User{age@skip(if:$a)...Nested}fragment Nested on User{blah}query Foo($a:Boolean,$b:Int){user(age:0,name:\\"\\"){aliased:name tz...Bar...on User{bee hello}}}"`; 30 | 31 | exports[`defaultOperationRegistrySignature with various argument types 1`] = `"query OpName($a:[[Boolean!]!],$b:EnumType,$c:Int!){user{name(apple:$a,bag:$b,cat:$c)}}"`; 32 | 33 | exports[`defaultOperationRegistrySignature with various inline types 1`] = `"query OpName{user{name(apple:[[0]],bag:{input:\\"\\"},cat:ENUM_VALUE)}}"`; 34 | -------------------------------------------------------------------------------- /packages/apollo-graphql/src/__tests__/transforms.test.ts: -------------------------------------------------------------------------------- 1 | import { default as gql, disableFragmentWarnings } from "graphql-tag"; 2 | 3 | import { printWithReducedWhitespace, hideLiterals } from "../transforms"; 4 | 5 | // The gql duplicate fragment warning feature really is just warnings; nothing 6 | // breaks if you turn it off in tests. 7 | disableFragmentWarnings(); 8 | 9 | describe("printWithReducedWhitespace", () => { 10 | const cases = [ 11 | { 12 | name: "lots of whitespace", 13 | // Note: there's a tab after "tab->", which prettier wants to keep as a 14 | // literal tab rather than \t. In the output, there should be a literal 15 | // backslash-t. 16 | input: gql` 17 | query Foo($a: Int) { 18 | user( 19 | name: " tab-> yay" 20 | other: """ 21 | apple 22 | bag 23 | cat 24 | """ 25 | ) { 26 | name 27 | } 28 | } 29 | `, 30 | output: 31 | 'query Foo($a:Int){user(name:" tab->\\tyay",other:"apple\\n bag\\ncat"){name}}' 32 | } 33 | ]; 34 | cases.forEach(({ name, input, output }) => { 35 | test(name, () => { 36 | expect(printWithReducedWhitespace(input)).toEqual(output); 37 | }); 38 | }); 39 | }); 40 | 41 | describe("hideLiterals", () => { 42 | const cases = [ 43 | { 44 | name: "full test", 45 | input: gql` 46 | query Foo($b: Int, $a: Boolean) { 47 | user(name: "hello", age: 5) { 48 | ...Bar 49 | ... on User { 50 | hello 51 | bee 52 | } 53 | tz 54 | aliased: name 55 | } 56 | } 57 | 58 | fragment Bar on User { 59 | age @skip(if: $a) 60 | ...Nested 61 | } 62 | 63 | fragment Nested on User { 64 | blah 65 | } 66 | `, 67 | output: 68 | 'query Foo($b:Int,$a:Boolean){user(name:"",age:0){...Bar...on User{hello bee}tz aliased:name}}' + 69 | "fragment Bar on User{age@skip(if:$a)...Nested}fragment Nested on User{blah}" 70 | } 71 | ]; 72 | cases.forEach(({ name, input, output }) => { 73 | test(name, () => { 74 | expect(printWithReducedWhitespace(hideLiterals(input))).toEqual(output); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/service/push.ts: -------------------------------------------------------------------------------- 1 | import { flags } from "@oclif/command"; 2 | import { table } from "heroku-cli-util"; 3 | import { introspectionFromSchema } from "graphql"; 4 | 5 | import { gitInfo } from "../../git"; 6 | import { ProjectCommand } from "../../Command"; 7 | 8 | export default class ServicePush extends ProjectCommand { 9 | static aliases = ["schema:publish"]; 10 | static description = "Push a service to Engine"; 11 | static flags = { 12 | ...ProjectCommand.flags, 13 | tag: flags.string({ 14 | char: "t", 15 | description: "The tag to publish this service to", 16 | default: "current" 17 | }), 18 | localSchemaFile: flags.string({ 19 | description: 20 | "Path to your local GraphQL schema file (introspection result or SDL)" 21 | }) 22 | }; 23 | 24 | async run() { 25 | let result; 26 | let gitContext; 27 | await this.runTasks(({ flags, project, config }) => [ 28 | { 29 | title: "Uploading service to Engine", 30 | task: async () => { 31 | if (!config.name) { 32 | throw new Error("No service found to link to Engine"); 33 | } 34 | 35 | const schema = await project.resolveSchema({ tag: flags.tag }); 36 | gitContext = await gitInfo(this.log); 37 | 38 | const { tag, code } = await project.engine.uploadSchema({ 39 | id: config.name, 40 | // @ts-ignore 41 | // XXX Looks like TS should be generating ReadonlyArrays instead 42 | schema: introspectionFromSchema(schema).__schema, 43 | tag: flags.tag, 44 | gitContext 45 | }); 46 | 47 | result = { 48 | service: config.name, 49 | hash: tag.schema.hash, 50 | tag: tag.tag, 51 | code 52 | }; 53 | } 54 | } 55 | ]); 56 | 57 | this.log("\n"); 58 | if (result.code === "NO_CHANGES") { 59 | this.log("No change in schema from previous version\n"); 60 | } 61 | table([result], { 62 | columns: [ 63 | { 64 | key: "hash", 65 | label: "id", 66 | format: (hash: string) => hash.slice(0, 6) 67 | }, 68 | { key: "service", label: "schema" }, 69 | { key: "tag" } 70 | ] 71 | }); 72 | this.log("\n"); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /packages/apollo/src/utils/validateHistoricParams.ts: -------------------------------------------------------------------------------- 1 | import { duration } from "moment"; 2 | import { graphqlTypes } from "apollo-language-server"; 3 | 4 | export function validateHistoricParams({ 5 | validationPeriod, 6 | queryCountThreshold, 7 | queryCountThresholdPercentage 8 | }: Partial<{ 9 | validationPeriod: string; 10 | queryCountThreshold: number; 11 | queryCountThresholdPercentage: number; 12 | }>): Partial | null { 13 | if ( 14 | !validationPeriod && 15 | !queryCountThreshold && 16 | !queryCountThresholdPercentage 17 | ) { 18 | return null; 19 | } 20 | 21 | let from: number | null = null; 22 | if (validationPeriod) { 23 | // Validation period can be one of two things: 24 | // 1) a number in seconds 25 | // 2) an ISO 8601 formatted duration, i.e. "P1D", "P10DT1H", "PT6H" 26 | from = isNumeric(validationPeriod) 27 | ? -1 * duration(Number(validationPeriod), "seconds").asSeconds() 28 | : -1 * duration(validationPeriod).asSeconds(); 29 | 30 | if (from >= 0) { 31 | throw new Error( 32 | "Please provide a valid duration for the --validationPeriod flag. Valid durations are represented in ISO 8601, see: https://bit.ly/2DEJ3UN." 33 | ); 34 | } 35 | } 36 | 37 | if ( 38 | queryCountThreshold && 39 | (!Number.isInteger(queryCountThreshold) || queryCountThreshold < 1) 40 | ) { 41 | throw new Error( 42 | "Please provide a valid number for the --queryCountThreshold flag. Valid numbers are integers in the range x >= 1." 43 | ); 44 | } 45 | 46 | let asPercentage: number | null = null; 47 | if (queryCountThresholdPercentage) { 48 | if ( 49 | queryCountThresholdPercentage < 0 || 50 | queryCountThresholdPercentage > 100 51 | ) { 52 | throw new Error( 53 | "Please provide a valid number for the --queryCountThresholdPercentage flag. Valid numbers are in the range 0 <= x <= 100." 54 | ); 55 | } 56 | asPercentage = queryCountThresholdPercentage / 100; 57 | } 58 | 59 | return { 60 | ...(from && { to: -0, from }), 61 | ...(queryCountThreshold && { queryCountThreshold }), 62 | ...(asPercentage && { queryCountThresholdPercentage: asPercentage }) 63 | }; 64 | } 65 | 66 | function isNumeric(maybeNumber: string) { 67 | return !Number.isNaN(Number(maybeNumber)); 68 | } 69 | -------------------------------------------------------------------------------- /packages/apollo/__mocks__/apollo-cli-test.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import Nock from "@fancy-test/nock"; 4 | import * as Test from "@oclif/test"; 5 | export { expect } from "@oclif/test"; 6 | import { mockConsole } from "heroku-cli-util"; 7 | 8 | const time = label => { 9 | let start = +new Date(); 10 | 11 | return { 12 | async run() {}, 13 | finally() { 14 | console.log(`${label || "TIME"}:`, +new Date() - start, "ms"); 15 | } 16 | }; 17 | }; 18 | 19 | const debug = fn => { 20 | return { 21 | async run() { 22 | fn(); 23 | }, 24 | finally() {} 25 | }; 26 | }; 27 | 28 | const deleteFolderRecursive = path => { 29 | // don't relete files on azure CI 30 | if (process.env.AZURE_HTTP_USER_AGENT) return; 31 | 32 | if (fs.existsSync(path)) { 33 | fs.readdirSync(path).forEach(function(file, index) { 34 | var curPath = path + "/" + file; 35 | if (fs.lstatSync(curPath).isDirectory()) { 36 | // recurse 37 | deleteFolderRecursive(curPath); 38 | } else { 39 | // delete file 40 | fs.unlinkSync(curPath); 41 | } 42 | }); 43 | fs.rmdirSync(path); 44 | } 45 | }; 46 | 47 | const makeNestedDir = dir => { 48 | if (fs.existsSync(dir)) return; 49 | 50 | try { 51 | fs.mkdirSync(dir); 52 | } catch (err) { 53 | if (err.code == "ENOENT") { 54 | makeNestedDir(path.dirname(dir)); //create parent dir 55 | makeNestedDir(dir); //create dir 56 | } 57 | } 58 | }; 59 | 60 | const setupFS = (files: Record) => { 61 | let dir; 62 | return { 63 | async run(ctx: any, ...rest) { 64 | // make a random remp dir & chdir into it 65 | dir = fs.mkdtempSync("__tmp__"); 66 | process.chdir(dir); 67 | // fill the dir with `files` 68 | Object.keys(files).forEach(key => { 69 | if (key.includes("/")) makeNestedDir(path.dirname(key)); 70 | fs.writeFileSync(key, files[key]); 71 | }); 72 | }, 73 | finally(ctx: any) { 74 | process.chdir("../"); 75 | deleteFolderRecursive(dir); 76 | } 77 | }; 78 | }; 79 | 80 | export const test = Test.test 81 | .register("nock", Nock) 82 | .register("fs", setupFS) 83 | .register("timing", time) 84 | .register("debug", debug); 85 | 86 | // it would be great to have an .expectStdout(out => expection) 87 | 88 | mockConsole(); 89 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/serializeToJSON.ts: -------------------------------------------------------------------------------- 1 | import { 2 | isType, 3 | GraphQLType, 4 | GraphQLScalarType, 5 | GraphQLEnumType, 6 | GraphQLInputObjectType 7 | } from "graphql"; 8 | 9 | import { LegacyCompilerContext } from "./compiler/legacyIR"; 10 | 11 | export default function serializeToJSON(context: LegacyCompilerContext) { 12 | return serializeAST( 13 | { 14 | operations: Object.values(context.operations), 15 | fragments: Object.values(context.fragments), 16 | typesUsed: context.typesUsed.map(serializeType) 17 | }, 18 | "\t" 19 | ); 20 | } 21 | 22 | export function serializeAST(ast: any, space?: string) { 23 | return JSON.stringify( 24 | ast, 25 | function(_, value) { 26 | if (isType(value)) { 27 | return String(value); 28 | } else { 29 | return value; 30 | } 31 | }, 32 | space 33 | ); 34 | } 35 | 36 | function serializeType(type: GraphQLType) { 37 | if (type instanceof GraphQLEnumType) { 38 | return serializeEnumType(type); 39 | } else if (type instanceof GraphQLInputObjectType) { 40 | return serializeInputObjectType(type); 41 | } else if (type instanceof GraphQLScalarType) { 42 | return serializeScalarType(type); 43 | } else { 44 | throw new Error(`Unexpected GraphQL type: ${type}`); 45 | } 46 | } 47 | 48 | function serializeEnumType(type: GraphQLEnumType) { 49 | const { name, description } = type; 50 | const values = type.getValues(); 51 | 52 | return { 53 | kind: "EnumType", 54 | name, 55 | description, 56 | values: values.map(value => ({ 57 | name: value.name, 58 | description: value.description, 59 | isDeprecated: value.isDeprecated, 60 | deprecationReason: value.deprecationReason 61 | })) 62 | }; 63 | } 64 | 65 | function serializeInputObjectType(type: GraphQLInputObjectType) { 66 | const { name, description } = type; 67 | const fields = Object.values(type.getFields()); 68 | 69 | return { 70 | kind: "InputObjectType", 71 | name, 72 | description, 73 | fields: fields.map(field => ({ 74 | name: field.name, 75 | type: String(field.type), 76 | description: field.description, 77 | defaultValue: field.defaultValue 78 | })) 79 | }; 80 | } 81 | 82 | function serializeScalarType(type: GraphQLScalarType) { 83 | const { name, description } = type; 84 | 85 | return { 86 | kind: "ScalarType", 87 | name, 88 | description 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /packages/apollo-codegen-typescript/src/helpers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLBoolean, 3 | GraphQLFloat, 4 | GraphQLInt, 5 | GraphQLID, 6 | GraphQLScalarType, 7 | GraphQLString, 8 | GraphQLType, 9 | isListType, 10 | isNonNullType 11 | } from "graphql"; 12 | 13 | import * as t from "@babel/types"; 14 | 15 | import { CompilerOptions } from "apollo-codegen-core/lib/compiler"; 16 | 17 | const builtInScalarMap = { 18 | [GraphQLString.name]: t.TSStringKeyword(), 19 | [GraphQLInt.name]: t.TSNumberKeyword(), 20 | [GraphQLFloat.name]: t.TSNumberKeyword(), 21 | [GraphQLBoolean.name]: t.TSBooleanKeyword(), 22 | [GraphQLID.name]: t.TSStringKeyword() 23 | }; 24 | 25 | export function createTypeFromGraphQLTypeFunction( 26 | compilerOptions: CompilerOptions 27 | ): (graphQLType: GraphQLType, typeName?: string) => t.TSType { 28 | function nonNullableTypeFromGraphQLType( 29 | graphQLType: GraphQLType, 30 | typeName?: string 31 | ): t.TSType { 32 | if (isListType(graphQLType)) { 33 | const elementType = typeFromGraphQLType(graphQLType.ofType, typeName); 34 | return t.TSArrayType( 35 | t.isTSUnionType(elementType) 36 | ? t.TSParenthesizedType(elementType) 37 | : elementType 38 | ); 39 | } else if (graphQLType instanceof GraphQLScalarType) { 40 | const builtIn = builtInScalarMap[typeName || graphQLType.name]; 41 | if (builtIn != null) { 42 | return builtIn; 43 | } else if (compilerOptions.passthroughCustomScalars) { 44 | return t.TSTypeReference( 45 | t.identifier( 46 | (compilerOptions.customScalarsPrefix || "") + graphQLType.name 47 | ) 48 | ); 49 | } else { 50 | return t.TSAnyKeyword(); 51 | } 52 | } else if (isNonNullType(graphQLType)) { 53 | // This won't happen; but for TypeScript completeness: 54 | return typeFromGraphQLType(graphQLType.ofType, typeName); 55 | } else { 56 | return t.TSTypeReference(t.identifier(typeName || graphQLType.name)); 57 | } 58 | } 59 | 60 | function typeFromGraphQLType( 61 | graphQLType: GraphQLType, 62 | typeName?: string 63 | ): t.TSType { 64 | if (isNonNullType(graphQLType)) { 65 | return nonNullableTypeFromGraphQLType(graphQLType.ofType, typeName); 66 | } else { 67 | const type = nonNullableTypeFromGraphQLType(graphQLType, typeName); 68 | return t.TSUnionType([type, t.TSNullKeyword()]); 69 | } 70 | } 71 | 72 | return typeFromGraphQLType; 73 | } 74 | -------------------------------------------------------------------------------- /packages/apollo-language-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-language-server", 3 | "description": "A language server for Apollo GraphQL projects", 4 | "version": "1.5.4", 5 | "author": "Apollo GraphQL ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 10 | }, 11 | "homepage": "https://github.com/apollographql/apollo-tooling", 12 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 13 | "main": "lib/index.js", 14 | "types": "lib/index.d.ts", 15 | "engines": { 16 | "node": ">=8", 17 | "npm": ">=6" 18 | }, 19 | "dependencies": { 20 | "@apollographql/apollo-tools": "file:../apollo-tools", 21 | "@apollographql/graphql-language-service-interface": "^2.0.2", 22 | "@endemolshinegroup/cosmiconfig-typescript-loader": "^1.0.0", 23 | "apollo-datasource": "^0.3.0", 24 | "apollo-env": "file:../apollo-env", 25 | "apollo-link": "^1.2.3", 26 | "apollo-link-context": "^1.0.9", 27 | "apollo-link-error": "^1.1.1", 28 | "apollo-link-http": "^1.5.5", 29 | "apollo-link-ws": "^1.0.9", 30 | "apollo-server-errors": "^2.0.2", 31 | "await-to-js": "^2.0.1", 32 | "core-js": "3.0.0-beta.13", 33 | "cosmiconfig": "^5.0.6", 34 | "dotenv": "^7.0.0", 35 | "glob": "^7.1.3", 36 | "graphql": "^14.0.2", 37 | "graphql-tag": "^2.10.1", 38 | "lodash": "^4.17.11", 39 | "minimatch": "^3.0.4", 40 | "minimist": "^1.2.0", 41 | "moment": "^2.22.2", 42 | "recursive-readdir": "^2.2.2", 43 | "subscriptions-transport-ws": "^0.9.15", 44 | "vscode-languageserver": "^5.1.0", 45 | "vscode-uri": "^1.0.6", 46 | "ws": "^6.1.0" 47 | }, 48 | "jest": { 49 | "preset": "ts-jest", 50 | "transformIgnorePatterns": [ 51 | "/node_modules/", 52 | "/apollo-env/" 53 | ], 54 | "testEnvironment": "node", 55 | "testMatch": [ 56 | "**/__tests__/*.(js|ts)" 57 | ], 58 | "setupFiles": [ 59 | "/../apollo-env/lib/index.js" 60 | ], 61 | "testPathIgnorePatterns": [ 62 | "/node_modules/", 63 | "/lib/", 64 | "/test/fixtures/", 65 | "/test/test-utils" 66 | ], 67 | "moduleFileExtensions": [ 68 | "ts", 69 | "js" 70 | ], 71 | "globals": { 72 | "ts-jest": { 73 | "tsConfig": "/tsconfig.test.json", 74 | "diagnostics": false 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/service/__tests__/download.test.ts: -------------------------------------------------------------------------------- 1 | it("is turned on after summit", () => {}); 2 | 3 | // jest.mock("apollo-codegen-core/lib/localfs", () => { 4 | // return require("../../../__mocks__/localfs"); 5 | // }); 6 | 7 | // // this is because of herkou-cli-utils hacky mocking system on their console logger 8 | // import { stdout, mockConsole } from "heroku-cli-util"; 9 | // import path from "path"; 10 | // import fs from "fs"; 11 | // import { test as setup } from "apollo-cli-test"; 12 | // import { introspectionQuery, print, execute, buildSchema } from "graphql"; 13 | // import gql from "graphql-tag"; 14 | // import { fs as mockFS, vol } from "apollo-codegen-core/lib/localfs"; 15 | 16 | // const test = setup.do(() => mockConsole()); 17 | // const fullSchema = execute( 18 | // buildSchema( 19 | // fs.readFileSync(path.resolve(__dirname, "./fixtures/schema.graphql"), { 20 | // encoding: "utf-8" 21 | // }) 22 | // ), 23 | // gql(introspectionQuery) 24 | // ).data; 25 | 26 | // const localSuccess = nock => { 27 | // nock 28 | // .post("/graphql", { 29 | // query: print(gql(introspectionQuery)), 30 | // operationName: "IntrospectionQuery", 31 | // variables: {} 32 | // }) 33 | // .reply(200, { data: fullSchema }); 34 | // }; 35 | 36 | // beforeEach(() => { 37 | // vol.reset(); 38 | // vol.fromJSON({ 39 | // __blankFileSoDirectoryExists: "" 40 | // }); 41 | // }); 42 | 43 | // jest.setTimeout(25000); 44 | 45 | // describe("successful schema downloading", () => { 46 | // test 47 | // .nock("http://localhost:4000", localSuccess) 48 | // .command(["service:download", "--endpoint=http://localhost:4000/graphql"]) 49 | // .it("grabs schema JSON from local server", () => { 50 | // expect(mockFS.readFileSync("schema.json").toString()).toMatchSnapshot(); 51 | // }); 52 | 53 | // test 54 | // .do(() => 55 | // vol.fromJSON({ 56 | // "package.json": ` 57 | // { 58 | // "apollo": { 59 | // "schemas": { 60 | // "localServer": { 61 | // "endpoint": "http://localhost:1234/graphql" 62 | // } 63 | // } 64 | // } 65 | // } 66 | // ` 67 | // }) 68 | // ) 69 | // .nock("http://localhost:1234", localSuccess) 70 | // .command(["service:download"]) 71 | // .it("grabs schema JSON from local server specified in config", () => { 72 | // expect(mockFS.readFileSync("schema.json").toString()).toMatchSnapshot(); 73 | // }); 74 | // }); 75 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/__tests__/valueFromValueNode.ts: -------------------------------------------------------------------------------- 1 | import { parseValue } from "graphql"; 2 | 3 | import { valueFromValueNode } from "../utilities/graphql"; 4 | 5 | describe("#valueFromValueNode", () => { 6 | test(`should return a number for an IntValue`, () => { 7 | const valueNode = parseValue("1"); 8 | const value = valueFromValueNode(valueNode); 9 | 10 | expect(value).toBe(1); 11 | }); 12 | 13 | test(`should return a number for a FloatValue`, () => { 14 | const valueNode = parseValue("1.0"); 15 | const value = valueFromValueNode(valueNode); 16 | 17 | expect(value).toBe(1.0); 18 | }); 19 | 20 | test(`should return a boolean for a BooleanValue`, () => { 21 | const valueNode = parseValue("true"); 22 | const value = valueFromValueNode(valueNode); 23 | 24 | expect(value).toBe(true); 25 | }); 26 | 27 | test(`should return null for a NullValue`, () => { 28 | const valueNode = parseValue("null"); 29 | const value = valueFromValueNode(valueNode); 30 | 31 | expect(value).toBe(null); 32 | }); 33 | 34 | test(`should return a string for a StringValue`, () => { 35 | const valueNode = parseValue('"foo"'); 36 | const value = valueFromValueNode(valueNode); 37 | 38 | expect(value).toBe("foo"); 39 | }); 40 | 41 | test(`should return a string for an EnumValue`, () => { 42 | const valueNode = parseValue("JEDI"); 43 | const value = valueFromValueNode(valueNode); 44 | 45 | expect(value).toBe("JEDI"); 46 | }); 47 | 48 | test(`should return an object for a Variable`, () => { 49 | const valueNode = parseValue("$something"); 50 | const value = valueFromValueNode(valueNode); 51 | 52 | expect(value).toEqual({ kind: "Variable", variableName: "something" }); 53 | }); 54 | 55 | test(`should return an array for a ListValue`, () => { 56 | const valueNode = parseValue('[ "foo", 1, JEDI, $something ]'); 57 | const value = valueFromValueNode(valueNode); 58 | 59 | expect(value).toEqual([ 60 | "foo", 61 | 1, 62 | "JEDI", 63 | { kind: "Variable", variableName: "something" } 64 | ]); 65 | }); 66 | 67 | test(`should return an object for an ObjectValue`, () => { 68 | const valueNode = parseValue( 69 | '{ foo: "foo", bar: 1, bla: JEDI, baz: $something }' 70 | ); 71 | const value = valueFromValueNode(valueNode); 72 | 73 | expect(value).toEqual({ 74 | foo: "foo", 75 | bar: 1, 76 | bla: "JEDI", 77 | baz: { kind: "Variable", variableName: "something" } 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/utilities/__tests__/graphql.test.ts: -------------------------------------------------------------------------------- 1 | import { parse, print } from "graphql"; 2 | import { 3 | withTypenameFieldAddedWhereNeeded, 4 | removeConnectionDirectives, 5 | removeClientDirectives 6 | } from "../graphql"; 7 | 8 | describe("typename additions", () => { 9 | it("adds typenames to selectionSets", () => { 10 | const original = parse(` 11 | query GetUser { 12 | me { 13 | firstName 14 | friends { 15 | firstName 16 | } 17 | } 18 | } 19 | `); 20 | 21 | const modified = print( 22 | parse(` 23 | query GetUser { 24 | me { 25 | __typename 26 | firstName 27 | friends { 28 | __typename 29 | firstName 30 | } 31 | } 32 | } 33 | `) 34 | ); 35 | 36 | const newQuery = withTypenameFieldAddedWhereNeeded(original); 37 | expect(print(newQuery)).toEqual(modified); 38 | }); 39 | }); 40 | 41 | describe("client removals", () => { 42 | it("removes the @connection directive", () => { 43 | const original = parse(` 44 | query GetUser { 45 | list @connection(key: "Value") 46 | } 47 | `); 48 | 49 | const modified = print( 50 | parse(` 51 | query GetUser { 52 | list 53 | } 54 | `) 55 | ); 56 | 57 | const newQuery = removeConnectionDirectives(original); 58 | expect(print(newQuery)).toEqual(modified); 59 | }); 60 | it("removes @client id from a mixed query", () => { 61 | const original = parse(` 62 | query GetUser { 63 | list @client 64 | remote { 65 | id 66 | virtual @client 67 | virtualSelectionSet @client @export(as: "id") { 68 | name 69 | } 70 | } 71 | } 72 | `); 73 | 74 | const modified = print( 75 | parse(` 76 | query GetUser { 77 | remote { 78 | id 79 | } 80 | } 81 | `) 82 | ); 83 | 84 | const newQuery = removeClientDirectives(original); 85 | expect(print(newQuery)).toEqual(modified); 86 | }); 87 | it("returns and empty string when removing all fields", () => { 88 | const original = parse(` 89 | query GetUser { 90 | list @client 91 | local @client { 92 | id 93 | } 94 | } 95 | `); 96 | 97 | const newQuery = removeClientDirectives(original); 98 | expect(print(newQuery).trim()).toBeFalsy(); 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /packages/apollo-codegen-typescript/src/printer.ts: -------------------------------------------------------------------------------- 1 | import * as t from "@babel/types"; 2 | import generate from "@babel/generator"; 3 | 4 | type Printable = t.Node | string; 5 | 6 | export default class Printer { 7 | private printQueue: Printable[] = []; 8 | 9 | public print(): string { 10 | return ( 11 | this.printQueue.reduce((document: string, printable) => { 12 | if (typeof printable === "string") { 13 | return document + printable; 14 | } else { 15 | const documentPart = generate(printable).code; 16 | return document + this.indentComments(documentPart); 17 | } 18 | }, "") + "\n" 19 | ); 20 | } 21 | 22 | public enqueue(printable: Printable) { 23 | if (this.printQueue.length > 0) { 24 | this.printQueue.push("\n"); 25 | this.printQueue.push("\n"); 26 | } 27 | this.printQueue.push(printable); 28 | } 29 | 30 | public printAndClear() { 31 | const output = this.print(); 32 | this.printQueue = []; 33 | return output; 34 | } 35 | 36 | private indentComments(documentPart: string) { 37 | const lines = documentPart.split("\n").filter(Boolean); // filter out lines that have no content 38 | 39 | let currentLine = 0; 40 | const newDocumentParts = []; 41 | // Keep track of what column comments should start on 42 | // to keep things aligned 43 | let maxCommentColumn = 0; 44 | 45 | while (currentLine !== lines.length) { 46 | const currentLineContents = lines[currentLine]; 47 | const commentColumn = currentLineContents.indexOf("//"); 48 | if (commentColumn > 0) { 49 | if (maxCommentColumn < commentColumn) { 50 | maxCommentColumn = commentColumn; 51 | } 52 | 53 | const [contents, comment] = currentLineContents.split("//"); 54 | newDocumentParts.push({ 55 | main: contents.replace(/\s+$/g, ""), 56 | comment: comment ? comment.trim() : null 57 | }); 58 | } else { 59 | newDocumentParts.push({ 60 | main: currentLineContents, 61 | comment: null 62 | }); 63 | } 64 | 65 | currentLine++; 66 | } 67 | 68 | return newDocumentParts 69 | .reduce((memo: string[], part) => { 70 | const { main, comment } = part; 71 | 72 | let line; 73 | if (comment !== null) { 74 | const spacesBetween = maxCommentColumn - main.length; 75 | line = `${main}${" ".repeat(spacesBetween)} // ${comment.trim()}`; 76 | } else { 77 | line = main; 78 | } 79 | 80 | return [...memo, line]; 81 | }, []) 82 | .join("\n"); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/fileSet.ts: -------------------------------------------------------------------------------- 1 | import { relative } from "path"; 2 | import minimatch = require("minimatch"); 3 | import glob from "glob"; 4 | import { invariant } from "@apollographql/apollo-tools"; 5 | import URI from "vscode-uri"; 6 | 7 | export class FileSet { 8 | private rootURI: URI; 9 | private includes: string[]; 10 | private excludes: string[]; 11 | 12 | constructor({ 13 | rootURI, 14 | includes, 15 | excludes, 16 | configURI 17 | }: { 18 | rootURI: URI; 19 | includes: string[]; 20 | excludes: string[]; 21 | configURI?: URI; 22 | }) { 23 | invariant(rootURI, `Must provide "rootURI".`); 24 | invariant(includes, `Must provide "includes".`); 25 | invariant(excludes, `Must provide "excludes".`); 26 | 27 | this.rootURI = rootURI; 28 | this.includes = includes; 29 | this.excludes = excludes; 30 | 31 | /** 32 | * This function is used in the Array.filter function below it to remove any .env files and config files. 33 | * If there are 0 files remaining after removing those files, we should warn the user that their config 34 | * may be wrong. We shouldn't throw an error here, since they could just be initially setting up a project 35 | * and there's no way to know for sure that there _should_ be files. 36 | */ 37 | const filterConfigAndEnvFiles = (path: string) => 38 | !( 39 | path.includes("apollo.config") || 40 | path.includes(".env") || 41 | (configURI && path === configURI.fsPath) 42 | ); 43 | if (this.allFiles().filter(filterConfigAndEnvFiles).length === 0) { 44 | console.warn( 45 | "⚠️ It looks like there are 0 files associated with this Apollo Project. " + 46 | "This may be because you don't have any files yet, or your includes/excludes " + 47 | "fields are configured incorrectly, and Apollo can't find your files. " + 48 | "For help configuring Apollo projects, see this guide: https://bit.ly/2ByILPj" 49 | ); 50 | } 51 | } 52 | 53 | includesFile(filePath: string): boolean { 54 | return this.allFiles().includes(filePath); 55 | } 56 | 57 | allFiles(): string[] { 58 | // since glob.sync takes a single pattern, but we allow an array of `includes`, we can join all the 59 | // `includes` globs into a single pattern and pass to glob.sync. The `ignore` option does, however, allow 60 | // an array of globs to ignore, so we can pass it in directly 61 | const joinedIncludes = `{${this.includes.join(",")}}`; 62 | return glob.sync(joinedIncludes, { 63 | cwd: this.rootURI.fsPath, 64 | absolute: true, 65 | ignore: this.excludes 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/apollo/src/utils/__tests__/validateHistoricParams.test.ts: -------------------------------------------------------------------------------- 1 | import { validateHistoricParams } from ".."; 2 | 3 | describe("validateHistoricParams", () => { 4 | it("generates valid params with valid input", () => { 5 | // Providing a number in seconds 6 | expect(getValidParams("86400")).toEqual({ 7 | to: -0, 8 | from: -86400, 9 | queryCountThreshold: 1, 10 | queryCountThresholdPercentage: 0.5 11 | }); 12 | 13 | // Providing an ISO 8601 formatted duration 14 | expect(getValidParams("P1D")).toEqual({ 15 | to: -0, 16 | from: -86400, 17 | queryCountThreshold: 1, 18 | queryCountThresholdPercentage: 0.5 19 | }); 20 | }); 21 | 22 | it("throws an error with invalid input", () => { 23 | // Period must be > 0 24 | expect(() => 25 | validateHistoricParams({ 26 | validationPeriod: "0", 27 | queryCountThreshold: 1, 28 | queryCountThresholdPercentage: 50 29 | }) 30 | ).toThrow(/--validationPeriod/); 31 | 32 | // Count threshold must be an integer >= 1 33 | expect(() => 34 | validateHistoricParams({ 35 | validationPeriod: "P1D", 36 | queryCountThreshold: 0.5, 37 | queryCountThresholdPercentage: 50 38 | }) 39 | ).toThrow(/--queryCountThreshold/); 40 | 41 | // Count threshold percentage must be an integer 0 <= x <= 100 42 | expect(() => 43 | validateHistoricParams({ 44 | validationPeriod: "P1D", 45 | queryCountThreshold: 1, 46 | queryCountThresholdPercentage: 101 47 | }) 48 | ).toThrow(/--queryCountThresholdPercentage/); 49 | }); 50 | 51 | it("handles partial input", () => { 52 | expect(validateHistoricParams({})).toEqual(null); 53 | 54 | expect( 55 | validateHistoricParams({ 56 | validationPeriod: "P1D" 57 | }) 58 | ).toEqual({ to: -0, from: -86400 }); 59 | 60 | expect( 61 | validateHistoricParams({ 62 | queryCountThreshold: 1 63 | }) 64 | ).toEqual({ queryCountThreshold: 1 }); 65 | 66 | expect( 67 | validateHistoricParams({ 68 | queryCountThresholdPercentage: 50 69 | }) 70 | ).toEqual({ queryCountThresholdPercentage: 0.5 }); 71 | 72 | expect( 73 | validateHistoricParams({ 74 | validationPeriod: "P1D", 75 | queryCountThresholdPercentage: 50 76 | }) 77 | ).toEqual({ to: -0, from: -86400, queryCountThresholdPercentage: 0.5 }); 78 | }); 79 | }); 80 | 81 | function getValidParams(validationPeriod: string) { 82 | return validateHistoricParams({ 83 | validationPeriod, 84 | queryCountThreshold: 1, 85 | queryCountThresholdPercentage: 50 86 | }); 87 | } 88 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/__tests__/diagnostics.ts: -------------------------------------------------------------------------------- 1 | import { Source } from "graphql"; 2 | import { loadSchema } from "apollo-codegen-core/lib/loading"; 3 | import { GraphQLDocument } from "../document"; 4 | import { collectExecutableDefinitionDiagnositics } from "../diagnostics"; 5 | const schema = loadSchema( 6 | require.resolve("../../../../__fixtures__/starwars/schema.json") 7 | ); 8 | const validDocument = new GraphQLDocument( 9 | new Source(` 10 | query HeroAndFriendsNames { 11 | hero { 12 | name 13 | friends { 14 | name 15 | } 16 | } 17 | }`) 18 | ); 19 | const invalidDocument = new GraphQLDocument( 20 | new Source(` 21 | query HeroAndFriendsNames { 22 | hero { 23 | nam # Missing letter 'e' 24 | friend { # Missing letter 's' 25 | name 26 | } 27 | } 28 | }`) 29 | ); 30 | const documentWithTypes = new GraphQLDocument( 31 | new Source(` 32 | type SomeType { 33 | thing: String 34 | } 35 | enum SomeEnum { 36 | THING_ONE 37 | THING_TWO 38 | } 39 | query HeroAndFriendsNames { 40 | hero { 41 | name 42 | friends { 43 | name 44 | } 45 | } 46 | }`) 47 | ); 48 | const documentWithOffset = new GraphQLDocument( 49 | new Source(`query QueryWithOffset { hero { nam } }`, "testDocument", { 50 | line: 5, 51 | column: 10 52 | }) 53 | ); 54 | describe("Language server diagnostics", () => { 55 | describe("#collectExecutableDefinitionDiagnositics", () => { 56 | it("returns no diagnostics for a correct document", () => { 57 | const diagnostics = collectExecutableDefinitionDiagnositics( 58 | schema, 59 | validDocument 60 | ); 61 | expect(diagnostics.length).toEqual(0); 62 | }); 63 | it("returns two diagnostics for a document with two errors", () => { 64 | const diagnostics = collectExecutableDefinitionDiagnositics( 65 | schema, 66 | invalidDocument 67 | ); 68 | expect(diagnostics.length).toEqual(2); 69 | }); 70 | it("returns no diagnostics for a document that includes type definitions", () => { 71 | const diagnostics = collectExecutableDefinitionDiagnositics( 72 | schema, 73 | documentWithTypes 74 | ); 75 | expect(diagnostics.length).toEqual(0); 76 | }); 77 | it("correctly offsets locations", () => { 78 | const diagnostics = collectExecutableDefinitionDiagnositics( 79 | schema, 80 | documentWithOffset 81 | ); 82 | expect(diagnostics.length).toEqual(1); 83 | expect(diagnostics[0].range.start.character).toEqual(40); 84 | }); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/diagnostics.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLSchema, 3 | GraphQLError, 4 | FragmentDefinitionNode, 5 | findDeprecatedUsages, 6 | isExecutableDefinitionNode 7 | } from "graphql"; 8 | 9 | import { Diagnostic, DiagnosticSeverity } from "vscode-languageserver"; 10 | 11 | import { GraphQLDocument } from "./document"; 12 | import { highlightNodeForNode } from "./utilities/graphql"; 13 | import { rangeForASTNode } from "./utilities/source"; 14 | 15 | import { getValidationErrors } from "./errors/validation"; 16 | import { DocumentUri } from "./project/base"; 17 | 18 | /** 19 | * Build an array of code diagnostics for all executable definitions in a document. 20 | */ 21 | export function collectExecutableDefinitionDiagnositics( 22 | schema: GraphQLSchema, 23 | queryDocument: GraphQLDocument, 24 | fragments: { [fragmentName: string]: FragmentDefinitionNode } = {} 25 | ): Diagnostic[] { 26 | const ast = queryDocument.ast; 27 | if (!ast) return queryDocument.syntaxErrors; 28 | 29 | const astWithExecutableDefinitions = { 30 | ...ast, 31 | definitions: ast.definitions.filter(isExecutableDefinitionNode) 32 | }; 33 | 34 | const diagnostics = []; 35 | 36 | for (const error of getValidationErrors( 37 | schema, 38 | astWithExecutableDefinitions, 39 | fragments 40 | )) { 41 | diagnostics.push( 42 | ...diagnosticsFromError(error, DiagnosticSeverity.Error, "Validation") 43 | ); 44 | } 45 | 46 | for (const error of findDeprecatedUsages( 47 | schema, 48 | astWithExecutableDefinitions 49 | )) { 50 | diagnostics.push( 51 | ...diagnosticsFromError(error, DiagnosticSeverity.Warning, "Deprecation") 52 | ); 53 | } 54 | 55 | return diagnostics; 56 | } 57 | 58 | export function diagnosticsFromError( 59 | error: GraphQLError, 60 | severity: DiagnosticSeverity, 61 | type: string 62 | ): Diagnostic[] { 63 | if (!error.nodes) { 64 | return []; 65 | } 66 | 67 | return error.nodes.map(node => { 68 | return { 69 | source: `GraphQL: ${type}`, 70 | message: error.message, 71 | severity, 72 | range: rangeForASTNode(highlightNodeForNode(node) || node) 73 | }; 74 | }); 75 | } 76 | 77 | export class DiagnosticSet { 78 | private diagnosticsByFile = new Map(); 79 | 80 | entries() { 81 | return this.diagnosticsByFile.entries(); 82 | } 83 | 84 | addDiagnostics(uri: DocumentUri, diagnostics: Diagnostic[]) { 85 | const existingDiagnostics = this.diagnosticsByFile.get(uri); 86 | if (!existingDiagnostics) { 87 | this.diagnosticsByFile.set(uri, diagnostics); 88 | } else { 89 | existingDiagnostics.push(...diagnostics); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /packages/apollo-codegen-flow/src/helpers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLBoolean, 3 | GraphQLFloat, 4 | GraphQLInt, 5 | GraphQLID, 6 | GraphQLScalarType, 7 | GraphQLString, 8 | GraphQLType, 9 | isListType, 10 | isNonNullType 11 | } from "graphql"; 12 | 13 | import * as t from "@babel/types"; 14 | 15 | import { CompilerOptions } from "apollo-codegen-core/lib/compiler"; 16 | 17 | const builtInScalarMap = { 18 | [GraphQLString.name]: t.stringTypeAnnotation(), 19 | [GraphQLInt.name]: t.numberTypeAnnotation(), 20 | [GraphQLFloat.name]: t.numberTypeAnnotation(), 21 | [GraphQLBoolean.name]: t.booleanTypeAnnotation(), 22 | [GraphQLID.name]: t.stringTypeAnnotation() 23 | }; 24 | 25 | export interface FlowCompilerOptions extends CompilerOptions { 26 | useFlowReadOnlyTypes: boolean; 27 | } 28 | 29 | export function createTypeAnnotationFromGraphQLTypeFunction( 30 | compilerOptions: FlowCompilerOptions 31 | ): Function { 32 | const arrayType = compilerOptions.useFlowReadOnlyTypes 33 | ? "$ReadOnlyArray" 34 | : "Array"; 35 | 36 | function nonNullableTypeAnnotationFromGraphQLType( 37 | type: GraphQLType, 38 | typeName?: string 39 | ): t.FlowTypeAnnotation { 40 | if (isListType(type)) { 41 | return t.genericTypeAnnotation( 42 | t.identifier(arrayType), 43 | t.typeParameterInstantiation([ 44 | typeAnnotationFromGraphQLType(type.ofType, typeName) 45 | ]) 46 | ); 47 | } else if (type instanceof GraphQLScalarType) { 48 | const builtIn = builtInScalarMap[typeName || type.name]; 49 | if (builtIn != null) { 50 | return builtIn; 51 | } else if (compilerOptions.passthroughCustomScalars) { 52 | return t.genericTypeAnnotation( 53 | t.identifier( 54 | (compilerOptions.customScalarsPrefix || "") + 55 | (typeName || type.name) 56 | ) 57 | ); 58 | } else { 59 | return t.anyTypeAnnotation(); 60 | } 61 | } else if (isNonNullType(type)) { 62 | // This won't happen; but for TypeScript completeness: 63 | return typeAnnotationFromGraphQLType(type.ofType, typeName); 64 | } else { 65 | return t.genericTypeAnnotation(t.identifier(typeName || type.name)); 66 | } 67 | } 68 | 69 | function typeAnnotationFromGraphQLType( 70 | type: GraphQLType, 71 | typeName?: string 72 | ): t.FlowTypeAnnotation { 73 | if (isNonNullType(type)) { 74 | return nonNullableTypeAnnotationFromGraphQLType(type.ofType, typeName); 75 | } else { 76 | return t.nullableTypeAnnotation( 77 | nonNullableTypeAnnotationFromGraphQLType(type, typeName) 78 | ); 79 | } 80 | } 81 | 82 | return typeAnnotationFromGraphQLType; 83 | } 84 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Node.js 2 | # Build a general Node.js project with npm. 3 | # Add steps that analyze code, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript 5 | 6 | jobs: 7 | # - job: Linux_Node8 8 | 9 | # pool: 10 | # vmImage: "ubuntu 16.04" 11 | 12 | # steps: 13 | # - task: NodeTool@0 14 | # inputs: 15 | # versionSpec: "8.x" 16 | # displayName: "Install Node.js" 17 | 18 | # - script: | 19 | # npm run azure 20 | # displayName: "npm ci && test" 21 | 22 | # - script: | 23 | # npm run lint 24 | # displayName: "npm run lint" 25 | 26 | # - script: | 27 | # ENGINE_API_KEY=$(CHECKS_API_KEY) ./packages/apollo/bin/run client:check 28 | # displayName: "Query Check" 29 | 30 | # - job: Linux_Node10 31 | 32 | # pool: 33 | # vmImage: "ubuntu 16.04" 34 | 35 | # steps: 36 | # - task: NodeTool@0 37 | # inputs: 38 | # versionSpec: "10.x" 39 | # displayName: "Install Node.js" 40 | 41 | # - script: | 42 | # npm run azure 43 | # displayName: "npm ci && test" 44 | 45 | - job: Windows_Node8 46 | 47 | pool: 48 | vmImage: "vs2017-win2016" 49 | 50 | steps: 51 | - task: NodeTool@0 52 | inputs: 53 | versionSpec: "8.14" 54 | displayName: "Install Node.js" 55 | 56 | - script: | 57 | npm run azure 58 | displayName: "npm ci && test" 59 | 60 | - job: Windows_Node10 61 | 62 | pool: 63 | vmImage: "vs2017-win2016" 64 | 65 | steps: 66 | - task: NodeTool@0 67 | inputs: 68 | versionSpec: "10.x" 69 | displayName: "Install Node.js" 70 | 71 | - script: | 72 | npm run azure 73 | displayName: "npm ci && test" 74 | 75 | - job: Build_VSCode 76 | 77 | pool: 78 | vmImage: "ubuntu 16.04" 79 | 80 | steps: 81 | - task: NodeTool@0 82 | inputs: 83 | versionSpec: "10.x" 84 | displayName: "Install Node.js" 85 | 86 | - script: | 87 | npm run package-extension 88 | displayName: "package-extension" 89 | 90 | - task: CopyFiles@2 91 | inputs: 92 | sourceFolder: "./packages/vscode-apollo" 93 | contents: "*.vsix" 94 | targetFolder: "$(Build.ArtifactStagingDirectory)" 95 | condition: succeededOrFailed() 96 | 97 | - task: PublishBuildArtifacts@1 98 | inputs: 99 | pathtoPublish: "$(Build.ArtifactStagingDirectory)" 100 | artifactName: "vsix" 101 | condition: succeededOrFailed() 102 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/errors/validation.ts: -------------------------------------------------------------------------------- 1 | import { 2 | specifiedRules, 3 | NoUnusedFragmentsRule, 4 | KnownDirectivesRule, 5 | GraphQLError, 6 | FieldNode, 7 | ValidationContext, 8 | GraphQLSchema, 9 | DocumentNode, 10 | OperationDefinitionNode, 11 | TypeInfo, 12 | FragmentDefinitionNode, 13 | visit, 14 | visitWithTypeInfo, 15 | visitInParallel 16 | } from "graphql"; 17 | 18 | import { ToolError, logError } from "./logger"; 19 | 20 | export function getValidationErrors( 21 | schema: GraphQLSchema, 22 | document: DocumentNode, 23 | fragments?: { [fragmentName: string]: FragmentDefinitionNode } 24 | ) { 25 | const specifiedRulesToBeRemoved = [ 26 | NoUnusedFragmentsRule, 27 | KnownDirectivesRule 28 | ]; 29 | 30 | const rules = [ 31 | NoAnonymousQueries, 32 | NoTypenameAlias, 33 | ...specifiedRules.filter(rule => !specifiedRulesToBeRemoved.includes(rule)) 34 | ]; 35 | 36 | const typeInfo = new TypeInfo(schema); 37 | const context = new ValidationContext(schema, document, typeInfo); 38 | 39 | if (fragments) { 40 | (context as any)._fragments = fragments; 41 | } 42 | 43 | const visitors = rules.map(rule => rule(context)); 44 | // Visit the whole document with each instance of all provided rules. 45 | visit(document, visitWithTypeInfo(typeInfo, visitInParallel(visitors))); 46 | return context.getErrors(); 47 | } 48 | 49 | export function validateQueryDocument( 50 | schema: GraphQLSchema, 51 | document: DocumentNode 52 | ) { 53 | try { 54 | const validationErrors = getValidationErrors(schema, document); 55 | if (validationErrors && validationErrors.length > 0) { 56 | for (const error of validationErrors) { 57 | logError(error); 58 | } 59 | throw new ToolError("Validation of GraphQL query document failed"); 60 | } 61 | } catch (e) { 62 | console.error(e); 63 | throw e; 64 | } 65 | } 66 | 67 | export function NoAnonymousQueries(context: ValidationContext) { 68 | return { 69 | OperationDefinition(node: OperationDefinitionNode) { 70 | if (!node.name) { 71 | context.reportError( 72 | new GraphQLError("Apollo does not support anonymous operations", [ 73 | node 74 | ]) 75 | ); 76 | } 77 | return false; 78 | } 79 | }; 80 | } 81 | 82 | export function NoTypenameAlias(context: ValidationContext) { 83 | return { 84 | Field(node: FieldNode) { 85 | const aliasName = node.alias && node.alias.value; 86 | if (aliasName == "__typename") { 87 | context.reportError( 88 | new GraphQLError( 89 | "Apollo needs to be able to insert __typename when needed, please do not use it as an alias", 90 | [node] 91 | ) 92 | ); 93 | } 94 | } 95 | }; 96 | } 97 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/src/types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLString, 3 | GraphQLInt, 4 | GraphQLFloat, 5 | GraphQLBoolean, 6 | GraphQLID, 7 | GraphQLScalarType, 8 | GraphQLEnumType, 9 | isAbstractType, 10 | isNonNullType, 11 | isListType 12 | } from "graphql"; 13 | import { LegacyCompilerContext } from "apollo-codegen-core/lib/compiler/legacyIR"; 14 | import { GraphQLType } from "graphql"; 15 | 16 | const builtInScalarMap = { 17 | [GraphQLString.name]: "String", 18 | [GraphQLInt.name]: "Int", 19 | [GraphQLFloat.name]: "Double", 20 | [GraphQLBoolean.name]: "Boolean", 21 | [GraphQLID.name]: "String" 22 | }; 23 | 24 | export function possibleTypesForType( 25 | context: LegacyCompilerContext, 26 | type: GraphQLType 27 | ) { 28 | if (isAbstractType(type)) { 29 | return context.schema.getPossibleTypes(type); 30 | } else { 31 | return [type]; 32 | } 33 | } 34 | 35 | export function typeNameFromGraphQLType( 36 | context: LegacyCompilerContext, 37 | type: GraphQLType, 38 | bareTypeName?: string, 39 | isOptional?: boolean, 40 | isInputObject?: boolean 41 | ): string { 42 | if (isNonNullType(type)) { 43 | return typeNameFromGraphQLType( 44 | context, 45 | type.ofType, 46 | bareTypeName, 47 | isOptional || false, 48 | isInputObject 49 | ); 50 | } else if (isOptional === undefined) { 51 | isOptional = true; 52 | } 53 | 54 | let typeName; 55 | if (isListType(type)) { 56 | if (isInputObject) { 57 | typeName = 58 | "Seq[" + 59 | typeNameFromGraphQLType( 60 | context, 61 | type.ofType, 62 | bareTypeName, 63 | undefined, 64 | isInputObject 65 | ) + 66 | "]"; 67 | } else { 68 | typeName = 69 | "scala.scalajs.js.Array[" + 70 | typeNameFromGraphQLType( 71 | context, 72 | type.ofType, 73 | bareTypeName, 74 | undefined, 75 | isInputObject 76 | ) + 77 | "]"; 78 | } 79 | } else if (type instanceof GraphQLScalarType) { 80 | typeName = typeNameForScalarType(context, type); 81 | } else if (type instanceof GraphQLEnumType) { 82 | typeName = "String"; 83 | } else { 84 | typeName = bareTypeName || type.name; 85 | } 86 | 87 | return isOptional 88 | ? `com.apollographql.scalajs.OptionalValue[${typeName}]` 89 | : typeName; 90 | } 91 | 92 | function typeNameForScalarType( 93 | context: LegacyCompilerContext, 94 | type: GraphQLScalarType 95 | ): string { 96 | return ( 97 | builtInScalarMap[type.name] || 98 | (context.options.passthroughCustomScalars 99 | ? context.options.customScalarsPrefix + type.name 100 | : GraphQLString.name) 101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/__tests__/loading.ts: -------------------------------------------------------------------------------- 1 | import { stripIndents } from "common-tags"; 2 | import fs from "fs"; 3 | import path from "path"; 4 | 5 | import { 6 | extractDocumentFromJavascript, 7 | loadAndMergeQueryDocuments, 8 | loadQueryDocuments 9 | } from "../loading"; 10 | 11 | // Test example javascript source files are located within __fixtures__ 12 | describe("extractDocumentFromJavascript", () => { 13 | test("normal queries", () => { 14 | const contents = fs 15 | .readFileSync(path.join(__dirname, "__fixtures__", "normal.js")) 16 | .toString(); 17 | expect(stripIndents`${extractDocumentFromJavascript(contents)}`).toMatch( 18 | stripIndents` 19 | query UserProfileView { 20 | me { 21 | id 22 | uuid 23 | role 24 | } 25 | } 26 | ` 27 | ); 28 | }); 29 | 30 | test("comments in template string", () => { 31 | const contents = fs 32 | .readFileSync(path.join(__dirname, "__fixtures__", "comments.js")) 33 | .toString(); 34 | expect(stripIndents`${extractDocumentFromJavascript(contents)}`).toMatch( 35 | stripIndents` 36 | query UserProfileView { 37 | me { 38 | id 39 | # TODO: https://www.fast.com/sdf/sdf 40 | uuid 41 | # Some other comment 42 | role 43 | } 44 | } 45 | ` 46 | ); 47 | }); 48 | 49 | test("gql completely commented out", () => { 50 | const contents = fs 51 | .readFileSync(path.join(__dirname, "__fixtures__", "commentedOut.js")) 52 | .toString(); 53 | expect(extractDocumentFromJavascript(contents)).toBeNull(); 54 | }); 55 | 56 | test("invalid gql", () => { 57 | const contents = fs 58 | .readFileSync(path.join(__dirname, "__fixtures__", "invalid.js")) 59 | .toString(); 60 | expect(extractDocumentFromJavascript(contents)).toBeNull(); 61 | }); 62 | }); 63 | 64 | describe("Validation", () => { 65 | test(`should extract gql snippet from javascript file`, () => { 66 | const inputPaths = [ 67 | path.join(__dirname, "../../../../__fixtures__/starwars/gqlQueries.js") 68 | ]; 69 | 70 | const document = loadAndMergeQueryDocuments(inputPaths); 71 | 72 | expect(document).toMatchSnapshot(); 73 | }); 74 | }); 75 | 76 | describe("loadQueryDocuments", () => { 77 | test(`should load a schema document from a .graphqls file`, () => { 78 | const inputPaths = [ 79 | path.join(__dirname, "../../../../__fixtures__/starwars/schema.graphqls") 80 | ]; 81 | 82 | const document = loadQueryDocuments(inputPaths); 83 | 84 | expect(document.length).toEqual(1); 85 | expect(document[0].definitions).toHaveLength(16); 86 | expect(document[0].kind).toEqual("Document"); 87 | expect(document[0].loc).toBeDefined(); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /packages/vscode-apollo/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { LanguageClient } from "vscode-languageclient"; 2 | 3 | export const timeSince = (date: number) => { 4 | const seconds = Math.floor((+new Date() - date) / 1000); 5 | if (!seconds) return; 6 | let interval = Math.floor(seconds / 86400); 7 | if (interval >= 1) return `${interval}d`; 8 | 9 | interval = Math.floor(seconds / 3600); 10 | if (interval >= 1) return `${interval}h`; 11 | 12 | interval = Math.floor(seconds / 60); 13 | if (interval >= 1) return `${interval}m`; 14 | 15 | return `${Math.floor(seconds)}s`; 16 | }; 17 | 18 | export const printNoFileOpenMessage = ( 19 | client: LanguageClient, 20 | extVersion: string 21 | ) => { 22 | client.outputChannel.appendLine("------------------------------"); 23 | client.outputChannel.appendLine(`🚀 Apollo GraphQL v${extVersion}`); 24 | client.outputChannel.appendLine("------------------------------"); 25 | }; 26 | 27 | export interface TypeStats { 28 | service?: number; 29 | client?: number; 30 | total?: number; 31 | } 32 | 33 | export interface ProjectStats { 34 | type: string; 35 | loaded: boolean; 36 | serviceId?: string; 37 | types?: TypeStats; 38 | tag?: string; 39 | lastFetch?: number; 40 | } 41 | 42 | export const printStatsToClientOutputChannel = ( 43 | client: LanguageClient, 44 | stats: ProjectStats, 45 | extVersion: string 46 | ) => { 47 | client.outputChannel.appendLine("------------------------------"); 48 | client.outputChannel.appendLine(`🚀 Apollo GraphQL v${extVersion}`); 49 | client.outputChannel.appendLine("------------------------------"); 50 | 51 | if (!stats || !stats.loaded) { 52 | client.outputChannel.appendLine( 53 | "❌ Service stats could not be loaded. This may be because you're missing an apollo.config.js file " + 54 | "or it is misconfigured. For more information about configuring Apollo projects, " + 55 | "see the guide here (https://bit.ly/2ByILPj)." 56 | ); 57 | return; 58 | } 59 | 60 | // we don't support logging of stats for service projects currently 61 | if (stats.type === "service") { 62 | return; 63 | } else if (stats.type === "client") { 64 | client.outputChannel.appendLine("✅ Service Loaded!"); 65 | client.outputChannel.appendLine(`🆔 Service ID: ${stats.serviceId}`); 66 | client.outputChannel.appendLine(`🏷 Schema Tag: ${stats.tag}`); 67 | 68 | if (stats.types) 69 | client.outputChannel.appendLine( 70 | `📈 Number of Types: ${stats.types.total} (${ 71 | stats.types.client 72 | } client ${stats.types.client === 1 ? "type" : "types"})` 73 | ); 74 | 75 | if (stats.lastFetch && timeSince(stats.lastFetch)) { 76 | client.outputChannel.appendLine( 77 | `🗓 Last Fetched ${timeSince(stats.lastFetch)} Ago` 78 | ); 79 | } 80 | client.outputChannel.appendLine("------------------------------"); 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/test-utils/matchers.ts: -------------------------------------------------------------------------------- 1 | import { collectAndMergeFields } from '../src/compiler/visitors/collectAndMergeFields'; 2 | 3 | import { SelectionSet } from '../src/compiler'; 4 | 5 | declare global { 6 | namespace jest { 7 | interface Matchers { 8 | toMatchSelectionSet(possibleTypeNames: string[], expectedResponseKeys: string[]): R; 9 | toContainSelectionSetMatching(possibleTypeNames: string[], expectedResponseKeys: string[]): R; 10 | } 11 | interface MatcherUtils { 12 | equals(a: any, b: any): boolean; 13 | } 14 | } 15 | } 16 | 17 | function toMatchSelectionSet( 18 | this: jest.MatcherUtils, 19 | received: SelectionSet, 20 | possibleTypeNames: string[], 21 | expectedResponseKeys: string[] 22 | ): { message(): string; pass: boolean } { 23 | const actualResponseKeys = collectAndMergeFields(received).map(field => field.responseKey); 24 | 25 | const pass = this.equals(actualResponseKeys, expectedResponseKeys); 26 | 27 | if (pass) { 28 | return { 29 | message: () => 30 | `Expected selection set for ${this.utils.printExpected(possibleTypeNames)}\n` + 31 | `To not match:\n` + 32 | ` ${this.utils.printExpected(expectedResponseKeys)}` + 33 | 'Received:\n' + 34 | ` ${this.utils.printReceived(actualResponseKeys)}`, 35 | pass: true 36 | }; 37 | } else { 38 | return { 39 | message: () => 40 | `Expected selection set for ${this.utils.printExpected(possibleTypeNames)}\n` + 41 | `To match:\n` + 42 | ` ${this.utils.printExpected(expectedResponseKeys)}\n` + 43 | 'Received:\n' + 44 | ` ${this.utils.printReceived(actualResponseKeys)}`, 45 | pass: false 46 | }; 47 | } 48 | } 49 | 50 | function toContainSelectionSetMatching( 51 | this: jest.MatcherUtils, 52 | received: SelectionSet[], 53 | possibleTypeNames: string[], 54 | expectedResponseKeys: string[] 55 | ): { message(): string; pass: boolean } { 56 | const variant = received.find(variant => { 57 | return this.equals(Array.from(variant.possibleTypes).map(type => type.name), possibleTypeNames); 58 | }); 59 | 60 | if (!variant) { 61 | return { 62 | message: () => 63 | `Expected array to contain variant for:\n` + 64 | ` ${this.utils.printExpected(possibleTypeNames)}\n` + 65 | `But only found variants for:\n` + 66 | received 67 | .map( 68 | variant => 69 | ` ${this.utils.printReceived(variant.possibleTypes)} -> ${this.utils.printReceived( 70 | collectAndMergeFields(variant).map(field => field.name) 71 | )}` 72 | ) 73 | .join('\n'), 74 | pass: false 75 | }; 76 | } 77 | 78 | return toMatchSelectionSet.call(this, variant, possibleTypeNames, expectedResponseKeys); 79 | } 80 | 81 | expect.extend({ 82 | toMatchSelectionSet, 83 | toContainSelectionSetMatching 84 | } as any); 85 | -------------------------------------------------------------------------------- /packages/apollo/src/commands/client/extract.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from "crypto"; 2 | import { writeFileSync } from "fs"; 3 | import { 4 | printWithReducedWhitespace, 5 | sortAST, 6 | defaultSignature as engineDefaultSignature 7 | } from "apollo-engine-reporting"; 8 | import { DocumentNode } from "graphql"; 9 | 10 | import { ClientCommand } from "../../Command"; 11 | import { hideCertainLiterals } from "./push"; 12 | 13 | // XXX this is duplicated code 14 | const manifestOperationHash = (str: string): string => 15 | createHash("sha256") 16 | .update(str) 17 | .digest("hex"); 18 | 19 | const engineSignature = (_TODO_operationAST: DocumentNode): string => { 20 | // TODO. We don't currently have access to the operation name since it's 21 | // currently omitted by the `apollo-codegen-core` package logic. 22 | return engineDefaultSignature(_TODO_operationAST, "TODO"); 23 | }; 24 | 25 | export default class ClientExtract extends ClientCommand { 26 | static description = "Extract queries from a client"; 27 | static flags = { 28 | ...ClientCommand.flags 29 | }; 30 | 31 | static args = [ 32 | { 33 | name: "output", 34 | description: "Path to write the extracted queries to", 35 | required: true, 36 | default: "manifest.json" 37 | } 38 | ]; 39 | 40 | async run() { 41 | const { clientIdentity, operations, filename }: any = await this.runTasks( 42 | ({ flags, project, config, args }) => [ 43 | { 44 | title: "Extracting operations from project", 45 | task: async ctx => { 46 | const operations = Object.values( 47 | this.project.mergedOperationsAndFragmentsForService 48 | ).map(operationAST => { 49 | // While this could include dropping unused definitions, they are 50 | // kept because the registered operations should mirror those in the 51 | // client bundle minus any PII which lives within string literals. 52 | const printed = printWithReducedWhitespace( 53 | sortAST(hideCertainLiterals(operationAST)) 54 | ); 55 | 56 | return { 57 | signature: manifestOperationHash(printed), 58 | document: printed, 59 | metadata: { 60 | engineSignature: engineSignature(operationAST) 61 | } 62 | }; 63 | }); 64 | 65 | ctx.operations = operations; 66 | ctx.clientIdentity = config.client; 67 | } 68 | }, 69 | { 70 | title: "Outputing extracted queries", 71 | task: (ctx, task) => { 72 | const filename = args.output; 73 | task.title = "Outputing extracted queries to " + filename; 74 | ctx.filename = filename; 75 | writeFileSync( 76 | filename, 77 | JSON.stringify( 78 | { version: 1, operations: ctx.operations }, 79 | null, 80 | 2 81 | ) 82 | ); 83 | } 84 | } 85 | ] 86 | ); 87 | 88 | this.log( 89 | `Successfully wrote ${operations.length} operations from the ${ 90 | clientIdentity.name 91 | } client to ${filename}` 92 | ); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /packages/apollo-codegen-flow/src/printer.ts: -------------------------------------------------------------------------------- 1 | import * as t from "@babel/types"; 2 | import generate from "@babel/generator"; 3 | 4 | import { stripIndent } from "common-tags"; 5 | 6 | type Printable = t.Node | string; 7 | 8 | export default class Printer { 9 | private printQueue: Printable[] = []; 10 | 11 | public print(): string { 12 | return (this.printQueue.reduce((document: string, printable) => { 13 | if (typeof printable === "string") { 14 | return document + printable; 15 | } else { 16 | const documentPart = generate(printable).code; 17 | return document + this.fixCommas(documentPart); 18 | } 19 | }, "") as string).trim(); 20 | } 21 | 22 | public enqueue(printable: Printable) { 23 | this.printQueue = [...this.printQueue, "\n", "\n", printable]; 24 | } 25 | 26 | public printAndClear() { 27 | const output = this.print(); 28 | this.printQueue = []; 29 | return output; 30 | } 31 | 32 | /** 33 | * When using trailing commas on ObjectTypeProperties within 34 | * ObjectTypeAnnotations, we get weird behavior: 35 | * ``` 36 | * { 37 | * homePlanet: ?string // description 38 | * , 39 | * friends: any // description 40 | * } 41 | * ``` 42 | * when we want 43 | * ``` 44 | * { 45 | * homePlanet: ?string, // description 46 | * friends: any // description 47 | * } 48 | * ``` 49 | */ 50 | private fixCommas(documentPart: string) { 51 | const lines = documentPart.split("\n").filter(Boolean); // filter out lines that have no content 52 | 53 | let currentLine = 0; 54 | let nextLine; 55 | const newDocumentParts = []; 56 | // Keep track of what column comments should start on 57 | // to keep things aligned 58 | let maxCommentColumn = 0; 59 | 60 | while (currentLine !== lines.length) { 61 | nextLine = currentLine + 1; 62 | const strippedNextLine = stripIndent`${lines[nextLine]}`; 63 | if (strippedNextLine.length === 1 && strippedNextLine[0] === ",") { 64 | const currentLineContents = lines[currentLine]; 65 | const commentColumn = currentLineContents.indexOf("//"); 66 | if (maxCommentColumn < commentColumn) { 67 | maxCommentColumn = commentColumn; 68 | } 69 | 70 | const [contents, comment] = currentLineContents.split("//"); 71 | newDocumentParts.push({ 72 | main: contents.replace(/\s+$/g, "") + ",", 73 | comment: comment ? comment.trim() : null 74 | }); 75 | currentLine++; 76 | } else { 77 | newDocumentParts.push({ 78 | main: lines[currentLine], 79 | comment: null 80 | }); 81 | } 82 | 83 | currentLine++; 84 | } 85 | 86 | return newDocumentParts 87 | .reduce((memo: string[], part) => { 88 | const { main, comment } = part; 89 | 90 | let line; 91 | if (comment !== null) { 92 | const spacesBetween = maxCommentColumn - main.length; 93 | line = `${main}${" ".repeat(spacesBetween)} // ${comment}`; 94 | } else { 95 | line = main; 96 | } 97 | 98 | return [...memo, line]; 99 | }, []) 100 | .join("\n"); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/config/__tests__/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApolloConfig, 3 | ApolloConfigFormat, 4 | getServiceFromKey, 5 | getServiceName, 6 | isClientConfig, 7 | isLocalServiceConfig, 8 | isServiceConfig, 9 | parseServiceSpecifier 10 | } from "../"; 11 | 12 | describe("getServiceFromKey", () => { 13 | it("returns undefined with no provided key", () => { 14 | expect(getServiceFromKey()).toBeUndefined(); 15 | }); 16 | 17 | it("returns service name from service api key", () => { 18 | const key = "service:bob-123:489fhseo4"; 19 | expect(getServiceFromKey(key)).toEqual("bob-123"); 20 | }); 21 | 22 | it("returns nothing if key is not a service key", () => { 23 | const key = "not-a-service:bob-123:489fhseo4"; 24 | expect(getServiceFromKey(key)).toBeUndefined(); 25 | }); 26 | 27 | it("returns nothing if key is malformed", () => { 28 | const key = "service/bob-123:489fhseo4"; 29 | expect(getServiceFromKey(key)).toBeUndefined(); 30 | }); 31 | }); 32 | 33 | describe("getServiceName", () => { 34 | describe("client config", () => { 35 | it("finds service name when client.service is a string", () => { 36 | const rawConfig: ApolloConfigFormat = { 37 | client: { service: "my-service" } 38 | }; 39 | expect(getServiceName(rawConfig)).toEqual("my-service"); 40 | 41 | const rawConfigWithTag: ApolloConfigFormat = { 42 | client: { service: "my-service@master" } 43 | }; 44 | expect(getServiceName(rawConfigWithTag)).toEqual("my-service"); 45 | }); 46 | 47 | it("finds service name when client.service is an object", () => { 48 | const rawConfig: ApolloConfigFormat = { 49 | client: { service: { name: "my-service" } } 50 | }; 51 | expect(getServiceName(rawConfig)).toEqual("my-service"); 52 | }); 53 | }); 54 | describe("service config", () => { 55 | it("finds service name from raw service config", () => { 56 | const rawConfig: ApolloConfigFormat = { service: { name: "my-service" } }; 57 | expect(getServiceName(rawConfig)).toEqual("my-service"); 58 | }); 59 | }); 60 | }); 61 | 62 | describe("isClientConfig", () => { 63 | it("identifies client config properly", () => { 64 | const config = new ApolloConfig({ client: { service: "hello" } }); 65 | expect(isClientConfig(config)).toBeTruthy(); 66 | }); 67 | }); 68 | 69 | describe("isLocalServiceConfig", () => { 70 | it("properly identifies a client config that uses localSchemaFiles", () => { 71 | const clientServiceConfig = { localSchemaFile: "okay" }; 72 | expect(isLocalServiceConfig(clientServiceConfig)).toBeTruthy(); 73 | }); 74 | }); 75 | 76 | describe("isServiceConfig", () => { 77 | it("identifies service config properly", () => { 78 | const config = new ApolloConfig({ service: "hello" }); 79 | expect(isServiceConfig(config)).toBeTruthy(); 80 | }); 81 | }); 82 | 83 | describe("parseServiceSpecifier", () => { 84 | it("parses service identifier for service id and tag properly", () => { 85 | const [id, tag] = parseServiceSpecifier("my-service@master"); 86 | expect(id).toEqual("my-service"); 87 | expect(tag).toEqual("master"); 88 | 89 | const [idFromSimpleName, tagFromSimpleName] = parseServiceSpecifier( 90 | "my-service" 91 | ); 92 | expect(idFromSimpleName).toEqual("my-service"); 93 | expect(tagFromSimpleName).toBeUndefined(); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /packages/apollo/src/git.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | import ci from "env-ci"; 4 | import { gitToJs } from "git-parse"; 5 | import git from "git-rev-sync"; 6 | import { pickBy, identity } from "lodash"; 7 | import Command from "@oclif/command"; 8 | 9 | const findGitRoot = (start?: string | string[]): string | void => { 10 | start = start || process.cwd(); 11 | if (typeof start === "string") { 12 | if (start[start.length - 1] !== path.sep) start += path.sep; 13 | start = start.split(path.sep); 14 | } 15 | if (!start.length) return; 16 | start.pop(); 17 | const dir = start.join(path.sep); 18 | if (fs.existsSync(path.join(dir, ".git"))) { 19 | return path.normalize(dir); 20 | } else { 21 | return findGitRoot(start); 22 | } 23 | }; 24 | 25 | export interface Commit { 26 | authorName: string | null; 27 | authorEmail: string | null; 28 | } 29 | 30 | export interface GitContext { 31 | committer?: string; 32 | commit: string; 33 | message?: string; 34 | remoteUrl?: string; 35 | branch?: string; 36 | } 37 | 38 | export const gitInfo = async ( 39 | log: Command["log"] 40 | ): Promise => { 41 | // Occasionally `branch` will be undefined depending on the environment, so 42 | // we need to fallback on `prBranch`. However in some cases, we are not able 43 | // to get to the branch at all. For more information, see 44 | // https://github.com/pvdlg/env-ci#caveats 45 | const { commit, branch: ciBranch, root, prBranch } = ci(); 46 | const gitLoc = root ? root : findGitRoot(); 47 | 48 | if (!commit) return; 49 | 50 | let committer; 51 | let branch = ciBranch || prBranch; 52 | // BUILD_REPOSITORY_ID is for azure pipelines 53 | let remoteUrl = process.env.BUILD_REPOSITORY_ID; 54 | let message; 55 | 56 | // In order to use git-parse and git-rev-sync, we must ensure that a git context is 57 | // accessible. Without this check, the commands would throw 58 | if (gitLoc) { 59 | const { authorName, authorEmail, ...commit } = await gitToJs(gitLoc) 60 | .then((commits: Commit[]) => 61 | commits && commits.length > 0 62 | ? commits[0] 63 | : { authorName: null, authorEmail: null, message: null } 64 | ) 65 | .catch(() => ({ authorEmail: null, authorName: null, message: null })); 66 | 67 | committer = `${authorName || ""} ${ 68 | authorEmail ? `<${authorEmail}>` : "" 69 | }`.trim(); 70 | 71 | message = commit.message; 72 | 73 | // The remoteUrl call can fail and throw an error 74 | // https://github.com/kurttheviking/git-rev-sync-js#gitremoteurl--string 75 | try { 76 | remoteUrl = git.remoteUrl(); 77 | } catch (e) { 78 | log(["Unable to retrieve remote url, failed with:", e].join("\n\n")); 79 | } 80 | 81 | // The ci and pr branches pulled from the ci's environment can be undefined, 82 | // so we fallback on the git context. 83 | // 84 | // See https://github.com/pvdlg/env-ci#caveats for a detailed list of when 85 | // branch can be undefined 86 | if (!branch) { 87 | branch = git.branch([gitLoc]); 88 | } 89 | } 90 | 91 | return pickBy( 92 | { 93 | committer, 94 | commit, 95 | remoteUrl, 96 | message, 97 | branch 98 | }, 99 | identity 100 | ) as GitContext; 101 | }; 102 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/engine/GraphQLDataSource.ts: -------------------------------------------------------------------------------- 1 | import { DataSourceConfig } from "apollo-datasource"; 2 | import { ApolloLink, execute, GraphQLRequest, makePromise } from "apollo-link"; 3 | import { setContext } from "apollo-link-context"; 4 | import { onError } from "apollo-link-error"; 5 | import { createHttpLink } from "apollo-link-http"; 6 | import { 7 | ApolloError, 8 | AuthenticationError, 9 | ForbiddenError 10 | } from "apollo-server-errors"; 11 | import to from "await-to-js"; 12 | import { GraphQLError } from "graphql"; 13 | import { fetch } from "apollo-env"; 14 | 15 | export interface GraphQLResponse { 16 | data?: T; 17 | errors?: GraphQLError[]; 18 | } 19 | export class GraphQLDataSource { 20 | public baseURL!: string; 21 | public context!: TContext; 22 | 23 | public initialize(config: DataSourceConfig): void { 24 | this.context = config.context; 25 | } 26 | 27 | // XXX can we kill the casting here? 28 | public async execute( 29 | operation: GraphQLRequest 30 | ): Promise> { 31 | return this.executeSingleOperation(operation) as Promise< 32 | GraphQLResponse 33 | >; 34 | } 35 | 36 | protected willSendRequest?(request: any): any; 37 | 38 | private composeLinks(): ApolloLink { 39 | const uri = this.resolveUri(); 40 | 41 | return ApolloLink.from([ 42 | this.onErrorLink(), 43 | this.onRequestLink(), 44 | createHttpLink({ fetch, uri }) 45 | ]); 46 | } 47 | 48 | private didEncounterError(error: any) { 49 | const status = error.statusCode ? error.statusCode : null; 50 | const message = error.bodyText 51 | ? error.bodyText 52 | : error.message 53 | ? error.message 54 | : null; 55 | 56 | let apolloError: ApolloError; 57 | 58 | switch (status) { 59 | case 401: 60 | apolloError = new AuthenticationError(message); 61 | break; 62 | case 403: 63 | apolloError = new ForbiddenError(message); 64 | break; 65 | default: 66 | apolloError = new ApolloError(message); 67 | } 68 | 69 | throw apolloError; 70 | } 71 | 72 | private async executeSingleOperation(operation: GraphQLRequest) { 73 | const link = this.composeLinks(); 74 | 75 | const [error, response] = await to(makePromise(execute(link, operation))); 76 | 77 | if (error) { 78 | this.didEncounterError(error); 79 | } 80 | 81 | return response; 82 | } 83 | 84 | private resolveUri(): string { 85 | const baseURL = this.baseURL; 86 | 87 | if (!baseURL) { 88 | throw new ApolloError( 89 | "Cannot make request to GraphQL API, missing baseURL" 90 | ); 91 | } 92 | 93 | return baseURL; 94 | } 95 | 96 | private onRequestLink() { 97 | return setContext((_, request) => { 98 | if (this.willSendRequest) { 99 | this.willSendRequest(request); 100 | } 101 | 102 | return request; 103 | }); 104 | } 105 | 106 | private onErrorLink() { 107 | return onError(({ graphQLErrors, networkError }) => { 108 | if (graphQLErrors) { 109 | graphQLErrors.map(graphqlError => 110 | console.error(`[GraphQL error]: ${graphqlError.message}`) 111 | ); 112 | } 113 | 114 | if (networkError) { 115 | console.log(`[Network Error]: ${networkError}`); 116 | } 117 | }); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /packages/apollo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo", 3 | "description": "Command line tool for Apollo GraphQL", 4 | "version": "2.6.2", 5 | "referenceID": "21ad0845-c235-422e-be7d-a998310df972", 6 | "author": "Apollo GraphQL ", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/apollographql/apollo-tooling.git" 11 | }, 12 | "homepage": "https://github.com/apollographql/apollo-tooling", 13 | "bugs": "https://github.com/apollographql/apollo-tooling/issues", 14 | "files": [ 15 | "/bin", 16 | "/lib", 17 | "/oclif.manifest.json" 18 | ], 19 | "main": "lib/index.js", 20 | "types": "lib/index.d.ts", 21 | "bin": { 22 | "apollo": "./bin/run" 23 | }, 24 | "scripts": { 25 | "prepack": "oclif-dev manifest && oclif-dev readme", 26 | "postpack": "rm -f oclif.manifest.json", 27 | "version": "oclif-dev readme && git add README.md" 28 | }, 29 | "engines": { 30 | "node": ">=8", 31 | "npm": ">=6" 32 | }, 33 | "dependencies": { 34 | "@apollographql/apollo-tools": "file:../apollo-tools", 35 | "@oclif/command": "1.5.12", 36 | "@oclif/config": "1.12.12", 37 | "@oclif/errors": "1.2.2", 38 | "@oclif/plugin-autocomplete": "0.1.0", 39 | "@oclif/plugin-help": "2.1.6", 40 | "@oclif/plugin-not-found": "1.2.2", 41 | "@oclif/plugin-plugins": "1.7.8", 42 | "@oclif/plugin-warn-if-update-available": "1.7.0", 43 | "apollo-codegen-core": "file:../apollo-codegen-core", 44 | "apollo-codegen-flow": "file:../apollo-codegen-flow", 45 | "apollo-codegen-scala": "file:../apollo-codegen-scala", 46 | "apollo-codegen-swift": "file:../apollo-codegen-swift", 47 | "apollo-codegen-typescript": "file:../apollo-codegen-typescript", 48 | "apollo-engine-reporting": "0.2.2", 49 | "apollo-env": "file:../apollo-env", 50 | "apollo-language-server": "file:../apollo-language-server", 51 | "chalk": "2.4.2", 52 | "cli-ux": "4.9.3", 53 | "env-ci": "3.2.0", 54 | "gaze": "1.1.3", 55 | "git-parse": "1.0.3", 56 | "git-rev-sync": "1.12.0", 57 | "glob": "7.1.3", 58 | "graphql": "^14.0.2", 59 | "graphql-tag": "2.10.1", 60 | "heroku-cli-util": "8.0.11", 61 | "listr": "0.14.3", 62 | "lodash": "4.17.11", 63 | "tty": "1.0.1", 64 | "vscode-uri": "1.0.6" 65 | }, 66 | "devDependencies": { 67 | "typescript": "3.4.1" 68 | }, 69 | "oclif": { 70 | "commands": "./lib/commands", 71 | "bin": "apollo", 72 | "plugins": [ 73 | "@oclif/plugin-help", 74 | "@oclif/plugin-not-found", 75 | "@oclif/plugin-plugins", 76 | "@oclif/plugin-warn-if-update-available" 77 | ], 78 | "repositoryPrefix": "<%- repo %>/blob/master/packages/apollo/<%- commandPath %>" 79 | }, 80 | "jest": { 81 | "preset": "ts-jest", 82 | "transformIgnorePatterns": [ 83 | "/node_modules/", 84 | "/apollo-env/" 85 | ], 86 | "testMatch": null, 87 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 88 | "testPathIgnorePatterns": [ 89 | "node_modules", 90 | "lib" 91 | ], 92 | "moduleFileExtensions": [ 93 | "ts", 94 | "tsx", 95 | "js", 96 | "jsx", 97 | "json", 98 | "node" 99 | ], 100 | "testEnvironment": "node", 101 | "globals": { 102 | "ts-jest": { 103 | "tsConfig": "/tsconfig.test.json", 104 | "diagnostics": false 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /packages/apollo-codegen-core/src/utilities/CodeGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface BasicGeneratedFile { 2 | output: string; 3 | } 4 | 5 | export class GeneratedFile implements BasicGeneratedFile { 6 | scopeStack: Scope[] = []; 7 | indentWidth = 2; 8 | indentLevel = 0; 9 | startOfIndentLevel = false; 10 | 11 | public output = ""; 12 | 13 | pushScope(scope: Scope) { 14 | this.scopeStack.push(scope); 15 | } 16 | 17 | popScope() { 18 | return this.scopeStack.pop(); 19 | } 20 | 21 | get scope(): Scope { 22 | if (this.scopeStack.length < 1) throw new Error("No active scope"); 23 | 24 | return this.scopeStack[this.scopeStack.length - 1]; 25 | } 26 | 27 | print(string?: string) { 28 | if (string) { 29 | this.output += string; 30 | } 31 | } 32 | 33 | printNewline() { 34 | if (this.output) { 35 | this.print("\n"); 36 | this.startOfIndentLevel = false; 37 | } 38 | } 39 | 40 | printNewlineIfNeeded() { 41 | if (!this.startOfIndentLevel) { 42 | this.printNewline(); 43 | } 44 | } 45 | 46 | printOnNewline(string?: string) { 47 | if (string) { 48 | this.printNewline(); 49 | this.printIndent(); 50 | this.print(string); 51 | } 52 | } 53 | 54 | printIndent() { 55 | const indentation = " ".repeat(this.indentLevel * this.indentWidth); 56 | this.output += indentation; 57 | } 58 | 59 | withIndent(closure: Function) { 60 | if (!closure) return; 61 | 62 | this.indentLevel++; 63 | this.startOfIndentLevel = true; 64 | closure(); 65 | this.indentLevel--; 66 | } 67 | 68 | withinBlock(closure: Function, open = " {", close = "}") { 69 | this.print(open); 70 | this.withIndent(closure); 71 | this.printOnNewline(close); 72 | } 73 | } 74 | 75 | export default class CodeGenerator { 76 | generatedFiles: { [fileName: string]: GeneratedFile } = {}; 77 | currentFile: GeneratedFile; 78 | 79 | constructor(public context: Context) { 80 | this.currentFile = new GeneratedFile(); 81 | } 82 | 83 | withinFile(fileName: string, closure: Function) { 84 | let file = this.generatedFiles[fileName]; 85 | if (!file) { 86 | file = new GeneratedFile(); 87 | this.generatedFiles[fileName] = file; 88 | } 89 | const oldCurrentFile = this.currentFile; 90 | this.currentFile = file; 91 | closure(); 92 | this.currentFile = oldCurrentFile; 93 | } 94 | 95 | get output(): string { 96 | return this.currentFile.output; 97 | } 98 | 99 | pushScope(scope: Scope) { 100 | this.currentFile.pushScope(scope); 101 | } 102 | 103 | popScope() { 104 | this.currentFile.popScope(); 105 | } 106 | 107 | get scope(): Scope { 108 | return this.currentFile.scope; 109 | } 110 | 111 | print(string?: string) { 112 | this.currentFile.print(string); 113 | } 114 | 115 | printNewline() { 116 | this.currentFile.printNewline(); 117 | } 118 | 119 | printNewlineIfNeeded() { 120 | this.currentFile.printNewlineIfNeeded(); 121 | } 122 | 123 | printOnNewline(string?: string) { 124 | this.currentFile.printOnNewline(string); 125 | } 126 | 127 | printIndent() { 128 | this.currentFile.printIndent(); 129 | } 130 | 131 | withIndent(closure: Function) { 132 | this.currentFile.withIndent(closure); 133 | } 134 | 135 | withinBlock(closure: Function, open = " {", close = "}") { 136 | this.currentFile.withinBlock(closure, open, close); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /packages/apollo-env/src/fetch/fetch.d.ts: -------------------------------------------------------------------------------- 1 | import { Agent as HttpAgent } from "http"; 2 | import { Agent as HttpsAgent } from "https"; 3 | 4 | export declare function fetch( 5 | input?: RequestInfo, 6 | init?: RequestInit 7 | ): Promise; 8 | 9 | export type RequestAgent = HttpAgent | HttpsAgent; 10 | 11 | export type RequestInfo = Request | string; 12 | 13 | export declare class Headers implements Iterable<[string, string]> { 14 | constructor(init?: HeadersInit); 15 | 16 | append(name: string, value: string): void; 17 | delete(name: string): void; 18 | get(name: string): string | null; 19 | has(name: string): boolean; 20 | set(name: string, value: string): void; 21 | 22 | entries(): Iterator<[string, string]>; 23 | keys(): Iterator; 24 | values(): Iterator<[string]>; 25 | [Symbol.iterator](): Iterator<[string, string]>; 26 | } 27 | 28 | export type HeadersInit = Headers | string[][] | { [name: string]: string }; 29 | 30 | export declare class Body { 31 | readonly bodyUsed: boolean; 32 | arrayBuffer(): Promise; 33 | json(): Promise; 34 | text(): Promise; 35 | } 36 | 37 | export declare class Request extends Body { 38 | constructor(input: Request | string, init?: RequestInit); 39 | 40 | readonly method: string; 41 | readonly url: string; 42 | readonly headers: Headers; 43 | 44 | clone(): Request; 45 | } 46 | 47 | export interface RequestInit { 48 | method?: string; 49 | headers?: HeadersInit; 50 | body?: BodyInit; 51 | mode?: RequestMode; 52 | credentials?: RequestCredentials; 53 | cache?: RequestCache; 54 | redirect?: RequestRedirect; 55 | referrer?: string; 56 | referrerPolicy?: ReferrerPolicy; 57 | integrity?: string; 58 | 59 | // The following properties are node-fetch extensions 60 | follow?: number; 61 | timeout?: number; 62 | compress?: boolean; 63 | size?: number; 64 | agent?: RequestAgent | false; 65 | 66 | // Cloudflare Workers accept a `cf` property to control Cloudflare features 67 | // See https://developers.cloudflare.com/workers/reference/cloudflare-features/ 68 | cf?: { 69 | [key: string]: any; 70 | }; 71 | } 72 | 73 | export type RequestMode = "navigate" | "same-origin" | "no-cors" | "cors"; 74 | 75 | export type RequestCredentials = "omit" | "same-origin" | "include"; 76 | 77 | export type RequestCache = 78 | | "default" 79 | | "no-store" 80 | | "reload" 81 | | "no-cache" 82 | | "force-cache" 83 | | "only-if-cached"; 84 | 85 | export type RequestRedirect = "follow" | "error" | "manual"; 86 | 87 | export type ReferrerPolicy = 88 | | "" 89 | | "no-referrer" 90 | | "no-referrer-when-downgrade" 91 | | "same-origin" 92 | | "origin" 93 | | "strict-origin" 94 | | "origin-when-cross-origin" 95 | | "strict-origin-when-cross-origin" 96 | | "unsafe-url"; 97 | 98 | export declare class Response extends Body { 99 | constructor(body?: BodyInit, init?: ResponseInit); 100 | static error(): Response; 101 | static redirect(url: string, status?: number): Response; 102 | 103 | readonly url: string; 104 | readonly redirected: boolean; 105 | readonly status: number; 106 | readonly ok: boolean; 107 | readonly statusText: string; 108 | readonly headers: Headers; 109 | 110 | clone(): Response; 111 | } 112 | 113 | export interface ResponseInit { 114 | headers?: HeadersInit; 115 | status?: number; 116 | statusText?: string; 117 | // Although this isn't part of the spec, `node-fetch` accepts a `url` property 118 | url?: string; 119 | } 120 | 121 | export type BodyInit = ArrayBuffer | ArrayBufferView | string; 122 | -------------------------------------------------------------------------------- /packages/apollo-codegen-scala/src/naming.ts: -------------------------------------------------------------------------------- 1 | import { camelCase, pascalCase } from "change-case"; 2 | import * as Inflector from "inflected"; 3 | 4 | import { join } from "apollo-codegen-core/lib/utilities/printing"; 5 | 6 | import { escapeIdentifierIfNeeded, Property } from "./language"; 7 | 8 | import { typeNameFromGraphQLType } from "./types"; 9 | 10 | import { 11 | GraphQLList, 12 | GraphQLNonNull, 13 | getNamedType, 14 | isCompositeType 15 | } from "graphql"; 16 | import { 17 | LegacyCompilerContext, 18 | LegacyField, 19 | LegacyInlineFragment 20 | } from "apollo-codegen-core/lib/compiler/legacyIR"; 21 | import { GraphQLInputField } from "graphql"; 22 | 23 | export function enumCaseName(name: string) { 24 | return camelCase(name); 25 | } 26 | 27 | export function operationClassName(name: string) { 28 | return pascalCase(name); 29 | } 30 | 31 | export function traitNameForPropertyName(propertyName: string) { 32 | return pascalCase(Inflector.singularize(propertyName)); 33 | } 34 | 35 | export function traitNameForFragmentName(fragmentName: string) { 36 | return pascalCase(fragmentName); 37 | } 38 | 39 | export function traitNameForInlineFragment( 40 | inlineFragment: LegacyInlineFragment 41 | ) { 42 | return "As" + pascalCase(String(inlineFragment.typeCondition)); 43 | } 44 | 45 | export function propertyFromInputField( 46 | context: LegacyCompilerContext, 47 | field: GraphQLInputField, 48 | namespace?: string, 49 | parentTraitName?: string 50 | ): GraphQLInputField & Property { 51 | const name = field.name; 52 | const unescapedPropertyName = isMetaFieldName(name) ? name : camelCase(name); 53 | const propertyName = escapeIdentifierIfNeeded(unescapedPropertyName); 54 | 55 | const type = field.type; 56 | const isList = type instanceof GraphQLList || type instanceof GraphQLList; 57 | const isOptional = !(type instanceof GraphQLNonNull); 58 | const bareType = getNamedType(type); 59 | 60 | const bareTypeName = isCompositeType(bareType) 61 | ? join( 62 | [ 63 | namespace, 64 | parentTraitName, 65 | escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name))) 66 | ], 67 | "." 68 | ) 69 | : undefined; 70 | const typeName = typeNameFromGraphQLType( 71 | context, 72 | type, 73 | bareTypeName, 74 | isOptional, 75 | true 76 | ); 77 | return { 78 | ...field, 79 | propertyName, 80 | typeName, 81 | isOptional, 82 | isList, 83 | description: field.description || undefined 84 | }; 85 | } 86 | 87 | export function propertyFromLegacyField( 88 | context: LegacyCompilerContext, 89 | field: LegacyField, 90 | namespace?: string, 91 | parentTraitName?: string 92 | ): LegacyField & Property { 93 | const name = field.responseName; 94 | const propertyName = escapeIdentifierIfNeeded(name); 95 | 96 | const type = field.type; 97 | const isList = type instanceof GraphQLList || type instanceof GraphQLList; 98 | const isOptional = field.isConditional || !(type instanceof GraphQLNonNull); 99 | const bareType = getNamedType(type); 100 | 101 | const bareTypeName = isCompositeType(bareType) 102 | ? join( 103 | [ 104 | namespace, 105 | parentTraitName, 106 | escapeIdentifierIfNeeded(pascalCase(Inflector.singularize(name))) 107 | ], 108 | "." 109 | ) 110 | : undefined; 111 | const typeName = typeNameFromGraphQLType( 112 | context, 113 | type, 114 | bareTypeName, 115 | isOptional 116 | ); 117 | return { ...field, propertyName, typeName, isOptional, isList }; 118 | } 119 | 120 | function isMetaFieldName(name: string) { 121 | return name.startsWith("__"); 122 | } 123 | -------------------------------------------------------------------------------- /packages/apollo-language-server/src/utilities/source.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Source, 3 | ASTNode, 4 | Kind, 5 | visit, 6 | BREAK, 7 | TypeInfo, 8 | GraphQLSchema 9 | } from "graphql"; 10 | import { SourceLocation, getLocation } from "graphql/language/location"; 11 | 12 | import { Position, Range } from "vscode-languageserver"; 13 | 14 | import { visitWithTypeInfo } from "graphql"; 15 | 16 | export function positionFromPositionInContainingDocument( 17 | source: Source, 18 | position: Position 19 | ) { 20 | if (!source.locationOffset) return position; 21 | return Position.create( 22 | position.line - (source.locationOffset.line - 1), 23 | position.character 24 | ); 25 | } 26 | 27 | export function positionInContainingDocument( 28 | source: Source, 29 | position: Position 30 | ): Position { 31 | if (!source.locationOffset) return position; 32 | return Position.create( 33 | source.locationOffset.line - 1 + position.line, 34 | position.character 35 | ); 36 | } 37 | 38 | export function rangeInContainingDocument(source: Source, range: Range): Range { 39 | if (!source.locationOffset) return range; 40 | return Range.create( 41 | positionInContainingDocument(source, range.start), 42 | positionInContainingDocument(source, range.end) 43 | ); 44 | } 45 | 46 | export function rangeForASTNode(node: ASTNode): Range { 47 | const location = node.loc!; 48 | const source = location.source; 49 | 50 | return Range.create( 51 | positionFromSourceLocation(source, getLocation(source, location.start)), 52 | positionFromSourceLocation(source, getLocation(source, location.end)) 53 | ); 54 | } 55 | 56 | export function positionFromSourceLocation( 57 | source: Source, 58 | location: SourceLocation 59 | ) { 60 | return Position.create( 61 | (source.locationOffset ? source.locationOffset.line - 1 : 0) + 62 | location.line - 63 | 1, 64 | (source.locationOffset && location.line === 1 65 | ? source.locationOffset.column - 1 66 | : 0) + 67 | location.column - 68 | 1 69 | ); 70 | } 71 | 72 | export function positionToOffset(source: Source, position: Position): number { 73 | const lineRegexp = /\r\n|[\n\r]/g; 74 | 75 | const linesUntilPosition = source.body 76 | .split(lineRegexp) 77 | .slice(0, position.line); 78 | return ( 79 | position.character + 80 | linesUntilPosition 81 | .map( 82 | line => line.length + 1 // count EOL 83 | ) 84 | .reduce((a, b) => a + b, 0) 85 | ); 86 | } 87 | 88 | export function getASTNodeAndTypeInfoAtPosition( 89 | source: Source, 90 | position: Position, 91 | root: ASTNode, 92 | schema: GraphQLSchema 93 | ): [ASTNode, TypeInfo] | null { 94 | const offset = positionToOffset(source, position); 95 | 96 | let nodeContainingPosition: ASTNode | null = null; 97 | 98 | const typeInfo = new TypeInfo(schema); 99 | visit( 100 | root, 101 | visitWithTypeInfo(typeInfo, { 102 | enter(node: ASTNode) { 103 | if ( 104 | node.kind !== Kind.NAME && // We're usually interested in their parents 105 | node.loc && 106 | node.loc.start <= offset && 107 | offset <= node.loc.end 108 | ) { 109 | nodeContainingPosition = node; 110 | } else { 111 | return false; 112 | } 113 | return; 114 | }, 115 | leave(node: ASTNode) { 116 | if (node.loc && node.loc.start <= offset && offset <= node.loc.end) { 117 | return BREAK; 118 | } 119 | return; 120 | } 121 | }) 122 | ); 123 | 124 | if (nodeContainingPosition) { 125 | return [nodeContainingPosition, typeInfo]; 126 | } else { 127 | return null; 128 | } 129 | } 130 | --------------------------------------------------------------------------------