Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/eslint-prettier-on-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# workflow to enforce style and linting on PR
name: eslint-prettier
on:
pull_request:
branches:
- main
jobs:
format-and-lint:
runs-on: ubuntu-latest
permissions:
# Give the default GITHUB_TOKEN write permission to commit and push the changed files back to the repository.
contents: write

steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.head_ref }}
# Setup bun environment to run tests
- uses: oven-sh/setup-bun@v2
with:
bun-version: 'latest'
- run: bun install --frozen-lockfile # equivalent to npm ci
- run: bun run lint:eslint-config-prettier
- run: bun run format
- run: bun run lint
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Apply prettier formatting changes and check with eslint
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bunx lint-staged
3 changes: 3 additions & 0 deletions .lintstagedrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"*.ts": ["eslint-config-prettier", "prettier --write", "prettier --check", "eslint"],
}
8 changes: 8 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"singleQuote": true,
"bracketSpacing": false,
"arrowParens": "always",
"trailingComma": "all"
}
Binary file modified bun.lockb
Binary file not shown.
37 changes: 37 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from "eslint-config-prettier";

export default [
// typescript eslint
eslint.configs.recommended,
...tseslint.configs.recommended,
// eslint config
{
ignores: [
"node_modules/*",
"docs/*",
"docs-src/*",
"rollup-config.js",
"custom-elements.json",
"custom-elements-manifest.config.json",
"web-dev-server.config.js",
],
languageOptions: {
ecmaVersion: 2020,
sourceType: "module",
},
rules: {
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/no-unused-vars": ["warn", {
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}],
},
},
// prettier eslint
eslintConfigPrettier,
];
17 changes: 15 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
"build": "tsc && cp ./src/types/*.graphql ./dist/types",
"build:watch": "tsc-watch",
"clean": "rm -rf ./dist",
"lint": "npm run lint:eslint",
"lint:eslint": "eslint src/*.ts src/**/*.ts",
"lint:eslint-config-prettier": "eslint-config-prettier src/*.ts src/**/*.ts",
"format": "prettier src/*.ts src/**/*.ts --write",
"serve": "bun run ./dist/index.js",
"serve:dev": "NODE_ENV=development bun run tsc-watch --onSuccess \"bun run serve\"",
"serve:prod": "NODE_ENV=production bun run serve",
"start": "bun run clean && bun run build && bun run serve"
"start": "bun run clean && bun run build && bun run serve",
"postinstall": "husky"
},
"keywords": [
"typescript",
Expand All @@ -26,10 +31,18 @@
"dependencies": {
"@apollo/datasource-rest": "^6.3.0",
"@apollo/server": "^4.11.0",
"@eslint/js": "^9.26.0",
"@graphql-tools/load-files": "^7.0.0",
"@graphql-tools/merge": "^9.0.8",
"@types/eslint__js": "^9.14.0",
"dotenv": "^16.4.5",
"graphql": "^16.9.0"
"eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.2",
"graphql": "^16.9.0",
"husky": "^9.1.7",
"lint-staged": "^15.5.1",
"prettier": "^3.5.3",
"typescript-eslint": "^8.32.0"
},
"devDependencies": {
"tsc-watch": "^6.2.0",
Expand Down
13 changes: 7 additions & 6 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type { KeyValueCache } from '@apollo/utils.keyvaluecache';

import { DataSources, dataSources } from './data-sources/index.js';
import type {KeyValueCache} from '@apollo/utils.keyvaluecache';

import {DataSources, dataSources} from './data-sources/index.js';

export interface ContextValue {
dataSources: DataSources;
}


export const contextFactory =
(intermineURI: string, microservicesURI: string, cache: KeyValueCache) => {
export const contextFactory = (
intermineURI: string,
microservicesURI: string,
cache: KeyValueCache,
) => {
return async () => {
return {
// We create new instances of our data sources with each request.
Expand Down
21 changes: 10 additions & 11 deletions src/data-sources/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import type { KeyValueCache } from '@apollo/utils.keyvaluecache';
import type {KeyValueCache} from '@apollo/utils.keyvaluecache';

import { IntermineAPI } from './intermine/index.js';
import { MicroservicesAPI } from './microservices/index.js';


export { IntermineAPI } from './intermine/index.js';
export { MicroservicesAPI } from './microservices/index.js';
import {IntermineAPI} from './intermine/index.js';
import {MicroservicesAPI} from './microservices/index.js';

export {IntermineAPI} from './intermine/index.js';
export {MicroservicesAPI} from './microservices/index.js';

export type DataSources = {
lisIntermineAPI: IntermineAPI;
lisMicroservicesAPI: MicroservicesAPI;
};


export const dataSources =
async (intermineURI: string, microservicesURI: string, cache: KeyValueCache):
Promise<DataSources> => {
export const dataSources = async (
intermineURI: string,
microservicesURI: string,
cache: KeyValueCache,
): Promise<DataSources> => {
const config = {cache};
const lisIntermineAPI = new IntermineAPI(intermineURI, config);
// TODO: this crashes the server rather than throwing a GraphQL error
Expand Down
29 changes: 13 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { config } from 'dotenv';
import {ApolloServer} from '@apollo/server';
import {startStandaloneServer} from '@apollo/server/standalone';
import {config} from 'dotenv';

// import *.js files because node doesn't support directory imports in modules!
import { ContextValue, contextFactory } from './context.js';
import { typeDefs } from './types/index.js';
import { resolvers } from './resolvers/index.js';

import {ContextValue, contextFactory} from './context.js';
import {typeDefs} from './types/index.js';
import {resolvers} from './resolvers/index.js';

// load environment variables from the .env file into process.env
config();


// The ApolloServer constructor requires two parameters: a schema definition and
// a set of resolvers.
// NOTE: 'introspection' option is automatically set to false when NODE_ENV is
Expand All @@ -21,21 +19,20 @@ const server = new ApolloServer<ContextValue>({
resolvers,
});


const port = Number(process.env.PORT) || 4000;
const intermineURI = process.env.INTERMINE_URI || 'https://mines.legumeinfo.org/minimine/service';
const microservicesURI = process.env.MICROSERVICES_URI || 'https://services.lis.ncgr.org';
const { cache } = server;

const intermineURI =
process.env.INTERMINE_URI || 'https://mines.legumeinfo.org/minimine/service';
const microservicesURI =
process.env.MICROSERVICES_URI || 'https://services.lis.ncgr.org';
const {cache} = server;

// Passing an ApolloServer instance to the `startStandaloneServer` function:
// 1. creates an Express app
// 2. installs the ApolloServer instance as middleware
// 3. prepares the app to handle incoming requests
const { url } = await startStandaloneServer(server, {
listen: { port },
const {url} = await startStandaloneServer(server, {
listen: {port},
context: contextFactory(intermineURI, microservicesURI, cache),
});


console.log(`🚀 Server ready at: ${url}`);
30 changes: 16 additions & 14 deletions src/models/page-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ export interface GraphQLPageInfo {
hasNextPage: boolean;
}


export const pageInfoFactory =
(numResults: number, currentPage: number|null, pageSize: number|null) => {
if (currentPage == null) currentPage = 1;
if (pageSize == null) pageSize = numResults;
const pageCount = (numResults == 0 ? 1 : Math.ceil(numResults/pageSize));
return {
currentPage,
pageSize,
numResults,
pageCount,
hasPreviousPage: currentPage > 1,
hasNextPage: currentPage < pageCount,
};
export const pageInfoFactory = (
numResults: number,
currentPage: number | null,
pageSize: number | null,
) => {
if (currentPage == null) currentPage = 1;
if (pageSize == null) pageSize = numResults;
const pageCount = numResults == 0 ? 1 : Math.ceil(numResults / pageSize);
return {
currentPage,
pageSize,
numResults,
pageCount,
hasPreviousPage: currentPage > 1,
hasNextPage: currentPage < pageCount,
};
};
21 changes: 11 additions & 10 deletions src/models/results-info.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
export interface GraphQLIdentifierCount {
identifier: string;
count: number;
identifier: string;
count: number;
}


export interface GraphQLResultsInfo {
uniqueValues: number;
identifierCounts: GraphQLIdentifierCount[];
}


export const resultsInfoFactory =
(uniqueValues: number, idCountMap: Record<string, number>) => {
const identifierCounts =
Object.entries(idCountMap).map(([identifier, count]) => ({identifier, count}));
return {uniqueValues, identifierCounts};
};
export const resultsInfoFactory = (
uniqueValues: number,
idCountMap: Record<string, number>,
) => {
const identifierCounts = Object.entries(idCountMap).map(
([identifier, count]) => ({identifier, count}),
);
return {uniqueValues, identifierCounts};
};
2 changes: 1 addition & 1 deletion src/models/string-key-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
* accessing properties using index syntax.
*/
export interface StringKeyObject {
[key: string]: string|number|boolean|StringKeyObject
[key: string]: string | number | boolean | StringKeyObject;
}
7 changes: 3 additions & 4 deletions src/resolvers/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { mergeResolvers } from '@graphql-tools/merge';
import { intermineResolverFactory } from './intermine/index.js';
import { microservicesResolverFactory } from './microservices/index.js';

import {mergeResolvers} from '@graphql-tools/merge';
import {intermineResolverFactory} from './intermine/index.js';
import {microservicesResolverFactory} from './microservices/index.js';

export const resolvers = mergeResolvers([
intermineResolverFactory('lisIntermineAPI', 'lisMicroservicesAPI'),
Expand Down
3 changes: 1 addition & 2 deletions src/resolvers/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import type {
GraphQLIsTypeOfFn,
} from 'graphql';


export interface GraphQLResolvers {
[fieldName: string]: (() => any) | GraphQLResolverObject | GraphQLScalarType;
}
// TODO: remove legacy type
export interface ResolverMap extends GraphQLResolvers { };
export interface ResolverMap extends GraphQLResolvers {}

export type GraphQLResolverObject = {
[fieldName: string]: GraphQLFieldResolver<any, any> | GraphQLResolverOptions;
Expand Down
12 changes: 6 additions & 6 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
// ----------------------------------------------------------------

import path from 'path';
import { fileURLToPath } from 'url';
import { loadFilesSync } from '@graphql-tools/load-files';
import { mergeTypeDefs } from '@graphql-tools/merge';

import {fileURLToPath} from 'url';
import {loadFilesSync} from '@graphql-tools/load-files';
import {mergeTypeDefs} from '@graphql-tools/merge';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const types = loadFilesSync(path.join(__dirname, './'), { extensions: ['graphql'] });

const types = loadFilesSync(path.join(__dirname, './'), {
extensions: ['graphql'],
});

export const typeDefs = mergeTypeDefs(types);
5 changes: 2 additions & 3 deletions src/utils/input-error.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ApolloServerErrorCode } from '@apollo/server/errors';
import { GraphQLError } from 'graphql';

import {ApolloServerErrorCode} from '@apollo/server/errors';
import {GraphQLError} from 'graphql';

export function inputError(msg: string) {
throw new GraphQLError(msg, {
Expand Down
4 changes: 2 additions & 2 deletions src/utils/key-of-type.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export type KeyOfType<T, V> = keyof {
[P in keyof T as T[P] extends V? P: never]: any
}
[P in keyof T as T[P] extends V ? P : never]: any;
};