Repository navigation
Expand file tree
/
Copy patheslint.config.js
More file actions
120 lines (117 loc) · 3.63 KB
/
Copy patheslint.config.js
File metadata and controls
120 lines (117 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import prettier from 'eslint-config-prettier'
const DETERMINISM_HINT = 'Use the seeded RandomSource and the simulation clock instead.'
const MATH_HINT = 'use the engine math in math/trig.ts (docs/simulation/determinism.md).'
const ITERATION_HINT =
'iterate stores in id order or a fixed array (docs/simulation/determinism.md).'
// Transcendental and other implementation-defined Math functions (see determinism.md, section 6).
const PLATFORM_MATH = [
'sin',
'cos',
'tan',
'asin',
'acos',
'atan',
'atan2',
'sinh',
'cosh',
'tanh',
'asinh',
'acosh',
'atanh',
'log',
'log2',
'log10',
'log1p',
'exp',
'expm1',
'pow',
'hypot',
'cbrt'
]
export default tseslint.config(
{
ignores: ['**/dist/**', '**/node_modules/**', 'legacy/**', '.claude/**', '.dev/**']
},
js.configs.recommended,
...tseslint.configs.recommended,
prettier,
{
// The simulation engine must stay headless and deterministic (ADR 0001).
files: ['packages/simulation/src/**/*.ts'],
rules: {
'@typescript-eslint/no-explicit-any': 'error',
'no-console': 'error',
'no-restricted-imports': [
'error',
{
paths: ['react', 'react-dom', 'vite', 'electron', 'pixi.js'].map((name) => ({
name,
message: `The simulation engine must not import "${name}".`
})),
patterns: [
{
group: ['react/*', 'react-dom/*', 'vite/*', '@vitejs/*', 'electron/*', '@electron/*'],
message: 'The simulation engine must not import UI, bundler, or desktop packages.'
}
]
}
],
'no-restricted-globals': [
'error',
...[
'window',
'document',
'navigator',
'localStorage',
'sessionStorage',
'indexedDB',
'requestAnimationFrame',
'cancelAnimationFrame',
'HTMLCanvasElement',
'CanvasRenderingContext2D',
'OffscreenCanvas'
].map((name) => ({
name,
message: 'The simulation engine must not use browser APIs.'
}))
],
'no-restricted-properties': [
'error',
{ object: 'Math', property: 'random', message: DETERMINISM_HINT },
{ object: 'Date', property: 'now', message: DETERMINISM_HINT },
{ object: 'performance', property: 'now', message: DETERMINISM_HINT },
...PLATFORM_MATH.map((property) => ({
object: 'Math',
property,
message: `Math.${property} is implementation-defined; ${MATH_HINT}`
})),
...['keys', 'values', 'entries'].map((property) => ({
object: 'Object',
property,
message: `Object.${property} depends on enumeration order; ${ITERATION_HINT}`
}))
],
'no-restricted-syntax': [
'error',
{
selector: "NewExpression[callee.name='Date'][arguments.length=0]",
message: `Wall-clock time is not allowed in simulation code. ${DETERMINISM_HINT}`
},
{
selector: "BinaryExpression[operator='**'], AssignmentExpression[operator='**=']",
message: `The ** operator is implementation-defined for non-integer exponents; ${MATH_HINT}`
},
{
selector: 'ForInStatement',
message: `for...in depends on property enumeration order; ${ITERATION_HINT}`
},
{
selector: "CallExpression[callee.property.name='sort'][arguments.length=0]",
message: 'Array.prototype.sort without a comparator sorts lexicographically; pass one.'
}
]
}
}
)