Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into pr/api-extractor
Browse files Browse the repository at this point in the history
  • Loading branch information
phryneas committed Sep 14, 2023
2 parents be151b0 + d73c738 commit ebad71b
Show file tree
Hide file tree
Showing 44 changed files with 1,856 additions and 1,575 deletions.
18 changes: 14 additions & 4 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "import"],
"plugins": ["@typescript-eslint", "import", "local-rules"],
"env": {
"browser": true,
"node": true,
Expand Down Expand Up @@ -52,15 +52,25 @@
"ignorePackages": true,
"checkTypeImports": true
}
]
],
"local-rules/require-using-disposable": "error"
}
},
{
"files": ["**/__tests__/**/*.[jt]sx", "**/?(*.)+(test).[jt]sx"],
"files": [
"**/__tests__/**/*.[jt]s",
"**/__tests__/**/*.[jt]sx",
"**/?(*.)+(test).[jt]s",
"**/?(*.)+(test).[jt]sx"
],
"extends": ["plugin:testing-library/react"],
"parserOptions": {
"project": "./tsconfig.tests.json"
},
"rules": {
"testing-library/prefer-user-event": "error",
"testing-library/no-wait-for-multiple-assertions": "off"
"testing-library/no-wait-for-multiple-assertions": "off",
"local-rules/require-using-disposable": "error"
}
}
],
Expand Down
8 changes: 3 additions & 5 deletions config/version.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,9 @@ switch (process.argv[2]) {
}

case "verify": {
const { ApolloClient, InMemoryCache } = require(path.join(
distRoot,
"core",
"core.cjs"
));
const { ApolloClient, InMemoryCache } = require(
path.join(distRoot, "core", "core.cjs")
);

// Though this may seem like overkill, verifying that ApolloClient is
// constructible in Node.js is actually pretty useful, too!
Expand Down
41 changes: 41 additions & 0 deletions docs/source/caching/cache-configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,47 @@ This code also has the following drawbacks:
* It does nothing to protect against undefined object properties.
* Accidentally using different key fields at different times can cause inconsistencies in the cache.

### Customizing Type Policies

After creating an `InMemoryCache` instance, you can use the `addTypePolicies` method to add or modify type policies.

Here is an example of how to use the `addTypePolicies` method:

```ts
const cache = new InMemoryCache({
typePolicies: {
Person: {
fields: {
name: {
read(name = "UNKNOWN NAME") {
return name.toUpperCase();;
}
},
},
},
},
});

// Add a type policy to the cache.
cache.policies.addTypePolicies({
Person: {
fields: {
email: {
read(email = "[email protected]") {
return email;
},
},
},
},
});
```

The code creates an `InMemoryCache` with a custom type policy for the `Person` type. The type policy specifies that if the `name` field is not available in the cache, it should return a default value of "UNKNOWN NAME" and converts it to uppercase.

Then, the code adds an additional type policy to the cache using `cache.policies.addTypePolicies`. This new type policy is related to the `Person` type and its `email` field. The custom read function specifies that if the email field is not available in the cache, it should return a default value of "[email protected]".

Overall, the code sets up caching behaviors for the `Person` type, ensuring that default values are provided for the `name` and `email` fields if they are not present in the cache.

### Disabling normalization

You can instruct the `InMemoryCache` _not_ to normalize objects of a particular type. This can be useful for metrics and other transient data that's identified by a timestamp and never receives updates.
Expand Down
5 changes: 3 additions & 2 deletions docs/source/development-testing/static-typing.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Below, we'll guide you through installing and configuring GraphQL Code Generator
To get started using GraphQL Code Generator, begin by installing the following packages (using Yarn or NPM):

```bash
yarn add -D typescript @graphql-codegen/cli @graphql-codegen/client-preset
yarn add -D typescript @graphql-codegen/cli @graphql-codegen/client-preset @graphql-typed-document-node/core
```

Next, we'll create a configuration file for GraphQL Code Generator, named [`codegen.ts`](https://www.the-guild.dev/graphql/codegen/docs/config-reference/codegen-config), at the root of our project:
Expand All @@ -26,7 +26,8 @@ import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
schema: '<URL_OF_YOUR_GRAPHQL_API>',
documents: ['src/**/*.tsx'],
// this assumes that all your source files are in a top-level `src/` directory - you might need to adjust this to your file structure
documents: ['src/**/*.{ts,tsx}'],
generates: {
'./src/__generated__/': {
preset: 'client',
Expand Down
Empty file.
Empty file.
7 changes: 7 additions & 0 deletions eslint-local-rules/fixtures/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"strict": true,
"target": "esnext"
},
"include": ["file.ts", "react.tsx"]
}
14 changes: 14 additions & 0 deletions eslint-local-rules/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require("ts-node").register({
transpileOnly: true,
compilerOptions: {
// we need this to be nodenext in the tsconfig, because
// @typescript-eslint/utils only seems to export ESM
// in TypeScript's eyes, but it totally works
module: "commonjs",
moduleResolution: "node",
},
});

module.exports = {
"require-using-disposable": require("./require-using-disposable").rule,
};
5 changes: 5 additions & 0 deletions eslint-local-rules/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"scripts": {
"test": "node -r ts-node/register/transpile-only --no-warnings --test --watch *.test.ts"
}
}
31 changes: 31 additions & 0 deletions eslint-local-rules/require-using-disposable.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { rule } from "./require-using-disposable";
import { ruleTester } from "./testSetup";

