datera 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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -0
  3. package/dist/api/clean.d.ts +138 -0
  4. package/dist/api/clean.js +138 -0
  5. package/dist/api/formats.d.ts +19 -0
  6. package/dist/api/formats.js +106 -0
  7. package/dist/api/index.d.ts +8 -0
  8. package/dist/api/index.js +27 -0
  9. package/dist/api/inspect.d.ts +13 -0
  10. package/dist/api/inspect.js +44 -0
  11. package/dist/api/parse.d.ts +2 -0
  12. package/dist/api/parse.js +19 -0
  13. package/dist/api/rows.d.ts +23 -0
  14. package/dist/api/rows.js +63 -0
  15. package/dist/cli.d.ts +62 -0
  16. package/dist/cli.js +225 -0
  17. package/dist/commands.d.ts +3 -0
  18. package/dist/commands.js +169 -0
  19. package/dist/config/check.d.ts +11 -0
  20. package/dist/config/check.js +99 -0
  21. package/dist/config/index.d.ts +7 -0
  22. package/dist/config/index.js +16 -0
  23. package/dist/config/ioSchema.d.ts +97 -0
  24. package/dist/config/ioSchema.js +111 -0
  25. package/dist/config/load.d.ts +5 -0
  26. package/dist/config/load.js +68 -0
  27. package/dist/config/mergeSchema.d.ts +36 -0
  28. package/dist/config/mergeSchema.js +46 -0
  29. package/dist/config/messages.d.ts +7 -0
  30. package/dist/config/messages.js +33 -0
  31. package/dist/config/prepareSchema.d.ts +12 -0
  32. package/dist/config/prepareSchema.js +15 -0
  33. package/dist/config/schema.d.ts +195 -0
  34. package/dist/config/schema.js +44 -0
  35. package/dist/config/validationSchema.d.ts +27 -0
  36. package/dist/config/validationSchema.js +50 -0
  37. package/dist/env.d.ts +2 -0
  38. package/dist/env.js +15 -0
  39. package/dist/filters/combine.d.ts +10 -0
  40. package/dist/filters/combine.js +60 -0
  41. package/dist/filters/combineTypes.d.ts +6 -0
  42. package/dist/filters/combineTypes.js +2 -0
  43. package/dist/filters/dedupe.d.ts +12 -0
  44. package/dist/filters/dedupe.js +45 -0
  45. package/dist/filters/fillEmpty.d.ts +9 -0
  46. package/dist/filters/fillEmpty.js +32 -0
  47. package/dist/filters/fillEmptyTypes.d.ts +5 -0
  48. package/dist/filters/fillEmptyTypes.js +2 -0
  49. package/dist/filters/merge.d.ts +15 -0
  50. package/dist/filters/merge.js +113 -0
  51. package/dist/filters/mergeStrategies.d.ts +10 -0
  52. package/dist/filters/mergeStrategies.js +69 -0
  53. package/dist/filters/mergeTypes.d.ts +32 -0
  54. package/dist/filters/mergeTypes.js +2 -0
  55. package/dist/filters/mergeUnkeyed.d.ts +3 -0
  56. package/dist/filters/mergeUnkeyed.js +21 -0
  57. package/dist/filters/types.d.ts +3 -0
  58. package/dist/filters/types.js +2 -0
  59. package/dist/filters/validate.d.ts +16 -0
  60. package/dist/filters/validate.js +79 -0
  61. package/dist/filters/validateTypes.d.ts +28 -0
  62. package/dist/filters/validateTypes.js +2 -0
  63. package/dist/index.d.ts +13 -0
  64. package/dist/index.js +40 -0
  65. package/dist/io/csv/csvFormat.d.ts +4 -0
  66. package/dist/io/csv/csvFormat.js +94 -0
  67. package/dist/io/csv/csvSink.d.ts +14 -0
  68. package/dist/io/csv/csvSink.js +32 -0
  69. package/dist/io/csv/csvSource.d.ts +13 -0
  70. package/dist/io/csv/csvSource.js +29 -0
  71. package/dist/io/custom/loader.d.ts +1 -0
  72. package/dist/io/custom/loader.js +36 -0
  73. package/dist/io/custom/registry.d.ts +13 -0
  74. package/dist/io/custom/registry.js +50 -0
  75. package/dist/io/excel/excelCell.d.ts +4 -0
  76. package/dist/io/excel/excelCell.js +29 -0
  77. package/dist/io/excel/excelSink.d.ts +14 -0
  78. package/dist/io/excel/excelSink.js +57 -0
  79. package/dist/io/excel/excelSource.d.ts +11 -0
  80. package/dist/io/excel/excelSource.js +47 -0
  81. package/dist/io/excel/workbook.d.ts +4 -0
  82. package/dist/io/excel/workbook.js +20 -0
  83. package/dist/io/factory.d.ts +5 -0
  84. package/dist/io/factory.js +106 -0
  85. package/dist/io/files.d.ts +7 -0
  86. package/dist/io/files.js +48 -0
  87. package/dist/io/header.d.ts +2 -0
  88. package/dist/io/header.js +42 -0
  89. package/dist/io/json/jsonSink.d.ts +12 -0
  90. package/dist/io/json/jsonSink.js +19 -0
  91. package/dist/io/json/jsonSource.d.ts +11 -0
  92. package/dist/io/json/jsonSource.js +66 -0
  93. package/dist/io/mysql/client.d.ts +13 -0
  94. package/dist/io/mysql/client.js +73 -0
  95. package/dist/io/mysql/mysqlSource.d.ts +13 -0
  96. package/dist/io/mysql/mysqlSource.js +25 -0
  97. package/dist/io/optional.d.ts +2 -0
  98. package/dist/io/optional.js +36 -0
  99. package/dist/io/parquet/parquetLibrary.d.ts +11 -0
  100. package/dist/io/parquet/parquetLibrary.js +20 -0
  101. package/dist/io/parquet/parquetSink.d.ts +15 -0
  102. package/dist/io/parquet/parquetSink.js +58 -0
  103. package/dist/io/parquet/parquetSource.d.ts +13 -0
  104. package/dist/io/parquet/parquetSource.js +68 -0
  105. package/dist/io/postgres/postgresSource.d.ts +26 -0
  106. package/dist/io/postgres/postgresSource.js +42 -0
  107. package/dist/io/safety.d.ts +4 -0
  108. package/dist/io/safety.js +83 -0
  109. package/dist/io/sheets/client.d.ts +10 -0
  110. package/dist/io/sheets/client.js +141 -0
  111. package/dist/io/sheets/sheetsSink.d.ts +12 -0
  112. package/dist/io/sheets/sheetsSink.js +24 -0
  113. package/dist/io/sheets/sheetsSource.d.ts +10 -0
  114. package/dist/io/sheets/sheetsSource.js +47 -0
  115. package/dist/io/sql/cell.d.ts +5 -0
  116. package/dist/io/sql/cell.js +38 -0
  117. package/dist/io/sql/driver.d.ts +1 -0
  118. package/dist/io/sql/driver.js +15 -0
  119. package/dist/io/sql/names.d.ts +1 -0
  120. package/dist/io/sql/names.js +12 -0
  121. package/dist/io/sqlite/sqliteSource.d.ts +11 -0
  122. package/dist/io/sqlite/sqliteSource.js +52 -0
  123. package/dist/io/sqlserver/sqlServerSource.d.ts +24 -0
  124. package/dist/io/sqlserver/sqlServerSource.js +49 -0
  125. package/dist/io/types.d.ts +11 -0
  126. package/dist/io/types.js +2 -0
  127. package/dist/io/xml/xmlParse.d.ts +9 -0
  128. package/dist/io/xml/xmlParse.js +178 -0
  129. package/dist/io/xml/xmlSink.d.ts +18 -0
  130. package/dist/io/xml/xmlSink.js +79 -0
  131. package/dist/io/xml/xmlSource.d.ts +11 -0
  132. package/dist/io/xml/xmlSource.js +93 -0
  133. package/dist/logger.d.ts +11 -0
  134. package/dist/logger.js +29 -0
  135. package/dist/main.d.ts +2 -0
  136. package/dist/main.js +18 -0
  137. package/dist/normalizers/builtin.d.ts +5 -0
  138. package/dist/normalizers/builtin.js +23 -0
  139. package/dist/normalizers/index.d.ts +2 -0
  140. package/dist/normalizers/index.js +14 -0
  141. package/dist/normalizers/loader.d.ts +1 -0
  142. package/dist/normalizers/loader.js +30 -0
  143. package/dist/normalizers/registry.d.ts +9 -0
  144. package/dist/normalizers/registry.js +29 -0
  145. package/dist/pipeline/index.d.ts +7 -0
  146. package/dist/pipeline/index.js +17 -0
  147. package/dist/pipeline/modes.d.ts +6 -0
  148. package/dist/pipeline/modes.js +48 -0
  149. package/dist/pipeline/report.d.ts +3 -0
  150. package/dist/pipeline/report.js +32 -0
  151. package/dist/pipeline/runEtl.d.ts +24 -0
  152. package/dist/pipeline/runEtl.js +98 -0
  153. package/dist/pipeline/steps.d.ts +4 -0
  154. package/dist/pipeline/steps.js +36 -0
  155. package/dist/pipeline/types.d.ts +34 -0
  156. package/dist/pipeline/types.js +2 -0
  157. package/dist/types.d.ts +3 -0
  158. package/dist/types.js +2 -0
  159. package/package.json +128 -0
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RowValidator = exports.DEFAULT_REASON_COLUMN = exports.DEFAULT_PENDING_SHEET = void 0;
4
+ const registry_1 = require("../normalizers/registry");
5
+ exports.DEFAULT_PENDING_SHEET = "Pendências";
6
+ exports.DEFAULT_REASON_COLUMN = "Motivo";
7
+ class RowValidator {
8
+ reasonColumn;
9
+ checks;
10
+ constructor(rules, reasonColumn = exports.DEFAULT_REASON_COLUMN) {
11
+ this.reasonColumn = reasonColumn;
12
+ this.checks = rules.map((rule) => this.buildCheck(rule));
13
+ }
14
+ split(rows) {
15
+ const valid = [];
16
+ const pending = [];
17
+ for (const row of rows) {
18
+ const reasons = this.checks
19
+ .filter((check) => !this.passes(check, row[check.column]))
20
+ .map((check) => check.message);
21
+ if (reasons.length === 0) {
22
+ valid.push(row);
23
+ continue;
24
+ }
25
+ const withReason = { [this.reasonColumn]: null, ...row };
26
+ withReason[this.reasonColumn] = Array.from(new Set(reasons)).join("; ");
27
+ pending.push(withReason);
28
+ }
29
+ return { valid, pending };
30
+ }
31
+ passes(check, value) {
32
+ const text = value === null || value === undefined ? "" : String(value).trim();
33
+ if (text === "")
34
+ return check.skipEmpty;
35
+ return check.isValid(text);
36
+ }
37
+ buildCheck(rule) {
38
+ const { column } = rule;
39
+ switch (rule.rule) {
40
+ case "required":
41
+ return {
42
+ column,
43
+ message: rule.message ?? `${column} vazio`,
44
+ skipEmpty: false,
45
+ isValid: () => true,
46
+ };
47
+ case "pattern": {
48
+ const flags = (rule.flags ?? "").replace(/[gy]/g, "");
49
+ const regex = new RegExp(rule.pattern, flags);
50
+ return {
51
+ column,
52
+ message: rule.message ?? `${column} fora do formato`,
53
+ skipEmpty: true,
54
+ isValid: (text) => regex.test(text),
55
+ };
56
+ }
57
+ case "oneOf": {
58
+ const normalize = (text) => rule.ignoreCase ? text.toLowerCase() : text;
59
+ const allowed = new Set(rule.values.map((v) => normalize(v.trim())));
60
+ return {
61
+ column,
62
+ message: rule.message ?? `${column} com valor não permitido`,
63
+ skipEmpty: true,
64
+ isValid: (text) => allowed.has(normalize(text)),
65
+ };
66
+ }
67
+ case "normalizer": {
68
+ const normalizer = (0, registry_1.getKeyNormalizer)(rule.normalizer);
69
+ return {
70
+ column,
71
+ message: rule.message ?? `${column} inválido`,
72
+ skipEmpty: true,
73
+ isValid: (text) => normalizer(text) !== null,
74
+ };
75
+ }
76
+ }
77
+ }
78
+ }
79
+ exports.RowValidator = RowValidator;
@@ -0,0 +1,28 @@
1
+ interface BaseRule {
2
+ column: string;
3
+ message?: string | undefined;
4
+ }
5
+ export interface RequiredRule extends BaseRule {
6
+ rule: "required";
7
+ }
8
+ export interface PatternRule extends BaseRule {
9
+ rule: "pattern";
10
+ pattern: string;
11
+ flags?: string | undefined;
12
+ }
13
+ export interface OneOfRule extends BaseRule {
14
+ rule: "oneOf";
15
+ values: string[];
16
+ ignoreCase?: boolean | undefined;
17
+ }
18
+ export interface NormalizerRule extends BaseRule {
19
+ rule: "normalizer";
20
+ normalizer: string;
21
+ }
22
+ export type ValidationRule = RequiredRule | PatternRule | OneOfRule | NormalizerRule;
23
+ export interface ValidationConfig {
24
+ rules: ValidationRule[];
25
+ pendingSheet?: string | undefined;
26
+ reasonColumn?: string | undefined;
27
+ }
28
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ export * from "./api";
2
+ export { runEtl, applySteps, formatReport, parseMode, MODES } from "./pipeline";
3
+ export type { RunEtlOptions, EtlReport, StepReport, PendingReason, Mode, } from "./pipeline";
4
+ export { loadConfig, loadJsonConfig, parseConfig, etlConfigSchema, checkConfigFile, checkConfigText, } from "./config";
5
+ export type { EtlConfig, SourceConfig, DestinationConfig, ConfigCheck, ConfigProblem, } from "./config";
6
+ export { consoleLogger, silentLogger, createMemoryLogger } from "./logger";
7
+ export type { Logger, MemoryLogger } from "./logger";
8
+ export type { Source, Sink, SinkWriteOptions } from "./io/types";
9
+ export { registerSourceAdapter, registerSinkAdapter, } from "./io/custom/registry";
10
+ export type { AdapterContext, AdapterOptions } from "./io/custom/registry";
11
+ export { registerKeyNormalizer } from "./normalizers/registry";
12
+ export type { KeyNormalizer, NormalizedKey } from "./normalizers/registry";
13
+ export type { TableRow } from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.registerKeyNormalizer = exports.registerSinkAdapter = exports.registerSourceAdapter = exports.createMemoryLogger = exports.silentLogger = exports.consoleLogger = exports.checkConfigText = exports.checkConfigFile = exports.etlConfigSchema = exports.parseConfig = exports.loadJsonConfig = exports.loadConfig = exports.MODES = exports.parseMode = exports.formatReport = exports.applySteps = exports.runEtl = void 0;
18
+ __exportStar(require("./api"), exports);
19
+ var pipeline_1 = require("./pipeline");
20
+ Object.defineProperty(exports, "runEtl", { enumerable: true, get: function () { return pipeline_1.runEtl; } });
21
+ Object.defineProperty(exports, "applySteps", { enumerable: true, get: function () { return pipeline_1.applySteps; } });
22
+ Object.defineProperty(exports, "formatReport", { enumerable: true, get: function () { return pipeline_1.formatReport; } });
23
+ Object.defineProperty(exports, "parseMode", { enumerable: true, get: function () { return pipeline_1.parseMode; } });
24
+ Object.defineProperty(exports, "MODES", { enumerable: true, get: function () { return pipeline_1.MODES; } });
25
+ var config_1 = require("./config");
26
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
27
+ Object.defineProperty(exports, "loadJsonConfig", { enumerable: true, get: function () { return config_1.loadJsonConfig; } });
28
+ Object.defineProperty(exports, "parseConfig", { enumerable: true, get: function () { return config_1.parseConfig; } });
29
+ Object.defineProperty(exports, "etlConfigSchema", { enumerable: true, get: function () { return config_1.etlConfigSchema; } });
30
+ Object.defineProperty(exports, "checkConfigFile", { enumerable: true, get: function () { return config_1.checkConfigFile; } });
31
+ Object.defineProperty(exports, "checkConfigText", { enumerable: true, get: function () { return config_1.checkConfigText; } });
32
+ var logger_1 = require("./logger");
33
+ Object.defineProperty(exports, "consoleLogger", { enumerable: true, get: function () { return logger_1.consoleLogger; } });
34
+ Object.defineProperty(exports, "silentLogger", { enumerable: true, get: function () { return logger_1.silentLogger; } });
35
+ Object.defineProperty(exports, "createMemoryLogger", { enumerable: true, get: function () { return logger_1.createMemoryLogger; } });
36
+ var registry_1 = require("./io/custom/registry");
37
+ Object.defineProperty(exports, "registerSourceAdapter", { enumerable: true, get: function () { return registry_1.registerSourceAdapter; } });
38
+ Object.defineProperty(exports, "registerSinkAdapter", { enumerable: true, get: function () { return registry_1.registerSinkAdapter; } });
39
+ var registry_2 = require("./normalizers/registry");
40
+ Object.defineProperty(exports, "registerKeyNormalizer", { enumerable: true, get: function () { return registry_2.registerKeyNormalizer; } });
@@ -0,0 +1,4 @@
1
+ export declare function stripBom(text: string): string;
2
+ export declare function detectDelimiter(text: string): string;
3
+ export declare function parseCsv(text: string, delimiter: string): string[][];
4
+ export declare function toCsv(rows: string[][], delimiter: string): string;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stripBom = stripBom;
4
+ exports.detectDelimiter = detectDelimiter;
5
+ exports.parseCsv = parseCsv;
6
+ exports.toCsv = toCsv;
7
+ const BOM = "\uFEFF";
8
+ const CANDIDATE_DELIMITERS = [",", ";", "\t", "|"];
9
+ function stripBom(text) {
10
+ return text.startsWith(BOM) ? text.slice(1) : text;
11
+ }
12
+ function detectDelimiter(text) {
13
+ let best = ",";
14
+ let bestCount = 0;
15
+ for (const delimiter of CANDIDATE_DELIMITERS) {
16
+ let count = 0;
17
+ let inQuotes = false;
18
+ for (const char of text) {
19
+ if (char === '"')
20
+ inQuotes = !inQuotes;
21
+ else if (!inQuotes && (char === "\n" || char === "\r"))
22
+ break;
23
+ else if (!inQuotes && char === delimiter)
24
+ count++;
25
+ }
26
+ if (count > bestCount) {
27
+ best = delimiter;
28
+ bestCount = count;
29
+ }
30
+ }
31
+ return best;
32
+ }
33
+ function parseCsv(text, delimiter) {
34
+ const rows = [];
35
+ let row = [];
36
+ let field = "";
37
+ let inQuotes = false;
38
+ for (let i = 0; i < text.length; i++) {
39
+ const char = text.charAt(i);
40
+ if (inQuotes) {
41
+ if (char === '"' && text[i + 1] === '"') {
42
+ field += '"';
43
+ i++;
44
+ }
45
+ else if (char === '"') {
46
+ inQuotes = false;
47
+ }
48
+ else {
49
+ field += char;
50
+ }
51
+ continue;
52
+ }
53
+ if (char === '"') {
54
+ inQuotes = true;
55
+ }
56
+ else if (text.startsWith(delimiter, i)) {
57
+ row.push(field);
58
+ field = "";
59
+ i += delimiter.length - 1;
60
+ }
61
+ else if (char === "\n" || char === "\r") {
62
+ if (char === "\r" && text[i + 1] === "\n")
63
+ i++;
64
+ row.push(field);
65
+ rows.push(row);
66
+ row = [];
67
+ field = "";
68
+ }
69
+ else {
70
+ field += char;
71
+ }
72
+ }
73
+ if (inQuotes) {
74
+ throw new Error("CSV com aspas abertas que nunca fecham.");
75
+ }
76
+ if (field !== "" || row.length > 0) {
77
+ row.push(field);
78
+ rows.push(row);
79
+ }
80
+ return rows.filter((r) => !(r.length === 1 && r[0] === ""));
81
+ }
82
+ function escapeField(value, delimiter) {
83
+ const needsQuotes = value.includes(delimiter) ||
84
+ value.includes('"') ||
85
+ value.includes("\n") ||
86
+ value.includes("\r") ||
87
+ value !== value.trim();
88
+ return needsQuotes ? `"${value.replace(/"/g, '""')}"` : value;
89
+ }
90
+ function toCsv(rows, delimiter) {
91
+ return rows
92
+ .map((row) => row.map((value) => escapeField(value, delimiter)).join(delimiter))
93
+ .join("\r\n");
94
+ }
@@ -0,0 +1,14 @@
1
+ import { TableRow } from "../../types";
2
+ import { Sink, SinkWriteOptions } from "../types";
3
+ import { Logger } from "../../logger";
4
+ export interface CsvSinkOptions {
5
+ path: string;
6
+ delimiter?: string | undefined;
7
+ bom?: boolean | undefined;
8
+ }
9
+ export declare class CsvSink implements Sink {
10
+ private readonly options;
11
+ private readonly logger;
12
+ constructor(options: CsvSinkOptions, logger?: Logger);
13
+ write(rows: TableRow[], options?: SinkWriteOptions): Promise<void>;
14
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CsvSink = void 0;
4
+ const header_1 = require("../header");
5
+ const csvFormat_1 = require("./csvFormat");
6
+ const files_1 = require("../files");
7
+ const logger_1 = require("../../logger");
8
+ class CsvSink {
9
+ options;
10
+ logger;
11
+ constructor(options, logger = logger_1.consoleLogger) {
12
+ this.options = options;
13
+ this.logger = logger;
14
+ }
15
+ async write(rows, options = {}) {
16
+ const filePath = (0, files_1.extraOutputPath)(this.options.path, options.name);
17
+ const header = (0, header_1.buildHeader)(rows);
18
+ const lines = rows.map((row) => header.map((column) => {
19
+ const value = row[column];
20
+ return value === null || value === undefined
21
+ ? ""
22
+ : String(value);
23
+ }));
24
+ const content = rows.length === 0
25
+ ? ""
26
+ : (0, csvFormat_1.toCsv)([header, ...lines], this.options.delimiter ?? ",");
27
+ const bom = (this.options.bom ?? true) ? "\uFEFF" : "";
28
+ (0, files_1.writeTextFile)(filePath, bom + content + (content ? "\r\n" : ""));
29
+ this.logger.info(`${rows.length} linhas escritas em ${filePath}.`);
30
+ }
31
+ }
32
+ exports.CsvSink = CsvSink;
@@ -0,0 +1,13 @@
1
+ import { TableRow } from "../../types";
2
+ import { Source } from "../types";
3
+ import { FileEncoding } from "../files";
4
+ export interface CsvSourceOptions {
5
+ path: string;
6
+ delimiter?: string | undefined;
7
+ encoding?: FileEncoding | undefined;
8
+ }
9
+ export declare class CsvSource implements Source {
10
+ private readonly options;
11
+ constructor(options: CsvSourceOptions);
12
+ read(): Promise<TableRow[]>;
13
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CsvSource = void 0;
4
+ const csvFormat_1 = require("./csvFormat");
5
+ const files_1 = require("../files");
6
+ class CsvSource {
7
+ options;
8
+ constructor(options) {
9
+ this.options = options;
10
+ }
11
+ async read() {
12
+ const text = (0, csvFormat_1.stripBom)((0, files_1.readTextFile)(this.options.path, this.options.encoding));
13
+ const delimiter = this.options.delimiter ?? (0, csvFormat_1.detectDelimiter)(text);
14
+ const [header, ...lines] = (0, csvFormat_1.parseCsv)(text, delimiter);
15
+ if (!header)
16
+ return [];
17
+ const columns = header.map((column) => column.trim());
18
+ return lines.map((values) => {
19
+ const row = {};
20
+ columns.forEach((column, index) => {
21
+ const value = values[index];
22
+ row[column] =
23
+ value === undefined || value === "" ? null : value;
24
+ });
25
+ return row;
26
+ });
27
+ }
28
+ }
29
+ exports.CsvSource = CsvSource;
@@ -0,0 +1 @@
1
+ export declare function loadAdapterModules(modulePaths: string[]): void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadAdapterModules = loadAdapterModules;
7
+ const path_1 = __importDefault(require("path"));
8
+ const registry_1 = require("./registry");
9
+ function registerAll(modulePath, group, register) {
10
+ for (const [name, factory] of Object.entries(group ?? {})) {
11
+ if (typeof factory !== "function") {
12
+ throw new Error(`Em "${modulePath}", "${name}" não é uma função.`);
13
+ }
14
+ register(name, factory);
15
+ }
16
+ }
17
+ function loadAdapterModules(modulePaths) {
18
+ for (const modulePath of modulePaths) {
19
+ let loaded;
20
+ try {
21
+ loaded = require(path_1.default.resolve(modulePath));
22
+ }
23
+ catch (error) {
24
+ const reason = error instanceof Error ? error.message : String(error);
25
+ throw new Error(`Não consegui carregar o módulo de adapters "${modulePath}": ${reason}`);
26
+ }
27
+ const adapters = (loaded ?? {});
28
+ const hasSources = typeof adapters.sources === "object" && adapters.sources !== null;
29
+ const hasSinks = typeof adapters.sinks === "object" && adapters.sinks !== null;
30
+ if (!hasSources && !hasSinks) {
31
+ throw new Error(`O módulo "${modulePath}" precisa exportar um objeto "sources", um objeto "sinks" ou os dois. Exemplo: export const sources = { minhaFonte };`);
32
+ }
33
+ registerAll(modulePath, adapters.sources, registry_1.registerSourceAdapter);
34
+ registerAll(modulePath, adapters.sinks, registry_1.registerSinkAdapter);
35
+ }
36
+ }
@@ -0,0 +1,13 @@
1
+ import { Sink, Source } from "../types";
2
+ import { Logger } from "../../logger";
3
+ export type AdapterOptions = Record<string, unknown>;
4
+ export interface AdapterContext {
5
+ logger: Logger;
6
+ }
7
+ export type SourceFactory = (options: AdapterOptions, context: AdapterContext) => Source;
8
+ export type SinkFactory = (options: AdapterOptions, context: AdapterContext) => Sink;
9
+ export declare function registerSourceAdapter(name: string, factory: SourceFactory): void;
10
+ export declare function registerSinkAdapter(name: string, factory: SinkFactory): void;
11
+ export declare function createCustomSource(name: string, options: AdapterOptions, logger?: Logger): Source;
12
+ export declare function createCustomSink(name: string, options: AdapterOptions, logger?: Logger): Sink;
13
+ export declare function clearCustomAdapters(): void;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSourceAdapter = registerSourceAdapter;
4
+ exports.registerSinkAdapter = registerSinkAdapter;
5
+ exports.createCustomSource = createCustomSource;
6
+ exports.createCustomSink = createCustomSink;
7
+ exports.clearCustomAdapters = clearCustomAdapters;
8
+ const logger_1 = require("../../logger");
9
+ const sources = new Map();
10
+ const sinks = new Map();
11
+ function register(registry, kind, name, factory) {
12
+ const existing = registry.get(name);
13
+ if (existing && existing !== factory) {
14
+ throw new Error(`Já existe ${kind} registrado com o nome "${name}".`);
15
+ }
16
+ registry.set(name, factory);
17
+ }
18
+ function find(registry, kind, name) {
19
+ const factory = registry.get(name);
20
+ if (!factory) {
21
+ const available = Array.from(registry.keys());
22
+ const hint = available.length > 0 ? available.join(", ") : "nenhum registrado";
23
+ throw new Error(`${kind} "${name}" não encontrado. Disponíveis: ${hint}`);
24
+ }
25
+ return factory;
26
+ }
27
+ function registerSourceAdapter(name, factory) {
28
+ register(sources, "uma fonte", name, factory);
29
+ }
30
+ function registerSinkAdapter(name, factory) {
31
+ register(sinks, "um destino", name, factory);
32
+ }
33
+ function createCustomSource(name, options, logger = logger_1.consoleLogger) {
34
+ const source = find(sources, "Fonte", name)(options, { logger });
35
+ if (typeof source?.read !== "function") {
36
+ throw new Error(`A fonte "${name}" precisa devolver um objeto com o método read().`);
37
+ }
38
+ return source;
39
+ }
40
+ function createCustomSink(name, options, logger = logger_1.consoleLogger) {
41
+ const sink = find(sinks, "Destino", name)(options, { logger });
42
+ if (typeof sink?.write !== "function") {
43
+ throw new Error(`O destino "${name}" precisa devolver um objeto com o método write().`);
44
+ }
45
+ return sink;
46
+ }
47
+ function clearCustomAdapters() {
48
+ sources.clear();
49
+ sinks.clear();
50
+ }
@@ -0,0 +1,4 @@
1
+ import type { CellValue as ExcelCellValue } from "exceljs";
2
+ type CellValue = string | number | null;
3
+ export declare function fromExcelCell(value: ExcelCellValue | undefined): CellValue;
4
+ export {};
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fromExcelCell = fromExcelCell;
4
+ function isoDate(date) {
5
+ const iso = date.toISOString();
6
+ return iso.endsWith("T00:00:00.000Z") ? iso.slice(0, 10) : iso;
7
+ }
8
+ function fromExcelCell(value) {
9
+ if (value === null || value === undefined)
10
+ return null;
11
+ if (typeof value === "number")
12
+ return value;
13
+ if (typeof value === "string")
14
+ return value === "" ? null : value;
15
+ if (typeof value === "boolean")
16
+ return String(value);
17
+ if (value instanceof Date)
18
+ return isoDate(value);
19
+ if ("richText" in value) {
20
+ return fromExcelCell(value.richText.map((part) => part.text).join(""));
21
+ }
22
+ if ("formula" in value || "sharedFormula" in value) {
23
+ return fromExcelCell(value.result);
24
+ }
25
+ if ("hyperlink" in value) {
26
+ return fromExcelCell(value.text);
27
+ }
28
+ return null;
29
+ }
@@ -0,0 +1,14 @@
1
+ import { TableRow } from "../../types";
2
+ import { Sink, SinkWriteOptions } from "../types";
3
+ import { Logger } from "../../logger";
4
+ export interface ExcelSinkOptions {
5
+ path: string;
6
+ sheet?: string | undefined;
7
+ }
8
+ export declare function safeSheetName(name: string): string;
9
+ export declare class ExcelSink implements Sink {
10
+ private readonly options;
11
+ private readonly logger;
12
+ constructor(options: ExcelSinkOptions, logger?: Logger);
13
+ write(rows: TableRow[], options?: SinkWriteOptions): Promise<void>;
14
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ExcelSink = void 0;
7
+ exports.safeSheetName = safeSheetName;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const header_1 = require("../header");
10
+ const workbook_1 = require("./workbook");
11
+ const logger_1 = require("../../logger");
12
+ const DEFAULT_SHEET = "Dados";
13
+ const MAX_SHEET_NAME = 31;
14
+ function safeSheetName(name) {
15
+ const clean = name
16
+ .replace(/[[\]:*?/\\]/g, " ")
17
+ .trim()
18
+ .slice(0, MAX_SHEET_NAME);
19
+ return clean || DEFAULT_SHEET;
20
+ }
21
+ class ExcelSink {
22
+ options;
23
+ logger;
24
+ constructor(options, logger = logger_1.consoleLogger) {
25
+ this.options = options;
26
+ this.logger = logger;
27
+ }
28
+ async write(rows, options = {}) {
29
+ const isMain = options.name === undefined;
30
+ const sheetName = safeSheetName(options.name ?? this.options.sheet ?? DEFAULT_SHEET);
31
+ const workbook = !isMain && fs_1.default.existsSync(this.options.path)
32
+ ? await (0, workbook_1.openWorkbook)(this.options.path)
33
+ : (0, workbook_1.createWorkbook)();
34
+ if (!isMain) {
35
+ const old = workbook.getWorksheet(sheetName);
36
+ if (old)
37
+ workbook.removeWorksheet(old.id);
38
+ }
39
+ const worksheet = workbook.addWorksheet(sheetName, {
40
+ views: [{ state: "frozen", ySplit: 1 }],
41
+ });
42
+ const header = (0, header_1.buildHeader)(rows);
43
+ if (header.length > 0) {
44
+ worksheet.addRow(header).font = { bold: true };
45
+ for (const row of rows) {
46
+ worksheet.addRow(header.map((column) => row[column] ?? null));
47
+ }
48
+ header.forEach((column, index) => {
49
+ const longest = Math.max(column.length, ...rows.map((row) => String(row[column] ?? "").length));
50
+ worksheet.getColumn(index + 1).width = Math.min(Math.max(longest + 2, 10), 50);
51
+ });
52
+ }
53
+ await (0, workbook_1.saveWorkbook)(workbook, this.options.path);
54
+ this.logger.info(`${rows.length} linhas escritas na aba "${sheetName}" de ${this.options.path}.`);
55
+ }
56
+ }
57
+ exports.ExcelSink = ExcelSink;
@@ -0,0 +1,11 @@
1
+ import { TableRow } from "../../types";
2
+ import { Source } from "../types";
3
+ export interface ExcelSourceOptions {
4
+ path: string;
5
+ sheet?: string | undefined;
6
+ }
7
+ export declare class ExcelSource implements Source {
8
+ private readonly options;
9
+ constructor(options: ExcelSourceOptions);
10
+ read(): Promise<TableRow[]>;
11
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExcelSource = void 0;
4
+ const workbook_1 = require("./workbook");
5
+ const excelCell_1 = require("./excelCell");
6
+ class ExcelSource {
7
+ options;
8
+ constructor(options) {
9
+ this.options = options;
10
+ }
11
+ async read() {
12
+ const workbook = await (0, workbook_1.openWorkbook)(this.options.path);
13
+ const sheetName = this.options.sheet;
14
+ const worksheet = sheetName === undefined
15
+ ? workbook.worksheets[0]
16
+ : workbook.getWorksheet(sheetName);
17
+ if (!worksheet) {
18
+ const names = workbook.worksheets.map((ws) => ws.name).join(", ");
19
+ throw new Error(sheetName === undefined
20
+ ? `O arquivo ${this.options.path} não tem nenhuma aba.`
21
+ : `Aba "${sheetName}" não encontrada em ${this.options.path}. Abas: ${names}`);
22
+ }
23
+ const header = new Map();
24
+ worksheet.getRow(1).eachCell((cell, column) => {
25
+ const name = (0, excelCell_1.fromExcelCell)(cell.value);
26
+ if (name !== null)
27
+ header.set(column, String(name).trim());
28
+ });
29
+ const rows = [];
30
+ worksheet.eachRow((excelRow, rowNumber) => {
31
+ if (rowNumber === 1)
32
+ return;
33
+ const row = {};
34
+ let hasValue = false;
35
+ for (const [column, name] of header) {
36
+ const value = (0, excelCell_1.fromExcelCell)(excelRow.getCell(column).value);
37
+ row[name] = value;
38
+ if (value !== null)
39
+ hasValue = true;
40
+ }
41
+ if (hasValue)
42
+ rows.push(row);
43
+ });
44
+ return rows;
45
+ }
46
+ }
47
+ exports.ExcelSource = ExcelSource;
@@ -0,0 +1,4 @@
1
+ import type { Workbook } from "exceljs";
2
+ export declare function createWorkbook(): Workbook;
3
+ export declare function openWorkbook(filePath: string): Promise<Workbook>;
4
+ export declare function saveWorkbook(workbook: Workbook, filePath: string): Promise<void>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createWorkbook = createWorkbook;
4
+ exports.openWorkbook = openWorkbook;
5
+ exports.saveWorkbook = saveWorkbook;
6
+ const optional_1 = require("../optional");
7
+ const files_1 = require("../files");
8
+ function createWorkbook() {
9
+ const exceljs = (0, optional_1.requireOptional)(() => require("exceljs"), ["exceljs"], "Excel");
10
+ return new exceljs.Workbook();
11
+ }
12
+ async function openWorkbook(filePath) {
13
+ const workbook = createWorkbook();
14
+ await workbook.xlsx.load((0, files_1.readBinaryFile)(filePath));
15
+ return workbook;
16
+ }
17
+ async function saveWorkbook(workbook, filePath) {
18
+ const buffer = await workbook.xlsx.writeBuffer();
19
+ (0, files_1.writeBinaryFile)(filePath, Buffer.from(buffer));
20
+ }