@jhlagado/azm 0.2.12 → 0.2.14
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/src/api-compile.d.ts +7 -1
- package/dist/src/api-compile.js +17 -5
- package/dist/src/api-register-contracts.js +69 -2
- package/dist/src/api-tooling.d.ts +1 -1
- package/dist/src/cli/artifact-files.d.ts +1 -0
- package/dist/src/cli/artifact-files.js +5 -0
- package/dist/src/cli/parse-args.d.ts +6 -1
- package/dist/src/cli/parse-args.js +59 -0
- package/dist/src/cli/run.js +2 -2
- package/dist/src/cli/usage.js +5 -0
- package/dist/src/cli/write-artifacts.d.ts +1 -1
- package/dist/src/cli/write-artifacts.js +15 -2
- package/dist/src/expansion/op-expansion.js +12 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/outputs/types.d.ts +13 -1
- package/dist/src/register-contracts/analyze-helpers.d.ts +6 -1
- package/dist/src/register-contracts/analyze-helpers.js +67 -0
- package/dist/src/register-contracts/analyze.d.ts +8 -1
- package/dist/src/register-contracts/analyze.js +353 -16
- package/dist/src/register-contracts/interfaceContracts.js +45 -0
- package/dist/src/register-contracts/liveness.js +23 -0
- package/dist/src/register-contracts/policy.d.ts +2 -0
- package/dist/src/register-contracts/policy.js +54 -0
- package/dist/src/register-contracts/profiles.d.ts +5 -0
- package/dist/src/register-contracts/profiles.js +32 -2
- package/dist/src/register-contracts/programModel-boundaries.d.ts +5 -1
- package/dist/src/register-contracts/programModel-boundaries.js +20 -5
- package/dist/src/register-contracts/programModel-routines.js +37 -6
- package/dist/src/register-contracts/ratchet.d.ts +3 -0
- package/dist/src/register-contracts/ratchet.js +88 -0
- package/dist/src/register-contracts/report.d.ts +8 -1
- package/dist/src/register-contracts/report.js +174 -0
- package/dist/src/register-contracts/smartCommentParsing.js +22 -0
- package/dist/src/register-contracts/summaries.js +4 -0
- package/dist/src/register-contracts/summary-boundary.js +21 -3
- package/dist/src/register-contracts/summary.js +31 -3
- package/dist/src/register-contracts/tooling.d.ts +2 -1
- package/dist/src/register-contracts/tooling.js +2 -0
- package/dist/src/register-contracts/types.d.ts +159 -0
- package/dist/src/syntax/parse-line.js +3 -0
- package/docs/codebase/02-source-loading-and-parsing.md +10 -6
- package/docs/codebase/04-ops-and-register-contracts.md +58 -4
- package/docs/codebase/05-interfaces-and-output-artifacts.md +69 -6
- package/docs/codebase/06-verification-and-maintenance.md +10 -2
- package/docs/codebase/appendices/a-directory-file-reference.md +3 -1
- package/docs/codebase/appendices/b-compile-flow-reference.md +7 -5
- package/docs/codebase/appendices/c-public-surface-reference.md +19 -5
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { writeHex } from './outputs/write-hex.js';
|
|
|
3
3
|
import type { AddressRange, Artifact, D8mArtifact, D8mFileEntry, D8mFileSymbol, D8mGenerator, D8mJson, D8mSegment, D8mSymbol, EmittedByteMap, FormatWriters, SymbolEntry, WriteD8mOptions } from './outputs/types.js';
|
|
4
4
|
import type { Diagnostic } from './model/diagnostic.js';
|
|
5
5
|
import type { CaseStyleMode } from './tooling/case-style.js';
|
|
6
|
-
import type { RegisterContractsMode } from './register-contracts/types.js';
|
|
6
|
+
import type { RegisterContractsMode, RegisterContractsPolicy, RegisterContractsReportFormat } from './register-contracts/types.js';
|
|
7
7
|
export { writeHex, defaultFormatWriters };
|
|
8
8
|
export type { AddressRange, Artifact, D8mArtifact, D8mFileEntry, D8mFileSymbol, D8mGenerator, D8mJson, D8mSegment, D8mSymbol, EmittedByteMap, FormatWriters, SymbolEntry, WriteD8mOptions, };
|
|
9
9
|
export type CompileDependencies = CompileNextDependencies;
|
|
@@ -30,8 +30,14 @@ export interface CompileNextFunctionOptions {
|
|
|
30
30
|
readonly registerContracts?: RegisterContractsMode;
|
|
31
31
|
/** @deprecated Use registerContracts. */
|
|
32
32
|
readonly registerCare?: RegisterContractsMode;
|
|
33
|
+
readonly registerContractsPolicy?: RegisterContractsPolicy;
|
|
33
34
|
readonly emitRegisterReport?: boolean;
|
|
35
|
+
readonly registerContractsReportFormat?: RegisterContractsReportFormat;
|
|
36
|
+
readonly registerContractsBaseline?: string;
|
|
37
|
+
readonly registerContractsRatchet?: boolean;
|
|
34
38
|
readonly emitRegisterInterface?: boolean;
|
|
39
|
+
readonly emitRegisterInference?: boolean;
|
|
40
|
+
readonly registerContractsInferenceFormat?: 'json' | 'markdown';
|
|
35
41
|
readonly emitRegisterAnnotations?: boolean;
|
|
36
42
|
readonly fixRegisterContracts?: boolean;
|
|
37
43
|
readonly acceptRegisterOutputCandidates?: string[];
|
package/dist/src/api-compile.js
CHANGED
|
@@ -5,12 +5,13 @@ import { runRegisterContracts, shouldAnalyzeRegisterContracts } from './api-regi
|
|
|
5
5
|
import { analyzeProgramNext, loadProgramNext } from './tooling/api.js';
|
|
6
6
|
import { defaultFormatWriters } from './outputs/index.js';
|
|
7
7
|
import { writeHex } from './outputs/write-hex.js';
|
|
8
|
+
import { registerContractsPolicyModeForFile } from './register-contracts/policy.js';
|
|
8
9
|
import { buildRegisterContractsProgramModel } from './register-contracts/programModel.js';
|
|
9
10
|
function parseUnresolvedSymbolName(message) {
|
|
10
11
|
const match = /^Unresolved symbol "([^"]+)"/.exec(message);
|
|
11
12
|
return match?.[1];
|
|
12
13
|
}
|
|
13
|
-
function isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls) {
|
|
14
|
+
function isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls, policy, fallbackMode) {
|
|
14
15
|
if (directCalls === undefined || directCalls.length === 0) {
|
|
15
16
|
return false;
|
|
16
17
|
}
|
|
@@ -27,7 +28,11 @@ function isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCall
|
|
|
27
28
|
return directCalls.some((call) => call.target === symbol &&
|
|
28
29
|
call.file === diagnostic.sourceName &&
|
|
29
30
|
call.line === diagnostic.line &&
|
|
30
|
-
call.column === diagnostic.column
|
|
31
|
+
call.column === diagnostic.column &&
|
|
32
|
+
!isRegisterContractsPolicyOffForFile(call.file, policy, fallbackMode));
|
|
33
|
+
}
|
|
34
|
+
function isRegisterContractsPolicyOffForFile(file, policy, fallbackMode) {
|
|
35
|
+
return policy !== undefined && registerContractsPolicyModeForFile(file, policy, fallbackMode) === 'off';
|
|
31
36
|
}
|
|
32
37
|
export { writeHex, defaultFormatWriters };
|
|
33
38
|
/**
|
|
@@ -56,10 +61,14 @@ export async function compile(entryFile, options = {}, deps = { formats: default
|
|
|
56
61
|
.directCalls
|
|
57
62
|
: undefined;
|
|
58
63
|
diagnostics.push(...analysis.diagnostics.filter((diagnostic) => analyzeRegisterContractsNow
|
|
59
|
-
? !isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls)
|
|
64
|
+
? !isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls, options.registerContractsPolicy, options.registerContracts ?? options.registerCare)
|
|
60
65
|
: true));
|
|
61
66
|
const artifacts = [];
|
|
62
67
|
if (hasErrors(diagnostics)) {
|
|
68
|
+
if (analyzeRegisterContractsNow && options.emitRegisterReport === true) {
|
|
69
|
+
const registerContracts = await runRegisterContracts(loaded.loadedProgram, options);
|
|
70
|
+
artifacts.push(...registerContractsReportArtifacts(registerContracts.artifacts));
|
|
71
|
+
}
|
|
63
72
|
sortDiagnosticsInPlace(diagnostics);
|
|
64
73
|
return { diagnostics, artifacts };
|
|
65
74
|
}
|
|
@@ -76,11 +85,11 @@ export async function compile(entryFile, options = {}, deps = { formats: default
|
|
|
76
85
|
const program = loaded.loadedProgram.program.files[0]?.items ?? [];
|
|
77
86
|
const assembled = assembleProgram(program);
|
|
78
87
|
diagnostics.push(...assembled.diagnostics.filter((diagnostic) => analyzeRegisterContractsNow
|
|
79
|
-
? !isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls)
|
|
88
|
+
? !isSuppressedUnknownSymbolInRegisterContractsMode(diagnostic, directCalls, options.registerContractsPolicy, options.registerContracts ?? options.registerCare)
|
|
80
89
|
: true));
|
|
81
90
|
sortDiagnosticsInPlace(diagnostics);
|
|
82
91
|
if (hasErrors(diagnostics)) {
|
|
83
|
-
return { diagnostics, artifacts:
|
|
92
|
+
return { diagnostics, artifacts: registerContractsReportArtifacts(artifacts) };
|
|
84
93
|
}
|
|
85
94
|
const emittedArtifacts = await emitAssemblyArtifacts({
|
|
86
95
|
entryFile: normalizedEntry,
|
|
@@ -100,6 +109,9 @@ export async function compile(entryFile, options = {}, deps = { formats: default
|
|
|
100
109
|
function hasErrors(diagnostics) {
|
|
101
110
|
return diagnostics.some((diagnostic) => diagnostic.severity === 'error');
|
|
102
111
|
}
|
|
112
|
+
function registerContractsReportArtifacts(artifacts) {
|
|
113
|
+
return artifacts.filter((artifact) => artifact.kind === 'register-contracts-report');
|
|
114
|
+
}
|
|
103
115
|
function sortDiagnosticsInPlace(diagnostics) {
|
|
104
116
|
dedupeDiagnosticsInPlace(diagnostics);
|
|
105
117
|
diagnostics.sort((left, right) => {
|
|
@@ -8,10 +8,13 @@ export function shouldAnalyzeRegisterContracts(options) {
|
|
|
8
8
|
return (registerContractsMode !== 'off' ||
|
|
9
9
|
options.emitRegisterReport === true ||
|
|
10
10
|
options.emitRegisterInterface === true ||
|
|
11
|
+
options.emitRegisterInference === true ||
|
|
11
12
|
options.emitRegisterAnnotations === true ||
|
|
12
13
|
options.fixRegisterContracts === true ||
|
|
14
|
+
options.registerContractsPolicy !== undefined ||
|
|
13
15
|
(options.acceptRegisterOutputCandidates?.length ?? 0) > 0 ||
|
|
14
|
-
(options.registerContractsInterfaces?.length ?? options.registerCareInterfaces?.length ?? 0) > 0
|
|
16
|
+
(options.registerContractsInterfaces?.length ?? options.registerCareInterfaces?.length ?? 0) > 0 ||
|
|
17
|
+
options.registerContractsBaseline !== undefined);
|
|
15
18
|
}
|
|
16
19
|
export async function runRegisterContracts(loadedProgram, options) {
|
|
17
20
|
const diagnostics = [];
|
|
@@ -20,10 +23,24 @@ export async function runRegisterContracts(loadedProgram, options) {
|
|
|
20
23
|
if (hasErrors(diagnostics)) {
|
|
21
24
|
return { diagnostics, artifacts };
|
|
22
25
|
}
|
|
26
|
+
const baselineReport = await loadBaselineReport(options.registerContractsBaseline, diagnostics);
|
|
27
|
+
if (hasErrors(diagnostics)) {
|
|
28
|
+
return { diagnostics, artifacts };
|
|
29
|
+
}
|
|
23
30
|
const registerContracts = analyzeRegisterContracts(loadedProgram, {
|
|
24
31
|
mode: options.registerContracts ?? options.registerCare ?? 'off',
|
|
32
|
+
...(options.registerContractsPolicy !== undefined
|
|
33
|
+
? { policy: options.registerContractsPolicy }
|
|
34
|
+
: {}),
|
|
25
35
|
emitReport: options.emitRegisterReport === true,
|
|
36
|
+
...(options.registerContractsReportFormat !== undefined
|
|
37
|
+
? { reportFormat: options.registerContractsReportFormat }
|
|
38
|
+
: {}),
|
|
26
39
|
emitInterface: options.emitRegisterInterface === true,
|
|
40
|
+
emitInference: options.emitRegisterInference === true,
|
|
41
|
+
...(options.registerContractsInferenceFormat !== undefined
|
|
42
|
+
? { inferenceFormat: options.registerContractsInferenceFormat }
|
|
43
|
+
: {}),
|
|
27
44
|
emitAnnotations: options.emitRegisterAnnotations === true || options.fixRegisterContracts === true,
|
|
28
45
|
fixRegisterContracts: options.fixRegisterContracts === true,
|
|
29
46
|
acceptedOutputCandidates: parseAcceptedOutputCandidates(options.acceptRegisterOutputCandidates ?? []),
|
|
@@ -33,13 +50,36 @@ export async function runRegisterContracts(loadedProgram, options) {
|
|
|
33
50
|
}
|
|
34
51
|
: {}),
|
|
35
52
|
...(interfaceContracts.length > 0 ? { interfaceContracts } : {}),
|
|
53
|
+
...(baselineReport !== undefined ? { baselineReport } : {}),
|
|
54
|
+
...(options.registerContractsBaseline !== undefined
|
|
55
|
+
? { baselineFile: normalize(options.registerContractsBaseline) }
|
|
56
|
+
: {}),
|
|
57
|
+
ratchet: options.registerContractsRatchet === true,
|
|
36
58
|
});
|
|
37
59
|
if (registerContracts.reportText !== undefined) {
|
|
38
|
-
artifacts.push({
|
|
60
|
+
artifacts.push({
|
|
61
|
+
kind: 'register-contracts-report',
|
|
62
|
+
...(registerContracts.reportFormat !== undefined
|
|
63
|
+
? { format: registerContracts.reportFormat }
|
|
64
|
+
: {}),
|
|
65
|
+
text: registerContracts.reportText,
|
|
66
|
+
...(registerContracts.reportJson !== undefined ? { json: registerContracts.reportJson } : {}),
|
|
67
|
+
...(registerContracts.findings !== undefined ? { findings: registerContracts.findings } : {}),
|
|
68
|
+
});
|
|
39
69
|
}
|
|
40
70
|
if (registerContracts.interfaceText !== undefined) {
|
|
41
71
|
artifacts.push({ kind: 'register-contracts-interface', text: registerContracts.interfaceText });
|
|
42
72
|
}
|
|
73
|
+
if (registerContracts.inferenceText !== undefined) {
|
|
74
|
+
artifacts.push({
|
|
75
|
+
kind: 'register-contracts-inference',
|
|
76
|
+
format: registerContracts.inferenceFormat ?? 'json',
|
|
77
|
+
text: registerContracts.inferenceText,
|
|
78
|
+
...(registerContracts.inferenceJson !== undefined
|
|
79
|
+
? { json: registerContracts.inferenceJson }
|
|
80
|
+
: {}),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
43
83
|
if (registerContracts.annotations !== undefined && registerContracts.annotations.length > 0) {
|
|
44
84
|
artifacts.push({
|
|
45
85
|
kind: 'register-contracts-annotations',
|
|
@@ -52,6 +92,33 @@ export async function runRegisterContracts(loadedProgram, options) {
|
|
|
52
92
|
diagnostics.push(...registerContracts.diagnostics);
|
|
53
93
|
return { artifacts, diagnostics };
|
|
54
94
|
}
|
|
95
|
+
async function loadBaselineReport(rawPath, diagnostics) {
|
|
96
|
+
if (rawPath === undefined)
|
|
97
|
+
return undefined;
|
|
98
|
+
const baselinePath = normalize(rawPath);
|
|
99
|
+
try {
|
|
100
|
+
const parsed = JSON.parse(await readFile(baselinePath, 'utf8'));
|
|
101
|
+
if (parsed.format !== 'azm-register-contracts-report' || !Array.isArray(parsed.findings)) {
|
|
102
|
+
diagnostics.push({
|
|
103
|
+
severity: 'error',
|
|
104
|
+
code: 'AZMN_REGISTER_CONTRACTS',
|
|
105
|
+
sourceName: baselinePath,
|
|
106
|
+
message: 'Register contracts baseline must be a JSON register-contracts report',
|
|
107
|
+
});
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return parsed;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
diagnostics.push({
|
|
114
|
+
severity: 'error',
|
|
115
|
+
code: 'AZMN_REGISTER_CONTRACTS',
|
|
116
|
+
sourceName: baselinePath,
|
|
117
|
+
message: `Unable to read register contracts baseline: ${String(error)}`,
|
|
118
|
+
});
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
55
122
|
async function loadInterfaceContracts(interfaces, diagnostics) {
|
|
56
123
|
const interfaceContracts = [];
|
|
57
124
|
for (const rawInterface of interfaces) {
|
|
@@ -4,4 +4,4 @@ export { DiagnosticIds } from './model/diagnostic.js';
|
|
|
4
4
|
export type { AnalyzeProgramOptions, AnalyzeProgramResult, LoadedProgram, LoadProgramOptions, LoadProgramResult, AnalyzeProgramNextOptions, AnalyzeProgramNextResult, LoadedProgramNext, LoadProgramNextOptions, LoadProgramNextResult, } from './tooling/api.js';
|
|
5
5
|
export type { CaseStyleMode } from './tooling/case-style.js';
|
|
6
6
|
export type { Diagnostic, DiagnosticId, DiagnosticSeverity } from './model/diagnostic.js';
|
|
7
|
-
export type { RegisterCareMode, RegisterCareOutputCandidate, RegisterCareUnit, RegisterContractsMode, RegisterContractsOutputCandidate, RegisterContractsUnit, } from './register-contracts/types.js';
|
|
7
|
+
export type { RegisterCareMode, RegisterCareOutputCandidate, RegisterCareUnit, RegisterContractsMode, RegisterContractsFinding, RegisterContractsFindingKind, RegisterContractsOutputCandidate, RegisterContractsUnit, } from './register-contracts/types.js';
|
|
@@ -57,6 +57,11 @@ function queueRegisterContractsArtifacts(writes, byKind, paths) {
|
|
|
57
57
|
writes.push(writeTextArtifact(paths.registerContractsInterface, iface.text));
|
|
58
58
|
registerContractsPath ??= paths.registerContractsInterface;
|
|
59
59
|
}
|
|
60
|
+
const inference = byKind.get('register-contracts-inference');
|
|
61
|
+
if (inference?.kind === 'register-contracts-inference') {
|
|
62
|
+
writes.push(writeTextArtifact(paths.registerContractsInference, inference.text));
|
|
63
|
+
registerContractsPath ??= paths.registerContractsInference;
|
|
64
|
+
}
|
|
60
65
|
return registerContractsPath;
|
|
61
66
|
}
|
|
62
67
|
function queueRegisterContractsAnnotationArtifacts(writes, byKind) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RegisterContractsMode } from '../register-contracts/types.js';
|
|
1
|
+
import type { RegisterContractsInferenceFormat, RegisterContractsMode, RegisterContractsReportFormat } from '../register-contracts/types.js';
|
|
2
2
|
import type { CaseStyleMode } from '../tooling/case-style.js';
|
|
3
3
|
import { cliUsage } from './usage.js';
|
|
4
4
|
export type CliExit = {
|
|
@@ -16,7 +16,12 @@ export type CliOptions = {
|
|
|
16
16
|
caseStyle: CaseStyleMode;
|
|
17
17
|
registerContracts: RegisterContractsMode;
|
|
18
18
|
emitRegisterReport: boolean;
|
|
19
|
+
registerContractsReportFormat: RegisterContractsReportFormat;
|
|
20
|
+
registerContractsBaseline: string | undefined;
|
|
21
|
+
registerContractsRatchet: boolean;
|
|
19
22
|
emitRegisterInterface: boolean;
|
|
23
|
+
emitRegisterInference: boolean;
|
|
24
|
+
registerContractsInferenceFormat: RegisterContractsInferenceFormat;
|
|
20
25
|
emitRegisterAnnotations: boolean;
|
|
21
26
|
fixRegisterContracts: boolean;
|
|
22
27
|
acceptRegisterOutputCandidates: string[];
|
|
@@ -38,6 +38,20 @@ const BOOLEAN_FLAG_ACTIONS = [
|
|
|
38
38
|
state.emitRegisterInterface = true;
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
|
+
{
|
|
42
|
+
flags: ['--reg-infer'],
|
|
43
|
+
apply: (state) => {
|
|
44
|
+
state.emitRegisterInference = true;
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
flags: ['--reg-ratchet'],
|
|
49
|
+
apply: (state) => {
|
|
50
|
+
state.registerContractsRatchet = true;
|
|
51
|
+
state.emitRegisterReport = true;
|
|
52
|
+
state.registerContractsReportFormat = 'json';
|
|
53
|
+
},
|
|
54
|
+
},
|
|
41
55
|
{
|
|
42
56
|
flags: ['--fix'],
|
|
43
57
|
apply: (state) => {
|
|
@@ -67,7 +81,12 @@ function createDefaultCliState() {
|
|
|
67
81
|
caseStyle: 'off',
|
|
68
82
|
registerContracts: 'off',
|
|
69
83
|
emitRegisterReport: false,
|
|
84
|
+
registerContractsReportFormat: 'text',
|
|
85
|
+
registerContractsBaseline: undefined,
|
|
86
|
+
registerContractsRatchet: false,
|
|
70
87
|
emitRegisterInterface: false,
|
|
88
|
+
emitRegisterInference: false,
|
|
89
|
+
registerContractsInferenceFormat: 'json',
|
|
71
90
|
emitRegisterAnnotations: false,
|
|
72
91
|
fixRegisterContracts: false,
|
|
73
92
|
acceptRegisterOutputCandidates: [],
|
|
@@ -199,6 +218,37 @@ function parseRegisterProfileArg(arg, argv, indexRef, state) {
|
|
|
199
218
|
state.registerContractsProfile = parsed.value;
|
|
200
219
|
return true;
|
|
201
220
|
}
|
|
221
|
+
function parseRegisterReportFormatArg(arg, argv, indexRef, state) {
|
|
222
|
+
const parsed = readMatchedFlagValue(arg, argv, indexRef, ['--reg-report-format']);
|
|
223
|
+
if (!parsed)
|
|
224
|
+
return false;
|
|
225
|
+
if (parsed.value !== 'text' && parsed.value !== 'json') {
|
|
226
|
+
fail(`Unsupported ${parsed.flag} "${parsed.value}" (expected text|json)`);
|
|
227
|
+
}
|
|
228
|
+
state.emitRegisterReport = true;
|
|
229
|
+
state.registerContractsReportFormat = parsed.value;
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
function parseRegisterInferenceFormatArg(arg, argv, indexRef, state) {
|
|
233
|
+
const parsed = readMatchedFlagValue(arg, argv, indexRef, ['--reg-infer-format']);
|
|
234
|
+
if (!parsed)
|
|
235
|
+
return false;
|
|
236
|
+
if (parsed.value !== 'json' && parsed.value !== 'markdown') {
|
|
237
|
+
fail(`Unsupported ${parsed.flag} "${parsed.value}" (expected json|markdown)`);
|
|
238
|
+
}
|
|
239
|
+
state.emitRegisterInference = true;
|
|
240
|
+
state.registerContractsInferenceFormat = parsed.value;
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
function parseRegisterBaselineArg(arg, argv, indexRef, state) {
|
|
244
|
+
const parsed = readMatchedFlagValue(arg, argv, indexRef, ['--reg-baseline']);
|
|
245
|
+
if (!parsed)
|
|
246
|
+
return false;
|
|
247
|
+
state.registerContractsBaseline = parsed.value;
|
|
248
|
+
state.emitRegisterReport = true;
|
|
249
|
+
state.registerContractsReportFormat = 'json';
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
202
252
|
function parseRegisterInterfaceArg(arg, argv, indexRef, state) {
|
|
203
253
|
if (arg !== '--interface' && !arg.startsWith('--interface='))
|
|
204
254
|
return false;
|
|
@@ -264,7 +314,12 @@ function finalizeCliOptions(state) {
|
|
|
264
314
|
caseStyle: state.caseStyle,
|
|
265
315
|
registerContracts: state.registerContracts,
|
|
266
316
|
emitRegisterReport: state.emitRegisterReport,
|
|
317
|
+
registerContractsReportFormat: state.registerContractsBaseline !== undefined ? 'json' : state.registerContractsReportFormat,
|
|
318
|
+
registerContractsBaseline: state.registerContractsBaseline,
|
|
319
|
+
registerContractsRatchet: state.registerContractsRatchet,
|
|
267
320
|
emitRegisterInterface: state.emitRegisterInterface,
|
|
321
|
+
emitRegisterInference: state.emitRegisterInference,
|
|
322
|
+
registerContractsInferenceFormat: state.registerContractsInferenceFormat,
|
|
268
323
|
emitRegisterAnnotations: state.emitRegisterAnnotations,
|
|
269
324
|
fixRegisterContracts: state.fixRegisterContracts,
|
|
270
325
|
acceptRegisterOutputCandidates: state.acceptRegisterOutputCandidates,
|
|
@@ -299,6 +354,7 @@ function emitsRegisterContractsArtifact(state) {
|
|
|
299
354
|
state.registerContracts !== 'off',
|
|
300
355
|
state.emitRegisterReport,
|
|
301
356
|
state.emitRegisterInterface,
|
|
357
|
+
state.emitRegisterInference,
|
|
302
358
|
state.emitRegisterAnnotations,
|
|
303
359
|
state.fixRegisterContracts,
|
|
304
360
|
state.acceptRegisterOutputCandidates.length > 0,
|
|
@@ -324,6 +380,9 @@ const VALUE_ARG_PARSERS = [
|
|
|
324
380
|
(arg, { argv, indexRef, state }) => parseDirectiveAliasFileArg(arg, argv, indexRef, state),
|
|
325
381
|
(arg, { argv, indexRef, state }) => parseRegisterContractsArg(arg, argv, indexRef, state),
|
|
326
382
|
(arg, { argv, indexRef, state }) => parseRegisterProfileArg(arg, argv, indexRef, state),
|
|
383
|
+
(arg, { argv, indexRef, state }) => parseRegisterReportFormatArg(arg, argv, indexRef, state),
|
|
384
|
+
(arg, { argv, indexRef, state }) => parseRegisterInferenceFormatArg(arg, argv, indexRef, state),
|
|
385
|
+
(arg, { argv, indexRef, state }) => parseRegisterBaselineArg(arg, argv, indexRef, state),
|
|
327
386
|
(arg, { argv, indexRef, state }) => parseAcceptOutputArg(arg, argv, indexRef, state),
|
|
328
387
|
(arg, { argv, indexRef, state }) => parseRegisterInterfaceArg(arg, argv, indexRef, state),
|
|
329
388
|
(arg, { argv, indexRef, state }) => parseIncludeArg(arg, argv, indexRef, state),
|
package/dist/src/cli/run.js
CHANGED
|
@@ -19,11 +19,11 @@ export async function runCli(argv) {
|
|
|
19
19
|
}
|
|
20
20
|
if (sortedDiagnostics.some((diagnostic) => diagnostic.severity === 'error')) {
|
|
21
21
|
if (compileResult.artifacts.length > 0) {
|
|
22
|
-
await writeArtifacts(base, compileResult.artifacts, parsed.outputType);
|
|
22
|
+
await writeArtifacts(base, compileResult.artifacts, parsed.outputType, parsed.registerContractsReportFormat);
|
|
23
23
|
}
|
|
24
24
|
return 1;
|
|
25
25
|
}
|
|
26
|
-
const primaryPath = await writeArtifacts(base, compileResult.artifacts, parsed.outputType);
|
|
26
|
+
const primaryPath = await writeArtifacts(base, compileResult.artifacts, parsed.outputType, parsed.registerContractsReportFormat);
|
|
27
27
|
if (primaryPath !== undefined) {
|
|
28
28
|
process.stdout.write(primaryPath);
|
|
29
29
|
}
|
package/dist/src/cli/usage.js
CHANGED
|
@@ -12,7 +12,12 @@ export function cliUsage() {
|
|
|
12
12
|
' --register-contracts <m> Register contracts mode: off|audit|warn|error|strict',
|
|
13
13
|
' --rc <m> Register contracts mode alias for --register-contracts',
|
|
14
14
|
' --reg-report Emit register contracts report artifact',
|
|
15
|
+
' --reg-report-format <f> Report format: text|json (default: text)',
|
|
16
|
+
' --reg-baseline <f> Compare against a JSON register contracts report',
|
|
17
|
+
' --reg-ratchet Fail if register contract findings increase',
|
|
15
18
|
' --reg-interface Emit inferred register contracts interface (.asmi)',
|
|
19
|
+
' --reg-infer Emit inferred register contracts review artifact',
|
|
20
|
+
' --reg-infer-format <f> Inference format: json|markdown (default: json)',
|
|
16
21
|
' --contracts Rewrite source with inferred register contracts',
|
|
17
22
|
' --fix Enable contract rewrite and conservative fixes',
|
|
18
23
|
' --accept-out <x> Accept register contracts output candidates',
|
|
@@ -17,5 +17,5 @@ export declare function compareDiagnosticsForCli(a: {
|
|
|
17
17
|
message: string;
|
|
18
18
|
}): number;
|
|
19
19
|
export declare function artifactBase(entryFile: string, outputType: 'hex' | 'bin', outputPath?: string): string;
|
|
20
|
-
export declare function writeArtifacts(base: string, artifacts: readonly Artifact[], outputType: 'hex' | 'bin'): Promise<string | undefined>;
|
|
20
|
+
export declare function writeArtifacts(base: string, artifacts: readonly Artifact[], outputType: 'hex' | 'bin', registerContractsReportFormat?: 'text' | 'json'): Promise<string | undefined>;
|
|
21
21
|
export declare function buildCompileOptions(parsed: CliOptions, base: string): CompileNextFunctionOptions;
|
|
@@ -46,14 +46,20 @@ export function artifactBase(entryFile, outputType, outputPath) {
|
|
|
46
46
|
const entryExt = extname(resolvedEntry);
|
|
47
47
|
return entryExt.length > 0 ? resolvedEntry.slice(0, -entryExt.length) : resolvedEntry;
|
|
48
48
|
}
|
|
49
|
-
export async function writeArtifacts(base, artifacts, outputType) {
|
|
49
|
+
export async function writeArtifacts(base, artifacts, outputType, registerContractsReportFormat = 'text') {
|
|
50
|
+
const registerContractsReportExt = registerContractsReportFormat === 'json' ? 'json' : 'txt';
|
|
51
|
+
const inference = artifacts.find((artifact) => artifact.kind === 'register-contracts-inference');
|
|
52
|
+
const registerContractsInferenceExt = inference?.kind === 'register-contracts-inference' && inference.format === 'markdown'
|
|
53
|
+
? 'md'
|
|
54
|
+
: 'json';
|
|
50
55
|
const result = await writeArtifactFiles(artifacts, {
|
|
51
56
|
hex: `${base}.hex`,
|
|
52
57
|
bin: `${base}.bin`,
|
|
53
58
|
d8m: `${base}.d8.json`,
|
|
54
59
|
asm80: `${base}.z80`,
|
|
55
|
-
registerContractsReport: `${base}.regcontracts
|
|
60
|
+
registerContractsReport: `${base}.regcontracts.${registerContractsReportExt}`,
|
|
56
61
|
registerContractsInterface: `${base}.asmi`,
|
|
62
|
+
registerContractsInference: `${base}.regcontracts.inference.${registerContractsInferenceExt}`,
|
|
57
63
|
}, outputType);
|
|
58
64
|
return result.primaryPath ?? result.registerContractsPath;
|
|
59
65
|
}
|
|
@@ -70,7 +76,14 @@ export function buildCompileOptions(parsed, base) {
|
|
|
70
76
|
caseStyle: parsed.caseStyle,
|
|
71
77
|
registerContracts: parsed.registerContracts,
|
|
72
78
|
emitRegisterReport: parsed.emitRegisterReport,
|
|
79
|
+
registerContractsReportFormat: parsed.registerContractsReportFormat,
|
|
80
|
+
...(parsed.registerContractsBaseline !== undefined
|
|
81
|
+
? { registerContractsBaseline: parsed.registerContractsBaseline }
|
|
82
|
+
: {}),
|
|
83
|
+
registerContractsRatchet: parsed.registerContractsRatchet,
|
|
73
84
|
emitRegisterInterface: parsed.emitRegisterInterface,
|
|
85
|
+
emitRegisterInference: parsed.emitRegisterInference,
|
|
86
|
+
registerContractsInferenceFormat: parsed.registerContractsInferenceFormat,
|
|
74
87
|
emitRegisterAnnotations: parsed.emitRegisterAnnotations,
|
|
75
88
|
fixRegisterContracts: parsed.fixRegisterContracts,
|
|
76
89
|
acceptRegisterOutputCandidates: parsed.acceptRegisterOutputCandidates,
|
|
@@ -127,7 +127,18 @@ function parseOpBodyTemplates(line, paramNames, diagnostics, parseOptions) {
|
|
|
127
127
|
kind: 'label',
|
|
128
128
|
name: label.name,
|
|
129
129
|
...(label.isEntry ? { isEntry: true } : {}),
|
|
130
|
-
span: {
|
|
130
|
+
span: {
|
|
131
|
+
sourceName: segmentLine.sourceName,
|
|
132
|
+
line: segmentLine.line,
|
|
133
|
+
column: label.labelColumn,
|
|
134
|
+
...(segmentLine.sourceUnit !== undefined ? { sourceUnit: segmentLine.sourceUnit } : {}),
|
|
135
|
+
...(segmentLine.sourceRelation !== undefined
|
|
136
|
+
? { sourceRelation: segmentLine.sourceRelation }
|
|
137
|
+
: {}),
|
|
138
|
+
...(segmentLine.sourceUnitRelation !== undefined
|
|
139
|
+
? { sourceUnitRelation: segmentLine.sourceUnitRelation }
|
|
140
|
+
: {}),
|
|
141
|
+
},
|
|
131
142
|
},
|
|
132
143
|
],
|
|
133
144
|
}),
|
package/dist/src/index.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export { compile, defaultFormatWriters, writeHex } from './api-compile.js';
|
|
|
11
11
|
export type { AddressRange, Artifact, CompileDependencies, CompileFunctionOptions, CompileResult, CompileNextDependencies, CompileNextFunctionOptions, EmittedByteMap, FormatWriters, CompileNextResult as CompileNextProgramResult, } from './api-compile.js';
|
|
12
12
|
export type { AnalyzeProgramOptions, AnalyzeProgramResult, LoadProgramOptions, LoadProgramResult, LoadedProgram, AnalyzeProgramNextOptions, AnalyzeProgramNextResult, LoadProgramNextOptions, LoadProgramNextResult, LoadedProgramNext, } from './tooling/api.js';
|
|
13
13
|
export type { CaseStyleMode } from './tooling/case-style.js';
|
|
14
|
-
export type { RegisterCareMode, RegisterCareOutputCandidate, RegisterCareUnit, RegisterContractsMode, RegisterContractsOutputCandidate, RegisterContractsUnit, } from './register-contracts/types.js';
|
|
14
|
+
export type { RegisterCareMode, RegisterCareOutputCandidate, RegisterCareUnit, RegisterContractsMode, RegisterContractsFinding, RegisterContractsFindingKind, RegisterContractsInferenceFormat, RegisterContractsInferenceModel, RegisterContractsInferenceRoutine, RegisterContractsOutputCandidate, RegisterContractsPolicy, RegisterContractsPolicyMode, RegisterContractsReportFormat, RegisterContractsUnit, } from './register-contracts/types.js';
|
|
15
15
|
export type { D8mArtifact, D8mGenerator, D8mJson, D8mFileEntry, D8mFileSymbol, D8mSegment, D8mSymbol, SymbolEntry, WriteD8mOptions, } from './outputs/types.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SourceItem } from '../model/source-item.js';
|
|
2
|
+
import type { RegisterContractsFinding, RegisterContractsInferenceFormat, RegisterContractsInferenceModel, RegisterContractsJsonReportModel, RegisterContractsReportFormat } from '../register-contracts/types.js';
|
|
2
3
|
/** Half-open address range in the Z80 16-bit address space. */
|
|
3
4
|
export interface AddressRange {
|
|
4
5
|
/** Inclusive start address. */
|
|
@@ -54,7 +55,10 @@ export interface HexArtifact {
|
|
|
54
55
|
export interface RegisterContractsReportArtifact {
|
|
55
56
|
kind: 'register-contracts-report';
|
|
56
57
|
path?: string;
|
|
58
|
+
format?: RegisterContractsReportFormat;
|
|
57
59
|
text: string;
|
|
60
|
+
json?: RegisterContractsJsonReportModel;
|
|
61
|
+
findings?: RegisterContractsFinding[];
|
|
58
62
|
}
|
|
59
63
|
/** @deprecated Use RegisterContractsReportArtifact. */
|
|
60
64
|
export type RegisterCareReportArtifact = RegisterContractsReportArtifact;
|
|
@@ -66,6 +70,14 @@ export interface RegisterContractsInterfaceArtifact {
|
|
|
66
70
|
}
|
|
67
71
|
/** @deprecated Use RegisterContractsInterfaceArtifact. */
|
|
68
72
|
export type RegisterCareInterfaceArtifact = RegisterContractsInterfaceArtifact;
|
|
73
|
+
/** In-memory inferred register contracts review artifact. */
|
|
74
|
+
export interface RegisterContractsInferenceArtifact {
|
|
75
|
+
kind: 'register-contracts-inference';
|
|
76
|
+
path?: string;
|
|
77
|
+
format: RegisterContractsInferenceFormat;
|
|
78
|
+
text: string;
|
|
79
|
+
json?: RegisterContractsInferenceModel;
|
|
80
|
+
}
|
|
69
81
|
/** In-memory register contracts source annotation artifact. */
|
|
70
82
|
export interface RegisterContractsAnnotationsArtifact {
|
|
71
83
|
kind: 'register-contracts-annotations';
|
|
@@ -166,7 +178,7 @@ export interface WriteD8mOptions {
|
|
|
166
178
|
}
|
|
167
179
|
export interface WriteAsm80Options {
|
|
168
180
|
}
|
|
169
|
-
export type Artifact = BinArtifact | HexArtifact | D8mArtifact | Asm80Artifact | RegisterContractsReportArtifact | RegisterContractsInterfaceArtifact | RegisterContractsAnnotationsArtifact;
|
|
181
|
+
export type Artifact = BinArtifact | HexArtifact | D8mArtifact | Asm80Artifact | RegisterContractsReportArtifact | RegisterContractsInterfaceArtifact | RegisterContractsInferenceArtifact | RegisterContractsAnnotationsArtifact;
|
|
170
182
|
/** Writer contract used by the compile API. */
|
|
171
183
|
export interface FormatWriters {
|
|
172
184
|
writeHex(map: EmittedByteMap, symbols: readonly SymbolEntry[], opts?: WriteHexOptions): HexArtifact;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Diagnostic } from '../model/diagnostic.js';
|
|
2
2
|
import { unknownCallList } from './summaries.js';
|
|
3
|
-
import type { AnalyzeRegisterContractsOptions, RegisterContractsOutputCandidate, RegisterContractsReportModel, RegisterContractsRoutine, RegisterContractsUnit, RoutineSummary } from './types.js';
|
|
3
|
+
import type { AnalyzeRegisterContractsOptions, RegisterContractsDirectCall, RegisterContractsFinding, RegisterContractsOutputCandidate, RegisterContractsReportModel, RegisterContractsRoutine, RegisterContractsUnit, RoutineSummary } from './types.js';
|
|
4
4
|
export declare function candidateMessageWithFixability(candidate: RegisterContractsOutputCandidate, autoFixable: boolean): string;
|
|
5
5
|
export declare function knownRoutineNames(routines: readonly RegisterContractsRoutine[], contractNames: Iterable<string>, profile: AnalyzeRegisterContractsOptions['registerContractsProfile']): Set<string>;
|
|
6
6
|
export declare function outputCandidatesWithFixability(routines: readonly RegisterContractsRoutine[], outputCandidates: readonly RegisterContractsOutputCandidate[]): {
|
|
@@ -14,12 +14,17 @@ export declare function diagnosticsForConflicts(conflicts: readonly {
|
|
|
14
14
|
message: string;
|
|
15
15
|
}[], mode: AnalyzeRegisterContractsOptions['mode']): Diagnostic[];
|
|
16
16
|
export declare function strictStackDiagnostics(routines: readonly RegisterContractsRoutine[], summaries: readonly RoutineSummary[]): Diagnostic[];
|
|
17
|
+
export declare function strictStackFindings(routines: readonly RegisterContractsRoutine[], summaries: readonly RoutineSummary[]): RegisterContractsFinding[];
|
|
18
|
+
export declare function unknownBoundaryFindings(directBoundaries: readonly RegisterContractsDirectCall[], knownRoutines: ReadonlySet<string>): RegisterContractsFinding[];
|
|
19
|
+
export declare function diagnosticsForFindings(findings: readonly RegisterContractsFinding[], mode: AnalyzeRegisterContractsOptions['mode']): Diagnostic[];
|
|
17
20
|
export declare function summariesForAnnotations(summariesByName: ReadonlyMap<string, RoutineSummary>, outputCandidates: readonly RegisterContractsOutputCandidate[]): Map<string, RoutineSummary>;
|
|
18
21
|
export declare function buildRegisterContractsReportModel(input: {
|
|
19
22
|
entryFile: string;
|
|
20
23
|
mode: AnalyzeRegisterContractsOptions['mode'];
|
|
21
24
|
summaries: readonly RoutineSummary[];
|
|
22
25
|
profileSummaries: readonly RoutineSummary[];
|
|
26
|
+
findings: readonly RegisterContractsFinding[];
|
|
27
|
+
suppressedFindings?: RegisterContractsReportModel['suppressedFindings'];
|
|
23
28
|
conflicts: RegisterContractsReportModel['conflicts'];
|
|
24
29
|
outputCandidates: readonly RegisterContractsOutputCandidate[];
|
|
25
30
|
profile: AnalyzeRegisterContractsOptions['registerContractsProfile'];
|
|
@@ -24,6 +24,7 @@ export function outputCandidatesWithFixability(routines, outputCandidates) {
|
|
|
24
24
|
const autoFixable = outputCandidateFixability.get(outputCandidateKey(candidate.file, candidate.line, candidate.column)) ?? false;
|
|
25
25
|
return {
|
|
26
26
|
...candidate,
|
|
27
|
+
kind: 'output_candidate',
|
|
27
28
|
autoFixable,
|
|
28
29
|
message: candidateMessageWithFixability(candidate, autoFixable),
|
|
29
30
|
};
|
|
@@ -63,6 +64,68 @@ export function strictStackDiagnostics(routines, summaries) {
|
|
|
63
64
|
}
|
|
64
65
|
return diagnostics;
|
|
65
66
|
}
|
|
67
|
+
export function strictStackFindings(routines, summaries) {
|
|
68
|
+
const routinesByName = new Map(routines.map((routine) => [routine.name, routine]));
|
|
69
|
+
const findings = [];
|
|
70
|
+
for (const summary of summaries) {
|
|
71
|
+
const routine = routinesByName.get(summary.name);
|
|
72
|
+
if (routine === undefined)
|
|
73
|
+
continue;
|
|
74
|
+
const stackIssues = strictStackIssueText(summary);
|
|
75
|
+
if (stackIssues === undefined)
|
|
76
|
+
continue;
|
|
77
|
+
findings.push({
|
|
78
|
+
kind: 'unknown_control_flow',
|
|
79
|
+
routine: summary.name,
|
|
80
|
+
stackBalanced: summary.stackBalanced,
|
|
81
|
+
...(summary.hasUnknownStackEffect !== undefined
|
|
82
|
+
? { hasUnknownStackEffect: summary.hasUnknownStackEffect }
|
|
83
|
+
: {}),
|
|
84
|
+
file: routine.span.file,
|
|
85
|
+
line: routine.span.start.line,
|
|
86
|
+
column: routine.span.start.column,
|
|
87
|
+
...(routine.span.sourceUnit !== undefined ? { sourceUnit: routine.span.sourceUnit } : {}),
|
|
88
|
+
...(routine.span.sourceRelation !== undefined
|
|
89
|
+
? { sourceRelation: routine.span.sourceRelation }
|
|
90
|
+
: {}),
|
|
91
|
+
...(routine.span.sourceUnitRelation !== undefined
|
|
92
|
+
? { sourceUnitRelation: routine.span.sourceUnitRelation }
|
|
93
|
+
: {}),
|
|
94
|
+
message: `Register contracts cannot prove stack discipline for ${summary.name}: ${stackIssues}. Keep PUSH/POP pairs and stack-changing exits inside one @ routine boundary, or split the code into explicit callable routines.`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return findings;
|
|
98
|
+
}
|
|
99
|
+
export function unknownBoundaryFindings(directBoundaries, knownRoutines) {
|
|
100
|
+
return directBoundaries
|
|
101
|
+
.filter((boundary) => !knownRoutines.has(boundary.target))
|
|
102
|
+
.map((boundary) => ({
|
|
103
|
+
kind: 'missing_callee_contract',
|
|
104
|
+
callTarget: boundary.target,
|
|
105
|
+
subject: boundary.subject,
|
|
106
|
+
file: boundary.file,
|
|
107
|
+
line: boundary.line,
|
|
108
|
+
column: boundary.column,
|
|
109
|
+
...(boundary.sourceUnit !== undefined ? { sourceUnit: boundary.sourceUnit } : {}),
|
|
110
|
+
...(boundary.sourceRelation !== undefined ? { sourceRelation: boundary.sourceRelation } : {}),
|
|
111
|
+
...(boundary.sourceUnitRelation !== undefined
|
|
112
|
+
? { sourceUnitRelation: boundary.sourceUnitRelation }
|
|
113
|
+
: {}),
|
|
114
|
+
message: `Register contracts cannot prove ${boundary.subject}; add a routine body or .asmi extern contract.`,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
export function diagnosticsForFindings(findings, mode) {
|
|
118
|
+
if (mode === 'audit')
|
|
119
|
+
return [];
|
|
120
|
+
return findings.map((finding) => ({
|
|
121
|
+
severity: mode === 'error' || mode === 'strict' ? 'error' : 'warning',
|
|
122
|
+
code: 'AZMN_REGISTER_CONTRACTS',
|
|
123
|
+
sourceName: finding.file,
|
|
124
|
+
line: finding.line,
|
|
125
|
+
column: finding.column,
|
|
126
|
+
message: finding.message,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
66
129
|
function strictStackIssueText(summary) {
|
|
67
130
|
const issues = [];
|
|
68
131
|
if (!summary.stackBalanced)
|
|
@@ -99,6 +162,10 @@ export function buildRegisterContractsReportModel(input) {
|
|
|
99
162
|
entryFile: input.entryFile,
|
|
100
163
|
mode: input.mode,
|
|
101
164
|
summaries: [...input.summaries, ...input.profileSummaries],
|
|
165
|
+
findings: [...input.findings],
|
|
166
|
+
...(input.suppressedFindings !== undefined && input.suppressedFindings.length > 0
|
|
167
|
+
? { suppressedFindings: [...input.suppressedFindings] }
|
|
168
|
+
: {}),
|
|
102
169
|
conflicts: [...input.conflicts],
|
|
103
170
|
outputCandidates: [...input.outputCandidates],
|
|
104
171
|
...(input.profile !== undefined ? { profile: input.profile } : {}),
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { Diagnostic } from '../model/diagnostic.js';
|
|
2
2
|
import type { SourceItem } from '../model/source-item.js';
|
|
3
|
-
import type { AnalyzeRegisterContractsOptions, RegisterContractsAnnotationFile, RegisterContractsOutputCandidate } from './types.js';
|
|
3
|
+
import type { AnalyzeRegisterContractsOptions, RegisterContractsFinding, RegisterContractsAnnotationFile, RegisterContractsJsonReportModel, RegisterContractsOutputCandidate } from './types.js';
|
|
4
|
+
import { buildRegisterContractsInference } from './report.js';
|
|
4
5
|
interface AnalyzeRegisterContractsResult {
|
|
5
6
|
diagnostics: Diagnostic[];
|
|
7
|
+
findings?: RegisterContractsFinding[];
|
|
6
8
|
outputCandidates?: RegisterContractsOutputCandidate[];
|
|
7
9
|
reportText?: string;
|
|
10
|
+
reportJson?: RegisterContractsJsonReportModel;
|
|
11
|
+
reportFormat?: 'text' | 'json';
|
|
8
12
|
interfaceText?: string;
|
|
13
|
+
inferenceText?: string;
|
|
14
|
+
inferenceJson?: ReturnType<typeof buildRegisterContractsInference>;
|
|
15
|
+
inferenceFormat?: 'json' | 'markdown';
|
|
9
16
|
annotations?: readonly RegisterContractsAnnotationFile[];
|
|
10
17
|
unknownCalls?: string[];
|
|
11
18
|
}
|