@kalbi/zeicheck 0.1.0

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.
@@ -0,0 +1,994 @@
1
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
+
3
+ // src/models/types.ts
4
+ function yen(n) {
5
+ return Math.trunc(n);
6
+ }
7
+ var FormType = /* @__PURE__ */ ((FormType3) => {
8
+ FormType3["ABA"] = "ABA";
9
+ FormType3["ABB"] = "ABB";
10
+ FormType3["VCA"] = "VCA";
11
+ return FormType3;
12
+ })(FormType || {});
13
+
14
+ // src/parser/xtx-reader.ts
15
+ import { readFile } from "fs/promises";
16
+ import { XMLParser } from "fast-xml-parser";
17
+ var parser = new XMLParser({
18
+ ignoreAttributes: false,
19
+ attributeNamePrefix: "@_",
20
+ isArray: (_name, jpath) => {
21
+ return jpath === "DataRoot.FormData" || /\.FormData\.Field$/.test(jpath);
22
+ }
23
+ });
24
+ function parseXml(xml) {
25
+ const result = parser.parse(xml);
26
+ const root = result.DataRoot;
27
+ if (!root) {
28
+ throw new Error("Invalid xtx: missing DataRoot element");
29
+ }
30
+ const formDataArray = root.FormData ?? [];
31
+ const forms = formDataArray.map((fd) => {
32
+ const fields = /* @__PURE__ */ new Map();
33
+ const xmlFields = fd.Field ?? [];
34
+ for (const field of xmlFields) {
35
+ const value = field["#text"] != null ? String(field["#text"]) : "";
36
+ fields.set(field["@_id"], value);
37
+ }
38
+ return {
39
+ formType: fd["@_id"],
40
+ fields
41
+ };
42
+ });
43
+ return { forms, rawXml: xml };
44
+ }
45
+ function readXtxString(xml) {
46
+ return parseXml(xml);
47
+ }
48
+ async function readXtxFile(filePath) {
49
+ const xml = await readFile(filePath, "utf-8");
50
+ return parseXml(xml);
51
+ }
52
+
53
+ // src/parser/form-detector.ts
54
+ var knownForms = /* @__PURE__ */ new Map([
55
+ ["ABA", "ABA" /* ABA */],
56
+ ["ABB", "ABB" /* ABB */],
57
+ ["VCA", "VCA" /* VCA */]
58
+ ]);
59
+ function detectForms(parsed) {
60
+ const detected = [];
61
+ for (const form of parsed.forms) {
62
+ const formType = knownForms.get(form.formType);
63
+ if (formType !== void 0) {
64
+ detected.push(formType);
65
+ }
66
+ }
67
+ return detected;
68
+ }
69
+
70
+ // src/parser/normalizer.ts
71
+ function yenField(fields, code) {
72
+ const raw = fields.get(code);
73
+ return yen(raw ? Number(raw) : 0);
74
+ }
75
+ function accountBalance(fields, openingCode, closingCode) {
76
+ return {
77
+ opening: yenField(fields, openingCode),
78
+ closing: yenField(fields, closingCode)
79
+ };
80
+ }
81
+ function getFormFields(parsed, formType) {
82
+ const form = parsed.forms.find((f) => f.formType === formType);
83
+ return form?.fields ?? /* @__PURE__ */ new Map();
84
+ }
85
+ function buildIncomeStatement(vca) {
86
+ return {
87
+ revenue: yenField(vca, "ITA_VCA0010"),
88
+ cogs: {
89
+ openingInventory: yenField(vca, "ITA_VCA0020"),
90
+ purchases: yenField(vca, "ITA_VCA0030"),
91
+ closingInventory: yenField(vca, "ITA_VCA0040"),
92
+ total: yenField(vca, "ITA_VCA0050")
93
+ },
94
+ grossProfit: yenField(vca, "ITA_VCA0060"),
95
+ expenses: {
96
+ taxes: yenField(vca, "ITA_VCA0100"),
97
+ insurance: yenField(vca, "ITA_VCA0110"),
98
+ repairs: yenField(vca, "ITA_VCA0120"),
99
+ depreciation: yenField(vca, "ITA_VCA0130"),
100
+ welfare: yenField(vca, "ITA_VCA0140"),
101
+ salaries: yenField(vca, "ITA_VCA0150"),
102
+ outsourcing: yenField(vca, "ITA_VCA0160"),
103
+ interest: yenField(vca, "ITA_VCA0170"),
104
+ rent: yenField(vca, "ITA_VCA0180"),
105
+ retirement: yenField(vca, "ITA_VCA0190"),
106
+ utilities: yenField(vca, "ITA_VCA0200"),
107
+ travel: yenField(vca, "ITA_VCA0210"),
108
+ communication: yenField(vca, "ITA_VCA0220"),
109
+ advertising: yenField(vca, "ITA_VCA0230"),
110
+ entertainment: yenField(vca, "ITA_VCA0240"),
111
+ consumables: yenField(vca, "ITA_VCA0250"),
112
+ miscellaneous: yenField(vca, "ITA_VCA0260"),
113
+ otherExpenses: yenField(vca, "ITA_VCA0270")
114
+ },
115
+ totalExpenses: yenField(vca, "ITA_VCA0280"),
116
+ operatingIncome: yenField(vca, "ITA_VCA0290")
117
+ };
118
+ }
119
+ function buildBalanceSheet(vca) {
120
+ return {
121
+ // Assets
122
+ cash: accountBalance(vca, "ITA_VCA1010", "ITA_VCA1210"),
123
+ deposits: accountBalance(vca, "ITA_VCA1020", "ITA_VCA1220"),
124
+ accountsReceivable: accountBalance(vca, "ITA_VCA1030", "ITA_VCA1230"),
125
+ inventory: accountBalance(vca, "ITA_VCA1040", "ITA_VCA1240"),
126
+ otherCurrentAssets: accountBalance(vca, "ITA_VCA1050", "ITA_VCA1250"),
127
+ buildings: accountBalance(vca, "ITA_VCA1060", "ITA_VCA1260"),
128
+ buildingImprovements: accountBalance(vca, "ITA_VCA1070", "ITA_VCA1270"),
129
+ machinery: accountBalance(vca, "ITA_VCA1080", "ITA_VCA1280"),
130
+ vehicles: accountBalance(vca, "ITA_VCA1090", "ITA_VCA1290"),
131
+ tools: accountBalance(vca, "ITA_VCA1100", "ITA_VCA1300"),
132
+ land: accountBalance(vca, "ITA_VCA1110", "ITA_VCA1310"),
133
+ otherFixedAssets: accountBalance(vca, "ITA_VCA1120", "ITA_VCA1320"),
134
+ accumulatedDepreciation: accountBalance(vca, "ITA_VCA1130", "ITA_VCA1330"),
135
+ assetsTotal: accountBalance(vca, "ITA_VCA1140", "ITA_VCA1340"),
136
+ // Liabilities
137
+ accountsPayable: accountBalance(vca, "ITA_VCA1410", "ITA_VCA1510"),
138
+ borrowings: accountBalance(vca, "ITA_VCA1420", "ITA_VCA1520"),
139
+ otherCurrentLiabilities: accountBalance(vca, "ITA_VCA1430", "ITA_VCA1530"),
140
+ liabilitiesTotal: accountBalance(vca, "ITA_VCA1440", "ITA_VCA1540"),
141
+ // Equity
142
+ ownerEquity: accountBalance(vca, "ITA_VCA1610", "ITA_VCA1710"),
143
+ ownerDrawings: accountBalance(vca, "ITA_VCA1620", "ITA_VCA1720"),
144
+ ownerContributions: accountBalance(vca, "ITA_VCA1630", "ITA_VCA1730"),
145
+ retainedEarnings: yenField(vca, "ITA_VCA1640"),
146
+ equityTotal: accountBalance(vca, "ITA_VCA1650", "ITA_VCA1750")
147
+ };
148
+ }
149
+ function buildTaxFormA(aba) {
150
+ return {
151
+ businessIncome: yenField(aba, "ITA_ABA0010"),
152
+ realEstateIncome: yenField(aba, "ITA_ABA0020"),
153
+ otherIncome: yenField(aba, "ITA_ABA0030"),
154
+ businessProfit: yenField(aba, "ITA_ABA0110"),
155
+ realEstateProfit: yenField(aba, "ITA_ABA0120"),
156
+ totalIncome: yenField(aba, "ITA_ABA0130"),
157
+ totalDeductions: yenField(aba, "ITA_ABA0280"),
158
+ blueReturnDeduction: yenField(aba, "ITA_ABA0290"),
159
+ taxableIncome: yenField(aba, "ITA_ABA0310"),
160
+ incomeTax: yenField(aba, "ITA_ABA0320"),
161
+ taxDue: yenField(aba, "ITA_ABA0360")
162
+ };
163
+ }
164
+ function buildTaxFormB(abb) {
165
+ return {
166
+ incomeDetails: [
167
+ {
168
+ type: abb.get("ITA_ABB0010") ?? "",
169
+ payer: abb.get("ITA_ABB0020") ?? "",
170
+ amount: yenField(abb, "ITA_ABB0030"),
171
+ withheld: yenField(abb, "ITA_ABB0040")
172
+ }
173
+ ],
174
+ socialInsurance: yenField(abb, "ITA_ABB0110"),
175
+ smallBusinessMutualAid: yenField(abb, "ITA_ABB0120"),
176
+ lifeInsurance: yenField(abb, "ITA_ABB0130"),
177
+ earthquakeInsurance: yenField(abb, "ITA_ABB0140"),
178
+ spouseDeduction: yenField(abb, "ITA_ABB0210"),
179
+ dependentDeduction: yenField(abb, "ITA_ABB0220"),
180
+ basicDeduction: yenField(abb, "ITA_ABB0230")
181
+ };
182
+ }
183
+ function buildDefaultFiscalYear() {
184
+ return {
185
+ nengo: 5,
186
+ year: 2023,
187
+ startDate: "2023-01-01",
188
+ endDate: "2023-12-31"
189
+ };
190
+ }
191
+ function buildEmptyDepreciationSchedule() {
192
+ return {
193
+ assets: [],
194
+ totalDepreciation: yen(0),
195
+ totalBusinessDepreciation: yen(0)
196
+ };
197
+ }
198
+ function normalize(parsed) {
199
+ const vca = getFormFields(parsed, "VCA");
200
+ const aba = getFormFields(parsed, "ABA");
201
+ const abb = getFormFields(parsed, "ABB");
202
+ const formTypes = detectForms(parsed);
203
+ return {
204
+ fiscalYear: buildDefaultFiscalYear(),
205
+ incomeStatement: buildIncomeStatement(vca),
206
+ balanceSheet: buildBalanceSheet(vca),
207
+ taxFormA: buildTaxFormA(aba),
208
+ taxFormB: buildTaxFormB(abb),
209
+ depreciationSchedule: buildEmptyDepreciationSchedule(),
210
+ metadata: {
211
+ filePath: "",
212
+ formTypes
213
+ }
214
+ };
215
+ }
216
+
217
+ // src/parser/index.ts
218
+ async function parseXtxFile(filePath) {
219
+ const parsed = await readXtxFile(filePath);
220
+ const taxReturn = normalize(parsed);
221
+ return {
222
+ ...taxReturn,
223
+ metadata: { ...taxReturn.metadata, filePath }
224
+ };
225
+ }
226
+ function parseXtxString(xml) {
227
+ const parsed = readXtxString(xml);
228
+ return normalize(parsed);
229
+ }
230
+
231
+ // src/rules/rule-runner.ts
232
+ var severityOrder = {
233
+ error: 0,
234
+ warning: 1,
235
+ info: 2,
236
+ off: 3
237
+ };
238
+ function runRules(rules, ctx) {
239
+ const diagnostics = [];
240
+ for (const rule of rules) {
241
+ const configEntry = ctx.config.rules[rule.meta.id];
242
+ const severity = Array.isArray(configEntry) ? configEntry[0] : configEntry ?? rule.meta.severity;
243
+ if (severity === "off") continue;
244
+ const results = rule.check(ctx);
245
+ for (const diag of results) {
246
+ diagnostics.push({ ...diag, severity });
247
+ }
248
+ }
249
+ diagnostics.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
250
+ return diagnostics;
251
+ }
252
+
253
+ // src/utils/monetary.ts
254
+ function formatYen(a) {
255
+ return a.toLocaleString("ja-JP");
256
+ }
257
+
258
+ // src/rules/balance-sheet/bs-equation.ts
259
+ var bsEquationRule = {
260
+ meta: {
261
+ id: "balance-sheet/equation",
262
+ name: "Balance Sheet Equation",
263
+ description: "\u8CC7\u7523\u5408\u8A08 = \u8CA0\u50B5\u5408\u8A08 + \u8CC7\u672C\u5408\u8A08 \u3092\u691C\u8A3C\u3059\u308B",
264
+ severity: "error"
265
+ },
266
+ check(ctx) {
267
+ const bs = ctx.taxReturn.balanceSheet;
268
+ const diagnostics = [];
269
+ const closingAssets = bs.assetsTotal.closing;
270
+ const closingLiabilities = bs.liabilitiesTotal.closing;
271
+ const closingEquity = bs.equityTotal.closing;
272
+ if (closingAssets !== closingLiabilities + closingEquity) {
273
+ diagnostics.push({
274
+ ruleId: "balance-sheet/equation",
275
+ severity: "error",
276
+ message: `\u671F\u672B\u6B8B\u9AD8: \u8CC7\u7523\u5408\u8A08(${formatYen(closingAssets)}) \u2260 \u8CA0\u50B5\u5408\u8A08(${formatYen(closingLiabilities)}) + \u8CC7\u672C\u5408\u8A08(${formatYen(closingEquity)})`
277
+ });
278
+ }
279
+ const openingAssets = bs.assetsTotal.opening;
280
+ const openingLiabilities = bs.liabilitiesTotal.opening;
281
+ const openingEquity = bs.equityTotal.opening;
282
+ if (openingAssets !== openingLiabilities + openingEquity) {
283
+ diagnostics.push({
284
+ ruleId: "balance-sheet/equation",
285
+ severity: "error",
286
+ message: `\u671F\u9996\u6B8B\u9AD8: \u8CC7\u7523\u5408\u8A08(${formatYen(openingAssets)}) \u2260 \u8CA0\u50B5\u5408\u8A08(${formatYen(openingLiabilities)}) + \u8CC7\u672C\u5408\u8A08(${formatYen(openingEquity)})`
287
+ });
288
+ }
289
+ return diagnostics;
290
+ }
291
+ };
292
+
293
+ // src/rules/income-statement/pl-arithmetic-chain.ts
294
+ var plArithmeticChainRule = {
295
+ meta: {
296
+ id: "income-statement/pl-chain",
297
+ name: "P/L Arithmetic Chain",
298
+ description: "\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u8A08\u7B97\u9023\u9396\u3092\u691C\u8A3C\u3059\u308B",
299
+ severity: "error"
300
+ },
301
+ check(ctx) {
302
+ const pl = ctx.taxReturn.incomeStatement;
303
+ const diagnostics = [];
304
+ const expectedGross = pl.revenue - pl.cogs.total;
305
+ if (pl.grossProfit !== expectedGross) {
306
+ diagnostics.push({
307
+ ruleId: "income-statement/pl-chain",
308
+ severity: "error",
309
+ message: `\u58F2\u4E0A\u7DCF\u5229\u76CA(${formatYen(pl.grossProfit)}) \u2260 \u58F2\u4E0A(${formatYen(pl.revenue)}) - \u58F2\u4E0A\u539F\u4FA1(${formatYen(pl.cogs.total)})`
310
+ });
311
+ }
312
+ const expectedOperating = pl.grossProfit - pl.totalExpenses;
313
+ if (pl.operatingIncome !== expectedOperating) {
314
+ diagnostics.push({
315
+ ruleId: "income-statement/pl-chain",
316
+ severity: "error",
317
+ message: `\u6240\u5F97\u91D1\u984D(${formatYen(pl.operatingIncome)}) \u2260 \u58F2\u4E0A\u7DCF\u5229\u76CA(${formatYen(pl.grossProfit)}) - \u7D4C\u8CBB\u5408\u8A08(${formatYen(pl.totalExpenses)})`
318
+ });
319
+ }
320
+ return diagnostics;
321
+ }
322
+ };
323
+
324
+ // src/rules/income-statement/cogs-calculation.ts
325
+ var cogsCalculationRule = {
326
+ meta: {
327
+ id: "income-statement/cogs",
328
+ name: "COGS Calculation",
329
+ description: "\u58F2\u4E0A\u539F\u4FA1\u306E\u8A08\u7B97\u3092\u691C\u8A3C\u3059\u308B",
330
+ severity: "error"
331
+ },
332
+ check(ctx) {
333
+ const cogs = ctx.taxReturn.incomeStatement.cogs;
334
+ if (cogs.openingInventory === 0 && cogs.purchases === 0 && cogs.closingInventory === 0 && cogs.total === 0) {
335
+ return [];
336
+ }
337
+ const expected = cogs.openingInventory + cogs.purchases - cogs.closingInventory;
338
+ if (cogs.total !== expected) {
339
+ return [
340
+ {
341
+ ruleId: "income-statement/cogs",
342
+ severity: "error",
343
+ message: `\u58F2\u4E0A\u539F\u4FA1\u5408\u8A08(${formatYen(cogs.total)}) \u2260 \u671F\u9996\u68DA\u5378\u9AD8(${formatYen(cogs.openingInventory)}) + \u4ED5\u5165\u91D1\u984D(${formatYen(cogs.purchases)}) - \u671F\u672B\u68DA\u5378\u9AD8(${formatYen(cogs.closingInventory)})`
344
+ }
345
+ ];
346
+ }
347
+ return [];
348
+ }
349
+ };
350
+
351
+ // src/rules/income-statement/expense-total.ts
352
+ var expenseTotalRule = {
353
+ meta: {
354
+ id: "income-statement/expense-total",
355
+ name: "Expense Total",
356
+ description: "\u7D4C\u8CBB\u5408\u8A08\u304C\u5404\u7D4C\u8CBB\u9805\u76EE\u306E\u5408\u8A08\u3068\u4E00\u81F4\u3059\u308B\u304B\u691C\u8A3C\u3059\u308B",
357
+ severity: "error"
358
+ },
359
+ check(ctx) {
360
+ const exp = ctx.taxReturn.incomeStatement.expenses;
361
+ const computed = exp.salaries + exp.outsourcing + exp.retirement + exp.rent + exp.interest + exp.taxes + exp.insurance + exp.repairs + exp.consumables + exp.depreciation + exp.welfare + exp.utilities + exp.travel + exp.communication + exp.advertising + exp.entertainment + exp.miscellaneous + exp.otherExpenses;
362
+ const totalExpenses = ctx.taxReturn.incomeStatement.totalExpenses;
363
+ if (totalExpenses !== computed) {
364
+ return [
365
+ {
366
+ ruleId: "income-statement/expense-total",
367
+ severity: "error",
368
+ message: `\u7D4C\u8CBB\u5408\u8A08(${formatYen(totalExpenses)}) \u2260 \u5404\u7D4C\u8CBB\u9805\u76EE\u306E\u5408\u8A08(${formatYen(computed)})`
369
+ }
370
+ ];
371
+ }
372
+ return [];
373
+ }
374
+ };
375
+
376
+ // src/rules/cross-statement/bs-pl-bridge.ts
377
+ var bsPlBridgeRule = {
378
+ meta: {
379
+ id: "cross-statement/bs-pl-bridge",
380
+ name: "BS-PL Bridge",
381
+ description: "\u8CB8\u501F\u5BFE\u7167\u8868\u306E\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u524D\u306E\u6240\u5F97\u91D1\u984D\u3068\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u6240\u5F97\u91D1\u984D\u306E\u4E00\u81F4\u3092\u691C\u8A3C\u3059\u308B",
382
+ severity: "error"
383
+ },
384
+ check(ctx) {
385
+ const bsRetained = ctx.taxReturn.balanceSheet.retainedEarnings;
386
+ const plOperating = ctx.taxReturn.incomeStatement.operatingIncome;
387
+ if (bsRetained !== plOperating) {
388
+ return [
389
+ {
390
+ ruleId: "cross-statement/bs-pl-bridge",
391
+ severity: "error",
392
+ message: `\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u6240\u5F97\u91D1\u984D(${formatYen(plOperating)}) \u2260 \u8CB8\u501F\u5BFE\u7167\u8868\u306E\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u524D\u306E\u6240\u5F97\u91D1\u984D(${formatYen(bsRetained)})`
393
+ }
394
+ ];
395
+ }
396
+ return [];
397
+ }
398
+ };
399
+
400
+ // src/rules/balance-sheet/opening-owner-equity.ts
401
+ var openingOwnerEquityRule = {
402
+ meta: {
403
+ id: "balance-sheet/opening-owner-equity",
404
+ name: "\u4E8B\u696D\u4E3B\u8CB8\u501F \u671F\u9996\u6B8B\u9AD8\u30BC\u30ED",
405
+ description: "\u4E8B\u696D\u4E3B\u8CB8\u3068\u4E8B\u696D\u4E3B\u501F\u306F\u6BCE\u671F\u9996\u306B\u5143\u5165\u91D1\u3078\u632F\u66FF\u3055\u308C\u308B\u305F\u3081\u3001\u671F\u9996\u6B8B\u9AD8\u306F0\u5186\u3067\u3042\u308B\u3079\u304D\u3067\u3059\u3002",
406
+ severity: "error"
407
+ },
408
+ check(ctx) {
409
+ const diagnostics = [];
410
+ const bs = ctx.taxReturn.balanceSheet;
411
+ if (bs.ownerDrawings.opening !== 0) {
412
+ diagnostics.push({
413
+ ruleId: this.meta.id,
414
+ severity: this.meta.severity,
415
+ message: `\u4E8B\u696D\u4E3B\u8CB8\u306E\u671F\u9996\u6B8B\u9AD8\u304C0\u3067\u306F\u3042\u308A\u307E\u305B\u3093: ${formatYen(bs.ownerDrawings.opening)}`
416
+ });
417
+ }
418
+ if (bs.ownerContributions.opening !== 0) {
419
+ diagnostics.push({
420
+ ruleId: this.meta.id,
421
+ severity: this.meta.severity,
422
+ message: `\u4E8B\u696D\u4E3B\u501F\u306E\u671F\u9996\u6B8B\u9AD8\u304C0\u3067\u306F\u3042\u308A\u307E\u305B\u3093: ${formatYen(bs.ownerContributions.opening)}`
423
+ });
424
+ }
425
+ return diagnostics;
426
+ }
427
+ };
428
+
429
+ // src/rules/balance-sheet/motoire-kin-formula.ts
430
+ var motoireKinFormulaRule = {
431
+ meta: {
432
+ id: "balance-sheet/motoire-kin-formula",
433
+ name: "\u5143\u5165\u91D1\u7E70\u8D8A\u8A08\u7B97",
434
+ description: "\u5143\u5165\u91D1(\u5F53\u671F) = \u5143\u5165\u91D1(\u524D\u671F) + \u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u524D\u6240\u5F97(\u524D\u671F) + \u4E8B\u696D\u4E3B\u501F(\u524D\u671F\u672B) - \u4E8B\u696D\u4E3B\u8CB8(\u524D\u671F\u672B) \u3067\u3042\u308B\u3079\u304D\u3067\u3059\u3002\u524D\u5E74\u30C7\u30FC\u30BF\u304C\u5FC5\u8981\u3067\u3059\u3002",
435
+ severity: "error"
436
+ },
437
+ check(ctx) {
438
+ if (!ctx.priorYear) return [];
439
+ const priorBs = ctx.priorYear.balanceSheet;
440
+ const currentBs = ctx.taxReturn.balanceSheet;
441
+ const expected = yen(
442
+ priorBs.ownerEquity.opening + priorBs.retainedEarnings + priorBs.ownerContributions.closing - priorBs.ownerDrawings.closing
443
+ );
444
+ const actual = currentBs.ownerEquity.opening;
445
+ if (actual !== expected) {
446
+ return [
447
+ {
448
+ ruleId: this.meta.id,
449
+ severity: this.meta.severity,
450
+ message: `\u5143\u5165\u91D1\u306E\u671F\u9996\u6B8B\u9AD8(${formatYen(actual)}) \u2260 \u7E70\u8D8A\u8A08\u7B97\u984D(${formatYen(expected)})`,
451
+ details: `\u8A08\u7B97\u5F0F: \u5143\u5165\u91D1(\u524D\u671F\u9996)(${formatYen(priorBs.ownerEquity.opening)}) + \u6240\u5F97(\u524D\u671F)(${formatYen(priorBs.retainedEarnings)}) + \u4E8B\u696D\u4E3B\u501F(\u524D\u671F\u672B)(${formatYen(priorBs.ownerContributions.closing)}) - \u4E8B\u696D\u4E3B\u8CB8(\u524D\u671F\u672B)(${formatYen(priorBs.ownerDrawings.closing)})`
452
+ }
453
+ ];
454
+ }
455
+ return [];
456
+ }
457
+ };
458
+
459
+ // src/rules/balance-sheet/non-negative-cash.ts
460
+ var nonNegativeCashRule = {
461
+ meta: {
462
+ id: "balance-sheet/non-negative-cash",
463
+ name: "\u73FE\u91D1\u6B8B\u9AD8\u306E\u975E\u8CA0\u30C1\u30A7\u30C3\u30AF",
464
+ description: "\u73FE\u91D1\u6B8B\u9AD8\u306F0\u4EE5\u4E0A\u3067\u3042\u308B\u3079\u304D\u3067\u3059\u3002\u30DE\u30A4\u30CA\u30B9\u6B8B\u9AD8\u306F\u8A18\u5E33\u30DF\u30B9\u306E\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002",
465
+ severity: "warning"
466
+ },
467
+ check(ctx) {
468
+ const diagnostics = [];
469
+ const bs = ctx.taxReturn.balanceSheet;
470
+ if (bs.cash.opening < 0) {
471
+ diagnostics.push({
472
+ ruleId: this.meta.id,
473
+ severity: this.meta.severity,
474
+ message: `\u73FE\u91D1\u306E\u671F\u9996\u6B8B\u9AD8\u304C\u30DE\u30A4\u30CA\u30B9\u3067\u3059: ${formatYen(bs.cash.opening)}`
475
+ });
476
+ }
477
+ if (bs.cash.closing < 0) {
478
+ diagnostics.push({
479
+ ruleId: this.meta.id,
480
+ severity: this.meta.severity,
481
+ message: `\u73FE\u91D1\u306E\u671F\u672B\u6B8B\u9AD8\u304C\u30DE\u30A4\u30CA\u30B9\u3067\u3059: ${formatYen(bs.cash.closing)}`
482
+ });
483
+ }
484
+ return diagnostics;
485
+ }
486
+ };
487
+
488
+ // src/rules/deductions/blue-deduction-cap.ts
489
+ var blueDeductionCapRule = {
490
+ meta: {
491
+ id: "deductions/blue-deduction-cap",
492
+ name: "\u9752\u8272\u63A7\u9664\u4E0A\u9650\u30C1\u30A7\u30C3\u30AF",
493
+ description: "\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D\u306F\u3001\u63A7\u9664\u524D\u306E\u6240\u5F97\u91D1\u984D\u3092\u8D85\u3048\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002\u6240\u5F97\u3092\u8D85\u3048\u308B\u5834\u5408\u306F\u6240\u5F97\u91D1\u984D\u304C\u4E0A\u9650\u3068\u306A\u308A\u307E\u3059\u3002",
494
+ severity: "warning"
495
+ },
496
+ check(ctx) {
497
+ const deduction = ctx.taxReturn.taxFormA.blueReturnDeduction;
498
+ const income = ctx.taxReturn.incomeStatement.operatingIncome;
499
+ if (deduction > income) {
500
+ return [
501
+ {
502
+ ruleId: this.meta.id,
503
+ severity: this.meta.severity,
504
+ message: `\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D(${formatYen(deduction)}) > \u63A7\u9664\u524D\u6240\u5F97(${formatYen(income)})`,
505
+ details: "\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D\u306F\u63A7\u9664\u524D\u6240\u5F97\u91D1\u984D\u304C\u4E0A\u9650\u3067\u3059\u3002\u6240\u5F97\u304C\u5C11\u306A\u3044\u5834\u5408\u306F\u6240\u5F97\u91D1\u984D\u307E\u3067\u3057\u304B\u63A7\u9664\u3067\u304D\u307E\u305B\u3093\u3002"
506
+ }
507
+ ];
508
+ }
509
+ return [];
510
+ }
511
+ };
512
+
513
+ // src/rules/deductions/blue-deduction-eligibility.ts
514
+ var blueDeductionEligibilityRule = {
515
+ meta: {
516
+ id: "deductions/blue-deduction-eligibility",
517
+ name: "\u9752\u8272\u63A7\u966465\u4E07\u5186\u9069\u7528\u8981\u4EF6",
518
+ description: "65\u4E07\u5186\u306E\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u306B\u306Fe-Tax\u306B\u3088\u308B\u7533\u544A\u307E\u305F\u306F\u96FB\u5B50\u5E33\u7C3F\u4FDD\u5B58\u304C\u5FC5\u8981\u3067\u3059\uFF08\u4EE4\u548C2\u5E74\u5206\u4EE5\u964D\uFF09\u3002\u8981\u4EF6\u3092\u6E80\u305F\u3055\u306A\u3044\u5834\u5408\u306F55\u4E07\u5186\u304C\u4E0A\u9650\u3067\u3059\u3002",
519
+ severity: "info"
520
+ },
521
+ check(ctx) {
522
+ const deduction = ctx.taxReturn.taxFormA.blueReturnDeduction;
523
+ const limit55 = yen(55e4);
524
+ const limit65 = yen(65e4);
525
+ if (deduction > limit55 && deduction <= limit65) {
526
+ return [
527
+ {
528
+ ruleId: this.meta.id,
529
+ severity: this.meta.severity,
530
+ message: `\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D\u304C${formatYen(limit65)}\u3067\u3059\u3002e-Tax\u7533\u544A\u307E\u305F\u306F\u96FB\u5B50\u5E33\u7C3F\u4FDD\u5B58\u306E\u8981\u4EF6\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`,
531
+ details: "\u4EE4\u548C2\u5E74\u5206\u4EE5\u964D\u300165\u4E07\u5186\u63A7\u9664\u306B\u306Fe-Tax\u306B\u3088\u308B\u78BA\u5B9A\u7533\u544A\u306E\u9001\u4FE1\u3001\u307E\u305F\u306F\u96FB\u5B50\u5E33\u7C3F\u4FDD\u5B58\u6CD5\u306B\u57FA\u3065\u304F\u96FB\u5B50\u5E33\u7C3F\u306E\u5099\u4ED8\u3051\u304A\u3088\u3073\u4FDD\u5B58\u304C\u5FC5\u8981\u3067\u3059\u3002\u8981\u4EF6\u3092\u6E80\u305F\u3055\u306A\u3044\u5834\u5408\u306F55\u4E07\u5186\u304C\u4E0A\u9650\u3068\u306A\u308A\u307E\u3059\u3002"
532
+ }
533
+ ];
534
+ }
535
+ return [];
536
+ }
537
+ };
538
+
539
+ // src/rules/depreciation/useful-life-rates.ts
540
+ var COMMON_USEFUL_LIVES = {
541
+ \u30D1\u30BD\u30B3\u30F3: [4],
542
+ \u30B5\u30FC\u30D0\u30FC: [5],
543
+ \u666E\u901A\u81EA\u52D5\u8ECA: [6],
544
+ \u8EFD\u81EA\u52D5\u8ECA: [4],
545
+ \u6728\u9020\u5EFA\u7269: [22],
546
+ \u9244\u7B4B\u30B3\u30F3\u30AF\u30EA\u30FC\u30C8\u5EFA\u7269: [47],
547
+ \u91D1\u5C5E\u88FD\u5BB6\u5177: [15]
548
+ };
549
+ var usefulLifeRatesRule = {
550
+ meta: {
551
+ id: "depreciation/useful-life-rates",
552
+ name: "\u6CD5\u5B9A\u8010\u7528\u5E74\u6570\u30C1\u30A7\u30C3\u30AF",
553
+ description: "\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u8010\u7528\u5E74\u6570\u304C\u6CD5\u5B9A\u8010\u7528\u5E74\u6570\u30C6\u30FC\u30D6\u30EB\u3068\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002",
554
+ severity: "warning"
555
+ },
556
+ check(ctx) {
557
+ const diagnostics = [];
558
+ const assets = ctx.taxReturn.depreciationSchedule.assets;
559
+ for (const asset of assets) {
560
+ for (const [keyword, validLives] of Object.entries(COMMON_USEFUL_LIVES)) {
561
+ if (asset.name.includes(keyword) && !validLives.includes(asset.usefulLife)) {
562
+ diagnostics.push({
563
+ ruleId: this.meta.id,
564
+ severity: this.meta.severity,
565
+ message: `\u300C${asset.name}\u300D\u306E\u8010\u7528\u5E74\u6570(${asset.usefulLife}\u5E74)\u304C\u6CD5\u5B9A\u8010\u7528\u5E74\u6570(${validLives.join("/")}\u5E74)\u3068\u7570\u306A\u308A\u307E\u3059`
566
+ });
567
+ }
568
+ }
569
+ }
570
+ return diagnostics;
571
+ }
572
+ };
573
+
574
+ // src/rules/depreciation/small-asset-threshold.ts
575
+ var smallAssetThresholdRule = {
576
+ meta: {
577
+ id: "depreciation/small-asset-threshold",
578
+ name: "\u5C11\u984D\u8CC7\u7523\u306E\u511F\u5374\u65B9\u6CD5\u30C1\u30A7\u30C3\u30AF",
579
+ description: "\u53D6\u5F97\u4FA1\u984D10\u4E07\u5186\u4EE5\u4E0B\u306F\u5168\u984D\u7D4C\u8CBB\u300110\u4E07\u5186\u8D8530\u4E07\u5186\u4EE5\u4E0B\u306F\u5C11\u984D\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u7279\u4F8B\uFF08\u9752\u8272\u7533\u544A\u8005\uFF09\u304C\u9069\u7528\u53EF\u80FD\u3067\u3059\u3002",
580
+ severity: "warning"
581
+ },
582
+ check(ctx) {
583
+ const diagnostics = [];
584
+ const assets = ctx.taxReturn.depreciationSchedule.assets;
585
+ const threshold10 = yen(1e5);
586
+ const threshold30 = yen(3e5);
587
+ for (const asset of assets) {
588
+ if (asset.acquisitionCost <= threshold10 && asset.usefulLife > 1) {
589
+ diagnostics.push({
590
+ ruleId: this.meta.id,
591
+ severity: this.meta.severity,
592
+ message: `\u300C${asset.name}\u300D(\u53D6\u5F97\u4FA1\u984D${formatYen(asset.acquisitionCost)})\u306F10\u4E07\u5186\u4EE5\u4E0B\u306E\u305F\u3081\u3001\u5168\u984D\u7D4C\u8CBB\u8A08\u4E0A\u304C\u53EF\u80FD\u3067\u3059`
593
+ });
594
+ }
595
+ if (asset.acquisitionCost > threshold10 && asset.acquisitionCost <= threshold30 && asset.depreciationMethod !== "\u4E00\u62EC\u511F\u5374") {
596
+ diagnostics.push({
597
+ ruleId: this.meta.id,
598
+ severity: this.meta.severity,
599
+ message: `\u300C${asset.name}\u300D(\u53D6\u5F97\u4FA1\u984D${formatYen(asset.acquisitionCost)})\u306F30\u4E07\u5186\u4EE5\u4E0B\u306E\u305F\u3081\u3001\u5C11\u984D\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u7279\u4F8B\uFF08\u4E00\u62EC\u7D4C\u8CBB\u8A08\u4E0A\uFF09\u304C\u9069\u7528\u53EF\u80FD\u3067\u3059`,
600
+ details: "\u9752\u8272\u7533\u544A\u8005\u306F\u53D6\u5F97\u4FA1\u984D30\u4E07\u5186\u672A\u6E80\u306E\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306B\u3064\u3044\u3066\u3001\u5E74\u9593\u5408\u8A08300\u4E07\u5186\u307E\u3067\u5168\u984D\u7D4C\u8CBB\u306B\u8A08\u4E0A\u3067\u304D\u307E\u3059\u3002"
601
+ });
602
+ }
603
+ }
604
+ return diagnostics;
605
+ }
606
+ };
607
+
608
+ // src/rules/cross-statement/decision-to-return.ts
609
+ var decisionToReturnRule = {
610
+ meta: {
611
+ id: "cross-statement/decision-to-return",
612
+ name: "\u6C7A\u7B97\u66F8\u2192\u7533\u544A\u66F8 \u8EE2\u8A18\u4E00\u81F4",
613
+ description: "\u9752\u8272\u7533\u544A\u6C7A\u7B97\u66F8\u306E\u58F2\u4E0A\u91D1\u984D\u30FB\u6240\u5F97\u91D1\u984D\u304C\u7533\u544A\u66F8\u7B2C\u4E00\u8868\u306B\u6B63\u3057\u304F\u8EE2\u8A18\u3055\u308C\u3066\u3044\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002",
614
+ severity: "error"
615
+ },
616
+ check(ctx) {
617
+ const diagnostics = [];
618
+ const pl = ctx.taxReturn.incomeStatement;
619
+ const form = ctx.taxReturn.taxFormA;
620
+ if (pl.revenue !== form.businessIncome) {
621
+ diagnostics.push({
622
+ ruleId: this.meta.id,
623
+ severity: this.meta.severity,
624
+ message: `\u6C7A\u7B97\u66F8\u306E\u58F2\u4E0A\u91D1\u984D(${formatYen(pl.revenue)}) \u2260 \u7533\u544A\u66F8\u306E\u55B6\u696D\u7B49\u53CE\u5165(${formatYen(form.businessIncome)})`
625
+ });
626
+ }
627
+ const expectedProfit = yen(pl.operatingIncome - form.blueReturnDeduction);
628
+ if (form.businessProfit !== expectedProfit) {
629
+ diagnostics.push({
630
+ ruleId: this.meta.id,
631
+ severity: this.meta.severity,
632
+ message: `\u7533\u544A\u66F8\u306E\u55B6\u696D\u7B49\u6240\u5F97(${formatYen(form.businessProfit)}) \u2260 \u6C7A\u7B97\u66F8\u6240\u5F97(${formatYen(pl.operatingIncome)}) - \u9752\u8272\u63A7\u9664(${formatYen(form.blueReturnDeduction)})`,
633
+ details: `\u671F\u5F85\u5024: ${formatYen(expectedProfit)}`
634
+ });
635
+ }
636
+ return diagnostics;
637
+ }
638
+ };
639
+
640
+ // src/rules/cross-statement/depreciation-sum.ts
641
+ var depreciationSumRule = {
642
+ meta: {
643
+ id: "cross-statement/depreciation-sum",
644
+ name: "\u6E1B\u4FA1\u511F\u5374\u8CBB\u5408\u8A08\u306E\u4E00\u81F4",
645
+ description: "\u6E1B\u4FA1\u511F\u5374\u660E\u7D30\u306E\u5FC5\u8981\u7D4C\u8CBB\u7B97\u5165\u984D\u5408\u8A08\u304C\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u6E1B\u4FA1\u511F\u5374\u8CBB\u3068\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002",
646
+ severity: "error"
647
+ },
648
+ check(ctx) {
649
+ const scheduleTotal = ctx.taxReturn.depreciationSchedule.totalBusinessDepreciation;
650
+ const plDepreciation = ctx.taxReturn.incomeStatement.expenses.depreciation;
651
+ if (scheduleTotal === 0 && plDepreciation === 0) return [];
652
+ if (scheduleTotal !== plDepreciation) {
653
+ return [
654
+ {
655
+ ruleId: this.meta.id,
656
+ severity: this.meta.severity,
657
+ message: `\u6E1B\u4FA1\u511F\u5374\u660E\u7D30\u306E\u5408\u8A08(${formatYen(scheduleTotal)}) \u2260 P/L\u6E1B\u4FA1\u511F\u5374\u8CBB(${formatYen(plDepreciation)})`
658
+ }
659
+ ];
660
+ }
661
+ return [];
662
+ }
663
+ };
664
+
665
+ // src/rules/continuity/opening-closing-match.ts
666
+ var ACCOUNT_NAMES = {
667
+ cash: "\u73FE\u91D1",
668
+ deposits: "\u9810\u91D1",
669
+ accountsReceivable: "\u58F2\u639B\u91D1",
670
+ inventory: "\u68DA\u5378\u8CC7\u7523",
671
+ buildings: "\u5EFA\u7269",
672
+ vehicles: "\u8ECA\u4E21\u904B\u642C\u5177",
673
+ tools: "\u5DE5\u5177\u5668\u5177\u5099\u54C1",
674
+ land: "\u571F\u5730",
675
+ accountsPayable: "\u8CB7\u639B\u91D1",
676
+ borrowings: "\u501F\u5165\u91D1",
677
+ ownerEquity: "\u5143\u5165\u91D1"
678
+ };
679
+ var openingClosingMatchRule = {
680
+ meta: {
681
+ id: "continuity/opening-closing-match",
682
+ name: "\u671F\u9996=\u524D\u671F\u672B \u4E00\u81F4\u30C1\u30A7\u30C3\u30AF",
683
+ description: "\u5F53\u671F\u306E\u671F\u9996\u6B8B\u9AD8\u304C\u524D\u671F\u306E\u671F\u672B\u6B8B\u9AD8\u3068\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002\u524D\u5E74\u30C7\u30FC\u30BF\u304C\u5FC5\u8981\u3067\u3059\u3002",
684
+ severity: "error"
685
+ },
686
+ check(ctx) {
687
+ if (!ctx.priorYear) return [];
688
+ const diagnostics = [];
689
+ const currentBs = ctx.taxReturn.balanceSheet;
690
+ const priorBs = ctx.priorYear.balanceSheet;
691
+ for (const [key, label] of Object.entries(ACCOUNT_NAMES)) {
692
+ const current = currentBs[key];
693
+ const prior = priorBs[key];
694
+ if (current && prior && typeof current === "object" && "opening" in current && "closing" in prior && current.opening !== prior.closing) {
695
+ diagnostics.push({
696
+ ruleId: this.meta.id,
697
+ severity: this.meta.severity,
698
+ message: `${label}: \u5F53\u671F\u9996(${formatYen(current.opening)}) \u2260 \u524D\u671F\u672B(${formatYen(prior.closing)})`
699
+ });
700
+ }
701
+ }
702
+ return diagnostics;
703
+ }
704
+ };
705
+
706
+ // src/rules/continuity/year-over-year-change.ts
707
+ var FIELDS_TO_CHECK = [
708
+ { key: "revenue", label: "\u58F2\u4E0A" },
709
+ { key: "totalExpenses", label: "\u7D4C\u8CBB\u5408\u8A08" },
710
+ { key: "operatingIncome", label: "\u6240\u5F97\u91D1\u984D" }
711
+ ];
712
+ var yearOverYearChangeRule = {
713
+ meta: {
714
+ id: "continuity/year-over-year-change",
715
+ name: "\u524D\u5E74\u6BD4\u5909\u52D5\u30C1\u30A7\u30C3\u30AF",
716
+ description: "\u58F2\u4E0A\u30FB\u7D4C\u8CBB\u30FB\u6240\u5F97\u304C\u524D\u5E74\u6BD4\u3067200%\u8D85\u306E\u5897\u52A0\u307E\u305F\u306F80%\u8D85\u306E\u6E1B\u5C11\u304C\u3042\u308B\u5834\u5408\u306B\u8B66\u544A\u3057\u307E\u3059\u3002\u524D\u5E74\u30C7\u30FC\u30BF\u304C\u5FC5\u8981\u3067\u3059\u3002",
717
+ severity: "warning"
718
+ },
719
+ check(ctx) {
720
+ if (!ctx.priorYear) return [];
721
+ const diagnostics = [];
722
+ const currentPl = ctx.taxReturn.incomeStatement;
723
+ const priorPl = ctx.priorYear.incomeStatement;
724
+ for (const { key, label } of FIELDS_TO_CHECK) {
725
+ const current = currentPl[key];
726
+ const prior = priorPl[key];
727
+ if (prior === 0) continue;
728
+ const ratio = current / prior;
729
+ if (ratio > 3) {
730
+ diagnostics.push({
731
+ ruleId: this.meta.id,
732
+ severity: this.meta.severity,
733
+ message: `${label}\u304C\u524D\u5E74\u6BD4${Math.round(ratio * 100)}%\u3067\u3059\uFF08${formatYen(prior)} \u2192 ${formatYen(current)}\uFF09`,
734
+ details: "200%\u3092\u8D85\u3048\u308B\u5927\u5E45\u306A\u5897\u52A0\u304C\u3042\u308A\u307E\u3059\u3002\u8A18\u5E33\u5185\u5BB9\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002"
735
+ });
736
+ } else if (ratio < 0.2) {
737
+ diagnostics.push({
738
+ ruleId: this.meta.id,
739
+ severity: this.meta.severity,
740
+ message: `${label}\u304C\u524D\u5E74\u6BD4${Math.round(ratio * 100)}%\u3067\u3059\uFF08${formatYen(prior)} \u2192 ${formatYen(current)}\uFF09`,
741
+ details: "80%\u3092\u8D85\u3048\u308B\u5927\u5E45\u306A\u6E1B\u5C11\u304C\u3042\u308A\u307E\u3059\u3002\u8A18\u5E33\u5185\u5BB9\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002"
742
+ });
743
+ }
744
+ }
745
+ return diagnostics;
746
+ }
747
+ };
748
+
749
+ // src/rules/home-office/reasonable-ratio.ts
750
+ var DEFAULT_MAX_RATIO = 0.9;
751
+ var reasonableRatioRule = {
752
+ meta: {
753
+ id: "home-office/reasonable-ratio",
754
+ name: "\u5BB6\u4E8B\u6309\u5206\u7387\u306E\u59A5\u5F53\u6027",
755
+ description: "\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u4E8B\u696D\u5C02\u7528\u5272\u5408\uFF08\u5BB6\u4E8B\u6309\u5206\u7387\uFF09\u304C\u59A5\u5F53\u306A\u7BC4\u56F2\u5185\u304B\u30C1\u30A7\u30C3\u30AF\u3057\u307E\u3059\u3002\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u4E0A\u9650\u306F90%\u3067\u3059\u3002",
756
+ severity: "warning"
757
+ },
758
+ check(ctx) {
759
+ const diagnostics = [];
760
+ const assets = ctx.taxReturn.depreciationSchedule.assets;
761
+ const ruleConfig = ctx.config.rules[this.meta.id];
762
+ let maxRatio = DEFAULT_MAX_RATIO;
763
+ if (Array.isArray(ruleConfig) && typeof ruleConfig[1]?.maxRatio === "number") {
764
+ maxRatio = ruleConfig[1].maxRatio;
765
+ }
766
+ for (const asset of assets) {
767
+ if (asset.businessUseRatio > maxRatio) {
768
+ diagnostics.push({
769
+ ruleId: this.meta.id,
770
+ severity: this.meta.severity,
771
+ message: `\u300C${asset.name}\u300D\u306E\u4E8B\u696D\u5C02\u7528\u5272\u5408(${Math.round(asset.businessUseRatio * 100)}%)\u304C\u4E0A\u9650(${Math.round(maxRatio * 100)}%)\u3092\u8D85\u3048\u3066\u3044\u307E\u3059`,
772
+ details: "\u5BB6\u4E8B\u6309\u5206\u7387\u304C\u9AD8\u3059\u304E\u308B\u5834\u5408\u3001\u7A0E\u52D9\u8ABF\u67FB\u3067\u5426\u8A8D\u3055\u308C\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u5B9F\u614B\u306B\u5373\u3057\u305F\u5272\u5408\u3092\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
773
+ });
774
+ }
775
+ }
776
+ return diagnostics;
777
+ }
778
+ };
779
+
780
+ // src/rules/index.ts
781
+ var ruleRegistry = /* @__PURE__ */ new Map();
782
+ function registerRule(rule) {
783
+ ruleRegistry.set(rule.meta.id, rule);
784
+ }
785
+ function getAllRules() {
786
+ return [...ruleRegistry.values()];
787
+ }
788
+ function getRule(id) {
789
+ return ruleRegistry.get(id);
790
+ }
791
+ registerRule(bsEquationRule);
792
+ registerRule(openingOwnerEquityRule);
793
+ registerRule(motoireKinFormulaRule);
794
+ registerRule(nonNegativeCashRule);
795
+ registerRule(plArithmeticChainRule);
796
+ registerRule(cogsCalculationRule);
797
+ registerRule(expenseTotalRule);
798
+ registerRule(bsPlBridgeRule);
799
+ registerRule(decisionToReturnRule);
800
+ registerRule(depreciationSumRule);
801
+ registerRule(blueDeductionCapRule);
802
+ registerRule(blueDeductionEligibilityRule);
803
+ registerRule(usefulLifeRatesRule);
804
+ registerRule(smallAssetThresholdRule);
805
+ registerRule(openingClosingMatchRule);
806
+ registerRule(yearOverYearChangeRule);
807
+ registerRule(reasonableRatioRule);
808
+
809
+ // src/config/index.ts
810
+ import { readFile as readFile2 } from "fs/promises";
811
+ import { resolve } from "path";
812
+
813
+ // src/utils/errors.ts
814
+ var ConfigError = class extends Error {
815
+ constructor(message, configPath) {
816
+ super(message);
817
+ this.configPath = configPath;
818
+ this.name = "ConfigError";
819
+ }
820
+ };
821
+
822
+ // src/config/defaults.ts
823
+ var defaultConfig = {
824
+ rules: {},
825
+ format: "stylish",
826
+ warningsAsErrors: false
827
+ };
828
+
829
+ // src/config/schema.ts
830
+ import { z } from "zod";
831
+ var severitySchema = z.enum(["error", "warning", "info", "off"]);
832
+ var ruleValueSchema = z.union([
833
+ severitySchema,
834
+ z.tuple([severitySchema, z.record(z.unknown())])
835
+ ]);
836
+ var configSchema = z.object({
837
+ rules: z.record(ruleValueSchema).default({}),
838
+ priorYearFile: z.string().optional(),
839
+ format: z.enum(["stylish", "json"]).default("stylish"),
840
+ warningsAsErrors: z.boolean().default(false)
841
+ });
842
+
843
+ // src/config/index.ts
844
+ async function loadConfig(configPath) {
845
+ if (!configPath) {
846
+ const defaultPath = resolve(process.cwd(), ".zeicheckrc.json");
847
+ try {
848
+ return await readConfigFile(defaultPath);
849
+ } catch {
850
+ return defaultConfig;
851
+ }
852
+ }
853
+ return readConfigFile(configPath);
854
+ }
855
+ async function readConfigFile(filePath) {
856
+ let raw;
857
+ try {
858
+ raw = await readFile2(filePath, "utf-8");
859
+ } catch {
860
+ throw new ConfigError(`\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${filePath}`, filePath);
861
+ }
862
+ let parsed;
863
+ try {
864
+ parsed = JSON.parse(raw);
865
+ } catch {
866
+ throw new ConfigError(
867
+ `\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306EJSON\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${filePath}`,
868
+ filePath
869
+ );
870
+ }
871
+ const result = configSchema.safeParse(parsed);
872
+ if (!result.success) {
873
+ const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
874
+ throw new ConfigError(
875
+ `\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306E\u30D0\u30EA\u30C7\u30FC\u30B7\u30E7\u30F3\u306B\u5931\u6557\u3057\u307E\u3057\u305F:
876
+ ${issues}`,
877
+ filePath
878
+ );
879
+ }
880
+ return result.data;
881
+ }
882
+
883
+ // src/cli/formatter/stylish.ts
884
+ import pc from "picocolors";
885
+ function colorSeverity(severity) {
886
+ switch (severity) {
887
+ case "error":
888
+ return pc.red(severity);
889
+ case "warning":
890
+ return pc.yellow(severity);
891
+ case "info":
892
+ return pc.blue(severity);
893
+ default:
894
+ return severity;
895
+ }
896
+ }
897
+ function padRight(str, len) {
898
+ return str + " ".repeat(Math.max(0, len - str.length));
899
+ }
900
+ var stylishFormatter = {
901
+ format(input) {
902
+ const { filePath, diagnostics } = input;
903
+ let errorCount = 0;
904
+ let warningCount = 0;
905
+ let infoCount = 0;
906
+ for (const d of diagnostics) {
907
+ if (d.severity === "error") errorCount++;
908
+ else if (d.severity === "warning") warningCount++;
909
+ else if (d.severity === "info") infoCount++;
910
+ }
911
+ if (diagnostics.length === 0) {
912
+ return { output: "", errorCount: 0, warningCount: 0, infoCount: 0 };
913
+ }
914
+ const lines = [];
915
+ lines.push("");
916
+ lines.push(pc.underline(filePath));
917
+ lines.push("");
918
+ const maxRuleIdLen = Math.max(
919
+ ...diagnostics.map((d) => d.ruleId.length)
920
+ );
921
+ const maxSeverityLen = 7;
922
+ for (const diag of diagnostics) {
923
+ const ruleId = padRight(diag.ruleId, maxRuleIdLen);
924
+ const severity = padRight(diag.severity, maxSeverityLen);
925
+ lines.push(
926
+ ` ${ruleId} ${colorSeverity(diag.severity)}${" ".repeat(maxSeverityLen - diag.severity.length)} ${diag.message}`
927
+ );
928
+ }
929
+ lines.push("");
930
+ const total = diagnostics.length;
931
+ const summary = `${pc.bold(errorCount > 0 ? pc.red(`\u2716 ${total} \u4EF6\u306E\u554F\u984C`) : `\u2716 ${total} \u4EF6\u306E\u554F\u984C`)} (${errorCount} errors, ${warningCount} warnings)`;
932
+ lines.push(summary);
933
+ return {
934
+ output: lines.join("\n"),
935
+ errorCount,
936
+ warningCount,
937
+ infoCount
938
+ };
939
+ }
940
+ };
941
+
942
+ // src/cli/formatter/json.ts
943
+ var jsonFormatter = {
944
+ format(input) {
945
+ const { filePath, diagnostics } = input;
946
+ let errorCount = 0;
947
+ let warningCount = 0;
948
+ let infoCount = 0;
949
+ for (const d of diagnostics) {
950
+ if (d.severity === "error") errorCount++;
951
+ else if (d.severity === "warning") warningCount++;
952
+ else if (d.severity === "info") infoCount++;
953
+ }
954
+ const output = JSON.stringify(
955
+ {
956
+ filePath,
957
+ diagnostics,
958
+ summary: {
959
+ total: diagnostics.length,
960
+ errors: errorCount,
961
+ warnings: warningCount,
962
+ info: infoCount
963
+ }
964
+ },
965
+ null,
966
+ 2
967
+ );
968
+ return { output, errorCount, warningCount, infoCount };
969
+ }
970
+ };
971
+
972
+ // src/cli/formatter/index.ts
973
+ function getFormatter(name) {
974
+ switch (name) {
975
+ case "json":
976
+ return jsonFormatter;
977
+ case "stylish":
978
+ default:
979
+ return stylishFormatter;
980
+ }
981
+ }
982
+
983
+ export {
984
+ yen,
985
+ FormType,
986
+ parseXtxFile,
987
+ parseXtxString,
988
+ runRules,
989
+ getAllRules,
990
+ getRule,
991
+ loadConfig,
992
+ getFormatter
993
+ };
994
+ //# sourceMappingURL=chunk-LZZKQ7B2.js.map