fix(tooling): lint 검사를 저메모리 하이브리드로 전환

This commit is contained in:
2026-08-31 04:58:57 +00:00
parent 8d88603305
commit 99a477b47e
18 changed files with 532 additions and 32 deletions
+36
View File
@@ -0,0 +1,36 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"categories": {
"correctness": "off"
},
"plugins": ["typescript"],
"options": {
"typeAware": true,
"respectEslintDisableDirectives": true
},
"rules": {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksVoidReturn": {
"arguments": false,
"attributes": false
}
}
]
},
"ignorePatterns": [
"**/dist/**",
"**/node_modules/**",
"**/*.d.ts",
"**/*.js",
"**/*.mjs",
"**/*.cjs",
"**/*.vue",
"legacy/**",
"packages/infra/prisma/client/**",
"**/generated/**",
".pnpm-store/**"
]
}
+5
View File
@@ -175,6 +175,11 @@ pnpm build
pnpm test:integration pnpm test:integration
``` ```
`pnpm lint`는 ESLint의 일반 TypeScript/Vue 검사, Oxlint의 type-aware TypeScript
Promise 검사, ESLint의 type-aware Vue Promise 검사를 메모리 경계에 맞게 나누어
실행합니다. cache를 제외한 전체 검증은 `pnpm lint:uncached`, package 하나만
검사할 때는 기존처럼 `pnpm --filter <package-name> lint`를 사용합니다.
루트 `test``build`는 Codex와 일반 개발 검증에서 성공 로그를 줄이는 간단 출력이 루트 `test``build`는 Codex와 일반 개발 검증에서 성공 로그를 줄이는 간단 출력이
기본입니다. 테스트별 진행과 전체 Turbo task 로그가 필요한 실패 진단에는 기본입니다. 테스트별 진행과 전체 Turbo task 로그가 필요한 실패 진단에는
`pnpm test-verbose`, `pnpm build-verbose`를 사용합니다. Gateway 서버 빌드 워커는 `pnpm test-verbose`, `pnpm build-verbose`를 사용합니다. Gateway 서버 빌드 워커는
+2 -2
View File
@@ -20,8 +20,8 @@
"worker:auction:dev": "GAME_API_ROLE=auction-worker tsdown -c ../../tsdown.config.ts -F @sammo-ts/game-api --watch", "worker:auction:dev": "GAME_API_ROLE=auction-worker tsdown -c ../../tsdown.config.ts -F @sammo-ts/game-api --watch",
"worker:tournament": "GAME_API_ROLE=tournament-worker node dist/index.js", "worker:tournament": "GAME_API_ROLE=tournament-worker node dist/index.js",
"worker:tournament:dev": "GAME_API_ROLE=tournament-worker tsdown -c ../../tsdown.config.ts -F @sammo-ts/game-api --watch", "worker:tournament:dev": "GAME_API_ROLE=tournament-worker tsdown -c ../../tsdown.config.ts -F @sammo-ts/game-api --watch",
"lint": "eslint .", "lint": "pnpm -w lint:target app/game-api",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix app/game-api",
"test": "vitest run --config vitest.config.ts", "test": "vitest run --config vitest.config.ts",
"typecheck": "pnpm -w tsc7 -b app/game-api/tsconfig.json" "typecheck": "pnpm -w tsc7 -b app/game-api/tsconfig.json"
}, },
+2 -2
View File
@@ -103,8 +103,8 @@
"build": "tsdown -c ./tsdown.config.ts && node ../../tools/check-package-exports.mjs .", "build": "tsdown -c ./tsdown.config.ts && node ../../tools/check-package-exports.mjs .",
"dev": "tsdown -c ./tsdown.config.ts --watch", "dev": "tsdown -c ./tsdown.config.ts --watch",
"start": "pnpm run build && GAME_ENGINE_ROLE=turn-daemon node dist/index.js", "start": "pnpm run build && GAME_ENGINE_ROLE=turn-daemon node dist/index.js",
"lint": "eslint .", "lint": "pnpm -w lint:target app/game-engine",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix app/game-engine",
"profile:npc-unification-memory": "node scripts/profile-npc-unification-memory.mjs", "profile:npc-unification-memory": "node scripts/profile-npc-unification-memory.mjs",
"profile:npc-unification-timing": "node scripts/profile-npc-unification-timing.mjs", "profile:npc-unification-timing": "node scripts/profile-npc-unification-timing.mjs",
"profile:npc-lifecycle-memory": "node scripts/profile-npc-lifecycle-memory.mjs", "profile:npc-lifecycle-memory": "node scripts/profile-npc-lifecycle-memory.mjs",
+2 -2
View File
@@ -28,8 +28,8 @@
"test:e2e:npc-possession-live": "pnpm --filter @sammo-ts/infra prisma:generate && pnpm --filter @sammo-ts/common build && pnpm --filter @sammo-ts/logic build && pnpm --filter @sammo-ts/infra build && pnpm --filter @sammo-ts/game-engine build && pnpm --filter @sammo-ts/game-api build && playwright test --config e2e/npcPossession.live.playwright.config.mjs --tsconfig e2e/playwright.live.tsconfig.json", "test:e2e:npc-possession-live": "pnpm --filter @sammo-ts/infra prisma:generate && pnpm --filter @sammo-ts/common build && pnpm --filter @sammo-ts/logic build && pnpm --filter @sammo-ts/infra build && pnpm --filter @sammo-ts/game-engine build && pnpm --filter @sammo-ts/game-api build && playwright test --config e2e/npcPossession.live.playwright.config.mjs --tsconfig e2e/playwright.live.tsconfig.json",
"test:e2e:die-on-prestart-live": "pnpm --filter @sammo-ts/infra prisma:generate && pnpm --filter @sammo-ts/common build && pnpm --filter @sammo-ts/logic build && pnpm --filter @sammo-ts/infra build && pnpm --filter @sammo-ts/game-engine build && pnpm --filter @sammo-ts/game-api build && playwright test --config e2e/dieOnPrestart.live.playwright.config.mjs --tsconfig e2e/playwright.live.tsconfig.json", "test:e2e:die-on-prestart-live": "pnpm --filter @sammo-ts/infra prisma:generate && pnpm --filter @sammo-ts/common build && pnpm --filter @sammo-ts/logic build && pnpm --filter @sammo-ts/infra build && pnpm --filter @sammo-ts/game-engine build && pnpm --filter @sammo-ts/game-api build && playwright test --config e2e/dieOnPrestart.live.playwright.config.mjs --tsconfig e2e/playwright.live.tsconfig.json",
"test:e2e:default-recruit-commands-live": "pnpm --filter @sammo-ts/infra prisma:generate && pnpm --filter @sammo-ts/common build && pnpm --filter @sammo-ts/logic build && pnpm --filter @sammo-ts/infra build && pnpm --filter @sammo-ts/game-engine build && pnpm --filter @sammo-ts/game-api build && playwright test --config e2e/defaultRecruitCommands.live.playwright.config.mjs --tsconfig e2e/playwright.live.tsconfig.json", "test:e2e:default-recruit-commands-live": "pnpm --filter @sammo-ts/infra prisma:generate && pnpm --filter @sammo-ts/common build && pnpm --filter @sammo-ts/logic build && pnpm --filter @sammo-ts/infra build && pnpm --filter @sammo-ts/game-engine build && pnpm --filter @sammo-ts/game-api build && playwright test --config e2e/defaultRecruitCommands.live.playwright.config.mjs --tsconfig e2e/playwright.live.tsconfig.json",
"lint": "eslint .", "lint": "pnpm -w lint:target app/game-frontend",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix app/game-frontend",
"typecheck": "vue-tsc --noEmit" "typecheck": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
+2 -2
View File
@@ -18,8 +18,8 @@
"build": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/gateway-api", "build": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/gateway-api",
"dev": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/gateway-api --watch", "dev": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/gateway-api --watch",
"orchestrator": "GATEWAY_ROLE=orchestrator node dist/index.js", "orchestrator": "GATEWAY_ROLE=orchestrator node dist/index.js",
"lint": "eslint .", "lint": "pnpm -w lint:target app/gateway-api",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix app/gateway-api",
"test": "vitest run --config vitest.config.ts", "test": "vitest run --config vitest.config.ts",
"typecheck": "pnpm -w tsc7 -b app/gateway-api/tsconfig.json" "typecheck": "pnpm -w tsc7 -b app/gateway-api/tsconfig.json"
}, },
+2 -2
View File
@@ -13,8 +13,8 @@
"build:release": "vite build", "build:release": "vite build",
"typecheck:release": "vue-tsc --noEmit", "typecheck:release": "vue-tsc --noEmit",
"preview": "vite preview", "preview": "vite preview",
"lint": "eslint .", "lint": "pnpm -w lint:target app/gateway-frontend",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix app/gateway-frontend",
"typecheck": "vue-tsc --noEmit" "typecheck": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
+2 -2
View File
@@ -11,8 +11,8 @@
"run-once": "node dist/index.js run-once", "run-once": "node dist/index.js run-once",
"status": "node dist/index.js status", "status": "node dist/index.js status",
"self-upgrade": "node dist/index.js self-upgrade", "self-upgrade": "node dist/index.js self-upgrade",
"lint": "eslint .", "lint": "pnpm -w lint:target app/release-controller",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix app/release-controller",
"test": "vitest run --config vitest.config.ts", "test": "vitest run --config vitest.config.ts",
"typecheck": "pnpm -w tsc7 -b app/release-controller/tsconfig.json" "typecheck": "pnpm -w tsc7 -b app/release-controller/tsconfig.json"
}, },
+5
View File
@@ -19,6 +19,11 @@ pnpm test
pnpm build pnpm build
``` ```
루트 lint는 ESLint의 일반 규칙과 Vue 규칙을 먼저 실행하고, type-aware Promise
규칙은 TypeScript 파일에 Oxlint, Vue SFC에 ESLint를 사용합니다. 전체 cold 경로를
확인할 때는 `pnpm lint:uncached`, package 하나는
`pnpm --filter <package-name> lint`를 사용합니다.
루트 `pnpm test``pnpm build`는 간단 출력이 기본입니다. Turbo는 실패한 task의 루트 `pnpm test``pnpm build`는 간단 출력이 기본입니다. Turbo는 실패한 task의
로그를 남기고 성공 task의 본문을 생략하며, Vitest를 package에서 직접 실행할 때도 로그를 남기고 성공 task의 본문을 생략하며, Vitest를 package에서 직접 실행할 때도
`minimal` reporter를 사용합니다. 테스트별 진행과 성공 task 로그까지 필요한 진단은 `minimal` reporter를 사용합니다. 테스트별 진행과 성공 task 로그까지 필요한 진단은
+14 -10
View File
@@ -8,12 +8,15 @@ import globals from 'globals';
// projectService reloads every TS project when this value changes between TS and Vue files. // projectService reloads every TS project when this value changes between TS and Vue files.
const extraFileExtensions = ['.vue']; const extraFileExtensions = ['.vue'];
const typedParserOptions = { const typeAware = process.env.ESLINT_TYPE_AWARE !== '0';
extraFileExtensions, const typedParserOptions = typeAware
jsDocParsingMode: 'none', ? {
projectService: true, extraFileExtensions,
tsconfigRootDir: import.meta.dirname, jsDocParsingMode: 'none',
}; projectService: true,
tsconfigRootDir: import.meta.dirname,
}
: {};
export default tseslint.config( export default tseslint.config(
{ {
@@ -68,6 +71,8 @@ export default tseslint.config(
{ {
files: ['**/*.{ts,tsx,vue}'], files: ['**/*.{ts,tsx,vue}'],
rules: { rules: {
// TypeScript resolves ambient and imported names more accurately than ESLint's base rule.
'no-undef': 'off',
'@typescript-eslint/no-unused-vars': [ '@typescript-eslint/no-unused-vars': [
'error', 'error',
{ {
@@ -84,9 +89,9 @@ export default tseslint.config(
fixStyle: 'separate-type-imports', fixStyle: 'separate-type-imports',
}, },
], ],
'@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-floating-promises': typeAware ? 'error' : 'off',
'@typescript-eslint/no-misused-promises': [ '@typescript-eslint/no-misused-promises': [
'error', typeAware ? 'error' : 'off',
{ {
checksVoidReturn: { checksVoidReturn: {
arguments: false, arguments: false,
@@ -110,8 +115,7 @@ export default tseslint.config(
{ {
object: 'Math', object: 'Math',
property: 'random', property: 'random',
message: message: 'Authoritative game state must use an explicitly seeded RandUtil/LiteHashDRBG stream.',
'Authoritative game state must use an explicitly seeded RandUtil/LiteHashDRBG stream.',
}, },
], ],
}, },
+65
View File
@@ -0,0 +1,65 @@
import tseslint from 'typescript-eslint';
import vueParser from 'vue-eslint-parser';
const project = process.env.ESLINT_TYPED_PROJECT;
if (!project) {
throw new Error('ESLINT_TYPED_PROJECT must point to the target tsconfig.json');
}
const typedParserOptions = {
extraFileExtensions: ['.vue'],
jsDocParsingMode: 'none',
project: [project],
tsconfigRootDir: import.meta.dirname,
};
const promiseRules = {
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': [
'error',
{
checksVoidReturn: {
arguments: false,
attributes: false,
},
},
],
};
const plugins = {
'@typescript-eslint': tseslint.plugin,
};
export default tseslint.config(
{
ignores: [
'**/dist/**',
'**/node_modules/**',
'**/*.d.ts',
'legacy/**',
'packages/infra/prisma/client/**',
'**/generated/**',
'.pnpm-store/**',
],
},
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: tseslint.parser,
parserOptions: typedParserOptions,
},
plugins,
rules: promiseRules,
},
{
files: ['**/*.vue'],
languageOptions: {
parser: vueParser,
parserOptions: {
...typedParserOptions,
parser: tseslint.parser,
sourceType: 'module',
},
},
plugins,
rules: promiseRules,
}
);
+7 -2
View File
@@ -5,8 +5,11 @@
"version": "0.0.0", "version": "0.0.0",
"packageManager": "pnpm@11.21.0", "packageManager": "pnpm@11.21.0",
"scripts": { "scripts": {
"lint": "NODE_OPTIONS=--max-old-space-size=1024 turbo lint --concurrency=1", "lint": "node tools/run-lint.mjs",
"lint:fix": "NODE_OPTIONS=--max-old-space-size=1024 turbo lint:fix --concurrency=1", "lint:fix": "node tools/run-lint.mjs --fix",
"lint:uncached": "node tools/run-lint.mjs --no-cache",
"lint:target": "node tools/run-lint.mjs --target",
"lint:target:fix": "node tools/run-lint.mjs --fix --target",
"format": "prettier --write .", "format": "prettier --write .",
"test": "turbo test --ui=stream --output-logs=errors-only", "test": "turbo test --ui=stream --output-logs=errors-only",
"test-verbose": "SAMMO_TEST_REPORTER=verbose turbo test --ui=stream --output-logs=full", "test-verbose": "SAMMO_TEST_REPORTER=verbose turbo test --ui=stream --output-logs=full",
@@ -53,6 +56,8 @@
"eslint-plugin-prettier": "^5.5.6", "eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-vue": "^10.10.0", "eslint-plugin-vue": "^10.10.0",
"globals": "^17.11.0", "globals": "^17.11.0",
"oxlint": "1.80.0",
"oxlint-tsgolint": "7.0.2001",
"prettier": "^3.9.6", "prettier": "^3.9.6",
"tsdown": "^0.22.14", "tsdown": "^0.22.14",
"turbo": "^2.10.9", "turbo": "^2.10.9",
+2 -2
View File
@@ -62,8 +62,8 @@
"scripts": { "scripts": {
"build": "tsdown -c ./tsdown.config.ts", "build": "tsdown -c ./tsdown.config.ts",
"dev": "tsdown -c ./tsdown.config.ts --watch", "dev": "tsdown -c ./tsdown.config.ts --watch",
"lint": "eslint .", "lint": "pnpm -w lint:target packages/common",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix packages/common",
"test": "vitest run --config vitest.config.ts", "test": "vitest run --config vitest.config.ts",
"typecheck": "pnpm -w tsc7 -b packages/common/tsconfig.json" "typecheck": "pnpm -w tsc7 -b packages/common/tsconfig.json"
}, },
+2 -2
View File
@@ -8,8 +8,8 @@
"scripts": { "scripts": {
"build": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/infra", "build": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/infra",
"dev": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/infra --watch", "dev": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/infra --watch",
"lint": "eslint .", "lint": "pnpm -w lint:target packages/infra",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix packages/infra",
"test": "vitest run --config vitest.config.ts", "test": "vitest run --config vitest.config.ts",
"prisma:generate": "pnpm prisma:generate:game && pnpm prisma:generate:gateway", "prisma:generate": "pnpm prisma:generate:game && pnpm prisma:generate:gateway",
"typecheck": "pnpm -w tsc7 -b packages/infra/tsconfig.json", "typecheck": "pnpm -w tsc7 -b packages/infra/tsconfig.json",
+2 -2
View File
@@ -15,8 +15,8 @@
"scripts": { "scripts": {
"build": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/logic", "build": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/logic",
"dev": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/logic --watch", "dev": "tsdown -c ../../tsdown.config.ts -F @sammo-ts/logic --watch",
"lint": "eslint .", "lint": "pnpm -w lint:target packages/logic",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix packages/logic",
"test": "vitest run --config vitest.config.ts", "test": "vitest run --config vitest.config.ts",
"typecheck": "pnpm -w tsc7 -b packages/logic/tsconfig.json" "typecheck": "pnpm -w tsc7 -b packages/logic/tsconfig.json"
}, },
+282
View File
@@ -49,6 +49,12 @@ importers:
globals: globals:
specifier: ^17.11.0 specifier: ^17.11.0
version: 17.11.0 version: 17.11.0
oxlint:
specifier: 1.80.0
version: 1.80.0(oxlint-tsgolint@7.0.2001)
oxlint-tsgolint:
specifier: 7.0.2001
version: 7.0.2001
prettier: prettier:
specifier: ^3.9.6 specifier: ^3.9.6
version: 3.9.6 version: 3.9.6
@@ -1335,6 +1341,158 @@ packages:
'@oxc-project/types@0.144.0': '@oxc-project/types@0.144.0':
resolution: {integrity: sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==} resolution: {integrity: sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==}
'@oxlint-tsgolint/darwin-arm64@7.0.2001':
resolution: {integrity: sha512-CUJEdbSZ54+Xy9OXqOhWLTKZKV0BBiV7C2i/ygyVmXtkUNXx5YCzN8DpSSshTAKktoL7S+tnQ/ftFG/i7X896w==}
cpu: [arm64]
os: [darwin]
'@oxlint-tsgolint/darwin-x64@7.0.2001':
resolution: {integrity: sha512-pXfBb5BqONCcgrXQNUZWXgiYmRSWJzd97S8i41VVOh6ut0tyo+cJ5FKFpczDHxiVNfj/3e7c9B4MtztNdpIVCw==}
cpu: [x64]
os: [darwin]
'@oxlint-tsgolint/linux-arm64@7.0.2001':
resolution: {integrity: sha512-roP7zujb/QDPzDwEKsFFpzNHHy91/Y7oX9vQXk78ekyZtcQj1QXDIMH33gjDdHBfRl4K9pZ36xhRgrP4Zr+R8A==}
cpu: [arm64]
os: [linux]
'@oxlint-tsgolint/linux-x64@7.0.2001':
resolution: {integrity: sha512-UDezNqdECVmngu2TPnjaS1YoAmcTaBoI5lV9vk3VahBxoi+I5r9k3iJTT7qZoYWOXTD/7T7bNcwRgrocR6BscQ==}
cpu: [x64]
os: [linux]
'@oxlint-tsgolint/win32-arm64@7.0.2001':
resolution: {integrity: sha512-uJZhqB6pdXLuN+AD1F5082byyQti/NPmJA77GtcFlmT2HzRelqbNls3SaIqxpjdFgvSBF9g0yOKGBkGFg7kX8Q==}
cpu: [arm64]
os: [win32]
'@oxlint-tsgolint/win32-x64@7.0.2001':
resolution: {integrity: sha512-FkDRm8hx9OwzGQqyWG1tO5QrTLRApff9DzSgpz9QZau37BR8d1VYKOxMLGf6shPZntJFoTwIIJYT68VndYDCog==}
cpu: [x64]
os: [win32]
'@oxlint/binding-android-arm-eabi@1.80.0':
resolution: {integrity: sha512-RM3Plj+biQpxa5d1GOOX6ciDlcUROmm4OZ/pLTpitkQt2mJv4jhtY4cbgaetOm5UKWZe05/TGQ6o1Vl8EOHkrA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [android]
'@oxlint/binding-android-arm64@1.80.0':
resolution: {integrity: sha512-YlO5JEf0Yr2bUUlu8O8daVcUxtcGGbcSmyV7E7nSbJbfAdxTE0PFPwgnIlw7wXJaTYjb+qs5hI5q3jxUkI7cAw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@oxlint/binding-darwin-arm64@1.80.0':
resolution: {integrity: sha512-BULDOyO3AhsmdWfQeIUCykDt3dd7XZBGLhp1eIh56skRv01O+cNjNPwXMIbeW1x4+pxcln5if72wcRgViVo7PA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@oxlint/binding-darwin-x64@1.80.0':
resolution: {integrity: sha512-YJ4JzLw7N5TDSQFlA0hAQGHvnDZgyypm1yunObVWcWiF9KM7eGCJKYKLgTC2Fi/57OdnBhbj4OkzPGdFQJ6HyA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@oxlint/binding-freebsd-x64@1.80.0':
resolution: {integrity: sha512-AYUIk5QnL0s8oWAYsREZwkRYy1SupJTXALo93J1TgzHywxQtdM99FecRMQ87MXEdPQ0j1TmEpeeq3fGNkpvMqg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@oxlint/binding-linux-arm-gnueabihf@1.80.0':
resolution: {integrity: sha512-9hBZVANupQ89W9dXyE0n8doCyaW5pDyGn3y6XlIMPZ+rIKuyqkr3SNUXmVJIhuvUq0NBU3RBiSXXE69l4XI6KA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@oxlint/binding-linux-arm-musleabihf@1.80.0':
resolution: {integrity: sha512-SvS2uKqzY+pbfuvAHzH4338R6Zwo805GAwrIMVvK1KxoOWCIjZUdfzTCvilD7z6JK91v011+zYMryabhDo2AsQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@oxlint/binding-linux-arm64-gnu@1.80.0':
resolution: {integrity: sha512-tCLadyqRVL3pQTRPNg7cjXKvcvS4fbyXeQHhKk5BTJ1oftQln5/yIIWbu/Xom/DX41zv2P9QGt6+D/TtQVtY3A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-arm64-musl@1.80.0':
resolution: {integrity: sha512-XfpCNRlOPcLlJl4Bn/FUhjqlR6BVavEykERBf/MV7YA9VZDa5g5znVqYhyviMafcxS9Pe/i/kPvHNO0U6svEHQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@oxlint/binding-linux-ppc64-gnu@1.80.0':
resolution: {integrity: sha512-3I4yMwcFG9NeO8ioY6JBBuKsIm5GL/x7MATt1S4tVWaxPu5HcJ+XnLUbcVBTxG8q2Wu56HSj+NmXQiVYb1lp6A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-riscv64-gnu@1.80.0':
resolution: {integrity: sha512-E1wAKymkpe1/E8helzBKdm81OBOF+ezxRyXRMEuik3ZpWDER5CPOKZwF66RsdwW98uwZv8UTFremUQtC1CzdJA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-riscv64-musl@1.80.0':
resolution: {integrity: sha512-+gLRGD4sIo3+VA++iham5UxD9tKSoJ/VOrROCEXIcknrYtQg6iIQgvjN0cpiRF7N6UYC7pJbvHJlDnMge5LRpQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@oxlint/binding-linux-s390x-gnu@1.80.0':
resolution: {integrity: sha512-aR0PrzHj9leW3NmzBAAP4EzdoBNoJcs9sjnIQPIwyRnBGYrRbXUIpEB5Q39AqK3PLY5JK5uEhDQDiUa1QSAstw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-x64-gnu@1.80.0':
resolution: {integrity: sha512-vSVh5cSo3Xxs6ghBCcFJlpbkbENzDog1qXtoXLa/HC3aCrR4XO76GZbXmQoCPHnu99nQpdCeC3H9tdNICfDh7A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-x64-musl@1.80.0':
resolution: {integrity: sha512-FfzBXpNQ8u7/ZI/p8bl73MeZ508Ax3hxWp3SiJpEFiC+BB9XcXy5FAZHTLKDPSzrUpxQZSZJAVdDmuJp/+HDBQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@oxlint/binding-openharmony-arm64@1.80.0':
resolution: {integrity: sha512-zMzbkumtmprCgRwoYNzcB3iC39fXdJIMLMU33KdCjEGLlJGOEt1+LwQ4LF8ndLzAEKVz4BR0y3V6Xrkk3Nm3yA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@oxlint/binding-win32-arm64-msvc@1.80.0':
resolution: {integrity: sha512-ib6iRcrXsk4t1fm3iKcwksyWh1ZkZXC/2mEzakl0ai2+6HZunf1WWMZ/xP9EJAvw9g9K4UVTC3NF/+G2qLrbTQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@oxlint/binding-win32-ia32-msvc@1.80.0':
resolution: {integrity: sha512-xhRWBMpLxZvgKAH6+DJZmpP+W8Y8UdQOSU1JfxSWNXsaBaRGW77j+1hCuNHlzj7OH4SPN8fYd1q0o2qrDtoVyw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ia32]
os: [win32]
'@oxlint/binding-win32-x64-msvc@1.80.0':
resolution: {integrity: sha512-yAnO7lwBYQnz2pcfBPIGQQZWIX5zd5R/1aAKIF3oE+TVj7IhoHcROjOkz3sRDngzqhfPKfFaXqug5j5rE5dn6Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
'@pinojs/redact@0.4.0': '@pinojs/redact@0.4.0':
resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==}
@@ -3977,6 +4135,23 @@ packages:
orderedmap@2.1.1: orderedmap@2.1.1:
resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==}
oxlint-tsgolint@7.0.2001:
resolution: {integrity: sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==}
hasBin: true
oxlint@1.80.0:
resolution: {integrity: sha512-5nTiSps4qdbCWLbxzuO00alHkEO2exR9YMN/ig6QXWrLsYSG0KaObOAM+l6oU2LcKPWoSAGYbkZIGEu1ViiWKA==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
oxlint-tsgolint: '>=7.0.2001'
vite-plus: '*'
peerDependenciesMeta:
oxlint-tsgolint:
optional: true
vite-plus:
optional: true
p-limit@3.1.0: p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -5522,6 +5697,81 @@ snapshots:
'@oxc-project/types@0.144.0': {} '@oxc-project/types@0.144.0': {}
'@oxlint-tsgolint/darwin-arm64@7.0.2001':
optional: true
'@oxlint-tsgolint/darwin-x64@7.0.2001':
optional: true
'@oxlint-tsgolint/linux-arm64@7.0.2001':
optional: true
'@oxlint-tsgolint/linux-x64@7.0.2001':
optional: true
'@oxlint-tsgolint/win32-arm64@7.0.2001':
optional: true
'@oxlint-tsgolint/win32-x64@7.0.2001':
optional: true
'@oxlint/binding-android-arm-eabi@1.80.0':
optional: true
'@oxlint/binding-android-arm64@1.80.0':
optional: true
'@oxlint/binding-darwin-arm64@1.80.0':
optional: true
'@oxlint/binding-darwin-x64@1.80.0':
optional: true
'@oxlint/binding-freebsd-x64@1.80.0':
optional: true
'@oxlint/binding-linux-arm-gnueabihf@1.80.0':
optional: true
'@oxlint/binding-linux-arm-musleabihf@1.80.0':
optional: true
'@oxlint/binding-linux-arm64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-arm64-musl@1.80.0':
optional: true
'@oxlint/binding-linux-ppc64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-riscv64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-riscv64-musl@1.80.0':
optional: true
'@oxlint/binding-linux-s390x-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-x64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-x64-musl@1.80.0':
optional: true
'@oxlint/binding-openharmony-arm64@1.80.0':
optional: true
'@oxlint/binding-win32-arm64-msvc@1.80.0':
optional: true
'@oxlint/binding-win32-ia32-msvc@1.80.0':
optional: true
'@oxlint/binding-win32-x64-msvc@1.80.0':
optional: true
'@pinojs/redact@0.4.0': {} '@pinojs/redact@0.4.0': {}
'@pkgr/core@0.3.6': {} '@pkgr/core@0.3.6': {}
@@ -7952,6 +8202,38 @@ snapshots:
orderedmap@2.1.1: {} orderedmap@2.1.1: {}
oxlint-tsgolint@7.0.2001:
optionalDependencies:
'@oxlint-tsgolint/darwin-arm64': 7.0.2001
'@oxlint-tsgolint/darwin-x64': 7.0.2001
'@oxlint-tsgolint/linux-arm64': 7.0.2001
'@oxlint-tsgolint/linux-x64': 7.0.2001
'@oxlint-tsgolint/win32-arm64': 7.0.2001
'@oxlint-tsgolint/win32-x64': 7.0.2001
oxlint@1.80.0(oxlint-tsgolint@7.0.2001):
optionalDependencies:
'@oxlint/binding-android-arm-eabi': 1.80.0
'@oxlint/binding-android-arm64': 1.80.0
'@oxlint/binding-darwin-arm64': 1.80.0
'@oxlint/binding-darwin-x64': 1.80.0
'@oxlint/binding-freebsd-x64': 1.80.0
'@oxlint/binding-linux-arm-gnueabihf': 1.80.0
'@oxlint/binding-linux-arm-musleabihf': 1.80.0
'@oxlint/binding-linux-arm64-gnu': 1.80.0
'@oxlint/binding-linux-arm64-musl': 1.80.0
'@oxlint/binding-linux-ppc64-gnu': 1.80.0
'@oxlint/binding-linux-riscv64-gnu': 1.80.0
'@oxlint/binding-linux-riscv64-musl': 1.80.0
'@oxlint/binding-linux-s390x-gnu': 1.80.0
'@oxlint/binding-linux-x64-gnu': 1.80.0
'@oxlint/binding-linux-x64-musl': 1.80.0
'@oxlint/binding-openharmony-arm64': 1.80.0
'@oxlint/binding-win32-arm64-msvc': 1.80.0
'@oxlint/binding-win32-ia32-msvc': 1.80.0
'@oxlint/binding-win32-x64-msvc': 1.80.0
oxlint-tsgolint: 7.0.2001
p-limit@3.1.0: p-limit@3.1.0:
dependencies: dependencies:
yocto-queue: 0.1.0 yocto-queue: 0.1.0
+2 -2
View File
@@ -8,8 +8,8 @@
}, },
"scripts": { "scripts": {
"build": "tsdown src/cli.ts --no-config --format esm --out-dir dist --dts --sourcemap --target node22 --platform node", "build": "tsdown src/cli.ts --no-config --format esm --out-dir dist --dts --sourcemap --target node22 --platform node",
"lint": "eslint .", "lint": "pnpm -w lint:target tools/legacy-db-migration",
"lint:fix": "eslint . --fix", "lint:fix": "pnpm -w lint:target:fix tools/legacy-db-migration",
"test": "vitest run --config vitest.config.ts", "test": "vitest run --config vitest.config.ts",
"typecheck": "pnpm -w tsc7 -b tools/legacy-db-migration/tsconfig.json", "typecheck": "pnpm -w tsc7 -b tools/legacy-db-migration/tsconfig.json",
"migrate": "tsx src/cli.ts" "migrate": "tsx src/cli.ts"
+98
View File
@@ -0,0 +1,98 @@
import { spawnSync } from 'node:child_process';
const allLintTargets = [
'app/game-api',
'app/game-engine',
'app/game-frontend',
'app/gateway-api',
'app/gateway-frontend',
'app/release-controller',
'packages/common',
'packages/infra',
'packages/logic',
'tools/legacy-db-migration',
];
const targetArgumentIndex = process.argv.indexOf('--target');
const requestedTarget = targetArgumentIndex === -1 ? undefined : process.argv[targetArgumentIndex + 1];
if (targetArgumentIndex !== -1 && !requestedTarget) {
console.error('Usage: run-lint.mjs --target <workspace-path>');
process.exit(2);
}
if (requestedTarget && !allLintTargets.includes(requestedTarget)) {
console.error(`Unknown lint target: ${requestedTarget}`);
process.exit(2);
}
const lintTargets = requestedTarget ? [requestedTarget] : allLintTargets;
const eslintTargets = [
...lintTargets,
...(!requestedTarget ? ['eslint.config.js', 'eslint.promise.config.js', 'tools/run-lint.mjs'] : []),
];
const vueTargets = ['app/game-frontend', 'app/gateway-frontend']
.filter((target) => lintTargets.includes(target))
.map((target) => ({ glob: `${target}/**/*.vue`, project: `${target}/tsconfig.json`, target }));
const shouldFix = process.argv.includes('--fix');
const useCache = !process.argv.includes('--no-cache');
const pnpmCommand = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
const withNodeHeap = (heapSizeMb, extraEnv = {}) => {
const inheritedOptions = (process.env.NODE_OPTIONS ?? '')
.replace(/--max[-_]old[-_]space[-_]size(?:=|\s+)\d+/g, '')
.trim();
return {
...process.env,
...extraEnv,
NODE_OPTIONS: `${inheritedOptions} --max-old-space-size=${heapSizeMb}`.trim(),
};
};
const run = (label, args, env = process.env) => {
console.log(`\n[lint] ${label}`);
const result = spawnSync(pnpmCommand, ['exec', ...args], {
env,
stdio: 'inherit',
});
if (result.error) {
throw result.error;
}
if (result.status !== 0) {
process.exit(result.status ?? 1);
}
};
run(
'ESLint syntax and Vue rules',
[
'eslint',
...(shouldFix ? ['--fix'] : []),
...(useCache
? ['--cache', '--cache-strategy', 'content', '--cache-location', 'node_modules/.cache/eslint/syntax']
: []),
...eslintTargets,
],
withNodeHeap(512, { ESLINT_TYPE_AWARE: '0' })
);
for (const lintTarget of lintTargets) {
run(`Oxlint type-aware TypeScript promise rules: ${lintTarget}`, ['oxlint', lintTarget]);
}
for (const vueTarget of vueTargets) {
const cacheName = vueTarget.target.split('/')[1];
run(
`ESLint type-aware Vue promise rules: ${vueTarget.glob}`,
[
'eslint',
'--config',
'eslint.promise.config.js',
...(useCache
? [
'--cache',
'--cache-strategy',
'content',
'--cache-location',
`node_modules/.cache/eslint/${cacheName}-vue-promise`,
]
: []),
vueTarget.glob,
],
withNodeHeap(1280, { ESLINT_TYPED_PROJECT: vueTarget.project })
);
}