@prestack/thread 0.0.1 → 0.0.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/dist/core/actor.ts +20 -0
- package/dist/core/asking.d.ts +0 -1
- package/dist/core/asking.js +0 -1
- package/dist/core/asking.ts +1342 -0
- package/dist/core/attach.js +2 -2
- package/dist/core/attach.ts +585 -0
- package/dist/core/chain.js +8 -1
- package/dist/core/chain.ts +148 -0
- package/dist/core/cli.js +97 -18
- package/dist/core/cli.ts +2004 -0
- package/dist/core/condition.ts +227 -0
- package/dist/core/descend.d.ts +1 -0
- package/dist/core/descend.js +36 -0
- package/dist/core/descend.ts +1001 -0
- package/dist/core/finding.ts +38 -0
- package/dist/core/generators/meta.js +6 -0
- package/dist/core/generators/meta.ts +1006 -0
- package/dist/core/init.ts +170 -0
- package/dist/core/invoked.ts +47 -0
- package/dist/core/round.ts +57 -0
- package/dist/core/rows.ts +369 -0
- package/dist/core/scope.ts +18 -0
- package/dist/core/thread.ts +29 -0
- package/dist/core/tree.ts +67 -0
- package/dist/core/types.ts +350 -0
- package/dist/derivation/attach.js +1 -1
- package/dist/derivation/attach.ts +68 -0
- package/dist/derivation/generators/build.ts +232 -0
- package/dist/derivation/generators/check.ts +118 -0
- package/dist/derivation/generators/derivation.ts +347 -0
- package/dist/derivation/generators/determinism.ts +145 -0
- package/dist/derivation/generators/release.js +19 -9
- package/dist/derivation/generators/release.ts +213 -0
- package/dist/derivation/makers/release.ts +135 -0
- package/dist/derivation/release.ts +23 -0
- package/dist/integrations/attach.js +2 -2
- package/dist/integrations/attach.ts +207 -0
- package/dist/integrations/generators/read.ts +127 -0
- package/dist/integrations/generators/secret.ts +289 -0
- package/dist/integrations/generators/target.js +16 -6
- package/dist/integrations/generators/target.ts +944 -0
- package/dist/integrations/generators/vault.js +46 -14
- package/dist/integrations/generators/vault.ts +212 -0
- package/dist/integrations/{sdk.js → module.js} +4 -4
- package/dist/integrations/module.ts +189 -0
- package/dist/integrations/secret.ts +50 -0
- package/dist/integrations/target.d.ts +3 -1
- package/dist/integrations/target.js +14 -11
- package/dist/integrations/target.ts +340 -0
- package/dist/integrations/vault.d.ts +2 -0
- package/dist/integrations/vault.js +4 -2
- package/dist/integrations/vault.ts +136 -0
- package/dist/integrity/attach.ts +234 -0
- package/dist/integrity/check-threads.js +2 -26
- package/dist/integrity/check-threads.ts +166 -0
- package/dist/integrity/constraint.ts +1202 -0
- package/dist/integrity/generators/compiler.ts +161 -0
- package/dist/integrity/generators/gate.ts +201 -0
- package/dist/integrity/generators/issues.ts +160 -0
- package/dist/integrity/generators/publish.js +14 -5
- package/dist/integrity/generators/publish.ts +247 -0
- package/dist/integrity/generators/rule.ts +271 -0
- package/dist/integrity/generators/seal.ts +117 -0
- package/dist/integrity/generators/trial.ts +320 -0
- package/dist/integrity/lint.ts +227 -0
- package/dist/integrity/lsp/bin.ts +42 -0
- package/dist/integrity/lsp/diagnostics.ts +92 -0
- package/dist/integrity/lsp/findings.ts +63 -0
- package/dist/integrity/lsp/lint.ts +140 -0
- package/dist/integrity/lsp/protocol.ts +78 -0
- package/dist/integrity/lsp/server.ts +224 -0
- package/dist/integrity/sealed.js +2 -2
- package/dist/integrity/sealed.ts +56 -0
- package/dist/integrity/slopnator.ts +350 -0
- package/dist/integrity/slopnators/sl_broken_lineage.ts +36 -0
- package/dist/integrity/slopnators/sl_declared_elsewhere.ts +39 -0
- package/dist/integrity/slopnators/sl_derived_drift.ts +98 -0
- package/dist/integrity/slopnators/sl_hardcoded_style.ts +55 -0
- package/dist/integrity/slopnators/sl_inert_island.ts +91 -0
- package/dist/integrity/slopnators/sl_inert_slopnator.ts +93 -0
- package/dist/integrity/slopnators/sl_missing_row.ts +182 -0
- package/dist/integrity/slopnators/sl_no_barrel.ts +48 -0
- package/dist/integrity/slopnators/sl_no_child_process.ts +74 -0
- package/dist/integrity/slopnators/sl_no_comment.ts +43 -0
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +328 -0
- package/dist/integrity/slopnators/sl_no_import_cycle.ts +50 -0
- package/dist/integrity/slopnators/sl_no_such_command.ts +64 -0
- package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +63 -0
- package/dist/integrity/slopnators/sl_secret_literal.ts +100 -0
- package/dist/integrity/slopnators/sl_stale_path.ts +94 -0
- package/dist/integrity/slopnators/sl_twice_meant.ts +31 -0
- package/dist/integrity/slopnators/sl_twice_parented.ts +37 -0
- package/dist/integrity/slopnators/sl_undeclared_crossing.ts +87 -0
- package/dist/integrity/slopnators/sl_undeclared_destination.ts +65 -0
- package/dist/integrity/slopnators/sl_undeclared_element.ts +44 -0
- package/dist/integrity/slopnators/sl_undeclared_node.ts +69 -0
- package/dist/integrity/slopnators/sl_undeclared_operation.ts +147 -0
- package/dist/integrity/slopnators/sl_undeclared_variant.ts +148 -0
- package/dist/integrity/slopnators/sl_undescribed.ts +65 -0
- package/dist/integrity/slopnators/sl_ungoverned_island.ts +61 -0
- package/dist/integrity/slopnators/sl_unkept_rows.ts +111 -0
- package/dist/integrity/slopnators/sl_unnamed_island.ts +41 -0
- package/dist/integrity/slopnators/sl_unpaired_member.ts +131 -0
- package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +58 -0
- package/dist/integrity/slopnators/sl_unprefixed_member.ts +136 -0
- package/dist/integrity/slopnators/sl_unseamed_reach.ts +79 -0
- package/dist/integrity/slopnators/sl_unthreaded.ts +419 -0
- package/dist/integrity/slopnators/sl_untranslated_key.ts +164 -0
- package/dist/integrity/slopnators/sl_unversioned.ts +36 -0
- package/dist/integrity/sweep.ts +307 -0
- package/dist/knowledge/attach.ts +350 -0
- package/dist/knowledge/generators/docsgen.ts +174 -0
- package/dist/knowledge/generators/glossary.ts +73 -0
- package/dist/knowledge/generators/skills.ts +263 -0
- package/dist/knowledge/glossary.ts +6 -0
- package/dist/operations/access.ts +88 -0
- package/dist/operations/attach.ts +475 -0
- package/dist/operations/capabilities.ts +65 -0
- package/dist/operations/cost.ts +58 -0
- package/dist/operations/dispatch.ts +348 -0
- package/dist/operations/error-results.ts +31 -0
- package/dist/operations/errors/catalog.ts +168 -0
- package/dist/operations/errors/classes.ts +51 -0
- package/dist/operations/errors/errors.ts +314 -0
- package/dist/operations/generators/capability.js +29 -19
- package/dist/operations/generators/capability.ts +704 -0
- package/dist/operations/generators/compile.js +20 -1
- package/dist/operations/generators/compile.ts +643 -0
- package/dist/operations/generators/grant.ts +336 -0
- package/dist/operations/generators/operation.ts +972 -0
- package/dist/operations/generators/permits.ts +223 -0
- package/dist/operations/generators/seed.ts +347 -0
- package/dist/operations/generators/trial.js +4 -1
- package/dist/operations/generators/trial.ts +529 -0
- package/dist/operations/http.ts +164 -0
- package/dist/operations/makers/capability.ts +166 -0
- package/dist/operations/makers/trial.ts +520 -0
- package/dist/operations/memory.ts +470 -0
- package/dist/operations/metering.ts +328 -0
- package/dist/operations/nodes.ts +54 -0
- package/dist/operations/operations.ts +32 -0
- package/dist/operations/queue-policy.ts +10 -0
- package/dist/operations/result.ts +28 -0
- package/dist/operations/seams.d.ts +4 -4
- package/dist/operations/seams.ts +364 -0
- package/dist/operations/store.ts +29 -0
- package/package.json +8 -1
- package/dist/integrations/generators/sdk.d.ts +0 -1
- package/dist/integrations/generators/sdk.js +0 -148
- /package/dist/integrations/{sdk.d.ts → module.d.ts} +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface At {
|
|
2
|
+
readonly line: number
|
|
3
|
+
readonly column: number
|
|
4
|
+
readonly endLine?: number
|
|
5
|
+
readonly endColumn?: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Finding {
|
|
9
|
+
readonly severity: 'error' | 'warning'
|
|
10
|
+
|
|
11
|
+
readonly check: string
|
|
12
|
+
readonly detail: string
|
|
13
|
+
|
|
14
|
+
readonly file: string
|
|
15
|
+
|
|
16
|
+
readonly at?: At
|
|
17
|
+
|
|
18
|
+
readonly anchor?: string
|
|
19
|
+
|
|
20
|
+
readonly suggestions?: readonly string[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function detailOf(finding: Finding): string {
|
|
24
|
+
const offered = finding.suggestions ?? []
|
|
25
|
+
return offered.length === 0 ? finding.detail : `${finding.detail} ${offered.join(' ')}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DECLARED_ID = /\b[a-z]{2,6}_[a-z][a-z0-9_]*\b/g
|
|
29
|
+
|
|
30
|
+
export function anchorIn(detail: string): string | undefined {
|
|
31
|
+
const candidates = [
|
|
32
|
+
...(detail.match(DECLARED_ID) ?? []),
|
|
33
|
+
...[...detail.matchAll(/"([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_*]+)+)"/g)].map((m) => m[1] as string),
|
|
34
|
+
]
|
|
35
|
+
if (candidates.length === 0) return undefined
|
|
36
|
+
return candidates.reduce((longest, one) => (one.length > longest.length ? one : longest))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function locate(text: string, anchor: string): At | undefined {
|
|
40
|
+
const lines = text.split('\n')
|
|
41
|
+
for (const [index, line] of lines.entries()) {
|
|
42
|
+
const column = line.indexOf(anchor)
|
|
43
|
+
if (column === -1) continue
|
|
44
|
+
return {
|
|
45
|
+
line: index + 1,
|
|
46
|
+
column: column + 1,
|
|
47
|
+
endLine: index + 1,
|
|
48
|
+
endColumn: column + 1 + anchor.length,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return undefined
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function headOf(text: string): At {
|
|
55
|
+
const first = text.split('\n')[0] ?? ''
|
|
56
|
+
return { line: 1, column: 1, endLine: 1, endColumn: Math.max(first.length, 1) + 1 }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function rangeOf(finding: Finding, text: string): At {
|
|
60
|
+
if (finding.at !== undefined) return finding.at
|
|
61
|
+
const anchor = finding.anchor ?? anchorIn(finding.detail)
|
|
62
|
+
return (anchor === undefined ? undefined : locate(text, anchor)) ?? headOf(text)
|
|
63
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { extname, join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { theRules } from '../lint.ts'
|
|
6
|
+
|
|
7
|
+
import type { Finding } from './findings.ts'
|
|
8
|
+
|
|
9
|
+
interface EslintMessage {
|
|
10
|
+
readonly ruleId?: string | null
|
|
11
|
+
readonly severity: number
|
|
12
|
+
readonly message: string
|
|
13
|
+
readonly line?: number
|
|
14
|
+
readonly column?: number
|
|
15
|
+
readonly endLine?: number
|
|
16
|
+
readonly endColumn?: number
|
|
17
|
+
|
|
18
|
+
readonly suggestions?: readonly { readonly desc?: string }[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface EslintFile {
|
|
22
|
+
readonly messages?: readonly EslintMessage[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const LINTABLE = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs', '.jsx'])
|
|
26
|
+
|
|
27
|
+
export const isLintable = (relative: string): boolean => LINTABLE.has(extname(relative))
|
|
28
|
+
|
|
29
|
+
export const LINT_CONFIG = 'eslint.config.js'
|
|
30
|
+
|
|
31
|
+
export class LintUnavailableError extends Error {
|
|
32
|
+
constructor(detail: string) {
|
|
33
|
+
super(
|
|
34
|
+
`ESLint could not be run over this repository: ${detail}. This server reports what the build ` +
|
|
35
|
+
'computes, so a lint pass that answered "no problems" because it never ran would be ' +
|
|
36
|
+
'indistinguishable from a clean file — which is the one thing it must never be.',
|
|
37
|
+
)
|
|
38
|
+
this.name = 'LintUnavailableError'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function binaryIn(root: string): string | undefined {
|
|
43
|
+
const local = join(root, 'node_modules', '.bin', 'eslint')
|
|
44
|
+
return existsSync(local) ? local : undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function ruleFindings(relative: string, text: string): Promise<readonly Finding[]> {
|
|
48
|
+
const rules = theRules()
|
|
49
|
+
return rules(relative, text).map((violation) => ({
|
|
50
|
+
severity: 'error' as const,
|
|
51
|
+
check: violation.rule,
|
|
52
|
+
|
|
53
|
+
detail: violation.bans ?? violation.message,
|
|
54
|
+
file: relative,
|
|
55
|
+
at: { line: violation.line, column: violation.column },
|
|
56
|
+
suggestions: [
|
|
57
|
+
...(violation.instead === undefined ? [] : [violation.instead]),
|
|
58
|
+
...(violation.right === undefined ? [] : [`Write: ${violation.right}`]),
|
|
59
|
+
],
|
|
60
|
+
}))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const suggestionsOf = (message: EslintMessage): readonly string[] =>
|
|
64
|
+
(message.suggestions ?? []).map((one) => one.desc).filter((desc): desc is string => desc !== undefined)
|
|
65
|
+
|
|
66
|
+
export async function lintFindings(root: string, relative: string, text: string): Promise<readonly Finding[]> {
|
|
67
|
+
if (!isLintable(relative)) return []
|
|
68
|
+
|
|
69
|
+
if (!existsSync(join(root, LINT_CONFIG))) return await ruleFindings(relative, text)
|
|
70
|
+
|
|
71
|
+
const binary = binaryIn(root)
|
|
72
|
+
if (binary === undefined) {
|
|
73
|
+
return [
|
|
74
|
+
{
|
|
75
|
+
severity: 'error',
|
|
76
|
+
check: 'lint:unavailable',
|
|
77
|
+
detail:
|
|
78
|
+
`${LINT_CONFIG} is here and node_modules/.bin/eslint is not, so none of this repository's ` +
|
|
79
|
+
'rules are being checked while you type. Install the dev dependencies.',
|
|
80
|
+
file: LINT_CONFIG,
|
|
81
|
+
},
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const report = await runEslint(binary, root, relative, text)
|
|
86
|
+
|
|
87
|
+
return report.flatMap((file) =>
|
|
88
|
+
(file.messages ?? []).map((message) => ({
|
|
89
|
+
severity: message.severity === 2 ? ('error' as const) : ('warning' as const),
|
|
90
|
+
check: message.ruleId ?? 'lint',
|
|
91
|
+
detail: message.message,
|
|
92
|
+
file: relative,
|
|
93
|
+
at: {
|
|
94
|
+
line: message.line ?? 1,
|
|
95
|
+
column: message.column ?? 1,
|
|
96
|
+
...(message.endLine === undefined ? {} : { endLine: message.endLine }),
|
|
97
|
+
...(message.endColumn === undefined ? {} : { endColumn: message.endColumn }),
|
|
98
|
+
},
|
|
99
|
+
...(suggestionsOf(message).length === 0 ? {} : { suggestions: suggestionsOf(message) }),
|
|
100
|
+
})),
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function runEslint(
|
|
105
|
+
binary: string,
|
|
106
|
+
root: string,
|
|
107
|
+
relative: string,
|
|
108
|
+
text: string,
|
|
109
|
+
): Promise<readonly EslintFile[]> {
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
111
|
+
|
|
112
|
+
const child = spawn(binary, ['--format', 'json', '--no-warn-ignored', '--stdin', '--stdin-filename', relative], {
|
|
113
|
+
cwd: root,
|
|
114
|
+
shell: false,
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
let out = ''
|
|
118
|
+
let err = ''
|
|
119
|
+
child.stdout.on('data', (chunk: Buffer) => (out += chunk.toString()))
|
|
120
|
+
child.stderr.on('data', (chunk: Buffer) => (err += chunk.toString()))
|
|
121
|
+
child.on('error', (error) => reject(new LintUnavailableError(error.message)))
|
|
122
|
+
child.on('close', () => {
|
|
123
|
+
|
|
124
|
+
let parsed: unknown
|
|
125
|
+
try {
|
|
126
|
+
parsed = JSON.parse(out)
|
|
127
|
+
} catch {
|
|
128
|
+
reject(new LintUnavailableError(err.trim() === '' ? `it wrote ${out.length} bytes of non-JSON` : err.trim()))
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
if (!Array.isArray(parsed)) {
|
|
132
|
+
reject(new LintUnavailableError('its JSON report was not an array of files'))
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
resolve(parsed as readonly EslintFile[])
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
child.stdin.end(text)
|
|
139
|
+
})
|
|
140
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export interface RpcMessage {
|
|
4
|
+
readonly jsonrpc: '2.0'
|
|
5
|
+
readonly id?: number | string | null
|
|
6
|
+
readonly method?: string
|
|
7
|
+
readonly params?: unknown
|
|
8
|
+
readonly result?: unknown
|
|
9
|
+
readonly error?: { readonly code: number; readonly message: string }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const HEADER_END = '\r\n\r\n'
|
|
13
|
+
|
|
14
|
+
export const METHOD_NOT_FOUND = -32601
|
|
15
|
+
|
|
16
|
+
export function encode(message: RpcMessage): Buffer {
|
|
17
|
+
const body = Buffer.from(JSON.stringify(message), 'utf8')
|
|
18
|
+
return Buffer.concat([Buffer.from(`Content-Length: ${body.length}${HEADER_END}`, 'ascii'), body])
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class MalformedMessageError extends Error {
|
|
22
|
+
constructor(detail: string) {
|
|
23
|
+
super(
|
|
24
|
+
`the editor sent something this server cannot parse: ${detail}. ` +
|
|
25
|
+
'A language server that skipped it would answer the next request against a stream it no ' +
|
|
26
|
+
'longer understands, which reads as a file with no problems.',
|
|
27
|
+
)
|
|
28
|
+
this.name = 'MalformedMessageError'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class MessageBuffer {
|
|
33
|
+
#pending: Buffer = Buffer.alloc(0)
|
|
34
|
+
|
|
35
|
+
push(chunk: Buffer): readonly RpcMessage[] {
|
|
36
|
+
this.#pending = Buffer.concat([this.#pending, chunk])
|
|
37
|
+
|
|
38
|
+
const found: RpcMessage[] = []
|
|
39
|
+
for (;;) {
|
|
40
|
+
const split = this.#pending.indexOf(HEADER_END, 0, 'ascii')
|
|
41
|
+
if (split === -1) return found
|
|
42
|
+
|
|
43
|
+
const header = this.#pending.subarray(0, split).toString('ascii')
|
|
44
|
+
const length = contentLength(header)
|
|
45
|
+
const start = split + HEADER_END.length
|
|
46
|
+
|
|
47
|
+
if (this.#pending.length < start + length) return found
|
|
48
|
+
|
|
49
|
+
const body = this.#pending.subarray(start, start + length).toString('utf8')
|
|
50
|
+
this.#pending = this.#pending.subarray(start + length)
|
|
51
|
+
|
|
52
|
+
let parsed: unknown
|
|
53
|
+
try {
|
|
54
|
+
parsed = JSON.parse(body)
|
|
55
|
+
} catch {
|
|
56
|
+
throw new MalformedMessageError(`a ${length}-byte body that is not JSON`)
|
|
57
|
+
}
|
|
58
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
59
|
+
throw new MalformedMessageError(`a ${length}-byte body that is not a JSON object`)
|
|
60
|
+
}
|
|
61
|
+
found.push(parsed as RpcMessage)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function contentLength(header: string): number {
|
|
67
|
+
for (const line of header.split('\r\n')) {
|
|
68
|
+
const [name, value] = line.split(':', 2)
|
|
69
|
+
|
|
70
|
+
if (name?.trim().toLowerCase() !== 'content-length') continue
|
|
71
|
+
const length = Number.parseInt((value ?? '').trim(), 10)
|
|
72
|
+
if (!Number.isInteger(length) || length < 0) {
|
|
73
|
+
throw new MalformedMessageError(`Content-Length: ${(value ?? '').trim()}`)
|
|
74
|
+
}
|
|
75
|
+
return length
|
|
76
|
+
}
|
|
77
|
+
throw new MalformedMessageError(`a header block with no Content-Length: ${JSON.stringify(header)}`)
|
|
78
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { relative as relativeTo, resolve } from 'node:path'
|
|
2
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
3
|
+
|
|
4
|
+
import { named } from '../../core/scope.ts'
|
|
5
|
+
import { report, SOURCE_NAME, type Diagnostic, type DiagnosticSource } from './diagnostics.ts'
|
|
6
|
+
import { METHOD_NOT_FOUND, type RpcMessage } from './protocol.ts'
|
|
7
|
+
|
|
8
|
+
const SYNC_FULL = 1
|
|
9
|
+
|
|
10
|
+
export interface ServerOptions {
|
|
11
|
+
|
|
12
|
+
readonly root: string
|
|
13
|
+
|
|
14
|
+
readonly sourceFor: (root: string) => DiagnosticSource
|
|
15
|
+
send(message: RpcMessage): void
|
|
16
|
+
|
|
17
|
+
settle?(): Promise<void>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface TextDocumentIdentifier {
|
|
21
|
+
readonly uri?: unknown
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DidOpenParams {
|
|
25
|
+
readonly textDocument?: { readonly uri?: unknown; readonly text?: unknown }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface DidChangeParams {
|
|
29
|
+
readonly textDocument?: TextDocumentIdentifier
|
|
30
|
+
readonly contentChanges?: readonly { readonly text?: unknown }[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface InitializeParams {
|
|
34
|
+
readonly rootUri?: unknown
|
|
35
|
+
readonly rootPath?: unknown
|
|
36
|
+
readonly workspaceFolders?: readonly { readonly uri?: unknown }[] | null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class LspServer {
|
|
40
|
+
#root: string
|
|
41
|
+
readonly #options: ServerOptions
|
|
42
|
+
|
|
43
|
+
readonly #open = new Map<string, string>()
|
|
44
|
+
|
|
45
|
+
#published = new Set<string>()
|
|
46
|
+
|
|
47
|
+
#running = false
|
|
48
|
+
#again = false
|
|
49
|
+
#shutdownRequested = false
|
|
50
|
+
#exited = false
|
|
51
|
+
|
|
52
|
+
constructor(options: ServerOptions) {
|
|
53
|
+
this.#options = options
|
|
54
|
+
this.#root = options.root
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get exited(): boolean {
|
|
58
|
+
return this.#exited
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get exitCode(): number {
|
|
62
|
+
return this.#shutdownRequested ? 0 : 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async handle(message: RpcMessage): Promise<void> {
|
|
66
|
+
|
|
67
|
+
if (message.method === undefined) return
|
|
68
|
+
|
|
69
|
+
switch (message.method) {
|
|
70
|
+
case 'initialize':
|
|
71
|
+
this.#root = rootIn(message.params as InitializeParams | undefined) ?? this.#root
|
|
72
|
+
this.#reply(message.id, {
|
|
73
|
+
capabilities: {
|
|
74
|
+
textDocumentSync: { openClose: true, change: SYNC_FULL, save: true },
|
|
75
|
+
|
|
76
|
+
diagnosticProvider: {
|
|
77
|
+
identifier: SOURCE_NAME,
|
|
78
|
+
|
|
79
|
+
interFileDependencies: true,
|
|
80
|
+
workspaceDiagnostics: false,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
serverInfo: { name: named('integrity') },
|
|
84
|
+
})
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
case 'initialized':
|
|
88
|
+
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
case 'shutdown':
|
|
92
|
+
this.#shutdownRequested = true
|
|
93
|
+
this.#reply(message.id, null)
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
case 'exit':
|
|
97
|
+
this.#exited = true
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
case 'textDocument/didOpen': {
|
|
101
|
+
const params = message.params as DidOpenParams | undefined
|
|
102
|
+
const path = this.#pathOf(params?.textDocument?.uri)
|
|
103
|
+
if (path === undefined) return
|
|
104
|
+
this.#open.set(path, typeof params?.textDocument?.text === 'string' ? params.textDocument.text : '')
|
|
105
|
+
await this.#recompute()
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
case 'textDocument/didChange': {
|
|
110
|
+
const params = message.params as DidChangeParams | undefined
|
|
111
|
+
const path = this.#pathOf(params?.textDocument?.uri)
|
|
112
|
+
if (path === undefined) return
|
|
113
|
+
|
|
114
|
+
const latest = params?.contentChanges?.at(-1)?.text
|
|
115
|
+
if (typeof latest === 'string') this.#open.set(path, latest)
|
|
116
|
+
await this.#recompute()
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case 'textDocument/didSave':
|
|
121
|
+
await this.#recompute()
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
case 'textDocument/didClose': {
|
|
125
|
+
const path = this.#pathOf((message.params as DidOpenParams | undefined)?.textDocument?.uri)
|
|
126
|
+
if (path === undefined) return
|
|
127
|
+
this.#open.delete(path)
|
|
128
|
+
await this.#recompute()
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
case 'textDocument/diagnostic': {
|
|
133
|
+
const path = this.#pathOf((message.params as DidOpenParams | undefined)?.textDocument?.uri)
|
|
134
|
+
const computed = await report(this.#sourceForRoot(), this.#open, this.#published)
|
|
135
|
+
this.#published = new Set([...computed].filter(([, list]) => list.length > 0).map(([file]) => file))
|
|
136
|
+
this.#reply(message.id, {
|
|
137
|
+
kind: 'full',
|
|
138
|
+
items: path === undefined ? [] : (computed.get(path) ?? []),
|
|
139
|
+
})
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
default:
|
|
144
|
+
|
|
145
|
+
if (message.id !== undefined && message.id !== null) {
|
|
146
|
+
this.#options.send({
|
|
147
|
+
jsonrpc: '2.0',
|
|
148
|
+
id: message.id,
|
|
149
|
+
error: { code: METHOD_NOT_FOUND, message: `${message.method} is not implemented by ${SOURCE_NAME}` },
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#sourceForRoot(): DiagnosticSource {
|
|
156
|
+
return this.#options.sourceFor(this.#root)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#reply(id: RpcMessage['id'], result: unknown): void {
|
|
160
|
+
if (id === undefined || id === null) return
|
|
161
|
+
this.#options.send({ jsonrpc: '2.0', id, result })
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async #recompute(): Promise<void> {
|
|
165
|
+
if (this.#running) {
|
|
166
|
+
this.#again = true
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.#running = true
|
|
171
|
+
try {
|
|
172
|
+
do {
|
|
173
|
+
this.#again = false
|
|
174
|
+
await (this.#options.settle?.() ?? sleep(200))
|
|
175
|
+
const computed = await report(this.#sourceForRoot(), this.#open, this.#published)
|
|
176
|
+
|
|
177
|
+
const nonEmpty = new Set<string>()
|
|
178
|
+
for (const [path, diagnostics] of computed) {
|
|
179
|
+
this.#publish(path, diagnostics)
|
|
180
|
+
if (diagnostics.length > 0) nonEmpty.add(path)
|
|
181
|
+
}
|
|
182
|
+
this.#published = nonEmpty
|
|
183
|
+
} while (this.#again)
|
|
184
|
+
} finally {
|
|
185
|
+
this.#running = false
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
#publish(path: string, diagnostics: readonly Diagnostic[]): void {
|
|
190
|
+
this.#options.send({
|
|
191
|
+
jsonrpc: '2.0',
|
|
192
|
+
method: 'textDocument/publishDiagnostics',
|
|
193
|
+
params: { uri: pathToFileURL(resolve(this.#root, path)).href, diagnostics },
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
#pathOf(uri: unknown): string | undefined {
|
|
198
|
+
if (typeof uri !== 'string' || !uri.startsWith('file://')) return undefined
|
|
199
|
+
let absolute: string
|
|
200
|
+
try {
|
|
201
|
+
absolute = fileURLToPath(uri)
|
|
202
|
+
} catch {
|
|
203
|
+
return undefined
|
|
204
|
+
}
|
|
205
|
+
const path = relativeTo(this.#root, absolute).split('\\').join('/')
|
|
206
|
+
|
|
207
|
+
return path.startsWith('..') || path.startsWith('/') ? undefined : path
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const sleep = (ms: number): Promise<void> => new Promise((done) => setTimeout(done, ms))
|
|
212
|
+
|
|
213
|
+
function rootIn(params: InitializeParams | undefined): string | undefined {
|
|
214
|
+
const folder = params?.workspaceFolders?.[0]?.uri
|
|
215
|
+
for (const uri of [folder, params?.rootUri]) {
|
|
216
|
+
if (typeof uri !== 'string' || !uri.startsWith('file://')) continue
|
|
217
|
+
try {
|
|
218
|
+
return fileURLToPath(uri)
|
|
219
|
+
} catch {
|
|
220
|
+
continue
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return typeof params?.rootPath === 'string' ? params.rootPath : undefined
|
|
224
|
+
}
|
package/dist/integrity/sealed.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export const SEALED = {
|
|
2
2
|
'attach.js': 'e879e49449a3b90118335ab4d2ea6666956da92203438fac7b88ff3a65a79103',
|
|
3
|
-
'check-threads.js': '
|
|
3
|
+
'check-threads.js': '3c943a890af508bfeb0071974ab74ff3f90ff3ce5e7cd1ffa2e2580c6214b3e2',
|
|
4
4
|
'constraint.js': 'c6eebad19fc11c42c095d82f5658c204f322d136bcbaab98aa9fc06dfa625afb',
|
|
5
5
|
'generators/compiler.js': 'c6db73bfd31513d8334ef5cd063fb5f12b89c56739ff0f2b73249252d1817cdc',
|
|
6
6
|
'generators/gate.js': 'f865f469f13b9e3b2eb120bd233b3e286c0df30a4cdf15cd20be4cb995854f88',
|
|
7
7
|
'generators/issues.js': '21cd7349d3375f15cb8b1a0c31714ab645b021b952275046b56357fba68478b8',
|
|
8
|
-
'generators/publish.js': '
|
|
8
|
+
'generators/publish.js': 'f19114019854ace16fd5ca94c42cbffd838894ce9e7679d6afd4cf26e2bdddd5',
|
|
9
9
|
'generators/rule.js': '82bdfefbf394528fa4e7994a60eb423b3188277571937e161648f72666728aa4',
|
|
10
10
|
'generators/seal.js': '39fb8ab5c95b9c0fd1d3d38090785b2e1890653bb1d0454868426b67b28abe3a',
|
|
11
11
|
'generators/trial.js': 'a2ef8fda83bb2894ae088a0d7887a4e49b9693fa1a7e1345879aaa63041914b0',
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const SEALED: Readonly<Record<string, string>> = {
|
|
2
|
+
'attach.js': 'e879e49449a3b90118335ab4d2ea6666956da92203438fac7b88ff3a65a79103',
|
|
3
|
+
'check-threads.js': '3c943a890af508bfeb0071974ab74ff3f90ff3ce5e7cd1ffa2e2580c6214b3e2',
|
|
4
|
+
'constraint.js': 'c6eebad19fc11c42c095d82f5658c204f322d136bcbaab98aa9fc06dfa625afb',
|
|
5
|
+
'generators/compiler.js': 'c6db73bfd31513d8334ef5cd063fb5f12b89c56739ff0f2b73249252d1817cdc',
|
|
6
|
+
'generators/gate.js': 'f865f469f13b9e3b2eb120bd233b3e286c0df30a4cdf15cd20be4cb995854f88',
|
|
7
|
+
'generators/issues.js': '21cd7349d3375f15cb8b1a0c31714ab645b021b952275046b56357fba68478b8',
|
|
8
|
+
'generators/publish.js': 'f19114019854ace16fd5ca94c42cbffd838894ce9e7679d6afd4cf26e2bdddd5',
|
|
9
|
+
'generators/rule.js': '82bdfefbf394528fa4e7994a60eb423b3188277571937e161648f72666728aa4',
|
|
10
|
+
'generators/seal.js': '39fb8ab5c95b9c0fd1d3d38090785b2e1890653bb1d0454868426b67b28abe3a',
|
|
11
|
+
'generators/trial.js': 'a2ef8fda83bb2894ae088a0d7887a4e49b9693fa1a7e1345879aaa63041914b0',
|
|
12
|
+
'lint.js': '63f9957725a94498d7e5a49544da343c5f2e1b3b9c2778000dae4a4f39036ef9',
|
|
13
|
+
'lsp/bin.js': 'b71d5da40c137dbe87083ad29bf1a54e30a190113b8811602263f4c5a4d5a11c',
|
|
14
|
+
'lsp/diagnostics.js': '0fd15477b4df60e5ec065bb1a85c5daab6b9b433e730cb836b8ddc747554e0b9',
|
|
15
|
+
'lsp/findings.js': '72f7d80645c0941926a1cc029417fed93eca87e7d53bf2d032f4ef647fb1f168',
|
|
16
|
+
'lsp/lint.js': '159b07ffa100a62b2cd445d621606ae0d6b68aacc342cb5fdb3a2f4cadd7f508',
|
|
17
|
+
'lsp/protocol.js': 'd0ad8650307bf563bd058dc2bbbbc0ec9d4fd6dc2c9120bdc261d57c076ddc5d',
|
|
18
|
+
'lsp/server.js': 'a9f76280e395a47521973a14f3769c4df9e8c1153d29dedc535f56276e5a2e2e',
|
|
19
|
+
'slopnator.js': '804adba20c269c1134fd09e075d354db73b79cfd00c4b4ce66c1e40279670905',
|
|
20
|
+
'slopnators/sl_broken_lineage.js': '6d0ee15127166d9792b365e8a4623b5770a57e2ff92c2accf196afbb85052112',
|
|
21
|
+
'slopnators/sl_declared_elsewhere.js': '394da91ac84369217b4a02bc078ab98f62bf6d522042d84bec82b9705d621751',
|
|
22
|
+
'slopnators/sl_derived_drift.js': 'f7fb0e26cd6bff9dfe7392e1b1593a51741a6f6fac408bdafbb783e04141cf2f',
|
|
23
|
+
'slopnators/sl_hardcoded_style.js': 'a2b006990bc33150733645f3c17942ff497e7b3a6565af1331263df36d3b5e0a',
|
|
24
|
+
'slopnators/sl_inert_island.js': '0900de73ab7439b02a3321a6459e53882cfba6267dc8ef45d630ebe40f4bfa84',
|
|
25
|
+
'slopnators/sl_inert_slopnator.js': 'e3c35cfa2b094e1e2fd6824b75138cf44e8edb5ec396375d67e47897d84c45d7',
|
|
26
|
+
'slopnators/sl_missing_row.js': 'd942940388a873bebeff72d93cdb5fef20ba88e4fe29c1aa68e2f42389714a4a',
|
|
27
|
+
'slopnators/sl_no_barrel.js': '7df2a763d4b4ab16d945341b844271380b25774491bfa9c204dc252910951bc6',
|
|
28
|
+
'slopnators/sl_no_child_process.js': '24d4f89a1493c95db12e92a34dc4281a422226f638a47c795f26447090e056a1',
|
|
29
|
+
'slopnators/sl_no_comment.js': '4c4b9b502d6b33ed00d653d0b190d8f95b02bc5ef10da87f97913ca425f59f40',
|
|
30
|
+
'slopnators/sl_no_dispatch_bypass.js': '1def29fca350861b7185129180edd4727199e0f2bba92a0e0a8c0af437cbb382',
|
|
31
|
+
'slopnators/sl_no_import_cycle.js': '7ab70e4c182e88f73b4af75cddef9655a49996b8c70fcc2dcebd5f4aeb5fef92',
|
|
32
|
+
'slopnators/sl_no_such_command.js': 'fe037c2ad6891fd3c0338dd84c7007110c0bcd272a12bd8f1cb85ec779df7a8b',
|
|
33
|
+
'slopnators/sl_only_takes_a_literal.js': '3d5074f9c6a9bb581c80af8aa6d4a6793e29ac93c793367a67326acc1612c8fe',
|
|
34
|
+
'slopnators/sl_secret_literal.js': 'bc3987627f3b2892eec169d775771b6309d47b2c93e98c1bccad3f3ed5c5d2b6',
|
|
35
|
+
'slopnators/sl_stale_path.js': '3cc4050cb9ca2875afbb69c818d20d06e82f36a762ec48bd033c342a7023ff8a',
|
|
36
|
+
'slopnators/sl_twice_meant.js': '6fc5aaf29b635335bd4963931475e7334110439f8305737786c01be39f81230c',
|
|
37
|
+
'slopnators/sl_twice_parented.js': 'caa590bc4c11dbebe971f5a611a1712a529cc5a2900f37ba43cfa6b67a0a722b',
|
|
38
|
+
'slopnators/sl_undeclared_crossing.js': '47e41a38334a4b5a3eb0616d675dc46c5e4d6ce1138710b4470acc276e6ddec5',
|
|
39
|
+
'slopnators/sl_undeclared_destination.js': '3bbf07029a31eb31fa6556b686d067aae0cd5bf9487fe6ca1896984a55970a5c',
|
|
40
|
+
'slopnators/sl_undeclared_element.js': '2aa469ffdd58f104936904cbee2c95cb38182a2ac1057e0caa4db3d85e81331c',
|
|
41
|
+
'slopnators/sl_undeclared_node.js': '84c069a7d1bdec3d3c950ad40e016c129f280796b63a196a7866232e14995443',
|
|
42
|
+
'slopnators/sl_undeclared_operation.js': 'bc3fa4efc83bf5641020373d0f1506856c6272c3d59e4c4d261e3076f69a155e',
|
|
43
|
+
'slopnators/sl_undeclared_variant.js': 'e41ec11c9f4baf52dbea1aa7828238e5738de609ea47cdcac793cbe6198df770',
|
|
44
|
+
'slopnators/sl_undescribed.js': '15c6139a4afc3a4dc1a6196ec1acc2af5066a3330343074f6e2b321291cdbbd0',
|
|
45
|
+
'slopnators/sl_ungoverned_island.js': '555ae51adf994c5fce4ce51701af7d022be8824c001eeb132403fd6342a12a49',
|
|
46
|
+
'slopnators/sl_unkept_rows.js': '8abd67e8b8347a6dd9abd20fb7719d4f10553d6f329001a34ccc3e063d448e1d',
|
|
47
|
+
'slopnators/sl_unnamed_island.js': '0c92c5b6fdf59fb97448f24d72b883cd64317c23280316e043f993e7b75ac1da',
|
|
48
|
+
'slopnators/sl_unpaired_member.js': 'aafba4f829ef038289176b6e5ea6622494eba1982268d8d52b44f8c9889943e9',
|
|
49
|
+
'slopnators/sl_unpaired_slopnator.js': '2fa5b8c3c8b6a8a71466086f1d3ae32ea16fd22c49b113225e3c9a7e76eda45e',
|
|
50
|
+
'slopnators/sl_unprefixed_member.js': '67640331089c55ac59e7950e3c919144740309fb4a91cf0af87c41edb761f75d',
|
|
51
|
+
'slopnators/sl_unseamed_reach.js': 'd27a64c85b221e7c5bac99ab9d36955ad4945520d2b9e5ec75927574ca454cda',
|
|
52
|
+
'slopnators/sl_unthreaded.js': 'b686212f3515eb2769030979f7141d236677c9f3c1802e436f254ea5410a2361',
|
|
53
|
+
'slopnators/sl_untranslated_key.js': '224e80a4f34ce760502ee256347c9191e8d103e8b0ff58ef995c10111ddf2854',
|
|
54
|
+
'slopnators/sl_unversioned.js': 'df73b3186e42e6b58e7fb3fd48c3146a2d3902a337861a6ccb52f433a569e392',
|
|
55
|
+
'sweep.js': '2402ba042f87e693bf785d8e81b40870dd2fec539a70a9593d7ecba767dcda2c',
|
|
56
|
+
}
|