Skip to content

Commit

Permalink
Add buildFragment, includeFragments
Browse files Browse the repository at this point in the history
  • Loading branch information
ajanauskas committed May 13, 2021
1 parent 94c3866 commit 2db28e0
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
lib/
12 changes: 12 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
]
}
38 changes: 38 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.swp

pids
logs
results
tmp

# Coverage reports
coverage

# API keys and secrets
.env

# Dependency directory
node_modules
bower_components

# Editors
.idea
*.iml

# OS metadata
.DS_Store
Thumbs.db

# Ignore built ts files
lib

# ignore yarn.lock
yarn.lock
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
semi: false
singleQuote: true
printWidth: 100

69 changes: 69 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# graphql-fragments-manager

`graphql-fragments-manager` helps with managing fragment dependencies when declaring graphql Queries, Mutations, Subscriptions

## Example:

```javascript
import { buildFragment, includeFragments } from 'graphql-fragments-manager'

const UserPhotoVersionFragment = buildFragment(
gql`
fragment UserPhotoVersionFragment on UserPhotoVersion {
width
height
version
}
`
)

const UserPhotoFragment = buildFragment(
gql`
fragment UserPhotoFragment on UserPhoto {
url
versions {
...UserPhotoVersionFragment
}
}
`,
[UserPhotoVersionFragment]
)

const UserFragment = buildFragment(
gql`
fragment UserFragment on User {
id
photo {
...UserPhotoFragment
}
}
`,
[UserPhotoFragment]
)

const QUERY = gql`
query UserQuery($id: ID!) {
user(id: $id) {
...UserFragment
}
}
${includeFragments(UserFragment)}
`

/// INSTEAD OF:

const QUERY = gql`
query UserQuery($id: ID!) {
user(id: $id) {
...UserFragment
}
}
${UserFragment}
${UserPhotoFragment}
${UserPhotoVersionFragment}
`
```

`includeFragments` function will gather dependencies on all included fragments and will include all necessary fragments that are necessary for graphql. This helps avoid runtime errors when fragments are complex, with many nested fragments.
22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "gql-fragments-manager",
"version": "0.0.1",
"description": "Library that helps to manage GraphQL fragment dependencies",
"main": "./lib/index.js",
"repository": "https://github.com/ajanauskas/gql-fragments-manager",
"author": "Andrius Janauskas <[email protected]>",
"license": "MIT",
"types": "./lib/index.d.ts",
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/parser": "^4.23.0",
"eslint": "^7.26.0",
"eslint-plugin-prettier": "^3.4.0",
"graphql": "^15.5.0",
"prettier": "^2.3.0",
"typescript": "^4.2.4"
},
"scripts": {
"lint": "eslint --ext '.js,.ts,.tsx' ."
}
}
17 changes: 17 additions & 0 deletions src/buildFragment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { DocumentNode } from 'graphql'

export type Fragment = {
fragment: DocumentNode
dependencies: ReadonlyArray<Fragment>
}

export default (
fragment: DocumentNode,
dependencies: ReadonlyArray<Fragment> | Fragment | undefined = undefined
): Fragment => ({
fragment,
dependencies:
(dependencies &&
((Array.isArray(dependencies) ? dependencies : [dependencies]) as ReadonlyArray<Fragment>)) ||
[],
})
31 changes: 31 additions & 0 deletions src/includeFragments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { DocumentNode } from 'graphql'
import { Fragment } from './buildFragment'

function getAllDocumentNodes(fragment: Fragment): ReadonlyArray<DocumentNode> {
const allDocumentNodes: Array<DocumentNode> = []
fragment.dependencies.forEach((dependency) =>
allDocumentNodes.push(...getAllDocumentNodes(dependency))
)
allDocumentNodes.push(fragment.fragment)
return allDocumentNodes
}

export default (fragments: ReadonlyArray<Fragment> | Fragment): string => {
const fragmentArray: ReadonlyArray<Fragment> = (Array.isArray(fragments)
? fragments
: [fragments]) as ReadonlyArray<Fragment>

const allDocumentNodes: Array<DocumentNode> = []

for (const fragment of fragmentArray) {
const documentNodes = getAllDocumentNodes(fragment)

for (const documentNode of documentNodes) {
if (!allDocumentNodes.find(node => node === documentNode)) {
allDocumentNodes.push(documentNode)
}
}
}

return allDocumentNodes.map((node) => node.loc?.source.body).join('\n')
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type { Fragment } from './buildFragment'
export { default as buildFragment } from './buildFragment'
export { default as includeFragments } from './includeFragments'
11 changes: 11 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true
},
"include": ["src"],
"exclude": ["node_modules", "**/__tests__/*"]
}

0 comments on commit 2db28e0

Please sign in to comment.