@opetope/lint 0.4.0 → 0.5.0
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/CHANGELOG.md +8 -0
- package/README.md +24 -15
- package/README.ru.md +25 -15
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/rules/no-internal-imports.d.ts +4 -0
- package/dist/rules/no-internal-imports.js +2 -0
- package/dist/rules/no-internal-imports.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @opetope/lint
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 410f2f0: Run authentic Calls in headless model tests with `runCall` from `@opetope/react/testing`, preserving their existing policies, cancellation, errors and owner lifetime.
|
|
8
|
+
|
|
9
|
+
Add the recommended `opetope/no-internal-imports` rule for static imports, re-exports, literal dynamic imports, unshadowed `require` and TypeScript import types. `configs.internalImports` uses this rule for JavaScript and TypeScript, including tests, without replacing the host's `no-restricted-imports`. The redundant `internalImportPattern` export is removed; allow trusted implementation files through the config or an explicit rule override.
|
|
10
|
+
|
|
3
11
|
## 0.4.0
|
|
4
12
|
|
|
5
13
|
No changes in this release.
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ both it and `eslint` are peer dependencies.
|
|
|
43
43
|
### `recommended`
|
|
44
44
|
|
|
45
45
|
Every rule that holds wherever Opetope is written: `when-predicate`, `define-feature-property-order`,
|
|
46
|
-
`require-literal-id`, `id-naming`, `no-snapshot-read-in-render` and `require-declared-models` as errors. A rule that needs to know where a
|
|
46
|
+
`require-literal-id`, `id-naming`, `no-internal-imports`, `no-snapshot-read-in-render` and `require-declared-models` as errors. A rule that needs to know where a
|
|
47
47
|
host keeps its files is off here and arrives through `layers`; `prefer-model-selection` is off because the number
|
|
48
48
|
of hooks a component may keep is a taste a project settles for itself.
|
|
49
49
|
|
|
@@ -68,27 +68,36 @@ because forgetting one is how a subscription outlives its reader.
|
|
|
68
68
|
|
|
69
69
|
### `internalImports`
|
|
70
70
|
|
|
71
|
-
`opetope.configs.internalImports({ allow, files })`
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
`opetope.configs.internalImports({ allow, files })` configures `opetope/no-internal-imports` across JavaScript and
|
|
72
|
+
TypeScript, including `.mjs` model tests. The rule is already enabled by `recommended`; this helper is useful for
|
|
73
|
+
scoping it or naming trusted library implementation and host integration files. `allow` explicitly switches off
|
|
74
|
+
only this rule for those files. Place the helper's blocks **after** `recommended`: a later `recommended` block
|
|
75
|
+
re-enables the rule, including for the allowed files. Other project restrictions stay intact.
|
|
75
76
|
|
|
76
77
|
```js
|
|
77
|
-
|
|
78
|
+
export default [
|
|
79
|
+
opetope.configs.recommended,
|
|
80
|
+
...opetope.configs.internalImports({ allow: ['src/bootstrap/**/devtools.ts'] }),
|
|
81
|
+
];
|
|
78
82
|
```
|
|
79
83
|
|
|
80
|
-
`no-restricted-imports
|
|
81
|
-
|
|
82
|
-
of spreading this configuration, which would replace that entry for every file it covers:
|
|
84
|
+
The dedicated rule never changes `no-restricted-imports`. The former `internalImportPattern` export is removed:
|
|
85
|
+
enable this rule or use the helper instead of merging an Opetope pattern into the host's restrictions (D261).
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
'no-restricted-imports': ['error', { paths: myPaths, patterns: [...myPatterns, opetope.internalImportPattern] }],
|
|
86
|
-
```
|
|
87
|
+
## Rules
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
restriction the project makes.
|
|
89
|
+
### `no-internal-imports`
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Application code and tests import public Opetope entries. The rule rejects `@opetope/*/internal` and its deeper
|
|
92
|
+
paths in imports, re-exports, literal `import()` calls, unshadowed `require()` calls, TypeScript import types and
|
|
93
|
+
`import = require`. It includes type-only imports; an internal type is still coupled to the private ABI.
|
|
94
|
+
Use `runCall` from `@opetope/react/testing` to run a real model Call, and `command` to construct a fixture Call.
|
|
95
|
+
Tests do not receive an automatic exception. Trusted library implementation or host integration can use an explicit
|
|
96
|
+
file override; the rule has no autofix because the correct public replacement depends on the imported operation.
|
|
97
|
+
|
|
98
|
+
**The boundary.** This is a syntactic check of literal module paths and templates without substitutions. It does
|
|
99
|
+
not resolve aliases, computed import paths, re-export graphs or custom loaders. A locally shadowed `require` is not
|
|
100
|
+
treated as Node's loader. Apply the config to every JavaScript/TypeScript source and test glob the project uses.
|
|
92
101
|
|
|
93
102
|
### `when-predicate`
|
|
94
103
|
|
package/README.ru.md
CHANGED
|
@@ -43,7 +43,7 @@ export default [
|
|
|
43
43
|
### `recommended`
|
|
44
44
|
|
|
45
45
|
Все правила, которые действуют везде, где пишут на Opetope: `when-predicate`, `define-feature-property-order`,
|
|
46
|
-
`require-literal-id`, `id-naming`, `no-snapshot-read-in-render` и `require-declared-models` как error. Правило, которому нужно знать, где хост
|
|
46
|
+
`require-literal-id`, `id-naming`, `no-internal-imports`, `no-snapshot-read-in-render` и `require-declared-models` как error. Правило, которому нужно знать, где хост
|
|
47
47
|
держит свои файлы, здесь выключено и приходит через `layers`; `prefer-model-selection` выключено потому, что число
|
|
48
48
|
hooks, которое компонент вправе держать, каждый проект решает для себя.
|
|
49
49
|
|
|
@@ -68,27 +68,37 @@ hooks, которое компонент вправе держать, кажды
|
|
|
68
68
|
|
|
69
69
|
### `internalImports`
|
|
70
70
|
|
|
71
|
-
`opetope.configs.internalImports({ allow, files })`
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
`opetope.configs.internalImports({ allow, files })` настраивает `opetope/no-internal-imports` для JavaScript и
|
|
72
|
+
TypeScript, включая `.mjs`-тесты моделей. Правило уже включено в `recommended`; helper полезен для ограничения
|
|
73
|
+
области проверки или явного перечисления доверенных файлов реализации библиотеки и интеграции хоста.
|
|
74
|
+
`allow` выключает только это правило в указанных файлах. Размещайте блоки helper **после** `recommended`:
|
|
75
|
+
последующий блок `recommended` снова включает правило, в том числе для разрешённых файлов. Остальные ограничения
|
|
76
|
+
проекта продолжают действовать.
|
|
75
77
|
|
|
76
78
|
```js
|
|
77
|
-
|
|
79
|
+
export default [
|
|
80
|
+
opetope.configs.recommended,
|
|
81
|
+
...opetope.configs.internalImports({ allow: ['src/bootstrap/**/devtools.ts'] }),
|
|
82
|
+
];
|
|
78
83
|
```
|
|
79
84
|
|
|
80
|
-
`no-restricted-imports
|
|
81
|
-
|
|
82
|
-
запись, а не раскрывает эту конфигурацию: она заменила бы его запись для каждого покрытого файла:
|
|
85
|
+
Отдельное правило не изменяет `no-restricted-imports`. Прежний экспорт `internalImportPattern` удалён:
|
|
86
|
+
включайте это правило или helper вместо добавления паттерна Opetope в ограничения хоста (D261).
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
'no-restricted-imports': ['error', { paths: myPaths, patterns: [...myPatterns, opetope.internalImportPattern] }],
|
|
86
|
-
```
|
|
88
|
+
## Rules
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
ограничения проекта.
|
|
90
|
+
### `no-internal-imports`
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
Код приложения и тесты импортируют публичные входы Opetope. Правило запрещает `@opetope/*/internal` и вложенные
|
|
93
|
+
пути в imports, re-exports, литеральных `import()`, незатенённых `require()`, TypeScript import types и
|
|
94
|
+
`import = require`. Type-only импорты тоже проверяются: внутренний тип связывает потребителя с приватным ABI.
|
|
95
|
+
Для запуска настоящего Call модели есть `runCall` из `@opetope/react/testing`, для создания фикстуры — `command`.
|
|
96
|
+
Автоматического исключения для тестов нет. Доверенные файлы реализации библиотеки или интеграции хоста можно
|
|
97
|
+
разрешить явным override; autofix отсутствует, потому что публичная замена зависит от импортированной операции.
|
|
98
|
+
|
|
99
|
+
**Граница.** Проверка синтаксическая: строковые пути модулей и шаблоны без подстановок. Она не разрешает алиасы,
|
|
100
|
+
вычисляемые пути, граф re-exports или пользовательские загрузчики. Локальный `require` не считается загрузчиком
|
|
101
|
+
Node. Применяйте конфигурацию ко всем используемым JavaScript/TypeScript исходникам и тестам.
|
|
92
102
|
|
|
93
103
|
### `when-predicate`
|
|
94
104
|
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,9 @@ declare const plugin: {
|
|
|
32
32
|
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
33
33
|
name: string;
|
|
34
34
|
};
|
|
35
|
+
'no-internal-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"internalImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
36
|
+
name: string;
|
|
37
|
+
};
|
|
35
38
|
'no-snapshot-read-in-render': import("@typescript-eslint/utils/ts-eslint").RuleModule<"snapshotInRender", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
36
39
|
name: string;
|
|
37
40
|
};
|
|
@@ -84,6 +87,7 @@ declare const configuredPlugin: {
|
|
|
84
87
|
'opetope/define-feature-property-order': "error";
|
|
85
88
|
'opetope/id-naming': "error";
|
|
86
89
|
'opetope/layer-placement': "off";
|
|
90
|
+
'opetope/no-internal-imports': "error";
|
|
87
91
|
'opetope/no-snapshot-read-in-render': "error";
|
|
88
92
|
'opetope/no-subscribe-outside-models': "off";
|
|
89
93
|
'opetope/prefer-model-selection': "off";
|
|
@@ -93,10 +97,6 @@ declare const configuredPlugin: {
|
|
|
93
97
|
};
|
|
94
98
|
};
|
|
95
99
|
};
|
|
96
|
-
internalImportPattern: {
|
|
97
|
-
group: string[];
|
|
98
|
-
message: string;
|
|
99
|
-
};
|
|
100
100
|
};
|
|
101
101
|
declare const opetopeLint: typeof configuredPlugin & Pick<ESLint.Plugin, "configs">;
|
|
102
102
|
export default opetopeLint;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{defineFeaturePropertyOrder as p}from"./rules/define-feature-property-order.js";import{idNaming as
|
|
1
|
+
import{defineFeaturePropertyOrder as p}from"./rules/define-feature-property-order.js";import{idNaming as s}from"./rules/id-naming.js";import{layerPlacement as i}from"./rules/layer-placement.js";import{noInternalImports as l}from"./rules/no-internal-imports.js";import{noSnapshotReadInRender as m}from"./rules/no-snapshot-read-in-render.js";import{noSubscribeOutsideModels as a}from"./rules/no-subscribe-outside-models.js";import{preferModelSelection as d}from"./rules/prefer-model-selection.js";import{requireDeclaredModels as c}from"./rules/require-declared-models.js";import{requireLiteralId as u}from"./rules/require-literal-id.js";import{whenPredicate as f}from"./rules/when-predicate.js";const g=["integration","models","ui"],b=["**/*.ts","**/*.tsx"],h=["**/__tests__/**","**/*.spec.ts","**/*.spec.tsx"],y={meta:{name:"@opetope/lint",version:"0.5.0"},rules:{"define-feature-property-order":p,"id-naming":s,"layer-placement":i,"no-internal-imports":l,"no-snapshot-read-in-render":m,"no-subscribe-outside-models":a,"prefer-model-selection":d,"require-declared-models":c,"require-literal-id":u,"when-predicate":f}},r=y,S={name:"opetope/recommended",plugins:{opetope:r},rules:{"opetope/define-feature-property-order":"error","opetope/id-naming":"error","opetope/layer-placement":"off","opetope/no-internal-imports":"error","opetope/no-snapshot-read-in-render":"error","opetope/no-subscribe-outside-models":"off","opetope/prefer-model-selection":"off","opetope/require-declared-models":"error","opetope/require-literal-id":"error","opetope/when-predicate":"error"}},I=e=>g.flatMap(o=>{const t=e[o]??[];return t.length===0?[]:[{files:[...t],name:`opetope/layers-${o}`,plugins:{opetope:r},rules:{"opetope/layer-placement":["error",{layer:o}]}}]}),q=({models:e=[],tests:o=h})=>e.length===0?[]:[{files:b,name:"opetope/layers-subscriptions",plugins:{opetope:r},rules:{"opetope/no-subscribe-outside-models":"error"}},{files:[...e,...o],name:"opetope/layers-subscriptions-allowed",rules:{"opetope/no-subscribe-outside-models":"off"}}],_=e=>[...I(e),...q(e)],j=({allow:e=[],files:o=["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"]}={})=>[{files:[...o],name:"opetope/internal-imports",plugins:{opetope:r},rules:{"opetope/no-internal-imports":"error"}},...e.length===0?[]:[{files:[...e],name:"opetope/internal-imports-allowed",rules:{"opetope/no-internal-imports":"off"}}]],x=Object.assign(r,{configs:{internalImports:j,layers:_,recommended:S}}),n=x;export{n as default,n as opetopeLint};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { ESLint, Linter } from 'eslint';\n\nimport { defineFeaturePropertyOrder } from './rules/define-feature-property-order';\nimport { idNaming } from './rules/id-naming';\nimport { layerPlacement } from './rules/layer-placement';\nimport { noSnapshotReadInRender } from './rules/no-snapshot-read-in-render';\nimport { noSubscribeOutsideModels } from './rules/no-subscribe-outside-models';\nimport { preferModelSelection } from './rules/prefer-model-selection';\nimport { requireDeclaredModels } from './rules/require-declared-models';\nimport { requireLiteralId } from './rules/require-literal-id';\nimport { whenPredicate } from './rules/when-predicate';\n\n/**\n * The layers a host names for itself, as globs of the files that hold each one, with the tests that are allowed\n * to reach past a layer. `tests` defaults to the usual two shapes of a test path.\n */\ntype LayerOptions = {\n readonly integration?: readonly string[];\n readonly models?: readonly string[];\n readonly tests?: readonly string[];\n readonly ui?: readonly string[];\n};\n\ntype InternalImportOptions = {\n readonly allow?: readonly string[];\n readonly files?: readonly string[];\n};\n\nconst LAYERS = ['integration', 'models', 'ui'] as const;\nconst SOURCE_FILES = ['**/*.ts', '**/*.tsx'];\nconst TEST_FILES = ['**/__tests__/**', '**/*.spec.ts', '**/*.spec.tsx'];\n\nconst plugin = {\n meta: { name: '@opetope/lint', version: '0.
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { ESLint, Linter } from 'eslint';\n\nimport { defineFeaturePropertyOrder } from './rules/define-feature-property-order';\nimport { idNaming } from './rules/id-naming';\nimport { layerPlacement } from './rules/layer-placement';\nimport { noInternalImports } from './rules/no-internal-imports';\nimport { noSnapshotReadInRender } from './rules/no-snapshot-read-in-render';\nimport { noSubscribeOutsideModels } from './rules/no-subscribe-outside-models';\nimport { preferModelSelection } from './rules/prefer-model-selection';\nimport { requireDeclaredModels } from './rules/require-declared-models';\nimport { requireLiteralId } from './rules/require-literal-id';\nimport { whenPredicate } from './rules/when-predicate';\n\n/**\n * The layers a host names for itself, as globs of the files that hold each one, with the tests that are allowed\n * to reach past a layer. `tests` defaults to the usual two shapes of a test path.\n */\ntype LayerOptions = {\n readonly integration?: readonly string[];\n readonly models?: readonly string[];\n readonly tests?: readonly string[];\n readonly ui?: readonly string[];\n};\n\ntype InternalImportOptions = {\n readonly allow?: readonly string[];\n readonly files?: readonly string[];\n};\n\nconst LAYERS = ['integration', 'models', 'ui'] as const;\nconst SOURCE_FILES = ['**/*.ts', '**/*.tsx'];\nconst TEST_FILES = ['**/__tests__/**', '**/*.spec.ts', '**/*.spec.tsx'];\n\nconst plugin = {\n meta: { name: '@opetope/lint', version: '0.5.0' },\n rules: {\n 'define-feature-property-order': defineFeaturePropertyOrder,\n 'id-naming': idNaming,\n 'layer-placement': layerPlacement,\n 'no-internal-imports': noInternalImports,\n 'no-snapshot-read-in-render': noSnapshotReadInRender,\n 'no-subscribe-outside-models': noSubscribeOutsideModels,\n 'prefer-model-selection': preferModelSelection,\n 'require-declared-models': requireDeclaredModels,\n 'require-literal-id': requireLiteralId,\n 'when-predicate': whenPredicate,\n },\n};\n\n/**\n * The laws every Opetope author writes against, with no assumption about where a host keeps its files. A rule that\n * needs such an assumption is off here and arrives through `layers`. The namespace is `opetope`, so a rule reads\n * `opetope/when-predicate` wherever a host names it.\n */\n// Rules use the parser's typed AST internally. The public bridge exposes the\n// supported ESLint rule API; package smoke tests execute it under both linters.\ntype NativeRule = NonNullable<ESLint.Plugin['rules']>[string];\ntype NativeRules = {\n [Name in keyof typeof plugin.rules]: Omit<(typeof plugin.rules)[Name], 'create'> & NativeRule;\n};\nconst nativePlugin = plugin as unknown as { meta: typeof plugin.meta; rules: NativeRules };\n\nconst recommended = {\n name: 'opetope/recommended',\n plugins: { opetope: nativePlugin },\n rules: {\n 'opetope/define-feature-property-order': 'error',\n 'opetope/id-naming': 'error',\n 'opetope/layer-placement': 'off',\n 'opetope/no-internal-imports': 'error',\n 'opetope/no-snapshot-read-in-render': 'error',\n 'opetope/no-subscribe-outside-models': 'off',\n 'opetope/prefer-model-selection': 'off',\n 'opetope/require-declared-models': 'error',\n 'opetope/require-literal-id': 'error',\n 'opetope/when-predicate': 'error',\n },\n} satisfies Linter.Config;\n\n/**\n * Placement is a convention of the project that names its layers, not a law of the framework: a layer without a\n * glob is a layer this host does not have, and it produces no configuration.\n */\nconst placement = (options: LayerOptions): readonly Linter.Config[] =>\n LAYERS.flatMap(layer => {\n const files = options[layer] ?? [];\n\n if (files.length === 0) return [];\n\n return [\n {\n files: [...files],\n name: `opetope/layers-${layer}`,\n plugins: { opetope: nativePlugin },\n rules: { 'opetope/layer-placement': ['error', { layer }] },\n } satisfies Linter.Config,\n ];\n });\n\n/**\n * A subscription is written where the state lives, so this pair arrives only with the model layer that owns it. The\n * restriction covers every source file and steps aside in that layer and in tests: a file no layer claims is\n * covered rather than forgotten.\n */\nconst subscriptions = ({ models = [], tests = TEST_FILES }: LayerOptions): readonly Linter.Config[] =>\n models.length === 0\n ? []\n : [\n {\n files: SOURCE_FILES,\n name: 'opetope/layers-subscriptions',\n plugins: { opetope: nativePlugin },\n rules: { 'opetope/no-subscribe-outside-models': 'error' },\n },\n {\n files: [...models, ...tests],\n name: 'opetope/layers-subscriptions-allowed',\n rules: { 'opetope/no-subscribe-outside-models': 'off' },\n },\n ];\n\nconst layers = (options: LayerOptions): readonly Linter.Config[] => [...placement(options), ...subscriptions(options)];\n\n/**\n * Only library implementation and explicitly named host integration can cross the internal ABI. A dedicated rule\n * leaves the project's `no-restricted-imports` untouched and also covers literal dynamic imports in JS tests.\n * Allowed files explicitly override `recommended`, which enables this rule as well.\n */\nconst internalImports = ({\n allow = [],\n files = ['**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}'],\n}: InternalImportOptions = {}): readonly Linter.Config[] => [\n {\n files: [...files],\n name: 'opetope/internal-imports',\n plugins: { opetope: nativePlugin },\n rules: { 'opetope/no-internal-imports': 'error' },\n },\n ...(allow.length === 0\n ? []\n : [\n {\n files: [...allow],\n name: 'opetope/internal-imports-allowed',\n rules: { 'opetope/no-internal-imports': 'off' as const },\n },\n ]),\n];\n\nconst configuredPlugin = Object.assign(nativePlugin, {\n configs: { internalImports, layers, recommended },\n});\n\n// ESLint consumes the rule map. Config factories are additional plugin helpers;\n// expose both contracts without requiring casts at native flat-config call sites.\n// oxlint-disable-next-line typescript/no-unnecessary-type-assertion -- Required by native ESLint config typetests.\nconst opetopeLint = configuredPlugin as unknown as typeof configuredPlugin & Pick<ESLint.Plugin, 'configs'>;\n\n/*\n * Two shapes of one object. The default is what a tool reads when it loads a plugin by path — Oxlint's `jsPlugins`\n * takes `(await import(path)).default` — and what an ESLint flat config imports by convention; the named export is\n * for a config that prefers to say which binding it takes.\n */\n// oxlint-disable-next-line import/no-default-export\n// eslint-disable-next-line import-x/no-default-export\nexport default opetopeLint;\nexport { opetopeLint };\n"],"names":["LAYERS","SOURCE_FILES","TEST_FILES","plugin","defineFeaturePropertyOrder","idNaming","layerPlacement","noInternalImports","noSnapshotReadInRender","noSubscribeOutsideModels","preferModelSelection","requireDeclaredModels","requireLiteralId","whenPredicate","nativePlugin","recommended","placement","options","layer","files","subscriptions","models","tests","layers","internalImports","allow","configuredPlugin","opetopeLint"],"mappings":"qrBA6BA,MAAMA,EAAS,CAAC,cAAe,SAAU,IAAI,EACvCC,EAAe,CAAC,UAAW,UAAU,EACrCC,EAAa,CAAC,kBAAmB,eAAgB,eAAe,EAEhEC,EAAS,CACb,KAAM,CAAE,KAAM,gBAAiB,QAAS,OAAO,EAC/C,MAAO,CACL,gCAAiCC,EACjC,YAAaC,EACb,kBAAmBC,EACnB,sBAAuBC,EACvB,6BAA8BC,EAC9B,8BAA+BC,EAC/B,yBAA0BC,EAC1B,0BAA2BC,EAC3B,qBAAsBC,EACtB,iBAAkBC,CACnB,GAcGC,EAAeX,EAEfY,EAAc,CAClB,KAAM,sBACN,QAAS,CAAE,QAASD,CAAY,EAChC,MAAO,CACL,wCAAyC,QACzC,oBAAqB,QACrB,0BAA2B,MAC3B,8BAA+B,QAC/B,qCAAsC,QACtC,sCAAuC,MACvC,iCAAkC,MAClC,kCAAmC,QACnC,6BAA8B,QAC9B,yBAA0B,OAC3B,GAOGE,EAAaC,GACjBjB,EAAO,QAAQkB,GAAQ,CACrB,MAAMC,EAAQF,EAAQC,CAAK,GAAK,CAAA,EAEhC,OAAIC,EAAM,SAAW,EAAU,CAAA,EAExB,CACL,CACE,MAAO,CAAC,GAAGA,CAAK,EAChB,KAAM,kBAAkBD,CAAK,GAC7B,QAAS,CAAE,QAASJ,CAAY,EAChC,MAAO,CAAE,0BAA2B,CAAC,QAAS,CAAE,MAAAI,CAAK,CAAE,CAAC,CACjC,EAE7B,CAAC,EAOGE,EAAgB,CAAC,CAAE,OAAAC,EAAS,CAAA,EAAI,MAAAC,EAAQpB,CAAU,IACtDmB,EAAO,SAAW,EACd,CAAA,EACA,CACE,CACE,MAAOpB,EACP,KAAM,+BACN,QAAS,CAAE,QAASa,CAAY,EAChC,MAAO,CAAE,sCAAuC,OAAO,CACxD,EACD,CACE,MAAO,CAAC,GAAGO,EAAQ,GAAGC,CAAK,EAC3B,KAAM,uCACN,MAAO,CAAE,sCAAuC,KAAK,CACtD,GAGHC,EAAUN,GAAoD,CAAC,GAAGD,EAAUC,CAAO,EAAG,GAAGG,EAAcH,CAAO,CAAC,EAO/GO,EAAkB,CAAC,CACvB,MAAAC,EAAQ,CAAA,EACR,MAAAN,EAAQ,CAAC,sCAAsC,CAAC,EACvB,KAAiC,CAC1D,CACE,MAAO,CAAC,GAAGA,CAAK,EAChB,KAAM,2BACN,QAAS,CAAE,QAASL,CAAY,EAChC,MAAO,CAAE,8BAA+B,OAAO,CAChD,EACD,GAAIW,EAAM,SAAW,EACjB,CAAA,EACA,CACE,CACE,MAAO,CAAC,GAAGA,CAAK,EAChB,KAAM,mCACN,MAAO,CAAE,8BAA+B,KAAc,CACvD,IAIHC,EAAmB,OAAO,OAAOZ,EAAc,CACnD,QAAS,CAAE,gBAAAU,EAAiB,OAAAD,EAAQ,YAAAR,CAAW,CAChD,CAAA,EAKKY,EAAcD"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{AST_NODE_TYPES as i,ASTUtils as a}from"@typescript-eslint/utils";import{createRule as l}from"../rule.js";const s=/^@opetope\/[^/]+\/internal(?:\/|$)/;function n(r){if(r.type===i.TSLiteralType)return n(r.literal);if(r.type===i.Literal&&typeof r.value=="string")return r.value;if(r.type===i.TemplateLiteral&&r.expressions.length===0)return r.quasis[0]?.value.cooked}function o(r){return r.argument??r.source??null}const p=l({create(r){const t=e=>{e!==null&&s.test(n(e)??"")&&r.report({messageId:"internalImport",node:e})};return{CallExpression(e){e.callee.type!==i.Identifier||e.callee.name!=="require"||(a.findVariable(r.sourceCode.getScope(e),e.callee)?.defs.length??0)>0||t(e.arguments[0]??null)},ExportAllDeclaration:e=>t(e.source),ExportNamedDeclaration:e=>t(e.source),ImportDeclaration:e=>t(e.source),ImportExpression:e=>t(e.source),TSExternalModuleReference:e=>t(e.expression),TSImportType:e=>t(o(e))}},meta:{docs:{description:"Application code and tests use public Opetope entries instead of the internal ABI."},messages:{internalImport:"Opetope internal entries are reserved for library implementation and explicit host integration. Use public entries; tests run real Calls with runCall from @opetope/react/testing."},schema:[],type:"problem"},name:"no-internal-imports"});export{p as noInternalImports};
|
|
2
|
+
//# sourceMappingURL=no-internal-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-internal-imports.js","sources":["../../src/rules/no-internal-imports.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils';\n\nimport { createRule } from '../rule';\n\n/** Match the package boundary, including deep paths, without claiming unrelated packages or `internals`. */\nconst internalEntry = /^@opetope\\/[^/]+\\/internal(?:\\/|$)/;\n\nfunction sourceText(node: TSESTree.Node): string | null | undefined {\n if (node.type === AST_NODE_TYPES.TSLiteralType) return sourceText(node.literal);\n if (node.type === AST_NODE_TYPES.Literal && typeof node.value === 'string') return node.value;\n if (node.type === AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0)\n return node.quasis[0]?.value.cooked;\n return undefined;\n}\n\n/** TypeScript-ESLint calls this `argument`; Oxlint's ESTree bridge exposes the same source as `source`. */\nfunction importTypeSource(node: {\n readonly argument?: TSESTree.Node;\n readonly source?: TSESTree.Node;\n}): TSESTree.Node | null {\n return node.argument ?? node.source ?? null;\n}\n\nconst noInternalImports = createRule<[], 'internalImport'>({\n create(context) {\n const inspect = (node: TSESTree.Node | null): void => {\n if (node !== null && internalEntry.test(sourceText(node) ?? ''))\n context.report({ messageId: 'internalImport', node });\n };\n return {\n CallExpression(node): void {\n if (node.callee.type !== AST_NODE_TYPES.Identifier || node.callee.name !== 'require') return;\n const variable = ASTUtils.findVariable(context.sourceCode.getScope(node), node.callee);\n if ((variable?.defs.length ?? 0) > 0) return;\n inspect(node.arguments[0] ?? null);\n },\n ExportAllDeclaration: node => inspect(node.source),\n ExportNamedDeclaration: node => inspect(node.source),\n ImportDeclaration: node => inspect(node.source),\n ImportExpression: node => inspect(node.source),\n TSExternalModuleReference: node => inspect(node.expression),\n TSImportType: node => inspect(importTypeSource(node)),\n };\n },\n meta: {\n docs: { description: 'Application code and tests use public Opetope entries instead of the internal ABI.' },\n messages: {\n internalImport:\n 'Opetope internal entries are reserved for library implementation and explicit host integration. Use public entries; tests run real Calls with runCall from @opetope/react/testing.',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-internal-imports',\n});\n\nexport { noInternalImports };\n"],"names":["internalEntry","sourceText","node","AST_NODE_TYPES","importTypeSource","noInternalImports","createRule","context","inspect","ASTUtils"],"mappings":"gHAMA,MAAMA,EAAgB,qCAEtB,SAASC,EAAWC,EAAmB,CACrC,GAAIA,EAAK,OAASC,EAAe,cAAe,OAAOF,EAAWC,EAAK,OAAO,EAC9E,GAAIA,EAAK,OAASC,EAAe,SAAW,OAAOD,EAAK,OAAU,SAAU,OAAOA,EAAK,MACxF,GAAIA,EAAK,OAASC,EAAe,iBAAmBD,EAAK,YAAY,SAAW,EAC9E,OAAOA,EAAK,OAAO,CAAC,GAAG,MAAM,MAEjC,CAGA,SAASE,EAAiBF,EAGzB,CACC,OAAOA,EAAK,UAAYA,EAAK,QAAU,IACzC,CAEA,MAAMG,EAAoBC,EAAiC,CACzD,OAAOC,EAAO,CACZ,MAAMC,EAAWN,GAAoC,CAC/CA,IAAS,MAAQF,EAAc,KAAKC,EAAWC,CAAI,GAAK,EAAE,GAC5DK,EAAQ,OAAO,CAAE,UAAW,iBAAkB,KAAAL,CAAI,CAAE,CACxD,EACA,MAAO,CACL,eAAeA,EAAI,CACbA,EAAK,OAAO,OAASC,EAAe,YAAcD,EAAK,OAAO,OAAS,YAC1DO,EAAS,aAAaF,EAAQ,WAAW,SAASL,CAAI,EAAGA,EAAK,MAAM,GACtE,KAAK,QAAU,GAAK,GACnCM,EAAQN,EAAK,UAAU,CAAC,GAAK,IAAI,CACnC,EACA,qBAAsBA,GAAQM,EAAQN,EAAK,MAAM,EACjD,uBAAwBA,GAAQM,EAAQN,EAAK,MAAM,EACnD,kBAAmBA,GAAQM,EAAQN,EAAK,MAAM,EAC9C,iBAAkBA,GAAQM,EAAQN,EAAK,MAAM,EAC7C,0BAA2BA,GAAQM,EAAQN,EAAK,UAAU,EAC1D,aAAcA,GAAQM,EAAQJ,EAAiBF,CAAI,CAAC,EAExD,EACA,KAAM,CACJ,KAAM,CAAE,YAAa,oFAAoF,EACzG,SAAU,CACR,eACE,oLACH,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,qBACP,CAAA"}
|