@prover-coder-ai/context-doc 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jscpd.json +16 -0
- package/CHANGELOG.md +13 -0
- package/bin/context-doc.js +12 -0
- package/biome.json +37 -0
- package/eslint.config.mts +305 -0
- package/eslint.effect-ts-check.config.mjs +220 -0
- package/linter.config.json +33 -0
- package/package.json +72 -41
- package/src/app/main.ts +29 -0
- package/src/app/program.ts +32 -0
- package/src/core/knowledge.ts +93 -129
- package/src/shell/cli.ts +73 -5
- package/src/shell/services/crypto.ts +50 -0
- package/src/shell/services/file-system.ts +142 -0
- package/src/shell/services/runtime-env.ts +54 -0
- package/src/shell/sync/index.ts +35 -0
- package/src/shell/sync/shared.ts +229 -0
- package/src/shell/sync/sources/claude.ts +54 -0
- package/src/shell/sync/sources/codex.ts +261 -0
- package/src/shell/sync/sources/qwen.ts +97 -0
- package/src/shell/sync/types.ts +47 -0
- package/tests/core/knowledge.test.ts +95 -0
- package/tests/shell/cli-pack.test.ts +176 -0
- package/tests/shell/sync-knowledge.test.ts +203 -0
- package/tests/support/fs-helpers.ts +50 -0
- package/tsconfig.json +19 -0
- package/vite.config.ts +32 -0
- package/vitest.config.ts +70 -66
- package/README.md +0 -42
- package/dist/core/greeting.js +0 -25
- package/dist/core/knowledge.js +0 -54
- package/dist/main.js +0 -27
- package/dist/shell/claudeSync.js +0 -23
- package/dist/shell/cli.js +0 -5
- package/dist/shell/codexSync.js +0 -129
- package/dist/shell/qwenSync.js +0 -41
- package/dist/shell/syncKnowledge.js +0 -39
- package/dist/shell/syncShared.js +0 -49
- package/dist/shell/syncTypes.js +0 -1
- package/src/core/greeting.ts +0 -39
- package/src/main.ts +0 -49
- package/src/shell/claudeSync.ts +0 -55
- package/src/shell/codexSync.ts +0 -236
- package/src/shell/qwenSync.ts +0 -73
- package/src/shell/syncKnowledge.ts +0 -49
- package/src/shell/syncShared.ts +0 -94
- package/src/shell/syncTypes.ts +0 -30
- package/src/types/env.d.ts +0 -10
- package/tsconfig.build.json +0 -18
package/.jscpd.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"threshold": 0,
|
|
3
|
+
"minTokens": 30,
|
|
4
|
+
"minLines": 5,
|
|
5
|
+
"ignore": [
|
|
6
|
+
"**/node_modules/**",
|
|
7
|
+
"**/build/**",
|
|
8
|
+
"**/dist/**",
|
|
9
|
+
"**/*.min.js",
|
|
10
|
+
"**/reports/**"
|
|
11
|
+
],
|
|
12
|
+
"skipComments": true,
|
|
13
|
+
"ignorePattern": [
|
|
14
|
+
"private readonly \\w+: \\w+;\\s*private readonly \\w+: \\w+;\\s*private \\w+: \\w+ \\| null = null;\\s*private \\w+: \\w+ \\| null = null;"
|
|
15
|
+
]
|
|
16
|
+
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// CHANGE: add a shebang CLI shim for npx execution
|
|
3
|
+
// WHY: npx needs an executable entry that invokes the built main module
|
|
4
|
+
// QUOTE(TZ): "Только вызов нашего пакета должен быть"
|
|
5
|
+
// REF: user-2026-01-19-npx-check
|
|
6
|
+
// SOURCE: n/a
|
|
7
|
+
// FORMAT THEOREM: forall env: exec(bin) -> runMain(program)
|
|
8
|
+
// PURITY: SHELL
|
|
9
|
+
// EFFECT: Effect<void, never, RuntimeEnv | FileSystemService | CryptoService | Path>
|
|
10
|
+
// INVARIANT: built main module is executed exactly once per invocation
|
|
11
|
+
// COMPLEXITY: O(1)/O(1)
|
|
12
|
+
import "../dist/main.js"
|
package/biome.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vcs": {
|
|
3
|
+
"enabled": false,
|
|
4
|
+
"clientKind": "git",
|
|
5
|
+
"useIgnoreFile": false
|
|
6
|
+
},
|
|
7
|
+
"files": {
|
|
8
|
+
"ignoreUnknown": false
|
|
9
|
+
},
|
|
10
|
+
"formatter": {
|
|
11
|
+
"enabled": false,
|
|
12
|
+
"indentStyle": "tab"
|
|
13
|
+
},
|
|
14
|
+
"assist": {
|
|
15
|
+
"actions": {
|
|
16
|
+
"source": {
|
|
17
|
+
"organizeImports": "off"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"linter": {
|
|
22
|
+
"enabled": false,
|
|
23
|
+
"rules": {
|
|
24
|
+
"recommended": false,
|
|
25
|
+
"suspicious": {
|
|
26
|
+
"noExplicitAny": "off"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"javascript": {
|
|
31
|
+
"formatter": {
|
|
32
|
+
"enabled": false,
|
|
33
|
+
"quoteStyle": "double",
|
|
34
|
+
"semicolons": "asNeeded"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// eslint.config.mjs
|
|
2
|
+
// @ts-check
|
|
3
|
+
import eslint from '@eslint/js';
|
|
4
|
+
import { defineConfig } from 'eslint/config';
|
|
5
|
+
import tseslint from 'typescript-eslint';
|
|
6
|
+
import vitest from "@vitest/eslint-plugin";
|
|
7
|
+
import suggestMembers from "@prover-coder-ai/eslint-plugin-suggest-members";
|
|
8
|
+
import sonarjs from "eslint-plugin-sonarjs";
|
|
9
|
+
import unicorn from "eslint-plugin-unicorn";
|
|
10
|
+
import * as effectEslint from "@effect/eslint-plugin";
|
|
11
|
+
import { fixupPluginRules } from "@eslint/compat";
|
|
12
|
+
import codegen from "eslint-plugin-codegen";
|
|
13
|
+
import importPlugin from "eslint-plugin-import";
|
|
14
|
+
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
|
15
|
+
import sortDestructureKeys from "eslint-plugin-sort-destructure-keys";
|
|
16
|
+
import globals from "globals";
|
|
17
|
+
import eslintCommentsConfigs from "@eslint-community/eslint-plugin-eslint-comments/configs";
|
|
18
|
+
|
|
19
|
+
const codegenPlugin = fixupPluginRules(
|
|
20
|
+
codegen as unknown as Parameters<typeof fixupPluginRules>[0],
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const noFetchExample = [
|
|
24
|
+
"Пример:",
|
|
25
|
+
" import { FetchHttpClient, HttpClient } from \"@effect/platform\"",
|
|
26
|
+
" import { Effect } from \"effect\"",
|
|
27
|
+
" const program = Effect.gen(function* () {",
|
|
28
|
+
" const client = yield* HttpClient.HttpClient",
|
|
29
|
+
" return yield* client.get(`${api}/robots`)",
|
|
30
|
+
" }).pipe(",
|
|
31
|
+
" Effect.scoped,",
|
|
32
|
+
" Effect.provide(FetchHttpClient.layer)",
|
|
33
|
+
" )",
|
|
34
|
+
].join("\n");
|
|
35
|
+
|
|
36
|
+
export default defineConfig(
|
|
37
|
+
eslint.configs.recommended,
|
|
38
|
+
tseslint.configs.strictTypeChecked,
|
|
39
|
+
effectEslint.configs.dprint,
|
|
40
|
+
suggestMembers.configs.recommended,
|
|
41
|
+
eslintCommentsConfigs.recommended,
|
|
42
|
+
{
|
|
43
|
+
name: "analyzers",
|
|
44
|
+
languageOptions: {
|
|
45
|
+
parser: tseslint.parser,
|
|
46
|
+
globals: { ...globals.node, ...globals.browser },
|
|
47
|
+
parserOptions: {
|
|
48
|
+
projectService: true,
|
|
49
|
+
tsconfigRootDir: import.meta.dirname,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
plugins: {
|
|
53
|
+
sonarjs,
|
|
54
|
+
unicorn,
|
|
55
|
+
import: fixupPluginRules(importPlugin),
|
|
56
|
+
"sort-destructure-keys": sortDestructureKeys,
|
|
57
|
+
"simple-import-sort": simpleImportSort,
|
|
58
|
+
codegen: codegenPlugin,
|
|
59
|
+
},
|
|
60
|
+
files: ["**/*.ts", '**/*.{test,spec}.{ts,tsx}', '**/tests/**', '**/__tests__/**'],
|
|
61
|
+
settings: {
|
|
62
|
+
"import/parsers": {
|
|
63
|
+
"@typescript-eslint/parser": [".ts", ".tsx"],
|
|
64
|
+
},
|
|
65
|
+
"import/resolver": {
|
|
66
|
+
typescript: {
|
|
67
|
+
alwaysTryTypes: true,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
rules: {
|
|
72
|
+
...sonarjs.configs.recommended.rules,
|
|
73
|
+
...unicorn.configs.recommended.rules,
|
|
74
|
+
"no-restricted-imports": ["error", {
|
|
75
|
+
paths: [
|
|
76
|
+
{
|
|
77
|
+
name: "ts-pattern",
|
|
78
|
+
message: "Use Effect.Match instead of ts-pattern.",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "zod",
|
|
82
|
+
message: "Use @effect/schema for schemas and validation.",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
}],
|
|
86
|
+
"codegen/codegen": "error",
|
|
87
|
+
"import/first": "error",
|
|
88
|
+
"import/newline-after-import": "error",
|
|
89
|
+
"import/no-duplicates": "error",
|
|
90
|
+
"import/no-unresolved": "off",
|
|
91
|
+
"import/order": "off",
|
|
92
|
+
"simple-import-sort/imports": "off",
|
|
93
|
+
"sort-destructure-keys/sort-destructure-keys": "error",
|
|
94
|
+
"no-fallthrough": "off",
|
|
95
|
+
"no-irregular-whitespace": "off",
|
|
96
|
+
"object-shorthand": "error",
|
|
97
|
+
"prefer-destructuring": "off",
|
|
98
|
+
"sort-imports": "off",
|
|
99
|
+
"no-unused-vars": "off",
|
|
100
|
+
"prefer-rest-params": "off",
|
|
101
|
+
"prefer-spread": "off",
|
|
102
|
+
"unicorn/prefer-top-level-await": "off",
|
|
103
|
+
"unicorn/prevent-abbreviations": "off",
|
|
104
|
+
"unicorn/no-null": "off",
|
|
105
|
+
complexity: ["error", 8],
|
|
106
|
+
"max-lines-per-function": [
|
|
107
|
+
"error",
|
|
108
|
+
{ max: 50, skipBlankLines: true, skipComments: true },
|
|
109
|
+
],
|
|
110
|
+
"max-params": ["error", 5],
|
|
111
|
+
"max-depth": ["error", 4],
|
|
112
|
+
"max-lines": [
|
|
113
|
+
"error",
|
|
114
|
+
{ max: 300, skipBlankLines: true, skipComments: true },
|
|
115
|
+
],
|
|
116
|
+
|
|
117
|
+
"@typescript-eslint/restrict-template-expressions": ["error", {
|
|
118
|
+
allowNumber: true,
|
|
119
|
+
allowBoolean: true,
|
|
120
|
+
allowNullish: false,
|
|
121
|
+
allowAny: false,
|
|
122
|
+
allowRegExp: false
|
|
123
|
+
}],
|
|
124
|
+
"@eslint-community/eslint-comments/no-use": "error",
|
|
125
|
+
"@eslint-community/eslint-comments/no-unlimited-disable": "error",
|
|
126
|
+
"@eslint-community/eslint-comments/disable-enable-pair": "error",
|
|
127
|
+
"@eslint-community/eslint-comments/no-unused-disable": "error",
|
|
128
|
+
"no-restricted-syntax": [
|
|
129
|
+
"error",
|
|
130
|
+
{
|
|
131
|
+
selector: "TSUnknownKeyword",
|
|
132
|
+
message: "Запрещено 'unknown'.",
|
|
133
|
+
},
|
|
134
|
+
// CHANGE: запрет прямого fetch в коде
|
|
135
|
+
// WHY: enforce Effect-TS httpClient as единственный источник сетевых эффектов
|
|
136
|
+
// QUOTE(ТЗ): "Вместо fetch должно быть всегда написано httpClient от библиотеки Effect-TS"
|
|
137
|
+
// REF: user-msg-1
|
|
138
|
+
// SOURCE: n/a
|
|
139
|
+
// FORMAT THEOREM: ∀call ∈ Calls: callee(call)=fetch → lint_error(call)
|
|
140
|
+
// PURITY: SHELL
|
|
141
|
+
// EFFECT: Effect<never, never, never>
|
|
142
|
+
// INVARIANT: direct fetch calls are forbidden
|
|
143
|
+
// COMPLEXITY: O(1)
|
|
144
|
+
{
|
|
145
|
+
selector: "CallExpression[callee.name='fetch']",
|
|
146
|
+
message: `Запрещён fetch — используй HttpClient (Effect-TS).\n${noFetchExample}`,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
selector:
|
|
150
|
+
"CallExpression[callee.object.name='window'][callee.property.name='fetch']",
|
|
151
|
+
message: `Запрещён window.fetch — используй HttpClient (Effect-TS).\n${noFetchExample}`,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
selector:
|
|
155
|
+
"CallExpression[callee.object.name='globalThis'][callee.property.name='fetch']",
|
|
156
|
+
message: `Запрещён globalThis.fetch — используй HttpClient (Effect-TS).\n${noFetchExample}`,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
selector:
|
|
160
|
+
"CallExpression[callee.object.name='self'][callee.property.name='fetch']",
|
|
161
|
+
message: `Запрещён self.fetch — используй HttpClient (Effect-TS).\n${noFetchExample}`,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
selector:
|
|
165
|
+
"CallExpression[callee.object.name='global'][callee.property.name='fetch']",
|
|
166
|
+
message: `Запрещён global.fetch — используй HttpClient (Effect-TS).\n${noFetchExample}`,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
selector: "TryStatement",
|
|
170
|
+
message: "Используй Effect.try / catchAll вместо try/catch в core/app/domain.",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
selector: "SwitchStatement",
|
|
174
|
+
message: [
|
|
175
|
+
"Switch statements are forbidden in functional programming paradigm.",
|
|
176
|
+
"How to fix: Use Effect.Match instead.",
|
|
177
|
+
"Example:",
|
|
178
|
+
" import { Match } from 'effect';",
|
|
179
|
+
" type Item = { type: 'this' } | { type: 'that' };",
|
|
180
|
+
" const result = Match.value(item).pipe(",
|
|
181
|
+
" Match.when({ type: 'this' }, (it) => processThis(it)),",
|
|
182
|
+
" Match.when({ type: 'that' }, (it) => processThat(it)),",
|
|
183
|
+
" Match.exhaustive,",
|
|
184
|
+
" );",
|
|
185
|
+
].join("\n"),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
selector: 'CallExpression[callee.name="require"]',
|
|
189
|
+
message: "Avoid using require(). Use ES6 imports instead.",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
selector: "ThrowStatement > Literal:not([value=/^\\w+Error:/])",
|
|
193
|
+
message:
|
|
194
|
+
'Do not throw string literals or non-Error objects. Throw new Error("...") instead.',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
selector:
|
|
198
|
+
"FunctionDeclaration[async=true], FunctionExpression[async=true], ArrowFunctionExpression[async=true]",
|
|
199
|
+
message:
|
|
200
|
+
"Запрещён async/await — используй Effect.gen / Effect.tryPromise.",
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
selector: "NewExpression[callee.name='Promise']",
|
|
204
|
+
message:
|
|
205
|
+
"Запрещён new Promise — используй Effect.async / Effect.tryPromise.",
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
selector: "CallExpression[callee.object.name='Promise']",
|
|
209
|
+
message:
|
|
210
|
+
"Запрещены Promise.* — используй комбинаторы Effect (all, forEach, etc.).",
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
selector: "CallExpression[callee.property.name='push'] > SpreadElement.arguments",
|
|
214
|
+
message: "Do not use spread arguments in Array.push",
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
"no-throw-literal": "error",
|
|
218
|
+
"@typescript-eslint/no-restricted-types": [
|
|
219
|
+
"error",
|
|
220
|
+
{
|
|
221
|
+
types: {
|
|
222
|
+
unknown: {
|
|
223
|
+
message:
|
|
224
|
+
"Не используем 'unknown'. Уточни тип или наведи порядок в источнике данных.",
|
|
225
|
+
},
|
|
226
|
+
Promise: {
|
|
227
|
+
message: "Запрещён Promise — используй Effect.Effect<A, E, R>.",
|
|
228
|
+
suggest: ["Effect.Effect"],
|
|
229
|
+
},
|
|
230
|
+
"Promise<*>": {
|
|
231
|
+
message:
|
|
232
|
+
"Запрещён Promise<T> — используй Effect.Effect<T, E, R>.",
|
|
233
|
+
suggest: ["Effect.Effect<T, E, R>"],
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
"@typescript-eslint/use-unknown-in-catch-callback-variable": "off",
|
|
239
|
+
// "no-throw-literal": "off",
|
|
240
|
+
"@typescript-eslint/only-throw-error": [
|
|
241
|
+
"error",
|
|
242
|
+
{ allowThrowingUnknown: false, allowThrowingAny: false },
|
|
243
|
+
],
|
|
244
|
+
"@typescript-eslint/array-type": ["warn", {
|
|
245
|
+
default: "generic",
|
|
246
|
+
readonly: "generic"
|
|
247
|
+
}],
|
|
248
|
+
"@typescript-eslint/member-delimiter-style": 0,
|
|
249
|
+
"@typescript-eslint/no-non-null-assertion": "off",
|
|
250
|
+
"@typescript-eslint/ban-types": "off",
|
|
251
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
252
|
+
"@typescript-eslint/no-empty-interface": "off",
|
|
253
|
+
"@typescript-eslint/consistent-type-imports": "warn",
|
|
254
|
+
"@typescript-eslint/no-unused-vars": ["error", {
|
|
255
|
+
argsIgnorePattern: "^_",
|
|
256
|
+
varsIgnorePattern: "^_"
|
|
257
|
+
}],
|
|
258
|
+
"@typescript-eslint/ban-ts-comment": "off",
|
|
259
|
+
"@typescript-eslint/camelcase": "off",
|
|
260
|
+
"@typescript-eslint/explicit-function-return-type": "off",
|
|
261
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
262
|
+
"@typescript-eslint/interface-name-prefix": "off",
|
|
263
|
+
"@typescript-eslint/no-array-constructor": "off",
|
|
264
|
+
"@typescript-eslint/no-use-before-define": "off",
|
|
265
|
+
"@typescript-eslint/no-namespace": "off",
|
|
266
|
+
"@effect/dprint": ["error", {
|
|
267
|
+
config: {
|
|
268
|
+
indentWidth: 2,
|
|
269
|
+
lineWidth: 120,
|
|
270
|
+
semiColons: "asi",
|
|
271
|
+
quoteStyle: "alwaysDouble",
|
|
272
|
+
trailingCommas: "never",
|
|
273
|
+
operatorPosition: "maintain",
|
|
274
|
+
"arrowFunction.useParentheses": "force"
|
|
275
|
+
}
|
|
276
|
+
}]
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
files: ['**/*.{test,spec}.{ts,tsx}', 'tests/**', '**/__tests__/**'],
|
|
281
|
+
...vitest.configs.all,
|
|
282
|
+
languageOptions: {
|
|
283
|
+
globals: {
|
|
284
|
+
...vitest.environments.env.globals,
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
rules: {
|
|
288
|
+
// Allow eslint-disable/enable comments in test files for fine-grained control
|
|
289
|
+
'@eslint-community/eslint-comments/no-use': 'off',
|
|
290
|
+
// Disable line count limit for E2E tests that contain multiple test cases
|
|
291
|
+
'max-lines-per-function': 'off',
|
|
292
|
+
// `it.effect` is not recognized by sonar rule; disable to avoid false positives
|
|
293
|
+
'sonarjs/no-empty-test-file': 'off',
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
// 3) Для JS-файлов отключим типо-зависимые проверки
|
|
298
|
+
{
|
|
299
|
+
files: ['**/*.{js,cjs,mjs}'],
|
|
300
|
+
extends: [tseslint.configs.disableTypeChecked],
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
// 4) Глобальные игноры
|
|
304
|
+
{ ignores: ['dist/**', 'build/**', 'coverage/**', '**/dist/**'] },
|
|
305
|
+
);
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// CHANGE: add Effect-TS compliance lint profile
|
|
2
|
+
// WHY: detect current deviations from strict Effect-TS guidance
|
|
3
|
+
// QUOTE(TZ): n/a
|
|
4
|
+
// REF: AGENTS.md Effect-TS compliance checks
|
|
5
|
+
// SOURCE: n/a
|
|
6
|
+
// PURITY: SHELL
|
|
7
|
+
// EFFECT: eslint config
|
|
8
|
+
// INVARIANT: config only flags explicit policy deviations
|
|
9
|
+
// COMPLEXITY: O(1)/O(1)
|
|
10
|
+
import eslintComments from "@eslint-community/eslint-plugin-eslint-comments"
|
|
11
|
+
import globals from "globals"
|
|
12
|
+
import tseslint from "typescript-eslint"
|
|
13
|
+
|
|
14
|
+
const restrictedImports = [
|
|
15
|
+
{
|
|
16
|
+
name: "node:fs",
|
|
17
|
+
message: "Use @effect/platform FileSystem instead of node:fs."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "fs",
|
|
21
|
+
message: "Use @effect/platform FileSystem instead of fs."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "node:fs/promises",
|
|
25
|
+
message: "Use @effect/platform FileSystem instead of node:fs/promises."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "node:path/posix",
|
|
29
|
+
message: "Use @effect/platform Path instead of node:path/posix."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "node:path",
|
|
33
|
+
message: "Use @effect/platform Path instead of node:path."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "path",
|
|
37
|
+
message: "Use @effect/platform Path instead of path."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "node:child_process",
|
|
41
|
+
message: "Use @effect/platform Command instead of node:child_process."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "child_process",
|
|
45
|
+
message: "Use @effect/platform Command instead of child_process."
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "node:process",
|
|
49
|
+
message: "Use @effect/platform Runtime instead of node:process."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "process",
|
|
53
|
+
message: "Use @effect/platform Runtime instead of process."
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
const restrictedSyntaxBase = [
|
|
58
|
+
{
|
|
59
|
+
selector: "SwitchStatement",
|
|
60
|
+
message: "Switch is forbidden. Use Match.exhaustive."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
selector: "TryStatement",
|
|
64
|
+
message: "Avoid try/catch in product code. Use Effect.try / Effect.catch*."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
selector: "AwaitExpression",
|
|
68
|
+
message: "Avoid await. Use Effect.gen / Effect.flatMap."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
selector: "FunctionDeclaration[async=true], FunctionExpression[async=true], ArrowFunctionExpression[async=true]",
|
|
72
|
+
message: "Avoid async/await. Use Effect.gen / Effect.tryPromise."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
selector: "NewExpression[callee.name='Promise']",
|
|
76
|
+
message: "Avoid new Promise. Use Effect.async / Effect.tryPromise."
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
selector: "CallExpression[callee.object.name='Promise']",
|
|
80
|
+
message: "Avoid Promise.*. Use Effect combinators."
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
selector: "CallExpression[callee.name='require']",
|
|
84
|
+
message: "Avoid require(). Use ES module imports."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
selector: "TSAsExpression",
|
|
88
|
+
message: "Casting is only allowed in src/core/axioms.ts."
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
selector: "TSTypeAssertion",
|
|
92
|
+
message: "Casting is only allowed in src/core/axioms.ts."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
selector: "CallExpression[callee.name='makeFilesystemService']",
|
|
96
|
+
message: "Do not instantiate FilesystemService directly. Provide Layer and access via Tag."
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
selector: "CallExpression[callee.property.name='catchAll']",
|
|
100
|
+
message: "Avoid catchAll that discards typed errors; map or propagate explicitly."
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
const restrictedSyntaxCore = [
|
|
105
|
+
...restrictedSyntaxBase,
|
|
106
|
+
{
|
|
107
|
+
selector: "TSUnknownKeyword",
|
|
108
|
+
message: "unknown is allowed only at shell boundaries with decoding."
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
selector: "CallExpression[callee.property.name='runSyncExit']",
|
|
112
|
+
message: "Effect.runSyncExit is shell-only. Move to a runner."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
selector: "CallExpression[callee.property.name='runSync']",
|
|
116
|
+
message: "Effect.runSync is shell-only. Move to a runner."
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
selector: "CallExpression[callee.property.name='runPromise']",
|
|
120
|
+
message: "Effect.runPromise is shell-only. Move to a runner."
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
const restrictedSyntaxCoreNoAs = [
|
|
125
|
+
...restrictedSyntaxCore.filter((rule) =>
|
|
126
|
+
rule.selector !== "TSAsExpression" && rule.selector !== "TSTypeAssertion"
|
|
127
|
+
)
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
const restrictedSyntaxBaseNoServiceFactory = [
|
|
131
|
+
...restrictedSyntaxBase.filter((rule) =>
|
|
132
|
+
rule.selector !== "CallExpression[callee.name='makeFilesystemService']"
|
|
133
|
+
)
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
export default tseslint.config(
|
|
137
|
+
{
|
|
138
|
+
name: "effect-ts-compliance-check",
|
|
139
|
+
files: ["src/**/*.ts", "scripts/**/*.ts"],
|
|
140
|
+
languageOptions: {
|
|
141
|
+
parser: tseslint.parser,
|
|
142
|
+
globals: { ...globals.node }
|
|
143
|
+
},
|
|
144
|
+
plugins: {
|
|
145
|
+
"@typescript-eslint": tseslint.plugin,
|
|
146
|
+
"eslint-comments": eslintComments
|
|
147
|
+
},
|
|
148
|
+
rules: {
|
|
149
|
+
"no-console": "error",
|
|
150
|
+
"no-restricted-imports": ["error", {
|
|
151
|
+
paths: restrictedImports,
|
|
152
|
+
patterns: [
|
|
153
|
+
{
|
|
154
|
+
group: ["node:*"],
|
|
155
|
+
message: "Do not import from node:* directly. Use @effect/platform-node or @effect/platform services."
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}],
|
|
159
|
+
"no-restricted-syntax": ["error", ...restrictedSyntaxBase],
|
|
160
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
161
|
+
"@typescript-eslint/ban-ts-comment": ["error", {
|
|
162
|
+
"ts-ignore": true,
|
|
163
|
+
"ts-nocheck": true,
|
|
164
|
+
"ts-check": false,
|
|
165
|
+
"ts-expect-error": true
|
|
166
|
+
}],
|
|
167
|
+
"@typescript-eslint/no-restricted-types": ["error", {
|
|
168
|
+
types: {
|
|
169
|
+
Promise: {
|
|
170
|
+
message: "Avoid Promise in types. Use Effect.Effect<A, E, R>."
|
|
171
|
+
},
|
|
172
|
+
"Promise<*>": {
|
|
173
|
+
message: "Avoid Promise<T>. Use Effect.Effect<T, E, R>."
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}],
|
|
177
|
+
"eslint-comments/no-use": "error",
|
|
178
|
+
"eslint-comments/no-unlimited-disable": "error",
|
|
179
|
+
"eslint-comments/disable-enable-pair": "error",
|
|
180
|
+
"eslint-comments/no-unused-disable": "error"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "effect-ts-compliance-core",
|
|
185
|
+
files: ["src/core/**/*.ts"],
|
|
186
|
+
rules: {
|
|
187
|
+
"no-restricted-syntax": ["error", ...restrictedSyntaxCore],
|
|
188
|
+
"no-restricted-imports": ["error", {
|
|
189
|
+
paths: restrictedImports,
|
|
190
|
+
patterns: [
|
|
191
|
+
{
|
|
192
|
+
group: [
|
|
193
|
+
"../shell/**",
|
|
194
|
+
"../../shell/**",
|
|
195
|
+
"../../../shell/**",
|
|
196
|
+
"./shell/**",
|
|
197
|
+
"src/shell/**",
|
|
198
|
+
"shell/**"
|
|
199
|
+
],
|
|
200
|
+
message: "CORE must not import from SHELL."
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}]
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
name: "effect-ts-compliance-axioms",
|
|
208
|
+
files: ["src/core/axioms.ts"],
|
|
209
|
+
rules: {
|
|
210
|
+
"no-restricted-syntax": ["error", ...restrictedSyntaxCoreNoAs]
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: "effect-ts-compliance-filesystem-service",
|
|
215
|
+
files: ["src/shell/services/filesystem.ts"],
|
|
216
|
+
rules: {
|
|
217
|
+
"no-restricted-syntax": ["error", ...restrictedSyntaxBaseNoServiceFactory]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"priorityLevels": [
|
|
3
|
+
{
|
|
4
|
+
"level": 1,
|
|
5
|
+
"name": "Critical Compiler Errors",
|
|
6
|
+
"rules": [
|
|
7
|
+
"ts(2835)",
|
|
8
|
+
"ts(2307)",
|
|
9
|
+
"@prover-coder-ai/suggest-members/suggest-members",
|
|
10
|
+
"@prover-coder-ai/suggest-members/suggest-imports",
|
|
11
|
+
"@prover-coder-ai/suggest-members/suggest-module-paths",
|
|
12
|
+
"@prover-coder-ai/suggest-members/suggest-exports",
|
|
13
|
+
"@prover-coder-ai/suggest-members/suggest-missing-names",
|
|
14
|
+
"@typescript-eslint/no-explicit-any"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"level": 2,
|
|
19
|
+
"name": "Critical Compiler Errors",
|
|
20
|
+
"rules": ["all"]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"level": 3,
|
|
24
|
+
"name": "Critical Compiler Errors (Code must follow Clean Code and best practices)",
|
|
25
|
+
"rules": ["max-lines-per-function", "max-lines"]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"level": 4,
|
|
29
|
+
"name": "Critical Compiler Errors (Code must follow Clean Code and best practices)",
|
|
30
|
+
"rules": ["complexity", "max-params", "max-depth"]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|