chore: replace prettier and eslint by biome (#422)

* chore: replace `prettier` and `eslint` by `biome` (#421)

* chore: replace `prettier` and `eslint` by `biome`

* chore: lint

* changeset
This commit is contained in:
sripwoud
2024-03-30 23:15:54 +01:00
committed by GitHub
parent 54ae17a914
commit 94eac87e5c
60 changed files with 458 additions and 1557 deletions

View File

@@ -0,0 +1,8 @@
---
"@anonklub/spartan-ecdsa-worker": patch
"@anonklub/merkle-tree-worker": patch
"@anonklub/proof": patch
"@anonklub/query": patch
---
lint: use `type` imports

View File

@@ -1,31 +0,0 @@
node_modules
pnpm-lock.yaml
# build dirs
dist
.next
.graphclient
wasm-pkg
# Jest
coverage
# JetBrains IDE
.idea
# Generated code
generated
next-env.d.ts
next.config.js
public
.turbo
cache
queries
target
commitlint.config.js
.husky/*
.prettierignore

View File

@@ -1,81 +0,0 @@
extends: ['@sripwoud/eslint-config-with-jest']
parserOptions:
project:
[
'circom/tsconfig.json',
'discord-bot/tsconfig.json',
'pkgs/merkle-tree-worker/tsconfig.json',
'pkgs/proof/tsconfig.json',
'pkgs/query/tsconfig.json',
'pkgs/spartan-ecdsa-worker/tsconfig.json',
'query-api/tsconfig.json',
'test/tsconfig.json',
'ui/tsconfig.json',
'tsconfig.json',
]
rules:
no-useless-constructor: off
overrides:
- files: ['*.ts', '*.tsx']
rules:
'@typescript-eslint/await-thenable': error
- files: ['query-api/test/unit/DuneRepository.test.ts']
rules:
'@typescript-eslint/no-dynamic-delete': off
- files: ['*.ts']
rules:
'@typescript-eslint/dot-notation': off # because using noPropertyAccessFromIndexSignature tsc option
- files: ['test/jest-preset.js']
rules:
'@typescript-eslint/no-var-requires': off
- files: ['pkgs/proof/test/ProofRequest.test.ts']
rules:
'@typescript-eslint/dot-notation': off
- files:
[
'pkgs/cli/src/cli/index.ts',
'pkgs/proof/src/ProofRequest/index.ts',
'pkgs/proof/test/ProofRequest.test.ts',
]
rules:
'@typescript-eslint/restrict-template-expressions': off
- files:
[
'query-api/src/api/controllers/requests/getEthBalanceAnonSetQuery.ts',
'query-api/src/api/repositories/DuneRepository.ts',
]
rules:
'@typescript-eslint/no-inferrable-types': off
- files: ['*.tsx']
rules:
'@typescript-eslint/no-misused-promises':
[error, { checksVoidReturn: { attributes: false } }]
- files:
[
'pkgs/cli/src/{,Cli/}index.ts',
'circom/scripts/*.ts',
'query-api/src/index.ts',
'ui/src/lib/config.ts',
'discord-bot/src/{index,events/{ClientReady,MessageCreate}}.ts',
]
rules:
no-console: off
- files: ['query-api/src/decorators/Logger.ts']
rules:
'@typescript-eslint/no-explicit-any': 'off'
- files:
[
'query-api/test/unit/QueryService.test.ts',
'query-api/src/decorators/Logger.ts',
]
rules:
'@typescript-eslint/ban-ts-comment': 'off'
- files:
['circom/test/circuit.test.ts', 'query-api/test/unit/*Controller.test.ts']
rules:
jest/expect-expect: 'off'
- files: ['pkgs/cli/src/Prompt/index.ts']
rules:
'@typescript-eslint/naming-convention': off

View File

@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
CI=true NODE_ENV=production pnpm run githook:precommit
CI=true NODE_ENV=production pnpm lint-staged

View File

@@ -1,6 +1,8 @@
{
"*": "prettier -u -w",
"**/*.{json,jsonc,js,jsx,ts,tsx}": [
"pnpm biome lint --apply",
"pnpm biome format --write"
],
"**/*.rs": "rustfmt",
"**/*.{ts,tsx}": "tsc-files --noEmit",
"**/*.{js,jsx,ts,tsx}": "eslint"
"**/*.{ts,tsx}": "tsc-files --noEmit"
}

View File

@@ -1,30 +0,0 @@
node_modules
pnpm-lock.yaml
# build dirs
dist
.next
# Jest
coverage
# JetBrains IDE
.idea
*.graphql
.graphclient
public
.turbo
cache
contracts/lib/forge-std
contracts/lib/openzeppelin-contracts
contracts/out
# after editing by the release/changeset workflow, these won't match the formatting rules
package.json
target
commitlint.config.js

