@impetik/xeer-mcp 0.2.19 → 0.2.21
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/README.md +2 -2
- package/dist/server.js +4 -1
- package/package.json +2 -2
- package/vendor/spec/actions.d.ts +10 -5
- package/vendor/spec/actions.js +23 -8
- package/vendor/spec/diagnostics.js +95 -11
- package/vendor/spec/editor-settings.d.ts +26 -0
- package/vendor/spec/editor-settings.js +33 -0
- package/vendor/spec/import-policy.d.ts +168 -18
- package/vendor/spec/import-policy.js +284 -56
- package/vendor/spec/index.d.ts +2 -0
- package/vendor/spec/index.js +2 -0
- package/vendor/spec/schema.d.ts +5 -1
- package/vendor/spec/schema.js +57 -6
- package/vendor/spec/template-distribution.d.ts +101 -0
- package/vendor/spec/template-distribution.js +158 -0
- package/vendor/spec/template.d.ts +54 -6
- package/vendor/spec/template.js +34 -14
- package/vendor/spec/type-check-profile.d.ts +65 -4
- package/vendor/spec/type-check-profile.js +144 -12
- package/vendor/spec/types.d.ts +49 -11
- package/vendor/spec/types.js +24 -0
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* `"react-jsx"`, `lib` without the `lib.`/`.d.ts` affixes), which is what
|
|
17
17
|
* `ts.convertCompilerOptionsFromJson` reads.
|
|
18
18
|
*/
|
|
19
|
+
import { NORMALIZED_CLIENT_RUNTIME, clientImportPolicy, isImportableClassification, } from './import-policy.js';
|
|
19
20
|
export const PLATFORM_TYPE_CHECK_COMPILER_OPTIONS = Object.freeze({
|
|
20
21
|
allowJs: true,
|
|
21
22
|
allowArbitraryExtensions: true,
|
|
@@ -35,21 +36,148 @@ export const PLATFORM_TYPE_CHECK_COMPILER_OPTIONS = Object.freeze({
|
|
|
35
36
|
verbatimModuleSyntax: true,
|
|
36
37
|
});
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
39
|
+
* Where the platform package keeps the editor shims of one provider, relative to `dist/`.
|
|
40
|
+
*
|
|
41
|
+
* Published layout, not an implementation detail: every scaffolded `tsconfig.json` names these
|
|
42
|
+
* directories, so renaming one rewrites every application's file. `compat` is the Preact provider's
|
|
43
|
+
* because that is where the React-family compatibility shims have always lived.
|
|
44
|
+
*/
|
|
45
|
+
const PROVIDER_SHIM_DIRECTORIES = Object.freeze({
|
|
46
|
+
preact: 'compat',
|
|
47
|
+
react: 'react',
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* The module inside the platform package each provider's client adapter is published as, relative to
|
|
51
|
+
* `dist/` and without an extension — the target of the `./client/<provider>` export.
|
|
52
|
+
*/
|
|
53
|
+
const PROVIDER_CLIENT_ADAPTER_MODULES = Object.freeze({
|
|
54
|
+
preact: 'client',
|
|
55
|
+
react: 'client-react',
|
|
56
|
+
});
|
|
57
|
+
/** How a `paths` row names a module inside the installed platform package. */
|
|
58
|
+
function installedPlatformModule(module) {
|
|
59
|
+
return `./node_modules/@impetik/xeer/dist/${module}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The shim file name one specifier's row points at. Derived from the specifier so that the table and
|
|
63
|
+
* the generator agree by construction rather than by two lists matching: `react-dom/server.browser`
|
|
64
|
+
* is `react-dom-server-browser`, and nothing anywhere else decides that.
|
|
65
|
+
*/
|
|
66
|
+
function shimModuleName(specifier) {
|
|
67
|
+
return specifier.replaceAll('/', '-').replaceAll('.', '-');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Every renderer mapping one provider's editor needs, derived from the family descriptor.
|
|
71
|
+
*
|
|
72
|
+
* Two rules, and both are the descriptor's rather than anyone's memory. **Completeness**: every
|
|
73
|
+
* specifier the import policy admits from the renderer family gets a row, alias keys included,
|
|
74
|
+
* because the policy is what decides whether an application may write the import and this table is
|
|
75
|
+
* what decides whether its editor can read it. Five hand-kept rows against twelve admitted
|
|
76
|
+
* specifiers is how `react-dom/server` came to be a clean `xeer check` beside a TS2307 in the same
|
|
77
|
+
* file, and ten unmapped `preact/*` entrypoints were the same defect one provider over (#277).
|
|
78
|
+
* **Honesty**: an entrypoint whose declarations exist nowhere gets no row, so both tools refuse it
|
|
79
|
+
* by construction — `scheduler` and `react-dom/profiling` under React, `preact/compat/scheduler` and
|
|
80
|
+
* the two `compat/server` spellings under Preact. A row inventing types for one of those would make
|
|
81
|
+
* an editor accept what `xeer check` rejects, which is the same divergence pointed the other way.
|
|
82
|
+
*/
|
|
83
|
+
export function rendererEditorRows(provider) {
|
|
84
|
+
const directory = PROVIDER_SHIM_DIRECTORIES[provider];
|
|
85
|
+
const rows = [];
|
|
86
|
+
const add = (specifier, entrypoint, family) => {
|
|
87
|
+
const described = family.entrypoints.get(entrypoint);
|
|
88
|
+
if (!described || !isImportableClassification(described.classification))
|
|
89
|
+
return;
|
|
90
|
+
if (described.types.kind === 'none')
|
|
91
|
+
return;
|
|
92
|
+
rows.push({
|
|
93
|
+
specifier,
|
|
94
|
+
entrypoint,
|
|
95
|
+
types: described.types,
|
|
96
|
+
module: `${directory}/${shimModuleName(specifier)}`,
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
for (const family of clientImportPolicy(provider).managedFamilies) {
|
|
100
|
+
for (const specifier of family.entrypoints.keys())
|
|
101
|
+
add(specifier, specifier, family);
|
|
102
|
+
for (const [alias, target] of family.compatAliases)
|
|
103
|
+
add(alias, target, family);
|
|
104
|
+
}
|
|
105
|
+
return rows;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The `@impetik/xeer/*` subpaths whose *module* the provider chooses, mapped for the editor.
|
|
109
|
+
*
|
|
110
|
+
* The platform package publishes one module for each of these under every provider, and it is the
|
|
111
|
+
* bundler that picks which renderer they mean: the `client` facade, and the JSX runtime with its dev
|
|
112
|
+
* twin. The package's own `exports` map answers with the default provider's module, so only a
|
|
113
|
+
* non-default provider needs rows — which is also why an untouched Preact application's file is
|
|
114
|
+
* byte-for-byte what it was. Without them a React application's editor would type every element
|
|
115
|
+
* against Preact's JSX namespace and its `mount`/`useQuery` against the Preact adapter while the
|
|
116
|
+
* artifact ran React: green on the wrong evidence, the exact failure this profile exists to prevent
|
|
117
|
+
* (#248).
|
|
118
|
+
*
|
|
119
|
+
* The facade row names a published module rather than a generated shim — `./client/<provider>` is a
|
|
120
|
+
* real export, refused as an application import so that no source file decides the renderer. The JSX
|
|
121
|
+
* rows point at the very shim the family's own JSX entrypoints resolve to, so one name cannot mean
|
|
122
|
+
* two files.
|
|
123
|
+
*/
|
|
124
|
+
function providerFacadeRows(provider) {
|
|
125
|
+
const rows = new Map();
|
|
126
|
+
if (provider === NORMALIZED_CLIENT_RUNTIME.provider)
|
|
127
|
+
return rows;
|
|
128
|
+
rows.set('@impetik/xeer/client', PROVIDER_CLIENT_ADAPTER_MODULES[provider]);
|
|
129
|
+
const shims = new Map(rendererEditorRows(provider).map((row) => [row.specifier, row.module]));
|
|
130
|
+
for (const family of clientImportPolicy(provider).managedFamilies) {
|
|
131
|
+
for (const [subpath, entrypoint] of [
|
|
132
|
+
['@impetik/xeer/jsx-runtime', family.jsx.runtime],
|
|
133
|
+
['@impetik/xeer/jsx-dev-runtime', family.jsx.devRuntime],
|
|
134
|
+
]) {
|
|
135
|
+
const shim = shims.get(entrypoint);
|
|
136
|
+
if (shim)
|
|
137
|
+
rows.set(subpath, shim);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return rows;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The editor's resolution table for one UI provider — the `paths` block of a scaffolded
|
|
144
|
+
* `tsconfig.json`.
|
|
41
145
|
*
|
|
42
146
|
* Not part of {@link PLATFORM_TYPE_CHECK_COMPILER_OPTIONS}: the platform check answers the same
|
|
43
147
|
* question through its module-resolution host instead, so this is the editor's half of one rule
|
|
44
148
|
* rather than a second rule.
|
|
149
|
+
*
|
|
150
|
+
* Every target is a module *inside* the installed platform package, because both renderers are
|
|
151
|
+
* platform-sourced: applications never declare them, and only a path inside the installed package
|
|
152
|
+
* resolves under npm hoisting and pnpm strictness alike. One rule binds a row to the file it names —
|
|
153
|
+
* a mapping rewrites *every* matching specifier in the program, including the ones written in the
|
|
154
|
+
* file it points at, so the file a row names may never import that row's own specifier. It would
|
|
155
|
+
* resolve back onto itself and answer with an empty module: an editor with no renderer types at all.
|
|
156
|
+
* The generator in the CLI package is what keeps that true, and `editor-resolution.test.ts` there
|
|
157
|
+
* type-checks a scaffolded project through its own `tsconfig.json` to prove it.
|
|
158
|
+
*
|
|
159
|
+
* Keys are sorted, so the file's bytes depend on which rows exist rather than on the order two
|
|
160
|
+
* declarations happen to be written in.
|
|
45
161
|
*/
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
162
|
+
export function tsconfigPathsFor(provider) {
|
|
163
|
+
const rows = new Map(providerFacadeRows(provider));
|
|
164
|
+
for (const row of rendererEditorRows(provider))
|
|
165
|
+
rows.set(row.specifier, row.module);
|
|
166
|
+
return Object.freeze(Object.fromEntries([...rows.keys()].sort()
|
|
167
|
+
.map((specifier) => [specifier, Object.freeze([installedPlatformModule(rows.get(specifier))])])));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The editor mappings a `tsconfig.json` carries under the **Preact** provider: the React-family
|
|
171
|
+
* names an application may write, aliased onto the platform's `preact/compat` surface, and Preact's
|
|
172
|
+
* own admitted entrypoints, which an application may equally write and whose editor rows were
|
|
173
|
+
* missing until #277.
|
|
174
|
+
*/
|
|
175
|
+
export const REACT_COMPAT_TSCONFIG_PATHS = tsconfigPathsFor('preact');
|
|
176
|
+
/**
|
|
177
|
+
* The same mappings under the **React** provider, pointed at the renderer itself rather than at a
|
|
178
|
+
* compatibility layer — which is the whole point of selecting the provider.
|
|
179
|
+
*/
|
|
180
|
+
export const REACT_PROVIDER_TSCONFIG_PATHS = tsconfigPathsFor('react');
|
|
53
181
|
/**
|
|
54
182
|
* The files an application's `tsconfig.json` type-checks: sources, TypeScript tests, and the
|
|
55
183
|
* generated contract.
|
|
@@ -69,10 +197,14 @@ export const APPLICATION_TSCONFIG_INCLUDE = Object.freeze(['src', 'tests/**/*.ts
|
|
|
69
197
|
* bytes. Serialized here rather than returned as an object because "the file the editor reads" is
|
|
70
198
|
* what has to match, and two callers stringifying the same object with different options would
|
|
71
199
|
* produce two different files.
|
|
200
|
+
*
|
|
201
|
+
* The provider changes `paths` and nothing else. Every rule the platform enforces is identical
|
|
202
|
+
* across providers — the choice is about which renderer a name resolves to, never about how strictly
|
|
203
|
+
* the code is judged — and the default keeps a Preact application's file byte-for-byte what it was.
|
|
72
204
|
*/
|
|
73
|
-
export function applicationTsconfigDocument() {
|
|
205
|
+
export function applicationTsconfigDocument(provider = 'preact') {
|
|
74
206
|
return `${JSON.stringify({
|
|
75
|
-
compilerOptions: { ...PLATFORM_TYPE_CHECK_COMPILER_OPTIONS, paths:
|
|
207
|
+
compilerOptions: { ...PLATFORM_TYPE_CHECK_COMPILER_OPTIONS, paths: tsconfigPathsFor(provider) },
|
|
76
208
|
include: APPLICATION_TSCONFIG_INCLUDE,
|
|
77
209
|
}, null, 2)}\n`;
|
|
78
210
|
}
|
package/vendor/spec/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ClientRuntime, ClientRuntimeProvider, ClientRuntimeSource } from './import-policy.js';
|
|
1
2
|
import type { PublicAssetsV0 } from './public-assets.js';
|
|
2
3
|
export declare const SOURCE_FORMAT: "xeer.application-source.v0";
|
|
3
4
|
export declare const ARTIFACT_FORMAT: "xeer.application.v0";
|
|
@@ -31,6 +32,26 @@ export interface Diagnostic {
|
|
|
31
32
|
*/
|
|
32
33
|
causedBy?: string;
|
|
33
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Whether a set of diagnostics refuses the command that produced it.
|
|
37
|
+
*
|
|
38
|
+
* `ok` is "no error", never "no diagnostic": a warning is the platform telling a builder something
|
|
39
|
+
* while still doing the work, and a command that failed on one would make every advisory a breaking
|
|
40
|
+
* change. The rule lives here because `check`, `build`, and `doctor` each decide it about the same
|
|
41
|
+
* diagnostics, and three copies of it is how one of them ends up refusing a warning the other two
|
|
42
|
+
* report and keep going past.
|
|
43
|
+
*/
|
|
44
|
+
export declare function refusesCompletion(diagnostics: readonly Diagnostic[]): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The members of a set that refuse it — the same rule as {@link refusesCompletion}, asked for the
|
|
47
|
+
* subset rather than the verdict.
|
|
48
|
+
*
|
|
49
|
+
* A consumer that *reports* a refusal needs the boolean; a consumer that *shows* one needs to know
|
|
50
|
+
* which diagnostics it is showing, because a set that mixes a refusal with an advisory is the normal
|
|
51
|
+
* case rather than the odd one. Deriving the verdict from the subset is what stops the two answers
|
|
52
|
+
* from ever disagreeing about the same set.
|
|
53
|
+
*/
|
|
54
|
+
export declare function refusingDiagnostics(diagnostics: readonly Diagnostic[]): readonly Diagnostic[];
|
|
34
55
|
/**
|
|
35
56
|
* `ref` is a scalar in the only sense that matters here: it is one TEXT column holding one row id.
|
|
36
57
|
* What distinguishes it is that the column carries a FOREIGN KEY to the declared table it names, so
|
|
@@ -182,15 +203,25 @@ export interface ApplicationManifestV0 {
|
|
|
182
203
|
storage?: StorageConfigV0;
|
|
183
204
|
capabilities?: Capability[];
|
|
184
205
|
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
|
|
206
|
+
* Installed dependencies acknowledged as shipping no TypeScript declarations; see the schema
|
|
207
|
+
* module, where the rule and its reasoning live. Package names, one per package: the acknowledgment
|
|
208
|
+
* covers every subpath of the package it names.
|
|
209
|
+
*/
|
|
210
|
+
untypedDependencies?: string[];
|
|
211
|
+
/**
|
|
212
|
+
* The client runtime selection (#212, #214). Optional, and closed: only implemented
|
|
213
|
+
* provider/source combinations are accepted, and omission normalizes to `{ provider: "preact",
|
|
214
|
+
* source: "platform" }` with identical semantics and build output.
|
|
215
|
+
*
|
|
216
|
+
* The provider is the one line that differs between a Preact application and a React one:
|
|
217
|
+
* `jsxImportSource` stays `@impetik/xeer` and the sources stay byte-identical, because the import
|
|
218
|
+
* policy — not the application — decides what the platform's JSX runtime and client facade
|
|
219
|
+
* resolve to. A future app-owned renderer would be `source: "application"`, not `"user"`.
|
|
189
220
|
*/
|
|
190
221
|
client?: {
|
|
191
222
|
runtime?: {
|
|
192
|
-
provider:
|
|
193
|
-
source?:
|
|
223
|
+
provider: ClientRuntimeProvider;
|
|
224
|
+
source?: ClientRuntimeSource;
|
|
194
225
|
};
|
|
195
226
|
};
|
|
196
227
|
budgets?: {
|
|
@@ -243,12 +274,19 @@ export interface NormalizedApplicationManifestV0 {
|
|
|
243
274
|
*/
|
|
244
275
|
storage: NormalizedStorageConfigV0 | null;
|
|
245
276
|
capabilities: Capability[];
|
|
246
|
-
/**
|
|
277
|
+
/**
|
|
278
|
+
* Sorted and deduplicated, `[]` when the manifest declares none. Deliberately absent from the
|
|
279
|
+
* artifact payload: an acknowledgment is type-space only, so it must not move an `artifactId`.
|
|
280
|
+
*/
|
|
281
|
+
untypedDependencies: string[];
|
|
282
|
+
/**
|
|
283
|
+
* Always present once normalized: omission and the explicit default are the same statement. What
|
|
284
|
+
* is *declared*, however, is carried through rather than defaulted away — this block is where the
|
|
285
|
+
* import policy, the type-resolution profile, and the artifact's provenance all read the
|
|
286
|
+
* application's provider from.
|
|
287
|
+
*/
|
|
247
288
|
client: {
|
|
248
|
-
runtime:
|
|
249
|
-
provider: 'preact';
|
|
250
|
-
source: 'platform';
|
|
251
|
-
};
|
|
289
|
+
runtime: ClientRuntime;
|
|
252
290
|
};
|
|
253
291
|
budgets: {
|
|
254
292
|
queryRows: number;
|
package/vendor/spec/types.js
CHANGED
|
@@ -2,6 +2,30 @@ export const SOURCE_FORMAT = 'xeer.application-source.v0';
|
|
|
2
2
|
export const ARTIFACT_FORMAT = 'xeer.application.v0';
|
|
3
3
|
export const DEV_PROTOCOL = 'xeer.dev.v0';
|
|
4
4
|
export const INSPECT_PROTOCOL = 'xeer.inspect.v0';
|
|
5
|
+
/**
|
|
6
|
+
* Whether a set of diagnostics refuses the command that produced it.
|
|
7
|
+
*
|
|
8
|
+
* `ok` is "no error", never "no diagnostic": a warning is the platform telling a builder something
|
|
9
|
+
* while still doing the work, and a command that failed on one would make every advisory a breaking
|
|
10
|
+
* change. The rule lives here because `check`, `build`, and `doctor` each decide it about the same
|
|
11
|
+
* diagnostics, and three copies of it is how one of them ends up refusing a warning the other two
|
|
12
|
+
* report and keep going past.
|
|
13
|
+
*/
|
|
14
|
+
export function refusesCompletion(diagnostics) {
|
|
15
|
+
return refusingDiagnostics(diagnostics).length !== 0;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The members of a set that refuse it — the same rule as {@link refusesCompletion}, asked for the
|
|
19
|
+
* subset rather than the verdict.
|
|
20
|
+
*
|
|
21
|
+
* A consumer that *reports* a refusal needs the boolean; a consumer that *shows* one needs to know
|
|
22
|
+
* which diagnostics it is showing, because a set that mixes a refusal with an advisory is the normal
|
|
23
|
+
* case rather than the odd one. Deriving the verdict from the subset is what stops the two answers
|
|
24
|
+
* from ever disagreeing about the same set.
|
|
25
|
+
*/
|
|
26
|
+
export function refusingDiagnostics(diagnostics) {
|
|
27
|
+
return diagnostics.filter((diagnostic) => diagnostic.severity === 'error');
|
|
28
|
+
}
|
|
5
29
|
/**
|
|
6
30
|
* The capabilities an application may declare. A capability name in `capabilities[]` and its config
|
|
7
31
|
* block are one declaration in two halves: either both are present or neither is, checked in both
|