Mirror: TypeScript LSP plugin that finds GraphQL documents in your code and provides diagnostics, auto-complete and hover-information.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

resolve introspection from url (#26)

authored by

Jovi De Croock and committed by
GitHub
b9aa659c 80d59f61

+329 -91
+5
.changeset/five-dancers-refuse.md
··· 1 + --- 2 + '@0no-co/graphqlsp': minor 3 + --- 4 + 5 + Add ability to specify a URL for your schema, GraphQLSP will then fetch the introspection from the specified URL
+174 -63
example/src/index.generated.ts
··· 1 1 import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; 2 2 export type Maybe<T> = T | null; 3 3 export type InputMaybe<T> = Maybe<T>; 4 - export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] }; 5 - export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> }; 6 - export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> }; 4 + export type Exact<T extends { [key: string]: unknown }> = { 5 + [K in keyof T]: T[K]; 6 + }; 7 + export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { 8 + [SubKey in K]?: Maybe<T[SubKey]>; 9 + }; 10 + export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { 11 + [SubKey in K]: Maybe<T[SubKey]>; 12 + }; 7 13 /** All built-in and custom scalars, mapped to their actual values */ 8 14 export type Scalars = { 9 15 ID: string; ··· 13 19 Float: number; 14 20 }; 15 21 22 + /** Elemental property associated with either a Pokémon or one of their moves. */ 23 + export type PokemonType = 24 + | 'Grass' 25 + | 'Poison' 26 + | 'Fire' 27 + | 'Flying' 28 + | 'Water' 29 + | 'Bug' 30 + | 'Normal' 31 + | 'Electric' 32 + | 'Ground' 33 + | 'Fairy' 34 + | 'Fighting' 35 + | 'Psychic' 36 + | 'Rock' 37 + | 'Steel' 38 + | 'Ice' 39 + | 'Ghost' 40 + | 'Dragon' 41 + | 'Dark'; 42 + 16 43 /** Move a Pokémon can perform with the associated damage and type. */ 17 44 export type Attack = { 18 45 __typename?: 'Attack'; 19 - damage?: Maybe<Scalars['Int']>; 20 46 name?: Maybe<Scalars['String']>; 21 47 type?: Maybe<PokemonType>; 22 - }; 23 - 24 - export type AttacksConnection = { 25 - __typename?: 'AttacksConnection'; 26 - fast?: Maybe<Array<Maybe<Attack>>>; 27 - special?: Maybe<Array<Maybe<Attack>>>; 48 + damage?: Maybe<Scalars['Int']>; 28 49 }; 29 50 30 51 /** Requirement that prevents an evolution through regular means of levelling up. */ ··· 34 55 name?: Maybe<Scalars['String']>; 35 56 }; 36 57 58 + export type PokemonDimension = { 59 + __typename?: 'PokemonDimension'; 60 + minimum?: Maybe<Scalars['String']>; 61 + maximum?: Maybe<Scalars['String']>; 62 + }; 63 + 64 + export type AttacksConnection = { 65 + __typename?: 'AttacksConnection'; 66 + fast?: Maybe<Array<Maybe<Attack>>>; 67 + special?: Maybe<Array<Maybe<Attack>>>; 68 + }; 69 + 37 70 export type Pokemon = { 38 71 __typename?: 'Pokemon'; 39 - attacks?: Maybe<AttacksConnection>; 40 - /** @deprecated And this is the reason why */ 72 + id: Scalars['ID']; 73 + name: Scalars['String']; 41 74 classification?: Maybe<Scalars['String']>; 75 + types?: Maybe<Array<Maybe<PokemonType>>>; 76 + resistant?: Maybe<Array<Maybe<PokemonType>>>; 77 + weaknesses?: Maybe<Array<Maybe<PokemonType>>>; 42 78 evolutionRequirements?: Maybe<Array<Maybe<EvolutionRequirement>>>; 43 - evolutions?: Maybe<Array<Maybe<Pokemon>>>; 79 + weight?: Maybe<PokemonDimension>; 80 + height?: Maybe<PokemonDimension>; 81 + attacks?: Maybe<AttacksConnection>; 44 82 /** Likelihood of an attempt to catch a Pokémon to fail. */ 45 83 fleeRate?: Maybe<Scalars['Float']>; 46 - height?: Maybe<PokemonDimension>; 47 - id: Scalars['ID']; 48 84 /** Maximum combat power a Pokémon may achieve at max level. */ 49 85 maxCP?: Maybe<Scalars['Int']>; 50 86 /** Maximum health points a Pokémon may achieve at max level. */ 51 87 maxHP?: Maybe<Scalars['Int']>; 52 - name: Scalars['String']; 53 - resistant?: Maybe<Array<Maybe<PokemonType>>>; 54 - types?: Maybe<Array<Maybe<PokemonType>>>; 55 - weaknesses?: Maybe<Array<Maybe<PokemonType>>>; 56 - weight?: Maybe<PokemonDimension>; 57 - }; 58 - 59 - export type PokemonDimension = { 60 - __typename?: 'PokemonDimension'; 61 - maximum?: Maybe<Scalars['String']>; 62 - minimum?: Maybe<Scalars['String']>; 88 + evolutions?: Maybe<Array<Maybe<Pokemon>>>; 63 89 }; 64 90 65 - /** Elemental property associated with either a Pokémon or one of their moves. */ 66 - export type PokemonType = 67 - | 'Bug' 68 - | 'Dark' 69 - | 'Dragon' 70 - | 'Electric' 71 - | 'Fairy' 72 - | 'Fighting' 73 - | 'Fire' 74 - | 'Flying' 75 - | 'Ghost' 76 - | 'Grass' 77 - | 'Ground' 78 - | 'Ice' 79 - | 'Normal' 80 - | 'Poison' 81 - | 'Psychic' 82 - | 'Rock' 83 - | 'Steel' 84 - | 'Water'; 85 - 86 91 export type Query = { 87 92 __typename?: 'Query'; 93 + /** List out all Pokémon, optionally in pages */ 94 + pokemons?: Maybe<Array<Maybe<Pokemon>>>; 88 95 /** Get a single Pokémon by its ID, a three character long identifier padded with zeroes */ 89 96 pokemon?: Maybe<Pokemon>; 90 - /** List out all Pokémon, optionally in pages */ 91 - pokemons?: Maybe<Array<Maybe<Pokemon>>>; 92 97 }; 93 98 99 + export type QueryPokemonsArgs = { 100 + limit?: InputMaybe<Scalars['Int']>; 101 + skip?: InputMaybe<Scalars['Int']>; 102 + }; 94 103 95 104 export type QueryPokemonArgs = { 96 105 id: Scalars['ID']; 97 106 }; 98 107 108 + export type PokemonsQueryVariables = Exact<{ [key: string]: never }>; 99 109 100 - export type QueryPokemonsArgs = { 101 - limit?: InputMaybe<Scalars['Int']>; 102 - skip?: InputMaybe<Scalars['Int']>; 110 + export type PokemonsQuery = { 111 + __typename?: 'Query'; 112 + pokemons?: Array<{ 113 + __typename: 'Pokemon'; 114 + id: string; 115 + name: string; 116 + } | null> | null; 103 117 }; 104 118 105 - export type PokemonsQueryVariables = Exact<{ [key: string]: never; }>; 106 - 107 - 108 - export type PokemonsQuery = { __typename?: 'Query', pokemons?: Array<{ __typename: 'Pokemon', id: string, name: string } | null> | null }; 109 - 110 - export type PokemonFieldsFragment = { __typename?: 'Pokemon', id: string, name: string }; 119 + export type PokemonFieldsFragment = { 120 + __typename?: 'Pokemon'; 121 + id: string; 122 + name: string; 123 + }; 111 124 112 125 export type PokemonQueryVariables = Exact<{ 113 126 id: Scalars['ID']; 114 127 }>; 115 128 129 + export type PokemonQuery = { 130 + __typename?: 'Query'; 131 + pokemon?: { __typename: 'Pokemon'; id: string; name: string } | null; 132 + }; 116 133 117 - export type PokemonQuery = { __typename?: 'Query', pokemon?: { __typename: 'Pokemon', id: string, name: string } | null }; 118 - 119 - export const PokemonFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"pokemonFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Pokemon"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode<PokemonFieldsFragment, unknown>; 120 - export const PokemonsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Pokemons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pokemons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"pokemonFields"}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}}]}},...PokemonFieldsFragmentDoc.definitions]} as unknown as DocumentNode<PokemonsQuery, PokemonsQueryVariables>; 121 - export const PokemonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Pokemon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pokemon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"__typename"}}]}}]}}]} as unknown as DocumentNode<PokemonQuery, PokemonQueryVariables>; 134 + export const PokemonFieldsFragmentDoc = { 135 + kind: 'Document', 136 + definitions: [ 137 + { 138 + kind: 'FragmentDefinition', 139 + name: { kind: 'Name', value: 'pokemonFields' }, 140 + typeCondition: { 141 + kind: 'NamedType', 142 + name: { kind: 'Name', value: 'Pokemon' }, 143 + }, 144 + selectionSet: { 145 + kind: 'SelectionSet', 146 + selections: [ 147 + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, 148 + { kind: 'Field', name: { kind: 'Name', value: 'name' } }, 149 + ], 150 + }, 151 + }, 152 + ], 153 + } as unknown as DocumentNode<PokemonFieldsFragment, unknown>; 154 + export const PokemonsDocument = { 155 + kind: 'Document', 156 + definitions: [ 157 + { 158 + kind: 'OperationDefinition', 159 + operation: 'query', 160 + name: { kind: 'Name', value: 'Pokemons' }, 161 + selectionSet: { 162 + kind: 'SelectionSet', 163 + selections: [ 164 + { 165 + kind: 'Field', 166 + name: { kind: 'Name', value: 'pokemons' }, 167 + selectionSet: { 168 + kind: 'SelectionSet', 169 + selections: [ 170 + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, 171 + { kind: 'Field', name: { kind: 'Name', value: 'name' } }, 172 + { 173 + kind: 'FragmentSpread', 174 + name: { kind: 'Name', value: 'pokemonFields' }, 175 + }, 176 + { kind: 'Field', name: { kind: 'Name', value: '__typename' } }, 177 + ], 178 + }, 179 + }, 180 + ], 181 + }, 182 + }, 183 + ...PokemonFieldsFragmentDoc.definitions, 184 + ], 185 + } as unknown as DocumentNode<PokemonsQuery, PokemonsQueryVariables>; 186 + export const PokemonDocument = { 187 + kind: 'Document', 188 + definitions: [ 189 + { 190 + kind: 'OperationDefinition', 191 + operation: 'query', 192 + name: { kind: 'Name', value: 'Pokemon' }, 193 + variableDefinitions: [ 194 + { 195 + kind: 'VariableDefinition', 196 + variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } }, 197 + type: { 198 + kind: 'NonNullType', 199 + type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } }, 200 + }, 201 + }, 202 + ], 203 + selectionSet: { 204 + kind: 'SelectionSet', 205 + selections: [ 206 + { 207 + kind: 'Field', 208 + name: { kind: 'Name', value: 'pokemon' }, 209 + arguments: [ 210 + { 211 + kind: 'Argument', 212 + name: { kind: 'Name', value: 'id' }, 213 + value: { 214 + kind: 'Variable', 215 + name: { kind: 'Name', value: 'id' }, 216 + }, 217 + }, 218 + ], 219 + selectionSet: { 220 + kind: 'SelectionSet', 221 + selections: [ 222 + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, 223 + { kind: 'Field', name: { kind: 'Name', value: 'name' } }, 224 + { kind: 'Field', name: { kind: 'Name', value: '__typename' } }, 225 + ], 226 + }, 227 + }, 228 + ], 229 + }, 230 + }, 231 + ], 232 + } as unknown as DocumentNode<PokemonQuery, PokemonQueryVariables>;
+12 -10
example/tsconfig.json
··· 1 1 { 2 2 "compilerOptions": { 3 - "plugins": [{ 4 - "name": "plugin", 5 - "schema": "./schema.graphql" 6 - }], 3 + "plugins": [ 4 + { 5 + "name": "plugin", 6 + "schema": "https://trygql.formidable.dev/graphql/basic-pokedex" 7 + } 8 + ], 7 9 /* Visit https://aka.ms/tsconfig to read more about this file */ 8 10 9 11 /* Projects */ ··· 15 17 // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 16 18 17 19 /* Language and Environment */ 18 - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 20 + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 19 21 // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 20 22 // "jsx": "preserve", /* Specify what JSX code is generated. */ 21 23 // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ ··· 29 31 // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 30 32 31 33 /* Modules */ 32 - "module": "commonjs", /* Specify what module code is generated. */ 34 + "module": "commonjs" /* Specify what module code is generated. */, 33 35 // "rootDir": "./", /* Specify the root folder within your source files. */ 34 36 // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 35 37 // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ ··· 75 77 /* Interop Constraints */ 76 78 // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 77 79 // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 78 - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 80 + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 79 81 // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 80 - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 82 + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 81 83 82 84 /* Type Checking */ 83 - "strict": true, /* Enable all strict type-checking options. */ 85 + "strict": true /* Enable all strict type-checking options. */, 84 86 // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 85 87 // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 86 88 // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ ··· 102 104 103 105 /* Completeness */ 104 106 // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 105 - "skipLibCheck": true /* Skip type checking all .d.ts files. */ 107 + "skipLibCheck": true /* Skip type checking all .d.ts files. */ 106 108 } 107 109 }
+9 -1
example/yarn.lock
··· 1209 1209 dependencies: 1210 1210 whatwg-url "^5.0.0" 1211 1211 1212 + node-fetch@^2.0.0: 1213 + version "2.6.9" 1214 + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" 1215 + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== 1216 + dependencies: 1217 + whatwg-url "^5.0.0" 1218 + 1212 1219 node-int64@^0.4.0: 1213 1220 version "0.4.0" 1214 1221 resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" ··· 1316 1323 integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 1317 1324 1318 1325 "plugin@file:..": 1319 - version "1.0.0" 1326 + version "0.1.0" 1320 1327 dependencies: 1321 1328 "@graphql-codegen/core" "^2.6.8" 1322 1329 "@graphql-codegen/typed-document-node" "^2.3.10" 1323 1330 "@graphql-codegen/typescript" "^2.8.5" 1324 1331 "@graphql-codegen/typescript-operations" "^2.5.10" 1325 1332 graphql-language-service "^5.0.6" 1333 + node-fetch "^2.0.0" 1326 1334 1327 1335 promise@^7.1.1: 1328 1336 version "7.3.1"
+3 -1
package.json
··· 38 38 "@rollup/plugin-terser": "^0.4.1", 39 39 "@rollup/plugin-typescript": "^11.1.0", 40 40 "@types/node": "^18.15.11", 41 + "@types/node-fetch": "^2.6.3", 41 42 "dotenv": "^16.0.3", 42 43 "graphql": "^16.5.0", 43 44 "husky": "^8.0.3", ··· 51 52 "@graphql-codegen/typed-document-node": "^2.3.10", 52 53 "@graphql-codegen/typescript": "^2.8.5", 53 54 "@graphql-codegen/typescript-operations": "^2.5.10", 54 - "graphql-language-service": "^5.0.6" 55 + "graphql-language-service": "^5.0.6", 56 + "node-fetch": "^2.0.0" 55 57 } 56 58 }
+50
pnpm-lock.yaml
··· 16 16 graphql-language-service: 17 17 specifier: ^5.0.6 18 18 version: 5.0.6(graphql@16.5.0) 19 + node-fetch: 20 + specifier: ^2.0.0 21 + version: 2.6.7 19 22 20 23 devDependencies: 21 24 '@changesets/cli': ··· 33 36 '@types/node': 34 37 specifier: ^18.15.11 35 38 version: 18.15.11 39 + '@types/node-fetch': 40 + specifier: ^2.6.3 41 + version: 2.6.3 36 42 dotenv: 37 43 specifier: ^16.0.3 38 44 version: 16.0.3 ··· 1150 1156 resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} 1151 1157 dev: true 1152 1158 1159 + /@types/node-fetch@2.6.3: 1160 + resolution: {integrity: sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==} 1161 + dependencies: 1162 + '@types/node': 18.15.11 1163 + form-data: 3.0.1 1164 + dev: true 1165 + 1153 1166 /@types/node@12.20.55: 1154 1167 resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} 1155 1168 dev: true ··· 1258 1271 /astral-regex@2.0.0: 1259 1272 resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} 1260 1273 engines: {node: '>=8'} 1274 + dev: true 1275 + 1276 + /asynckit@0.4.0: 1277 + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 1261 1278 dev: true 1262 1279 1263 1280 /auto-bind@4.0.0: ··· 1533 1550 resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} 1534 1551 dev: true 1535 1552 1553 + /combined-stream@1.0.8: 1554 + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 1555 + engines: {node: '>= 0.8'} 1556 + dependencies: 1557 + delayed-stream: 1.0.0 1558 + dev: true 1559 + 1536 1560 /commander@10.0.0: 1537 1561 resolution: {integrity: sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==} 1538 1562 engines: {node: '>=14'} ··· 1651 1675 object-keys: 1.1.1 1652 1676 dev: true 1653 1677 1678 + /delayed-stream@1.0.0: 1679 + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 1680 + engines: {node: '>=0.4.0'} 1681 + dev: true 1682 + 1654 1683 /dependency-graph@0.11.0: 1655 1684 resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==} 1656 1685 engines: {node: '>= 0.6.0'} ··· 1892 1921 resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} 1893 1922 dependencies: 1894 1923 is-callable: 1.2.7 1924 + dev: true 1925 + 1926 + /form-data@3.0.1: 1927 + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} 1928 + engines: {node: '>= 6'} 1929 + dependencies: 1930 + asynckit: 0.4.0 1931 + combined-stream: 1.0.8 1932 + mime-types: 2.1.35 1895 1933 dev: true 1896 1934 1897 1935 /fs-extra@7.0.1: ··· 2580 2618 dependencies: 2581 2619 braces: 3.0.2 2582 2620 picomatch: 2.3.1 2621 + dev: true 2622 + 2623 + /mime-db@1.52.0: 2624 + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 2625 + engines: {node: '>= 0.6'} 2626 + dev: true 2627 + 2628 + /mime-types@2.1.35: 2629 + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 2630 + engines: {node: '>= 0.6'} 2631 + dependencies: 2632 + mime-db: 1.52.0 2583 2633 dev: true 2584 2634 2585 2635 /mimic-fn@2.1.0:
+67 -11
src/getSchema.ts
··· 1 - import { GraphQLSchema, buildSchema, buildClientSchema } from 'graphql'; 1 + import { 2 + GraphQLSchema, 3 + buildSchema, 4 + buildClientSchema, 5 + getIntrospectionQuery, 6 + IntrospectionQuery, 7 + } from 'graphql'; 8 + import fetch from 'node-fetch'; 2 9 import path from 'path'; 3 10 import fs from 'fs'; 4 11 12 + import { Logger } from './index'; 13 + 5 14 export const loadSchema = ( 6 15 root: string, 7 - schema: string 16 + schema: string, 17 + logger: Logger 8 18 ): { current: GraphQLSchema | null } => { 9 19 const ref: { current: GraphQLSchema | null } = { current: null }; 10 - const isJson = schema.endsWith('json'); 11 - const resolvedPath = path.resolve(path.dirname(root), schema); 12 - const contents = fs.readFileSync(resolvedPath, 'utf-8'); 20 + let url: URL | undefined; 21 + 22 + try { 23 + url = new URL(schema); 24 + } catch (e) {} 13 25 14 - fs.watchFile(resolvedPath, () => { 26 + if (url) { 27 + logger(`Fetching introspection from ${url.toString()}`); 28 + fetch(url.toString(), { 29 + method: 'POST', 30 + headers: { 31 + 'Content-Type': 'application/json', 32 + }, 33 + body: JSON.stringify({ 34 + query: getIntrospectionQuery({ 35 + descriptions: true, 36 + schemaDescription: true, 37 + inputValueDeprecation: false, 38 + directiveIsRepeatable: false, 39 + specifiedByUrl: false, 40 + }), 41 + }), 42 + }) 43 + .then(response => { 44 + logger(`Got response ${response.statusText} ${response.status}`); 45 + if (response.ok) return response.json(); 46 + else return response.text(); 47 + }) 48 + .then(result => { 49 + if (typeof result === 'string') { 50 + logger(`Got error while fetching introspection ${result}`); 51 + } else { 52 + try { 53 + ref.current = buildClientSchema( 54 + (result as { data: IntrospectionQuery }).data 55 + ); 56 + logger(`Got schema for ${url!.toString()}`); 57 + } catch (e: any) { 58 + logger(`Got schema error for ${e.message}`); 59 + } 60 + } 61 + }); 62 + } else { 63 + const isJson = schema.endsWith('json'); 64 + const resolvedPath = path.resolve(path.dirname(root), schema); 65 + logger(`Getting schema from ${resolvedPath}`); 15 66 const contents = fs.readFileSync(resolvedPath, 'utf-8'); 67 + 68 + fs.watchFile(resolvedPath, () => { 69 + const contents = fs.readFileSync(resolvedPath, 'utf-8'); 70 + ref.current = isJson 71 + ? buildClientSchema(JSON.parse(contents)) 72 + : buildSchema(contents); 73 + }); 74 + 16 75 ref.current = isJson 17 76 ? buildClientSchema(JSON.parse(contents)) 18 77 : buildSchema(contents); 19 - }); 20 - 21 - ref.current = isJson 22 - ? buildClientSchema(JSON.parse(contents)) 23 - : buildSchema(contents); 78 + logger(`Got schema and initialized watcher for ${schema}`); 79 + } 24 80 25 81 return ref; 26 82 };
+9 -5
src/index.ts
··· 43 43 return proxy; 44 44 } 45 45 46 + export type Logger = (msg: string) => void; 47 + 46 48 function create(info: ts.server.PluginCreateInfo) { 47 - const logger = (msg: string) => 49 + const logger: Logger = (msg: string) => 48 50 info.project.projectService.logger.info(`[ts-graphql-plugin] ${msg}`); 49 51 logger('config: ' + JSON.stringify(info.config)); 50 52 if (!info.config.schema) { 51 53 throw new Error('Please provide a GraphQL Schema!'); 52 54 } 53 55 54 - info.project.projectService.logger.info('Setting up the GraphQL Plugin'); 56 + logger('Setting up the GraphQL Plugin'); 55 57 56 58 const tagTemplate = info.config.template || 'gql'; 57 59 const scalars = info.config.scalars || {}; 58 60 59 61 const proxy = createBasicDecorator(info); 60 62 61 - // TODO: check out interesting stuff on ts.factory 62 - 63 - const schema = loadSchema(info.project.getProjectName(), info.config.schema); 63 + const schema = loadSchema( 64 + info.project.getProjectName(), 65 + info.config.schema, 66 + logger 67 + ); 64 68 65 69 proxy.getSemanticDiagnostics = (filename: string): ts.Diagnostic[] => { 66 70 const originalDiagnostics =