View File

@@ -1 +0,0 @@
'@sripwoud/prettier-config'

178
biome.jsonc Normal file
View File

@@ -0,0 +1,178 @@
{
"$schema": "https://biomejs.dev/schemas/1.6.3/schema.json",
"linter": {
"ignore": []
},
"formatter": {
"indentStyle": "space",
"indentWidth": 2,
"ignore": [
"**/node_modules/**",
"**/dist/**",
"**/out/**",
"**/.next/**",
"**/target/**",
"**/.turbo/**",
"**/coverage/**",
"**/*.graphql",
"**/.graphclient/**",
"**/cache/**",
"contracts/lib/forge-std/**",
"contracts/lib/openzeppelin-contracts/**",
"**/package.json"
]
},
"organizeImports": {
"enabled": true
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "single",
"quoteStyle": "single",
"semicolons": "asNeeded"
},
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
},
"ignore": [
"**/node_modules/**",
"**/dist/**",
"**/out/**",
"**/.next/**",
"**/target/**",
"**/generated/**",
"**/coverage/**",
"**/*.graphql",
"**/.graphclient/**",
"**/cache/**",
"contracts/lib/forge-std/**",
"contracts/lib/openzeppelin-contracts/**",
"**/package.json",
"ui/next.config.js",
"ui/next-env.d.ts",
"ui/public/**",
".turbo/**",
"queries/**"
]
},
"overrides": [
{
"include": [
"discord-bot/src/lib/decorators/tryCatch.ts",
"query-api/src/decorators/handle-dune-credits-error.ts",
"query-api/src/decorators/tryCatchReply.ts"
],
"linter": {
"rules": {
"complexity": { "useArrowFunction": "off" }
}
}
},
{
"include": ["ui/src/**/*.tsx"],
"linter": {
"rules": {
"a11y": {
"useButtonType": "warn"
}
}
}
},
{
// TODO: why a string literal was used to get the env var here?
"include": ["query-api/src/repositories/dune-client/index.ts"],
"linter": {
"rules": {
"complexity": {
"useLiteralKeys": "warn"
}
}
}
},
{
"include": [
"discord-bot/src/lib/decorators/*.ts",
"discord-bot/src/events/*.ts",
"pkgs/proof/src/poseidon.ts",
"pkgs/proof/src/ExcludableMerkleTree.ts",
"query-api/src/repositories/dune-client/types.ts",
"query-api/src/repositories/GraphRepository.ts",
"query-api/src/decorators/handle-dune-credits-error.ts",
"ui/src/components/ExternalLink.tsx",
"**/test/**"
],
"linter": {
"rules": {
"suspicious": {
"noExplicitAny": "warn"
}
}
}
},
{
"include": ["**/test/**"],
"linter": { "rules": { "suspicious": { "noImplicitAnyLet": "off" } } }
},
{
"include": ["ui/src/components/*.tsx"],
"linter": {
"rules": {
"a11y": {
"useValidAnchor": "warn"
}
}
}
},
{
"include": ["ui/src/app/**/error.tsx", "discord-bot/src/events/*.ts"],
"linter": {
"rules": {
"suspicious": {
"noShadowRestrictedNames": "off"
}
}
}
},
{
// FIXME
"include": ["ui/src/**/*.tsx", "ui/src/**/*.ts"],
"linter": {
"rules": {
"correctness": {
"useExhaustiveDependencies": "warn"
}
}
}
},
{
"include": ["pkgs/proof/src/MerkleTree.ts", "pkgs/proof/src/helpers.ts"],
"linter": { "rules": { "style": { "noParameterAssign": "off" } } }
},
// FIXME
{
"include": ["ui/src/**"],
"linter": { "rules": { "complexity": { "noUselessCatch": "warn" } } }
},
{
"include": [
"discord-bot/src/Client/index.ts",
"query-api/src/*.ts",
"discord-bot/src/*.ts"
],
"linter": {
"rules": {
//FIXME
"complexity": { "noForEach": "warn" },
// using import type breaks typeDI Service/Container
"style": { "useImportType": "off" }
}
}
}
]
}

View File

