Skip to content
Open
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
16 changes: 4 additions & 12 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
{
"git.ignoreLimitWarning": true,
"[typescriptreact]": {
"editor.formatOnType": true,
"editor.formatOnSave": true,
"editor.defaultFormatter": "standard.vscode-standard"
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "standard.vscode-standard"
},
"standard.enable": true,
"standard.autoFixOnSave": true,
"standard.engine": "ts-standard",
"standard.treatErrorsAsWarnings": true,
"javascript.format.enable": false,
"javascript.format.semicolons": "remove",
"typescript.format.enable": false,
"prettier.enable": false,
"editor.defaultFormatter": "standard.vscode-standard"
"eslint.format.enable": true,
"[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features"
}
}
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM registry.gitlab.com/openbeta/openbeta-nodejs-docker:18
FROM node:22-alpine

ENV APP_DIR=/apps/openbeta-graphql

Expand All @@ -13,4 +13,4 @@ COPY . *.env ./
RUN yarn install --no-progress && \
yarn build-release

CMD node --experimental-json-modules build/main.js
CMD ["node", "build/main.js"]
90 changes: 90 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// @ts-check

import tseslint from 'typescript-eslint'
import love from 'eslint-config-love'
import stylisticTs from '@stylistic/eslint-plugin-ts'