ruleTester.run("require-using-disposable", rule, {
valid: [
`
function foo(): Disposable {}
using bar = foo()
`,
`
function foo(): AsyncDisposable {}
await using bar = foo()
`,
],
invalid: [
{
code: `
function foo(): Disposable {}
const bar = foo()
`,
errors: [{ messageId: "missingUsing" }],
},
{
code: `
function foo(): AsyncDisposable {}
const bar = foo()
`,
errors: [{ messageId: "missingAwaitUsing" }],
},
],
});
63 changes: 63 additions & 0 deletions eslint-local-rules/require-using-disposable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { ESLintUtils } from "@typescript-eslint/utils";
import ts from "typescript";
import * as utils from "ts-api-utils";

export const rule = ESLintUtils.RuleCreator.withoutDocs({
create(context) {
return {
VariableDeclaration(node) {
for (const declarator of node.declarations) {
if (!declarator.init) continue;
const services = ESLintUtils.getParserServices(context);
const type = services.getTypeAtLocation(declarator.init);
for (const typePart of parts(type)) {
if (!utils.isObjectType(typePart) || !typePart.symbol) {
continue;
}
if (
// bad check, but will do for now
// in the future, we should check for a `[Symbol.disposable]` property
// but I have no idea how to do that right now
typePart.symbol.escapedName === "Disposable" &&
node.kind != "using"
) {
context.report({
messageId: "missingUsing",
node: declarator,
});
}
if (
// similarly bad check
typePart.symbol.escapedName === "AsyncDisposable" &&
node.kind != "await using"
) {
context.report({
messageId: "missingAwaitUsing",
node: declarator,
});
}
}
}
},
};
},
meta: {
messages: {
missingUsing:
"Disposables should be allocated with `using <disposable>`.",
missingAwaitUsing:
"AsyncDisposables should be allocated with `await using <disposable>`.",
},
type: "suggestion",
schema: [],
},
defaultOptions: [],
});

function parts(type: ts.Type): ts.Type[] {
return type.isUnion()
? utils.unionTypeParts(type).flatMap(parts)
: type.isIntersection()
? utils.intersectionTypeParts(type).flatMap(parts)
: [type];
}
15 changes: 15 additions & 0 deletions eslint-local-rules/testSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { RuleTester } from "@typescript-eslint/rule-tester";
import nodeTest from "node:test";

RuleTester.it = nodeTest.it;
RuleTester.itOnly = nodeTest.only;
RuleTester.describe = nodeTest.describe;
RuleTester.afterAll = nodeTest.after;

export const ruleTester = new RuleTester({
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json",
tsconfigRootDir: __dirname + "/fixtures",
},
});
7 changes: 7 additions & 0 deletions eslint-local-rules/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"noEmit": true
}
}
Loading

0 comments on commit ebad71b

Please sign in to comment.