@@ -1,13 +1,16 @@
import inquirer, { DistinctQuestion, QuestionCollection } from 'inquirer'
import inquirer, {
type DistinctQuestion,
type QuestionCollection,
} from 'inquirer'
import inquirerFuzzyPath from 'inquirer-fuzzy-path'
import { join } from 'path'
import { join } from 'node:path'
inquirer.registerPrompt('fuzzypath', inquirerFuzzyPath)
export const prompt =
<T>(questions: QuestionCollection | DistinctQuestion) =>
async (): Promise<T> => {
if (questions instanceof Array)
if (Array.isArray(questions))
return (await inquirer.prompt(questions as QuestionCollection)) as T
const { name } = questions as DistinctQuestion

View File

@@ -1,4 +1,4 @@
import { execSync } from 'child_process'
import { execSync } from 'node:child_process'
import { groth16 } from 'snarkjs'
import { askProofFile, askPublicSignalsFile } from './_prompt'
import { wrapExec } from './_wrap'

View File

@@ -11,11 +11,11 @@ import { Point, sign } from '@noble/secp256k1'
import { wasm as wasm_tester } from 'circom_tester'
import { buildPoseidon } from 'circomlibjs'
import { BigNumber, utils } from 'ethers'
import { join } from 'path'
import { join } from 'node:path'
jest.setTimeout(10_000_000) // ~1 hour
describe('Poseidon Merkle Tree', function () {
describe('Poseidon Merkle Tree', () => {
let poseidon
let F
let circuit
@@ -158,7 +158,7 @@ describe('Poseidon Merkle Tree', function () {
})
})
describe('SetMembership', function () {
describe('SetMembership', () => {
let poseidon
let F
let membershipCircuit
@@ -177,7 +177,7 @@ describe('SetMembership', function () {
).toBigInt(),
)
beforeAll(async function () {
beforeAll(async () => {
membershipCircuit = await wasm_tester(
join(__dirname, 'membership_test.circom'),
)
@@ -248,7 +248,7 @@ describe('SetMembership', function () {
})
})
describe('ECDSACheckPubKey', function () {
describe('ECDSACheckPubKey', () => {
const testCases: Array<[bigint, bigint]> = []
const privkeys: bigint[] = [
88549154299169935420064281163296845505587953610183896504176354567359434168161n,
@@ -263,19 +263,19 @@ describe('ECDSACheckPubKey', function () {
}
let circuit: any
beforeAll(async function () {
beforeAll(async () => {
circuit = await wasm_tester(
join(__dirname, 'test_ecdsa_check_pub_key.circom'),
)
})
const testECDSAVerify = function (testCase: [bigint, bigint]) {
const testECDSAVerify = (testCase: [bigint, bigint]) => {
const pub0 = testCase[0]
const pub1 = testCase[1]
const pub0Array: bigint[] = bigintToArray(64, 4, pub0)
const pub1Array: bigint[] = bigintToArray(64, 4, pub1)
it(`Testing valid pub key: pub0: ${pub0} pub1: ${pub1}`, async function () {
it(`Testing valid pub key: pub0: ${pub0} pub1: ${pub1}`, async () => {
const witness = await circuit.calculateWitness({
pubkey: [pub0Array, pub1Array],
})
@@ -286,9 +286,9 @@ describe('ECDSACheckPubKey', function () {
testCases.forEach(testECDSAVerify)
})
describe('Ordering', function () {
describe('Ordering', () => {
let orderingCircuit
beforeAll(async function () {
beforeAll(async () => {
orderingCircuit = await wasm_tester(
join(__dirname, 'is_ordered_test.circom'),
)

View File

@@ -6,14 +6,12 @@
},
"devDependencies": {
"@anonklub/test": "workspace:^",
"@biomejs/biome": "1.6.3",
"@changesets/cli": "^2.26.2",
"@faker-js/faker": "^7.6.0",
"@sripwoud/eslint-config-with-jest": "^1.0.2",
"@sripwoud/prettier-config": "^1.0.3",
"@types/jest": "^29.5.3",
"@types/node": "^18.11.15",
"barrelsby": "^2.5.1",
"eslint-config-next": "^13.4.2",
"find-up-cli": "^5.0.0",
"husky": "^9.0.10",
"is-ci": "^3.0.1",
@@ -51,16 +49,16 @@
"clean": "find . \\( -name 'node_modules' -o -name 'dist' -o -name 'next' \\) -type d -prune -exec rm -rf '{}' +",
"compile": "turbo _compile",
"fix": "turbo _format.fix _lint.fix",
"format": "turbo format.cargo format.forge format.prettier",
"format.fix": "turbo format.cargo.fix format.forge.fix format.prettier.fix",
"format.prettier": "prettier -c .",
"format.prettier.fix": "prettier -w .",
"format": "turbo format.cargo format.forge format.biome",
"format.fix": "turbo format.cargo.fix format.forge.fix format.biome.fix",
"format.biome": "biome format .",
"format.biome.fix": "biome format --write .",
"githook:precommit": "lint-staged",
"knip": "knip -c .knip.ts --production --strict",
"lint": "turbo lint.cargo lint.eslint lint.solhint",
"lint.eslint": "NODE_OPTIONS='--max-old-space-size=4096' eslint . --ext .js,.jsx,.ts,.tsx",
"lint.eslint.fix": "eslint . --ext .js,.ts,.tsx --fix",
"lint.fix": "turbo lint.cargo.fix lint.eslint.fix lint.solhint.fix",
"lint": "turbo lint.cargo lint.biome lint.solhint",
"lint.biome": "biome lint --max-diagnostics 200 .",
"lint.biome.fix": "biome lint --apply --max-diagnostics 200 .",
"lint.fix": "turbo lint.cargo.fix lint.biome.fix lint.solhint.fix",
"prepare": "is-ci || husky install",
"publish.pkgs": "pnpm build.pkgs && changeset version && changeset publish",
"start.query-api": "pnpm --filter query-api start.dev",
@@ -71,7 +69,7 @@
"test.coverage.html": "cargo llvm-cov --all-features --workspace --html --output-dir=target/llvm-cov/html",
"test.coverage.summary": "cargo llvm-cov --all-features --workspace --summary-only",
"typecheck": "turbo typecheck",
"validate": "turbo format.cargo format.forge format.prettier lint.cargo lint.eslint lint.solhint build _compile --cache-dir=.turbo"
"validate": "turbo format.cargo format.forge format.biome lint.cargo lint.biome lint.solhint build _compile --cache-dir=.turbo"
},
"workspaces": [
"contracts",

View File

@@ -1,5 +1,5 @@
import { Remote, wrap } from 'comlink'
import { IMerkleTreeWorker } from './interface'
import { type Remote, wrap } from 'comlink'
import type { IMerkleTreeWorker } from './interface'
let MerkleTreeWorker: Remote<IMerkleTreeWorker>

View File

@@ -1,5 +1,5 @@
import { expose } from 'comlink'
import { IMerkleTreeWasm, IMerkleTreeWorker } from './interface'
import type { IMerkleTreeWasm, IMerkleTreeWorker } from './interface'
let merkleTreeWasm: IMerkleTreeWasm

View File

@@ -8,7 +8,7 @@ export class MerkleTree {
levels: bigint[][]
constructor(elements: bigint[], depth: number, hashFunction, field) {
if (elements.length > Math.pow(2, depth)) {
if (elements.length > 2 ** depth) {
throw new Error(
`Merkle tree depth ${depth} is too small for ${elements.length} items`,
)

View File

@@ -1,12 +1,17 @@
import { URLS } from '../CONSTANTS'
import { fetchJson } from '../fetch-json'
import {
import type {
EnsProposalVotersRequest,
Erc20BalanceAnonSetRequest,
EthBalanceAnonSetRequest,
} from '../requests'
import { Endpoint, Environment, Request, RequestClass } from '../types'
import { AnonymitySetI } from './interface'
import {
Endpoint,
Environment,
type Request,
type RequestClass,
} from '../types'
import type { AnonymitySetI } from './interface'
export class AnonymitySet implements AnonymitySetI {
constructor(public env = Environment.PRODUCTION) {}

View File

@@ -1,9 +1,9 @@
import {
import type {
EnsProposalVotersRequest,
Erc20BalanceAnonSetRequest,
EthBalanceAnonSetRequest,
} from '../requests'
import { AnonSetResponse } from '../types'
import type { AnonSetResponse } from '../types'
export interface AnonymitySetI {
fromEthBalance: ({

View File

@@ -1,4 +1,4 @@
import { AnonSetResponse } from './types'
import type { AnonSetResponse } from './types'
export const fetchJson = async (
url: string,

View File

@@ -1,4 +1,4 @@
import {
import type {
EnsProposalVotersRequest,
Erc20BalanceAnonSetRequest,
EthBalanceAnonSetRequest,

View File

@@ -26,9 +26,9 @@ describe('AnonymitySet', () => {
const { data } = await anonymitySet.fromEthBalance({ min })
expect(data).toBeDefined()
data?.forEach((address) => {
for (const address of data ?? []) {
expect(address).toMatch(/^0x[0-9a-fA-F]{40}$/)
})
}
expect(fetchMock).toHaveBeenCalledWith(
`${URLS[env]}/${Endpoint.EthBalance}?min=${min}`,
)
@@ -39,9 +39,9 @@ describe('AnonymitySet', () => {
const { data } = await anonymitySet.fromErc20Balance({ min, tokenAddress })
expect(data).toBeDefined()
data?.forEach((address) => {
for (const address of data ?? []) {
expect(address).toMatch(/^0x[0-9a-fA-F]{40}$/)
})
}
expect(fetchMock).toHaveBeenCalledWith(
`${URLS[env]}/${Endpoint.Erc20Balance}?min=${min}&tokenAddress=${tokenAddress}`,
)
@@ -51,9 +51,9 @@ describe('AnonymitySet', () => {
const { data } = await anonymitySet.fromCryptoPunkOwners()
expect(data).toBeDefined()
data?.forEach((address) => {
for (const address of data ?? []) {
expect(address).toMatch(/^0x[0-9a-fA-F]{40}$/)
})
}
expect(fetchMock).toHaveBeenCalledWith(
`${URLS[env]}/${Endpoint.CryptoPunks}`,
)
@@ -63,9 +63,9 @@ describe('AnonymitySet', () => {
const { data } = await anonymitySet.fromBeaconDepositors()
expect(data).toBeDefined()
data?.forEach((address) => {
for (const address of data ?? []) {
expect(address).toMatch(/^0x[0-9a-fA-F]{40}$/)
})
}
expect(fetchMock).toHaveBeenCalledWith(
`${URLS[env]}/${Endpoint.BeaconDepositors}`,
)
@@ -85,9 +85,9 @@ describe('AnonymitySet', () => {
})
expect(data).toBeDefined()
data?.forEach((address) => {
for (const address of data ?? []) {
expect(address).toMatch(/^0x[0-9a-fA-F]{40}$/)
})
}
expect(fetchMock).toHaveBeenCalledWith(
`${URLS[env]}/${Endpoint.EnsProposalVoters}?choice=${
choice as string

View File

@@ -1,5 +1,5 @@
import { Remote, wrap } from 'comlink'
import { ISpartanEcdsaWorker } from './interface'
import { type Remote, wrap } from 'comlink'
import type { ISpartanEcdsaWorker } from './interface'
let SpartanEcdsaWorker: Remote<ISpartanEcdsaWorker>

View File

@@ -4,7 +4,7 @@ import type {
prove_membership,
verify_membership,
} from '@anonklub/spartan-ecdsa-wasm'
import { Hex } from 'viem'
import type { Hex } from 'viem'
export interface MerkleProof {
root: bigint

View File

@@ -1,6 +1,6 @@
import { expose } from 'comlink'
import { hashMessage, hexToBytes, hexToSignature } from 'viem'
import { ISpartanEcdsaWasm, ISpartanEcdsaWorker } from './interface'
import type { ISpartanEcdsaWasm, ISpartanEcdsaWorker } from './interface'
import { calculateSigRecovery } from './utils'
let spartanEcdsaWasm: ISpartanEcdsaWasm

1399
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -47,19 +47,19 @@ export class AnonsetService {
@HandleDuneCreditsError()
async getBeaconDepositors() {
this.logger.log(`getBeaconDepositors`)
this.logger.log('getBeaconDepositors')
return this.duneRepository.getBeaconDepositors().then(({ result }) => {
return result.rows.map((row) => row.address) ?? []
})
}
async getEnsProposalVoters(dto: GetEnsProposalVotersDto) {
this.logger.log(`getEnsProposalVoters: ${dto.choice} ${dto.id}`)
this.logger.log('getEnsProposalVoters: ${dto.choice} ${dto.id}')
return this.graphRepository.getEnsProposalVoters(dto)
}
async getCryptopunkOwners() {
this.logger.log(`getCryptopunkOwners`)
this.logger.log('getCryptopunkOwners')
return this.graphRepository.getCryptopunkOwners()
}

View File

@@ -1,6 +1,6 @@
import { ApiProperty } from '@nestjs/swagger'
import { IsDefined, IsIn, IsNumberString, Length } from 'class-validator'
import { VoteChoice } from '../repositories'
import type { VoteChoice } from '../repositories'
export class GetEnsProposalVotersDto {
@IsDefined()

View File

@@ -1,5 +1,5 @@
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common'
import { Response } from 'express'
import { type ArgumentsHost, Catch, type ExceptionFilter } from '@nestjs/common'
import type { Response } from 'express'
import { OutOfDuneCreditsException } from './out-of-dune-credits.exception'
@Catch(OutOfDuneCreditsException)

View File

@@ -1,8 +1,8 @@
import { ValidationPipe } from '@nestjs/common'
import { NestFactory } from '@nestjs/core'
import { NestExpressApplication } from '@nestjs/platform-express'
import type { NestExpressApplication } from '@nestjs/platform-express'
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'
import { join } from 'path'
import { join } from 'node:path'
import { AnonsetModule } from './anonset.module'
async function bootstrap() {

View File

@@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common'
import {
execute,
Punk,
type Punk,
PunkOwnersDocument,
Scalars,
Vote,
VoteChoice,
type Scalars,
type Vote,
type VoteChoice,
VotersPerProposalDocument,
} from './graph-client'

View File

@@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common'
import ms from 'ms'
import {
ApiError,
DuneClientI,
ExecuteOk,
GetQueryResultsOk,
GetQueryStatusOk,
type ApiError,
type DuneClientI,
type ExecuteOk,
type GetQueryResultsOk,
type GetQueryStatusOk,
Query as DuneQuery,
QueryState,
} from './types'

View File

@@ -1,5 +1,5 @@
const tsJestPreset = require('ts-jest/jest-preset')
const { join } = require('path')
const { join } = require('node:path')
const projects = [
...['proof', 'query'].map((name) => `pkgs/${name}`),

View File

@@ -8,11 +8,12 @@
"!{pkgs/query,discord-bot,query-api,ui}/**/{build,dist,node_modules,.next}/**"
]
},
"//#format.prettier": {
"//#format.biome": {
"cache": false,
"inputs": [
"*.{cjs,js,jsx,ts,tsx,yaml,yml,json,md,mdx,css,html,graphql}",
"{.github,pkgs,circom,discord-bot,query-api,test,ui}/**/*.{cjs,js,jsx,ts,tsx,yaml,yml,json,md,mdx,css,html,graphql}",
"!{pkgs,circom,discord-bot,query-api,test,ui}/**/{build,dist,node_modules,.next}/**"
"*.{cjs,js,jsx,ts,tsx,json,jsonc}",
"{.github,pkgs,circom,discord-bot,query-api,ui}/**/*.{cjs,js,jsx,ts,tsx,json,jsonc}",
"!{pkgs,circom,discord-bot,query-api,ui}/**/{build,dist,node_modules,.next}/**"
]
},
"format.cargo": {
@@ -31,10 +32,11 @@
"cache": false,
"inputs": ["contracts/{script,src,test}/**/*.sol"]
},
"//#format.prettier.fix": {
"//#format.biome.fix": {
"cache": false,
"inputs": [
"*.{cjs,js,jsx,ts,tsx,yaml,yml,json,md,mdx,css,html,graphql}",
"{.github,pkgs,circom,discord-bot,query-api,ui}/**/*.{cjs,js,jsx,ts,tsx,yaml,yml,json,md,mdx,css,html,graphql}",
"*.{cjs,js,jsx,ts,tsx,json,jsonc}",
"{.github,pkgs,circom,discord-bot,query-api,ui}/**/*.{cjs,js,jsx,ts,tsx,json,jsonc}",
"!{pkgs,circom,discord-bot,query-api,ui}/**/{build,dist,node_modules,.next}/**"
]
},
@@ -61,14 +63,14 @@
"cache": false,
"inputs": ["pkgs/{merkle-tree,spartan-ecdsa}-wasm/src/**/*.rs"]
},
"//#lint.eslint": {
"//#lint.biome": {
"inputs": [
"*.{cjs,js,jsx,ts,tsx}",
"{pkgs,circom,discord-bot,query-api,test,ui}/**/*.{cjs,js,jsx,ts,tsx}",
"!{pkgs,circom,discord-bot,query-api,ui}/**/{build,dist,node_modules,.next}/**"
]
},
"//#lint.eslint.fix": {
"//#lint.biome.fix": {
"inputs": [
"*.{cjs,js,jsx,ts,tsx}",
"{pkgs,circom,discord-bot,query-api,test,ui}/**/*.{cjs,js,jsx,ts,tsx}",

View File

@@ -6,7 +6,7 @@ const nextConfig = {
ignoreDuringBuilds: true,
},
reactStrictMode: true,
webpack: function (config, options) {
webpack: (config, options) => {
if (!options.isServer) {
config.resolve.fallback.fs = false
config.resolve.fallback.readline = false

View File

@@ -3,7 +3,7 @@ import '../globals.css'
import 'tailwindcss/tailwind.css'
import { Bubble } from '@typebot.io/nextjs'
import { StoreProvider } from 'easy-peasy'
import { ReactNode } from 'react'
import type { ReactNode } from 'react'
import { WagmiConfig } from 'wagmi'
import { config, wagmiConfig } from '#'
import { store } from '@/store'

View File

@@ -16,7 +16,7 @@ export default function Page() {
<div className='flex flex-col items-end space-y-4'>
{anonSet !== null && (
<Link href='/prove/submit'>
<button className='btn btn-secondary'>
<button type='button' className='btn btn-secondary'>
{NAVIGATION.PREPARE_PROOF_REQUEST}
</button>
</Link>

View File

@@ -42,10 +42,18 @@ export default function Page() {
<div className='text-grey'>{ellipsify(fullProof.toString(), 100)}</div>
{copySuccess}
<div className='buttons-row'>
<button onClick={copyToClipboard} className='btn btn-primary'>
<button
type='button'
onClick={copyToClipboard}
className='btn btn-primary'
>
Copy to Clipboard
</button>
<button onClick={downloadTextFile} className='btn btn-primary'>
<button
type='button'
onClick={downloadTextFile}
className='btn btn-primary'
>
Download as Text File
</button>
</div>

View File

@@ -52,7 +52,7 @@ export default function Page() {
className='input text-center'
value={min}
onChange={({ target }) => {
setMin(parseInt(target.value))
setMin(Number.parseInt(target.value))
}}
/>
</div>

View File

@@ -38,12 +38,13 @@ export default function Page() {
className='input text-center'
value={min}
onChange={({ target }) => {
setMin(parseInt(target.value))
setMin(Number.parseInt(target.value))
}}
/>
</div>
<button
type='button'
className={`btn self-center ${
canFetch ? 'btn-primary' : 'is-disabled'
}`}

View File

@@ -2,7 +2,7 @@
import Link from 'next/link'
import { useEffect } from 'react'
import { NAVIGATION } from '#'
import { JSONValue, ScrollableJsonContainer } from '@components'
import { type JSONValue, ScrollableJsonContainer } from '@components'
import { useStore } from '@hooks'
export function AnonSetResults({
@@ -25,7 +25,7 @@ export function AnonSetResults({
<h3>Results</h3>
</div>
<Link href='/prove/submit'>
<button className='btn btn-secondary'>
<button type='button' className='btn btn-secondary'>
{NAVIGATION.PREPARE_PROOF_REQUEST}
</button>
</Link>

View File

@@ -34,7 +34,12 @@ export function ConnectButton() {
}
return hasMounted ? (
<button className='btn btn-secondary' onClick={onClick} disabled={loading}>
<button
type='button'
className='btn btn-secondary'
onClick={onClick}
disabled={loading}
>
{loading ? 'Loading...' : label}
</button>
) : (

View File

@@ -8,7 +8,7 @@ export const ErrorContainer = ({ message }) => {
<div className='error-container'>
<h2 className='mb-4 text-4xl font-bold'>Something went wrong!</h2>
<p className='mb-8 text-red'>{message}</p>
<button className='btn btn-error' onClick={goBack}>
<button type='button' className='btn btn-error' onClick={goBack}>
Back
</button>
</div>

View File

@@ -1,5 +1,5 @@
import Link from 'next/link'
import { ReactNode } from 'react'
import type { ReactNode } from 'react'
export enum Links {
Twitter = 'https://twitter.com/PrivacyScaling',

View File

@@ -12,7 +12,7 @@ export const HelpModal = () => {
return (
helpText !== null && (
<div>
<button className='btn btn-secondary' onClick={open}>
<button type='button' className='btn btn-secondary' onClick={open}>
?
</button>
<Modal ref={ref}>

View File

@@ -48,7 +48,7 @@ export function JsonFileInput({
className='hidden'
ref={inputRef}
/>
<button className='btn btn-primary' onClick={onClick}>
<button type='button' className='btn btn-primary' onClick={onClick}>
<div className='flex flex-row items-center'>
<ArrowUpOnSquareIcon className='w-[40px]' />
</div>

View File

@@ -18,7 +18,7 @@ export function Loader() {
return (
<div className='mt-40 flex flex-row justify-center'>
<progress value={progress} max='100'></progress>
<progress value={progress} max='100' />
</div>
)
}

View File

@@ -1,5 +1,5 @@
'use client'
import { forwardRef, ReactNode, RefObject } from 'react'
import { forwardRef, type ReactNode, type RefObject } from 'react'
import { modal } from '#'
const Modal = forwardRef(
@@ -15,7 +15,11 @@ const Modal = forwardRef(
<form method='dialog' className='space-y-5'>
{children}
<menu className='dialog-menu flex flex-row justify-center'>
<button className='btn btn-secondary' onClick={close}>
<button
type='button'
className='btn btn-secondary'
onClick={close}
>
Cancel
</button>
</menu>

View File

@@ -1,4 +1,4 @@
import { JSONValue } from './JsonFileInput'
import type { JSONValue } from './JsonFileInput'
export function ScrollableJsonContainer({
data,

View File

@@ -47,12 +47,12 @@ export function SubmitProofRequest() {
/>
{warningWasRead ? (
<Link href='/prove/result'>
<button className='btn btn-secondary'>
<button type='button' className='btn btn-secondary'>
{NAVIGATION.SUBMIT_PROOF}
</button>
</Link>
) : (
<button className='btn btn-secondary is-disabled'>
<button type='button' className='btn btn-secondary is-disabled'>
{NAVIGATION.SUBMIT_PROOF}
</button>
)}
@@ -74,6 +74,7 @@ export function SubmitProofRequest() {
</div>
<div className='flex flex-row items-end justify-evenly'>
<button
type='button'
className={`btn ${canSign ? 'btn-primary' : 'is-disabled'}`}
onClick={() => signMessage()}
>

View File

@@ -1,8 +1,8 @@
export function Text({ lines }: { lines: string[] }) {
return (
<div className='text-center'>
{lines.map((line, i) => (
<p key={i}>{line}</p>
{lines.map((line) => (
<p key={line}>{line}</p>
))}
</div>
)

View File

@@ -19,6 +19,7 @@ export const WarningModal = ({ content }: { content: string[] }) => {
<Text lines={content} />
<menu className='dialog-menu flex flex-row justify-center'>
<button
type='button'
className='btn btn-secondary'
onClick={() => {
setWarningWasRead(true)

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'
import useSWR, { Fetcher } from 'swr'
import useSWR, { type Fetcher } from 'swr'
import { useBlockNumber } from 'wagmi'
/**

View File

@@ -1,5 +1,5 @@
import { ActionCreator } from 'easy-peasy'
import { ChangeEvent } from 'react'
import type { ActionCreator } from 'easy-peasy'
import type { ChangeEvent } from 'react'
import { readJsonFile } from '#'
import { useStoreActions } from '@hooks'

View File

@@ -1,5 +1,5 @@
import {
GenerateMerkleProofFn,
type GenerateMerkleProofFn,
MerkleTreeWorker,
} from '@anonklub/merkle-tree-worker'
import { useWorker } from '@/hooks'

View File

@@ -1,5 +1,5 @@
import { useAsync } from 'react-use'
import { Hex } from 'viem'
import type { Hex } from 'viem'
import { useStore } from '@hooks'
import { useSpartanEcdsaWorker } from './useSpartanEcdsaWorker'

View File

@@ -1,7 +1,7 @@
import {
ProveMembershipFn,
type ProveMembershipFn,
SpartanEcdsaWorker,
VerifyMembershipFn,
type VerifyMembershipFn,
} from '@anonklub/spartan-ecdsa-worker'
import { useWorker } from '@/hooks'

View File

@@ -1,5 +1,5 @@
import { createTypedHooks } from 'easy-peasy'
import { StoreModel } from '@/store'
import type { StoreModel } from '@/store'
const typedHooks = createTypedHooks<StoreModel>()

View File

@@ -1,5 +1,5 @@
import { MerkleTreeWorker } from '@anonklub/merkle-tree-worker'
import { SpartanEcdsaWorker } from '@anonklub/spartan-ecdsa-worker'
import type { MerkleTreeWorker } from '@anonklub/merkle-tree-worker'
import type { SpartanEcdsaWorker } from '@anonklub/spartan-ecdsa-worker'
import { useEffect, useState } from 'react'
export const useWorker = (

View File

@@ -1,4 +1,4 @@
import { Chain } from 'wagmi'
import type { Chain } from 'wagmi'
import { sepolia } from 'wagmi/chains'
interface Config {
@@ -16,17 +16,16 @@ interface Config {
// https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#loading-environment-variables
const walletConnectProjectId =
process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID ?? ''
;[[walletConnectProjectId, 'NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID']].forEach(
([value, name]) => {
if (value === '') {
// this means next build will fail
if (process.env.NEXT_PHASE === 'phase-production-build')
throw new Error(`Missing environment variable ${name}`)
else console.warn(`Missing environment variable ${name}`)
}
},
)
if (walletConnectProjectId === '') {
// this means next build will fail
if (process.env.NEXT_PHASE === 'phase-production-build')
throw new Error(
'Missing environment variable NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID',
)
console.warn(
'Missing environment variable NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID',
)
}
export const config: Config = {
appTitle: 'Anonklub',

View File

@@ -1,4 +1,4 @@
import { RefObject } from 'react'
import type { RefObject } from 'react'
export const modal = (ref: RefObject<HTMLDialogElement>) => {
const open = () => {

View File

@@ -1,5 +1,5 @@
import { ProofRequest } from '@anonklub/proof'
import { action, Action, createStore } from 'easy-peasy'
import type { ProofRequest } from '@anonklub/proof'
import { action, type Action, createStore } from 'easy-peasy'
export interface StoreModel {
anonSet: {