export default tseslint.config(
{
ignores: ['./hacks', './db-migrations', './build', 'jest.config.cjs']
},
{
files: ['**/*.ts']
},
tseslint.configs.strictTypeChecked,
tseslint.configs.stylisticTypeChecked,
love,
{
plugins: {
'@stylistic/ts': stylisticTs
},
rules: {
'@stylistic/ts/quotes': ['error', 'single'],
'@stylistic/ts/indent': ['error', 2],
'@stylistic/ts/semi': ['error', 'never'],
'comma-dangle': ['error', 'never'],
'promise/avoid-new': 'off',
'dot-notation': 'off',
'@typescript-eslint/dot-notation': 'error',
'prefer-const': 'off',
'no-console': 'off',
'max-nested-callbacks': 'off',
'max-lines': 'off',
'logical-assignment-operators': 'off',
'guard-for-in': 'off',
'eslint-comments/require-description': 'off',
'eslint-comments/no-unlimited-disable': 'off',
complexity: 'off',
'arrow-body-style': 'off',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/switch-exhaustiveness-check': 'off',
'@typescript-eslint/strict-boolean-expressions': 'off',
'@typescript-eslint/return-await': 'off',
'@typescript-eslint/require-await': 'off',
'@typescript-eslint/promise-function-async': 'off',
'@typescript-eslint/prefer-return-this-type': 'off',
'@typescript-eslint/prefer-promise-reject-errors': 'off',
'@typescript-eslint/prefer-optional-chain': 'off',
'@typescript-eslint/prefer-nullish-coalescing': 'off',
'@typescript-eslint/prefer-destructuring': 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@typescript-eslint/no-wrapper-object-types': 'off',
'@typescript-eslint/no-unsafe-type-assertion': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
'@typescript-eslint/no-unnecessary-type-arguments': 'off',
'@typescript-eslint/no-unnecessary-condition': 'off',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-misused-spread': 'off',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/no-magic-numbers': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-duplicate-type-constituents': 'off',
'@typescript-eslint/no-confusing-void-expression': 'off',
'@typescript-eslint/max-params': 'off',
'@typescript-eslint/init-declarations': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/consistent-type-imports': 'off',
'@typescript-eslint/consistent-type-exports': 'off',
'@typescript-eslint/consistent-indexed-object-style': 'off',
'@typescript-eslint/class-methods-use-this': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/await-thenable': 'off',
'@typescript-eslint/array-type': 'off'
},
languageOptions: {
parser: tseslint.parser,
parserOptions: {
project: './tsconfig.json'
}
}
}
)
33 changes: 13 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@
"author": "<openbeta@noreply>",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@stylistic/eslint-plugin-ts": "^4.2.0",
"@types/auth0": "^3.3.2",
"@types/jest": "^29.4.0",
"@types/node": "^18.13.0",
"@types/supertest": "^2.0.12",
"@types/underscore": "^1.11.4",
"@typescript-eslint/eslint-plugin": "^8.32.1",
"@typescript-eslint/parser": "^8.32.1",
"cross-env": "^7.0.3",
"eslint": "^9.26.0",
"eslint-config-love": "^119.0.0",
"eslint-plugin-import": "^2.31.0",
"husky": "^8.0.1",
"jest": "^29.7.0",
"jest-extended": "^4.0.2",
Expand All @@ -21,7 +27,8 @@
"supertest": "^6.3.3",
"ts-jest": "^29.2.5",
"ts-standard": "^12.0.0",
"typescript": "4.9.5",
"typescript": "^5.8.3",
"typescript-eslint": "^8.32.1",
"wait-for-expect": "^3.0.2"
},
"dependencies": {
Expand Down Expand Up @@ -71,13 +78,13 @@
"yup": "^1.1.1"
},
"scripts": {
"lint": "yarn ts-standard",
"fix": "yarn ts-standard --fix",
"lint": "yarn eslint",
"fix": "yarn eslint --fix",
"test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --runInBand",
"build": "tsc -p tsconfig.json",
"build-release": "tsc -p tsconfig.release.json",
"clean": "tsc -b --clean && rm -rf build/*",
"serve": "yarn build && node --experimental-json-modules build/main.js",
"serve": "yarn build && node build/main.js",
"serve-dev": "echo \"🚨 LOCAL_DEV_BYPASS_AUTH enabled 🚨\" && LOCAL_DEV_BYPASS_AUTH=true yarn serve",
"seed-db": "./seed-db.sh",
"add-countries": "yarn build && node build/db/utils/jobs/AddCountriesJob.js",
Expand All @@ -93,22 +100,8 @@
"maptiles:upload": "./scripts/upload-tiles.sh",
"maptiles:full": "yarn build && yarn maptiles:export-db && yarn maptiles:upload"
},
"standard": {
"plugins": [
"html"
],
"parser": "babel-eslint"
},
"ts-standard": {
"ignore": [
"build",
"hacks",
"**/*.test.ts",
"db-migrations"
]
},
"type": "module",
"engines": {
"node": ">=18.20.0 <19"
"node": ">=22.14.0 <= 24"
}
}
}
17 changes: 10 additions & 7 deletions src/GradeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,17 @@ export const createGradeObject = (gradeStr: string, disciplines: DisciplineType
if (disciplines[curr] === true) {
const scaleTxt = context[curr]
const scaleApi = getScale(scaleTxt)
if (scaleApi != null && !(scaleApi.getScore(gradeStr) < 0)) {
// only assign valid grade
if (acc == null) {
acc = {
[scaleTxt]: gradeStr
if (scaleApi != null) {
const grade = scaleApi.getScore(gradeStr)
if ((typeof grade === 'number' && grade > 0) || grade[0] > 0 || grade[1] > 0) {
// only assign valid grade
if (acc == null) {
acc = {
[scaleTxt]: gradeStr
}
} else {
acc[scaleTxt] = gradeStr
}
} else {
acc[scaleTxt] = gradeStr
}
}
}
Expand Down
44 changes: 22 additions & 22 deletions src/__tests__/bulkImport.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {ApolloServer} from "@apollo/server";
import muuid from "uuid-mongodb";
import express from "express";
import {InMemoryDB} from "../utils/inMemoryDB.js";
import {queryAPI, setUpServer} from "../utils/testUtils.js";
import {muuidToString} from "../utils/helpers.js";
import exampleImportData from './import-example.json' assert {type: 'json'};
import {AreaType} from "../db/AreaTypes.js";
import {BulkImportResultType} from "../db/BulkImportTypes.js";
import MutableClimbDataSource from "../model/MutableClimbDataSource.js";
import BulkImportDataSource from "../model/BulkImportDataSource.js";
import {ApolloServer} from '@apollo/server'
import muuid from 'uuid-mongodb'
import express from 'express'
import {InMemoryDB} from '../utils/inMemoryDB.js'
import {queryAPI, setUpServer} from '../utils/testUtils.js'
import {muuidToString} from '../utils/helpers.js'
import exampleImportData from './import-example.json'
import {AreaType} from '../db/AreaTypes.js'
import {BulkImportResultType} from '../db/BulkImportTypes.js'
import MutableClimbDataSource from '../model/MutableClimbDataSource.js'
import BulkImportDataSource from '../model/BulkImportDataSource.js'

describe('bulkImportAreas', () => {
const query = `
Expand Down Expand Up @@ -56,7 +56,7 @@ describe('bulkImportAreas', () => {
beforeEach(async () => {
await inMemoryDB.clear()
await bulkImport.addCountry('usa')
testArea = await bulkImport.addArea(user, "Test Area", null, "us")
testArea = await bulkImport.addArea(user, 'Test Area', null, 'us')
})

afterAll(async () => {
Expand Down Expand Up @@ -112,25 +112,25 @@ describe('bulkImportAreas', () => {
...exampleImportData.areas,
{
uuid: testArea.metadata.area_id,
areaName: "Updated Test Area",
areaName: 'Updated Test Area'
}
]
}
}
});
})
expect(res.body.errors).toBeFalsy()

const result = res.body.data.bulkImportAreas as BulkImportResultType
expect(result.addedAreas.length).toBe(4)

const committedAreas = await Promise.all(result.addedAreas.map((area) => bulkImport.findOneAreaByUUID(muuid.from(area.metadata.area_id))));
expect(committedAreas.length).toBe(4);
const committedAreas = await Promise.all(result.addedAreas.map((area) => bulkImport.findOneAreaByUUID(muuid.from(area.metadata.area_id))))
expect(committedAreas.length).toBe(4)

const committedClimbs = await Promise.all(result.addedOrUpdatedClimbs.map((climb) => climbs.findOneClimbByMUUID(climb._id)));
expect(committedClimbs.length).toBe(2);
const committedClimbs = await Promise.all(result.addedOrUpdatedClimbs.map((climb) => climbs.findOneClimbByMUUID(climb._id)))
expect(committedClimbs.length).toBe(2)

const updatedAreas = await Promise.all(result.updatedAreas.map((area) => bulkImport.findOneAreaByUUID(muuid.from(area.metadata.area_id))));
expect(updatedAreas.length).toBe(1);
expect(updatedAreas[0].area_name).toBe("Updated Test Area");
const updatedAreas = await Promise.all(result.updatedAreas.map((area) => bulkImport.findOneAreaByUUID(muuid.from(area.metadata.area_id))))
expect(updatedAreas.length).toBe(1)
expect(updatedAreas[0].area_name).toBe('Updated Test Area')
})
});
})
2 changes: 1 addition & 1 deletion src/auth/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async function validateTokenAndExtractUser (req: Request): Promise<CustomContext
}
} catch (e) {
logger.error(`Can't verify JWT token ${e.toString() as string}`)
throw new Error("Unauthorized. Can't verify JWT token")
throw new Error('Unauthorized. Can\'t verify JWT token')
}
}

Expand Down
44 changes: 22 additions & 22 deletions src/db/export/queries/get-all-climbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,32 @@ export async function * getAllClimbs (chunkSize: number = DEFAULT_CHUNK_SIZE): A
while (true) {
const page = await getClimbModel()
.aggregate<ClimbExtType>([
{
$lookup: {
from: 'areas', // other collection name
localField: 'metadata.areaRef',
foreignField: 'metadata.area_id',
as: 'area', // clobber array of climb IDs with climb objects
pipeline: [
{
$project: {
{
$lookup: {
from: 'areas', // other collection name
localField: 'metadata.areaRef',
foreignField: 'metadata.area_id',
as: 'area', // clobber array of climb IDs with climb objects
pipeline: [
{
$project: {
// only include specific fields
_id: 0,
ancestors: 1,
pathTokens: 1
_id: 0,
ancestors: 1,
pathTokens: 1
}
}
}
]
}
},
{ $unwind: '$area' }, // Previous stage returns as an array of 1 element. 'unwind' turn it into an object.
{
$replaceWith: {
]
}
},
{ $unwind: '$area' }, // Previous stage returns as an array of 1 element. 'unwind' turn it into an object.
{
$replaceWith: {
// Merge area.* with top-level object
$mergeObjects: ['$$ROOT', '$area']
$mergeObjects: ['$$ROOT', '$area']
}
}
}
])
])
.skip(pageNum * chunkSize)
.limit(chunkSize)

Expand Down
4 changes: 0 additions & 4 deletions src/db/import/usa/AreaTransformer.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import mongoose from 'mongoose'
import { geometry, Point } from '@turf/helpers'
import isoCountries from 'i18n-iso-countries'
import enJson from 'i18n-iso-countries/langs/en.json' assert { type: 'json' }

import { getAreaModel } from '../../AreaSchema.js'
import { AreaType } from '../../AreaTypes'
import { Tree, AreaNode, createRootNode } from './AreaTree.js'
import { MUUID } from 'uuid-mongodb'

isoCountries.registerLocale(enJson)

export const createRoot = async (countryCode: string, shortCode?: string): Promise<AreaNode> => {
if (!isoCountries.isValid(countryCode)) {
throw new Error('ISO code must be alpha 2 or 3')
Expand All @@ -33,7 +30,6 @@ export const createAreas = async (root: AreaNode, areas: any[], areaModel: mongo
const tree = new Tree(root)
areas.forEach(record => {
const { path }: { path: string } = record
/* eslint-disable-next-line */
const fullPath = `${record.us_state}|${path}` // 'path' doesn't have a parent (a US state)
tree.insertMany(fullPath, record)
})
Expand Down
2 changes: 1 addition & 1 deletion src/db/import/usa/AreaTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class Tree {
} else {
// find this new node's parent
const parent = this.getParent(key)
if (parent === undefined) assert(false, "Parent path exists but parent node doesn't")
if (parent === undefined) assert(false, 'Parent path exists but parent node doesn\'t')
parent?.linkChild(newNode)
newNode.setParent(parent)
}
Expand Down
Loading
Loading