@accounter/shaam-uniform-format-generator 0.1.0 → 0.1.1
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/README.md +366 -13
- package/dist/README.md +476 -0
- package/dist/cjs/api/generate-report-legacy.js +6 -0
- package/dist/cjs/api/generate-report.js +328 -0
- package/dist/cjs/constants.js +11 -0
- package/dist/cjs/generator/format/encoder.js +86 -0
- package/dist/cjs/generator/records/a000-sum.js +66 -0
- package/dist/cjs/generator/records/a000.js +349 -0
- package/dist/cjs/generator/records/a100.js +107 -0
- package/dist/cjs/generator/records/b100.js +305 -0
- package/dist/cjs/generator/records/b110.js +255 -0
- package/dist/cjs/generator/records/c100.js +338 -0
- package/dist/cjs/generator/records/d110.js +272 -0
- package/dist/cjs/generator/records/d120.js +278 -0
- package/{cjs → dist/cjs}/generator/records/index.js +1 -0
- package/dist/cjs/generator/records/m100.js +177 -0
- package/dist/cjs/generator/records/z900.js +93 -0
- package/{cjs → dist/cjs}/index.js +3 -0
- package/dist/cjs/records/a100.js +78 -0
- package/dist/cjs/records/index.js +20 -0
- package/dist/cjs/records/z900.js +82 -0
- package/dist/cjs/types/enums.js +457 -0
- package/{cjs → dist/cjs}/types/index.js +6 -1
- package/dist/cjs/utils/file-helpers.js +198 -0
- package/dist/cjs/utils/index.js +8 -0
- package/dist/cjs/utils/key-generator.js +71 -0
- package/dist/esm/api/generate-report-legacy.js +2 -0
- package/dist/esm/api/generate-report.js +325 -0
- package/dist/esm/constants.js +8 -0
- package/dist/esm/generator/format/encoder.js +77 -0
- package/dist/esm/generator/records/a000-sum.js +61 -0
- package/dist/esm/generator/records/a000.js +344 -0
- package/dist/esm/generator/records/a100.js +102 -0
- package/dist/esm/generator/records/b100.js +300 -0
- package/dist/esm/generator/records/b110.js +250 -0
- package/dist/esm/generator/records/c100.js +333 -0
- package/dist/esm/generator/records/d110.js +267 -0
- package/dist/esm/generator/records/d120.js +273 -0
- package/{esm → dist/esm}/generator/records/index.js +1 -0
- package/dist/esm/generator/records/m100.js +172 -0
- package/dist/esm/generator/records/z900.js +88 -0
- package/{esm → dist/esm}/index.js +3 -0
- package/dist/esm/records/a100.js +73 -0
- package/dist/esm/records/index.js +11 -0
- package/dist/esm/records/z900.js +77 -0
- package/dist/esm/types/enums.js +454 -0
- package/{esm → dist/esm}/types/index.js +5 -1
- package/dist/esm/utils/file-helpers.js +188 -0
- package/dist/esm/utils/index.js +5 -0
- package/dist/esm/utils/key-generator.js +65 -0
- package/dist/package.json +54 -0
- package/dist/typings/api/generate-report-legacy.d.cts +1 -0
- package/dist/typings/api/generate-report-legacy.d.ts +1 -0
- package/dist/typings/constants.d.cts +8 -0
- package/dist/typings/constants.d.ts +8 -0
- package/dist/typings/generator/format/encoder.d.cts +57 -0
- package/dist/typings/generator/format/encoder.d.ts +57 -0
- package/dist/typings/generator/records/a000-sum.d.cts +40 -0
- package/dist/typings/generator/records/a000-sum.d.ts +40 -0
- package/dist/typings/generator/records/a000.d.cts +238 -0
- package/dist/typings/generator/records/a000.d.ts +238 -0
- package/dist/typings/generator/records/a100.d.cts +59 -0
- package/dist/typings/generator/records/a100.d.ts +59 -0
- package/dist/typings/generator/records/b100.d.cts +101 -0
- package/dist/typings/generator/records/b100.d.ts +101 -0
- package/dist/typings/generator/records/b110.d.cts +89 -0
- package/dist/typings/generator/records/b110.d.ts +89 -0
- package/dist/typings/generator/records/c100.d.cts +133 -0
- package/dist/typings/generator/records/c100.d.ts +133 -0
- package/dist/typings/generator/records/d110.d.cts +98 -0
- package/dist/typings/generator/records/d110.d.ts +98 -0
- package/dist/typings/generator/records/d120.d.cts +95 -0
- package/dist/typings/generator/records/d120.d.ts +95 -0
- package/{typings → dist/typings}/generator/records/index.d.cts +1 -0
- package/{typings → dist/typings}/generator/records/index.d.ts +1 -0
- package/dist/typings/generator/records/m100.d.cts +69 -0
- package/dist/typings/generator/records/m100.d.ts +69 -0
- package/dist/typings/generator/records/z900.d.cts +61 -0
- package/dist/typings/generator/records/z900.d.ts +61 -0
- package/{typings → dist/typings}/index.d.cts +3 -0
- package/{typings → dist/typings}/index.d.ts +3 -0
- package/dist/typings/records/a100.d.cts +35 -0
- package/dist/typings/records/a100.d.ts +35 -0
- package/dist/typings/records/index.d.cts +2 -0
- package/dist/typings/records/index.d.ts +2 -0
- package/dist/typings/records/z900.d.cts +38 -0
- package/dist/typings/records/z900.d.ts +38 -0
- package/dist/typings/types/enums.d.cts +162 -0
- package/dist/typings/types/enums.d.ts +162 -0
- package/{typings → dist/typings}/types/index.d.cts +17 -14
- package/{typings → dist/typings}/types/index.d.ts +17 -14
- package/dist/typings/utils/file-helpers.d.cts +131 -0
- package/dist/typings/utils/file-helpers.d.ts +131 -0
- package/dist/typings/utils/index.d.cts +5 -0
- package/dist/typings/utils/index.d.ts +5 -0
- package/dist/typings/utils/key-generator.d.cts +41 -0
- package/dist/typings/utils/key-generator.d.ts +41 -0
- package/documentation/IncomeTax_IncomeTaxSoftwareHousesInfo_horaot1.31_2_05.pdf +0 -0
- package/documentation/_4D6963726F736F667420576F7264202D20F8E5E0E9ED20F8E7E5F720F8E5E0E9ED20F9F7E5F32E646F63_.pdf +0 -0
- package/documentation/a000-sum.csv +3 -0
- package/documentation/a000.csv +37 -0
- package/documentation/a100.csv +7 -0
- package/documentation/b100.csv +29 -0
- package/documentation/b110.csv +26 -0
- package/documentation/c100.csv +37 -0
- package/documentation/d110.csv +27 -0
- package/documentation/d120.csv +26 -0
- package/documentation/m100.csv +17 -0
- package/documentation/z900.csv +8 -0
- package/package.json +50 -29
- package/prompt_plan.md +259 -0
- package/spec.md +206 -0
- package/src/api/generate-report.ts +366 -0
- package/src/api/parse-files.ts +33 -0
- package/src/constants.ts +9 -0
- package/src/format/index.ts +6 -0
- package/src/format/newline.ts +8 -0
- package/src/format/padding.ts +39 -0
- package/src/generator/format/decoder.ts +15 -0
- package/src/generator/format/encoder.ts +95 -0
- package/src/generator/format/index.ts +6 -0
- package/src/generator/index.ts +6 -0
- package/src/generator/records/a000-sum.ts +78 -0
- package/src/generator/records/a000.ts +373 -0
- package/src/generator/records/a100.ts +118 -0
- package/src/generator/records/b100.ts +317 -0
- package/src/generator/records/b110.ts +267 -0
- package/src/generator/records/c100.ts +347 -0
- package/src/generator/records/d110.ts +286 -0
- package/src/generator/records/d120.ts +293 -0
- package/src/generator/records/index.ts +14 -0
- package/src/generator/records/m100.ts +185 -0
- package/src/generator/records/z900.ts +104 -0
- package/src/index.ts +18 -0
- package/src/parser/data-parser.ts +14 -0
- package/src/parser/index.ts +6 -0
- package/src/parser/ini-parser.ts +14 -0
- package/src/types/enums.ts +531 -0
- package/src/types/index.ts +110 -0
- package/src/utils/file-helpers.ts +221 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/key-generator.ts +75 -0
- package/src/validation/errors.ts +35 -0
- package/src/validation/index.ts +6 -0
- package/src/validation/validate-input.ts +67 -0
- package/tests/debug-output.test.ts +81 -0
- package/tests/format/crlf-join.test.ts +124 -0
- package/tests/format/encoder.test.ts +80 -0
- package/tests/format/newline.test.ts +19 -0
- package/tests/format/padding.test.ts +74 -0
- package/tests/index.test.ts +29 -0
- package/tests/ini-text.test.ts +122 -0
- package/tests/integration/comprehensive.integration.test.ts +350 -0
- package/tests/integration/roundtrip.integration.test.ts +377 -0
- package/tests/records/a000-sum.test.ts +278 -0
- package/tests/records/a000.test.ts +318 -0
- package/tests/records/a100.test.ts +239 -0
- package/tests/records/b100.test.ts +419 -0
- package/tests/records/b110.test.ts +445 -0
- package/tests/records/c100.test.ts +333 -0
- package/tests/records/d110.test.ts +93 -0
- package/tests/records/d120.test.ts +275 -0
- package/tests/records/m100.test.ts +437 -0
- package/tests/records/z900.test.ts +254 -0
- package/tests/types/enums.test.ts +290 -0
- package/tests/utils/file-helpers.test.ts +276 -0
- package/tests/utils/key-generator.test.ts +121 -0
- package/tests/validation/document-type-validation.test.ts +521 -0
- package/tests/validation/validate-input.test.ts +219 -0
- package/todo.md +203 -0
- package/tsconfig.json +10 -0
- package/vitest.config.ts +11 -0
- package/cjs/api/generate-report.js +0 -53
- package/cjs/generator/format/encoder.js +0 -46
- package/cjs/generator/records/a000.js +0 -8
- package/cjs/generator/records/a100.js +0 -8
- package/cjs/generator/records/b100.js +0 -8
- package/cjs/generator/records/b110.js +0 -8
- package/cjs/generator/records/c100.js +0 -8
- package/cjs/generator/records/d110.js +0 -8
- package/cjs/generator/records/d120.js +0 -8
- package/cjs/generator/records/m100.js +0 -8
- package/cjs/generator/records/z900.js +0 -8
- package/esm/api/generate-report.js +0 -50
- package/esm/generator/format/encoder.js +0 -42
- package/esm/generator/records/a000.js +0 -5
- package/esm/generator/records/a100.js +0 -5
- package/esm/generator/records/b100.js +0 -5
- package/esm/generator/records/b110.js +0 -5
- package/esm/generator/records/c100.js +0 -5
- package/esm/generator/records/d110.js +0 -5
- package/esm/generator/records/d120.js +0 -5
- package/esm/generator/records/m100.js +0 -5
- package/esm/generator/records/z900.js +0 -5
- package/typings/generator/format/encoder.d.cts +0 -33
- package/typings/generator/format/encoder.d.ts +0 -33
- package/typings/generator/records/a000.d.cts +0 -4
- package/typings/generator/records/a000.d.ts +0 -4
- package/typings/generator/records/a100.d.cts +0 -4
- package/typings/generator/records/a100.d.ts +0 -4
- package/typings/generator/records/b100.d.cts +0 -4
- package/typings/generator/records/b100.d.ts +0 -4
- package/typings/generator/records/b110.d.cts +0 -4
- package/typings/generator/records/b110.d.ts +0 -4
- package/typings/generator/records/c100.d.cts +0 -4
- package/typings/generator/records/c100.d.ts +0 -4
- package/typings/generator/records/d110.d.cts +0 -4
- package/typings/generator/records/d110.d.ts +0 -4
- package/typings/generator/records/d120.d.cts +0 -4
- package/typings/generator/records/d120.d.ts +0 -4
- package/typings/generator/records/m100.d.cts +0 -4
- package/typings/generator/records/m100.d.ts +0 -4
- package/typings/generator/records/z900.d.cts +0 -4
- package/typings/generator/records/z900.d.ts +0 -4
- /package/{cjs → dist/cjs}/api/parse-files.js +0 -0
- /package/{cjs → dist/cjs}/format/index.js +0 -0
- /package/{cjs → dist/cjs}/format/newline.js +0 -0
- /package/{cjs → dist/cjs}/format/padding.js +0 -0
- /package/{cjs → dist/cjs}/generator/format/decoder.js +0 -0
- /package/{cjs → dist/cjs}/generator/format/index.js +0 -0
- /package/{cjs → dist/cjs}/generator/index.js +0 -0
- /package/{cjs → dist/cjs}/package.json +0 -0
- /package/{cjs → dist/cjs}/parser/data-parser.js +0 -0
- /package/{cjs → dist/cjs}/parser/index.js +0 -0
- /package/{cjs → dist/cjs}/parser/ini-parser.js +0 -0
- /package/{cjs → dist/cjs}/validation/errors.js +0 -0
- /package/{cjs → dist/cjs}/validation/index.js +0 -0
- /package/{cjs → dist/cjs}/validation/validate-input.js +0 -0
- /package/{esm → dist/esm}/api/parse-files.js +0 -0
- /package/{esm → dist/esm}/format/index.js +0 -0
- /package/{esm → dist/esm}/format/newline.js +0 -0
- /package/{esm → dist/esm}/format/padding.js +0 -0
- /package/{esm → dist/esm}/generator/format/decoder.js +0 -0
- /package/{esm → dist/esm}/generator/format/index.js +0 -0
- /package/{esm → dist/esm}/generator/index.js +0 -0
- /package/{esm → dist/esm}/parser/data-parser.js +0 -0
- /package/{esm → dist/esm}/parser/index.js +0 -0
- /package/{esm → dist/esm}/parser/ini-parser.js +0 -0
- /package/{esm → dist/esm}/validation/errors.js +0 -0
- /package/{esm → dist/esm}/validation/index.js +0 -0
- /package/{esm → dist/esm}/validation/validate-input.js +0 -0
- /package/{typings → dist/typings}/api/generate-report.d.cts +0 -0
- /package/{typings → dist/typings}/api/generate-report.d.ts +0 -0
- /package/{typings → dist/typings}/api/parse-files.d.cts +0 -0
- /package/{typings → dist/typings}/api/parse-files.d.ts +0 -0
- /package/{typings → dist/typings}/format/index.d.cts +0 -0
- /package/{typings → dist/typings}/format/index.d.ts +0 -0
- /package/{typings → dist/typings}/format/newline.d.cts +0 -0
- /package/{typings → dist/typings}/format/newline.d.ts +0 -0
- /package/{typings → dist/typings}/format/padding.d.cts +0 -0
- /package/{typings → dist/typings}/format/padding.d.ts +0 -0
- /package/{typings → dist/typings}/generator/format/decoder.d.cts +0 -0
- /package/{typings → dist/typings}/generator/format/decoder.d.ts +0 -0
- /package/{typings → dist/typings}/generator/format/index.d.cts +0 -0
- /package/{typings → dist/typings}/generator/format/index.d.ts +0 -0
- /package/{typings → dist/typings}/generator/index.d.cts +0 -0
- /package/{typings → dist/typings}/generator/index.d.ts +0 -0
- /package/{typings → dist/typings}/parser/data-parser.d.cts +0 -0
- /package/{typings → dist/typings}/parser/data-parser.d.ts +0 -0
- /package/{typings → dist/typings}/parser/index.d.cts +0 -0
- /package/{typings → dist/typings}/parser/index.d.ts +0 -0
- /package/{typings → dist/typings}/parser/ini-parser.d.cts +0 -0
- /package/{typings → dist/typings}/parser/ini-parser.d.ts +0 -0
- /package/{typings → dist/typings}/validation/errors.d.cts +0 -0
- /package/{typings → dist/typings}/validation/errors.d.ts +0 -0
- /package/{typings → dist/typings}/validation/index.d.cts +0 -0
- /package/{typings → dist/typings}/validation/index.d.ts +0 -0
- /package/{typings → dist/typings}/validation/validate-input.d.cts +0 -0
- /package/{typings → dist/typings}/validation/validate-input.d.ts +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* File Helper Utilities for SHAAM Uniform Format Generator
|
|
4
|
+
* Provides utilities for creating and managing File objects
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.FileNaming = void 0;
|
|
8
|
+
exports.createFile = createFile;
|
|
9
|
+
exports.createIniFile = createIniFile;
|
|
10
|
+
exports.createDataFile = createDataFile;
|
|
11
|
+
exports.createShaamFiles = createShaamFiles;
|
|
12
|
+
exports.validateShaamFile = validateShaamFile;
|
|
13
|
+
exports.readFileAsText = readFileAsText;
|
|
14
|
+
exports.getFileInfo = getFileInfo;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a File object with the given text content and filename
|
|
17
|
+
* This is a utility function to standardize File creation across the package
|
|
18
|
+
*
|
|
19
|
+
* @param text - The text content for the file
|
|
20
|
+
* @param name - The filename (should include extension)
|
|
21
|
+
* @param options - Optional File constructor options
|
|
22
|
+
* @returns A File object containing the text content
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const iniFile = createFile(iniText, 'report.INI.TXT');
|
|
27
|
+
* const dataFile = createFile(dataText, 'report.BKMVDATA.TXT');
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function createFile(text, name, options = { type: 'text/plain' }) {
|
|
31
|
+
if (!text || typeof text !== 'string') {
|
|
32
|
+
throw new Error('Text content must be a non-empty string');
|
|
33
|
+
}
|
|
34
|
+
if (!name || typeof name !== 'string') {
|
|
35
|
+
throw new Error('Filename must be a non-empty string');
|
|
36
|
+
}
|
|
37
|
+
// Ensure we have proper line endings for SHAAM format
|
|
38
|
+
const normalizedText = text.replace(/\r?\n/g, '\r\n');
|
|
39
|
+
return new File([normalizedText], name, {
|
|
40
|
+
type: 'text/plain',
|
|
41
|
+
...options,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Creates an INI.TXT File object with standardized naming
|
|
46
|
+
*
|
|
47
|
+
* @param iniText - The INI text content
|
|
48
|
+
* @param baseFileName - Base filename (without extension)
|
|
49
|
+
* @returns A File object for the INI file
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const iniFile = createIniFile(iniText, 'my-report');
|
|
54
|
+
* // Creates file named: my-report.INI.TXT
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
function createIniFile(iniText, baseFileName = 'report') {
|
|
58
|
+
const fileName = `${baseFileName}.INI.TXT`;
|
|
59
|
+
return createFile(iniText, fileName);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Creates a BKMVDATA.TXT File object with standardized naming
|
|
63
|
+
*
|
|
64
|
+
* @param dataText - The data text content
|
|
65
|
+
* @param baseFileName - Base filename (without extension)
|
|
66
|
+
* @returns A File object for the data file
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const dataFile = createDataFile(dataText, 'my-report');
|
|
71
|
+
* // Creates file named: my-report.BKMVDATA.TXT
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function createDataFile(dataText, baseFileName = 'report') {
|
|
75
|
+
const fileName = `${baseFileName}.BKMVDATA.TXT`;
|
|
76
|
+
return createFile(dataText, fileName);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Creates both INI and Data File objects from the report output
|
|
80
|
+
*
|
|
81
|
+
* @param iniText - The INI text content
|
|
82
|
+
* @param dataText - The data text content
|
|
83
|
+
* @param baseFileName - Base filename (without extension)
|
|
84
|
+
* @returns An object containing both File objects
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const { iniFile, dataFile } = createShaamFiles(iniText, dataText, 'my-report');
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
function createShaamFiles(iniText, dataText, baseFileName = 'report') {
|
|
92
|
+
return {
|
|
93
|
+
iniFile: createIniFile(iniText, baseFileName),
|
|
94
|
+
dataFile: createDataFile(dataText, baseFileName),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Validates that a File object appears to be a valid SHAAM format file
|
|
99
|
+
*
|
|
100
|
+
* @param file - The File object to validate
|
|
101
|
+
* @param expectedType - Expected file type ('ini' | 'data')
|
|
102
|
+
* @returns True if the file appears valid
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const isValidIni = validateShaamFile(iniFile, 'ini');
|
|
107
|
+
* const isValidData = validateShaamFile(dataFile, 'data');
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
function validateShaamFile(file, expectedType) {
|
|
111
|
+
if (!file || !(file instanceof File)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
// Check filename convention
|
|
115
|
+
const expectedExtension = expectedType === 'ini' ? '.INI.TXT' : '.BKMVDATA.TXT';
|
|
116
|
+
if (!file.name.toUpperCase().endsWith(expectedExtension)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
// Check MIME type
|
|
120
|
+
if (file.type !== 'text/plain') {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
// Check that file has content
|
|
124
|
+
if (file.size === 0) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Reads text content from a File object
|
|
131
|
+
* This is an async utility for reading File objects back to text
|
|
132
|
+
*
|
|
133
|
+
* @param file - The File object to read
|
|
134
|
+
* @returns Promise that resolves to the text content
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const text = await readFileAsText(file);
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
async function readFileAsText(file) {
|
|
142
|
+
if (!file || !(file instanceof File)) {
|
|
143
|
+
throw new Error('Input must be a valid File object');
|
|
144
|
+
}
|
|
145
|
+
return file.text();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Gets file information from a File object
|
|
149
|
+
*
|
|
150
|
+
* @param file - The File object to inspect
|
|
151
|
+
* @returns File information object
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const info = getFileInfo(iniFile);
|
|
156
|
+
* console.log(`File: ${info.name}, Size: ${info.size} bytes`);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
function getFileInfo(file) {
|
|
160
|
+
if (!file || !(file instanceof File)) {
|
|
161
|
+
throw new Error('Input must be a valid File object');
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
name: file.name,
|
|
165
|
+
size: file.size,
|
|
166
|
+
type: file.type,
|
|
167
|
+
lastModified: file.lastModified,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* File naming utilities for SHAAM format files
|
|
172
|
+
*/
|
|
173
|
+
exports.FileNaming = {
|
|
174
|
+
/**
|
|
175
|
+
* Generates a standardized INI filename
|
|
176
|
+
*/
|
|
177
|
+
iniFileName: (base = 'report') => `${base}.INI.TXT`,
|
|
178
|
+
/**
|
|
179
|
+
* Generates a standardized data filename
|
|
180
|
+
*/
|
|
181
|
+
dataFileName: (base = 'report') => `${base}.BKMVDATA.TXT`,
|
|
182
|
+
/**
|
|
183
|
+
* Extracts base filename from a SHAAM file
|
|
184
|
+
*/
|
|
185
|
+
extractBaseName: (fileName) => {
|
|
186
|
+
if (!fileName || !exports.FileNaming.isValidShaamFileName(fileName)) {
|
|
187
|
+
return 'report';
|
|
188
|
+
}
|
|
189
|
+
const name = fileName.replace(/\.(INI|BKMVDATA)\.TXT$/i, '');
|
|
190
|
+
return name || 'report';
|
|
191
|
+
},
|
|
192
|
+
/**
|
|
193
|
+
* Validates filename follows SHAAM conventions
|
|
194
|
+
*/
|
|
195
|
+
isValidShaamFileName: (fileName) => {
|
|
196
|
+
return /\.(INI|BKMVDATA)\.TXT$/i.test(fileName);
|
|
197
|
+
},
|
|
198
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for SHAAM uniform format generator
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
tslib_1.__exportStar(require("./file-helpers.js"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./key-generator.js"), exports);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Key generator utility for generating unique identifiers
|
|
4
|
+
* Used for fields 1004, 1103, and 1153 which require randomly generated unique IDs
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.defaultKeyGenerator = exports.KeyGeneratorContext = void 0;
|
|
8
|
+
exports.generateRandomKey = generateRandomKey;
|
|
9
|
+
exports.generatePrimaryIdentifier = generatePrimaryIdentifier;
|
|
10
|
+
/**
|
|
11
|
+
* Generates a random numeric string of specified length
|
|
12
|
+
* @param length - The length of the numeric string to generate (max 15 digits)
|
|
13
|
+
* @returns A random numeric string padded with leading zeros if necessary
|
|
14
|
+
*/
|
|
15
|
+
function generateRandomKey(length = 15) {
|
|
16
|
+
if (length <= 0 || length > 15) {
|
|
17
|
+
throw new Error('Key length must be between 1 and 15 digits');
|
|
18
|
+
}
|
|
19
|
+
// Generate a random number with the specified number of digits
|
|
20
|
+
// For length 15, max value is 999,999,999,999,999 (15 nines)
|
|
21
|
+
const maxValue = Math.pow(10, length) - 1;
|
|
22
|
+
const minValue = Math.pow(10, length - 1); // Ensures we always get the full length
|
|
23
|
+
// Generate random number between minValue and maxValue
|
|
24
|
+
const randomNum = Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
|
|
25
|
+
// Convert to string and pad with zeros if needed
|
|
26
|
+
return randomNum.toString().padStart(length, '0');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Generates a primary identifier for fields 1004, 1103, and 1153
|
|
30
|
+
* These fields must have the same value across all records in a single file
|
|
31
|
+
* @returns A 15-digit numeric string
|
|
32
|
+
*/
|
|
33
|
+
function generatePrimaryIdentifier() {
|
|
34
|
+
return generateRandomKey(15);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Key generator context to maintain consistent IDs across records
|
|
38
|
+
* This ensures that fields 1004, 1103, and 1153 use the same value within a single file
|
|
39
|
+
*/
|
|
40
|
+
class KeyGeneratorContext {
|
|
41
|
+
_primaryIdentifier = null;
|
|
42
|
+
/**
|
|
43
|
+
* Gets or generates the primary identifier for this context
|
|
44
|
+
* Ensures the same ID is used across all records that require it
|
|
45
|
+
*/
|
|
46
|
+
getPrimaryIdentifier() {
|
|
47
|
+
this._primaryIdentifier ||= generatePrimaryIdentifier();
|
|
48
|
+
return this._primaryIdentifier;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resets the context, generating new IDs for the next file
|
|
52
|
+
*/
|
|
53
|
+
reset() {
|
|
54
|
+
this._primaryIdentifier = null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Sets a specific primary identifier (useful for testing or when you have a specific ID requirement)
|
|
58
|
+
*/
|
|
59
|
+
setPrimaryIdentifier(id) {
|
|
60
|
+
if (!/^\d{1,15}$/.test(id)) {
|
|
61
|
+
throw new Error('Primary identifier must be a numeric string with 1-15 digits');
|
|
62
|
+
}
|
|
63
|
+
this._primaryIdentifier = id.padStart(15, '0');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.KeyGeneratorContext = KeyGeneratorContext;
|
|
67
|
+
/**
|
|
68
|
+
* Default key generator context instance
|
|
69
|
+
* Use this for most cases to ensure consistency across records
|
|
70
|
+
*/
|
|
71
|
+
exports.defaultKeyGenerator = new KeyGeneratorContext();
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main API for generating SHAAM uniform format reports
|
|
3
|
+
*/
|
|
4
|
+
import { assembleFile } from '../generator/format/encoder.js';
|
|
5
|
+
import { encodeA000, encodeA000Sum, encodeA100, encodeB100, encodeB110, encodeC100, encodeD110, encodeD120, encodeM100, encodeZ900, } from '../generator/records/index.js';
|
|
6
|
+
import { ShaamFormatError } from '../validation/errors.js';
|
|
7
|
+
import { validateInput } from '../validation/validate-input.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generates SHAAM uniform format report files (INI.TXT and BKMVDATA.TXT)
|
|
10
|
+
* from a high-level JSON input object.
|
|
11
|
+
*
|
|
12
|
+
* @param input - The report input data
|
|
13
|
+
* @param options - Generation options
|
|
14
|
+
* @returns Report output with generated file content
|
|
15
|
+
*/
|
|
16
|
+
export function generateUniformFormatReport(input, options = {}) {
|
|
17
|
+
// Validate input data first
|
|
18
|
+
const validationMode = options.validationMode || 'fail-fast';
|
|
19
|
+
const validationErrors = validateInput(input, validationMode);
|
|
20
|
+
if (validationErrors.length > 0) {
|
|
21
|
+
if (validationMode === 'fail-fast') {
|
|
22
|
+
// This should have already thrown, but just in case
|
|
23
|
+
throw new ShaamFormatError('Validation failed', validationErrors);
|
|
24
|
+
}
|
|
25
|
+
// For collect-all mode, we still throw if there are errors
|
|
26
|
+
// The user can catch and inspect the errors if needed
|
|
27
|
+
throw new ShaamFormatError('Input validation failed', validationErrors);
|
|
28
|
+
}
|
|
29
|
+
const records = [];
|
|
30
|
+
const iniRecords = [];
|
|
31
|
+
const recordCounts = {};
|
|
32
|
+
let recordNumber = 1;
|
|
33
|
+
// Helper function to count and add data record
|
|
34
|
+
const addRecord = (recordType, recordContent) => {
|
|
35
|
+
records.push(recordContent);
|
|
36
|
+
recordCounts[recordType] = (recordCounts[recordType] || 0) + 1;
|
|
37
|
+
recordNumber++;
|
|
38
|
+
};
|
|
39
|
+
// Helper function to add INI record
|
|
40
|
+
const addIniRecord = (recordType, recordContent) => {
|
|
41
|
+
iniRecords.push(recordContent);
|
|
42
|
+
recordCounts[recordType] = (recordCounts[recordType] || 0) + 1;
|
|
43
|
+
};
|
|
44
|
+
// Generate A000 record for INI.TXT
|
|
45
|
+
const fileHeaderRecord = {
|
|
46
|
+
reservedFuture: '',
|
|
47
|
+
totalRecords: '0', // Will be updated later with actual count
|
|
48
|
+
vatId: input.business.taxId,
|
|
49
|
+
softwareRegNumber: '12345678', // TODO: Use actual software registration number
|
|
50
|
+
softwareName: 'SHAAM Generator',
|
|
51
|
+
softwareVersion: '1.0.0',
|
|
52
|
+
vendorVatId: '123456789', // TODO: Use actual vendor VAT ID
|
|
53
|
+
vendorName: 'Accounter',
|
|
54
|
+
softwareType: '2', // Multi-year software
|
|
55
|
+
fileOutputPath: options.fileNameBase || 'report',
|
|
56
|
+
accountingType: '2', // Double-entry accounting
|
|
57
|
+
balanceRequired: '1',
|
|
58
|
+
companyRegId: '',
|
|
59
|
+
withholdingFileNum: '',
|
|
60
|
+
reserved1017: '',
|
|
61
|
+
businessName: input.business.name,
|
|
62
|
+
businessStreet: '',
|
|
63
|
+
businessHouseNum: '',
|
|
64
|
+
businessCity: '',
|
|
65
|
+
businessZip: '',
|
|
66
|
+
taxYear: '',
|
|
67
|
+
startDate: input.business.reportingPeriod.startDate.replace(/-/g, ''),
|
|
68
|
+
endDate: input.business.reportingPeriod.endDate.replace(/-/g, ''),
|
|
69
|
+
processStartDate: new Date().toISOString().slice(0, 10).replace(/-/g, ''),
|
|
70
|
+
processStartTime: new Date().toTimeString().slice(0, 5).replace(':', ''),
|
|
71
|
+
languageCode: '0', // Hebrew
|
|
72
|
+
characterEncoding: '1', // ISO-8859-8-i
|
|
73
|
+
compressionSoftware: '',
|
|
74
|
+
reserved1031: '',
|
|
75
|
+
baseCurrency: 'ILS',
|
|
76
|
+
reserved1033: '',
|
|
77
|
+
branchInfoFlag: '0', // No branches for now
|
|
78
|
+
reserved1035: '',
|
|
79
|
+
};
|
|
80
|
+
addIniRecord('A000', encodeA000(fileHeaderRecord));
|
|
81
|
+
// Add A000Sum records for each record type to INI.TXT
|
|
82
|
+
// Calculate expected counts based on input data
|
|
83
|
+
const expectedCounts = {
|
|
84
|
+
A100: 1,
|
|
85
|
+
C100: input.documents.length,
|
|
86
|
+
D110: input.documents.length,
|
|
87
|
+
D120: input.documents.length,
|
|
88
|
+
B100: input.journalEntries.length,
|
|
89
|
+
B110: input.accounts.length,
|
|
90
|
+
M100: input.inventory.length,
|
|
91
|
+
Z900: 1,
|
|
92
|
+
};
|
|
93
|
+
// Add summary records for each record type
|
|
94
|
+
for (const [recordType, count] of Object.entries(expectedCounts)) {
|
|
95
|
+
if (count > 0) {
|
|
96
|
+
const summaryRecord = {
|
|
97
|
+
code: recordType,
|
|
98
|
+
recordCount: count.toString(),
|
|
99
|
+
};
|
|
100
|
+
addIniRecord('A000Sum', encodeA000Sum(summaryRecord));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 1. Business metadata - A100 record
|
|
104
|
+
const businessMetadata = {
|
|
105
|
+
recordNumber: recordNumber.toString(),
|
|
106
|
+
vatId: input.business.taxId,
|
|
107
|
+
reserved: '',
|
|
108
|
+
};
|
|
109
|
+
addRecord('A100', encodeA100(businessMetadata));
|
|
110
|
+
// TODO: 2. Summaries... (not implemented yet)
|
|
111
|
+
// 3. For each document in input.documents
|
|
112
|
+
for (const document of input.documents) {
|
|
113
|
+
// Document header - C100 record
|
|
114
|
+
const documentRecord = {
|
|
115
|
+
code: 'C100',
|
|
116
|
+
recordNumber: recordNumber.toString(),
|
|
117
|
+
vatId: input.business.taxId,
|
|
118
|
+
documentType: document.type,
|
|
119
|
+
documentId: document.id,
|
|
120
|
+
documentIssueDate: document.date.replace(/-/g, ''), // Convert YYYY-MM-DD to YYYYMMDD
|
|
121
|
+
documentIssueTime: '',
|
|
122
|
+
customerName: '',
|
|
123
|
+
customerStreet: '',
|
|
124
|
+
customerHouseNumber: '',
|
|
125
|
+
customerCity: '',
|
|
126
|
+
customerPostCode: '',
|
|
127
|
+
customerCountry: '',
|
|
128
|
+
customerCountryCode: '',
|
|
129
|
+
customerPhone: '',
|
|
130
|
+
customerVatId: '',
|
|
131
|
+
documentValueDate: '',
|
|
132
|
+
foreignCurrencyAmount: '',
|
|
133
|
+
currencyCode: '',
|
|
134
|
+
amountBeforeDiscount: '',
|
|
135
|
+
documentDiscount: '',
|
|
136
|
+
amountAfterDiscountExcludingVat: '',
|
|
137
|
+
vatAmount: '',
|
|
138
|
+
amountIncludingVat: document.amount.toFixed(2), // Format as decimal with 2 places
|
|
139
|
+
withholdingTaxAmount: '',
|
|
140
|
+
customerKey: '',
|
|
141
|
+
matchingField: '',
|
|
142
|
+
cancelledAttribute1: '',
|
|
143
|
+
cancelledDocument: '',
|
|
144
|
+
cancelledAttribute2: '',
|
|
145
|
+
documentDate: '',
|
|
146
|
+
branchKey: '',
|
|
147
|
+
cancelledAttribute3: '',
|
|
148
|
+
actionExecutor: '',
|
|
149
|
+
lineConnectingField: '',
|
|
150
|
+
reserved: '',
|
|
151
|
+
};
|
|
152
|
+
addRecord('C100', encodeC100(documentRecord));
|
|
153
|
+
// Document line - D110 record
|
|
154
|
+
const documentLineRecord = {
|
|
155
|
+
code: 'D110',
|
|
156
|
+
recordNumber: recordNumber.toString(),
|
|
157
|
+
vatId: input.business.taxId,
|
|
158
|
+
documentType: document.type,
|
|
159
|
+
documentNumber: document.id,
|
|
160
|
+
lineNumber: '1',
|
|
161
|
+
baseDocumentType: '',
|
|
162
|
+
baseDocumentNumber: '',
|
|
163
|
+
transactionType: '',
|
|
164
|
+
internalCatalogCode: '',
|
|
165
|
+
goodsServiceDescription: document.description || 'Item',
|
|
166
|
+
manufacturerName: '',
|
|
167
|
+
serialNumber: '',
|
|
168
|
+
unitOfMeasureDescription: '',
|
|
169
|
+
quantity: '1',
|
|
170
|
+
unitPriceExcludingVat: '',
|
|
171
|
+
lineDiscount: '',
|
|
172
|
+
lineTotal: '',
|
|
173
|
+
vatRatePercent: '',
|
|
174
|
+
reserved1: '',
|
|
175
|
+
branchId: '1',
|
|
176
|
+
reserved2: '',
|
|
177
|
+
documentDate: document.date.replace(/-/g, ''),
|
|
178
|
+
headerLinkField: '',
|
|
179
|
+
baseDocumentBranchId: '',
|
|
180
|
+
reserved3: '',
|
|
181
|
+
};
|
|
182
|
+
addRecord('D110', encodeD110(documentLineRecord));
|
|
183
|
+
// Payment record - D120 record (if applicable)
|
|
184
|
+
const paymentRecord = {
|
|
185
|
+
code: 'D120',
|
|
186
|
+
recordNumber: recordNumber.toString(),
|
|
187
|
+
vatId: input.business.taxId,
|
|
188
|
+
documentType: document.type,
|
|
189
|
+
documentNumber: document.id,
|
|
190
|
+
lineNumber: '1',
|
|
191
|
+
paymentMethod: '1', // Default payment method
|
|
192
|
+
bankNumber: '',
|
|
193
|
+
branchNumber: '',
|
|
194
|
+
accountNumber: '',
|
|
195
|
+
checkNumber: '',
|
|
196
|
+
paymentDueDate: '',
|
|
197
|
+
lineAmount: document.amount.toFixed(2), // Format as decimal with 2 places
|
|
198
|
+
acquirerCode: '',
|
|
199
|
+
cardBrand: '',
|
|
200
|
+
creditTransactionType: '',
|
|
201
|
+
firstPaymentAmount: '',
|
|
202
|
+
installmentsCount: '',
|
|
203
|
+
additionalPaymentAmount: '',
|
|
204
|
+
reserved1: '',
|
|
205
|
+
branchId: '1',
|
|
206
|
+
reserved2: '',
|
|
207
|
+
documentDate: document.date.replace(/-/g, ''),
|
|
208
|
+
headerLinkField: '',
|
|
209
|
+
reserved: '',
|
|
210
|
+
};
|
|
211
|
+
addRecord('D120', encodeD120(paymentRecord));
|
|
212
|
+
}
|
|
213
|
+
// 4. Journal lines: for each entry and its lines
|
|
214
|
+
for (const entry of input.journalEntries) {
|
|
215
|
+
const journalRecord = {
|
|
216
|
+
code: 'B100',
|
|
217
|
+
recordNumber: recordNumber.toString(),
|
|
218
|
+
vatId: input.business.taxId,
|
|
219
|
+
transactionNumber: entry.id.replace(/\D/g, '') || '1', // Extract only digits, default to '1'
|
|
220
|
+
transactionLineNumber: '1',
|
|
221
|
+
batchNumber: '',
|
|
222
|
+
transactionType: '',
|
|
223
|
+
referenceDocument: '',
|
|
224
|
+
referenceDocumentType: '',
|
|
225
|
+
referenceDocument2: '',
|
|
226
|
+
referenceDocumentType2: '',
|
|
227
|
+
details: entry.description || '',
|
|
228
|
+
date: entry.date.replace(/-/g, ''),
|
|
229
|
+
valueDate: entry.date.replace(/-/g, ''), // Same as date for simplicity
|
|
230
|
+
accountKey: entry.accountId,
|
|
231
|
+
counterAccountKey: '',
|
|
232
|
+
debitCreditIndicator: (entry.amount >= 0 ? '1' : '2'),
|
|
233
|
+
currencyCode: '',
|
|
234
|
+
transactionAmount: Math.abs(entry.amount).toFixed(2), // Format as decimal with 2 places
|
|
235
|
+
foreignCurrencyAmount: '',
|
|
236
|
+
quantityField: '',
|
|
237
|
+
matchingField1: '',
|
|
238
|
+
matchingField2: '',
|
|
239
|
+
branchId: '',
|
|
240
|
+
entryDate: entry.date.replace(/-/g, ''),
|
|
241
|
+
operatorUsername: '',
|
|
242
|
+
reserved: '',
|
|
243
|
+
};
|
|
244
|
+
addRecord('B100', encodeB100(journalRecord));
|
|
245
|
+
}
|
|
246
|
+
// 5. Accounts: B110 records
|
|
247
|
+
for (const account of input.accounts) {
|
|
248
|
+
const accountRecord = {
|
|
249
|
+
code: 'B110',
|
|
250
|
+
recordNumber: recordNumber.toString(),
|
|
251
|
+
vatId: input.business.taxId,
|
|
252
|
+
accountKey: account.id,
|
|
253
|
+
accountName: account.name,
|
|
254
|
+
trialBalanceCode: account.type,
|
|
255
|
+
trialBalanceCodeDescription: account.type,
|
|
256
|
+
customerSupplierAddressStreet: '',
|
|
257
|
+
customerSupplierAddressHouseNumber: '',
|
|
258
|
+
customerSupplierAddressCity: '',
|
|
259
|
+
customerSupplierAddressZip: '',
|
|
260
|
+
customerSupplierAddressCountry: '',
|
|
261
|
+
countryCode: '',
|
|
262
|
+
parentAccountKey: '',
|
|
263
|
+
accountOpeningBalance: '0',
|
|
264
|
+
totalDebits: '0',
|
|
265
|
+
totalCredits: '0',
|
|
266
|
+
accountingClassificationCode: '',
|
|
267
|
+
supplierCustomerTaxId: '',
|
|
268
|
+
branchId: '',
|
|
269
|
+
openingBalanceForeignCurrency: '',
|
|
270
|
+
foreignCurrencyCode: '',
|
|
271
|
+
reserved: '',
|
|
272
|
+
};
|
|
273
|
+
addRecord('B110', encodeB110(accountRecord));
|
|
274
|
+
}
|
|
275
|
+
// 6. Inventory: M100 records
|
|
276
|
+
for (const item of input.inventory) {
|
|
277
|
+
const inventoryRecord = {
|
|
278
|
+
code: 'M100',
|
|
279
|
+
recordNumber: recordNumber.toString(),
|
|
280
|
+
vatId: input.business.taxId,
|
|
281
|
+
universalItemCode: '',
|
|
282
|
+
supplierItemCode: '',
|
|
283
|
+
internalItemCode: item.id,
|
|
284
|
+
itemName: item.name,
|
|
285
|
+
classificationCode: '',
|
|
286
|
+
classificationDescription: '',
|
|
287
|
+
unitOfMeasure: '',
|
|
288
|
+
openingStock: '0',
|
|
289
|
+
totalStockIn: '0',
|
|
290
|
+
totalStockOut: item.quantity.toString(),
|
|
291
|
+
endPeriodCostNonBonded: '',
|
|
292
|
+
endPeriodCostBonded: '',
|
|
293
|
+
reserved: '',
|
|
294
|
+
};
|
|
295
|
+
addRecord('M100', encodeM100(inventoryRecord));
|
|
296
|
+
}
|
|
297
|
+
// 7. Closing record: Z900
|
|
298
|
+
const closingRecord = {
|
|
299
|
+
recordNumber: recordNumber.toString(),
|
|
300
|
+
vatId: input.business.taxId,
|
|
301
|
+
totalRecords: records.length.toString(), // Count of records before Z900 is added
|
|
302
|
+
reserved: '',
|
|
303
|
+
};
|
|
304
|
+
addRecord('Z900', encodeZ900(closingRecord));
|
|
305
|
+
// Build iniText and dataText using the assembler
|
|
306
|
+
const iniText = assembleFile(iniRecords);
|
|
307
|
+
const dataText = assembleFile(records);
|
|
308
|
+
// Create virtual File objects
|
|
309
|
+
const iniFile = new File([iniText], `${options.fileNameBase || 'report'}.INI.TXT`, {
|
|
310
|
+
type: 'text/plain',
|
|
311
|
+
});
|
|
312
|
+
const dataFile = new File([dataText], `${options.fileNameBase || 'report'}.BKMVDATA.TXT`, {
|
|
313
|
+
type: 'text/plain',
|
|
314
|
+
});
|
|
315
|
+
return {
|
|
316
|
+
iniText,
|
|
317
|
+
dataText,
|
|
318
|
+
iniFile,
|
|
319
|
+
dataFile,
|
|
320
|
+
summary: {
|
|
321
|
+
totalRecords: records.length + iniRecords.length,
|
|
322
|
+
perType: recordCounts,
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed-width formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
import { CRLF } from '../../format/newline.js';
|
|
5
|
+
import { padLeft, padRight } from '../../format/padding.js';
|
|
6
|
+
/**
|
|
7
|
+
* Formats a field value with specified width and alignment
|
|
8
|
+
*
|
|
9
|
+
* @param value - The value to format
|
|
10
|
+
* @param width - Target field width
|
|
11
|
+
* @param align - Alignment ('left' or 'right')
|
|
12
|
+
* @param padChar - Character to use for padding (default: space)
|
|
13
|
+
* @returns Formatted fixed-width string
|
|
14
|
+
*/
|
|
15
|
+
export function formatField(value, width, align, padChar = ' ') {
|
|
16
|
+
if (align === 'left') {
|
|
17
|
+
return padRight(value, width, padChar);
|
|
18
|
+
}
|
|
19
|
+
return padLeft(value, width, padChar);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Encodes a value to fixed-width format with padding
|
|
23
|
+
*
|
|
24
|
+
* @param value - The value to encode
|
|
25
|
+
* @param width - Target width
|
|
26
|
+
* @param padChar - Padding character (default: space)
|
|
27
|
+
* @param align - Alignment ('left' or 'right')
|
|
28
|
+
* @returns Fixed-width encoded string
|
|
29
|
+
*/
|
|
30
|
+
export function encodeFixedWidth(value, width, padChar = ' ', align = 'left') {
|
|
31
|
+
const str = String(value);
|
|
32
|
+
return formatField(str, width, align, padChar);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Helper function to format numeric fields with zero padding
|
|
36
|
+
*/
|
|
37
|
+
export function formatNumericField(value, width) {
|
|
38
|
+
return padLeft(value, width, '0');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Joins an array of field values into a single record line with CRLF ending
|
|
42
|
+
* This is used by individual record encoders to create their output
|
|
43
|
+
*
|
|
44
|
+
* @param fields - Array of formatted field values
|
|
45
|
+
* @returns Single record line ending with CRLF
|
|
46
|
+
*/
|
|
47
|
+
export function joinFields(fields) {
|
|
48
|
+
return fields.join('') + CRLF;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Joins an array of record lines that already have CRLF endings
|
|
52
|
+
*
|
|
53
|
+
* @param lines - Array of record lines to join (each line should already end with CRLF)
|
|
54
|
+
* @returns Joined string
|
|
55
|
+
*/
|
|
56
|
+
export function joinRecords(lines) {
|
|
57
|
+
return lines.join('');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Joins an array of record lines and adds CRLF to each line
|
|
61
|
+
*
|
|
62
|
+
* @param lines - Array of record lines to join (without CRLF endings)
|
|
63
|
+
* @returns Joined string with CRLF line endings
|
|
64
|
+
*/
|
|
65
|
+
export function joinLinesWithCRLF(lines) {
|
|
66
|
+
return lines.map(line => line + CRLF).join('');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Creates a complete SHAAM format file by joining records
|
|
70
|
+
* This is the main function for assembling final file content
|
|
71
|
+
*
|
|
72
|
+
* @param records - Array of encoded record strings (each already ending with CRLF)
|
|
73
|
+
* @returns Complete file content ready for output
|
|
74
|
+
*/
|
|
75
|
+
export function assembleFile(records) {
|
|
76
|
+
return joinRecords(records);
|
|
77
|
+
}
|