diff --git a/.changeset/wise-mangos-kick.md b/.changeset/wise-mangos-kick.md new file mode 100644 index 0000000..6377d81 --- /dev/null +++ b/.changeset/wise-mangos-kick.md @@ -0,0 +1,5 @@ +--- +'@0no-co/graphqlsp': patch +--- + +Add fix for nonNullAssertion and using Array.at diff --git a/packages/example-tada/src/index.tsx b/packages/example-tada/src/index.tsx index 6ddd4fa..edcd7e9 100644 --- a/packages/example-tada/src/index.tsx +++ b/packages/example-tada/src/index.tsx @@ -21,6 +21,12 @@ const PokemonQuery = graphql(` name __typename } + pokemons { + name + maxCP + maxHP + types + } } `, [PokemonFields]); @@ -30,6 +36,14 @@ const Pokemons = () => { variables: { id: '' } }); + const selected = result.data?.pokemons?.at(0)! + console.log(result.data?.pokemons?.at(0)?.maxCP) + console.log(selected.maxHP) + const names = result.data?.pokemons?.map(x => x?.name) + console.log(names) + const pos = result.data?.pokemons?.map(x => ({ ...x })) + console.log(pos && pos[0].types) + // Works console.log(result.data?.pokemon?.attacks && result.data?.pokemon?.attacks.special && result.data?.pokemon?.attacks.special[0] && result.data?.pokemon?.attacks.special[0].name) @@ -49,4 +63,3 @@ const Pokemons = () => { return ; } - diff --git a/packages/example-tada/tsconfig.json b/packages/example-tada/tsconfig.json index c1971a3..dcfaf25 100644 --- a/packages/example-tada/tsconfig.json +++ b/packages/example-tada/tsconfig.json @@ -4,9 +4,6 @@ { "name": "@0no-co/graphqlsp", "schema": "./schema.graphql", - "disableTypegen": true, - "shouldCheckForColocatedFragments": true, - "trackFieldUsage": true, "tadaOutputLocation": "./introspection.ts" } ], diff --git a/packages/graphqlsp/package.json b/packages/graphqlsp/package.json index 1c4a6e1..253287f 100644 --- a/packages/graphqlsp/package.json +++ b/packages/graphqlsp/package.json @@ -36,6 +36,7 @@ }, "homepage": "https://github.com/0no-co/GraphQLSP#readme", "devDependencies": { + "@0no-co/graphql.web": "^1.0.4", "@sindresorhus/fnv1a": "^2.0.0", "@types/node": "^18.15.11", "@types/node-fetch": "^2.6.3", diff --git a/packages/graphqlsp/src/fieldUsage.ts b/packages/graphqlsp/src/fieldUsage.ts index c7b0c3e..e53498a 100644 --- a/packages/graphqlsp/src/fieldUsage.ts +++ b/packages/graphqlsp/src/fieldUsage.ts @@ -69,6 +69,17 @@ const traverseDestructuring = ( return results; }; +const arrayMethods = new Set([ + 'map', + 'filter', + 'forEach', + 'reduce', + 'every', + 'some', + 'find', + 'flatMap', + 'sort', +]); const crawlScope = ( node: ts.Identifier | ts.BindingName, originalWip: Array, @@ -146,6 +157,52 @@ const crawlScope = ( !pathParts.includes(foundRef.text) ) { pathParts.push(foundRef.text); + } else if ( + ts.isPropertyAccessExpression(foundRef) && + foundRef.name.text === 'at' && + ts.isCallExpression(foundRef.parent) + ) { + foundRef = foundRef.parent; + } else if ( + ts.isPropertyAccessExpression(foundRef) && + arrayMethods.has(foundRef.name.text) && + ts.isCallExpression(foundRef.parent) + ) { + const isReduce = foundRef.name.text === 'reduce'; + const isSomeOrEvery = + foundRef.name.text === 'every' || foundRef.name.text === 'some'; + const callExpression = foundRef.parent; + const func = callExpression.arguments[0]; + if (ts.isFunctionExpression(func) || ts.isArrowFunction(func)) { + const param = func.parameters[isReduce ? 1 : 0]; + const res = crawlScope( + param.name, + pathParts, + allFields, + source, + info + ); + + // TODO: do we need to support variable destructuring here like + // .map being used in const [x] = list.map()? + if ( + ts.isVariableDeclaration(callExpression.parent) && + !isSomeOrEvery + ) { + const varRes = crawlScope( + callExpression.parent.name, + pathParts, + allFields, + source, + info + ); + res.push(...varRes); + } + + return res; + } else if (ts.isIdentifier(func)) { + // TODO: get the function and do the same as the above + } } else if ( ts.isPropertyAccessExpression(foundRef) && allFields.includes(foundRef.name.text) && @@ -161,7 +218,11 @@ const crawlScope = ( pathParts.push(foundRef.argumentExpression.text); } - foundRef = foundRef.parent; + if (ts.isNonNullExpression(foundRef.parent)) { + foundRef = foundRef.parent.parent; + } else { + foundRef = foundRef.parent; + } } return pathParts.join('.'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39c8a6f..809bafc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,6 +171,9 @@ importers: specifier: ^2.0.0 version: 2.6.7 devDependencies: + '@0no-co/graphql.web': + specifier: ^1.0.4 + version: 1.0.4(graphql@16.8.1) '@sindresorhus/fnv1a': specifier: ^2.0.0 version: 2.0.1 @@ -264,7 +267,6 @@ packages: optional: true dependencies: graphql: 16.8.1 - dev: false /@ampproject/remapping@2.2.1: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} @@ -3422,7 +3424,7 @@ packages: object-assign: 4.1.1 promise: 7.3.1 setimmediate: 1.0.5 - ua-parser-js: 1.0.37 + ua-parser-js: 0.7.37 transitivePeerDependencies: - encoding dev: true @@ -4587,7 +4589,7 @@ packages: dependencies: hosted-git-info: 2.8.9 resolve: 1.22.2 - semver: 7.5.4 + semver: 5.7.2 validate-npm-package-license: 3.0.4 dev: true @@ -5171,6 +5173,11 @@ packages: resolution: {integrity: sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==} dev: true + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + dev: true + /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -5687,8 +5694,8 @@ packages: hasBin: true dev: true - /ua-parser-js@1.0.37: - resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==} + /ua-parser-js@0.7.37: + resolution: {integrity: sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==} dev: true /ufo@1.3.1: