hledger-lsp 0.2.4 → 0.2.6
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/out/features/codeLens.d.ts +2 -5
- package/out/features/codeLens.d.ts.map +1 -1
- package/out/features/codeLens.js +2 -4
- package/out/features/codeLens.js.map +1 -1
- package/out/features/completion.d.ts +4 -10
- package/out/features/completion.d.ts.map +1 -1
- package/out/features/completion.js.map +1 -1
- package/out/features/formatter.d.ts +8 -32
- package/out/features/formatter.d.ts.map +1 -1
- package/out/features/formatter.js +81 -77
- package/out/features/formatter.js.map +1 -1
- package/out/features/formattingValidation.d.ts +53 -0
- package/out/features/formattingValidation.d.ts.map +1 -0
- package/out/features/formattingValidation.js +159 -0
- package/out/features/formattingValidation.js.map +1 -0
- package/out/features/inlayHints.d.ts +1 -9
- package/out/features/inlayHints.d.ts.map +1 -1
- package/out/features/inlayHints.js +7 -32
- package/out/features/inlayHints.js.map +1 -1
- package/out/features/validator.d.ts +13 -32
- package/out/features/validator.d.ts.map +1 -1
- package/out/features/validator.js +56 -2
- package/out/features/validator.js.map +1 -1
- package/out/parser/ast.d.ts.map +1 -1
- package/out/parser/ast.js +3 -1
- package/out/parser/ast.js.map +1 -1
- package/out/server/settings.d.ts +122 -50
- package/out/server/settings.d.ts.map +1 -1
- package/out/server/settings.js +12 -1
- package/out/server/settings.js.map +1 -1
- package/out/server.js +5 -13
- package/out/server.js.map +1 -1
- package/out/utils/amountFormatter.d.ts +10 -9
- package/out/utils/amountFormatter.d.ts.map +1 -1
- package/out/utils/amountFormatter.js +25 -21
- package/out/utils/amountFormatter.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting validation to prevent data corruption
|
|
3
|
+
*
|
|
4
|
+
* Pure validation functions that check if amounts are safe to format.
|
|
5
|
+
* These functions are used by:
|
|
6
|
+
* 1. Validator class - to generate diagnostics on document change
|
|
7
|
+
* 2. FormattingProvider - to decide whether to skip formatting
|
|
8
|
+
*/
|
|
9
|
+
import { Posting, ParsedDocument, Amount } from '../types';
|
|
10
|
+
import { FormattingOptions } from '../server/settings';
|
|
11
|
+
/**
|
|
12
|
+
* Check if a posting's amount is safe to format
|
|
13
|
+
*
|
|
14
|
+
* @param posting - The posting to validate
|
|
15
|
+
* @param parsedDoc - Full parsed document (for commodity formats)
|
|
16
|
+
* @param settings - Formatting settings
|
|
17
|
+
* @returns true if safe to format, false otherwise
|
|
18
|
+
*/
|
|
19
|
+
export declare function isSafeToFormat(posting: Posting, parsedDoc: ParsedDocument, settings?: Partial<FormattingOptions>): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Check if an amount's round-trip is safe
|
|
22
|
+
*
|
|
23
|
+
* Tests: parse → format → parse produces same value
|
|
24
|
+
*
|
|
25
|
+
* @param amount - The amount to validate
|
|
26
|
+
* @param parsedDoc - Full parsed document (for commodity formats)
|
|
27
|
+
* @param settings - Formatting settings
|
|
28
|
+
* @returns true if round-trip is safe, false otherwise
|
|
29
|
+
*/
|
|
30
|
+
export declare function isAmountRoundTripSafe(amount: Amount, parsedDoc: ParsedDocument, settings?: Partial<FormattingOptions>): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Check if an amount's format matches its declared commodity format
|
|
33
|
+
*
|
|
34
|
+
* @param amount - The amount to validate
|
|
35
|
+
* @param parsedDoc - Full parsed document (for commodity formats)
|
|
36
|
+
* @returns true if formats match (or no declared format), false otherwise
|
|
37
|
+
*/
|
|
38
|
+
export declare function isCommodityFormatMatch(amount: Amount, parsedDoc: ParsedDocument): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Get a descriptive reason why an amount is not safe to format
|
|
41
|
+
*
|
|
42
|
+
* This is used by the Validator to generate diagnostic messages
|
|
43
|
+
*
|
|
44
|
+
* @param amount - The amount to check
|
|
45
|
+
* @param parsedDoc - Full parsed document
|
|
46
|
+
* @param settings - Formatting settings
|
|
47
|
+
* @returns Diagnostic message describing the issue, or null if safe
|
|
48
|
+
*/
|
|
49
|
+
export declare function getFormatUnsafeReason(amount: Amount, parsedDoc: ParsedDocument, settings?: Partial<FormattingOptions>): {
|
|
50
|
+
code: string;
|
|
51
|
+
message: string;
|
|
52
|
+
} | null;
|
|
53
|
+
//# sourceMappingURL=formattingValidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formattingValidation.d.ts","sourceRoot":"","sources":["../../src/features/formattingValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAG3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,cAAc,EACzB,QAAQ,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACpC,OAAO,CAqBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,cAAc,EACzB,QAAQ,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACpC,OAAO,CA0BT;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,cAAc,GACxB,OAAO,CA4BT;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,cAAc,EACzB,QAAQ,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACpC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwD1C"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Formatting validation to prevent data corruption
|
|
4
|
+
*
|
|
5
|
+
* Pure validation functions that check if amounts are safe to format.
|
|
6
|
+
* These functions are used by:
|
|
7
|
+
* 1. Validator class - to generate diagnostics on document change
|
|
8
|
+
* 2. FormattingProvider - to decide whether to skip formatting
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.isSafeToFormat = isSafeToFormat;
|
|
12
|
+
exports.isAmountRoundTripSafe = isAmountRoundTripSafe;
|
|
13
|
+
exports.isCommodityFormatMatch = isCommodityFormatMatch;
|
|
14
|
+
exports.getFormatUnsafeReason = getFormatUnsafeReason;
|
|
15
|
+
const ast_1 = require("../parser/ast");
|
|
16
|
+
const amountFormatter_1 = require("../utils/amountFormatter");
|
|
17
|
+
/**
|
|
18
|
+
* Check if a posting's amount is safe to format
|
|
19
|
+
*
|
|
20
|
+
* @param posting - The posting to validate
|
|
21
|
+
* @param parsedDoc - Full parsed document (for commodity formats)
|
|
22
|
+
* @param settings - Formatting settings
|
|
23
|
+
* @returns true if safe to format, false otherwise
|
|
24
|
+
*/
|
|
25
|
+
function isSafeToFormat(posting, parsedDoc, settings) {
|
|
26
|
+
// Skip validation for inferred amounts - they're generated by us, so they're safe
|
|
27
|
+
if (posting.amount?.inferred) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
// No amount to validate
|
|
31
|
+
if (!posting.amount) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
// Run all validation checks
|
|
35
|
+
if (!isAmountRoundTripSafe(posting.amount, parsedDoc, settings)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (!isCommodityFormatMatch(posting.amount, parsedDoc)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if an amount's round-trip is safe
|
|
45
|
+
*
|
|
46
|
+
* Tests: parse → format → parse produces same value
|
|
47
|
+
*
|
|
48
|
+
* @param amount - The amount to validate
|
|
49
|
+
* @param parsedDoc - Full parsed document (for commodity formats)
|
|
50
|
+
* @param settings - Formatting settings
|
|
51
|
+
* @returns true if round-trip is safe, false otherwise
|
|
52
|
+
*/
|
|
53
|
+
function isAmountRoundTripSafe(amount, parsedDoc, settings) {
|
|
54
|
+
const commodity = amount.commodity || '';
|
|
55
|
+
// Step 1: Format the parsed amount
|
|
56
|
+
const formattedText = (0, amountFormatter_1.formatAmount)(amount.quantity, commodity, parsedDoc, settings);
|
|
57
|
+
// Step 2: Parse the formatted text back
|
|
58
|
+
const reparsedAmount = (0, ast_1.parseAmount)(formattedText);
|
|
59
|
+
// Step 3: Check if values match
|
|
60
|
+
if (!reparsedAmount) {
|
|
61
|
+
return false; // Cannot parse back
|
|
62
|
+
}
|
|
63
|
+
// Allow small floating point errors (< 0.005 to handle 2 decimal precision)
|
|
64
|
+
const quantityDifference = Math.abs(amount.quantity - reparsedAmount.quantity);
|
|
65
|
+
if (quantityDifference > 0.005) {
|
|
66
|
+
return false; // Value would change
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check if an amount's format matches its declared commodity format
|
|
72
|
+
*
|
|
73
|
+
* @param amount - The amount to validate
|
|
74
|
+
* @param parsedDoc - Full parsed document (for commodity formats)
|
|
75
|
+
* @returns true if formats match (or no declared format), false otherwise
|
|
76
|
+
*/
|
|
77
|
+
function isCommodityFormatMatch(amount, parsedDoc) {
|
|
78
|
+
if (!amount.commodity) {
|
|
79
|
+
return true; // No commodity to check
|
|
80
|
+
}
|
|
81
|
+
const commodity = parsedDoc.commodities.get(amount.commodity);
|
|
82
|
+
if (!commodity || !commodity.declared || !commodity.format) {
|
|
83
|
+
return true; // No declared format to check against
|
|
84
|
+
}
|
|
85
|
+
const amountFormat = amount.format;
|
|
86
|
+
const declaredFormat = commodity.format;
|
|
87
|
+
// Check if decimal marks match
|
|
88
|
+
if (amountFormat?.decimalMark && declaredFormat.decimalMark) {
|
|
89
|
+
if (amountFormat.decimalMark !== declaredFormat.decimalMark) {
|
|
90
|
+
return false; // Decimal mark mismatch
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Check if thousands separators match
|
|
94
|
+
if (amountFormat?.thousandsSeparator && declaredFormat.thousandsSeparator) {
|
|
95
|
+
if (amountFormat.thousandsSeparator !== declaredFormat.thousandsSeparator) {
|
|
96
|
+
return false; // Separator mismatch
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get a descriptive reason why an amount is not safe to format
|
|
103
|
+
*
|
|
104
|
+
* This is used by the Validator to generate diagnostic messages
|
|
105
|
+
*
|
|
106
|
+
* @param amount - The amount to check
|
|
107
|
+
* @param parsedDoc - Full parsed document
|
|
108
|
+
* @param settings - Formatting settings
|
|
109
|
+
* @returns Diagnostic message describing the issue, or null if safe
|
|
110
|
+
*/
|
|
111
|
+
function getFormatUnsafeReason(amount, parsedDoc, settings) {
|
|
112
|
+
const commodity = amount.commodity || '';
|
|
113
|
+
// Check round-trip
|
|
114
|
+
const formattedText = (0, amountFormatter_1.formatAmount)(amount.quantity, commodity, parsedDoc, settings);
|
|
115
|
+
const reparsedAmount = (0, ast_1.parseAmount)(formattedText);
|
|
116
|
+
if (!reparsedAmount) {
|
|
117
|
+
return {
|
|
118
|
+
code: 'format-roundtrip-failed',
|
|
119
|
+
message: `Cannot safely format amount: formatted value "${formattedText}" cannot be parsed back`
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const quantityDifference = Math.abs(amount.quantity - reparsedAmount.quantity);
|
|
123
|
+
if (quantityDifference > 0.005) {
|
|
124
|
+
return {
|
|
125
|
+
code: 'format-value-changed',
|
|
126
|
+
message: `Cannot safely format amount: value would change from ${amount.quantity} to ${reparsedAmount.quantity}. This may indicate a format mismatch (e.g., thousand separator vs decimal mark).`
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// Check commodity format match
|
|
130
|
+
if (!amount.commodity) {
|
|
131
|
+
return null; // No commodity to check
|
|
132
|
+
}
|
|
133
|
+
const commodityDef = parsedDoc.commodities.get(amount.commodity);
|
|
134
|
+
if (!commodityDef || !commodityDef.declared || !commodityDef.format) {
|
|
135
|
+
return null; // No declared format to check against
|
|
136
|
+
}
|
|
137
|
+
const amountFormat = amount.format;
|
|
138
|
+
const declaredFormat = commodityDef.format;
|
|
139
|
+
// Check decimal marks
|
|
140
|
+
if (amountFormat?.decimalMark && declaredFormat.decimalMark) {
|
|
141
|
+
if (amountFormat.decimalMark !== declaredFormat.decimalMark) {
|
|
142
|
+
return {
|
|
143
|
+
code: 'format-decimal-mismatch',
|
|
144
|
+
message: `Amount uses decimal mark "${amountFormat.decimalMark}" but commodity ${amount.commodity} is declared with "${declaredFormat.decimalMark}". This may cause value misinterpretation.`
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Check thousands separators
|
|
149
|
+
if (amountFormat?.thousandsSeparator && declaredFormat.thousandsSeparator) {
|
|
150
|
+
if (amountFormat.thousandsSeparator !== declaredFormat.thousandsSeparator) {
|
|
151
|
+
return {
|
|
152
|
+
code: 'format-separator-mismatch',
|
|
153
|
+
message: `Amount uses thousands separator "${amountFormat.thousandsSeparator}" but commodity ${amount.commodity} is declared with "${declaredFormat.thousandsSeparator}". This may cause formatting issues.`
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null; // Safe to format
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=formattingValidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formattingValidation.js","sourceRoot":"","sources":["../../src/features/formattingValidation.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,15 +9,7 @@
|
|
|
9
9
|
import { InlayHint, Range } from 'vscode-languageserver';
|
|
10
10
|
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
11
11
|
import { ParsedDocument } from '../types';
|
|
12
|
-
|
|
13
|
-
/** Show inferred amounts on postings without explicit amounts */
|
|
14
|
-
showInferredAmounts?: boolean;
|
|
15
|
-
/** Show running balance after each posting */
|
|
16
|
-
showRunningBalances?: boolean;
|
|
17
|
-
/** Show cost conversions (e.g., "= $135") */
|
|
18
|
-
showCostConversions?: boolean;
|
|
19
|
-
}
|
|
20
|
-
import { HledgerSettings } from '../server/settings';
|
|
12
|
+
import { type HledgerSettings } from '../server/settings';
|
|
21
13
|
export declare class InlayHintsProvider {
|
|
22
14
|
/**
|
|
23
15
|
* Provide inlay hints for a document
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inlayHints.d.ts","sourceRoot":"","sources":["../../src/features/inlayHints.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAA+C,KAAK,EAAW,MAAM,uBAAuB,CAAC;AAC/G,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAElE,OAAO,EAAE,cAAc,EAAgC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"inlayHints.d.ts","sourceRoot":"","sources":["../../src/features/inlayHints.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAA+C,KAAK,EAAW,MAAM,uBAAuB,CAAC;AAC/G,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAElE,OAAO,EAAE,cAAc,EAAgC,MAAM,UAAU,CAAC;AAIxE,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,kBAAkB;IAC7B;;OAEG;IACH,iBAAiB,CACf,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,cAAc,EACtB,QAAQ,CAAC,EAAE,eAAe,GACzB,SAAS,EAAE;IA6Cd;;OAEG;IACH,OAAO,CAAC,4CAA4C;IA4BpD;;KAEC;IACD,OAAO,CAAC,uCAAuC;IAkB/C;;KAEC;IACD,OAAO,CAAC,kCAAkC;IAiB1C;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAmF9B;;OAEG;IACH,OAAO,CAAC,+BAA+B;IA6FvC;;OAEG;IACH,OAAO,CAAC,sBAAsB;CAoE/B;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
|
|
@@ -13,17 +13,13 @@ const vscode_languageserver_1 = require("vscode-languageserver");
|
|
|
13
13
|
const vscode_uri_1 = require("vscode-uri");
|
|
14
14
|
const amountFormatter_1 = require("../utils/amountFormatter");
|
|
15
15
|
const runningBalanceCalculator_1 = require("../utils/runningBalanceCalculator");
|
|
16
|
-
const
|
|
17
|
-
showInferredAmounts: false,
|
|
18
|
-
showRunningBalances: false,
|
|
19
|
-
showCostConversions: false
|
|
20
|
-
};
|
|
16
|
+
const settings_1 = require("../server/settings");
|
|
21
17
|
class InlayHintsProvider {
|
|
22
18
|
/**
|
|
23
19
|
* Provide inlay hints for a document
|
|
24
20
|
*/
|
|
25
21
|
provideInlayHints(document, range, parsed, settings) {
|
|
26
|
-
const config = { ...
|
|
22
|
+
const config = { ...settings_1.DEFAULT_INLAY_HINTS_OPTIONS, ...settings?.inlayHints };
|
|
27
23
|
const hints = [];
|
|
28
24
|
// Normalize document URI to ensure proper encoding
|
|
29
25
|
const documentUri = vscode_uri_1.URI.parse(document.uri).toString();
|
|
@@ -63,21 +59,14 @@ class InlayHintsProvider {
|
|
|
63
59
|
*/
|
|
64
60
|
calculateInferredAmountHintInsertionPosition(line, accountEnd, amount, parsed, settings) {
|
|
65
61
|
const options = {
|
|
66
|
-
|
|
67
|
-
maxAccountWidth: 42,
|
|
68
|
-
maxCommodityWidth: 4,
|
|
69
|
-
maxAmountWidth: 12,
|
|
70
|
-
minSpacing: 2,
|
|
71
|
-
decimalAlignColumn: 52,
|
|
72
|
-
assertionDecimalAlignColumn: 70,
|
|
73
|
-
signPosition: 'after-symbol',
|
|
62
|
+
...settings_1.DEFAULT_FORMATTING_OPTIONS,
|
|
74
63
|
...settings?.formatting
|
|
75
64
|
};
|
|
76
65
|
// Get amount layout to determine pre-decimal width
|
|
77
|
-
const layout = (0, amountFormatter_1.getAmountLayout)(amount, parsed, options);
|
|
66
|
+
const layout = (0, amountFormatter_1.getAmountLayout)(amount, parsed, options, '');
|
|
78
67
|
const preDecimalWidth = layout.commodityBefore.length +
|
|
79
68
|
(layout.spaceBetweenCommodityAndAmount && layout.commodityBefore ? 1 : 0) +
|
|
80
|
-
(layout.
|
|
69
|
+
(layout.negPosSign ? 1 : 0) +
|
|
81
70
|
layout.amountIntegerString.length;
|
|
82
71
|
// Calculate the target position for the start of the amount (before the decimal)
|
|
83
72
|
const targetColumn = Math.max(options.decimalAlignColumn, accountEnd + options.minSpacing + preDecimalWidth);
|
|
@@ -89,14 +78,7 @@ class InlayHintsProvider {
|
|
|
89
78
|
*/
|
|
90
79
|
calculateAssertionHintInsertionPosition(line, accountEnd, amount, parsed, settings) {
|
|
91
80
|
const options = {
|
|
92
|
-
|
|
93
|
-
maxAccountWidth: 42,
|
|
94
|
-
maxCommodityWidth: 4,
|
|
95
|
-
maxAmountWidth: 12,
|
|
96
|
-
minSpacing: 2,
|
|
97
|
-
decimalAlignColumn: 52,
|
|
98
|
-
assertionDecimalAlignColumn: 70,
|
|
99
|
-
signPosition: 'after-symbol',
|
|
81
|
+
...settings_1.DEFAULT_FORMATTING_OPTIONS,
|
|
100
82
|
...settings?.formatting
|
|
101
83
|
};
|
|
102
84
|
// TODO implement proper calculation for assertion hint position
|
|
@@ -107,14 +89,7 @@ class InlayHintsProvider {
|
|
|
107
89
|
*/
|
|
108
90
|
calculateCostHintInsertionPosition(line, accountEnd, amount, parsed, settings) {
|
|
109
91
|
const options = {
|
|
110
|
-
|
|
111
|
-
maxAccountWidth: 42,
|
|
112
|
-
maxCommodityWidth: 4,
|
|
113
|
-
maxAmountWidth: 12,
|
|
114
|
-
minSpacing: 2,
|
|
115
|
-
decimalAlignColumn: 52,
|
|
116
|
-
assertionDecimalAlignColumn: 70,
|
|
117
|
-
signPosition: 'after-symbol',
|
|
92
|
+
...settings_1.DEFAULT_FORMATTING_OPTIONS,
|
|
118
93
|
...settings?.formatting
|
|
119
94
|
};
|
|
120
95
|
// TODO implement proper calculation for assertion hint position
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inlayHints.js","sourceRoot":"","sources":["../../src/features/inlayHints.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,iEAA+G;AAE/G,2CAAiC;AAEjC,
|
|
1
|
+
{"version":3,"file":"inlayHints.js","sourceRoot":"","sources":["../../src/features/inlayHints.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,iEAA+G;AAE/G,2CAAiC;AAEjC,8DAAyE;AAEzE,gFAAgG;AAChG,iDAM4B;AAE5B,MAAa,kBAAkB;IAC7B;;OAEG;IACH,iBAAiB,CACf,QAAsB,EACtB,KAAY,EACZ,MAAsB,EACtB,QAA0B;QAE1B,MAAM,MAAM,GAAG,EAAE,GAAG,sCAA2B,EAAE,GAAG,QAAQ,EAAE,UAAU,EAAE,CAAC;QAC3E,MAAM,KAAK,GAAgB,EAAE,CAAC;QAC9B,mDAAmD;QACnD,MAAM,WAAW,GAAG,gBAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;QAEvD,0FAA0F;QAC1F,kEAAkE;QAClE,MAAM,eAAe,GAAG,MAAM,CAAC,mBAAmB;YAChD,CAAC,CAAC,IAAA,mDAAwB,EAAC,MAAM,CAAC;YAClC,CAAC,CAAC,IAAI,GAAG,EAA4C,CAAC;QAExD,uDAAuD;QACvD,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YAC9C,iEAAiE;YACjE,IAAI,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,CAAC;gBACtD,SAAS;YACX,CAAC;YAED,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,IAAI,CAAC,CAAC;YAErC,sCAAsC;YACtC,IAAI,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBACzD,SAAS;YACX,CAAC;YAED,wBAAwB;YACxB,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;gBAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtF,CAAC;YAED,wBAAwB;YACxB,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;gBAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,+BAA+B,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC;YAChH,CAAC;YAED,wBAAwB;YACxB,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;gBAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtF,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,4CAA4C,CAClD,IAAY,EACZ,UAAkB,EAClB,MAAc,EACd,MAAsB,EACtB,QAA0B;QAE1B,MAAM,OAAO,GAAsB;YACjC,GAAG,qCAA0B;YAC7B,GAAG,QAAQ,EAAE,UAAU;SACxB,CAAC;QAEF,mDAAmD;QACnD,MAAM,MAAM,GAAG,IAAA,iCAAe,EAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5D,MAAM,eAAe,GACnB,MAAM,CAAC,eAAe,CAAC,MAAM;YAC7B,CAAC,MAAM,CAAC,8BAA8B,IAAI,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC;QAEpC,iFAAiF;QACjF,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,eAAe,CAAC,CAAC;QAC7G,MAAM,iBAAiB,GAAG,YAAY,GAAG,eAAe,CAAC;QAEzD,OAAO,iBAAiB,CAAA;IAE1B,CAAC;IAED;;KAEC;IACO,uCAAuC,CAC7C,IAAY,EACZ,UAAkB,EAClB,MAAc,EACd,MAAsB,EACtB,QAA0B;QAE1B,MAAM,OAAO,GAAsB;YACjC,GAAG,qCAA0B;YAC7B,GAAG,QAAQ,EAAE,UAAU;SACxB,CAAC;QAEF,gEAAgE;QAEhE,OAAO,OAAO,CAAC,kBAAkB,GAAG,CAAC,CAAC,CAAC,eAAe;IAExD,CAAC;IAED;;KAEC;IACO,kCAAkC,CACxC,IAAY,EACZ,UAAkB,EAClB,MAAc,EACd,MAAsB,EACtB,QAA0B;QAE1B,MAAM,OAAO,GAAsB;YACjC,GAAG,qCAA0B;YAC7B,GAAG,QAAQ,EAAE,UAAU;SACxB,CAAC;QAEF,gEAAgE;QAEhE,OAAO,OAAO,CAAC,kBAAkB,GAAG,CAAC,CAAC;IAExC,CAAC;IACD;;OAEG;IACK,sBAAsB,CAAC,QAAsB,EAAE,WAAwB,EAAE,MAAsB,EAAE,QAA0B;QACjI,MAAM,KAAK,GAAgB,EAAE,CAAC;QAE9B,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,IAAI,CAAC,CAAC;QACrC,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC3C,sCAAsC;YACtC,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC9C,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC,CAAE,oCAAoC;gBAChF,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC;oBAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE;oBACtC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,gBAAgB,EAAE;iBAC3D,CAAC,CAAC;gBAEH,2BAA2B;gBAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;gBAE1E,wEAAwE;gBACxE,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;gBAChD,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC/C,MAAM,aAAa,GAAG,UAAU,IAAI,CAAC;oBACnC,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC;oBACvC,CAAC,CAAC,YAAY,CAAC;gBAEjB,MAAM,sBAAsB,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;gBAE/D,wEAAwE;gBACxE,oFAAoF;gBACpF,IAAI,sBAAsB,EAAE,CAAC;oBAC3B,YAAY,EAAE,CAAC;oBACf,SAAS;gBACX,CAAC;gBAED,qDAAqD;gBACrD,MAAM,cAAc,GAAG,IAAI,CAAC,4CAA4C,CACtE,IAAI,EACJ,UAAU,EACV,OAAO,CAAC,MAAM,EACd,MAAM,EACN,QAAQ,CACT,CAAC;gBAIF,mEAAmE;gBACnE,MAAM,UAAU,GAAG,IAAA,8BAAY,EAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,EACvB,OAAO,CAAC,MAAM,CAAC,SAAS,EACxB,MAAM,EACN,QAAQ,EAAE,UAAU,CACrB,CAAC;gBAEF,gEAAgE;gBAChE,MAAM,SAAS,GAAuB;oBACpC,KAAK,EAAE,GAAG,UAAU,EAAE;oBACtB,OAAO,EAAE;wBACP,KAAK,EAAE,wBAAwB;wBAC/B,OAAO,EAAE,8BAA8B;wBACvC,SAAS,EAAE;4BACT,QAAQ,CAAC,GAAG;4BACZ,OAAO;4BACP,UAAU;4BACV,OAAO,CAAC,MAAM,CAAC,QAAQ;4BACvB,OAAO,CAAC,MAAM,CAAC,SAAS;yBACzB;qBACF;iBACF,CAAC;gBAEF,KAAK,CAAC,IAAI,CAAC;oBACT,QAAQ,EAAE,gCAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC;oBAClD,KAAK,EAAE,CAAC,SAAS,CAAC;oBAClB,IAAI,EAAE,qCAAa,CAAC,SAAS;oBAC7B,WAAW,EAAE,KAAK,EAAG,8BAA8B;oBACnD,OAAO,EAAE,wDAAwD;iBAClE,CAAC,CAAC;YACL,CAAC;YACD,YAAY,EAAE,CAAC;QACjB,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,+BAA+B,CACrC,QAAsB,EACtB,WAAwB,EACxB,MAAsB,EACtB,eAA8D,EAC9D,QAA0B;QAE1B,MAAM,KAAK,GAAgB,EAAE,CAAC;QAE9B,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACzD,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;YACnB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,eAAe,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,IAAI,CAAC,CAAC;QAErC,KAAK,IAAI,YAAY,GAAG,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;YACtF,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YACnD,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAErD,6EAA6E;YAC7E,mDAAmD;YACnD,IAAI,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBACrC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC;gBAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC;oBAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE;oBACtC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,gBAAgB,EAAE;iBAC3D,CAAC,CAAC;gBAEH,sDAAsD;gBACtD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACvC,MAAM,aAAa,GAAG,UAAU,IAAI,CAAC;oBACnC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC;oBAC/B,CAAC,CAAC,IAAI,CAAC;gBAET,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC;gBAC5C,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC;gBAEtC,iFAAiF;gBACjF,MAAM,YAAY,GAAG,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;gBACzD,MAAM,iBAAiB,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;gBAE3D,MAAM,cAAc,GAAG,IAAI,CAAC,uCAAuC,CACjE,IAAI,EACJ,UAAU,EACV,OAAO,CAAC,MAAO,EACf,MAAM,EACN,QAAQ,CACT,CAAC;gBACF,iDAAiD;gBACjD,MAAM,YAAY,GAAa,EAAE,CAAC;gBAClC,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;oBACxD,MAAM,gBAAgB,GAAG,IAAA,8BAAY,EAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;oBACxF,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBACtC,CAAC;gBAED,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAE5C,uEAAuE;gBACvE,0DAA0D;gBAC1D,MAAM,SAAS,GAAuB;oBACpC,KAAK,EAAE,MAAM,WAAW,GAAG;oBAC3B,OAAO,EAAE;wBACP,KAAK,EAAE,0BAA0B;wBACjC,OAAO,EAAE,gCAAgC;wBACzC,SAAS,EAAE;4BACT,QAAQ,CAAC,GAAG;4BACZ,OAAO;4BACP,OAAO,CAAC,OAAO;4BACf,YAAY;yBACb;qBACF;iBACF,CAAC;gBAEF,KAAK,CAAC,IAAI,CAAC;oBACT,QAAQ,EAAE,gCAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC;oBAClD,KAAK,EAAE,CAAC,SAAS,CAAC;oBAClB,IAAI,EAAE,qCAAa,CAAC,IAAI;oBACxB,WAAW,EAAE,KAAK,EAAG,iBAAiB;oBACtC,OAAO,EAAE,yCAAyC,OAAO,CAAC,OAAO,EAAE;iBACpE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,QAAsB,EAAE,WAAwB,EAAE,MAAsB,EAAE,QAA0B;QACjI,MAAM,KAAK,GAAgB,EAAE,CAAC;QAE9B,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,IAAI,CAAC,CAAC;QACrC,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC3C,6CAA6C;YAC7C,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAE1C,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC;gBAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC;oBAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE;oBACtC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,gBAAgB,EAAE;iBAC3D,CAAC,CAAC;gBAEH,2BAA2B;gBAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;gBAE1E,MAAM,cAAc,GAAG,IAAI,CAAC,kCAAkC,CAC5D,IAAI,EACJ,UAAU,EACV,OAAO,CAAC,IAAI,CAAC,MAAM,EACnB,MAAM,EACN,QAAQ,CACT,CAAC;gBAIF,mEAAmE;gBACnE,MAAM,UAAU,GAAG,IAAA,8BAAY,EAC7B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAC7B,MAAM,EACN,QAAQ,EAAE,UAAU,CACrB,CAAC;gBAEF,gEAAgE;gBAChE,MAAM,SAAS,GAAuB;oBACpC,KAAK,EAAE,OAAO,UAAU,EAAE;oBAC1B,OAAO,EAAE;wBACP,KAAK,EAAE,sBAAsB;wBAC7B,OAAO,EAAE,oBAAoB;wBAC7B,SAAS,EAAE;4BACT,QAAQ,CAAC,GAAG;4BACZ,OAAO;4BACP,UAAU;4BACV,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ;4BAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS;yBAC9B;qBACF;iBACF,CAAC;gBAEF,KAAK,CAAC,IAAI,CAAC;oBACT,QAAQ,EAAE,gCAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC;oBAClD,KAAK,EAAE,CAAC,SAAS,CAAC;oBAClB,IAAI,EAAE,qCAAa,CAAC,SAAS;oBAC7B,WAAW,EAAE,KAAK,EAAG,8BAA8B;oBACnD,OAAO,EAAE,sDAAsD;iBAChE,CAAC,CAAC;YAGL,CAAC;YACD,YAAY,EAAE,CAAC;QACjB,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AA3XD,gDA2XC;AAEY,QAAA,kBAAkB,GAAG,IAAI,kBAAkB,EAAE,CAAC"}
|
|
@@ -11,41 +11,14 @@ import { Diagnostic } from 'vscode-languageserver/node';
|
|
|
11
11
|
import { URI } from 'vscode-uri';
|
|
12
12
|
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
13
13
|
import { ParsedDocument, FileReader } from '../types';
|
|
14
|
+
import { ValidationOptions, SeverityOptions } from '../server/settings';
|
|
14
15
|
export interface ValidationResult {
|
|
15
16
|
diagnostics: Diagnostic[];
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
+
* Options for validator
|
|
19
20
|
*/
|
|
20
|
-
export interface
|
|
21
|
-
validation?: {
|
|
22
|
-
balance?: boolean;
|
|
23
|
-
missingAmounts?: boolean;
|
|
24
|
-
undeclaredAccounts?: boolean;
|
|
25
|
-
undeclaredPayees?: boolean;
|
|
26
|
-
undeclaredCommodities?: boolean;
|
|
27
|
-
undeclaredTags?: boolean;
|
|
28
|
-
dateOrdering?: boolean;
|
|
29
|
-
balanceAssertions?: boolean;
|
|
30
|
-
emptyTransactions?: boolean;
|
|
31
|
-
invalidDates?: boolean;
|
|
32
|
-
futureDates?: boolean;
|
|
33
|
-
emptyDescriptions?: boolean;
|
|
34
|
-
includeFiles?: boolean;
|
|
35
|
-
circularIncludes?: boolean;
|
|
36
|
-
markAllUndeclaredInstances?: boolean;
|
|
37
|
-
};
|
|
38
|
-
severity?: {
|
|
39
|
-
undeclaredAccounts?: 'error' | 'warning' | 'information' | 'hint';
|
|
40
|
-
undeclaredPayees?: 'error' | 'warning' | 'information' | 'hint';
|
|
41
|
-
undeclaredCommodities?: 'error' | 'warning' | 'information' | 'hint';
|
|
42
|
-
undeclaredTags?: 'error' | 'warning' | 'information' | 'hint';
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Options for validation
|
|
47
|
-
*/
|
|
48
|
-
export interface ValidationOptions {
|
|
21
|
+
export interface ValidatorOptions {
|
|
49
22
|
/**
|
|
50
23
|
* Base URI for resolving include paths
|
|
51
24
|
*/
|
|
@@ -57,13 +30,16 @@ export interface ValidationOptions {
|
|
|
57
30
|
/**
|
|
58
31
|
* Validation settings from user configuration
|
|
59
32
|
*/
|
|
60
|
-
settings?:
|
|
33
|
+
settings?: {
|
|
34
|
+
validation?: Partial<ValidationOptions>;
|
|
35
|
+
severity?: Partial<SeverityOptions>;
|
|
36
|
+
};
|
|
61
37
|
}
|
|
62
38
|
export declare class Validator {
|
|
63
39
|
/**
|
|
64
40
|
* Validate a parsed hledger document
|
|
65
41
|
*/
|
|
66
|
-
validate(document: TextDocument, parsedDoc: ParsedDocument, options?:
|
|
42
|
+
validate(document: TextDocument, parsedDoc: ParsedDocument, options?: ValidatorOptions): ValidationResult;
|
|
67
43
|
/**
|
|
68
44
|
* Validate transaction balance
|
|
69
45
|
* Transactions must balance (all amounts sum to zero per commodity)
|
|
@@ -130,6 +106,11 @@ export declare class Validator {
|
|
|
130
106
|
* Check for missing files and circular includes
|
|
131
107
|
*/
|
|
132
108
|
private validateIncludeDirectives;
|
|
109
|
+
/**
|
|
110
|
+
* Validate format mismatches
|
|
111
|
+
* Check if amounts have format issues that would cause data corruption during formatting
|
|
112
|
+
*/
|
|
113
|
+
private validateFormatMismatch;
|
|
133
114
|
/**
|
|
134
115
|
* Check if a circular include exists by recursively following includes
|
|
135
116
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/features/validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAsB,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/features/validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAsB,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;AAE5E,OAAO,EAAmB,iBAAiB,EAAE,eAAe,EAAsC,MAAM,oBAAoB,CAAC;AAM7H,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,OAAO,CAAC,EAAE,GAAG,CAAC;IAEd;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB;;OAEG;IACH,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACxC,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;KACrC,CAAC;CACH;AAED,qBAAa,SAAS;IACpB;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,gBAAgB;IAwGzG;;;OAGG;IACH,OAAO,CAAC,eAAe;IAoCvB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAiB9B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA0V/B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAsB3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA2B5B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IA8DjC;;OAEG;IACH,OAAO,CAAC,SAAS;IAOjB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiCxB;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAgBhC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA2E1B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAwB1B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAgBhC;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAqHjC;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA4D9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAoC7B;AAED,eAAO,MAAM,SAAS,WAAkB,CAAC"}
|
|
@@ -17,6 +17,7 @@ const settings_1 = require("../server/settings");
|
|
|
17
17
|
const balanceCalculator_1 = require("../utils/balanceCalculator");
|
|
18
18
|
const amountFormatter_1 = require("../utils/amountFormatter");
|
|
19
19
|
const runningBalanceCalculator_1 = require("../utils/runningBalanceCalculator");
|
|
20
|
+
const formattingValidation_1 = require("./formattingValidation");
|
|
20
21
|
class Validator {
|
|
21
22
|
/**
|
|
22
23
|
* Validate a parsed hledger document
|
|
@@ -35,7 +36,7 @@ class Validator {
|
|
|
35
36
|
return settings.validation[key] === true;
|
|
36
37
|
}
|
|
37
38
|
// Otherwise use defaults
|
|
38
|
-
return settings_1.defaultSettings.validation
|
|
39
|
+
return settings_1.defaultSettings.validation[key];
|
|
39
40
|
};
|
|
40
41
|
// Validate each transaction
|
|
41
42
|
for (const transaction of parsedDoc.transactions) {
|
|
@@ -74,6 +75,11 @@ class Validator {
|
|
|
74
75
|
const emptyDescIssues = this.validateEmptyDescription(transaction, document);
|
|
75
76
|
diagnostics.push(...emptyDescIssues);
|
|
76
77
|
}
|
|
78
|
+
// Check format mismatches
|
|
79
|
+
if (isEnabled('formatMismatch')) {
|
|
80
|
+
const formatIssues = this.validateFormatMismatch(transaction, document, parsedDoc, settings);
|
|
81
|
+
diagnostics.push(...formatIssues);
|
|
82
|
+
}
|
|
77
83
|
}
|
|
78
84
|
// Check for undeclared items (each type can be enabled/disabled separately)
|
|
79
85
|
const undeclaredIssues = this.validateUndeclaredItems(document, parsedDoc, settings, isEnabled('undeclaredAccounts'), isEnabled('undeclaredPayees'), isEnabled('undeclaredCommodities'), isEnabled('undeclaredTags'));
|
|
@@ -166,7 +172,7 @@ class Validator {
|
|
|
166
172
|
}
|
|
167
173
|
};
|
|
168
174
|
// Check if we should mark all instances or just the first one
|
|
169
|
-
const markAllInstances = settings?.validation?.markAllUndeclaredInstances ?? settings_1.defaultSettings.validation
|
|
175
|
+
const markAllInstances = settings?.validation?.markAllUndeclaredInstances ?? settings_1.defaultSettings.validation.markAllUndeclaredInstances;
|
|
170
176
|
// Check undeclared accounts (if enabled)
|
|
171
177
|
if (checkAccounts) {
|
|
172
178
|
const undeclaredAccounts = new Set(Array.from(parsedDoc.accounts.values()).filter(a => !a.declared).map(a => a.name));
|
|
@@ -834,6 +840,54 @@ class Validator {
|
|
|
834
840
|
}
|
|
835
841
|
return diagnostics;
|
|
836
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* Validate format mismatches
|
|
845
|
+
* Check if amounts have format issues that would cause data corruption during formatting
|
|
846
|
+
*/
|
|
847
|
+
validateFormatMismatch(transaction, document, parsedDoc, settings) {
|
|
848
|
+
const diagnostics = [];
|
|
849
|
+
if (transaction.line === undefined) {
|
|
850
|
+
return diagnostics; // Can't create diagnostics without line numbers
|
|
851
|
+
}
|
|
852
|
+
const text = document.getText();
|
|
853
|
+
const lines = text.split('\n');
|
|
854
|
+
// Check each posting's amount for format mismatches
|
|
855
|
+
let postingLineOffset = 1;
|
|
856
|
+
for (const posting of transaction.postings) {
|
|
857
|
+
// Skip inferred amounts - they're safe by design
|
|
858
|
+
if (posting.amount?.inferred) {
|
|
859
|
+
postingLineOffset++;
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
// Skip postings without amounts
|
|
863
|
+
if (!posting.amount) {
|
|
864
|
+
postingLineOffset++;
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
// Get formatting settings (fall back to defaults)
|
|
868
|
+
const formattingSettings = settings?.formatting ? settings.formatting : settings_1.defaultSettings.formatting;
|
|
869
|
+
// Check if this amount has format issues
|
|
870
|
+
const unsafeReason = (0, formattingValidation_1.getFormatUnsafeReason)(posting.amount, parsedDoc, formattingSettings);
|
|
871
|
+
if (unsafeReason) {
|
|
872
|
+
const postingLine = transaction.line + postingLineOffset;
|
|
873
|
+
if (postingLine < lines.length) {
|
|
874
|
+
const line = lines[postingLine];
|
|
875
|
+
diagnostics.push({
|
|
876
|
+
severity: node_1.DiagnosticSeverity.Warning,
|
|
877
|
+
range: {
|
|
878
|
+
start: { line: postingLine, character: 0 },
|
|
879
|
+
end: { line: postingLine, character: line.length }
|
|
880
|
+
},
|
|
881
|
+
message: unsafeReason.message,
|
|
882
|
+
source: 'hledger-formatter',
|
|
883
|
+
code: unsafeReason.code
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
postingLineOffset++;
|
|
888
|
+
}
|
|
889
|
+
return diagnostics;
|
|
890
|
+
}
|
|
837
891
|
/**
|
|
838
892
|
* Check if a circular include exists by recursively following includes
|
|
839
893
|
*/
|