Lines 11-51javascript
11// command resolves them out of the game's installed engine, which is the very
12// same file its eslint.config.js imports. One copy: the gate and the editor
15// Escape hatch: `// eslint-disable-next-line looop/<rule>` — the one every
16// developer already knows. This is mandatory, not a nicety: creators are not
17// developers, and a false positive must never wall someone out of their own
18// test command with no way through.
19import { existsSync } from 'node:fs';
20import { createRequire } from 'node:module';
21import { join, relative } from 'node:path';
22import { pathToFileURL } from 'node:url';
23import { findProject, resolveEngine } from './project.mjs';
25const CONFIG_NAMES = ['eslint.config.js', 'eslint.config.mjs', 'eslint.config.cjs'];
27// Resolve ESLint from the GAME's node_modules — same preflight shape as
28// playwright in test-cmd.mjs. Games scaffolded before lint existed simply don't
29// have it; they skip rather than break.
30async function loadFromProject(projectDir) {
32 const req = createRequire(join(projectDir, 'package.json'));
33 const mod = await import(pathToFileURL(req.resolve('eslint')).href);
MediumDynamic Require
Package source references dynamic require/import behavior.
lib/lint.mjsView on unpkg · L31 34 return mod.ESLint ?? mod.default?.ESLint ?? null;
40// The shareable config, out of the installed engine artifact.
42// The two ways this can come up empty are DIFFERENT problems with different
43// fixes, and conflating them sends people in a circle: the first version of this
44// said "engine ships no rules — run looop update" when the engine was not
45// installed at all, so `looop update` was the one command that could never help.
47async function loadRulesFromEngine(projectDir) {
50 ({ dir: engineDir } = resolveEngine(projectDir));