Skip to content

Commit 4604283

Browse files
authored
Add library exports and tests (#2)
2 parents 2727502 + 82b54e6 commit 4604283

15 files changed

+2101
-19
lines changed

.eslintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/node_modules
2+
/dist
3+
/__tests__/**/*.graphql

.eslintrc.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
module.exports = {
2+
parser: "@typescript-eslint/parser",
3+
extends: [
4+
"eslint:recommended",
5+
"plugin:@typescript-eslint/eslint-recommended",
6+
"plugin:@typescript-eslint/recommended",
7+
"plugin:import/errors",
8+
"plugin:import/typescript",
9+
"prettier",
10+
],
11+
plugins: ["@typescript-eslint", "simple-import-sort", "import"],
12+
parserOptions: {
13+
ecmaVersion: 2018,
14+
sourceType: "module",
15+
},
16+
env: {
17+
node: true,
18+
es6: true,
19+
},
20+
globals: {
21+
NodeJS: false, // For TypeScript
22+
},
23+
rules: {
24+
"no-unused-vars": 0,
25+
"@typescript-eslint/no-unused-vars": [
26+
"error",
27+
{
28+
argsIgnorePattern: "^_",
29+
varsIgnorePattern: "^_",
30+
args: "after-used",
31+
ignoreRestSiblings: true,
32+
},
33+
],
34+
curly: "error",
35+
"no-else-return": 0,
36+
"no-return-assign": [2, "except-parens"],
37+
"no-underscore-dangle": 0,
38+
camelcase: 0,
39+
"prefer-arrow-callback": [
40+
"error",
41+
{
42+
allowNamedFunctions: true,
43+
},
44+
],
45+
"class-methods-use-this": 0,
46+
"no-restricted-syntax": 0,
47+
"no-param-reassign": [
48+
"error",
49+
{
50+
props: false,
51+
},
52+
],
53+
54+
"arrow-body-style": 0,
55+
"no-nested-ternary": 0,
56+
57+
/*
58+
* simple-import-sort seems to be the most stable import sorting currently,
59+
* disable others
60+
*/
61+
"simple-import-sort/imports": "error",
62+
"simple-import-sort/exports": "error",
63+
"sort-imports": "off",
64+
"import/order": "off",
65+
66+
"import/no-deprecated": "warn",
67+
"import/no-duplicates": "error",
68+
// Doesn't support 'exports'?
69+
"import/no-unresolved": "off",
70+
"@typescript-eslint/ban-ts-comment": "off",
71+
"@typescript-eslint/no-namespace": "off",
72+
},
73+
overrides: [
74+
{
75+
files: ["__tests__/**/*", "test.js"],
76+
rules: {
77+
"@typescript-eslint/no-explicit-any": 0,
78+
"@typescript-eslint/explicit-function-return-type": 0,
79+
"@typescript-eslint/no-var-requires": 0,
80+
"@typescript-eslint/ban-ts-comment": 0,
81+
},
82+
},
83+
{
84+
files: ["perfTest/**/*", "examples/**/*"],
85+
rules: {
86+
"@typescript-eslint/no-var-requires": 0,
87+
},
88+
},
89+
],
90+
};

.github/workflows/ci.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI
2+
3+
on: [push, pull_request]
4+
5+
env:
6+
CI: true
7+
NODE_OPTIONS: "--disable-proto=delete"
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [20.x]
16+
17+
steps:
18+
- uses: actions/checkout@v3
19+
- name: Use Node.js ${{ matrix.node-version }}
20+
uses: actions/setup-node@v3
21+
with:
22+
node-version: ${{ matrix.node-version }}
23+
- run: yarn --frozen-lockfile
24+
- run: yarn prepack
25+
- run: yarn test
26+
27+
lint:
28+
runs-on: ubuntu-latest
29+
30+
strategy:
31+
matrix:
32+
node-version: [20.x]
33+
34+
steps:
35+
- uses: actions/checkout@v3
36+
- name: Use Node.js ${{ matrix.node-version }}
37+
uses: actions/setup-node@v3
38+
with:
39+
node-version: ${{ matrix.node-version }}
40+
- run: yarn --frozen-lockfile
41+
- run: yarn lint

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ generation and other such functionality.
1818
Which command you use will depend on your setup; if you're using `graphql-toe`
1919
then you'll want `semantic-to-strict` to really capitalize on the benefits of
2020
semantic nullability. If you just want to use a semantic nullability SDL with
21-
traditional tools that don't yet understand it, then `semantic-to-nullable`
22-
will just strip out the semantic-non-null types for you.
21+
traditional tools that don't yet understand it, then `semantic-to-nullable` will
22+
just strip out the semantic-non-null types for you.
2323

2424
## Installation
2525

@@ -37,8 +37,8 @@ pnpm install --save graphql-sock
3737

3838
If a value is "null only on error" then it can be null. This conversion strips
3939
all semantic-non-null type wrappers from the SDL, making a schema that appears
40-
as it traditionally would. This means that you won't reap any of the benefits
41-
of semantic nullability, but you can support existing tools.
40+
as it traditionally would. This means that you won't reap any of the benefits of
41+
semantic nullability, but you can support existing tools.
4242

4343
```
4444
semantic-to-nullable -i input.graphql -o output.graphql
@@ -52,8 +52,8 @@ will be thrown, then it will not be possible for you to read a `null` from a
5252
"null only on error" position. As such, this position becomes equivalent to a
5353
traditional non-null for you, so this conversion converts all semantic-non-null
5454
type wrappers into traditional non-null wrappers. Your type generators can
55-
therefore generate fewer nullables, and your frontend engineers have to do
56-
fewer null checks and are therefore happier.
55+
therefore generate fewer nullables, and your frontend engineers have to do fewer
56+
null checks and are therefore happier.
5757

5858
```
5959
semantic-to-strict -i input.graphql -o output.graphql

__tests__/index.test.mjs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// @ts-check
2+
3+
import { test } from "node:test";
4+
import * as assert from "node:assert";
5+
import { semanticToStrict, semanticToNullable } from "../dist/index.js";
6+
import { buildSchema, printSchema } from "graphql";
7+
import { readdir, readFile } from "node:fs/promises";
8+
9+
const TEST_DIR = import.meta.dirname;
10+
const files = await readdir(TEST_DIR);
11+
12+
for (const file of files) {
13+
if (file.endsWith(".test.graphql") && !file.startsWith(".")) {
14+
test(file.replace(/\.test\.graphql$/, ""), async () => {
15+
const sdl = await readFile(TEST_DIR + "/" + file, "utf8");
16+
const schema = buildSchema(sdl);
17+
await test("semantic-to-strict", async () => {
18+
const expectedSdl = await readFile(
19+
TEST_DIR + "/snapshots/" + file.replace(".test.", ".strict."),
20+
"utf8",
21+
);
22+
const converted = semanticToStrict(schema);
23+
assert.equal(
24+
printSchema(converted).trim(),
25+
expectedSdl.trim(),
26+
"Expected semantic-to-strict to match",
27+
);
28+
});
29+
await test("semantic-to-nullable", async () => {
30+
const expectedSdl = await readFile(
31+
TEST_DIR + "/snapshots/" + file.replace(".test.", ".nullable."),
32+
"utf8",
33+
);
34+
const converted = semanticToNullable(schema);
35+
assert.equal(
36+
printSchema(converted).trim(),
37+
expectedSdl.trim(),
38+
"Expected semantic-to-nullable to match",
39+
);
40+
});
41+
});
42+
}
43+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
directive @semanticNonNull(levels: [Int!]) on FIELD_DEFINITION
2+
3+
type Query {
4+
allThings(includingArchived: Boolean, first: Int!): ThingConnection
5+
@semanticNonNull
6+
}
7+
8+
type ThingConnection {
9+
pageInfo: PageInfo!
10+
nodes: [Thing] @semanticNonNull(levels: [0, 1])
11+
}
12+
13+
type PageInfo {
14+
startCursor: String @semanticNonNull(levels: [0])
15+
endCursor: String @semanticNonNull
16+
hasNextPage: Boolean @semanticNonNull
17+
hasPreviousPage: Boolean @semanticNonNull
18+
}
19+
20+
interface Thing {
21+
id: ID!
22+
name: String @semanticNonNull
23+
description: String
24+
}
25+
26+
type Book implements Thing {
27+
id: ID!
28+
# Test that this semantic-non-null doesn't cause issues
29+
name: String* @semanticNonNull
30+
description: String
31+
# Test that this non-null gets stripped
32+
pages: Int! @semanticNonNull
33+
}
34+
35+
type Car implements Thing {
36+
id: ID!
37+
name: String @semanticNonNull
38+
description: String
39+
mileage: Float @semanticNonNull
40+
}
41+
File renamed without changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
type Query {
2+
allThings(includingArchived: Boolean, first: Int!): ThingConnection
3+
}
4+
5+
type ThingConnection {
6+
pageInfo: PageInfo!
7+
nodes: [Thing]
8+
}
9+
10+
type PageInfo {
11+
startCursor: String
12+
endCursor: String
13+
hasNextPage: Boolean
14+
hasPreviousPage: Boolean
15+
}
16+
17+
interface Thing {
18+
id: ID!
19+
name: String
20+
description: String
21+
}
22+
23+
type Book implements Thing {
24+
id: ID!
25+
name: String
26+
description: String
27+
pages: Int
28+
}
29+
30+
type Car implements Thing {
31+
id: ID!
32+
name: String
33+
description: String
34+
mileage: Float
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
type Query {
2+
allThings(includingArchived: Boolean, first: Int!): ThingConnection!
3+
}
4+
5+
type ThingConnection {
6+
pageInfo: PageInfo!
7+
nodes: [Thing!]!
8+
}
9+
10+
type PageInfo {
11+
startCursor: String!
12+
endCursor: String!
13+
hasNextPage: Boolean!
14+
hasPreviousPage: Boolean!
15+
}
16+
17+
interface Thing {
18+
id: ID!
19+
name: String!
20+
description: String
21+
}
22+
23+
type Book implements Thing {
24+
id: ID!
25+
name: String!
26+
description: String
27+
pages: Int!
28+
}
29+
30+
type Car implements Thing {
31+
id: ID!
32+
name: String!
33+
description: String
34+
mileage: Float!
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
type Query {
2+
allThings(includingArchived: Boolean, first: Int!): ThingConnection
3+
}
4+
5+
type ThingConnection {
6+
pageInfo: PageInfo!
7+
nodes: [Thing]
8+
}
9+
10+
type PageInfo {
11+
startCursor: String
12+
endCursor: String
13+
hasNextPage: Boolean
14+
hasPreviousPage: Boolean
15+
}
16+
17+
interface Thing {
18+
id: ID!
19+
name: String
20+
description: String
21+
}
22+
23+
type Book implements Thing {
24+
id: ID!
25+
name: String
26+
description: String
27+
pages: Int
28+
}
29+
30+
type Car implements Thing {
31+
id: ID!
32+
name: String
33+
description: String
34+
mileage: Float
35+
}

0 commit comments

Comments
 (0)