@abide/abide 0.123.1 → 0.123.3
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 +33 -0
- package/bin/abide.ts +36 -65
- package/docs/REGISTRY.md +2 -2
- package/docs/RULEBOOK.md +2 -2
- package/docs/abide.md +2 -2
- package/package.json +1 -1
- package/src/compiler/Diagnostics.ts +198 -0
- package/src/compiler/KeptChecker.ts +97 -0
- package/src/compiler/Lowering.ts +1 -1
- package/src/compiler/PositionedRefusal.ts +1 -1
- package/src/compiler/TypeSession.ts +62 -85
- package/src/compiler/appLayout.ts +28 -20
- package/src/compiler/argsDefaultsIn.ts +1 -1
- package/src/compiler/checkApp.ts +64 -68
- package/src/compiler/checkedShadow.ts +1 -1
- package/src/compiler/compileApp.ts +101 -70
- package/src/compiler/declaredExports.ts +2 -4
- package/src/compiler/emitClient.ts +1 -1
- package/src/compiler/formatAbide.ts +2 -2
- package/src/compiler/handlersUnder.ts +17 -29
- package/src/compiler/lineOf.ts +0 -19
- package/src/compiler/matchersOf.ts +3 -3
- package/src/compiler/mountsOf.ts +3 -3
- package/src/compiler/readSources.ts +16 -18
- package/src/compiler/readsIn.ts +1 -1
- package/src/compiler/serveLanguage.ts +23 -57
- package/src/compiler/sharedModuleWrites.ts +1 -1
- package/src/compiler/templateWarnings.ts +1 -2
- package/src/compiler/trackingWarnings.ts +1 -1
- package/src/server/CLIENT_BUILD.ts +4 -32
- package/src/server/RESUME_MILLISECONDS.ts +2 -0
- package/src/server/answerRequest.ts +11 -300
- package/src/server/answerRpc.ts +12 -54
- package/src/server/answerSocket.ts +8 -35
- package/src/server/appBuild.ts +377 -0
- package/src/server/appPlugins.ts +15 -17
- package/src/server/appTree.ts +6 -5
- package/src/server/argsContract.ts +209 -0
- package/src/server/bridgeRelay.ts +153 -65
- package/src/server/claudeCode.ts +30 -127
- package/src/server/config.ts +6 -7
- package/src/server/createApp.ts +30 -64
- package/src/server/devWorker.ts +11 -15
- package/src/server/handlerFileMount.ts +40 -0
- package/src/server/index.ts +2 -2
- package/src/server/packageDirectory.ts +14 -0
- package/src/server/preload.ts +3 -2
- package/src/server/principal.ts +4 -3
- package/src/server/remote.ts +1 -1
- package/src/server/runCompiled.ts +1 -1
- package/src/server/runDesktop.ts +1 -1
- package/src/server/seedBuffer.ts +1 -1
- package/src/server/serveDev.ts +24 -58
- package/src/server/servedApp.ts +390 -0
- package/src/server/signInChanged.ts +20 -0
- package/src/server/surfaceOf.ts +2 -1
- package/src/server/versionOf.ts +6 -15
- package/src/shared/applyPatch.ts +1 -1
- package/src/shared/muxFrames.ts +1 -1
- package/src/shared/reactive/Keyed.ts +1 -1
- package/src/shared/reactive/Reactive.ts +21 -8
- package/src/shared/reactive/argsContract.ts +131 -4
- package/src/shared/reactive/index.ts +1 -0
- package/src/shared/reactive/patchLog.ts +79 -0
- package/src/shared/reactive/patchMarks.ts +34 -0
- package/src/shared/reactive/recordWrites.ts +11 -14
- package/src/shared/reactive/share.ts +4 -3
- package/src/shared/rpc.ts +12 -19
- package/src/shared/validateJson.ts +14 -3
- package/src/ui/ArmRegion.ts +10 -4
- package/src/ui/Level.ts +11 -20
- package/src/ui/LevelChain.ts +272 -0
- package/src/ui/Router.ts +54 -245
- package/src/ui/Scope.ts +17 -3
- package/src/ui/TryRegion.ts +22 -23
- package/src/ui/bindSpread.ts +2 -4
- package/src/ui/listenForRoutes.ts +3 -10
- package/src/ui/outboxQueue.ts +21 -3
- package/src/ui/reconcile.ts +4 -6
- package/src/ui/routing.ts +2 -1
- package/src/ui/rows.ts +2 -2
- package/src/ui/setAttribute.ts +12 -3
- package/src/ui/socketWire.ts +26 -11
- package/src/compiler/Finding.ts +0 -2
- package/src/compiler/Refusals.ts +0 -65
- package/src/compiler/formatDiagnosis.ts +0 -20
- package/src/server/appDirectories.ts +0 -9
- package/src/server/argsFor.ts +0 -39
- package/src/server/buildDirectory.ts +0 -10
- package/src/server/coerceArgs.ts +0 -109
- package/src/server/derivedArgs.ts +0 -95
- package/src/server/runBuild.ts +0 -24
- package/src/server/serveBuild.ts +0 -144
- package/src/server/testBuild.ts +0 -220
- package/src/shared/reactive/FOLLOWED.ts +0 -8
- package/src/shared/reactive/PATCHES.ts +0 -11
- package/src/shared/reactive/PATCH_SINKS.ts +0 -26
- package/src/shared/reactive/canonicalKey.ts +0 -95
|
@@ -36,9 +36,13 @@ import {
|
|
|
36
36
|
moduleConfigShadow,
|
|
37
37
|
} from './checkedShadow.ts'
|
|
38
38
|
import { type CheckerAnswer, UNCHECKED } from './CheckerAnswer.ts'
|
|
39
|
-
import
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
import {
|
|
40
|
+
byPlace,
|
|
41
|
+
type Diagnosis,
|
|
42
|
+
type Finding,
|
|
43
|
+
placedFindings,
|
|
44
|
+
} from './Diagnostics.ts'
|
|
45
|
+
import { lineOf } from './lineOf.ts'
|
|
42
46
|
import { CHECKED_VALUES } from './Lowering.ts'
|
|
43
47
|
import type { AbideFile } from './parseAbide.ts'
|
|
44
48
|
import { projectShadow, type Span } from './projectShadow.ts'
|
|
@@ -104,9 +108,11 @@ export class TypeSession {
|
|
|
104
108
|
api: API,
|
|
105
109
|
tsconfig: string,
|
|
106
110
|
keyOf: (path: string) => string,
|
|
111
|
+
root: string,
|
|
107
112
|
) {
|
|
108
113
|
this.api = api
|
|
109
114
|
this.tsconfig = tsconfig
|
|
115
|
+
this.root = root
|
|
110
116
|
this.opened = `${dirname(tsconfig)}/${SESSION_CONFIG}`
|
|
111
117
|
this.keyOf = keyOf
|
|
112
118
|
}
|
|
@@ -152,8 +158,8 @@ export class TypeSession {
|
|
|
152
158
|
*/
|
|
153
159
|
private stoodIn = new Set<string>()
|
|
154
160
|
|
|
155
|
-
/** The app's root, real
|
|
156
|
-
root
|
|
161
|
+
/** The app's root, real. */
|
|
162
|
+
readonly root: string
|
|
157
163
|
|
|
158
164
|
/**
|
|
159
165
|
* `path` below the app's root, where it lies under it.
|
|
@@ -228,8 +234,11 @@ export class TypeSession {
|
|
|
228
234
|
return COMPONENT_MODULE
|
|
229
235
|
}
|
|
230
236
|
|
|
231
|
-
/**
|
|
232
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Opens a session on the project `tsconfig` configures, for the app at `root` — real, and empty
|
|
239
|
+
* for a session asked about no app's routes.
|
|
240
|
+
*/
|
|
241
|
+
static async open(tsconfig: string, root = ''): Promise<TypeSession> {
|
|
233
242
|
const api = new API({
|
|
234
243
|
cwd: dirname(tsconfig),
|
|
235
244
|
fs: {
|
|
@@ -261,7 +270,7 @@ export class TypeSession {
|
|
|
261
270
|
throw new Error(
|
|
262
271
|
'abide: the TypeScript API no longer keeps `toPath` where the type session reads it, so a path cannot be keyed as the checker keys it.',
|
|
263
272
|
)
|
|
264
|
-
const session = new TypeSession(api, tsconfig, toPath)
|
|
273
|
+
const session = new TypeSession(api, tsconfig, toPath, root)
|
|
265
274
|
return session
|
|
266
275
|
}
|
|
267
276
|
|
|
@@ -757,27 +766,14 @@ export class TypeSession {
|
|
|
757
766
|
)
|
|
758
767
|
answers[at] = read.answer
|
|
759
768
|
suspects[at] = read.suspects
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
!isIgnored(source.text, offset, warning.message)
|
|
769
|
-
)
|
|
770
|
-
placed.push(
|
|
771
|
-
diagnosisAt(
|
|
772
|
-
source.path,
|
|
773
|
-
source.text,
|
|
774
|
-
offset,
|
|
775
|
-
'warning',
|
|
776
|
-
warning.message,
|
|
777
|
-
),
|
|
778
|
-
)
|
|
779
|
-
}
|
|
780
|
-
warned[at] = placed
|
|
769
|
+
warned[at] = placedFindings(
|
|
770
|
+
source.path,
|
|
771
|
+
source.text,
|
|
772
|
+
read.warnings,
|
|
773
|
+
(offset) => query.map.toSource(query.map.shadowPath, offset),
|
|
774
|
+
'warning',
|
|
775
|
+
true,
|
|
776
|
+
)
|
|
781
777
|
}
|
|
782
778
|
const every = queries.map((_, at) => at)
|
|
783
779
|
const first = project
|
|
@@ -868,11 +864,13 @@ export class TypeSession {
|
|
|
868
864
|
* 11.30 — `unkeyed`: every `args` defaulting a member its body's parameter does not, as warnings.
|
|
869
865
|
* Both over every `.ts` under `within` and each of `sources` as the shadow `readsFor` registered
|
|
870
866
|
* for it, because a keyed value is declared in a `.ts` as often as in a `.abide` — one walk of
|
|
871
|
-
* the files for the two, each finding on its own line of the file an author wrote.
|
|
867
|
+
* the files for the two, each finding on its own line of the file an author wrote. `scripts`
|
|
868
|
+
* as `diagnose` reads it: an editor asking about one page does not walk the app's `.ts`.
|
|
872
869
|
*/
|
|
873
870
|
async lints(
|
|
874
871
|
within: string,
|
|
875
872
|
sources: readonly Omit<ParsedSource, 'quiet'>[],
|
|
873
|
+
scripts = true,
|
|
876
874
|
): Promise<{ ambient: Diagnosis[]; unkeyed: Diagnosis[] }> {
|
|
877
875
|
using _held = this.hold()
|
|
878
876
|
const ambient: Diagnosis[] = []
|
|
@@ -905,10 +903,13 @@ export class TypeSession {
|
|
|
905
903
|
// A file of this session's own is one of `sources`' shadows or not walked at all: a
|
|
906
904
|
// checked module is the lowering's, and placed nowhere an author wrote.
|
|
907
905
|
const files: string[] = []
|
|
908
|
-
|
|
909
|
-
const
|
|
910
|
-
|
|
911
|
-
|
|
906
|
+
if (scripts)
|
|
907
|
+
for (const path of this.rootsUnder(project, within)) {
|
|
908
|
+
const key = this.keyOf(path)
|
|
909
|
+
if (authored.has(key) || !this.shadows.has(key))
|
|
910
|
+
files.push(path)
|
|
911
|
+
}
|
|
912
|
+
else for (const { map } of authored.values()) files.push(map.shadowPath)
|
|
912
913
|
await Promise.all(
|
|
913
914
|
files.map(async (path) => {
|
|
914
915
|
const sourceFile = await project.program.getSourceFile(path)
|
|
@@ -928,26 +929,25 @@ export class TypeSession {
|
|
|
928
929
|
: source.text
|
|
929
930
|
const place = (at: number): number =>
|
|
930
931
|
shadow === undefined ? at : shadow.map.toSource(path, at)
|
|
932
|
+
const named = source?.path ?? path
|
|
933
|
+
const ambientReads: Finding[] = []
|
|
931
934
|
for (const read of reads)
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
finding.message,
|
|
949
|
-
),
|
|
950
|
-
)
|
|
935
|
+
ambientReads.push({
|
|
936
|
+
at: read.at,
|
|
937
|
+
message: `abide: a \`global\` value's body reads \`${read.ambient}\`, which belongs to the request it was built in — every later request would be answered with this one's. Take it out of the body, or drop \`global\`. RULEBOOK 11.37.`,
|
|
938
|
+
})
|
|
939
|
+
ambient.push(
|
|
940
|
+
...placedFindings(
|
|
941
|
+
named,
|
|
942
|
+
text,
|
|
943
|
+
ambientReads,
|
|
944
|
+
place,
|
|
945
|
+
'error',
|
|
946
|
+
),
|
|
947
|
+
)
|
|
948
|
+
unkeyed.push(
|
|
949
|
+
...placedFindings(named, text, defaults, place, 'warning'),
|
|
950
|
+
)
|
|
951
951
|
}),
|
|
952
952
|
)
|
|
953
953
|
ambient.sort(byPlace)
|
|
@@ -1081,16 +1081,15 @@ export class TypeSession {
|
|
|
1081
1081
|
})
|
|
1082
1082
|
if (source.quiet) continue
|
|
1083
1083
|
// A refusal is at a projection offset (`Lowering.refusals`).
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
)
|
|
1084
|
+
refused.push(
|
|
1085
|
+
...placedFindings(
|
|
1086
|
+
source.path,
|
|
1087
|
+
source.text,
|
|
1088
|
+
refusals,
|
|
1089
|
+
(at) => map.toSource(map.shadowPath, at),
|
|
1090
|
+
'error',
|
|
1091
|
+
),
|
|
1092
|
+
)
|
|
1094
1093
|
reports.push(
|
|
1095
1094
|
report(map.checkedPath, source.path, (position) =>
|
|
1096
1095
|
lineOf(
|
|
@@ -1621,20 +1620,6 @@ declare module '*.md' {
|
|
|
1621
1620
|
}
|
|
1622
1621
|
`
|
|
1623
1622
|
|
|
1624
|
-
/**
|
|
1625
|
-
* One thing the checker said, placed in the file the author wrote.
|
|
1626
|
-
*
|
|
1627
|
-
* 38.3 — line and column from 1.
|
|
1628
|
-
*/
|
|
1629
|
-
export type Diagnosis = {
|
|
1630
|
-
path: string
|
|
1631
|
-
line: number
|
|
1632
|
-
column: number
|
|
1633
|
-
code: number
|
|
1634
|
-
category: 'error' | 'warning' | 'suggestion' | 'message'
|
|
1635
|
-
message: string
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
1623
|
/**
|
|
1639
1624
|
* Where something is in a file the author wrote, line and column from 1.
|
|
1640
1625
|
*
|
|
@@ -1792,14 +1777,6 @@ async function describe(
|
|
|
1792
1777
|
return `${keyword} ${name}: ${spelled}`
|
|
1793
1778
|
}
|
|
1794
1779
|
|
|
1795
|
-
function byPlace(one: Diagnosis, two: Diagnosis): number {
|
|
1796
|
-
return (
|
|
1797
|
-
one.path.localeCompare(two.path) ||
|
|
1798
|
-
one.line - two.line ||
|
|
1799
|
-
one.column - two.column
|
|
1800
|
-
)
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
1780
|
/** Indexed by the API's `DiagnosticCategory`. */
|
|
1804
1781
|
const CATEGORIES = ['warning', 'error', 'suggestion', 'message'] as const
|
|
1805
1782
|
|
|
@@ -16,16 +16,15 @@ import {
|
|
|
16
16
|
} from '#shared/routePattern.ts'
|
|
17
17
|
|
|
18
18
|
import { abideImportsOf, componentGraph } from './componentGraph.ts'
|
|
19
|
+
import { type Diagnosis, Diagnostics } from './Diagnostics.ts'
|
|
19
20
|
import type { HandlerFile } from './handlersUnder.ts'
|
|
20
21
|
import { hookCalls, hooksIn } from './hookCalls.ts'
|
|
21
22
|
import { matchersOf, type MountedTree } from './matchersOf.ts'
|
|
22
23
|
import { mountsOf } from './mountsOf.ts'
|
|
23
24
|
import { type AbideFile, scriptBodies } from './parseAbide.ts'
|
|
24
25
|
import { type ParsedSource, parseSources } from './readSources.ts'
|
|
25
|
-
import { Refusals } from './Refusals.ts'
|
|
26
26
|
import { resolverIn } from './resolverIn.ts'
|
|
27
27
|
import { attributedImports } from './splitImports.ts'
|
|
28
|
-
import type { Diagnosis } from './TypeSession.ts'
|
|
29
28
|
|
|
30
29
|
// THE APP, LAID OUT ONCE PER COMPILE OR CHECK: every `.abide` and handler file it holds — its own, a
|
|
31
30
|
// dependency's it imports, a package's it mounts — each with where it sits and what that makes it
|
|
@@ -110,15 +109,15 @@ export type AppLayout = {
|
|
|
110
109
|
*/
|
|
111
110
|
export async function appLayout(root: string): Promise<AppLayout> {
|
|
112
111
|
// COLLECTED, whoever asks: a layout is kept across checks (`AppChecker`), and a build adopts
|
|
113
|
-
// what it found (`
|
|
114
|
-
const refusals = new
|
|
112
|
+
// what it found (`Diagnostics.adopt`).
|
|
113
|
+
const refusals = new Diagnostics(root, true)
|
|
115
114
|
const { abide, handlers, params, modules, published } = appFiles(
|
|
116
115
|
root,
|
|
117
116
|
refusals,
|
|
118
117
|
)
|
|
119
118
|
await refuseModuleHooks(root, modules, refusals)
|
|
120
119
|
const resolve = resolverIn()
|
|
121
|
-
const unparsed = new
|
|
120
|
+
const unparsed = new Diagnostics(root, true)
|
|
122
121
|
const own = parseSources(
|
|
123
122
|
await textsAt(abide.map((path) => `${root}/${path}`)),
|
|
124
123
|
unparsed,
|
|
@@ -140,13 +139,7 @@ export async function appLayout(root: string): Promise<AppLayout> {
|
|
|
140
139
|
found.positions.get(source.path) ?? relative,
|
|
141
140
|
)
|
|
142
141
|
refusePlace(source, placed, resolve, refusals)
|
|
143
|
-
sources.push(
|
|
144
|
-
...source,
|
|
145
|
-
...placed,
|
|
146
|
-
paints: paints(source.file),
|
|
147
|
-
invoked: invoked.has(source.path),
|
|
148
|
-
hooks: hooksIn(scriptBodies(source.file)),
|
|
149
|
-
})
|
|
142
|
+
sources.push(placedSource(source, placed, invoked.has(source.path)))
|
|
150
143
|
}
|
|
151
144
|
const texts = await textsAt(found.handlers.map((file) => file.path))
|
|
152
145
|
const placedHandlers: PlacedHandler[] = []
|
|
@@ -209,8 +202,8 @@ export async function appLayout(root: string): Promise<AppLayout> {
|
|
|
209
202
|
errors,
|
|
210
203
|
published,
|
|
211
204
|
addresses: [...addresses].sort(),
|
|
212
|
-
refused: refusals.
|
|
213
|
-
unparsed: unparsed.
|
|
205
|
+
refused: refusals.refused,
|
|
206
|
+
unparsed: unparsed.refused,
|
|
214
207
|
resolve,
|
|
215
208
|
}
|
|
216
209
|
}
|
|
@@ -250,9 +243,9 @@ export async function withDependencies(
|
|
|
250
243
|
parsed: readonly ParsedSource[],
|
|
251
244
|
own: readonly string[],
|
|
252
245
|
resolve: (specifier: string, from: string) => string | undefined,
|
|
253
|
-
refusals:
|
|
246
|
+
refusals: Diagnostics,
|
|
254
247
|
/** Where what the parser refuses of a file reached here goes, where apart from `refusals`. */
|
|
255
|
-
unparsed:
|
|
248
|
+
unparsed: Diagnostics = refusals,
|
|
256
249
|
): Promise<{
|
|
257
250
|
sources: ParsedSource[]
|
|
258
251
|
handlers: HandlerFile[]
|
|
@@ -347,6 +340,21 @@ export async function withDependencies(
|
|
|
347
340
|
}
|
|
348
341
|
|
|
349
342
|
/** Whether a page or an error page has anything to paint: a template, or a head. 23.3, 35.14. */
|
|
343
|
+
/** `source` at `placed`, with what its own text says it paints and calls. */
|
|
344
|
+
export function placedSource(
|
|
345
|
+
source: ParsedSource,
|
|
346
|
+
placed: Placement,
|
|
347
|
+
invoked: boolean,
|
|
348
|
+
): PlacedSource {
|
|
349
|
+
return {
|
|
350
|
+
...source,
|
|
351
|
+
...placed,
|
|
352
|
+
paints: paints(source.file),
|
|
353
|
+
invoked,
|
|
354
|
+
hooks: hooksIn(scriptBodies(source.file)),
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
350
358
|
export function paints(file: AbideFile): boolean {
|
|
351
359
|
return file.template.length > 0 || file.head.length > 0
|
|
352
360
|
}
|
|
@@ -362,7 +370,7 @@ function refusePlace(
|
|
|
362
370
|
source: ParsedSource,
|
|
363
371
|
placed: Placement,
|
|
364
372
|
resolve: (specifier: string, from: string) => string | undefined,
|
|
365
|
-
refusals:
|
|
373
|
+
refusals: Diagnostics,
|
|
366
374
|
): void {
|
|
367
375
|
const { relative, place, kind } = placed
|
|
368
376
|
if (source.file.servers.length > 0 && place === 'public')
|
|
@@ -404,7 +412,7 @@ function refusePlace(
|
|
|
404
412
|
async function refuseModuleHooks(
|
|
405
413
|
root: string,
|
|
406
414
|
modules: readonly string[],
|
|
407
|
-
refusals:
|
|
415
|
+
refusals: Diagnostics,
|
|
408
416
|
): Promise<void> {
|
|
409
417
|
const texts = await textsAt(modules.map((module) => `${root}/${module}`))
|
|
410
418
|
for (let at = 0; at < modules.length; at += 1) {
|
|
@@ -428,7 +436,7 @@ async function refuseModuleHooks(
|
|
|
428
436
|
function refuseStrayLauncher(
|
|
429
437
|
sources: readonly PlacedSource[],
|
|
430
438
|
handlers: readonly PlacedHandler[],
|
|
431
|
-
refusals:
|
|
439
|
+
refusals: Diagnostics,
|
|
432
440
|
): void {
|
|
433
441
|
const stray = (relative: string): void =>
|
|
434
442
|
refusals.at(
|
|
@@ -457,7 +465,7 @@ function refuseStrayLauncher(
|
|
|
457
465
|
*/
|
|
458
466
|
function routesOf(
|
|
459
467
|
sources: readonly PlacedSource[],
|
|
460
|
-
refusals:
|
|
468
|
+
refusals: Diagnostics,
|
|
461
469
|
): { routes: AppRoute[]; errors: AppRoute[] } {
|
|
462
470
|
const layouts: { source: string; segments: Segment[] }[] = []
|
|
463
471
|
const layoutAt = new Map<string, string>()
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from 'typescript/unstable/ast/is'
|
|
18
18
|
import { type Checker, SymbolFlags, type Type } from 'typescript/unstable/async'
|
|
19
19
|
|
|
20
|
-
import type { Finding } from './
|
|
20
|
+
import type { Finding } from './Diagnostics.ts'
|
|
21
21
|
import { optionNamed, reactiveOptions } from './reactiveOptions.ts'
|
|
22
22
|
|
|
23
23
|
// 11.30 — AN `args` SCHEMA DEFAULTING A MEMBER THE BODY'S PARAMETER DOES NOT. The key is taken before
|
package/src/compiler/checkApp.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { relative } from 'node:path' // bun exposes no path helpers of its own
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { placement } from '#server/placement.ts'
|
|
4
4
|
|
|
5
|
-
import type
|
|
6
|
-
import { type AppChecker, compiled } from './compileApp.ts'
|
|
5
|
+
import { type PlacedSource, placedSource } from './appLayout.ts'
|
|
6
|
+
import { type AppChecker, compiled, compiledSources } from './compileApp.ts'
|
|
7
7
|
import { abideImportsOf } from './componentGraph.ts'
|
|
8
|
+
import { type Diagnosis, Diagnostics } from './Diagnostics.ts'
|
|
8
9
|
import { hooksIn } from './hookCalls.ts'
|
|
9
10
|
import { parseAbide, scriptBodies } from './parseAbide.ts'
|
|
10
11
|
import { parseSources, readSources } from './readSources.ts'
|
|
11
|
-
import { Refusals } from './Refusals.ts'
|
|
12
|
-
import type { Diagnosis } from './TypeSession.ts'
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Every finding `abide check` reports for the app at `appRoot`.
|
|
@@ -50,74 +49,71 @@ export async function checkSource(
|
|
|
50
49
|
): Promise<Diagnosis[]> {
|
|
51
50
|
const { session, root } = checker
|
|
52
51
|
const layout = await checker.layout()
|
|
52
|
+
const diagnostics = new Diagnostics(root, true)
|
|
53
53
|
// 38.33 — WHAT THE TREE REFUSES OF IT, off the layout the checker keeps until a move is heard.
|
|
54
54
|
// What the parser refuses is the held text's, below, never the disk's (`layout.unparsed`).
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (refused.path === path) tree.push(refused)
|
|
58
|
-
const refusals = new Refusals(root, true)
|
|
59
|
-
const [page] = parseSources([{ path, text }], refusals)
|
|
60
|
-
if (page === undefined) return [...tree, ...refusals.found]
|
|
55
|
+
diagnostics.adopt(layout.refused)
|
|
56
|
+
const [page] = parseSources([{ path, text }], diagnostics)
|
|
61
57
|
// 23.19 — WHERE THE APP PLACES IT, so a mounted page's `route.params` is typed by the route its
|
|
62
58
|
// mount gives it, as `checkApp` types it; a file the layout has not seen is placed at its path.
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
).values())
|
|
72
|
-
try {
|
|
73
|
-
imports.push({
|
|
74
|
-
path: imported,
|
|
75
|
-
text: held(imported) ?? (await Bun.file(imported).text()),
|
|
76
|
-
quiet: true,
|
|
77
|
-
})
|
|
78
|
-
} catch {
|
|
79
|
-
// A component that cannot be read takes anything here.
|
|
80
|
-
}
|
|
81
|
-
// 27.13 — AND EVERY FILE FILING `onConfig`, quietly, so a page that only reads `config()` is
|
|
82
|
-
// typed by defaults it never imported — as `checkApp`'s whole-app program types it. The calls
|
|
83
|
-
// only name candidates; the checker decides which file.
|
|
84
|
-
const lowered = new Set(imports.map((one) => one.path))
|
|
85
|
-
for (const other of layout.sources) {
|
|
86
|
-
if (other.path === path || lowered.has(other.path)) continue
|
|
87
|
-
const editing = held(other.path)
|
|
88
|
-
if (
|
|
89
|
-
editing === undefined || editing === other.text
|
|
90
|
-
? other.hooks.includes('onConfig')
|
|
91
|
-
: filesConfig(editing)
|
|
59
|
+
const own: PlacedSource[] = []
|
|
60
|
+
const beside: { path: string; text: string; quiet: boolean }[] = []
|
|
61
|
+
if (page !== undefined) {
|
|
62
|
+
const laid = layout.sources.find((source) => source.path === path)
|
|
63
|
+
own.push(
|
|
64
|
+
laid === undefined
|
|
65
|
+
? placedSource(page, placement(relative(root, path)), false)
|
|
66
|
+
: { ...laid, ...page },
|
|
92
67
|
)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
68
|
+
for (const imported of abideImportsOf(
|
|
69
|
+
path,
|
|
70
|
+
page.file,
|
|
71
|
+
layout.resolve,
|
|
72
|
+
).values())
|
|
73
|
+
try {
|
|
74
|
+
beside.push({
|
|
75
|
+
path: imported,
|
|
76
|
+
text: held(imported) ?? (await Bun.file(imported).text()),
|
|
77
|
+
quiet: true,
|
|
78
|
+
})
|
|
79
|
+
} catch {
|
|
80
|
+
// A component that cannot be read takes anything here.
|
|
81
|
+
}
|
|
82
|
+
// 27.13 — AND EVERY FILE FILING `onConfig`, quietly, so a page that only reads `config()`
|
|
83
|
+
// is typed by defaults it never imported — as `checkApp`'s whole-app program types it. The
|
|
84
|
+
// calls only name candidates; the checker decides which file.
|
|
85
|
+
const lowered = new Set(beside.map((one) => one.path))
|
|
86
|
+
for (const other of layout.sources) {
|
|
87
|
+
if (other.path === path || lowered.has(other.path)) continue
|
|
88
|
+
const editing = held(other.path)
|
|
89
|
+
if (
|
|
90
|
+
editing === undefined || editing === other.text
|
|
91
|
+
? other.hooks.includes('onConfig')
|
|
92
|
+
: filesConfig(editing)
|
|
93
|
+
)
|
|
94
|
+
beside.push({
|
|
95
|
+
path: other.path,
|
|
96
|
+
text: editing ?? other.text,
|
|
97
|
+
quiet: true,
|
|
98
|
+
})
|
|
99
|
+
}
|
|
98
100
|
}
|
|
99
101
|
// A component that does not parse, or that the checker refuses, is its own file's finding and
|
|
100
102
|
// takes anything here: a quiet source's refusal is reported by nobody.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
...beside,
|
|
116
|
-
],
|
|
117
|
-
layout,
|
|
118
|
-
false,
|
|
119
|
-
)
|
|
120
|
-
return [...tree, ...own, ...diagnoses]
|
|
103
|
+
if (own.length > 0)
|
|
104
|
+
await compiledSources(
|
|
105
|
+
layout,
|
|
106
|
+
session,
|
|
107
|
+
own,
|
|
108
|
+
parseSources(beside, diagnostics),
|
|
109
|
+
diagnostics,
|
|
110
|
+
true,
|
|
111
|
+
false,
|
|
112
|
+
)
|
|
113
|
+
const found: Diagnosis[] = []
|
|
114
|
+
for (const finding of diagnostics.findings)
|
|
115
|
+
if (finding.path === path) found.push(finding)
|
|
116
|
+
return found
|
|
121
117
|
}
|
|
122
118
|
|
|
123
119
|
/**
|
|
@@ -132,7 +128,7 @@ export async function lowerApp(
|
|
|
132
128
|
held: (path: string) => string | undefined,
|
|
133
129
|
): Promise<void> {
|
|
134
130
|
const layout = await checker.layout()
|
|
135
|
-
const
|
|
131
|
+
const diagnostics = new Diagnostics(checker.root, true)
|
|
136
132
|
const sources: (PlacedSource & { quiet: true })[] = []
|
|
137
133
|
for (const source of layout.sources) {
|
|
138
134
|
const editing = held(source.path)
|
|
@@ -142,12 +138,12 @@ export async function lowerApp(
|
|
|
142
138
|
}
|
|
143
139
|
const [parsed] = parseSources(
|
|
144
140
|
[{ path: source.path, text: editing, quiet: true }],
|
|
145
|
-
|
|
141
|
+
diagnostics,
|
|
146
142
|
)
|
|
147
143
|
if (parsed !== undefined)
|
|
148
144
|
sources.push({ ...source, ...parsed, quiet: true })
|
|
149
145
|
}
|
|
150
|
-
const
|
|
146
|
+
const read = await readSources(checker.session, sources, diagnostics)
|
|
151
147
|
await checker.session.diagnose(read, layout, false)
|
|
152
148
|
}
|
|
153
149
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SERVER_SPECIFIER } from '#shared/SPECIFIERS.ts'
|
|
2
2
|
|
|
3
3
|
import type { CheckerAnswer } from './CheckerAnswer.ts'
|
|
4
|
-
import type { Finding } from './
|
|
4
|
+
import type { Finding } from './Diagnostics.ts'
|
|
5
5
|
import { hookCalls } from './hookCalls.ts'
|
|
6
6
|
import {
|
|
7
7
|
CHECKED_CONFIG,
|