cosmemilton-acbr-node 0.1.1 → 0.2.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.
- package/LICENSE +502 -502
- package/NOTICE +8 -8
- package/README.md +137 -106
- package/acbr.config.json +16 -16
- package/acbr.lock.json +0 -0
- package/dist/cli.js +1345 -973
- package/dist/cli.js.map +4 -4
- package/dist/contract.json +1 -0
- package/dist/index.cjs +36 -11
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +36 -11
- package/dist/index.js.map +2 -2
- package/dist/runtime.cjs +36 -11
- package/dist/runtime.cjs.map +2 -2
- package/dist/runtime.js +36 -11
- package/dist/runtime.js.map +2 -2
- package/dist/types/generated/acbr/index.d.ts +3 -2
- package/dist/types/generated/acbr/models.d.ts +0 -0
- package/dist/types/src/cli.d.ts +4 -2
- package/dist/types/src/config.d.ts +0 -0
- package/dist/types/src/contract-help.d.ts +53 -0
- package/dist/types/src/diagnostics.d.ts +2 -0
- package/dist/types/src/generator.d.ts +2 -0
- package/dist/types/src/index.d.ts +3 -2
- package/dist/types/src/native-build.d.ts +1 -0
- package/dist/types/src/offline-check.d.ts +0 -0
- package/dist/types/src/offline-fixture.d.ts +0 -0
- package/dist/types/src/runtime.d.ts +1 -0
- package/dist/types/src/source.d.ts +0 -0
- package/dist/types/src/types.d.ts +4 -2
- package/docs/API.md +26 -0
- package/docs/ARQUITETURA.md +19 -15
- package/docs/CI.md +60 -60
- package/docs/CLI.md +52 -32
- package/docs/DEPENDENCIAS-NATIVAS.md +93 -93
- package/docs/VALIDACAO.md +67 -67
- package/docs/examples/recuperar-xml.mjs +54 -0
- package/docs/licenses/fpc/COPYING.FPC +25 -25
- package/docs/licenses/fpc/COPYING.GPL.txt +340 -340
- package/docs/licenses/fpc/COPYING.LGPL.txt +504 -504
- package/docs/licenses/fpc/ORIGIN.json +21 -21
- package/docs/licenses/lazarus/COPYING.LGPL.txt +481 -481
- package/docs/licenses/lazarus/COPYING.modifiedLGPL.txt +26 -26
- package/docs/licenses/lazarus/COPYING.txt +46 -46
- package/docs/licenses/lazarus/ORIGIN.json +1 -1
- package/native/NativeMotor.pas +55 -3
- package/native/NativeProtocol.pas +3 -2
- package/native/NativeRecovery.pas +274 -0
- package/native/generated/AcbrModels.pas +0 -0
- package/package.json +76 -74
- package/scripts/build-native-deps.mjs +237 -237
- package/tools/extract-model.lpr +119 -119
package/dist/cli.js
CHANGED
|
@@ -9,645 +9,266 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// src/
|
|
13
|
-
var
|
|
14
|
-
__export(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
renderTypeScript: () => renderTypeScript
|
|
12
|
+
// src/config.ts
|
|
13
|
+
var config_exports = {};
|
|
14
|
+
__export(config_exports, {
|
|
15
|
+
OFFICIAL_ACBR_URL: () => OFFICIAL_ACBR_URL,
|
|
16
|
+
SOURCE_PARTS: () => SOURCE_PARTS,
|
|
17
|
+
defaultConfig: () => defaultConfig,
|
|
18
|
+
initializeConfig: () => initializeConfig,
|
|
19
|
+
loadConfig: () => loadConfig,
|
|
20
|
+
parseConfig: () => parseConfig
|
|
22
21
|
});
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
import { readFile as readFile2, writeFile, mkdir, readdir, access } from "node:fs/promises";
|
|
23
|
+
import { dirname, isAbsolute, resolve } from "node:path";
|
|
24
|
+
function defaultConfig() {
|
|
25
|
+
return structuredClone(DEFAULT);
|
|
26
|
+
}
|
|
27
|
+
function record(value, name) {
|
|
28
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(`${name} deve ser um objeto.`);
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
function keys(value, allowed, name) {
|
|
32
|
+
const unexpected = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
33
|
+
if (unexpected.length) throw new Error(`Campo desconhecido em ${name}: ${unexpected.join(", ")}.`);
|
|
34
|
+
}
|
|
35
|
+
function string(value, name) {
|
|
36
|
+
if (typeof value !== "string" || !value.trim() || value.includes("\0")) throw new Error(`${name} deve ser um texto n\xE3o vazio.`);
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function parseConfig(input, configPath) {
|
|
40
|
+
const root = record(input, "configura\xE7\xE3o");
|
|
41
|
+
keys(root, ["formatVersion", "source", "generator", "native"], "configura\xE7\xE3o");
|
|
42
|
+
if (root.formatVersion !== 1) throw new Error("formatVersion deve ser 1.");
|
|
43
|
+
const source = record(root.source, "source");
|
|
44
|
+
keys(source, ["url", "revision", "directory"], "source");
|
|
45
|
+
const generator = record(root.generator, "generator");
|
|
46
|
+
keys(generator, ["outputDir"], "generator");
|
|
47
|
+
const native = record(root.native, "native");
|
|
48
|
+
keys(native, ["project", "outputDir", "fpc", "lazarusRoot", "libraryFiles", "providerFiles"], "native");
|
|
49
|
+
const url = string(source.url, "source.url").replace(/\/+$/, "");
|
|
50
|
+
if (url !== OFFICIAL_ACBR_URL) throw new Error(`source.url deve apontar ao reposit\xF3rio oficial ${OFFICIAL_ACBR_URL}.`);
|
|
51
|
+
const revision2 = source.revision;
|
|
52
|
+
if (revision2 !== "HEAD" && (!Number.isSafeInteger(revision2) || Number(revision2) < 1)) throw new Error("source.revision deve ser HEAD ou uma revis\xE3o SVN positiva.");
|
|
53
|
+
const absoluteConfig = resolve(configPath);
|
|
54
|
+
const projectRoot = dirname(absoluteConfig);
|
|
55
|
+
const localPath = (value, label) => resolve(projectRoot, string(value, label));
|
|
56
|
+
const fpcInput = string(native.fpc, "native.fpc");
|
|
57
|
+
const fpc = isAbsolute(fpcInput) || /[\\/]/.test(fpcInput) ? resolve(projectRoot, fpcInput) : fpcInput;
|
|
58
|
+
let libraryFiles;
|
|
59
|
+
if (native.libraryFiles !== void 0) {
|
|
60
|
+
if (!Array.isArray(native.libraryFiles)) throw new Error("native.libraryFiles deve ser uma lista de caminhos.");
|
|
61
|
+
libraryFiles = native.libraryFiles.map((item, i) => localPath(item, `native.libraryFiles[${i}]`));
|
|
38
62
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (found.type.kind === "alias") {
|
|
44
|
-
trail.add(key);
|
|
45
|
-
return resolve5(found.type.target, found.unit, trail);
|
|
46
|
-
}
|
|
47
|
-
return found;
|
|
63
|
+
let providerFiles;
|
|
64
|
+
if (native.providerFiles !== void 0) {
|
|
65
|
+
if (!Array.isArray(native.providerFiles)) throw new Error("native.providerFiles deve ser uma lista de caminhos.");
|
|
66
|
+
providerFiles = native.providerFiles.map((item, i) => localPath(item, `native.providerFiles[${i}]`));
|
|
48
67
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (!values.length) throw new Error("Enum sem valores: " + key);
|
|
64
|
-
generated.set(key, { name: key, unit: declUnit.name, kind: "enum", values });
|
|
65
|
-
return { kind: "enum", ref: key };
|
|
68
|
+
return {
|
|
69
|
+
formatVersion: 1,
|
|
70
|
+
configPath: absoluteConfig,
|
|
71
|
+
projectRoot,
|
|
72
|
+
lockPath: resolve(projectRoot, "acbr.lock.json"),
|
|
73
|
+
source: { url, revision: revision2, directory: localPath(source.directory, "source.directory") },
|
|
74
|
+
generator: { outputDir: localPath(generator.outputDir, "generator.outputDir") },
|
|
75
|
+
native: {
|
|
76
|
+
project: localPath(native.project, "native.project"),
|
|
77
|
+
outputDir: localPath(native.outputDir, "native.outputDir"),
|
|
78
|
+
fpc,
|
|
79
|
+
...native.lazarusRoot !== void 0 ? { lazarusRoot: localPath(native.lazarusRoot, "native.lazarusRoot") } : {},
|
|
80
|
+
...libraryFiles !== void 0 ? { libraryFiles } : {},
|
|
81
|
+
...providerFiles !== void 0 ? { providerFiles } : {}
|
|
66
82
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async function loadConfig(path4 = "acbr.config.json") {
|
|
86
|
+
const configPath = resolve(path4);
|
|
87
|
+
let contents;
|
|
88
|
+
try {
|
|
89
|
+
contents = await readFile2(configPath, "utf8");
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new Error(`N\xE3o foi poss\xEDvel ler ${configPath}. Execute acbr-node init.`, { cause: error });
|
|
92
|
+
}
|
|
93
|
+
let value;
|
|
94
|
+
try {
|
|
95
|
+
value = JSON.parse(contents);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new Error(`JSON inv\xE1lido em ${configPath}.`, { cause: error });
|
|
98
|
+
}
|
|
99
|
+
return parseConfig(value, configPath);
|
|
100
|
+
}
|
|
101
|
+
async function initializeConfig(path4 = "acbr.config.json", revision2 = "HEAD", assetRoot) {
|
|
102
|
+
const configPath = resolve(path4);
|
|
103
|
+
const config = defaultConfig();
|
|
104
|
+
config.source.revision = revision2;
|
|
105
|
+
parseConfig(config, configPath);
|
|
106
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
107
|
+
try {
|
|
108
|
+
await access(configPath);
|
|
109
|
+
throw Object.assign(new Error(`EEXIST: configura\xE7\xE3o j\xE1 existe: ${configPath}`), { code: "EEXIST" });
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error.code !== "ENOENT") throw error;
|
|
112
|
+
}
|
|
113
|
+
const resolved = parseConfig(config, configPath);
|
|
114
|
+
if (assetRoot) await copyInitAssets(assetRoot, resolved.projectRoot);
|
|
115
|
+
await writeFile(configPath, `${JSON.stringify(config, null, 2)}
|
|
116
|
+
`, { flag: "wx" });
|
|
117
|
+
await mkdir(resolve(resolved.projectRoot, ".acbr/generated"), { recursive: true });
|
|
118
|
+
await mkdir(resolve(resolved.projectRoot, "generated/acbr"), { recursive: true });
|
|
119
|
+
return resolved;
|
|
120
|
+
}
|
|
121
|
+
async function copyInitAssets(assetRoot, targetRoot) {
|
|
122
|
+
const entries = [];
|
|
123
|
+
async function scan(current, target) {
|
|
124
|
+
for (const entry of await readdir(current, { withFileTypes: true })) {
|
|
125
|
+
if (entry.name === "generated" || entry.name.startsWith(".")) continue;
|
|
126
|
+
const source = resolve(current, entry.name);
|
|
127
|
+
const destination = resolve(target, entry.name);
|
|
128
|
+
if (entry.isDirectory()) await scan(source, destination);
|
|
129
|
+
else if (entry.isFile() && /\.(pas|lpr|inc|lpi)$/i.test(entry.name)) entries.push({ source, destination, content: await readFile2(source) });
|
|
77
130
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
131
|
+
}
|
|
132
|
+
await scan(resolve(assetRoot, "native"), resolve(targetRoot, "native"));
|
|
133
|
+
if (!entries.some((entry) => entry.source.endsWith("acbr-worker.lpr"))) throw new Error("Assets do pacote n\xE3o cont\xEAm native/acbr-worker.lpr.");
|
|
134
|
+
entries.push({ source: resolve(assetRoot, "tools/extract-model.lpr"), destination: resolve(targetRoot, "tools/extract-model.lpr"), content: await readFile2(resolve(assetRoot, "tools/extract-model.lpr")) });
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
try {
|
|
137
|
+
const existing = await readFile2(entry.destination);
|
|
138
|
+
if (!existing.equals(entry.content)) throw new Error(`init preservou arquivo existente divergente: ${entry.destination}.`);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error.code !== "ENOENT") throw error;
|
|
85
141
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
142
|
+
}
|
|
143
|
+
for (const entry of entries) {
|
|
144
|
+
await mkdir(dirname(entry.destination), { recursive: true });
|
|
145
|
+
try {
|
|
146
|
+
await writeFile(entry.destination, entry.content, { flag: "wx" });
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (error.code !== "EEXIST") throw error;
|
|
93
149
|
}
|
|
94
|
-
node.properties = [...props.values()].sort((a, b) => a.name.localeCompare(b.name, "en"));
|
|
95
|
-
return { kind: "object", ref: key };
|
|
96
150
|
}
|
|
97
|
-
visit(raw.root, rootUnit);
|
|
98
|
-
return { schemaVersion: 1, root: raw.root, types: [...generated.values()].sort((a, b) => a.name.localeCompare(b.name, "en")) };
|
|
99
151
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
if (type.kind === "object") {
|
|
114
|
-
const a = new Map(before.properties.map((p) => [p.name, p])), b = new Map(type.properties.map((p) => [p.name, p]));
|
|
115
|
-
for (const [field, p] of b) {
|
|
116
|
-
if (!a.has(field)) additions.push(name + "." + field);
|
|
117
|
-
else if (stable(a.get(field)) !== stable(p)) changes.push(name + "." + field);
|
|
118
|
-
}
|
|
119
|
-
for (const field of a.keys()) if (!b.has(field)) removals.push(name + "." + field);
|
|
120
|
-
} else if (type.kind === "enum") {
|
|
121
|
-
for (const v of type.values) if (!before.values.includes(v)) additions.push(name + "." + v);
|
|
122
|
-
for (const v of before.values) if (!type.values.includes(v)) removals.push(name + "." + v);
|
|
123
|
-
} else if (type.item !== before.item) changes.push(name + ":item");
|
|
152
|
+
var OFFICIAL_ACBR_URL, SOURCE_PARTS, DEFAULT;
|
|
153
|
+
var init_config = __esm({
|
|
154
|
+
"src/config.ts"() {
|
|
155
|
+
"use strict";
|
|
156
|
+
OFFICIAL_ACBR_URL = "https://svn.code.sf.net/p/acbr/code/trunk2";
|
|
157
|
+
SOURCE_PARTS = ["Fontes", "Exemplos/ACBrDFe/Schemas/NFe", "Doctos/LICENSE.TXT"];
|
|
158
|
+
DEFAULT = {
|
|
159
|
+
formatVersion: 1,
|
|
160
|
+
source: { url: OFFICIAL_ACBR_URL, revision: "HEAD", directory: ".acbr/source" },
|
|
161
|
+
generator: { outputDir: "." },
|
|
162
|
+
native: { project: "native/acbr-worker.lpr", outputDir: ".acbr/runtime", fpc: "fpc" }
|
|
163
|
+
};
|
|
124
164
|
}
|
|
125
|
-
|
|
126
|
-
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// src/source.ts
|
|
168
|
+
var source_exports = {};
|
|
169
|
+
__export(source_exports, {
|
|
170
|
+
fileHash: () => fileHash,
|
|
171
|
+
lockExistingSource: () => lockExistingSource,
|
|
172
|
+
readSourceLock: () => readSourceLock,
|
|
173
|
+
resolveSourceRevision: () => resolveSourceRevision,
|
|
174
|
+
runCommand: () => runCommand,
|
|
175
|
+
snapshotSource: () => snapshotSource,
|
|
176
|
+
updateSource: () => updateSource,
|
|
177
|
+
verifySource: () => verifySource
|
|
178
|
+
});
|
|
179
|
+
import { spawn } from "node:child_process";
|
|
180
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
181
|
+
import { createReadStream } from "node:fs";
|
|
182
|
+
import { access as access2, mkdir as mkdir2, readdir as readdir2, readFile as readFile3, rename, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
183
|
+
import { dirname as dirname2, join, relative, resolve as resolve2, sep } from "node:path";
|
|
184
|
+
async function runCommand(command, args, options = {}) {
|
|
185
|
+
return new Promise((done, fail3) => {
|
|
186
|
+
const child = spawn(command, args, { cwd: options.cwd, env: options.env ?? process.env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, shell: false });
|
|
187
|
+
let stdout = "";
|
|
188
|
+
let stderr = "";
|
|
189
|
+
let overflow = false;
|
|
190
|
+
const maximum = options.maxOutputBytes ?? 16 * 1024 * 1024;
|
|
191
|
+
const append = (kind, data) => {
|
|
192
|
+
if (overflow) return;
|
|
193
|
+
if (kind === "stdout") stdout += data.toString("utf8");
|
|
194
|
+
else stderr += data.toString("utf8");
|
|
195
|
+
if (Buffer.byteLength(stdout) + Buffer.byteLength(stderr) > maximum) {
|
|
196
|
+
overflow = true;
|
|
197
|
+
child.kill();
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
child.stdout.on("data", (data) => append("stdout", data));
|
|
201
|
+
child.stderr.on("data", (data) => append("stderr", data));
|
|
202
|
+
child.on("error", (error) => fail3(new Error(`N\xE3o foi poss\xEDvel executar ${command}: ${error.message}`, { cause: error })));
|
|
203
|
+
child.on("close", (code) => {
|
|
204
|
+
if (overflow) fail3(new Error(`Sa\xEDda de ${command} excedeu o limite de ${maximum} bytes.`));
|
|
205
|
+
else if (code !== 0) {
|
|
206
|
+
const diagnostic = (stderr || stdout).split("\n").slice(-80).join("\n").slice(-16e3);
|
|
207
|
+
fail3(Object.assign(new Error(`${command} terminou com c\xF3digo ${code}:
|
|
208
|
+
${diagnostic}`), { stdout, stderr }));
|
|
209
|
+
} else done({ stdout, stderr });
|
|
210
|
+
});
|
|
211
|
+
});
|
|
127
212
|
}
|
|
128
|
-
function
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if(typeof at!=='string'||at.length>512||! /^[A-Za-z_]\w*(?:(?:\.[A-Za-z_]\w*)|(?:\[\d{1,7}\]))*$/.test(at))return undefined;
|
|
133
|
-
const parts=at.replace(/\[(\d+)\]/g,'.$1').split('.');let schema=Object.hasOwn(MODEL_SCHEMA,parts[0])?MODEL_SCHEMA[parts[0]]:undefined;
|
|
134
|
-
if(!schema)return undefined;
|
|
135
|
-
for(const part of parts.slice(1)){
|
|
136
|
-
if(schema.kind==='list'){if(! /^\d+$/.test(part))return undefined;schema=MODEL_SCHEMA[schema.item];}
|
|
137
|
-
else if(schema.kind==='object'){const p=schema.properties.find((p:any)=>p.name===part);if(!p)return undefined;schema=p.ref?MODEL_SCHEMA[p.ref]:{kind:p.kind};}
|
|
138
|
-
else return undefined;
|
|
139
|
-
}
|
|
140
|
-
return at;
|
|
141
|
-
}
|
|
142
|
-
/** TypeError compatível, com contexto seguro e sem o valor informado ou chaves desconhecidas. */
|
|
143
|
-
export class ErroValidacaoModelo extends TypeError {
|
|
144
|
-
readonly codigo: CodigoValidacaoModelo;
|
|
145
|
-
readonly diagnostico: Readonly<{codigo:CodigoValidacaoModelo;etapa:'documento';campo?:string;mensagem:string;acao:string;statusEnvio:'nao_enviado';causa:Readonly<{codigo:CodigoValidacaoModelo;etapa:'documento';campo?:string}>}>;
|
|
146
|
-
constructor(codigo: CodigoValidacaoModelo, at?: string) {
|
|
147
|
-
const catalogo:Record<CodigoValidacaoModelo,[string,string]>={
|
|
148
|
-
MODELO_DESCONHECIDO:['Modelo desconhecido.','Use um modelo exportado pelo cliente gerado.'],
|
|
149
|
-
ENUM_INVALIDO:['enum inválido','Use um dos valores textuais do enum exportado pelo cliente.'],
|
|
150
|
-
ARRAY_ESPERADO:['esperado array','Informe uma lista JSON entre colchetes.'],
|
|
151
|
-
OBJETO_ESPERADO:['esperado objeto','Informe um objeto JSON entre chaves.'],
|
|
152
|
-
CAMPO_DESCONHECIDO:['propriedade desconhecida','Confira os nomes permitidos neste grupo; a chave desconhecida não é registrada.'],
|
|
153
|
-
CAMPO_SOMENTE_LEITURA:['propriedade somente leitura','Remova este campo da entrada; o motor preenche seu resultado.'],
|
|
154
|
-
INTEIRO_INVALIDO:['inteiro fora do intervalo','Informe um número inteiro dentro do intervalo do campo.'],
|
|
155
|
-
BOOLEANO_ESPERADO:['esperado boolean','Informe true ou false como valor JSON, sem aspas.'],
|
|
156
|
-
DECIMAL_INVALIDO:['esperado decimal em string','Informe o decimal entre aspas, com ponto e a escala permitida pelo campo.'],
|
|
157
|
-
DATA_HORA_INVALIDA:['esperado data/hora civil ISO (sem timezone)','Informe a data/hora civil da UF como AAAA-MM-DDTHH:mm:ss, sem Z ou offset. Confira a data antes do envio.'],
|
|
158
|
-
DATA_INVALIDA:['data inválida','Confira dia, mês, ano e horário usando uma data civil válida.'],
|
|
159
|
-
TEXTO_ESPERADO:['esperado string','Informe texto entre aspas no JSON.']
|
|
160
|
-
};
|
|
161
|
-
const safeCode=Object.hasOwn(catalogo,codigo)?codigo:'MODELO_DESCONHECIDO';
|
|
162
|
-
const campo=campoConhecido(at),[texto,acao]=catalogo[safeCode],mensagem=(campo?campo+': ':'')+texto;
|
|
163
|
-
super(mensagem);this.codigo=safeCode;
|
|
164
|
-
const causa=Object.freeze({codigo:safeCode,etapa:'documento' as const,...(campo?{campo}:{})});
|
|
165
|
-
this.diagnostico=Object.freeze({codigo:safeCode,etapa:'documento' as const,...(campo?{campo}:{}),mensagem,acao,statusEnvio:'nao_enviado' as const,causa});
|
|
166
|
-
Object.defineProperty(this,'cause',{value:causa,enumerable:false});
|
|
167
|
-
}
|
|
168
|
-
toJSON(){return this.diagnostico;}
|
|
169
|
-
}
|
|
170
|
-
export function validateModel(model: string, value: unknown, at=model): void {
|
|
171
|
-
const schema=Object.hasOwn(MODEL_SCHEMA,model)?MODEL_SCHEMA[model]:undefined;
|
|
172
|
-
if(!schema)throw new ErroValidacaoModelo('MODELO_DESCONHECIDO');
|
|
173
|
-
at=campoConhecido(at)??model;
|
|
174
|
-
if(schema.kind==='enum'){if(typeof value!=='string'||!schema.values.includes(value))throw new ErroValidacaoModelo('ENUM_INVALIDO',at);return;}
|
|
175
|
-
if(schema.kind==='list'){if(!Array.isArray(value))throw new ErroValidacaoModelo('ARRAY_ESPERADO',at);value.forEach((item,index)=>validateModel(schema.item,item,at+'['+index+']'));return;}
|
|
176
|
-
if(value===null||typeof value!=='object'||Array.isArray(value))throw new ErroValidacaoModelo('OBJETO_ESPERADO',at);
|
|
177
|
-
const fields=new Map<string,any>(schema.properties.filter((p:any)=>!p.readonly).map((p:any)=>[p.name,p]));
|
|
178
|
-
for(const [name,v] of Object.entries(value)){
|
|
179
|
-
if(v===undefined)continue;
|
|
180
|
-
const p=fields.get(name);
|
|
181
|
-
if(!p){const readonly=schema.properties.some((p:any)=>p.name===name&&p.readonly);throw new ErroValidacaoModelo(readonly?'CAMPO_SOMENTE_LEITURA':'CAMPO_DESCONHECIDO',readonly?at+'.'+name:at);}
|
|
182
|
-
const field=at+'.'+name;
|
|
183
|
-
if(p.ref){validateModel(p.ref,v,field);continue;}
|
|
184
|
-
if(p.kind==='integer'){if(typeof v!=='number'||!Number.isSafeInteger(v)||v<p.min||v>p.max)throw new ErroValidacaoModelo('INTEIRO_INVALIDO',field);}
|
|
185
|
-
else if(p.kind==='boolean'){if(typeof v!=='boolean')throw new ErroValidacaoModelo('BOOLEANO_ESPERADO',field);}
|
|
186
|
-
else if(p.kind==='decimal'){if(typeof v!=='string'||v.length>64||! /^-?\d+(?:\.\d+)?$/.test(v)||p.scale!==undefined&&(v.split('.')[1]?.length??0)>p.scale)throw new ErroValidacaoModelo('DECIMAL_INVALIDO',field);}
|
|
187
|
-
else if(p.kind==='datetime'){
|
|
188
|
-
if(typeof v!=='string'||! /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?)?$/.test(v)||Number.isNaN(Date.parse(v+(v.length===10?'T00:00:00Z':'Z'))))throw new ErroValidacaoModelo('DATA_HORA_INVALIDA',field);
|
|
189
|
-
const date=new Date(v+(v.length===10?'T00:00:00Z':'Z'));if(date.toISOString().slice(0,10)!==v.slice(0,10))throw new ErroValidacaoModelo('DATA_INVALIDA',field);
|
|
190
|
-
}else if(typeof v!=='string')throw new ErroValidacaoModelo('TEXTO_ESPERADO',field);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
export function validateTNFe(value: unknown): asserts value is TNFeInput { validateModel('TNFe',value); }
|
|
194
|
-
`;
|
|
195
|
-
}
|
|
196
|
-
function renderTypeScript(ir, revision2, contractHash) {
|
|
197
|
-
const out = ["// Generated from ACBr AST. LGPL-2.1-or-later. Do not edit.", "export const ACBR_CONTRACT = " + stable({ sourceRevision: revision2, contractHash }) + " as const;", "export const SOURCE_REVISION=ACBR_CONTRACT.sourceRevision;", "export const CONTRACT_HASH=ACBR_CONTRACT.contractHash;"];
|
|
198
|
-
for (const t of ir.types) {
|
|
199
|
-
if (t.kind === "enum") {
|
|
200
|
-
out.push("export const " + t.name + " = Object.freeze(" + stable(Object.fromEntries(t.values.map((v) => [v, v]))) + " as const);", "export type " + t.name + " = typeof " + t.name + "[keyof typeof " + t.name + "];");
|
|
201
|
-
} else if (t.kind === "list") {
|
|
202
|
-
out.push("export type " + t.name + "Input = " + t.item + "Input[];", "export class " + t.name + " extends Array<" + t.item + "> {", " New(input: " + t.item + "Input = {}): " + t.item + " { const item=new " + t.item + "(input); this.push(item); return item; }", "}");
|
|
203
|
-
} else {
|
|
204
|
-
out.push("export interface " + t.name + "Input {");
|
|
205
|
-
for (const p of t.properties.filter((p2) => !p2.readonly)) out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
206
|
-
out.push("}", "export class " + t.name + " {");
|
|
207
|
-
for (const p of t.properties) {
|
|
208
|
-
if (p.readonly) {
|
|
209
|
-
out.push(" readonly " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
if (p.declaredDefault) out.push(" /** Pascal streaming default: " + p.declaredDefault.replaceAll("*/", "") + ". Omission preserves the native constructor. */");
|
|
213
|
-
if (p.kind === "object" || p.kind === "list") out.push(" " + JSON.stringify(p.name) + " = new " + p.ref + "();");
|
|
214
|
-
else out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
215
|
-
}
|
|
216
|
-
out.push(" constructor(input: " + t.name + "Input = {}) {", " validateModel(" + JSON.stringify(t.name) + ", input);");
|
|
217
|
-
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
218
|
-
const access5 = "input[" + JSON.stringify(p.name) + "]", target = "this[" + JSON.stringify(p.name) + "]";
|
|
219
|
-
out.push(" if (" + access5 + " !== undefined) " + target + " = " + (p.kind === "object" ? "new " + p.ref + "(" + access5 + ")" : p.kind === "list" ? "Object.assign(new " + p.ref + "(), " + access5 + ".map(v=>new " + ir.types.find((t2) => t2.name === p.ref).item + "(v)))" : access5) + ";");
|
|
220
|
-
}
|
|
221
|
-
out.push(" }", "}");
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
out.push("const MODEL_SCHEMA: Record<string, any> = " + stable(Object.fromEntries(ir.types.map((t) => [t.name, t]))) + ";");
|
|
225
|
-
out.push(renderModelValidation());
|
|
226
|
-
return out.join("\n") + "\n";
|
|
213
|
+
async function fileHash(path4) {
|
|
214
|
+
const hash2 = createHash2("sha256");
|
|
215
|
+
for await (const chunk of createReadStream(path4)) hash2.update(chunk);
|
|
216
|
+
return hash2.digest("hex");
|
|
227
217
|
}
|
|
228
|
-
function
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
begin if (D=nil) or (D.JSONType<>jtString) then Bad(P,'esperado string');Result:=D.AsString end;
|
|
240
|
-
function IntValue(D:TJSONData;const P:string;MinV,MaxV:Int64):Int64;
|
|
241
|
-
var V:Extended;
|
|
242
|
-
begin
|
|
243
|
-
if (D=nil) or (D.JSONType<>jtNumber) then Bad(P,'esperado inteiro');
|
|
244
|
-
V:=D.AsFloat;if IsNan(V) or IsInfinite(V) or (Frac(V)<>0) or (V<MinV) or (V>MaxV) then Bad(P,'inteiro fora do intervalo');
|
|
245
|
-
Result:=D.AsInt64;
|
|
246
|
-
end;
|
|
247
|
-
function BoolValue(D:TJSONData;const P:string):boolean;
|
|
248
|
-
begin if (D=nil) or (D.JSONType<>jtBoolean) then Bad(P,'esperado boolean');Result:=D.AsBoolean end;
|
|
249
|
-
function DecimalText(D:TJSONData;const P:string;Scale:integer):string;
|
|
250
|
-
var I,PointPos:integer;
|
|
251
|
-
begin
|
|
252
|
-
Result:=Text(D,P);PointPos:=0;
|
|
253
|
-
if (Result='') or (Length(Result)>64) then Bad(P,'decimal inválido');
|
|
254
|
-
for I:=1 to Length(Result) do begin
|
|
255
|
-
if Result[I]='.' then begin if (PointPos>0) or (I=1) or ((I=2) and (Result[1]='-')) or (I=Length(Result)) then Bad(P,'decimal inválido');PointPos:=I end
|
|
256
|
-
else if (Result[I]='-') and (I=1) then begin if Length(Result)=1 then Bad(P,'decimal inválido') end
|
|
257
|
-
else if not (Result[I] in ['0'..'9']) then Bad(P,'decimal inválido');
|
|
258
|
-
end;
|
|
259
|
-
if (PointPos>0) and (Scale>=0) and (Length(Result)-PointPos>Scale) then Bad(P,'casas decimais excedidas');
|
|
260
|
-
end;
|
|
261
|
-
function FloatValue(D:TJSONData;const P:string):Extended;
|
|
262
|
-
var F:TFormatSettings;S:string;
|
|
263
|
-
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,-1);
|
|
264
|
-
if not TryStrToFloat(S,Result,F) or IsNan(Result) or IsInfinite(Result) then Bad(P,'decimal fora do intervalo');
|
|
265
|
-
end;
|
|
266
|
-
function CurrencyValue(D:TJSONData;const P:string):Currency;
|
|
267
|
-
var F:TFormatSettings;S:string;
|
|
268
|
-
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,4);
|
|
269
|
-
if not TryStrToCurr(S,Result,F) then Bad(P,'currency fora do intervalo');
|
|
270
|
-
end;
|
|
271
|
-
function DateValue(D:TJSONData;const P:string):TDateTime;
|
|
272
|
-
var S:string;I:integer;
|
|
273
|
-
begin
|
|
274
|
-
S:=Text(D,P);
|
|
275
|
-
if not (Length(S) in [10,19,21,22,23]) then Bad(P,'esperado data/hora civil ISO sem timezone');
|
|
276
|
-
for I:=1 to Length(S) do if not ((S[I] in ['0'..'9']) or ((I in [5,8]) and (S[I]='-')) or ((I=11) and (S[I]='T')) or ((I in [14,17]) and (S[I]=':')) or ((I=20) and (S[I]='.'))) then Bad(P,'data ISO inválida');
|
|
277
|
-
if not TryISO8601ToDate(S,Result,true) then Bad(P,'data ISO inválida');
|
|
278
|
-
end;
|
|
279
|
-
`);
|
|
280
|
-
const q = (s) => "'" + s.replaceAll("'", "''") + "'";
|
|
281
|
-
for (const t of classes) out.push("procedure Load_" + t.name + "(D:TJSONObject;destino:" + t.unit + "." + t.name + ";const P:string); forward;");
|
|
282
|
-
for (const t of classes) {
|
|
283
|
-
out.push("procedure Load_" + t.name + "(D:TJSONObject;destino:" + t.unit + "." + t.name + ";const P:string);", "var I,J:integer;V:TJSONData;A:TJSONArray;K,At:string;", "begin", " if destino=nil then Bad(P,'objeto ACBr n\xE3o inicializado');", " for I:=0 to D.Count-1 do begin", " K:=D.Names[I];V:=D.Items[I];At:=P+'.'+K;");
|
|
284
|
-
let index = 0;
|
|
285
|
-
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
286
|
-
out.push(" " + (index++ ? "else " : "") + "if K=" + q(p.name) + " then begin");
|
|
287
|
-
const target = "destino." + p.name;
|
|
288
|
-
if (p.kind === "object") out.push(" Load_" + p.ref + "(Obj(V,At)," + target + ",At);");
|
|
289
|
-
else if (p.kind === "list") {
|
|
290
|
-
const list = byName.get(p.ref);
|
|
291
|
-
out.push(" A:=Arr(V,At);if " + target + "=nil then Bad(At,'cole\xE7\xE3o n\xE3o inicializada');" + target + ".Clear;", " for J:=0 to A.Count-1 do Load_" + list.item + "(Obj(A.Items[J],At+'['+IntToStr(J)+']')," + target + "." + list.factory + ",At+'['+IntToStr(J)+']');");
|
|
292
|
-
} else if (p.kind === "enum") {
|
|
293
|
-
const enumeration = byName.get(p.ref);
|
|
294
|
-
out.push(...enumeration.values.map((v, i) => " " + (i ? "else " : "") + "if Text(V,At)=" + q(v) + " then " + target + ":=" + enumeration.unit + "." + v), " else Bad(At,'enum inv\xE1lido');");
|
|
295
|
-
} else out.push(" " + target + ":=" + { string: "Text(V,At)", integer: "IntValue(V,At," + p.min + "," + p.max + ")", boolean: "BoolValue(V,At)", datetime: "DateValue(V,At)", decimal: p.scale === 4 ? "CurrencyValue(V,At)" : "FloatValue(V,At)" }[p.kind] + ";");
|
|
296
|
-
out.push(" end");
|
|
218
|
+
async function snapshotSource(directory) {
|
|
219
|
+
const files = /* @__PURE__ */ Object.create(null);
|
|
220
|
+
async function scan(current) {
|
|
221
|
+
const entries = (await readdir2(current, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name, "en"));
|
|
222
|
+
for (const entry of entries) {
|
|
223
|
+
if (entry.name === ".svn") continue;
|
|
224
|
+
const path4 = join(current, entry.name);
|
|
225
|
+
if (entry.isSymbolicLink()) throw new Error(`Fonte ACBr cont\xE9m link simb\xF3lico: ${path4}.`);
|
|
226
|
+
if (entry.isDirectory()) await scan(path4);
|
|
227
|
+
else if (entry.isFile()) files[relative(directory, path4).split(sep).join("/")] = await fileHash(path4);
|
|
228
|
+
else throw new Error(`Fonte ACBr cont\xE9m arquivo especial: ${path4}.`);
|
|
297
229
|
}
|
|
298
|
-
out.push((index ? " else " : " ") + "Bad(At,'propriedade desconhecida ou somente leitura');", " end;", "end;");
|
|
299
230
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
return [
|
|
305
|
-
"// Generated client bound to its own ACBr contract. Do not edit.",
|
|
306
|
-
"import { criarEmissor as criarRuntime, diagnosticarErro as diagnosticarErroRuntime, diagnosticarResultado, type OpcoesEmissor, type OpcoesOperacao } from " + JSON.stringify("cosmemilton-acbr-node/runtime") + ";",
|
|
307
|
-
"import { ACBR_CONTRACT, validateTNFe, ErroValidacaoModelo, type TNFeInput } from " + JSON.stringify("./models.js") + ";",
|
|
308
|
-
"export * from " + JSON.stringify("./models.js") + ";",
|
|
309
|
-
"export { diagnosticarResultado };",
|
|
310
|
-
"export function diagnosticarErro(erro:unknown) { return erro instanceof ErroValidacaoModelo ? erro.diagnostico : diagnosticarErroRuntime(erro); }",
|
|
311
|
-
"export function criarEmissor(options: Omit<OpcoesEmissor, " + JSON.stringify("contrato") + " | " + JSON.stringify("validaDocumento") + ">) {",
|
|
312
|
-
" const emissor=criarRuntime({...options, contrato:ACBR_CONTRACT, validaDocumento:validateTNFe});",
|
|
313
|
-
" return {...emissor, gerarXml(documento:TNFeInput, opcoes?:OpcoesOperacao) { return emissor.gerarXml(documento as unknown as Record<string,unknown>, opcoes); }};",
|
|
314
|
-
"}"
|
|
315
|
-
].join("\n") + "\n";
|
|
231
|
+
await scan(resolve2(directory));
|
|
232
|
+
const sortedFiles = Object.fromEntries(Object.entries(files).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
233
|
+
const treeHash = createHash2("sha256").update(JSON.stringify(sortedFiles)).digest("hex");
|
|
234
|
+
return { treeHash, files: sortedFiles };
|
|
316
235
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
else if (/\.(pas|pp|inc|xsd)$/i.test(entry.name)) files.push(f);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
await walk(dir);
|
|
327
|
-
const digest = createHash3("sha256");
|
|
328
|
-
for (const f of files.sort()) {
|
|
329
|
-
digest.update(path2.relative(dir, f).replaceAll("\\", "/"));
|
|
330
|
-
digest.update(await readFile5(f));
|
|
236
|
+
function validateLock(value) {
|
|
237
|
+
if (!value || typeof value !== "object") throw new Error("Lock ACBr inv\xE1lido.");
|
|
238
|
+
const lock = value;
|
|
239
|
+
if (lock.formatVersion !== 1 || !lock.source || !Number.isSafeInteger(lock.source.revision) || lock.source.revision < 1 || !Array.isArray(lock.source.parts) || !lock.source.files || typeof lock.source.files !== "object" || Array.isArray(lock.source.files) || !/^[a-f0-9]{64}$/.test(lock.source.treeHash)) throw new Error("Formato inv\xE1lido em acbr.lock.json.");
|
|
240
|
+
for (const [path4, hash2] of Object.entries(lock.source.files)) {
|
|
241
|
+
if (path4.startsWith("/") || path4.includes("\\") || path4.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(hash2)) throw new Error("Caminho ou hash inv\xE1lido no lock ACBr.");
|
|
331
242
|
}
|
|
332
|
-
|
|
243
|
+
if (lock.source.parts.join("\n") !== SOURCE_PARTS.join("\n")) throw new Error("Partes ACBr divergentes no lock.");
|
|
244
|
+
return lock;
|
|
333
245
|
}
|
|
334
|
-
async function
|
|
335
|
-
|
|
336
|
-
const models = path2.resolve(root, options.modelOutputDir ?? "generated/acbr"), native = path2.resolve(root, options.nativeOutputDir ?? "native/generated");
|
|
337
|
-
await Promise.all([mkdir4(cache, { recursive: true }), mkdir4(bin, { recursive: true }), mkdir4(models, { recursive: true }), mkdir4(native, { recursive: true })]);
|
|
338
|
-
const extractor = options.extractorPath ?? fileURLToPath2(new URL("../tools/extract-model.lpr", import.meta.url));
|
|
339
|
-
const executable = path2.join(bin, "extract-model" + (process.platform === "win32" ? ".exe" : ""));
|
|
246
|
+
async function readSourceLock(config) {
|
|
247
|
+
let lock;
|
|
340
248
|
try {
|
|
341
|
-
await
|
|
342
|
-
await execute(executable, [path2.resolve(options.acbrRoot), path2.join(cache, "raw-model.json"), process.platform === "win32" ? "win64" : "linux"], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
|
|
249
|
+
lock = validateLock(JSON.parse(await readFile3(config.lockPath, "utf8")));
|
|
343
250
|
} catch (error) {
|
|
344
|
-
|
|
345
|
-
throw new Error("Extra\xE7\xE3o FCL-passrc falhou: " + (e.stderr ?? "") + (e.stdout ?? "") + e.message);
|
|
251
|
+
throw new Error(`N\xE3o foi poss\xEDvel ler ${config.lockPath}. Execute acbr-node source update.`, { cause: error });
|
|
346
252
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
253
|
+
if (lock.source.url !== config.source.url) throw new Error("URL ACBr do lock diverge da configura\xE7\xE3o.");
|
|
254
|
+
if (config.source.revision !== "HEAD" && lock.source.revision !== config.source.revision) throw new Error("Revis\xE3o ACBr do lock diverge da configura\xE7\xE3o. Execute source update explicitamente.");
|
|
255
|
+
return lock;
|
|
256
|
+
}
|
|
257
|
+
async function verifySource(config) {
|
|
352
258
|
try {
|
|
353
|
-
|
|
259
|
+
await access2(`${config.lockPath}.operation`);
|
|
354
260
|
} catch (error) {
|
|
355
|
-
if (error.code
|
|
261
|
+
if (error.code === "ENOENT") return verifySourceContents(config);
|
|
262
|
+
throw error;
|
|
356
263
|
}
|
|
357
|
-
|
|
358
|
-
const files = [path2.relative(root, path2.join(models, "models.ts")), path2.relative(root, path2.join(models, "index.ts")), path2.relative(root, path2.join(native, "AcbrModels.pas"))].map((f) => f.replaceAll("\\", "/"));
|
|
359
|
-
const content = [renderTypeScript(ir, sourceRevision, contractHash), renderClientIndex(), renderPascal(ir, sourceRevision, contractHash)];
|
|
360
|
-
const fileHashes = Object.fromEntries(files.map((file, index) => [file, hash(content[index])]));
|
|
361
|
-
await Promise.all([
|
|
362
|
-
...files.map((file, index) => writeFile4(path2.resolve(root, file), content[index], "utf8")),
|
|
363
|
-
writeFile4(path2.join(cache, "model.ir.json"), JSON.stringify(ir, null, 2) + "\n", "utf8"),
|
|
364
|
-
writeFile4(reportPath, JSON.stringify(report, null, 2) + "\n", "utf8"),
|
|
365
|
-
writeFile4(manifestPath, JSON.stringify({ schemaVersion: 1, sourceRevision, sourceHash, contractHash, root: ir.root, models: ir.types.length, files, fileHashes }, null, 2) + "\n", "utf8")
|
|
366
|
-
]);
|
|
367
|
-
return { contractHash, sourceHash, models: ir.types.length, reportPath, manifestPath };
|
|
368
|
-
}
|
|
369
|
-
var execute, bases, primitives, stable, hash, tsType;
|
|
370
|
-
var init_generator = __esm({
|
|
371
|
-
"src/generator.ts"() {
|
|
372
|
-
"use strict";
|
|
373
|
-
execute = promisify(execFile);
|
|
374
|
-
bases = /* @__PURE__ */ new Set(["tobject", "tpersistent", "tacbrobjectlist"]);
|
|
375
|
-
primitives = {
|
|
376
|
-
string: { kind: "string" },
|
|
377
|
-
ansistring: { kind: "string" },
|
|
378
|
-
unicodestring: { kind: "string" },
|
|
379
|
-
widestring: { kind: "string" },
|
|
380
|
-
boolean: { kind: "boolean" },
|
|
381
|
-
byte: { kind: "integer", min: 0, max: 255 },
|
|
382
|
-
word: { kind: "integer", min: 0, max: 65535 },
|
|
383
|
-
integer: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
384
|
-
longint: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
385
|
-
smallint: { kind: "integer", min: -32768, max: 32767 },
|
|
386
|
-
shortint: { kind: "integer", min: -128, max: 127 },
|
|
387
|
-
cardinal: { kind: "integer", min: 0, max: 4294967295 },
|
|
388
|
-
longword: { kind: "integer", min: 0, max: 4294967295 },
|
|
389
|
-
int64: { kind: "integer", min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER },
|
|
390
|
-
qword: { kind: "integer", min: 0, max: Number.MAX_SAFE_INTEGER },
|
|
391
|
-
double: { kind: "decimal" },
|
|
392
|
-
extended: { kind: "decimal" },
|
|
393
|
-
single: { kind: "decimal" },
|
|
394
|
-
currency: { kind: "decimal", scale: 4 },
|
|
395
|
-
tdatetime: { kind: "datetime" },
|
|
396
|
-
tdate: { kind: "datetime" },
|
|
397
|
-
ttime: { kind: "datetime" }
|
|
398
|
-
};
|
|
399
|
-
stable = (value) => JSON.stringify(value);
|
|
400
|
-
hash = (value) => createHash3("sha256").update(value).digest("hex");
|
|
401
|
-
tsType = (p) => p.kind === "object" ? p.ref + "Input" : p.kind === "list" ? p.ref + "Input" : p.kind === "enum" ? p.ref : p.kind === "integer" ? "number" : p.kind === "boolean" ? "boolean" : "string";
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
// src/cli.ts
|
|
406
|
-
import { realpathSync } from "node:fs";
|
|
407
|
-
import { access as access4 } from "node:fs/promises";
|
|
408
|
-
import { resolve as resolve4 } from "node:path";
|
|
409
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
410
|
-
|
|
411
|
-
// src/config.ts
|
|
412
|
-
import { readFile, writeFile, mkdir, readdir, access } from "node:fs/promises";
|
|
413
|
-
import { dirname, isAbsolute, resolve } from "node:path";
|
|
414
|
-
var OFFICIAL_ACBR_URL = "https://svn.code.sf.net/p/acbr/code/trunk2";
|
|
415
|
-
var SOURCE_PARTS = ["Fontes", "Exemplos/ACBrDFe/Schemas/NFe", "Doctos/LICENSE.TXT"];
|
|
416
|
-
var DEFAULT = {
|
|
417
|
-
formatVersion: 1,
|
|
418
|
-
source: { url: OFFICIAL_ACBR_URL, revision: "HEAD", directory: ".acbr/source" },
|
|
419
|
-
generator: { outputDir: "." },
|
|
420
|
-
native: { project: "native/acbr-worker.lpr", outputDir: ".acbr/runtime", fpc: "fpc" }
|
|
421
|
-
};
|
|
422
|
-
function defaultConfig() {
|
|
423
|
-
return structuredClone(DEFAULT);
|
|
424
|
-
}
|
|
425
|
-
function record(value, name) {
|
|
426
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(`${name} deve ser um objeto.`);
|
|
427
|
-
return value;
|
|
428
|
-
}
|
|
429
|
-
function keys(value, allowed, name) {
|
|
430
|
-
const unexpected = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
431
|
-
if (unexpected.length) throw new Error(`Campo desconhecido em ${name}: ${unexpected.join(", ")}.`);
|
|
432
|
-
}
|
|
433
|
-
function string(value, name) {
|
|
434
|
-
if (typeof value !== "string" || !value.trim() || value.includes("\0")) throw new Error(`${name} deve ser um texto n\xE3o vazio.`);
|
|
435
|
-
return value;
|
|
436
|
-
}
|
|
437
|
-
function parseConfig(input, configPath) {
|
|
438
|
-
const root = record(input, "configura\xE7\xE3o");
|
|
439
|
-
keys(root, ["formatVersion", "source", "generator", "native"], "configura\xE7\xE3o");
|
|
440
|
-
if (root.formatVersion !== 1) throw new Error("formatVersion deve ser 1.");
|
|
441
|
-
const source = record(root.source, "source");
|
|
442
|
-
keys(source, ["url", "revision", "directory"], "source");
|
|
443
|
-
const generator = record(root.generator, "generator");
|
|
444
|
-
keys(generator, ["outputDir"], "generator");
|
|
445
|
-
const native = record(root.native, "native");
|
|
446
|
-
keys(native, ["project", "outputDir", "fpc", "lazarusRoot", "libraryFiles", "providerFiles"], "native");
|
|
447
|
-
const url = string(source.url, "source.url").replace(/\/+$/, "");
|
|
448
|
-
if (url !== OFFICIAL_ACBR_URL) throw new Error(`source.url deve apontar ao reposit\xF3rio oficial ${OFFICIAL_ACBR_URL}.`);
|
|
449
|
-
const revision2 = source.revision;
|
|
450
|
-
if (revision2 !== "HEAD" && (!Number.isSafeInteger(revision2) || Number(revision2) < 1)) throw new Error("source.revision deve ser HEAD ou uma revis\xE3o SVN positiva.");
|
|
451
|
-
const absoluteConfig = resolve(configPath);
|
|
452
|
-
const projectRoot = dirname(absoluteConfig);
|
|
453
|
-
const localPath = (value, label) => resolve(projectRoot, string(value, label));
|
|
454
|
-
const fpcInput = string(native.fpc, "native.fpc");
|
|
455
|
-
const fpc = isAbsolute(fpcInput) || /[\\/]/.test(fpcInput) ? resolve(projectRoot, fpcInput) : fpcInput;
|
|
456
|
-
let libraryFiles;
|
|
457
|
-
if (native.libraryFiles !== void 0) {
|
|
458
|
-
if (!Array.isArray(native.libraryFiles)) throw new Error("native.libraryFiles deve ser uma lista de caminhos.");
|
|
459
|
-
libraryFiles = native.libraryFiles.map((item, i) => localPath(item, `native.libraryFiles[${i}]`));
|
|
460
|
-
}
|
|
461
|
-
let providerFiles;
|
|
462
|
-
if (native.providerFiles !== void 0) {
|
|
463
|
-
if (!Array.isArray(native.providerFiles)) throw new Error("native.providerFiles deve ser uma lista de caminhos.");
|
|
464
|
-
providerFiles = native.providerFiles.map((item, i) => localPath(item, `native.providerFiles[${i}]`));
|
|
465
|
-
}
|
|
466
|
-
return {
|
|
467
|
-
formatVersion: 1,
|
|
468
|
-
configPath: absoluteConfig,
|
|
469
|
-
projectRoot,
|
|
470
|
-
lockPath: resolve(projectRoot, "acbr.lock.json"),
|
|
471
|
-
source: { url, revision: revision2, directory: localPath(source.directory, "source.directory") },
|
|
472
|
-
generator: { outputDir: localPath(generator.outputDir, "generator.outputDir") },
|
|
473
|
-
native: {
|
|
474
|
-
project: localPath(native.project, "native.project"),
|
|
475
|
-
outputDir: localPath(native.outputDir, "native.outputDir"),
|
|
476
|
-
fpc,
|
|
477
|
-
...native.lazarusRoot !== void 0 ? { lazarusRoot: localPath(native.lazarusRoot, "native.lazarusRoot") } : {},
|
|
478
|
-
...libraryFiles !== void 0 ? { libraryFiles } : {},
|
|
479
|
-
...providerFiles !== void 0 ? { providerFiles } : {}
|
|
480
|
-
}
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
async function loadConfig(path3 = "acbr.config.json") {
|
|
484
|
-
const configPath = resolve(path3);
|
|
485
|
-
let contents;
|
|
486
|
-
try {
|
|
487
|
-
contents = await readFile(configPath, "utf8");
|
|
488
|
-
} catch (error) {
|
|
489
|
-
throw new Error(`N\xE3o foi poss\xEDvel ler ${configPath}. Execute acbr-node init.`, { cause: error });
|
|
490
|
-
}
|
|
491
|
-
let value;
|
|
492
|
-
try {
|
|
493
|
-
value = JSON.parse(contents);
|
|
494
|
-
} catch (error) {
|
|
495
|
-
throw new Error(`JSON inv\xE1lido em ${configPath}.`, { cause: error });
|
|
496
|
-
}
|
|
497
|
-
return parseConfig(value, configPath);
|
|
498
|
-
}
|
|
499
|
-
async function initializeConfig(path3 = "acbr.config.json", revision2 = "HEAD", assetRoot) {
|
|
500
|
-
const configPath = resolve(path3);
|
|
501
|
-
const config = defaultConfig();
|
|
502
|
-
config.source.revision = revision2;
|
|
503
|
-
parseConfig(config, configPath);
|
|
504
|
-
await mkdir(dirname(configPath), { recursive: true });
|
|
505
|
-
try {
|
|
506
|
-
await access(configPath);
|
|
507
|
-
throw Object.assign(new Error(`EEXIST: configura\xE7\xE3o j\xE1 existe: ${configPath}`), { code: "EEXIST" });
|
|
508
|
-
} catch (error) {
|
|
509
|
-
if (error.code !== "ENOENT") throw error;
|
|
510
|
-
}
|
|
511
|
-
const resolved = parseConfig(config, configPath);
|
|
512
|
-
if (assetRoot) await copyInitAssets(assetRoot, resolved.projectRoot);
|
|
513
|
-
await writeFile(configPath, `${JSON.stringify(config, null, 2)}
|
|
514
|
-
`, { flag: "wx" });
|
|
515
|
-
await mkdir(resolve(resolved.projectRoot, ".acbr/generated"), { recursive: true });
|
|
516
|
-
await mkdir(resolve(resolved.projectRoot, "generated/acbr"), { recursive: true });
|
|
517
|
-
return resolved;
|
|
518
|
-
}
|
|
519
|
-
async function copyInitAssets(assetRoot, targetRoot) {
|
|
520
|
-
const entries = [];
|
|
521
|
-
async function scan(current, target) {
|
|
522
|
-
for (const entry of await readdir(current, { withFileTypes: true })) {
|
|
523
|
-
if (entry.name === "generated" || entry.name.startsWith(".")) continue;
|
|
524
|
-
const source = resolve(current, entry.name);
|
|
525
|
-
const destination = resolve(target, entry.name);
|
|
526
|
-
if (entry.isDirectory()) await scan(source, destination);
|
|
527
|
-
else if (entry.isFile() && /\.(pas|lpr|inc|lpi)$/i.test(entry.name)) entries.push({ source, destination, content: await readFile(source) });
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
await scan(resolve(assetRoot, "native"), resolve(targetRoot, "native"));
|
|
531
|
-
if (!entries.some((entry) => entry.source.endsWith("acbr-worker.lpr"))) throw new Error("Assets do pacote n\xE3o cont\xEAm native/acbr-worker.lpr.");
|
|
532
|
-
entries.push({ source: resolve(assetRoot, "tools/extract-model.lpr"), destination: resolve(targetRoot, "tools/extract-model.lpr"), content: await readFile(resolve(assetRoot, "tools/extract-model.lpr")) });
|
|
533
|
-
for (const entry of entries) {
|
|
534
|
-
try {
|
|
535
|
-
const existing = await readFile(entry.destination);
|
|
536
|
-
if (!existing.equals(entry.content)) throw new Error(`init preservou arquivo existente divergente: ${entry.destination}.`);
|
|
537
|
-
} catch (error) {
|
|
538
|
-
if (error.code !== "ENOENT") throw error;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
for (const entry of entries) {
|
|
542
|
-
await mkdir(dirname(entry.destination), { recursive: true });
|
|
543
|
-
try {
|
|
544
|
-
await writeFile(entry.destination, entry.content, { flag: "wx" });
|
|
545
|
-
} catch (error) {
|
|
546
|
-
if (error.code !== "EEXIST") throw error;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// src/native-build.ts
|
|
552
|
-
import { copyFile as copyFile2, mkdir as mkdir3, readdir as readdir3, readFile as readFile3, rename as rename2, rm as rm2, stat as stat2, chmod, realpath, access as access3, writeFile as writeFile3 } from "node:fs/promises";
|
|
553
|
-
import { basename, dirname as dirname3, join as join2, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
554
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
555
|
-
import { fileURLToPath } from "node:url";
|
|
556
|
-
|
|
557
|
-
// src/source.ts
|
|
558
|
-
import { spawn } from "node:child_process";
|
|
559
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
560
|
-
import { createReadStream } from "node:fs";
|
|
561
|
-
import { access as access2, mkdir as mkdir2, readdir as readdir2, readFile as readFile2, rename, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
562
|
-
import { dirname as dirname2, join, relative, resolve as resolve2, sep } from "node:path";
|
|
563
|
-
async function runCommand(command, args, options = {}) {
|
|
564
|
-
return new Promise((done, fail2) => {
|
|
565
|
-
const child = spawn(command, args, { cwd: options.cwd, env: options.env ?? process.env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, shell: false });
|
|
566
|
-
let stdout = "";
|
|
567
|
-
let stderr = "";
|
|
568
|
-
let overflow = false;
|
|
569
|
-
const maximum = options.maxOutputBytes ?? 16 * 1024 * 1024;
|
|
570
|
-
const append = (kind, data) => {
|
|
571
|
-
if (overflow) return;
|
|
572
|
-
if (kind === "stdout") stdout += data.toString("utf8");
|
|
573
|
-
else stderr += data.toString("utf8");
|
|
574
|
-
if (Buffer.byteLength(stdout) + Buffer.byteLength(stderr) > maximum) {
|
|
575
|
-
overflow = true;
|
|
576
|
-
child.kill();
|
|
577
|
-
}
|
|
578
|
-
};
|
|
579
|
-
child.stdout.on("data", (data) => append("stdout", data));
|
|
580
|
-
child.stderr.on("data", (data) => append("stderr", data));
|
|
581
|
-
child.on("error", (error) => fail2(new Error(`N\xE3o foi poss\xEDvel executar ${command}: ${error.message}`, { cause: error })));
|
|
582
|
-
child.on("close", (code) => {
|
|
583
|
-
if (overflow) fail2(new Error(`Sa\xEDda de ${command} excedeu o limite de ${maximum} bytes.`));
|
|
584
|
-
else if (code !== 0) {
|
|
585
|
-
const diagnostic = (stderr || stdout).split("\n").slice(-80).join("\n").slice(-16e3);
|
|
586
|
-
fail2(Object.assign(new Error(`${command} terminou com c\xF3digo ${code}:
|
|
587
|
-
${diagnostic}`), { stdout, stderr }));
|
|
588
|
-
} else done({ stdout, stderr });
|
|
589
|
-
});
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
async function fileHash(path3) {
|
|
593
|
-
const hash2 = createHash("sha256");
|
|
594
|
-
for await (const chunk of createReadStream(path3)) hash2.update(chunk);
|
|
595
|
-
return hash2.digest("hex");
|
|
596
|
-
}
|
|
597
|
-
async function snapshotSource(directory) {
|
|
598
|
-
const files = /* @__PURE__ */ Object.create(null);
|
|
599
|
-
async function scan(current) {
|
|
600
|
-
const entries = (await readdir2(current, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name, "en"));
|
|
601
|
-
for (const entry of entries) {
|
|
602
|
-
if (entry.name === ".svn") continue;
|
|
603
|
-
const path3 = join(current, entry.name);
|
|
604
|
-
if (entry.isSymbolicLink()) throw new Error(`Fonte ACBr cont\xE9m link simb\xF3lico: ${path3}.`);
|
|
605
|
-
if (entry.isDirectory()) await scan(path3);
|
|
606
|
-
else if (entry.isFile()) files[relative(directory, path3).split(sep).join("/")] = await fileHash(path3);
|
|
607
|
-
else throw new Error(`Fonte ACBr cont\xE9m arquivo especial: ${path3}.`);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
await scan(resolve2(directory));
|
|
611
|
-
const sortedFiles = Object.fromEntries(Object.entries(files).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
612
|
-
const treeHash = createHash("sha256").update(JSON.stringify(sortedFiles)).digest("hex");
|
|
613
|
-
return { treeHash, files: sortedFiles };
|
|
614
|
-
}
|
|
615
|
-
function validateLock(value) {
|
|
616
|
-
if (!value || typeof value !== "object") throw new Error("Lock ACBr inv\xE1lido.");
|
|
617
|
-
const lock = value;
|
|
618
|
-
if (lock.formatVersion !== 1 || !lock.source || !Number.isSafeInteger(lock.source.revision) || lock.source.revision < 1 || !Array.isArray(lock.source.parts) || !lock.source.files || typeof lock.source.files !== "object" || Array.isArray(lock.source.files) || !/^[a-f0-9]{64}$/.test(lock.source.treeHash)) throw new Error("Formato inv\xE1lido em acbr.lock.json.");
|
|
619
|
-
for (const [path3, hash2] of Object.entries(lock.source.files)) {
|
|
620
|
-
if (path3.startsWith("/") || path3.includes("\\") || path3.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(hash2)) throw new Error("Caminho ou hash inv\xE1lido no lock ACBr.");
|
|
621
|
-
}
|
|
622
|
-
if (lock.source.parts.join("\n") !== SOURCE_PARTS.join("\n")) throw new Error("Partes ACBr divergentes no lock.");
|
|
623
|
-
return lock;
|
|
624
|
-
}
|
|
625
|
-
async function readSourceLock(config) {
|
|
626
|
-
let lock;
|
|
627
|
-
try {
|
|
628
|
-
lock = validateLock(JSON.parse(await readFile2(config.lockPath, "utf8")));
|
|
629
|
-
} catch (error) {
|
|
630
|
-
throw new Error(`N\xE3o foi poss\xEDvel ler ${config.lockPath}. Execute acbr-node source update.`, { cause: error });
|
|
631
|
-
}
|
|
632
|
-
if (lock.source.url !== config.source.url) throw new Error("URL ACBr do lock diverge da configura\xE7\xE3o.");
|
|
633
|
-
if (config.source.revision !== "HEAD" && lock.source.revision !== config.source.revision) throw new Error("Revis\xE3o ACBr do lock diverge da configura\xE7\xE3o. Execute source update explicitamente.");
|
|
634
|
-
return lock;
|
|
635
|
-
}
|
|
636
|
-
async function verifySource(config) {
|
|
637
|
-
try {
|
|
638
|
-
await access2(`${config.lockPath}.operation`);
|
|
639
|
-
} catch (error) {
|
|
640
|
-
if (error.code === "ENOENT") return verifySourceContents(config);
|
|
641
|
-
throw error;
|
|
642
|
-
}
|
|
643
|
-
throw new Error("Atualiza\xE7\xE3o de fontes ACBr em andamento. Aguarde o CLI concluir.");
|
|
264
|
+
throw new Error("Atualiza\xE7\xE3o de fontes ACBr em andamento. Aguarde o CLI concluir.");
|
|
644
265
|
}
|
|
645
266
|
async function verifySourceContents(config) {
|
|
646
267
|
const lock = await readSourceLock(config);
|
|
647
268
|
const snapshot = await snapshotSource(config.source.directory);
|
|
648
269
|
if (snapshot.treeHash !== lock.source.treeHash) {
|
|
649
270
|
const names = /* @__PURE__ */ new Set([...Object.keys(snapshot.files), ...Object.keys(lock.source.files)]);
|
|
650
|
-
const changed = [...names].filter((
|
|
271
|
+
const changed = [...names].filter((path4) => snapshot.files[path4] !== lock.source.files[path4]);
|
|
651
272
|
throw new Error(`Fontes ACBr divergem do lock (${changed.length} arquivo(s)): ${changed.slice(0, 10).join(", ")}. Preserve as altera\xE7\xF5es antes de atualizar.`);
|
|
652
273
|
}
|
|
653
274
|
return lock;
|
|
@@ -718,7 +339,7 @@ async function performUpdateSource(config, revision2, runner) {
|
|
|
718
339
|
await mkdir2(stage, { recursive: true });
|
|
719
340
|
let previousLock;
|
|
720
341
|
try {
|
|
721
|
-
previousLock = await
|
|
342
|
+
previousLock = await readFile3(config.lockPath, "utf8");
|
|
722
343
|
} catch (error) {
|
|
723
344
|
if (error.code !== "ENOENT") throw error;
|
|
724
345
|
}
|
|
@@ -757,7 +378,7 @@ async function performUpdateSource(config, revision2, runner) {
|
|
|
757
378
|
}
|
|
758
379
|
}
|
|
759
380
|
async function persistRevision(config, revision2) {
|
|
760
|
-
const original = JSON.parse(await
|
|
381
|
+
const original = JSON.parse(await readFile3(config.configPath, "utf8"));
|
|
761
382
|
original.source.revision = revision2;
|
|
762
383
|
const temporary = `${config.configPath}.${randomUUID()}.tmp`;
|
|
763
384
|
await writeFile2(temporary, `${JSON.stringify(original, null, 2)}
|
|
@@ -768,29 +389,47 @@ async function persistRevision(config, revision2) {
|
|
|
768
389
|
await rm(temporary, { force: true });
|
|
769
390
|
}
|
|
770
391
|
}
|
|
392
|
+
var init_source = __esm({
|
|
393
|
+
"src/source.ts"() {
|
|
394
|
+
"use strict";
|
|
395
|
+
init_config();
|
|
396
|
+
}
|
|
397
|
+
});
|
|
771
398
|
|
|
772
399
|
// src/native-build.ts
|
|
400
|
+
var native_build_exports = {};
|
|
401
|
+
__export(native_build_exports, {
|
|
402
|
+
buildNative: () => buildNative,
|
|
403
|
+
checkBuild: () => checkBuild,
|
|
404
|
+
doctor: () => doctor,
|
|
405
|
+
findLazarus: () => findLazarus,
|
|
406
|
+
runtimeDirectory: () => runtimeDirectory
|
|
407
|
+
});
|
|
408
|
+
import { copyFile as copyFile2, mkdir as mkdir3, readdir as readdir3, readFile as readFile4, rename as rename2, rm as rm2, stat as stat2, chmod, realpath, access as access3, writeFile as writeFile3 } from "node:fs/promises";
|
|
409
|
+
import { basename, dirname as dirname3, join as join2, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
410
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
411
|
+
import { fileURLToPath } from "node:url";
|
|
773
412
|
function runtimeDirectory(config) {
|
|
774
413
|
return join2(config.native.outputDir, `${process.platform}-${process.arch}`);
|
|
775
414
|
}
|
|
776
|
-
async function exists(
|
|
415
|
+
async function exists(path4) {
|
|
777
416
|
try {
|
|
778
|
-
await access3(
|
|
417
|
+
await access3(path4);
|
|
779
418
|
return true;
|
|
780
419
|
} catch {
|
|
781
420
|
return false;
|
|
782
421
|
}
|
|
783
422
|
}
|
|
784
423
|
async function findLazarus(config) {
|
|
785
|
-
const candidates = config.native.lazarusRoot ? [config.native.lazarusRoot] : [process.env.LAZARUS_ROOT, "/usr/lib/lazarus/default", "/usr/lib/lazarus/3.0", "C:\\lazarus"].filter((
|
|
424
|
+
const candidates = config.native.lazarusRoot ? [config.native.lazarusRoot] : [process.env.LAZARUS_ROOT, "/usr/lib/lazarus/default", "/usr/lib/lazarus/3.0", "C:\\lazarus"].filter((path4) => Boolean(path4));
|
|
786
425
|
for (const candidate of candidates) if (await exists(join2(candidate, "components/lazutils"))) return realpath(candidate);
|
|
787
426
|
throw new Error("Lazarus n\xE3o encontrado. Defina native.lazarusRoot em acbr.config.json ou LAZARUS_ROOT.");
|
|
788
427
|
}
|
|
789
428
|
async function generatedManifest(config) {
|
|
790
|
-
const
|
|
429
|
+
const path4 = join2(config.generator.outputDir, ".acbr/generated/manifest.json");
|
|
791
430
|
let value;
|
|
792
431
|
try {
|
|
793
|
-
value = JSON.parse(await
|
|
432
|
+
value = JSON.parse(await readFile4(path4, "utf8"));
|
|
794
433
|
} catch (error) {
|
|
795
434
|
throw new Error("Contrato gerado ausente ou inv\xE1lido. Execute acbr-node generate.", { cause: error });
|
|
796
435
|
}
|
|
@@ -804,23 +443,21 @@ async function generatedManifest(config) {
|
|
|
804
443
|
}
|
|
805
444
|
return value;
|
|
806
445
|
}
|
|
807
|
-
async function subdirectories(
|
|
808
|
-
const result = [
|
|
809
|
-
for (const entry of (await readdir3(
|
|
810
|
-
if (entry.isDirectory()) result.push(...await subdirectories(join2(
|
|
446
|
+
async function subdirectories(path4) {
|
|
447
|
+
const result = [path4];
|
|
448
|
+
for (const entry of (await readdir3(path4, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
449
|
+
if (entry.isDirectory()) result.push(...await subdirectories(join2(path4, entry.name)));
|
|
811
450
|
}
|
|
812
451
|
return result;
|
|
813
452
|
}
|
|
814
|
-
var REQUIRED_DYNAMIC = ["libssl.so.3", "libcrypto.so.3", "libxml2.so.2"];
|
|
815
|
-
var CORE_SYSTEM = /^(?:lib(?:c|m|pthread|dl|rt|resolv|anl|util)\.so(?:\.|$)|ld-linux|linux-vdso)/;
|
|
816
453
|
async function copyLinuxLibraries(stage) {
|
|
817
454
|
const { stdout } = await runCommand("ldconfig", ["-p"]);
|
|
818
455
|
const libraries = /* @__PURE__ */ new Map();
|
|
819
456
|
for (const name of REQUIRED_DYNAMIC) {
|
|
820
457
|
const line = stdout.split("\n").find((value) => value.trim().startsWith(`${name} `) && value.includes("x86-64"));
|
|
821
|
-
const
|
|
822
|
-
if (!
|
|
823
|
-
libraries.set(name, await realpath(
|
|
458
|
+
const path4 = line?.split("=>")[1]?.trim();
|
|
459
|
+
if (!path4) throw new Error(`Depend\xEAncia din\xE2mica ausente: ${name}. Instale OpenSSL 3 e libxml2 compat\xEDveis.`);
|
|
460
|
+
libraries.set(name, await realpath(path4));
|
|
824
461
|
}
|
|
825
462
|
const modules = "/usr/lib/x86_64-linux-gnu/ossl-modules";
|
|
826
463
|
if (!await exists(join2(modules, "legacy.so"))) throw new Error("Provider legacy OpenSSL 3 ausente. Instale o pacote libssl3/libssl3t64 completo.");
|
|
@@ -828,9 +465,9 @@ async function copyLinuxLibraries(stage) {
|
|
|
828
465
|
const systemDependencies = /* @__PURE__ */ new Set();
|
|
829
466
|
const inspected = /* @__PURE__ */ new Set();
|
|
830
467
|
while (inspected.size < libraries.size) {
|
|
831
|
-
const [name,
|
|
468
|
+
const [name, path4] = [...libraries].find(([name2]) => !inspected.has(name2));
|
|
832
469
|
inspected.add(name);
|
|
833
|
-
const dependencies = await runCommand("ldd", [
|
|
470
|
+
const dependencies = await runCommand("ldd", [path4]);
|
|
834
471
|
for (const line of dependencies.stdout.split("\n")) {
|
|
835
472
|
if (line.includes("not found")) throw new Error(`Depend\xEAncia transitiva ausente: ${line.trim()}.`);
|
|
836
473
|
const match = /^\s*(\S+)\s+=>\s+(\S+)/.exec(line);
|
|
@@ -848,17 +485,17 @@ async function copyLinuxLibraries(stage) {
|
|
|
848
485
|
const licenseDir = join2(stage, "licenses");
|
|
849
486
|
await mkdir3(licenseDir, { recursive: true });
|
|
850
487
|
const provenance = {};
|
|
851
|
-
for (const [name,
|
|
488
|
+
for (const [name, path4] of libraries) {
|
|
852
489
|
const destination = name.startsWith("ossl-modules/") ? join2(stage, name) : join2(stage, "lib", name);
|
|
853
490
|
await mkdir3(dirname3(destination), { recursive: true });
|
|
854
|
-
await copyFile2(
|
|
491
|
+
await copyFile2(path4, destination);
|
|
855
492
|
const aliases = name === "libssl.so.3" ? ["libssl.so"] : name === "libcrypto.so.3" ? ["libcrypto.so"] : name === "libxml2.so.2" ? ["libxml2.so"] : [];
|
|
856
|
-
for (const alias of aliases) await copyFile2(
|
|
493
|
+
for (const alias of aliases) await copyFile2(path4, join2(stage, "lib", alias));
|
|
857
494
|
let owner;
|
|
858
495
|
try {
|
|
859
|
-
owner = (await runCommand("dpkg-query", ["-S",
|
|
496
|
+
owner = (await runCommand("dpkg-query", ["-S", path4])).stdout.split("\n")[0].split(": ")[0];
|
|
860
497
|
} catch (error) {
|
|
861
|
-
throw new Error(`N\xE3o foi poss\xEDvel identificar pacote/licen\xE7a de ${
|
|
498
|
+
throw new Error(`N\xE3o foi poss\xEDvel identificar pacote/licen\xE7a de ${path4}. Build requer Debian/Ubuntu com depend\xEAncias registradas pelo dpkg.`, { cause: error });
|
|
862
499
|
}
|
|
863
500
|
const pkg = owner.split(":")[0];
|
|
864
501
|
const copyright = `/usr/share/doc/${pkg}/copyright`;
|
|
@@ -900,10 +537,10 @@ async function copyExplicitLibraries(config, stage) {
|
|
|
900
537
|
for (const source of files) {
|
|
901
538
|
await copyFile2(source, join2(stage, directory, basename(source)));
|
|
902
539
|
await copyFile2(`${source}.LICENSE`, join2(stage, "licenses", `${basename(source)}.txt`));
|
|
903
|
-
if (await exists(`${source}.SOURCE.json`)) sources[`${directory}/${basename(source)}`] = JSON.parse(await
|
|
540
|
+
if (await exists(`${source}.SOURCE.json`)) sources[`${directory}/${basename(source)}`] = JSON.parse(await readFile4(`${source}.SOURCE.json`, "utf8"));
|
|
904
541
|
}
|
|
905
542
|
}
|
|
906
|
-
if (!config.native.providerFiles?.some((
|
|
543
|
+
if (!config.native.providerFiles?.some((path4) => basename(path4).toLowerCase() === "legacy.dll")) throw new Error("Windows requer native.providerFiles com o provider legacy.dll de OpenSSL 3 e licen\xE7a adjacente.");
|
|
907
544
|
await mkdir3(join2(stage, "sources"), { recursive: true });
|
|
908
545
|
await writeFile3(join2(stage, "sources/native-dependencies.json"), `${JSON.stringify(sources, null, 2)}
|
|
909
546
|
`);
|
|
@@ -940,8 +577,8 @@ async function buildNative(config, options = {}) {
|
|
|
940
577
|
`-FU${units}`,
|
|
941
578
|
`-FE${stage}`,
|
|
942
579
|
`-o${executable}`,
|
|
943
|
-
...searchPaths.map((
|
|
944
|
-
...fontPaths.map((
|
|
580
|
+
...searchPaths.map((path4) => `-Fu${path4}`),
|
|
581
|
+
...fontPaths.map((path4) => `-Fi${path4}`),
|
|
945
582
|
config.native.project
|
|
946
583
|
];
|
|
947
584
|
const responseFile = join2(stage, ".compiler.rsp");
|
|
@@ -1010,6 +647,7 @@ Log completo: ${logPath}`, { cause: compilation });
|
|
|
1010
647
|
executable,
|
|
1011
648
|
files,
|
|
1012
649
|
generatedFileHashes: contract.fileHashes,
|
|
650
|
+
capabilities: ["recuperarXml"],
|
|
1013
651
|
systemDependencies,
|
|
1014
652
|
...options.testOnly ? { testOnly: true } : {}
|
|
1015
653
|
};
|
|
@@ -1046,148 +684,504 @@ async function replaceRuntime(stage, target) {
|
|
|
1046
684
|
if (hadTarget) await rename2(backup, target);
|
|
1047
685
|
throw error;
|
|
1048
686
|
}
|
|
1049
|
-
if (hadTarget) await rm2(backup, { recursive: true, force: true });
|
|
687
|
+
if (hadTarget) await rm2(backup, { recursive: true, force: true });
|
|
688
|
+
}
|
|
689
|
+
async function checkBuild(config) {
|
|
690
|
+
const lock = await verifySource(config);
|
|
691
|
+
const generated = await generatedManifest(config);
|
|
692
|
+
const directory = runtimeDirectory(config);
|
|
693
|
+
const manifest = JSON.parse(await readFile4(join2(directory, "manifest.json"), "utf8"));
|
|
694
|
+
if (manifest.formatVersion !== 1 || manifest.platform !== process.platform || manifest.arch !== process.arch || manifest.sourceRevision !== lock.source.revision || generated.sourceHash !== lock.source.treeHash || manifest.contractHash !== generated.contractHash || !manifest.generatedFileHashes || Object.entries(generated.fileHashes).some(([name, hash2]) => manifest.generatedFileHashes[name] !== hash2) || !Array.isArray(manifest.capabilities) || !manifest.capabilities.includes("recuperarXml") || typeof manifest.executable !== "string" || !manifest.files || !Object.hasOwn(manifest.files, manifest.executable)) throw new Error("Runtime diverge das fontes ou contrato. Execute build.");
|
|
695
|
+
for (const [path4, expected] of Object.entries(manifest.files)) {
|
|
696
|
+
if (path4.startsWith("/") || path4.includes("\\") || path4.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(expected)) throw new Error(`Caminho/hash inv\xE1lido no runtime: ${path4}.`);
|
|
697
|
+
if (await fileHash(join2(directory, path4)) !== expected) throw new Error(`Hash inv\xE1lido no runtime: ${path4}.`);
|
|
698
|
+
}
|
|
699
|
+
return manifest;
|
|
700
|
+
}
|
|
701
|
+
async function doctor(config) {
|
|
702
|
+
const items = [{ name: "Node.js", ok: Number(process.versions.node.split(".")[0]) > 22 || Number(process.versions.node.split(".")[0]) === 22 && Number(process.versions.node.split(".")[1]) >= 12, detail: process.versions.node }];
|
|
703
|
+
for (const [name, command, args] of [["SVN", "svn", ["--version", "--quiet"]], ["Free Pascal", config?.native.fpc ?? "fpc", ["-iV"]]]) {
|
|
704
|
+
try {
|
|
705
|
+
const result = await runCommand(command, [...args]);
|
|
706
|
+
items.push({ name, ok: true, detail: result.stdout.trim() });
|
|
707
|
+
} catch (error) {
|
|
708
|
+
items.push({ name, ok: false, detail: error.message });
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (config) {
|
|
712
|
+
try {
|
|
713
|
+
items.push({ name: "Lazarus", ok: true, detail: await findLazarus(config) });
|
|
714
|
+
} catch (error) {
|
|
715
|
+
items.push({ name: "Lazarus", ok: false, detail: error.message });
|
|
716
|
+
}
|
|
717
|
+
try {
|
|
718
|
+
const lock = await verifySource(config);
|
|
719
|
+
items.push({ name: "Fontes ACBr", ok: true, detail: `revis\xE3o ${lock.source.revision}, ${lock.source.treeHash}` });
|
|
720
|
+
} catch (error) {
|
|
721
|
+
items.push({ name: "Fontes ACBr", ok: false, detail: error.message });
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (process.platform === "linux") {
|
|
725
|
+
try {
|
|
726
|
+
const result = await runCommand("ldconfig", ["-p"]);
|
|
727
|
+
const missing = REQUIRED_DYNAMIC.filter((name) => !result.stdout.includes(name));
|
|
728
|
+
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: missing.length === 0, detail: missing.length ? `Ausentes: ${missing.join(", ")}` : REQUIRED_DYNAMIC.join(", ") });
|
|
729
|
+
} catch (error) {
|
|
730
|
+
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: false, detail: error.message });
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return items;
|
|
734
|
+
}
|
|
735
|
+
async function copyCompilerLicenses(config, stage, lazarus) {
|
|
736
|
+
const packagedLazarus = fileURLToPath(new URL("../docs/licenses/lazarus/", import.meta.url));
|
|
737
|
+
const packagedFpc = fileURLToPath(new URL("../docs/licenses/fpc/", import.meta.url));
|
|
738
|
+
const notices = {};
|
|
739
|
+
async function copyNotice(name, candidates2) {
|
|
740
|
+
for (const source of candidates2) if (await exists(source)) {
|
|
741
|
+
await copyFile2(source, join2(stage, "licenses", name));
|
|
742
|
+
notices[name] = { source, sha256: await fileHash(source) };
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
throw new Error(`Notice obrigat\xF3rio ausente: ${name}.`);
|
|
746
|
+
}
|
|
747
|
+
for (const name of ["COPYING.txt", "COPYING.LGPL.txt", "COPYING.modifiedLGPL.txt"]) {
|
|
748
|
+
await copyNotice(`Lazarus-${name}`, [join2(lazarus, name), join2(lazarus, "docs", name), join2(packagedLazarus, name)]);
|
|
749
|
+
}
|
|
750
|
+
if (await exists(join2(packagedLazarus, "ORIGIN.json"))) await copyFile2(join2(packagedLazarus, "ORIGIN.json"), join2(stage, "licenses/Lazarus-notice-origin.json"));
|
|
751
|
+
const fpcRoot = resolve3(dirname3(config.native.fpc), "../..");
|
|
752
|
+
const sourceRoots = [join2(fpcRoot, "source"), join2(lazarus, "fpc/3.2.2/source"), "/usr/share/fpcsrc/3.2.2"];
|
|
753
|
+
for (const [name, sourceRelative] of [["COPYING.GPL.txt", "compiler/COPYING.txt"], ["COPYING.LGPL.txt", "rtl/COPYING.txt"], ["COPYING.FPC", "rtl/COPYING.FPC"]]) {
|
|
754
|
+
await copyNotice(`FPC-${name}`, [...sourceRoots.map((directory) => join2(directory, sourceRelative)), join2(packagedFpc, name)]);
|
|
755
|
+
}
|
|
756
|
+
if (await exists(join2(packagedFpc, "ORIGIN.json"))) await copyFile2(join2(packagedFpc, "ORIGIN.json"), join2(stage, "licenses/FPC-notice-origin.json"));
|
|
757
|
+
const candidates = [join2(fpcRoot, "doc"), fpcRoot, join2(lazarus, "fpc"), "/usr/share/doc/fp-compiler-3.2.2", "/usr/share/doc/fp-units-rtl-3.2.2"];
|
|
758
|
+
for (const directory of candidates) {
|
|
759
|
+
if (!await exists(directory)) continue;
|
|
760
|
+
for (const name of await readdir3(directory)) {
|
|
761
|
+
if (/^(?:copying|license|copyright)/i.test(name) && (await stat2(join2(directory, name))).isFile()) await copyFile2(join2(directory, name), join2(stage, "licenses", `FPC-${basename(directory)}-${name}`));
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
await writeFile3(join2(stage, "licenses/toolchain-notices.json"), `${JSON.stringify(notices, null, 2)}
|
|
765
|
+
`);
|
|
766
|
+
}
|
|
767
|
+
var REQUIRED_DYNAMIC, CORE_SYSTEM;
|
|
768
|
+
var init_native_build = __esm({
|
|
769
|
+
"src/native-build.ts"() {
|
|
770
|
+
"use strict";
|
|
771
|
+
init_source();
|
|
772
|
+
REQUIRED_DYNAMIC = ["libssl.so.3", "libcrypto.so.3", "libxml2.so.2"];
|
|
773
|
+
CORE_SYSTEM = /^(?:lib(?:c|m|pthread|dl|rt|resolv|anl|util)\.so(?:\.|$)|ld-linux|linux-vdso)/;
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
// src/generator.ts
|
|
778
|
+
var generator_exports = {};
|
|
779
|
+
__export(generator_exports, {
|
|
780
|
+
buildModelIR: () => buildModelIR,
|
|
781
|
+
compareContracts: () => compareContracts,
|
|
782
|
+
generateModel: () => generateModel,
|
|
783
|
+
renderClientIndex: () => renderClientIndex,
|
|
784
|
+
renderContractMetadata: () => renderContractMetadata,
|
|
785
|
+
renderModelValidation: () => renderModelValidation,
|
|
786
|
+
renderPascal: () => renderPascal,
|
|
787
|
+
renderTypeScript: () => renderTypeScript
|
|
788
|
+
});
|
|
789
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
790
|
+
import { execFile } from "node:child_process";
|
|
791
|
+
import { promisify } from "node:util";
|
|
792
|
+
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4, readdir as readdir4 } from "node:fs/promises";
|
|
793
|
+
import path2 from "node:path";
|
|
794
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
795
|
+
function buildModelIR(raw) {
|
|
796
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
797
|
+
for (const unit of raw.units) for (const type of unit.types) declarations.set((unit.name + "." + type.name).toLowerCase(), { unit, type });
|
|
798
|
+
function find(name, unit) {
|
|
799
|
+
for (const key of [unit.name + "." + name, ...[...unit.uses].reverse().map((u) => u + "." + name), name]) {
|
|
800
|
+
const item = declarations.get(key.toLowerCase());
|
|
801
|
+
if (item) return item;
|
|
802
|
+
}
|
|
803
|
+
throw new Error("Tipo Pascal n\xE3o resolvido: " + unit.name + "." + name);
|
|
804
|
+
}
|
|
805
|
+
function resolve5(name, unit, trail = /* @__PURE__ */ new Set()) {
|
|
806
|
+
if (primitives[name.toLowerCase()]) return { primitive: name.toLowerCase() };
|
|
807
|
+
const found = find(name, unit), key = (found.unit.name + "." + found.type.name).toLowerCase();
|
|
808
|
+
if (trail.has(key)) throw new Error("Alias Pascal c\xEDclico: " + key);
|
|
809
|
+
if (found.type.kind === "alias") {
|
|
810
|
+
trail.add(key);
|
|
811
|
+
return resolve5(found.type.target, found.unit, trail);
|
|
812
|
+
}
|
|
813
|
+
return found;
|
|
814
|
+
}
|
|
815
|
+
const rootUnit = raw.units.find((u) => u.types.some((t) => t.name === raw.root));
|
|
816
|
+
if (!rootUnit) throw new Error("Modelo raiz ausente: " + raw.root);
|
|
817
|
+
const generated = /* @__PURE__ */ new Map();
|
|
818
|
+
function visit(name, unit) {
|
|
819
|
+
const found = resolve5(name, unit);
|
|
820
|
+
if ("primitive" in found) return primitives[found.primitive];
|
|
821
|
+
const { type, unit: declUnit } = found, key = type.name;
|
|
822
|
+
if (generated.has(key)) {
|
|
823
|
+
const node2 = generated.get(key);
|
|
824
|
+
if (node2.unit !== declUnit.name) throw new Error("Tipos hom\xF4nimos incompat\xEDveis: " + key);
|
|
825
|
+
return { kind: node2.kind === "object" ? "object" : node2.kind === "list" ? "list" : "enum", ref: key };
|
|
826
|
+
}
|
|
827
|
+
if (type.kind === "enum") {
|
|
828
|
+
const values = type.values.map((v) => v.name);
|
|
829
|
+
if (!values.length) throw new Error("Enum sem valores: " + key);
|
|
830
|
+
generated.set(key, { name: key, unit: declUnit.name, kind: "enum", values });
|
|
831
|
+
return { kind: "enum", ref: key };
|
|
832
|
+
}
|
|
833
|
+
if (type.kind !== "class") throw new Error("Declara\xE7\xE3o Pascal n\xE3o suportada: " + declUnit.name + "." + key + " (" + (type.declarationKind ?? type.kind) + ")");
|
|
834
|
+
const creator = type.methods?.find((m) => m.name.toLowerCase() === "new" && m.arguments === 0);
|
|
835
|
+
const indexed = type.properties?.find((p) => p.indexed && p.name.toLowerCase() === "items");
|
|
836
|
+
if (creator || indexed) {
|
|
837
|
+
if (!creator || !indexed || !indexed.readable) throw new Error("Cole\xE7\xE3o sem contrato New/Items tipado: " + key);
|
|
838
|
+
const item = resolve5(creator.result, declUnit), itemProperty = resolve5(indexed.type, declUnit);
|
|
839
|
+
if ("primitive" in item || "primitive" in itemProperty || item.type.name !== itemProperty.type.name) throw new Error("Cole\xE7\xE3o com tipos New/Items divergentes: " + key);
|
|
840
|
+
generated.set(key, { name: key, unit: declUnit.name, kind: "list", item: item.type.name, factory: creator.name });
|
|
841
|
+
if (visit(creator.result, declUnit).kind !== "object") throw new Error("Item de cole\xE7\xE3o n\xE3o \xE9 objeto: " + key);
|
|
842
|
+
return { kind: "list", ref: key };
|
|
843
|
+
}
|
|
844
|
+
const node = { name: key, unit: declUnit.name, kind: "object", properties: [] };
|
|
845
|
+
generated.set(key, node);
|
|
846
|
+
let inherited = [];
|
|
847
|
+
if (type.ancestor && !bases.has(type.ancestor.toLowerCase())) {
|
|
848
|
+
const ancestor = visit(type.ancestor, declUnit);
|
|
849
|
+
if (ancestor.kind !== "object") throw new Error("Heran\xE7a n\xE3o suportada: " + key);
|
|
850
|
+
inherited = generated.get(ancestor.ref).properties;
|
|
851
|
+
}
|
|
852
|
+
const props = new Map(inherited.map((p) => [p.name.toLowerCase(), p]));
|
|
853
|
+
for (const p of type.properties ?? []) {
|
|
854
|
+
if (p.indexed) throw new Error("Propriedade indexada fora de cole\xE7\xE3o: " + key + "." + p.name);
|
|
855
|
+
if (!p.readable) throw new Error("Propriedade sem leitura: " + key + "." + p.name);
|
|
856
|
+
const resolved = visit(p.type, declUnit);
|
|
857
|
+
const readonly = !p.writable && !["object", "list"].includes(resolved.kind) || key === raw.root && ["signature", "procnfe", "infnfesupl"].includes(p.name.toLowerCase());
|
|
858
|
+
props.set(p.name.toLowerCase(), { name: p.name, type: p.type, ...resolved, readonly, ...p.default ? { declaredDefault: p.default } : {} });
|
|
859
|
+
}
|
|
860
|
+
node.properties = [...props.values()].sort((a, b) => a.name.localeCompare(b.name, "en"));
|
|
861
|
+
return { kind: "object", ref: key };
|
|
862
|
+
}
|
|
863
|
+
visit(raw.root, rootUnit);
|
|
864
|
+
return { schemaVersion: 1, root: raw.root, types: [...generated.values()].sort((a, b) => a.name.localeCompare(b.name, "en")) };
|
|
865
|
+
}
|
|
866
|
+
function compareContracts(previous, current) {
|
|
867
|
+
const old = new Map(previous?.types.map((t) => [t.name, t]) ?? []), now = new Map(current.types.map((t) => [t.name, t]));
|
|
868
|
+
const additions = [], removals = [], changes = [];
|
|
869
|
+
for (const [name, type] of now) {
|
|
870
|
+
const before = old.get(name);
|
|
871
|
+
if (!before) {
|
|
872
|
+
additions.push(name);
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
if (type.kind !== before.kind) {
|
|
876
|
+
changes.push(name + ":kind");
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
if (type.kind === "object") {
|
|
880
|
+
const a = new Map(before.properties.map((p) => [p.name, p])), b = new Map(type.properties.map((p) => [p.name, p]));
|
|
881
|
+
for (const [field, p] of b) {
|
|
882
|
+
if (!a.has(field)) additions.push(name + "." + field);
|
|
883
|
+
else if (stable(a.get(field)) !== stable(p)) changes.push(name + "." + field);
|
|
884
|
+
}
|
|
885
|
+
for (const field of a.keys()) if (!b.has(field)) removals.push(name + "." + field);
|
|
886
|
+
} else if (type.kind === "enum") {
|
|
887
|
+
for (const v of type.values) if (!before.values.includes(v)) additions.push(name + "." + v);
|
|
888
|
+
for (const v of before.values) if (!type.values.includes(v)) removals.push(name + "." + v);
|
|
889
|
+
} else if (type.item !== before.item) changes.push(name + ":item");
|
|
890
|
+
}
|
|
891
|
+
for (const name of old.keys()) if (!now.has(name)) removals.push(name);
|
|
892
|
+
return { additions: additions.sort(), removals: removals.sort(), changes: changes.sort(), breaking: removals.length > 0 || changes.length > 0 };
|
|
893
|
+
}
|
|
894
|
+
function renderModelValidation() {
|
|
895
|
+
return String.raw`
|
|
896
|
+
export type CodigoValidacaoModelo = 'MODELO_DESCONHECIDO'|'ENUM_INVALIDO'|'ARRAY_ESPERADO'|'OBJETO_ESPERADO'|'CAMPO_DESCONHECIDO'|'CAMPO_SOMENTE_LEITURA'|'INTEIRO_INVALIDO'|'BOOLEANO_ESPERADO'|'DECIMAL_INVALIDO'|'DATA_HORA_INVALIDA'|'DATA_INVALIDA'|'TEXTO_ESPERADO';
|
|
897
|
+
function campoConhecido(at: unknown): string | undefined {
|
|
898
|
+
if(typeof at!=='string'||at.length>512||! /^[A-Za-z_]\w*(?:(?:\.[A-Za-z_]\w*)|(?:\[\d{1,7}\]))*$/.test(at))return undefined;
|
|
899
|
+
const parts=at.replace(/\[(\d+)\]/g,'.$1').split('.');let schema=Object.hasOwn(MODEL_SCHEMA,parts[0])?MODEL_SCHEMA[parts[0]]:undefined;
|
|
900
|
+
if(!schema)return undefined;
|
|
901
|
+
for(const part of parts.slice(1)){
|
|
902
|
+
if(schema.kind==='list'){if(! /^\d+$/.test(part))return undefined;schema=MODEL_SCHEMA[schema.item];}
|
|
903
|
+
else if(schema.kind==='object'){const p=schema.properties.find((p:any)=>p.name===part);if(!p)return undefined;schema=p.ref?MODEL_SCHEMA[p.ref]:{kind:p.kind};}
|
|
904
|
+
else return undefined;
|
|
905
|
+
}
|
|
906
|
+
return at;
|
|
907
|
+
}
|
|
908
|
+
/** TypeError compatível, com contexto seguro e sem o valor informado ou chaves desconhecidas. */
|
|
909
|
+
export class ErroValidacaoModelo extends TypeError {
|
|
910
|
+
readonly codigo: CodigoValidacaoModelo;
|
|
911
|
+
readonly diagnostico: Readonly<{codigo:CodigoValidacaoModelo;etapa:'documento';campo?:string;mensagem:string;acao:string;statusEnvio:'nao_enviado';causa:Readonly<{codigo:CodigoValidacaoModelo;etapa:'documento';campo?:string}>}>;
|
|
912
|
+
constructor(codigo: CodigoValidacaoModelo, at?: string) {
|
|
913
|
+
const catalogo:Record<CodigoValidacaoModelo,[string,string]>={
|
|
914
|
+
MODELO_DESCONHECIDO:['Modelo desconhecido.','Use um modelo exportado pelo cliente gerado.'],
|
|
915
|
+
ENUM_INVALIDO:['enum inválido','Use um dos valores textuais do enum exportado pelo cliente.'],
|
|
916
|
+
ARRAY_ESPERADO:['esperado array','Informe uma lista JSON entre colchetes.'],
|
|
917
|
+
OBJETO_ESPERADO:['esperado objeto','Informe um objeto JSON entre chaves.'],
|
|
918
|
+
CAMPO_DESCONHECIDO:['propriedade desconhecida','Confira os nomes permitidos neste grupo; a chave desconhecida não é registrada.'],
|
|
919
|
+
CAMPO_SOMENTE_LEITURA:['propriedade somente leitura','Remova este campo da entrada; o motor preenche seu resultado.'],
|
|
920
|
+
INTEIRO_INVALIDO:['inteiro fora do intervalo','Informe um número inteiro dentro do intervalo do campo.'],
|
|
921
|
+
BOOLEANO_ESPERADO:['esperado boolean','Informe true ou false como valor JSON, sem aspas.'],
|
|
922
|
+
DECIMAL_INVALIDO:['esperado decimal em string','Informe o decimal entre aspas, com ponto e a escala permitida pelo campo.'],
|
|
923
|
+
DATA_HORA_INVALIDA:['esperado data/hora civil ISO (sem timezone)','Informe a data/hora civil da UF como AAAA-MM-DDTHH:mm:ss, sem Z ou offset. Confira a data antes do envio.'],
|
|
924
|
+
DATA_INVALIDA:['data inválida','Confira dia, mês, ano e horário usando uma data civil válida.'],
|
|
925
|
+
TEXTO_ESPERADO:['esperado string','Informe texto entre aspas no JSON.']
|
|
926
|
+
};
|
|
927
|
+
const safeCode=Object.hasOwn(catalogo,codigo)?codigo:'MODELO_DESCONHECIDO';
|
|
928
|
+
const campo=campoConhecido(at),[texto,acao]=catalogo[safeCode],mensagem=(campo?campo+': ':'')+texto;
|
|
929
|
+
super(mensagem);this.codigo=safeCode;
|
|
930
|
+
const causa=Object.freeze({codigo:safeCode,etapa:'documento' as const,...(campo?{campo}:{})});
|
|
931
|
+
this.diagnostico=Object.freeze({codigo:safeCode,etapa:'documento' as const,...(campo?{campo}:{}),mensagem,acao,statusEnvio:'nao_enviado' as const,causa});
|
|
932
|
+
Object.defineProperty(this,'cause',{value:causa,enumerable:false});
|
|
933
|
+
}
|
|
934
|
+
toJSON(){return this.diagnostico;}
|
|
935
|
+
}
|
|
936
|
+
export function validateModel(model: string, value: unknown, at=model): void {
|
|
937
|
+
const schema=Object.hasOwn(MODEL_SCHEMA,model)?MODEL_SCHEMA[model]:undefined;
|
|
938
|
+
if(!schema)throw new ErroValidacaoModelo('MODELO_DESCONHECIDO');
|
|
939
|
+
at=campoConhecido(at)??model;
|
|
940
|
+
if(schema.kind==='enum'){if(typeof value!=='string'||!schema.values.includes(value))throw new ErroValidacaoModelo('ENUM_INVALIDO',at);return;}
|
|
941
|
+
if(schema.kind==='list'){if(!Array.isArray(value))throw new ErroValidacaoModelo('ARRAY_ESPERADO',at);value.forEach((item,index)=>validateModel(schema.item,item,at+'['+index+']'));return;}
|
|
942
|
+
if(value===null||typeof value!=='object'||Array.isArray(value))throw new ErroValidacaoModelo('OBJETO_ESPERADO',at);
|
|
943
|
+
const fields=new Map<string,any>(schema.properties.filter((p:any)=>!p.readonly).map((p:any)=>[p.name,p]));
|
|
944
|
+
for(const [name,v] of Object.entries(value)){
|
|
945
|
+
if(v===undefined)continue;
|
|
946
|
+
const p=fields.get(name);
|
|
947
|
+
if(!p){const readonly=schema.properties.some((p:any)=>p.name===name&&p.readonly);throw new ErroValidacaoModelo(readonly?'CAMPO_SOMENTE_LEITURA':'CAMPO_DESCONHECIDO',readonly?at+'.'+name:at);}
|
|
948
|
+
const field=at+'.'+name;
|
|
949
|
+
if(p.ref){validateModel(p.ref,v,field);continue;}
|
|
950
|
+
if(p.kind==='integer'){if(typeof v!=='number'||!Number.isSafeInteger(v)||v<p.min||v>p.max)throw new ErroValidacaoModelo('INTEIRO_INVALIDO',field);}
|
|
951
|
+
else if(p.kind==='boolean'){if(typeof v!=='boolean')throw new ErroValidacaoModelo('BOOLEANO_ESPERADO',field);}
|
|
952
|
+
else if(p.kind==='decimal'){if(typeof v!=='string'||v.length>64||! /^-?\d+(?:\.\d+)?$/.test(v)||p.scale!==undefined&&(v.split('.')[1]?.length??0)>p.scale)throw new ErroValidacaoModelo('DECIMAL_INVALIDO',field);}
|
|
953
|
+
else if(p.kind==='datetime'){
|
|
954
|
+
if(typeof v!=='string'||! /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?)?$/.test(v)||Number.isNaN(Date.parse(v+(v.length===10?'T00:00:00Z':'Z'))))throw new ErroValidacaoModelo('DATA_HORA_INVALIDA',field);
|
|
955
|
+
const date=new Date(v+(v.length===10?'T00:00:00Z':'Z'));if(date.toISOString().slice(0,10)!==v.slice(0,10))throw new ErroValidacaoModelo('DATA_INVALIDA',field);
|
|
956
|
+
}else if(typeof v!=='string')throw new ErroValidacaoModelo('TEXTO_ESPERADO',field);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
export function validateTNFe(value: unknown): asserts value is TNFeInput { validateModel('TNFe',value); }
|
|
960
|
+
`;
|
|
961
|
+
}
|
|
962
|
+
function renderTypeScript(ir, revision2, contractHash) {
|
|
963
|
+
const out = ["// Generated from ACBr AST. LGPL-2.1-or-later. Do not edit.", "export const ACBR_CONTRACT = " + stable({ sourceRevision: revision2, contractHash }) + " as const;", "export const SOURCE_REVISION=ACBR_CONTRACT.sourceRevision;", "export const CONTRACT_HASH=ACBR_CONTRACT.contractHash;"];
|
|
964
|
+
for (const t of ir.types) {
|
|
965
|
+
if (t.kind === "enum") {
|
|
966
|
+
out.push("export const " + t.name + " = Object.freeze(" + stable(Object.fromEntries(t.values.map((v) => [v, v]))) + " as const);", "export type " + t.name + " = typeof " + t.name + "[keyof typeof " + t.name + "];");
|
|
967
|
+
} else if (t.kind === "list") {
|
|
968
|
+
out.push("export type " + t.name + "Input = " + t.item + "Input[];", "export class " + t.name + " extends Array<" + t.item + "> {", " New(input: " + t.item + "Input = {}): " + t.item + " { const item=new " + t.item + "(input); this.push(item); return item; }", "}");
|
|
969
|
+
} else {
|
|
970
|
+
out.push("export interface " + t.name + "Input {");
|
|
971
|
+
for (const p of t.properties.filter((p2) => !p2.readonly)) out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
972
|
+
out.push("}", "export class " + t.name + " {");
|
|
973
|
+
for (const p of t.properties) {
|
|
974
|
+
if (p.readonly) {
|
|
975
|
+
out.push(" readonly " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
if (p.declaredDefault) out.push(" /** Pascal streaming default: " + p.declaredDefault.replaceAll("*/", "") + ". Omission preserves the native constructor. */");
|
|
979
|
+
if (p.kind === "object" || p.kind === "list") out.push(" " + JSON.stringify(p.name) + " = new " + p.ref + "();");
|
|
980
|
+
else out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
981
|
+
}
|
|
982
|
+
out.push(" constructor(input: " + t.name + "Input = {}) {", " validateModel(" + JSON.stringify(t.name) + ", input);");
|
|
983
|
+
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
984
|
+
const access5 = "input[" + JSON.stringify(p.name) + "]", target = "this[" + JSON.stringify(p.name) + "]";
|
|
985
|
+
out.push(" if (" + access5 + " !== undefined) " + target + " = " + (p.kind === "object" ? "new " + p.ref + "(" + access5 + ")" : p.kind === "list" ? "Object.assign(new " + p.ref + "(), " + access5 + ".map(v=>new " + ir.types.find((t2) => t2.name === p.ref).item + "(v)))" : access5) + ";");
|
|
986
|
+
}
|
|
987
|
+
out.push(" }", "}");
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
out.push("const MODEL_SCHEMA: Record<string, any> = " + stable(Object.fromEntries(ir.types.map((t) => [t.name, t]))) + ";");
|
|
991
|
+
out.push(renderModelValidation());
|
|
992
|
+
return out.join("\n") + "\n";
|
|
993
|
+
}
|
|
994
|
+
function renderContractMetadata(ir, sourceRevision, sourceHash, contractHash) {
|
|
995
|
+
if (hash(stable({ sourceRevision, sourceHash, ir })) !== contractHash) throw new Error("Hash do contrato diverge dos metadados gerados.");
|
|
996
|
+
return stable({ formatVersion: 1, sourceRevision, sourceHash, contractHash, ir }) + "\n";
|
|
997
|
+
}
|
|
998
|
+
function renderPascal(ir, revision2, contractHash) {
|
|
999
|
+
const classes = ir.types.filter((t) => t.kind === "object"), byName = new Map(ir.types.map((t) => [t.name, t]));
|
|
1000
|
+
const units = [...new Set(ir.types.map((t) => t.unit))].sort();
|
|
1001
|
+
const out = ["{ Generated from ACBr AST. LGPL-2.1-or-later. Do not edit. }", "unit AcbrModels;", "{$mode delphi}{$H+}", "interface", "uses SysUtils, Classes, fpjson, DateUtils, Math, " + units.join(", ") + ";", "const SourceRevision = " + revision2 + ";", " ContractHash = '" + contractHash + "';", "procedure preencherTNFe(documento:TJSONObject; destino:TNFe);", "implementation"];
|
|
1002
|
+
out.push(String.raw`
|
|
1003
|
+
procedure Bad(const P,M:string); begin raise Exception.Create(P+': '+M) end;
|
|
1004
|
+
function Obj(D:TJSONData;const P:string):TJSONObject;
|
|
1005
|
+
begin if (D=nil) or (D.JSONType<>jtObject) then Bad(P,'esperado objeto');Result:=TJSONObject(D) end;
|
|
1006
|
+
function Arr(D:TJSONData;const P:string):TJSONArray;
|
|
1007
|
+
begin if (D=nil) or (D.JSONType<>jtArray) then Bad(P,'esperado array');Result:=TJSONArray(D) end;
|
|
1008
|
+
function Text(D:TJSONData;const P:string):string;
|
|
1009
|
+
begin if (D=nil) or (D.JSONType<>jtString) then Bad(P,'esperado string');Result:=D.AsString end;
|
|
1010
|
+
function IntValue(D:TJSONData;const P:string;MinV,MaxV:Int64):Int64;
|
|
1011
|
+
var V:Extended;
|
|
1012
|
+
begin
|
|
1013
|
+
if (D=nil) or (D.JSONType<>jtNumber) then Bad(P,'esperado inteiro');
|
|
1014
|
+
V:=D.AsFloat;if IsNan(V) or IsInfinite(V) or (Frac(V)<>0) or (V<MinV) or (V>MaxV) then Bad(P,'inteiro fora do intervalo');
|
|
1015
|
+
Result:=D.AsInt64;
|
|
1016
|
+
end;
|
|
1017
|
+
function BoolValue(D:TJSONData;const P:string):boolean;
|
|
1018
|
+
begin if (D=nil) or (D.JSONType<>jtBoolean) then Bad(P,'esperado boolean');Result:=D.AsBoolean end;
|
|
1019
|
+
function DecimalText(D:TJSONData;const P:string;Scale:integer):string;
|
|
1020
|
+
var I,PointPos:integer;
|
|
1021
|
+
begin
|
|
1022
|
+
Result:=Text(D,P);PointPos:=0;
|
|
1023
|
+
if (Result='') or (Length(Result)>64) then Bad(P,'decimal inválido');
|
|
1024
|
+
for I:=1 to Length(Result) do begin
|
|
1025
|
+
if Result[I]='.' then begin if (PointPos>0) or (I=1) or ((I=2) and (Result[1]='-')) or (I=Length(Result)) then Bad(P,'decimal inválido');PointPos:=I end
|
|
1026
|
+
else if (Result[I]='-') and (I=1) then begin if Length(Result)=1 then Bad(P,'decimal inválido') end
|
|
1027
|
+
else if not (Result[I] in ['0'..'9']) then Bad(P,'decimal inválido');
|
|
1028
|
+
end;
|
|
1029
|
+
if (PointPos>0) and (Scale>=0) and (Length(Result)-PointPos>Scale) then Bad(P,'casas decimais excedidas');
|
|
1030
|
+
end;
|
|
1031
|
+
function FloatValue(D:TJSONData;const P:string):Extended;
|
|
1032
|
+
var F:TFormatSettings;S:string;
|
|
1033
|
+
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,-1);
|
|
1034
|
+
if not TryStrToFloat(S,Result,F) or IsNan(Result) or IsInfinite(Result) then Bad(P,'decimal fora do intervalo');
|
|
1035
|
+
end;
|
|
1036
|
+
function CurrencyValue(D:TJSONData;const P:string):Currency;
|
|
1037
|
+
var F:TFormatSettings;S:string;
|
|
1038
|
+
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,4);
|
|
1039
|
+
if not TryStrToCurr(S,Result,F) then Bad(P,'currency fora do intervalo');
|
|
1040
|
+
end;
|
|
1041
|
+
function DateValue(D:TJSONData;const P:string):TDateTime;
|
|
1042
|
+
var S:string;I:integer;
|
|
1043
|
+
begin
|
|
1044
|
+
S:=Text(D,P);
|
|
1045
|
+
if not (Length(S) in [10,19,21,22,23]) then Bad(P,'esperado data/hora civil ISO sem timezone');
|
|
1046
|
+
for I:=1 to Length(S) do if not ((S[I] in ['0'..'9']) or ((I in [5,8]) and (S[I]='-')) or ((I=11) and (S[I]='T')) or ((I in [14,17]) and (S[I]=':')) or ((I=20) and (S[I]='.'))) then Bad(P,'data ISO inválida');
|
|
1047
|
+
if not TryISO8601ToDate(S,Result,true) then Bad(P,'data ISO inválida');
|
|
1048
|
+
end;
|
|
1049
|
+
`);
|
|
1050
|
+
const q = (s) => "'" + s.replaceAll("'", "''") + "'";
|
|
1051
|
+
for (const t of classes) out.push("procedure Load_" + t.name + "(D:TJSONObject;destino:" + t.unit + "." + t.name + ";const P:string); forward;");
|
|
1052
|
+
for (const t of classes) {
|
|
1053
|
+
out.push("procedure Load_" + t.name + "(D:TJSONObject;destino:" + t.unit + "." + t.name + ";const P:string);", "var I,J:integer;V:TJSONData;A:TJSONArray;K,At:string;", "begin", " if destino=nil then Bad(P,'objeto ACBr n\xE3o inicializado');", " for I:=0 to D.Count-1 do begin", " K:=D.Names[I];V:=D.Items[I];At:=P+'.'+K;");
|
|
1054
|
+
let index = 0;
|
|
1055
|
+
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
1056
|
+
out.push(" " + (index++ ? "else " : "") + "if K=" + q(p.name) + " then begin");
|
|
1057
|
+
const target = "destino." + p.name;
|
|
1058
|
+
if (p.kind === "object") out.push(" Load_" + p.ref + "(Obj(V,At)," + target + ",At);");
|
|
1059
|
+
else if (p.kind === "list") {
|
|
1060
|
+
const list = byName.get(p.ref);
|
|
1061
|
+
out.push(" A:=Arr(V,At);if " + target + "=nil then Bad(At,'cole\xE7\xE3o n\xE3o inicializada');" + target + ".Clear;", " for J:=0 to A.Count-1 do Load_" + list.item + "(Obj(A.Items[J],At+'['+IntToStr(J)+']')," + target + "." + list.factory + ",At+'['+IntToStr(J)+']');");
|
|
1062
|
+
} else if (p.kind === "enum") {
|
|
1063
|
+
const enumeration = byName.get(p.ref);
|
|
1064
|
+
out.push(...enumeration.values.map((v, i) => " " + (i ? "else " : "") + "if Text(V,At)=" + q(v) + " then " + target + ":=" + enumeration.unit + "." + v), " else Bad(At,'enum inv\xE1lido');");
|
|
1065
|
+
} else out.push(" " + target + ":=" + { string: "Text(V,At)", integer: "IntValue(V,At," + p.min + "," + p.max + ")", boolean: "BoolValue(V,At)", datetime: "DateValue(V,At)", decimal: p.scale === 4 ? "CurrencyValue(V,At)" : "FloatValue(V,At)" }[p.kind] + ";");
|
|
1066
|
+
out.push(" end");
|
|
1067
|
+
}
|
|
1068
|
+
out.push((index ? " else " : " ") + "Bad(At,'propriedade desconhecida ou somente leitura');", " end;", "end;");
|
|
1069
|
+
}
|
|
1070
|
+
out.push("procedure preencherTNFe(documento:TJSONObject;destino:TNFe);", "begin if documento=nil then Bad('TNFe','esperado objeto');Load_TNFe(documento,destino,'TNFe') end;", "end.");
|
|
1071
|
+
return out.join("\n") + "\n";
|
|
1050
1072
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1073
|
+
function renderClientIndex() {
|
|
1074
|
+
return [
|
|
1075
|
+
"// Generated client bound to its own ACBr contract. Do not edit.",
|
|
1076
|
+
"import { criarEmissor as criarRuntime, diagnosticarErro as diagnosticarErroRuntime, diagnosticarResultado, type OpcoesEmissor, type OpcoesOperacao } from " + JSON.stringify("cosmemilton-acbr-node/runtime") + ";",
|
|
1077
|
+
"import { ACBR_CONTRACT, validateTNFe, ErroValidacaoModelo, type TNFeInput } from " + JSON.stringify("./models.js") + ";",
|
|
1078
|
+
"export * from " + JSON.stringify("./models.js") + ";",
|
|
1079
|
+
"export { diagnosticarResultado };",
|
|
1080
|
+
"export function diagnosticarErro(erro:unknown) { return erro instanceof ErroValidacaoModelo ? erro.diagnostico : diagnosticarErroRuntime(erro); }",
|
|
1081
|
+
"export function criarEmissor(options: Omit<OpcoesEmissor, " + JSON.stringify("contrato") + " | " + JSON.stringify("validaDocumento") + ">) {",
|
|
1082
|
+
" const emissor=criarRuntime({...options, contrato:ACBR_CONTRACT, validaDocumento:validateTNFe});",
|
|
1083
|
+
" return {...emissor, gerarXml(documento:TNFeInput, opcoes?:OpcoesOperacao) { return emissor.gerarXml(documento as unknown as Record<string,unknown>, opcoes); }};",
|
|
1084
|
+
"}"
|
|
1085
|
+
].join("\n") + "\n";
|
|
1062
1086
|
}
|
|
1063
|
-
async function
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
const
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
items.push({ name, ok: false, detail: error.message });
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
if (config) {
|
|
1074
|
-
try {
|
|
1075
|
-
items.push({ name: "Lazarus", ok: true, detail: await findLazarus(config) });
|
|
1076
|
-
} catch (error) {
|
|
1077
|
-
items.push({ name: "Lazarus", ok: false, detail: error.message });
|
|
1078
|
-
}
|
|
1079
|
-
try {
|
|
1080
|
-
const lock = await verifySource(config);
|
|
1081
|
-
items.push({ name: "Fontes ACBr", ok: true, detail: `revis\xE3o ${lock.source.revision}, ${lock.source.treeHash}` });
|
|
1082
|
-
} catch (error) {
|
|
1083
|
-
items.push({ name: "Fontes ACBr", ok: false, detail: error.message });
|
|
1087
|
+
async function fingerprint(dir) {
|
|
1088
|
+
const files = [];
|
|
1089
|
+
async function walk(d) {
|
|
1090
|
+
for (const entry of await readdir4(d, { withFileTypes: true })) {
|
|
1091
|
+
const f = path2.join(d, entry.name);
|
|
1092
|
+
if (entry.isDirectory()) await walk(f);
|
|
1093
|
+
else if (/\.(pas|pp|inc|xsd)$/i.test(entry.name)) files.push(f);
|
|
1084
1094
|
}
|
|
1085
1095
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
} catch (error) {
|
|
1092
|
-
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: false, detail: error.message });
|
|
1093
|
-
}
|
|
1096
|
+
await walk(dir);
|
|
1097
|
+
const digest = createHash3("sha256");
|
|
1098
|
+
for (const f of files.sort()) {
|
|
1099
|
+
digest.update(path2.relative(dir, f).replaceAll("\\", "/"));
|
|
1100
|
+
digest.update(await readFile5(f));
|
|
1094
1101
|
}
|
|
1095
|
-
return
|
|
1102
|
+
return digest.digest("hex");
|
|
1096
1103
|
}
|
|
1097
|
-
async function
|
|
1098
|
-
const
|
|
1099
|
-
const
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
for (const name of ["COPYING.txt", "COPYING.LGPL.txt", "COPYING.modifiedLGPL.txt"]) {
|
|
1110
|
-
await copyNotice(`Lazarus-${name}`, [join2(lazarus, name), join2(lazarus, "docs", name), join2(packagedLazarus, name)]);
|
|
1111
|
-
}
|
|
1112
|
-
if (await exists(join2(packagedLazarus, "ORIGIN.json"))) await copyFile2(join2(packagedLazarus, "ORIGIN.json"), join2(stage, "licenses/Lazarus-notice-origin.json"));
|
|
1113
|
-
const fpcRoot = resolve3(dirname3(config.native.fpc), "../..");
|
|
1114
|
-
const sourceRoots = [join2(fpcRoot, "source"), join2(lazarus, "fpc/3.2.2/source"), "/usr/share/fpcsrc/3.2.2"];
|
|
1115
|
-
for (const [name, sourceRelative] of [["COPYING.GPL.txt", "compiler/COPYING.txt"], ["COPYING.LGPL.txt", "rtl/COPYING.txt"], ["COPYING.FPC", "rtl/COPYING.FPC"]]) {
|
|
1116
|
-
await copyNotice(`FPC-${name}`, [...sourceRoots.map((directory) => join2(directory, sourceRelative)), join2(packagedFpc, name)]);
|
|
1104
|
+
async function generateModel(options) {
|
|
1105
|
+
const root = path2.resolve(options.outputDir), cache = path2.join(root, ".acbr/generated"), bin = path2.join(root, ".acbr/bin");
|
|
1106
|
+
const models = path2.resolve(root, options.modelOutputDir ?? "generated/acbr"), native = path2.resolve(root, options.nativeOutputDir ?? "native/generated");
|
|
1107
|
+
await Promise.all([mkdir4(cache, { recursive: true }), mkdir4(bin, { recursive: true }), mkdir4(models, { recursive: true }), mkdir4(native, { recursive: true })]);
|
|
1108
|
+
const extractor = options.extractorPath ?? fileURLToPath2(new URL("../tools/extract-model.lpr", import.meta.url));
|
|
1109
|
+
const executable = path2.join(bin, "extract-model" + (process.platform === "win32" ? ".exe" : ""));
|
|
1110
|
+
try {
|
|
1111
|
+
await execute(options.fpcPath ?? "fpc", ["-Mobjfpc", "-Sh", "-FU" + bin, "-FE" + bin, extractor], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
|
|
1112
|
+
await execute(executable, [path2.resolve(options.acbrRoot), path2.join(cache, "raw-model.json"), process.platform === "win32" ? "win64" : "linux"], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
const e = error;
|
|
1115
|
+
throw new Error("Extra\xE7\xE3o FCL-passrc falhou: " + (e.stderr ?? "") + (e.stdout ?? "") + e.message);
|
|
1117
1116
|
}
|
|
1118
|
-
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1117
|
+
const raw = JSON.parse(await readFile5(path2.join(cache, "raw-model.json"), "utf8"));
|
|
1118
|
+
const ir = buildModelIR(raw), sourceRevision = Number(options.revision);
|
|
1119
|
+
if (!Number.isSafeInteger(sourceRevision) || sourceRevision < 1) throw new Error("Revis\xE3o SVN inv\xE1lida");
|
|
1120
|
+
const sourceHash = options.sourceHash ?? await fingerprint(options.acbrRoot), contractHash = hash(stable({ sourceRevision, sourceHash, ir }));
|
|
1121
|
+
let previous;
|
|
1122
|
+
try {
|
|
1123
|
+
previous = JSON.parse(await readFile5(path2.join(cache, "model.ir.json"), "utf8"));
|
|
1124
|
+
} catch (error) {
|
|
1125
|
+
if (error.code !== "ENOENT") throw error;
|
|
1125
1126
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1127
|
+
const report = compareContracts(previous, ir), reportPath = path2.join(cache, "changes.json"), manifestPath = path2.join(cache, "manifest.json");
|
|
1128
|
+
const files = [path2.relative(root, path2.join(models, "models.ts")), path2.relative(root, path2.join(models, "index.ts")), path2.relative(root, path2.join(native, "AcbrModels.pas"))].map((f) => f.replaceAll("\\", "/"));
|
|
1129
|
+
const content = [renderTypeScript(ir, sourceRevision, contractHash), renderClientIndex(), renderPascal(ir, sourceRevision, contractHash)];
|
|
1130
|
+
const fileHashes = Object.fromEntries(files.map((file, index) => [file, hash(content[index])]));
|
|
1131
|
+
const metadataPath = path2.join(models, "contract.json"), metadataContent = renderContractMetadata(ir, sourceRevision, sourceHash, contractHash);
|
|
1132
|
+
await Promise.all([
|
|
1133
|
+
...files.map((file, index) => writeFile4(path2.resolve(root, file), content[index], "utf8")),
|
|
1134
|
+
writeFile4(path2.join(cache, "model.ir.json"), JSON.stringify(ir, null, 2) + "\n", "utf8"),
|
|
1135
|
+
writeFile4(metadataPath, metadataContent, "utf8"),
|
|
1136
|
+
writeFile4(reportPath, JSON.stringify(report, null, 2) + "\n", "utf8"),
|
|
1137
|
+
writeFile4(manifestPath, JSON.stringify({ schemaVersion: 1, sourceRevision, sourceHash, contractHash, root: ir.root, models: ir.types.length, files, fileHashes, metadata: { file: path2.relative(root, metadataPath).replaceAll("\\", "/"), sha256: hash(metadataContent) } }, null, 2) + "\n", "utf8")
|
|
1138
|
+
]);
|
|
1139
|
+
return { contractHash, sourceHash, models: ir.types.length, reportPath, manifestPath, metadataPath };
|
|
1128
1140
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1141
|
+
var execute, bases, primitives, stable, hash, tsType;
|
|
1142
|
+
var init_generator = __esm({
|
|
1143
|
+
"src/generator.ts"() {
|
|
1144
|
+
"use strict";
|
|
1145
|
+
execute = promisify(execFile);
|
|
1146
|
+
bases = /* @__PURE__ */ new Set(["tobject", "tpersistent", "tacbrobjectlist"]);
|
|
1147
|
+
primitives = {
|
|
1148
|
+
string: { kind: "string" },
|
|
1149
|
+
ansistring: { kind: "string" },
|
|
1150
|
+
unicodestring: { kind: "string" },
|
|
1151
|
+
widestring: { kind: "string" },
|
|
1152
|
+
boolean: { kind: "boolean" },
|
|
1153
|
+
byte: { kind: "integer", min: 0, max: 255 },
|
|
1154
|
+
word: { kind: "integer", min: 0, max: 65535 },
|
|
1155
|
+
integer: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
1156
|
+
longint: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
1157
|
+
smallint: { kind: "integer", min: -32768, max: 32767 },
|
|
1158
|
+
shortint: { kind: "integer", min: -128, max: 127 },
|
|
1159
|
+
cardinal: { kind: "integer", min: 0, max: 4294967295 },
|
|
1160
|
+
longword: { kind: "integer", min: 0, max: 4294967295 },
|
|
1161
|
+
int64: { kind: "integer", min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER },
|
|
1162
|
+
qword: { kind: "integer", min: 0, max: Number.MAX_SAFE_INTEGER },
|
|
1163
|
+
double: { kind: "decimal" },
|
|
1164
|
+
extended: { kind: "decimal" },
|
|
1165
|
+
single: { kind: "decimal" },
|
|
1166
|
+
currency: { kind: "decimal", scale: 4 },
|
|
1167
|
+
tdatetime: { kind: "datetime" },
|
|
1168
|
+
tdate: { kind: "datetime" },
|
|
1169
|
+
ttime: { kind: "datetime" }
|
|
1170
|
+
};
|
|
1171
|
+
stable = (value) => JSON.stringify(value);
|
|
1172
|
+
hash = (value) => createHash3("sha256").update(value).digest("hex");
|
|
1173
|
+
tsType = (p) => p.kind === "object" ? p.ref + "Input" : p.kind === "list" ? p.ref + "Input" : p.kind === "enum" ? p.ref : p.kind === "integer" ? "number" : p.kind === "boolean" ? "boolean" : "string";
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1137
1176
|
|
|
1138
1177
|
// src/diagnostics.ts
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
CERTIFICADO_INVALIDO: ["configuracao", "O certificado A1 ou sua configura\xE7\xE3o \xE9 inv\xE1lido.", "Confira formato e validade do A1, pfx ou arquivo e a senha digitada, sem registrar esses dados."],
|
|
1145
|
-
CERTIFICADO_DIVERGENTE: ["assinatura", "O certificado n\xE3o corresponde \xE0 raiz CNPJ do emitente.", "Confira o CNPJ configurado e selecione o A1 correspondente ao emitente."],
|
|
1146
|
-
DEPENDENCIA_AUSENTE: ["runtime", "Uma depend\xEAncia do motor fiscal n\xE3o est\xE1 dispon\xEDvel.", "Reinstale o runtime completo da plataforma; confira a disponibilidade do OpenSSL distribu\xEDdo."],
|
|
1147
|
-
SCHEMAS_AUSENTES: ["runtime", "Os schemas fiscais n\xE3o est\xE3o dispon\xEDveis.", "Reinstale o runtime completo da plataforma."],
|
|
1148
|
-
SERVICOS_AUSENTES: ["runtime", "A configura\xE7\xE3o dos servi\xE7os fiscais n\xE3o est\xE1 dispon\xEDvel.", "Reinstale o runtime completo da plataforma."],
|
|
1149
|
-
CSC_AUSENTE: ["configuracao", "A opera\xE7\xE3o de NFC-e exige CSC.", "Informe id e valor do CSC na configura\xE7\xE3o sem registrar seu conte\xFAdo."],
|
|
1150
|
-
IDENTIDADE_DIVERGENTE: ["documento", "A identidade fiscal n\xE3o corresponde \xE0 configura\xE7\xE3o ou ao retorno.", "Confira emitente, UF, modelo, ambiente e chave do documento antes de continuar."],
|
|
1151
|
-
XML_SCHEMA_INVALIDO: ["validacao", "O XML n\xE3o atende aos schemas fiscais.", "Confira os campos obrigat\xF3rios e os tributos; a valida\xE7\xE3o de XML assinado deve ocorrer ap\xF3s a assinatura."],
|
|
1152
|
-
ASSINATURA_INVALIDA: ["assinatura", "A assinatura do XML n\xE3o foi validada.", "Confira o A1 correspondente e use o XML assinado sem altera\xE7\xF5es."],
|
|
1153
|
-
XML_NAO_ASSINADO: ["assinatura", "A opera\xE7\xE3o exige XML previamente assinado.", "Conclua a assinatura e a valida\xE7\xE3o antes de transmitir."],
|
|
1154
|
-
XML_ALTERADO: ["assinatura", "O XML assinado foi alterado.", "Use exatamente o XML assinado e persistido; n\xE3o edite seu conte\xFAdo."],
|
|
1155
|
-
RETORNO_INVALIDO: ["transmissao", "A identidade ou o protocolo do retorno fiscal \xE9 inv\xE1lido.", "Consulte a situa\xE7\xE3o fiscal antes de decidir repetir a opera\xE7\xE3o."],
|
|
1156
|
-
OPERACAO_FISCAL_FALHOU: ["operacao", "O motor n\xE3o conseguiu concluir a etapa fiscal.", "Confira a configura\xE7\xE3o da etapa, os dados do XML e as depend\xEAncias do runtime."],
|
|
1157
|
-
TLS_SERVIDOR_INVALIDO: ["transmissao", "A verifica\xE7\xE3o TLS do servi\xE7o fiscal falhou.", "Confira o servi\xE7o e a cadeia de confian\xE7a; mantenha a verifica\xE7\xE3o TLS habilitada."],
|
|
1158
|
-
CSC_INVALIDO: ["configuracao", "A configura\xE7\xE3o do CSC \xE9 inv\xE1lida.", "Confira id e valor do CSC sem registrar seu conte\xFAdo."],
|
|
1159
|
-
PLATAFORMA_NAO_SUPORTADA: ["runtime", "A plataforma n\xE3o \xE9 suportada.", "Execute em Windows ou Linux x64 com Node.js 22.12 ou superior."],
|
|
1160
|
-
RUNTIME_AUSENTE: ["runtime", "O motor fiscal n\xE3o foi encontrado.", "Instale o runtime da plataforma incluindo depend\xEAncias opcionais."],
|
|
1161
|
-
RUNTIME_INVALIDO: ["runtime", "O runtime fiscal \xE9 inv\xE1lido.", "Use um runtime distribu\xEDdo e compat\xEDvel com a plataforma."],
|
|
1162
|
-
RUNTIME_INCOMPLETO: ["runtime", "Falta um arquivo do runtime fiscal.", "Reinstale o runtime da plataforma."],
|
|
1163
|
-
RUNTIME_ALTERADO: ["runtime", "A integridade do runtime fiscal n\xE3o foi confirmada.", "Reinstale o runtime; n\xE3o desative a verifica\xE7\xE3o dos hashes."],
|
|
1164
|
-
CONTRATO_DIVERGENTE: ["runtime", "Cliente e motor usam contratos diferentes.", "Use vers\xF5es compat\xEDveis ou regenere e recompile ambos."],
|
|
1165
|
-
DOCUMENTO_INVALIDO: ["documento", "O documento cont\xE9m dados incompat\xEDveis com o modelo.", "Valide os campos e tipos do documento antes de gerar o XML."],
|
|
1166
|
-
OPERACAO_INVALIDA: ["operacao", "Os par\xE2metros da opera\xE7\xE3o s\xE3o inv\xE1lidos.", "Informe um objeto com os campos exigidos pela opera\xE7\xE3o."],
|
|
1167
|
-
OPERACAO_CANCELADA: ["operacao", "A opera\xE7\xE3o foi cancelada.", "Confira o estado do envio antes de decidir continuar."],
|
|
1168
|
-
TIMEOUT_MOTOR: ["runtime", "O motor excedeu o tempo de espera.", "Confira o estado do envio antes de repetir a opera\xE7\xE3o."],
|
|
1169
|
-
EMISSOR_FECHADO: ["operacao", "O emissor foi encerrado.", "Crie um novo emissor para continuar."],
|
|
1170
|
-
FALHA_INICIAR_MOTOR: ["runtime", "N\xE3o foi poss\xEDvel iniciar o motor fiscal.", "Confira a instala\xE7\xE3o e as permiss\xF5es de execu\xE7\xE3o do runtime."],
|
|
1171
|
-
FALHA_PIPE: ["runtime", "A comunica\xE7\xE3o com o motor foi interrompida.", "Confira a instala\xE7\xE3o e o estado do envio antes de continuar."],
|
|
1172
|
-
RESPOSTA_EXCESSIVA: ["runtime", "A resposta do motor excedeu o limite.", "Confira o tamanho da opera\xE7\xE3o e a vers\xE3o do runtime."],
|
|
1173
|
-
RESPOSTA_INVALIDA: ["runtime", "O motor devolveu uma resposta inv\xE1lida.", "Confira a compatibilidade do runtime e o estado do envio."],
|
|
1174
|
-
FALHA_MOTOR: ["runtime", "O motor encerrou sem uma resposta fiscal v\xE1lida.", "Confira a instala\xE7\xE3o e o estado do envio antes de continuar."],
|
|
1175
|
-
CERTIFICADO_AUSENTE: ["configuracao", "O certificado A1 n\xE3o est\xE1 dispon\xEDvel para esta opera\xE7\xE3o.", "Configure um A1 acess\xEDvel e sua senha sem registrar esses dados."],
|
|
1176
|
-
CERTIFICADO_EXCESSIVO: ["configuracao", "O certificado excede o limite de tamanho.", "Use um arquivo A1 de at\xE9 2 MiB."],
|
|
1177
|
-
REQUISICAO_INVALIDA: ["operacao", "Os dados n\xE3o puderam ser serializados ou excedem o limite.", "Use dados JSON e reduza o tamanho da opera\xE7\xE3o."],
|
|
1178
|
-
FILA_CHEIA: ["operacao", "A fila fiscal est\xE1 cheia.", "Aguarde a opera\xE7\xE3o atual terminar antes de iniciar outra."],
|
|
1179
|
-
XML_INVALIDO: ["documento", "O XML est\xE1 vazio, tem tipo inv\xE1lido ou excede o limite.", "Informe o XML como texto UTF-8 de at\xE9 2 MiB."],
|
|
1180
|
-
CHAVE_INVALIDA: ["documento", "A chave fiscal tem formato inv\xE1lido.", "Informe a chave como texto com 44 d\xEDgitos."],
|
|
1181
|
-
RECIBO_INVALIDO: ["documento", "O recibo tem formato inv\xE1lido.", "Informe o recibo como texto com 15 d\xEDgitos."],
|
|
1182
|
-
JUSTIFICATIVA_INVALIDA: ["documento", "A justificativa tem tamanho inv\xE1lido.", "Informe uma justificativa com 15 a 255 caracteres."],
|
|
1183
|
-
PROTOCOLO_INVALIDO: ["documento", "O protocolo tem formato inv\xE1lido.", "Informe o protocolo como texto com 15 d\xEDgitos."],
|
|
1184
|
-
OPERACAO_NAO_SUPORTADA: ["operacao", "A opera\xE7\xE3o n\xE3o \xE9 suportada para este modelo.", "Carta de corre\xE7\xE3o exige NF-e modelo 55."],
|
|
1185
|
-
CORRECAO_INVALIDA: ["documento", "Os dados da carta de corre\xE7\xE3o s\xE3o inv\xE1lidos.", "Confira a corre\xE7\xE3o de 15 a 1000 caracteres e a sequ\xEAncia de 1 a 20."],
|
|
1186
|
-
INUTILIZACAO_INVALIDA: ["documento", "A faixa de inutiliza\xE7\xE3o \xE9 inv\xE1lida.", "Confira ano, s\xE9rie e n\xFAmeros inicial e final."],
|
|
1187
|
-
FALHA_LOCAL: ["operacao", "N\xE3o foi poss\xEDvel concluir a opera\xE7\xE3o local.", "Confira a etapa e os tipos dos dados; n\xE3o registre o erro bruto."]
|
|
1188
|
-
};
|
|
1178
|
+
function base64XmlRecuperadoValido(value) {
|
|
1179
|
+
if (typeof value !== "string" || value.length === 0 || value.length > Math.ceil(MAX_RECOVERED_XML_BYTES / 3) * 4) return false;
|
|
1180
|
+
const bytes = Buffer.from(value, "base64");
|
|
1181
|
+
return bytes.length > 0 && bytes.length <= MAX_RECOVERED_XML_BYTES && bytes.toString("base64") === value;
|
|
1182
|
+
}
|
|
1189
1183
|
function etapaDaOperacao(comando) {
|
|
1190
|
-
return { gerarXml: "geracao", validar: "validacao", assinar: "assinatura", transmitir: "transmissao", consultar: "consulta", cancelar: "cancelamento", cartaCorrecao: "carta_correcao", inutilizar: "inutilizacao" }[comando] ?? "operacao";
|
|
1184
|
+
return { gerarXml: "geracao", validar: "validacao", assinar: "assinatura", transmitir: "transmissao", consultar: "consulta", recuperarXml: "consulta", cancelar: "cancelamento", cartaCorrecao: "carta_correcao", inutilizar: "inutilizacao" }[comando] ?? "operacao";
|
|
1191
1185
|
}
|
|
1192
1186
|
function criarDiagnosticoErro(codigo, desconhecido = false, detalhes = {}) {
|
|
1193
1187
|
const safeCode = Object.hasOwn(CATALOGO, codigo) ? codigo : "FALHA_LOCAL";
|
|
@@ -1224,18 +1218,30 @@ function diagnosticarResultado(resultado, comando) {
|
|
|
1224
1218
|
const protocolo = typeof resultado.protocolo === "string" && /^\d{15}$/.test(resultado.protocolo);
|
|
1225
1219
|
const chave = typeof resultado.chave === "string" && /^\d{44}$/.test(resultado.chave);
|
|
1226
1220
|
const autorizacao = (comando === "transmitir" || comando === "consultar") && resultado.estado === "AUTORIZADO" && [100, 150].includes(resultado.cStat) && protocolo && chave && (comando === "consultar" || resultado.envioIniciado !== false);
|
|
1221
|
+
const xmlRecuperado = comando === "recuperarXml" && base64XmlRecuperadoValido(resultado.xmlBase64);
|
|
1222
|
+
const recuperacao = comando === "recuperarXml" && resultado.estado === "XML_RECUPERADO" && resultado.cStat === 100 && protocolo && chave && semEvento && xmlRecuperado;
|
|
1227
1223
|
const evento = comando === "cancelar" && resultado.estado === "CANCELADO" && [135, 136].includes(resultado.cStat) && chave || comando === "cartaCorrecao" && resultado.estado === "EVENTO_REGISTRADO" && resultado.cStat === 135 && chave || comando === "inutilizar" && resultado.estado === "INUTILIZADO" && resultado.cStat === 102;
|
|
1228
1224
|
if (local && resultado.sucesso === true && semEvento) {
|
|
1229
1225
|
statusEnvio = "nao_enviado";
|
|
1230
1226
|
codigo = "ETAPA_LOCAL_CONCLUIDA";
|
|
1231
1227
|
mensagem = "A etapa local foi conclu\xEDda; esta opera\xE7\xE3o n\xE3o transmitiu a nota.";
|
|
1232
1228
|
acao = "Confira o resultado antes de seguir para a pr\xF3xima etapa.";
|
|
1229
|
+
} else if (resultado.sucesso === true && recuperacao) {
|
|
1230
|
+
statusEnvio = "autorizado";
|
|
1231
|
+
codigo = "XML_RECUPERADO";
|
|
1232
|
+
mensagem = "O XML autorizado foi recuperado por consulta; esta opera\xE7\xE3o n\xE3o transmitiu a nota.";
|
|
1233
|
+
acao = "Guarde o XML recuperado com o protocolo de autoriza\xE7\xE3o.";
|
|
1234
|
+
} else if (comando === "recuperarXml" && resultado.sucesso === false && resultado.codigo === "RECUPERACAO_NAO_COMPROVADA" && ["CONSULTADO", "ERRO"].includes(resultado.estado) && semEvento) {
|
|
1235
|
+
statusEnvio = "nao_enviado";
|
|
1236
|
+
codigo = "RECUPERACAO_NAO_COMPROVADA";
|
|
1237
|
+
mensagem = CATALOGO.RECUPERACAO_NAO_COMPROVADA[1];
|
|
1238
|
+
acao = CATALOGO.RECUPERACAO_NAO_COMPROVADA[2];
|
|
1233
1239
|
} else if (resultado.sucesso === true && (autorizacao || evento && protocolo && resultado.envioIniciado !== false)) {
|
|
1234
1240
|
statusEnvio = "autorizado";
|
|
1235
1241
|
codigo = "OPERACAO_CONFIRMADA";
|
|
1236
1242
|
mensagem = { AUTORIZADO: "A nota foi autorizada.", CANCELADO: "O cancelamento foi confirmado.", EVENTO_REGISTRADO: "O evento foi registrado.", INUTILIZADO: "A faixa foi inutilizada." }[resultado.estado];
|
|
1237
1243
|
acao = "Guarde o resultado fiscal. N\xE3o repita esta opera\xE7\xE3o.";
|
|
1238
|
-
} else if (resultado.sucesso === false && (comando === "consultar" || resultado.envioIniciado !== false) && ["transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(comando) && Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 && (resultado.estado === "DENEGADO" && [110, 301, 302].includes(resultado.cStat) || resultado.estado === "REJEITADO" && ![100, 150, 110, 301, 302, 101, 151, 155, 103, 104, 105, 108, 109, 204, 539, 573, 135, 136, 102, 217].includes(resultado.cStat))) {
|
|
1244
|
+
} else if (resultado.sucesso === false && (comando === "consultar" || comando === "recuperarXml" || resultado.envioIniciado !== false) && ["transmitir", "consultar", "recuperarXml", "cancelar", "cartaCorrecao", "inutilizar"].includes(comando) && Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 && (resultado.estado === "DENEGADO" && [110, 301, 302].includes(resultado.cStat) || resultado.estado === "REJEITADO" && ![100, 150, 110, 301, 302, 101, 151, 155, 103, 104, 105, 108, 109, 204, 539, 573, 135, 136, 102, 217].includes(resultado.cStat))) {
|
|
1239
1245
|
statusEnvio = "rejeitado";
|
|
1240
1246
|
codigo = resultado.estado === "DENEGADO" ? "NOTA_DENEGADA" : "OPERACAO_REJEITADA";
|
|
1241
1247
|
mensagem = resultado.estado === "DENEGADO" ? "A nota foi denegada." : "A opera\xE7\xE3o foi rejeitada.";
|
|
@@ -1250,97 +1256,164 @@ function diagnosticarResultado(resultado, comando) {
|
|
|
1250
1256
|
const cStat = Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 ? resultado.cStat : void 0;
|
|
1251
1257
|
return Object.freeze({ codigo, etapa, mensagem, acao, statusEnvio, ...cStat !== void 0 ? { cStat } : {} });
|
|
1252
1258
|
}
|
|
1259
|
+
var ETAPAS, CAMPOS, MAX_RECOVERED_XML_BYTES, CATALOGO;
|
|
1260
|
+
var init_diagnostics = __esm({
|
|
1261
|
+
"src/diagnostics.ts"() {
|
|
1262
|
+
"use strict";
|
|
1263
|
+
init_types();
|
|
1264
|
+
ETAPAS = /* @__PURE__ */ new Set(["configuracao", "documento", "runtime", "geracao", "validacao", "assinatura", "transmissao", "consulta", "cancelamento", "carta_correcao", "inutilizacao", "operacao", "limpeza"]);
|
|
1265
|
+
CAMPOS = /* @__PURE__ */ new Set(["cnpj", "uf", "modelo", "ambiente", "contrato", "certificado", "certificado.senha", "certificado.pfx", "certificado.arquivo", "csc", "csc.id", "csc.valor", "timeoutMs", "limiteFila", "limiteBytes", "runtimeDirectory", "documento", "xml", "consulta", "chave", "recibo", "cancelamento", "protocolo", "justificativa", "cartaCorrecao", "correcao", "sequenciaEvento", "inutilizacao", "ano", "serie", "numeroInicial", "numeroFinal", "operacao", "signal"]);
|
|
1266
|
+
MAX_RECOVERED_XML_BYTES = 4 * 1024 * 1024;
|
|
1267
|
+
CATALOGO = {
|
|
1268
|
+
CONFIGURACAO_INVALIDA: ["configuracao", "A configura\xE7\xE3o cont\xE9m um campo inv\xE1lido.", "Confira o campo indicado e seu tipo antes de continuar."],
|
|
1269
|
+
CONTRATO_INVALIDO: ["configuracao", "O contrato do cliente \xE9 inv\xE1lido.", "Use o contrato gerado junto com o cliente."],
|
|
1270
|
+
CERTIFICADO_INVALIDO: ["configuracao", "O certificado A1 ou sua configura\xE7\xE3o \xE9 inv\xE1lido.", "Confira formato e validade do A1, pfx ou arquivo e a senha digitada, sem registrar esses dados."],
|
|
1271
|
+
CERTIFICADO_DIVERGENTE: ["assinatura", "O certificado n\xE3o corresponde \xE0 raiz CNPJ do emitente.", "Confira o CNPJ configurado e selecione o A1 correspondente ao emitente."],
|
|
1272
|
+
DEPENDENCIA_AUSENTE: ["runtime", "Uma depend\xEAncia do motor fiscal n\xE3o est\xE1 dispon\xEDvel.", "Reinstale o runtime completo da plataforma; confira a disponibilidade do OpenSSL distribu\xEDdo."],
|
|
1273
|
+
SCHEMAS_AUSENTES: ["runtime", "Os schemas fiscais n\xE3o est\xE3o dispon\xEDveis.", "Reinstale o runtime completo da plataforma."],
|
|
1274
|
+
SERVICOS_AUSENTES: ["runtime", "A configura\xE7\xE3o dos servi\xE7os fiscais n\xE3o est\xE1 dispon\xEDvel.", "Reinstale o runtime completo da plataforma."],
|
|
1275
|
+
CSC_AUSENTE: ["configuracao", "A opera\xE7\xE3o de NFC-e exige CSC.", "Informe id e valor do CSC na configura\xE7\xE3o sem registrar seu conte\xFAdo."],
|
|
1276
|
+
IDENTIDADE_DIVERGENTE: ["documento", "A identidade fiscal n\xE3o corresponde \xE0 configura\xE7\xE3o ou ao retorno.", "Confira emitente, UF, modelo, ambiente e chave do documento antes de continuar."],
|
|
1277
|
+
XML_SCHEMA_INVALIDO: ["validacao", "O XML n\xE3o atende aos schemas fiscais.", "Confira os campos obrigat\xF3rios e os tributos; a valida\xE7\xE3o de XML assinado deve ocorrer ap\xF3s a assinatura."],
|
|
1278
|
+
ASSINATURA_INVALIDA: ["assinatura", "A assinatura do XML n\xE3o foi validada.", "Confira o A1 correspondente e use o XML assinado sem altera\xE7\xF5es."],
|
|
1279
|
+
XML_NAO_ASSINADO: ["assinatura", "A opera\xE7\xE3o exige XML previamente assinado.", "Conclua a assinatura e a valida\xE7\xE3o antes de transmitir."],
|
|
1280
|
+
XML_ALTERADO: ["assinatura", "O XML assinado foi alterado.", "Use exatamente o XML assinado e persistido; n\xE3o edite seu conte\xFAdo."],
|
|
1281
|
+
RETORNO_INVALIDO: ["transmissao", "A identidade ou o protocolo do retorno fiscal \xE9 inv\xE1lido.", "Consulte a situa\xE7\xE3o fiscal antes de decidir repetir a opera\xE7\xE3o."],
|
|
1282
|
+
RECUPERACAO_NAO_COMPROVADA: ["consulta", "A consulta n\xE3o comprovou a recupera\xE7\xE3o do XML autorizado.", "Preserve o XML assinado original e confira a situa\xE7\xE3o fiscal. N\xE3o transmita a nota para tentar recuperar o protocolo."],
|
|
1283
|
+
OPERACAO_FISCAL_FALHOU: ["operacao", "O motor n\xE3o conseguiu concluir a etapa fiscal.", "Confira a configura\xE7\xE3o da etapa, os dados do XML e as depend\xEAncias do runtime."],
|
|
1284
|
+
TLS_SERVIDOR_INVALIDO: ["transmissao", "A verifica\xE7\xE3o TLS do servi\xE7o fiscal falhou.", "Confira o servi\xE7o e a cadeia de confian\xE7a; mantenha a verifica\xE7\xE3o TLS habilitada."],
|
|
1285
|
+
CSC_INVALIDO: ["configuracao", "A configura\xE7\xE3o do CSC \xE9 inv\xE1lida.", "Confira id e valor do CSC sem registrar seu conte\xFAdo."],
|
|
1286
|
+
PLATAFORMA_NAO_SUPORTADA: ["runtime", "A plataforma n\xE3o \xE9 suportada.", "Execute em Windows ou Linux x64 com Node.js 22.12 ou superior."],
|
|
1287
|
+
RUNTIME_AUSENTE: ["runtime", "O motor fiscal n\xE3o foi encontrado.", "Instale o runtime da plataforma incluindo depend\xEAncias opcionais."],
|
|
1288
|
+
RUNTIME_INVALIDO: ["runtime", "O runtime fiscal \xE9 inv\xE1lido.", "Use um runtime distribu\xEDdo e compat\xEDvel com a plataforma."],
|
|
1289
|
+
RUNTIME_INCOMPLETO: ["runtime", "Falta um arquivo do runtime fiscal.", "Reinstale o runtime da plataforma."],
|
|
1290
|
+
RUNTIME_ALTERADO: ["runtime", "A integridade do runtime fiscal n\xE3o foi confirmada.", "Reinstale o runtime; n\xE3o desative a verifica\xE7\xE3o dos hashes."],
|
|
1291
|
+
RUNTIME_SEM_CAPACIDADE: ["runtime", "O runtime instalado n\xE3o oferece esta opera\xE7\xE3o.", "Atualize o pacote principal e o runtime da plataforma para vers\xF5es compat\xEDveis com a opera\xE7\xE3o solicitada."],
|
|
1292
|
+
CONTRATO_DIVERGENTE: ["runtime", "Cliente e motor usam contratos diferentes.", "Use vers\xF5es compat\xEDveis ou regenere e recompile ambos."],
|
|
1293
|
+
DOCUMENTO_INVALIDO: ["documento", "O documento cont\xE9m dados incompat\xEDveis com o modelo.", "Valide os campos e tipos do documento antes de gerar o XML."],
|
|
1294
|
+
OPERACAO_INVALIDA: ["operacao", "Os par\xE2metros da opera\xE7\xE3o s\xE3o inv\xE1lidos.", "Informe um objeto com os campos exigidos pela opera\xE7\xE3o."],
|
|
1295
|
+
OPERACAO_CANCELADA: ["operacao", "A opera\xE7\xE3o foi cancelada.", "Confira o estado do envio antes de decidir continuar."],
|
|
1296
|
+
TIMEOUT_MOTOR: ["runtime", "O motor excedeu o tempo de espera.", "Confira o estado do envio antes de repetir a opera\xE7\xE3o."],
|
|
1297
|
+
EMISSOR_FECHADO: ["operacao", "O emissor foi encerrado.", "Crie um novo emissor para continuar."],
|
|
1298
|
+
FALHA_INICIAR_MOTOR: ["runtime", "N\xE3o foi poss\xEDvel iniciar o motor fiscal.", "Confira a instala\xE7\xE3o e as permiss\xF5es de execu\xE7\xE3o do runtime."],
|
|
1299
|
+
FALHA_PIPE: ["runtime", "A comunica\xE7\xE3o com o motor foi interrompida.", "Confira a instala\xE7\xE3o e o estado do envio antes de continuar."],
|
|
1300
|
+
RESPOSTA_EXCESSIVA: ["runtime", "A resposta do motor excedeu o limite.", "Confira o tamanho da opera\xE7\xE3o e a vers\xE3o do runtime."],
|
|
1301
|
+
RESPOSTA_INVALIDA: ["runtime", "O motor devolveu uma resposta inv\xE1lida.", "Confira a compatibilidade do runtime e o estado do envio."],
|
|
1302
|
+
FALHA_MOTOR: ["runtime", "O motor encerrou sem uma resposta fiscal v\xE1lida.", "Confira a instala\xE7\xE3o e o estado do envio antes de continuar."],
|
|
1303
|
+
CERTIFICADO_AUSENTE: ["configuracao", "O certificado A1 n\xE3o est\xE1 dispon\xEDvel para esta opera\xE7\xE3o.", "Configure um A1 acess\xEDvel e sua senha sem registrar esses dados."],
|
|
1304
|
+
CERTIFICADO_EXCESSIVO: ["configuracao", "O certificado excede o limite de tamanho.", "Use um arquivo A1 de at\xE9 2 MiB."],
|
|
1305
|
+
REQUISICAO_INVALIDA: ["operacao", "Os dados n\xE3o puderam ser serializados ou excedem o limite.", "Use dados JSON e reduza o tamanho da opera\xE7\xE3o."],
|
|
1306
|
+
FILA_CHEIA: ["operacao", "A fila fiscal est\xE1 cheia.", "Aguarde a opera\xE7\xE3o atual terminar antes de iniciar outra."],
|
|
1307
|
+
XML_INVALIDO: ["documento", "O XML est\xE1 vazio, tem tipo inv\xE1lido ou excede o limite.", "Informe o XML como texto UTF-8 de at\xE9 2 MiB."],
|
|
1308
|
+
CHAVE_INVALIDA: ["documento", "A chave fiscal tem formato inv\xE1lido.", "Informe a chave como texto com 44 d\xEDgitos."],
|
|
1309
|
+
RECIBO_INVALIDO: ["documento", "O recibo tem formato inv\xE1lido.", "Informe o recibo como texto com 15 d\xEDgitos."],
|
|
1310
|
+
JUSTIFICATIVA_INVALIDA: ["documento", "A justificativa tem tamanho inv\xE1lido.", "Informe uma justificativa com 15 a 255 caracteres."],
|
|
1311
|
+
PROTOCOLO_INVALIDO: ["documento", "O protocolo tem formato inv\xE1lido.", "Informe o protocolo como texto com 15 d\xEDgitos."],
|
|
1312
|
+
OPERACAO_NAO_SUPORTADA: ["operacao", "A opera\xE7\xE3o n\xE3o \xE9 suportada para este modelo.", "Carta de corre\xE7\xE3o exige NF-e modelo 55."],
|
|
1313
|
+
CORRECAO_INVALIDA: ["documento", "Os dados da carta de corre\xE7\xE3o s\xE3o inv\xE1lidos.", "Confira a corre\xE7\xE3o de 15 a 1000 caracteres e a sequ\xEAncia de 1 a 20."],
|
|
1314
|
+
INUTILIZACAO_INVALIDA: ["documento", "A faixa de inutiliza\xE7\xE3o \xE9 inv\xE1lida.", "Confira ano, s\xE9rie e n\xFAmeros inicial e final."],
|
|
1315
|
+
FALHA_LOCAL: ["operacao", "N\xE3o foi poss\xEDvel concluir a opera\xE7\xE3o local.", "Confira a etapa e os tipos dos dados; n\xE3o registre o erro bruto."]
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1253
1319
|
|
|
1254
1320
|
// src/types.ts
|
|
1255
|
-
var ErroAcbrNode
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1321
|
+
var ErroAcbrNode;
|
|
1322
|
+
var init_types = __esm({
|
|
1323
|
+
"src/types.ts"() {
|
|
1324
|
+
"use strict";
|
|
1325
|
+
init_diagnostics();
|
|
1326
|
+
ErroAcbrNode = class extends Error {
|
|
1327
|
+
constructor(codigo, mensagem, resultadoDesconhecido = false, xmlBase64, detalhes) {
|
|
1328
|
+
super(mensagem);
|
|
1329
|
+
this.codigo = codigo;
|
|
1330
|
+
this.resultadoDesconhecido = resultadoDesconhecido;
|
|
1331
|
+
this.xmlBase64 = xmlBase64;
|
|
1332
|
+
this.#diagnostico = criarDiagnosticoErro(codigo, resultadoDesconhecido, detalhes);
|
|
1333
|
+
Object.defineProperty(this, "xmlBase64", { value: xmlBase64, enumerable: false });
|
|
1334
|
+
Object.defineProperty(this, "cause", { value: this.diagnostico.causa, enumerable: false });
|
|
1335
|
+
}
|
|
1336
|
+
name = "ErroAcbrNode";
|
|
1337
|
+
#diagnostico;
|
|
1338
|
+
get diagnostico() {
|
|
1339
|
+
return this.#diagnostico;
|
|
1340
|
+
}
|
|
1341
|
+
/** Acrescenta apenas o aviso estático de limpeza, preservando o erro da operação. */
|
|
1342
|
+
anotarFalhaLimpeza() {
|
|
1343
|
+
this.#diagnostico = adicionarDiagnosticoLimpeza(this.#diagnostico);
|
|
1344
|
+
}
|
|
1345
|
+
toJSON() {
|
|
1346
|
+
return this.diagnostico;
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1276
1349
|
}
|
|
1277
|
-
};
|
|
1350
|
+
});
|
|
1278
1351
|
|
|
1279
1352
|
// src/runtime.ts
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
var fail = (code, message, req, unknown = false, detalhes) => new ErroAcbrNode(code, message, unknown, req?.comando === "transmitir" ? req.xmlBase64 : void 0, { ...req ? { etapa: etapaDaOperacao(req.comando) } : {}, ...detalhes });
|
|
1353
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
1354
|
+
import { readFile as readFile6, stat as stat3 } from "node:fs/promises";
|
|
1355
|
+
import path3 from "node:path";
|
|
1356
|
+
import { createRequire } from "node:module";
|
|
1357
|
+
import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
|
|
1358
|
+
import { TextDecoder } from "node:util";
|
|
1287
1359
|
function confined(root, relative3) {
|
|
1288
|
-
const file =
|
|
1289
|
-
if (!relative3 ||
|
|
1360
|
+
const file = path3.resolve(root, relative3), part = path3.relative(root, file);
|
|
1361
|
+
if (!relative3 || path3.isAbsolute(relative3) || part === ".." || part.startsWith(".." + path3.sep)) throw fail2("RUNTIME_INVALIDO", "Caminho inv\xE1lido no runtime.");
|
|
1290
1362
|
return file;
|
|
1291
1363
|
}
|
|
1292
1364
|
async function resolveRuntime(directory, contract) {
|
|
1293
|
-
if (!validContract(contract)) throw
|
|
1365
|
+
if (!validContract(contract)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1294
1366
|
let root = directory;
|
|
1295
1367
|
if (!root) {
|
|
1296
|
-
if (!["linux", "win32"].includes(process.platform) || process.arch !== "x64") throw
|
|
1368
|
+
if (!["linux", "win32"].includes(process.platform) || process.arch !== "x64") throw fail2("PLATAFORMA_NAO_SUPORTADA", "Esta vers\xE3o exige Linux ou Windows x64.");
|
|
1297
1369
|
try {
|
|
1298
1370
|
const require2 = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url);
|
|
1299
|
-
root =
|
|
1371
|
+
root = path3.join(path3.dirname(require2.resolve("cosmemilton-acbr-node-" + process.platform + "-x64/package.json")), "runtime");
|
|
1300
1372
|
} catch {
|
|
1301
|
-
throw
|
|
1373
|
+
throw fail2("RUNTIME_AUSENTE", "Instale o pacote de runtime da plataforma ou informe runtimeDirectory.");
|
|
1302
1374
|
}
|
|
1303
1375
|
}
|
|
1304
|
-
root =
|
|
1376
|
+
root = path3.resolve(root);
|
|
1305
1377
|
let m;
|
|
1306
1378
|
try {
|
|
1307
|
-
m = JSON.parse(await
|
|
1379
|
+
m = JSON.parse(await readFile6(path3.join(root, "manifest.json"), "utf8"));
|
|
1308
1380
|
} catch {
|
|
1309
|
-
throw
|
|
1381
|
+
throw fail2("RUNTIME_AUSENTE", "Manifesto do runtime n\xE3o encontrado.");
|
|
1310
1382
|
}
|
|
1311
|
-
if (!validContract(m) || m.formatVersion !== 1 || !plain(m.files) || typeof m.executable !== "string" || m.platform !== process.platform || m.arch !== process.arch) throw
|
|
1312
|
-
if (m.
|
|
1383
|
+
if (!validContract(m) || m.formatVersion !== 1 || !plain(m.files) || typeof m.executable !== "string" || m.platform !== process.platform || m.arch !== process.arch) throw fail2("RUNTIME_INVALIDO", "Manifesto ou plataforma do runtime inv\xE1lidos.");
|
|
1384
|
+
if (m.capabilities !== void 0 && (!Array.isArray(m.capabilities) || !m.capabilities.every((value) => typeof value === "string" && /^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(value)))) throw fail2("RUNTIME_INVALIDO", "Capacidades do runtime inv\xE1lidas.");
|
|
1385
|
+
if (m.sourceRevision !== contract.sourceRevision || m.contractHash !== contract.contractHash) throw fail2("CONTRATO_DIVERGENTE", "Cliente e motor foram gerados de contratos diferentes; regenere e recompile.");
|
|
1313
1386
|
for (const [name, hash2] of Object.entries(m.files)) {
|
|
1314
|
-
if (typeof hash2 !== "string" || !/^[a-f0-9]{64}$/.test(hash2)) throw
|
|
1387
|
+
if (typeof hash2 !== "string" || !/^[a-f0-9]{64}$/.test(hash2)) throw fail2("RUNTIME_INVALIDO", "Hash inv\xE1lido no runtime.");
|
|
1315
1388
|
const file = confined(root, name);
|
|
1316
1389
|
let data;
|
|
1317
1390
|
try {
|
|
1318
1391
|
if (!(await stat3(file)).isFile()) throw Error();
|
|
1319
|
-
data = await
|
|
1392
|
+
data = await readFile6(file);
|
|
1320
1393
|
} catch {
|
|
1321
|
-
throw
|
|
1394
|
+
throw fail2("RUNTIME_INCOMPLETO", "Arquivo do runtime ausente.");
|
|
1322
1395
|
}
|
|
1323
|
-
if (
|
|
1396
|
+
if (createHash4("sha256").update(data).digest("hex") !== hash2) throw fail2("RUNTIME_ALTERADO", "O runtime n\xE3o corresponde ao manifesto distribu\xEDdo.");
|
|
1324
1397
|
}
|
|
1325
|
-
if (!m.files[m.executable]) throw
|
|
1326
|
-
return { directory: root, executable: confined(root, m.executable) };
|
|
1398
|
+
if (!m.files[m.executable]) throw fail2("RUNTIME_INVALIDO", "O execut\xE1vel n\xE3o consta no invent\xE1rio.");
|
|
1399
|
+
return { directory: root, executable: confined(root, m.executable), capabilities: new Set(m.capabilities ?? []) };
|
|
1327
1400
|
}
|
|
1328
1401
|
function criarEmissor(options) {
|
|
1329
|
-
const configFail = (campo) =>
|
|
1402
|
+
const configFail = (campo) => fail2("CONFIGURACAO_INVALIDA", "Informe campos e tipos v\xE1lidos na configura\xE7\xE3o.", void 0, false, { etapa: "configuracao", campo });
|
|
1330
1403
|
if (!plain(options)) throw configFail();
|
|
1331
1404
|
if (typeof options.cnpj !== "string" || !/^\d{14}$/.test(options.cnpj)) throw configFail("cnpj");
|
|
1332
1405
|
if (typeof options.uf !== "string" || !UFS.has(options.uf)) throw configFail("uf");
|
|
1333
1406
|
if (![55, 65].includes(options.modelo)) throw configFail("modelo");
|
|
1334
1407
|
if (![1, 2].includes(options.ambiente)) throw configFail("ambiente");
|
|
1335
|
-
if (!validContract(options.contrato)) throw
|
|
1408
|
+
if (!validContract(options.contrato)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1336
1409
|
const cert = options.certificado;
|
|
1337
|
-
if (cert !== void 0 && (!plain(cert) || typeof cert.senha !== "string" || !!cert.pfx === !!cert.arquivo || cert.pfx !== void 0 && !(cert.pfx instanceof Uint8Array) || cert.arquivo !== void 0 && (typeof cert.arquivo !== "string" || !cert.arquivo))) throw
|
|
1338
|
-
if (options.csc !== void 0 && (!plain(options.csc) || typeof options.csc.id !== "string" || !/^\d{1,6}$/.test(options.csc.id) || typeof options.csc.valor !== "string" || !options.csc.valor || options.csc.valor.length > 256)) throw
|
|
1410
|
+
if (cert !== void 0 && (!plain(cert) || typeof cert.senha !== "string" || !!cert.pfx === !!cert.arquivo || cert.pfx !== void 0 && !(cert.pfx instanceof Uint8Array) || cert.arquivo !== void 0 && (typeof cert.arquivo !== "string" || !cert.arquivo))) throw fail2("CERTIFICADO_INVALIDO", "Informe A1 em pfx ou arquivo e sua senha.", void 0, false, { campo: "certificado" });
|
|
1411
|
+
if (options.csc !== void 0 && (!plain(options.csc) || typeof options.csc.id !== "string" || !/^\d{1,6}$/.test(options.csc.id) || typeof options.csc.valor !== "string" || !options.csc.valor || options.csc.valor.length > 256)) throw fail2("CSC_INVALIDO", "CSC inv\xE1lido.", void 0, false, { campo: "csc" });
|
|
1339
1412
|
if (options.runtimeDirectory !== void 0 && (typeof options.runtimeDirectory !== "string" || !options.runtimeDirectory)) throw configFail("runtimeDirectory");
|
|
1340
1413
|
if (options.validaDocumento !== void 0 && typeof options.validaDocumento !== "function" || options.criaProcesso !== void 0 && typeof options.criaProcesso !== "function") throw configFail();
|
|
1341
1414
|
const cfg = { cnpj: options.cnpj, uf: options.uf, modelo: options.modelo, ambiente: options.ambiente, csc: options.csc ? { ...options.csc } : void 0 };
|
|
1342
1415
|
const certificate = cert ? { ...cert, pfx: cert.pfx ? Buffer.from(cert.pfx) : void 0 } : void 0;
|
|
1343
|
-
const contract = {
|
|
1416
|
+
const contract = { sourceRevision: options.contrato.sourceRevision, contractHash: options.contrato.contractHash };
|
|
1344
1417
|
const timeout = options.timeoutMs ?? 12e4, capacity = options.limiteFila ?? 32, bytesLimit = options.limiteBytes ?? MAX_BYTES;
|
|
1345
1418
|
if (!Number.isInteger(timeout) || timeout < 1 || timeout > 12e4) throw configFail("timeoutMs");
|
|
1346
1419
|
if (!Number.isInteger(capacity) || capacity < 0 || capacity > 1e3) throw configFail("limiteFila");
|
|
@@ -1349,7 +1422,7 @@ function criarEmissor(options) {
|
|
|
1349
1422
|
let runtimePromise, closed = false, teardownFailed = false, current;
|
|
1350
1423
|
const queue = [];
|
|
1351
1424
|
const closedError = () => {
|
|
1352
|
-
const error =
|
|
1425
|
+
const error = fail2("EMISSOR_FECHADO", "Emissor encerrado.");
|
|
1353
1426
|
if (teardownFailed) error.anotarFalhaLimpeza();
|
|
1354
1427
|
return error;
|
|
1355
1428
|
};
|
|
@@ -1361,9 +1434,10 @@ function criarEmissor(options) {
|
|
|
1361
1434
|
}
|
|
1362
1435
|
};
|
|
1363
1436
|
async function execute2(item) {
|
|
1364
|
-
if (closed || item.signal?.aborted) throw
|
|
1437
|
+
if (closed || item.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
|
|
1365
1438
|
const runtime = await (runtimePromise ??= resolveRuntime(options.runtimeDirectory, contract));
|
|
1366
|
-
if (
|
|
1439
|
+
if (item.req.comando === "recuperarXml" && !runtime.capabilities.has("recuperarXml")) throw fail2("RUNTIME_SEM_CAPACIDADE", "O runtime n\xE3o oferece recupera\xE7\xE3o de XML; atualize o pacote e o runtime compat\xEDvel.", item.req, false, { etapa: "runtime" });
|
|
1440
|
+
if (closed || item.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
|
|
1367
1441
|
return await new Promise((done, rejectExecution) => {
|
|
1368
1442
|
let stopError;
|
|
1369
1443
|
let child, finished = false, started = false, sending = false, total = 0, rest = Buffer.alloc(0), result;
|
|
@@ -1402,7 +1476,7 @@ function criarEmissor(options) {
|
|
|
1402
1476
|
};
|
|
1403
1477
|
const teardownFallback = () => {
|
|
1404
1478
|
if (finished) return;
|
|
1405
|
-
stopError ??=
|
|
1479
|
+
stopError ??= fail2("FALHA_MOTOR", "O motor n\xE3o foi encerrado.", item.req, uncertain());
|
|
1406
1480
|
stopError.anotarFalhaLimpeza();
|
|
1407
1481
|
teardownFailed = true;
|
|
1408
1482
|
closed = true;
|
|
@@ -1413,7 +1487,7 @@ function criarEmissor(options) {
|
|
|
1413
1487
|
};
|
|
1414
1488
|
const stop = (code, message) => {
|
|
1415
1489
|
if (finished || stopError) return;
|
|
1416
|
-
stopError =
|
|
1490
|
+
stopError = fail2(code, message, item.req, uncertain());
|
|
1417
1491
|
if (!child?.pid) {
|
|
1418
1492
|
finish(stopError);
|
|
1419
1493
|
detachOwnedChild();
|
|
@@ -1431,20 +1505,20 @@ function criarEmissor(options) {
|
|
|
1431
1505
|
current = { stop: () => stop("EMISSOR_FECHADO", "Emissor encerrado."), done: doneCurrent };
|
|
1432
1506
|
const env = {};
|
|
1433
1507
|
for (const key of ["PATH", "Path", "SystemRoot", "WINDIR", "TEMP", "TMP", "HOME", "LANG", "LC_ALL"]) if (process.env[key] !== void 0) env[key] = process.env[key];
|
|
1434
|
-
if (process.platform === "linux") env.LD_LIBRARY_PATH =
|
|
1508
|
+
if (process.platform === "linux") env.LD_LIBRARY_PATH = path3.join(runtime.directory, "lib");
|
|
1435
1509
|
if (process.platform === "win32") {
|
|
1436
1510
|
const inheritedPath = env.Path ?? env.PATH ?? "";
|
|
1437
1511
|
delete env.Path;
|
|
1438
|
-
env.PATH =
|
|
1512
|
+
env.PATH = path3.join(runtime.directory, "lib") + ";" + runtime.directory + ";" + inheritedPath;
|
|
1439
1513
|
}
|
|
1440
|
-
const modules =
|
|
1514
|
+
const modules = path3.join(runtime.directory, "ossl-modules");
|
|
1441
1515
|
env.OPENSSL_MODULES = modules;
|
|
1442
|
-
env.OPENSSL_CONF =
|
|
1516
|
+
env.OPENSSL_CONF = path3.join(runtime.directory, "openssl.cnf");
|
|
1443
1517
|
try {
|
|
1444
1518
|
child = launch(runtime.executable, ["--parent-pid", String(process.pid)], { cwd: runtime.directory, env, windowsHide: true, shell: false, stdio: ["pipe", "pipe", "pipe"] });
|
|
1445
1519
|
started = typeof child.pid === "number";
|
|
1446
1520
|
} catch {
|
|
1447
|
-
finish(
|
|
1521
|
+
finish(fail2("FALHA_INICIAR_MOTOR", "N\xE3o foi poss\xEDvel iniciar o motor.", item.req));
|
|
1448
1522
|
return;
|
|
1449
1523
|
}
|
|
1450
1524
|
item.signal?.addEventListener("abort", abort, { once: true });
|
|
@@ -1485,9 +1559,11 @@ function criarEmissor(options) {
|
|
|
1485
1559
|
continue;
|
|
1486
1560
|
}
|
|
1487
1561
|
if (result || frame.versao !== 1 || frame.sourceRevision !== contract.sourceRevision || frame.contractHash !== contract.contractHash || typeof frame.sucesso !== "boolean" || !STATES.has(String(frame.estado))) throw Error();
|
|
1488
|
-
if (frame.xmlBase64 !== void 0 && (typeof frame.xmlBase64 !== "string" || !frame.xmlBase64.length || Buffer.from(frame.xmlBase64, "base64").toString("base64") !== frame.xmlBase64)) throw Error();
|
|
1562
|
+
if (frame.xmlBase64 !== void 0 && (item.req.comando === "recuperarXml" ? !base64XmlRecuperadoValido(frame.xmlBase64) : typeof frame.xmlBase64 !== "string" || !frame.xmlBase64.length || Buffer.from(frame.xmlBase64, "base64").toString("base64") !== frame.xmlBase64)) throw Error();
|
|
1489
1563
|
if (frame.cStat !== void 0 && (!Number.isInteger(frame.cStat) || Number(frame.cStat) < 1 || Number(frame.cStat) > 9999)) throw Error();
|
|
1490
1564
|
if (frame.envioIniciado !== void 0 && typeof frame.envioIniciado !== "boolean" || sending && frame.envioIniciado === false) throw Error();
|
|
1565
|
+
if (frame.estado === "XML_RECUPERADO" && item.req.comando !== "recuperarXml") throw Error();
|
|
1566
|
+
if (item.req.comando === "recuperarXml" && (frame.sucesso === true || frame.estado === "XML_RECUPERADO") && (frame.sucesso !== true || frame.estado !== "XML_RECUPERADO" || frame.cStat !== 100 || typeof frame.chave !== "string" || !/^\d{44}$/.test(frame.chave) || typeof frame.protocolo !== "string" || !/^\d{15}$/.test(frame.protocolo) || typeof frame.xmlBase64 !== "string" || frame.envioIniciado === true || sending)) throw Error();
|
|
1491
1567
|
const fiscal = frame;
|
|
1492
1568
|
result = { ...fiscal, diagnostico: diagnosticarResultado(sending ? { ...fiscal, envioIniciado: true } : fiscal, item.req.comando) };
|
|
1493
1569
|
} catch {
|
|
@@ -1503,7 +1579,7 @@ function criarEmissor(options) {
|
|
|
1503
1579
|
return;
|
|
1504
1580
|
}
|
|
1505
1581
|
if (code !== 0 || rest.length || !result) {
|
|
1506
|
-
finish(
|
|
1582
|
+
finish(fail2("FALHA_MOTOR", "O motor encerrou sem resposta fiscal v\xE1lida.", item.req, uncertain()));
|
|
1507
1583
|
return;
|
|
1508
1584
|
}
|
|
1509
1585
|
finish();
|
|
@@ -1532,31 +1608,31 @@ function criarEmissor(options) {
|
|
|
1532
1608
|
}
|
|
1533
1609
|
async function request(command, data, operation = {}) {
|
|
1534
1610
|
const rawOperation = operation;
|
|
1535
|
-
if (!plain(rawOperation)) throw
|
|
1611
|
+
if (!plain(rawOperation)) throw fail2("OPERACAO_INVALIDA", "Informe op\xE7\xF5es v\xE1lidas para a opera\xE7\xE3o.", void 0, false, { etapa: etapaDaOperacao(command), campo: "operacao" });
|
|
1536
1612
|
const signal = operation.signal;
|
|
1537
|
-
if (signal !== void 0 && (!plain(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) throw
|
|
1613
|
+
if (signal !== void 0 && (!plain(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) throw fail2("OPERACAO_INVALIDA", "Informe op\xE7\xF5es v\xE1lidas para a opera\xE7\xE3o.", void 0, false, { etapa: etapaDaOperacao(command), campo: "signal" });
|
|
1538
1614
|
if (closed) throw closedError();
|
|
1539
|
-
if (operation.signal?.aborted) throw
|
|
1540
|
-
if (["assinar", "transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(command) && !certificate) throw
|
|
1615
|
+
if (operation.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
|
|
1616
|
+
if (["assinar", "transmitir", "consultar", "recuperarXml", "cancelar", "cartaCorrecao", "inutilizar"].includes(command) && !certificate) throw fail2("CERTIFICADO_AUSENTE", "A opera\xE7\xE3o exige um certificado A1.", void 0, false, { etapa: etapaDaOperacao(command) });
|
|
1541
1617
|
if (command === "gerarXml") options.validaDocumento?.(data.documento);
|
|
1542
1618
|
const config = { ...cfg };
|
|
1543
1619
|
if (certificate) {
|
|
1544
1620
|
let pfx;
|
|
1545
1621
|
try {
|
|
1546
|
-
pfx = certificate.pfx ?? await
|
|
1622
|
+
pfx = certificate.pfx ?? await readFile6(certificate.arquivo);
|
|
1547
1623
|
} catch {
|
|
1548
|
-
throw
|
|
1624
|
+
throw fail2("CERTIFICADO_AUSENTE", "N\xE3o foi poss\xEDvel ler o A1 configurado.");
|
|
1549
1625
|
}
|
|
1550
|
-
if (pfx.length > 2 * 1024 * 1024) throw
|
|
1626
|
+
if (pfx.length > 2 * 1024 * 1024) throw fail2("CERTIFICADO_EXCESSIVO", "Certificado excede o limite.");
|
|
1551
1627
|
config.certificado = { pfxBase64: pfx.toString("base64"), senha: certificate.senha };
|
|
1552
1628
|
}
|
|
1553
1629
|
let bytes, req;
|
|
1554
1630
|
try {
|
|
1555
|
-
bytes = Buffer.from(JSON.stringify({ versao: 1, id: randomUUID3(),
|
|
1631
|
+
bytes = Buffer.from(JSON.stringify({ ...data, ...contract, versao: 1, id: randomUUID3(), comando: command, config }) + "\n", "utf8");
|
|
1556
1632
|
if (bytes.length > bytesLimit) throw Error();
|
|
1557
1633
|
req = JSON.parse(bytes.toString("utf8"));
|
|
1558
1634
|
} catch {
|
|
1559
|
-
throw
|
|
1635
|
+
throw fail2("REQUISICAO_INVALIDA", "Dados da opera\xE7\xE3o inv\xE1lidos ou acima do limite.");
|
|
1560
1636
|
}
|
|
1561
1637
|
return new Promise((resolve5, reject) => {
|
|
1562
1638
|
if (closed) {
|
|
@@ -1566,7 +1642,7 @@ function criarEmissor(options) {
|
|
|
1566
1642
|
}
|
|
1567
1643
|
if (busy && queue.length >= capacity) {
|
|
1568
1644
|
bytes.fill(0);
|
|
1569
|
-
reject(
|
|
1645
|
+
reject(fail2("FILA_CHEIA", "A fila fiscal est\xE1 cheia."));
|
|
1570
1646
|
return;
|
|
1571
1647
|
}
|
|
1572
1648
|
const item = { req, bytes, signal: operation.signal, resolve: resolve5, reject };
|
|
@@ -1576,7 +1652,7 @@ function criarEmissor(options) {
|
|
|
1576
1652
|
queue.splice(i, 1);
|
|
1577
1653
|
bytes.fill(0);
|
|
1578
1654
|
operation.signal?.removeEventListener("abort", item.abort);
|
|
1579
|
-
reject(
|
|
1655
|
+
reject(fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o."));
|
|
1580
1656
|
}
|
|
1581
1657
|
};
|
|
1582
1658
|
operation.signal?.addEventListener("abort", item.abort, { once: true });
|
|
@@ -1586,47 +1662,48 @@ function criarEmissor(options) {
|
|
|
1586
1662
|
});
|
|
1587
1663
|
}
|
|
1588
1664
|
const xmlData = (xml) => {
|
|
1589
|
-
if (typeof xml !== "string" || !xml.trim() || Buffer.byteLength(xml, "utf8") > 2 * 1024 * 1024) throw
|
|
1665
|
+
if (typeof xml !== "string" || !xml.trim() || Buffer.byteLength(xml, "utf8") > 2 * 1024 * 1024) throw fail2("XML_INVALIDO", "XML vazio ou acima do limite.", void 0, false, { campo: "xml" });
|
|
1590
1666
|
return { xmlBase64: Buffer.from(xml, "utf8").toString("base64") };
|
|
1591
1667
|
};
|
|
1592
1668
|
const checkKey = (key) => {
|
|
1593
|
-
if (typeof key !== "string" || !/^\d{44}$/.test(key)) throw
|
|
1669
|
+
if (typeof key !== "string" || !/^\d{44}$/.test(key)) throw fail2("CHAVE_INVALIDA", "Chave fiscal inv\xE1lida.", void 0, false, { campo: "chave" });
|
|
1594
1670
|
};
|
|
1595
1671
|
const reason = (value) => {
|
|
1596
|
-
if (typeof value !== "string" || value.length < 15 || value.length > 255) throw
|
|
1672
|
+
if (typeof value !== "string" || value.length < 15 || value.length > 255) throw fail2("JUSTIFICATIVA_INVALIDA", "Justificativa deve ter de 15 a 255 caracteres.", void 0, false, { campo: "justificativa" });
|
|
1597
1673
|
};
|
|
1598
1674
|
const checkObject = (data, campo) => {
|
|
1599
|
-
if (!plain(data)) throw
|
|
1675
|
+
if (!plain(data)) throw fail2("OPERACAO_INVALIDA", "Informe os par\xE2metros da opera\xE7\xE3o como objeto.", void 0, false, { campo });
|
|
1600
1676
|
};
|
|
1601
1677
|
return {
|
|
1602
1678
|
gerarXml: (documento, op) => request("gerarXml", { documento }, op),
|
|
1603
1679
|
validar: (xml, op) => request("validar", xmlData(xml), op),
|
|
1604
1680
|
assinar: (xml, op) => request("assinar", xmlData(xml), op),
|
|
1605
1681
|
transmitir: (xml, op) => request("transmitir", xmlData(xml), op),
|
|
1682
|
+
recuperarXml: (xmlAssinado, opcoes) => request("recuperarXml", xmlData(xmlAssinado), opcoes),
|
|
1606
1683
|
consultar: (consulta, op) => {
|
|
1607
1684
|
checkObject(consulta, "consulta");
|
|
1608
1685
|
checkKey(consulta.chave);
|
|
1609
|
-
if (consulta.recibo !== void 0 && (typeof consulta.recibo !== "string" || !/^\d{15}$/.test(consulta.recibo))) throw
|
|
1610
|
-
return request("consultar", consulta, op);
|
|
1686
|
+
if (consulta.recibo !== void 0 && (typeof consulta.recibo !== "string" || !/^\d{15}$/.test(consulta.recibo))) throw fail2("RECIBO_INVALIDO", "Recibo inv\xE1lido.", void 0, false, { campo: "recibo" });
|
|
1687
|
+
return request("consultar", { chave: consulta.chave, ...consulta.recibo !== void 0 ? { recibo: consulta.recibo } : {} }, op);
|
|
1611
1688
|
},
|
|
1612
1689
|
cancelar: (data, op) => {
|
|
1613
1690
|
checkObject(data, "cancelamento");
|
|
1614
1691
|
checkKey(data.chave);
|
|
1615
1692
|
reason(data.justificativa);
|
|
1616
|
-
if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw
|
|
1617
|
-
return request("cancelar", data, op);
|
|
1693
|
+
if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw fail2("PROTOCOLO_INVALIDO", "Protocolo inv\xE1lido.", void 0, false, { campo: "protocolo" });
|
|
1694
|
+
return request("cancelar", { chave: data.chave, protocolo: data.protocolo, justificativa: data.justificativa }, op);
|
|
1618
1695
|
},
|
|
1619
1696
|
cartaCorrecao: (data, op) => {
|
|
1620
1697
|
checkObject(data, "cartaCorrecao");
|
|
1621
|
-
if (cfg.modelo !== 55) throw
|
|
1698
|
+
if (cfg.modelo !== 55) throw fail2("OPERACAO_NAO_SUPORTADA", "Carta de corre\xE7\xE3o exige NF-e modelo 55.");
|
|
1622
1699
|
checkKey(data.chave);
|
|
1623
|
-
if (typeof data.correcao !== "string" || data.correcao.length < 15 || data.correcao.length > 1e3 || !Number.isInteger(data.sequenciaEvento ?? 1) || (data.sequenciaEvento ?? 1) < 1 || (data.sequenciaEvento ?? 1) > 20) throw
|
|
1624
|
-
return request("cartaCorrecao", {
|
|
1700
|
+
if (typeof data.correcao !== "string" || data.correcao.length < 15 || data.correcao.length > 1e3 || !Number.isInteger(data.sequenciaEvento ?? 1) || (data.sequenciaEvento ?? 1) < 1 || (data.sequenciaEvento ?? 1) > 20) throw fail2("CORRECAO_INVALIDA", "Dados da carta de corre\xE7\xE3o inv\xE1lidos.", void 0, false, { campo: "cartaCorrecao" });
|
|
1701
|
+
return request("cartaCorrecao", { chave: data.chave, correcao: data.correcao, sequenciaEvento: data.sequenciaEvento ?? 1 }, op);
|
|
1625
1702
|
},
|
|
1626
1703
|
inutilizar: (data, op) => {
|
|
1627
1704
|
checkObject(data, "inutilizacao");
|
|
1628
1705
|
reason(data.justificativa);
|
|
1629
|
-
if (!Number.isInteger(data.ano) || data.ano < 0 || data.ano > 99 || !Number.isInteger(data.serie) || data.serie < 0 || data.serie > 999 || !Number.isInteger(data.numeroInicial) || data.numeroInicial < 1 || !Number.isInteger(data.numeroFinal) || data.numeroFinal < data.numeroInicial || data.numeroFinal > 999999999) throw
|
|
1706
|
+
if (!Number.isInteger(data.ano) || data.ano < 0 || data.ano > 99 || !Number.isInteger(data.serie) || data.serie < 0 || data.serie > 999 || !Number.isInteger(data.numeroInicial) || data.numeroInicial < 1 || !Number.isInteger(data.numeroFinal) || data.numeroFinal < data.numeroInicial || data.numeroFinal > 999999999) throw fail2("INUTILIZACAO_INVALIDA", "Faixa de inutiliza\xE7\xE3o inv\xE1lida.", void 0, false, { campo: "inutilizacao" });
|
|
1630
1707
|
return request("inutilizar", { inutilizacao: { ano: data.ano, serie: data.serie, numeroInicial: data.numeroInicial, numeroFinal: data.numeroFinal }, justificativa: data.justificativa }, op);
|
|
1631
1708
|
},
|
|
1632
1709
|
async fechar() {
|
|
@@ -1644,118 +1721,145 @@ function criarEmissor(options) {
|
|
|
1644
1721
|
}
|
|
1645
1722
|
};
|
|
1646
1723
|
}
|
|
1724
|
+
var STATES, UFS, MAX_BYTES, MAX_TEARDOWN_MS, plain, validContract, fail2;
|
|
1725
|
+
var init_runtime = __esm({
|
|
1726
|
+
"src/runtime.ts"() {
|
|
1727
|
+
"use strict";
|
|
1728
|
+
init_types();
|
|
1729
|
+
init_diagnostics();
|
|
1730
|
+
init_types();
|
|
1731
|
+
init_diagnostics();
|
|
1732
|
+
STATES = /* @__PURE__ */ new Set(["DENEGADO", "XML_GERADO", "VALIDADO", "ASSINADO", "XML_RECUPERADO", "AUTORIZADO", "REJEITADO", "PENDENTE", "INDETERMINADO", "CONSULTADO", "CANCELADO", "EVENTO_REGISTRADO", "INUTILIZADO", "ERRO"]);
|
|
1733
|
+
UFS = new Set("AC AL AP AM BA CE DF ES GO MA MT MS MG PA PB PR PE PI RJ RN RS RO RR SC SP SE TO".split(" "));
|
|
1734
|
+
MAX_BYTES = 8 * 1024 * 1024;
|
|
1735
|
+
MAX_TEARDOWN_MS = 1e3;
|
|
1736
|
+
plain = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
1737
|
+
validContract = (v) => plain(v) && Number.isInteger(v.sourceRevision) && Number(v.sourceRevision) > 0 && typeof v.contractHash === "string" && /^[a-f0-9]{64}$/.test(v.contractHash);
|
|
1738
|
+
fail2 = (code, message, req, unknown = false, detalhes) => new ErroAcbrNode(code, message, unknown, req?.comando === "transmitir" ? req.xmlBase64 : void 0, { ...req ? { etapa: etapaDaOperacao(req.comando) } : {}, ...detalhes });
|
|
1739
|
+
}
|
|
1740
|
+
});
|
|
1647
1741
|
|
|
1648
1742
|
// src/offline-fixture.ts
|
|
1649
|
-
var OFFLINE_DOCUMENT
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
"IE": "123456789",
|
|
1677
|
-
"CRT": "crtSimplesNacional",
|
|
1678
|
-
"EnderEmit": {
|
|
1679
|
-
"xLgr": "RUA TESTE",
|
|
1680
|
-
"nro": "1",
|
|
1681
|
-
"xBairro": "TESTE",
|
|
1682
|
-
"cMun": 2304400,
|
|
1683
|
-
"xMun": "FORTALEZA",
|
|
1684
|
-
"UF": "CE",
|
|
1685
|
-
"CEP": 6e7,
|
|
1686
|
-
"cPais": 1058,
|
|
1687
|
-
"xPais": "BRASIL"
|
|
1688
|
-
}
|
|
1689
|
-
},
|
|
1690
|
-
"Dest": {
|
|
1691
|
-
"CNPJCPF": "12345678909",
|
|
1692
|
-
"xNome": "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL",
|
|
1693
|
-
"indIEDest": "inNaoContribuinte",
|
|
1694
|
-
"EnderDest": {
|
|
1695
|
-
"xLgr": "RUA TESTE",
|
|
1696
|
-
"nro": "2",
|
|
1697
|
-
"xBairro": "TESTE",
|
|
1698
|
-
"cMun": 2304400,
|
|
1699
|
-
"xMun": "FORTALEZA",
|
|
1700
|
-
"UF": "CE",
|
|
1701
|
-
"CEP": 6e7,
|
|
1702
|
-
"cPais": 1058,
|
|
1703
|
-
"xPais": "BRASIL"
|
|
1704
|
-
}
|
|
1705
|
-
},
|
|
1706
|
-
"Det": [
|
|
1707
|
-
{
|
|
1708
|
-
"Prod": {
|
|
1709
|
-
"nItem": 1,
|
|
1710
|
-
"cProd": "TESTE",
|
|
1711
|
-
"cEAN": "SEM GTIN",
|
|
1712
|
-
"xProd": "Caf\xE9 S\xE3o Jos\xE9 PRODUTO SINT\xC9TICO OFFLINE",
|
|
1713
|
-
"NCM": "22021000",
|
|
1714
|
-
"CFOP": "5102",
|
|
1715
|
-
"uCom": "UN",
|
|
1716
|
-
"qCom": "1",
|
|
1717
|
-
"vUnCom": "10",
|
|
1718
|
-
"vProd": "10",
|
|
1719
|
-
"cEANTrib": "SEM GTIN",
|
|
1720
|
-
"uTrib": "UN",
|
|
1721
|
-
"qTrib": "1",
|
|
1722
|
-
"vUnTrib": "10",
|
|
1723
|
-
"IndTot": "itSomaTotalNFe"
|
|
1743
|
+
var OFFLINE_DOCUMENT, OFFLINE_SIGNED_XML;
|
|
1744
|
+
var init_offline_fixture = __esm({
|
|
1745
|
+
"src/offline-fixture.ts"() {
|
|
1746
|
+
"use strict";
|
|
1747
|
+
OFFLINE_DOCUMENT = {
|
|
1748
|
+
"infNFe": {
|
|
1749
|
+
"Versao": "4.00"
|
|
1750
|
+
},
|
|
1751
|
+
"Ide": {
|
|
1752
|
+
"cUF": 23,
|
|
1753
|
+
"cNF": 12345678,
|
|
1754
|
+
"natOp": "VENDA TESTE OFFLINE",
|
|
1755
|
+
"modelo": 55,
|
|
1756
|
+
"serie": 1,
|
|
1757
|
+
"nNF": 1,
|
|
1758
|
+
"dEmi": "2026-10-08T12:00:00",
|
|
1759
|
+
"tpNF": "tnSaida",
|
|
1760
|
+
"idDest": "doInterna",
|
|
1761
|
+
"cMunFG": 2304400,
|
|
1762
|
+
"tpImp": "tiRetrato",
|
|
1763
|
+
"tpEmis": "teNormal",
|
|
1764
|
+
"tpAmb": "taHomologacao",
|
|
1765
|
+
"finNFe": "fnNormal",
|
|
1766
|
+
"indFinal": "cfConsumidorFinal",
|
|
1767
|
+
"indPres": "pcPresencial",
|
|
1768
|
+
"procEmi": "peAplicativoContribuinte",
|
|
1769
|
+
"verProc": "ACBR-NODE-OFFLINE"
|
|
1724
1770
|
},
|
|
1725
|
-
"
|
|
1726
|
-
"
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
"
|
|
1731
|
-
"
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
"
|
|
1771
|
+
"Emit": {
|
|
1772
|
+
"CNPJCPF": "11222333000181",
|
|
1773
|
+
"xNome": "Caf\xE9 S\xE3o Jos\xE9 TESTE OFFLINE SEM VALOR FISCAL",
|
|
1774
|
+
"IE": "123456789",
|
|
1775
|
+
"CRT": "crtSimplesNacional",
|
|
1776
|
+
"EnderEmit": {
|
|
1777
|
+
"xLgr": "RUA TESTE",
|
|
1778
|
+
"nro": "1",
|
|
1779
|
+
"xBairro": "TESTE",
|
|
1780
|
+
"cMun": 2304400,
|
|
1781
|
+
"xMun": "FORTALEZA",
|
|
1782
|
+
"UF": "CE",
|
|
1783
|
+
"CEP": 6e7,
|
|
1784
|
+
"cPais": 1058,
|
|
1785
|
+
"xPais": "BRASIL"
|
|
1735
1786
|
}
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1787
|
+
},
|
|
1788
|
+
"Dest": {
|
|
1789
|
+
"CNPJCPF": "12345678909",
|
|
1790
|
+
"xNome": "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL",
|
|
1791
|
+
"indIEDest": "inNaoContribuinte",
|
|
1792
|
+
"EnderDest": {
|
|
1793
|
+
"xLgr": "RUA TESTE",
|
|
1794
|
+
"nro": "2",
|
|
1795
|
+
"xBairro": "TESTE",
|
|
1796
|
+
"cMun": 2304400,
|
|
1797
|
+
"xMun": "FORTALEZA",
|
|
1798
|
+
"UF": "CE",
|
|
1799
|
+
"CEP": 6e7,
|
|
1800
|
+
"cPais": 1058,
|
|
1801
|
+
"xPais": "BRASIL"
|
|
1802
|
+
}
|
|
1803
|
+
},
|
|
1804
|
+
"Det": [
|
|
1805
|
+
{
|
|
1806
|
+
"Prod": {
|
|
1807
|
+
"nItem": 1,
|
|
1808
|
+
"cProd": "TESTE",
|
|
1809
|
+
"cEAN": "SEM GTIN",
|
|
1810
|
+
"xProd": "Caf\xE9 S\xE3o Jos\xE9 PRODUTO SINT\xC9TICO OFFLINE",
|
|
1811
|
+
"NCM": "22021000",
|
|
1812
|
+
"CFOP": "5102",
|
|
1813
|
+
"uCom": "UN",
|
|
1814
|
+
"qCom": "1",
|
|
1815
|
+
"vUnCom": "10",
|
|
1816
|
+
"vProd": "10",
|
|
1817
|
+
"cEANTrib": "SEM GTIN",
|
|
1818
|
+
"uTrib": "UN",
|
|
1819
|
+
"qTrib": "1",
|
|
1820
|
+
"vUnTrib": "10",
|
|
1821
|
+
"IndTot": "itSomaTotalNFe"
|
|
1822
|
+
},
|
|
1823
|
+
"Imposto": {
|
|
1824
|
+
"ICMS": {
|
|
1825
|
+
"orig": "oeNacional",
|
|
1826
|
+
"CSOSN": "csosn102"
|
|
1827
|
+
},
|
|
1828
|
+
"PIS": {
|
|
1829
|
+
"CST": "pis07"
|
|
1830
|
+
},
|
|
1831
|
+
"COFINS": {
|
|
1832
|
+
"CST": "cof07"
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
],
|
|
1837
|
+
"Total": {
|
|
1838
|
+
"ICMSTot": {
|
|
1839
|
+
"vProd": "10",
|
|
1840
|
+
"vNF": "10"
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1843
|
+
"Transp": {
|
|
1844
|
+
"modFrete": "mfSemFrete"
|
|
1845
|
+
},
|
|
1846
|
+
"pag": [
|
|
1847
|
+
{
|
|
1848
|
+
"tPag": "fpDinheiro",
|
|
1849
|
+
"indPag": "ipVista",
|
|
1850
|
+
"vPag": "10"
|
|
1851
|
+
}
|
|
1852
|
+
]
|
|
1853
|
+
};
|
|
1854
|
+
OFFLINE_SIGNED_XML = '<?xml version="1.0" encoding="UTF-8"?><NFe xmlns="http://www.portalfiscal.inf.br/nfe"><infNFe Id="NFe23261011222333000181550010000000011123456780" versao="4.00"><ide><cUF>23</cUF><cNF>12345678</cNF><natOp>VENDA TESTE OFFLINE</natOp><mod>55</mod><serie>1</serie><nNF>1</nNF><dhEmi>2026-10-08T12:00:00-03:00</dhEmi><tpNF>1</tpNF><idDest>1</idDest><cMunFG>2304400</cMunFG><tpImp>1</tpImp><tpEmis>1</tpEmis><cDV>0</cDV><tpAmb>2</tpAmb><finNFe>1</finNFe><indFinal>1</indFinal><indPres>1</indPres><procEmi>0</procEmi><verProc>ACBR-NODE-OFFLINE</verProc></ide><emit><CNPJ>11222333000181</CNPJ><xNome>Caf\xE9 S\xE3o Jos\xE9 TESTE OFFLINE SEM VALOR FISCAL</xNome><enderEmit><xLgr>RUA TESTE</xLgr><nro>1</nro><xBairro>TESTE</xBairro><cMun>2304400</cMun><xMun>FORTALEZA</xMun><UF>CE</UF><CEP>60000000</CEP><cPais>1058</cPais><xPais>BRASIL</xPais></enderEmit><IE>123456789</IE><CRT>1</CRT></emit><dest><CPF>12345678909</CPF><xNome>NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL</xNome><enderDest><xLgr>RUA TESTE</xLgr><nro>2</nro><xBairro>TESTE</xBairro><cMun>2304400</cMun><xMun>FORTALEZA</xMun><UF>CE</UF><CEP>60000000</CEP><cPais>1058</cPais><xPais>BRASIL</xPais></enderDest><indIEDest>9</indIEDest></dest><det nItem="1"><prod><cProd>TESTE</cProd><cEAN>SEM GTIN</cEAN><xProd>Caf\xE9 S\xE3o Jos\xE9 PRODUTO SINT\xC9TICO OFFLINE</xProd><NCM>22021000</NCM><CFOP>5102</CFOP><uCom>UN</uCom><qCom>1.0000</qCom><vUnCom>10.0000000000</vUnCom><vProd>10.00</vProd><cEANTrib>SEM GTIN</cEANTrib><uTrib>UN</uTrib><qTrib>1.0000</qTrib><vUnTrib>10.0000000000</vUnTrib><indTot>1</indTot></prod><imposto><ICMS><ICMSSN102><orig>0</orig><CSOSN>102</CSOSN></ICMSSN102></ICMS><PIS><PISNT><CST>07</CST></PISNT></PIS><COFINS><COFINSNT><CST>07</CST></COFINSNT></COFINS></imposto></det><total><ICMSTot><vBC>0.00</vBC><vICMS>0.00</vICMS><vICMSDeson>0.00</vICMSDeson><vFCP>0.00</vFCP><vBCST>0.00</vBCST><vST>0.00</vST><vFCPST>0.00</vFCPST><vFCPSTRet>0.00</vFCPSTRet><vProd>10.00</vProd><vFrete>0.00</vFrete><vSeg>0.00</vSeg><vDesc>0.00</vDesc><vII>0.00</vII><vIPI>0.00</vIPI><vIPIDevol>0.00</vIPIDevol><vPIS>0.00</vPIS><vCOFINS>0.00</vCOFINS><vOutro>0.00</vOutro><vNF>10.00</vNF></ICMSTot></total><transp><modFrete>9</modFrete></transp><pag><detPag><indPag>0</indPag><tPag>01</tPag><vPag>10.00</vPag></detPag></pag></infNFe><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI="#NFe23261011222333000181550010000000011123456780"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform><Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>Ya5kXhcEibOVfcyOI0BzqcYzyMM=</DigestValue></Reference></SignedInfo><SignatureValue>mirdDvdV+VId/zsstW/6lVFsSVxdyWkdkY1NPd2ynLHpjtolFoIhaBGlfxxs7IhU/AzcNQmR6ivr9YkH1HXaMAypvvx9M6GR/T4du/Zqab4gx3YInVybjJTeQ7BKEDnLhde2TUKoXrxmfrrmBUw6K4nTNufVjUjFJBfGcwhJ57T72x7ssdoYuPvZCphb0IR8WxHRKhvKAQhjW61qfh33csTabelgVZSLuTC2I2k9+a+ARd88CLTlfhYNCAPItOdUnAjgrhAhtiDi2FjXKjywgRqx0zay8DxF9Y2iyTJd3IAoWOERGdI9whgsuzWiZUr2I0I5QGGBELVabfjXm/Bneg==</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIDhjCCAm6gAwIBAgIBATANBgkqhkiG9w0BAQsFADBbMSswKQYDVQQDEyJBQ0JSIE5PREUgU1lOVEhFVElDOjExMjIyMzMzMDAwMTgxMQswCQYDVQQGEwJCUjEfMB0GA1UEChMWU1lOVEhFVElDIE9GRkxJTkUgVEVTVDAeFw0yNjEwMDYyMjIzMzNaFw0yNzEwMDgyMjIzMzNaMFsxKzApBgNVBAMTIkFDQlIgTk9ERSBTWU5USEVUSUM6MTEyMjIzMzMwMDAxODExCzAJBgNVBAYTAkJSMR8wHQYDVQQKExZTWU5USEVUSUMgT0ZGTElORSBURVNUMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsOwRzuW4de7jrv1IkcNgT311292NR5NNIHt6Fncarm2iJX6mYsIjPWriFQmrU88p7bfRI3EsXJrlK0oGCuMafbNf1nBZ6Tu8aV1ixbAIgu9ZIbWoDqDNbYJBucQRuKsI1ytFbY7eI0juhcdAlBHw3TNdgSbuv/8kEGgTTJ803wBcC+emGZHdpb4Bwx6Db0Fio0lWLlBaep9+MFNZZiEYmDA3dwgZF14MAr5MpzcNDUVYh/g95Ks8x+mhErOPdtmL1A6cDg+xtjiApeMJZqjMrdsXP4yQ34h5VRy03ZUJkXVAquOfWhXpQL/qjoSzXfHvij2wB0pVn89FzVZh7GzStQIDAQABo1UwUzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DATBgNVHSUEDDAKBggrBgEFBQcDAjAkBgNVHREEHTAboBkGBWBMAQMDoBAMDjExMjIyMzMzMDAwMTgxMA0GCSqGSIb3DQEBCwUAA4IBAQBDhbpxphiuAUlQWXkcVt22Nc+g2UM6GCZyC3v9o21llLSCyK/nhkrRCQzM75/86kbnYZ1zdulC9N4XQFgATwm16Sf/nDZw8s5EsXqZ8mwbauDs/aQvWrbQnyawB7c+aXvlUDkcfNq+3hLQ5ep8/bmGh4eueiNoPD0fjf/jUVmrS6KyHb6/FyIZGP6fEYAO6XrqJPMSPxpJHnbPXZXKW2vcCh3qaG1vTSeN8PLfN2Q/mp1XUH8VqHgl3jzssx/zwb1NKuKEz9WL+6ilLc1ZfIqUakJyQNMqMz2KIjqGKGp7TtpNHZ7mz+kBX4Xw7D5fFVrXYb7DN6KylyKLmXoEzs1B</X509Certificate></X509Data></KeyInfo></Signature></NFe>';
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1757
1857
|
|
|
1758
1858
|
// src/offline-check.ts
|
|
1859
|
+
var offline_check_exports = {};
|
|
1860
|
+
__export(offline_check_exports, {
|
|
1861
|
+
checkOffline: () => checkOffline
|
|
1862
|
+
});
|
|
1759
1863
|
async function checkOffline(config, manifest) {
|
|
1760
1864
|
const emitter = criarEmissor({
|
|
1761
1865
|
cnpj: "11222333000181",
|
|
@@ -1790,11 +1894,246 @@ async function checkOffline(config, manifest) {
|
|
|
1790
1894
|
await emitter.fechar();
|
|
1791
1895
|
}
|
|
1792
1896
|
}
|
|
1897
|
+
var init_offline_check = __esm({
|
|
1898
|
+
"src/offline-check.ts"() {
|
|
1899
|
+
"use strict";
|
|
1900
|
+
init_native_build();
|
|
1901
|
+
init_runtime();
|
|
1902
|
+
init_offline_fixture();
|
|
1903
|
+
}
|
|
1904
|
+
});
|
|
1905
|
+
|
|
1906
|
+
// src/cli.ts
|
|
1907
|
+
import { realpathSync } from "node:fs";
|
|
1908
|
+
import { access as access4 } from "node:fs/promises";
|
|
1909
|
+
import { resolve as resolve4 } from "node:path";
|
|
1910
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1911
|
+
|
|
1912
|
+
// src/contract-help.ts
|
|
1913
|
+
import { createHash } from "node:crypto";
|
|
1914
|
+
import { readFile } from "node:fs/promises";
|
|
1915
|
+
import path from "node:path";
|
|
1916
|
+
|
|
1917
|
+
// generated/acbr/models.ts
|
|
1918
|
+
var ACBR_CONTRACT = { "sourceRevision": 48590, "contractHash": "e5a497cefe8e0e350a30da5cc04e88b35c38a98535893d52f878890260d1346d" };
|
|
1919
|
+
var SOURCE_REVISION = ACBR_CONTRACT.sourceRevision;
|
|
1920
|
+
var CONTRACT_HASH = ACBR_CONTRACT.contractHash;
|
|
1921
|
+
var TACBrProcessoEmissao = Object.freeze({ "peAplicativoContribuinte": "peAplicativoContribuinte", "peAvulsaFisco": "peAvulsaFisco", "peAvulsaContribuinte": "peAvulsaContribuinte", "peContribuinteAplicativoFisco": "peContribuinteAplicativoFisco", "peProvedorAssinaturaAutorizacao": "peProvedorAssinaturaAutorizacao" });
|
|
1922
|
+
var TACBrTipoAmbiente = Object.freeze({ "taProducao": "taProducao", "taHomologacao": "taHomologacao" });
|
|
1923
|
+
var TACBrTipoEmissao = Object.freeze({ "teNormal": "teNormal", "teContingencia": "teContingencia", "teSCAN": "teSCAN", "teDPEC": "teDPEC", "teFSDA": "teFSDA", "teSVCAN": "teSVCAN", "teSVCRS": "teSVCRS", "teSVCSP": "teSVCSP", "teOffLine": "teOffLine" });
|
|
1924
|
+
var TACBrTipoImpressao = Object.freeze({ "tiSemGeracao": "tiSemGeracao", "tiRetrato": "tiRetrato", "tiPaisagem": "tiPaisagem", "tiSimplificado": "tiSimplificado", "tiNFCe": "tiNFCe", "tiMsgEletronica": "tiMsgEletronica", "tiSimplificadoTipo2": "tiSimplificadoTipo2" });
|
|
1925
|
+
var TcCredPres = Object.freeze({ "cpNenhum": "cpNenhum", "cp01": "cp01", "cp02": "cp02", "cp03": "cp03", "cp04": "cp04", "cp05": "cp05", "cp06": "cp06", "cp07": "cp07", "cp08": "cp08", "cp09": "cp09", "cp10": "cp10", "cp11": "cp11", "cp12": "cp12", "cp13": "cp13" });
|
|
1926
|
+
var TCSOSNIcms = Object.freeze({ "csosnVazio": "csosnVazio", "csosn101": "csosn101", "csosn102": "csosn102", "csosn103": "csosn103", "csosn201": "csosn201", "csosn202": "csosn202", "csosn203": "csosn203", "csosn300": "csosn300", "csosn400": "csosn400", "csosn500": "csosn500", "csosn900": "csosn900" });
|
|
1927
|
+
var TCSTCofins = Object.freeze({ "cof01": "cof01", "cof02": "cof02", "cof03": "cof03", "cof04": "cof04", "cof05": "cof05", "cof06": "cof06", "cof07": "cof07", "cof08": "cof08", "cof09": "cof09", "cof49": "cof49", "cof50": "cof50", "cof51": "cof51", "cof52": "cof52", "cof53": "cof53", "cof54": "cof54", "cof55": "cof55", "cof56": "cof56", "cof60": "cof60", "cof61": "cof61", "cof62": "cof62", "cof63": "cof63", "cof64": "cof64", "cof65": "cof65", "cof66": "cof66", "cof67": "cof67", "cof70": "cof70", "cof71": "cof71", "cof72": "cof72", "cof73": "cof73", "cof74": "cof74", "cof75": "cof75", "cof98": "cof98", "cof99": "cof99" });
|
|
1928
|
+
var TCSTIBSCBS = Object.freeze({ "cstNenhum": "cstNenhum", "cst000": "cst000", "cst010": "cst010", "cst011": "cst011", "cst200": "cst200", "cst220": "cst220", "cst221": "cst221", "cst222": "cst222", "cst400": "cst400", "cst410": "cst410", "cst510": "cst510", "cst515": "cst515", "cst550": "cst550", "cst620": "cst620", "cst800": "cst800", "cst810": "cst810", "cst811": "cst811", "cst820": "cst820", "cst830": "cst830" });
|
|
1929
|
+
var TCSTIcms = Object.freeze({ "cstVazio": "cstVazio", "cst00": "cst00", "cst10": "cst10", "cst20": "cst20", "cst30": "cst30", "cst40": "cst40", "cst41": "cst41", "cst45": "cst45", "cst50": "cst50", "cst51": "cst51", "cst60": "cst60", "cst70": "cst70", "cst80": "cst80", "cst81": "cst81", "cst90": "cst90", "cstICMSOutraUF": "cstICMSOutraUF", "cstICMSSN": "cstICMSSN", "cstPart10": "cstPart10", "cstPart90": "cstPart90", "cstRep41": "cstRep41", "cstRep60": "cstRep60", "cst02": "cst02", "cst15": "cst15", "cst53": "cst53", "cst61": "cst61", "cst01": "cst01", "cst12": "cst12", "cst13": "cst13", "cst14": "cst14", "cst21": "cst21", "cst72": "cst72", "cst73": "cst73", "cst74": "cst74", "cstPart20": "cstPart20" });
|
|
1930
|
+
var TCSTPis = Object.freeze({ "pis01": "pis01", "pis02": "pis02", "pis03": "pis03", "pis04": "pis04", "pis05": "pis05", "pis06": "pis06", "pis07": "pis07", "pis08": "pis08", "pis09": "pis09", "pis49": "pis49", "pis50": "pis50", "pis51": "pis51", "pis52": "pis52", "pis53": "pis53", "pis54": "pis54", "pis55": "pis55", "pis56": "pis56", "pis60": "pis60", "pis61": "pis61", "pis62": "pis62", "pis63": "pis63", "pis64": "pis64", "pis65": "pis65", "pis66": "pis66", "pis67": "pis67", "pis70": "pis70", "pis71": "pis71", "pis72": "pis72", "pis73": "pis73", "pis74": "pis74", "pis75": "pis75", "pis98": "pis98", "pis99": "pis99" });
|
|
1931
|
+
var TIndicadorEx = Object.freeze({ "tieNenhum": "tieNenhum", "tieSim": "tieSim", "tieNao": "tieNao" });
|
|
1932
|
+
var TindIEDest = Object.freeze({ "inContribuinte": "inContribuinte", "inIsento": "inIsento", "inNaoContribuinte": "inNaoContribuinte" });
|
|
1933
|
+
var TindImport = Object.freeze({ "iiNacional": "iiNacional", "iiImportado": "iiImportado" });
|
|
1934
|
+
var TindIncentivo = Object.freeze({ "iiSim": "iiSim", "iiNao": "iiNao" });
|
|
1935
|
+
var TindIntermed = Object.freeze({ "iiSemOperacao": "iiSemOperacao", "iiOperacaoSemIntermediador": "iiOperacaoSemIntermediador", "iiOperacaoComIntermediador": "iiOperacaoComIntermediador" });
|
|
1936
|
+
var TIndSomaCOFINSST = Object.freeze({ "iscNenhum": "iscNenhum", "iscCOFINSSTNaoCompoe": "iscCOFINSSTNaoCompoe", "iscCOFINSSTCompoe": "iscCOFINSSTCompoe" });
|
|
1937
|
+
var TIndSomaPISST = Object.freeze({ "ispNenhum": "ispNenhum", "ispPISSTNaoCompoe": "ispPISSTNaoCompoe", "ispPISSTCompoe": "ispPISSTCompoe" });
|
|
1938
|
+
var TmotRedAdRem = Object.freeze({ "motTranspColetivo": "motTranspColetivo", "motOutros": "motOutros" });
|
|
1939
|
+
var TOrigemMercadoria = Object.freeze({ "oeNacional": "oeNacional", "oeEstrangeiraImportacaoDireta": "oeEstrangeiraImportacaoDireta", "oeEstrangeiraAdquiridaBrasil": "oeEstrangeiraAdquiridaBrasil", "oeNacionalConteudoImportacaoSuperior40": "oeNacionalConteudoImportacaoSuperior40", "oeNacionalProcessosBasicos": "oeNacionalProcessosBasicos", "oeNacionalConteudoImportacaoInferiorIgual40": "oeNacionalConteudoImportacaoInferiorIgual40", "oeEstrangeiraImportacaoDiretaSemSimilar": "oeEstrangeiraImportacaoDiretaSemSimilar", "oeEstrangeiraAdquiridaBrasilSemSimilar": "oeEstrangeiraAdquiridaBrasilSemSimilar", "oeNacionalConteudoImportacaoSuperior70": "oeNacionalConteudoImportacaoSuperior70", "oeReservadoParaUsoFuturo": "oeReservadoParaUsoFuturo", "oeVazio": "oeVazio" });
|
|
1940
|
+
var TpcnBandeiraCartao = Object.freeze({ "bcVisa": "bcVisa", "bcMasterCard": "bcMasterCard", "bcAmericanExpress": "bcAmericanExpress", "bcSorocred": "bcSorocred", "bcDinersClub": "bcDinersClub", "bcElo": "bcElo", "bcHipercard": "bcHipercard", "bcAura": "bcAura", "bcCabal": "bcCabal", "bcAlelo": "bcAlelo", "bcBanesCard": "bcBanesCard", "bcCalCard": "bcCalCard", "bcCredz": "bcCredz", "bcDiscover": "bcDiscover", "bcGoodCard": "bcGoodCard", "bcGreenCard": "bcGreenCard", "bcHiper": "bcHiper", "bcJcB": "bcJcB", "bcMais": "bcMais", "bcMaxVan": "bcMaxVan", "bcPolicard": "bcPolicard", "bcRedeCompras": "bcRedeCompras", "bcSodexo": "bcSodexo", "bcValeCard": "bcValeCard", "bcVerocheque": "bcVerocheque", "bcVR": "bcVR", "bcTicket": "bcTicket", "bcOutros": "bcOutros" });
|
|
1941
|
+
var TpcnCondicaoVeiculo = Object.freeze({ "cvAcabado": "cvAcabado", "cvInacabado": "cvInacabado", "cvSemiAcabado": "cvSemiAcabado" });
|
|
1942
|
+
var TpcnConsumidorFinal = Object.freeze({ "cfNao": "cfNao", "cfConsumidorFinal": "cfConsumidorFinal" });
|
|
1943
|
+
var TpcnCRT = Object.freeze({ "crtSimplesNacional": "crtSimplesNacional", "crtSimplesExcessoReceita": "crtSimplesExcessoReceita", "crtRegimeNormal": "crtRegimeNormal", "crtMEI": "crtMEI" });
|
|
1944
|
+
var TpcnCstIpi = Object.freeze({ "ipi00": "ipi00", "ipi49": "ipi49", "ipi50": "ipi50", "ipi99": "ipi99", "ipi01": "ipi01", "ipi02": "ipi02", "ipi03": "ipi03", "ipi04": "ipi04", "ipi05": "ipi05", "ipi51": "ipi51", "ipi52": "ipi52", "ipi53": "ipi53", "ipi54": "ipi54", "ipi55": "ipi55" });
|
|
1945
|
+
var TpcnDestinoOperacao = Object.freeze({ "doInterna": "doInterna", "doInterestadual": "doInterestadual", "doExterior": "doExterior" });
|
|
1946
|
+
var TpcnDeterminacaoBaseIcms = Object.freeze({ "dbiMargemValorAgregado": "dbiMargemValorAgregado", "dbiPauta": "dbiPauta", "dbiPrecoTabelado": "dbiPrecoTabelado", "dbiValorOperacao": "dbiValorOperacao", "dbiNenhum": "dbiNenhum" });
|
|
1947
|
+
var TpcnDeterminacaoBaseIcmsST = Object.freeze({ "dbisPrecoTabelado": "dbisPrecoTabelado", "dbisListaNegativa": "dbisListaNegativa", "dbisListaPositiva": "dbisListaPositiva", "dbisListaNeutra": "dbisListaNeutra", "dbisMargemValorAgregado": "dbisMargemValorAgregado", "dbisPauta": "dbisPauta", "dbisValordaOperacao": "dbisValordaOperacao" });
|
|
1948
|
+
var TpcnECFModRef = Object.freeze({ "ECFModRefVazio": "ECFModRefVazio", "ECFModRef2B": "ECFModRef2B", "ECFModRef2C": "ECFModRef2C", "ECFModRef2D": "ECFModRef2D" });
|
|
1949
|
+
var TpcnFinalidadeNFe = Object.freeze({ "fnNormal": "fnNormal", "fnComplementar": "fnComplementar", "fnAjuste": "fnAjuste", "fnDevolucao": "fnDevolucao", "fnCredito": "fnCredito", "fnDebito": "fnDebito" });
|
|
1950
|
+
var TpcnFormaPagamento = Object.freeze({ "fpDinheiro": "fpDinheiro", "fpCheque": "fpCheque", "fpCartaoCredito": "fpCartaoCredito", "fpCartaoDebito": "fpCartaoDebito", "fpCreditoLoja": "fpCreditoLoja", "fpValeAlimentacao": "fpValeAlimentacao", "fpValeRefeicao": "fpValeRefeicao", "fpValePresente": "fpValePresente", "fpValeCombustivel": "fpValeCombustivel", "fpDuplicataMercantil": "fpDuplicataMercantil", "fpBoletoBancario": "fpBoletoBancario", "fpDepositoBancario": "fpDepositoBancario", "fpPagamentoInstantaneo": "fpPagamentoInstantaneo", "fpTransfBancario": "fpTransfBancario", "fpProgramaFidelidade": "fpProgramaFidelidade", "fpSemPagamento": "fpSemPagamento", "fpRegimeEspecial": "fpRegimeEspecial", "fpOutro": "fpOutro", "fpPagamentoInstantaneoEstatico": "fpPagamentoInstantaneoEstatico", "fpCreditoEmLojaPorDevolucao": "fpCreditoEmLojaPorDevolucao", "fpFalhaHardware": "fpFalhaHardware", "fpPagamentoPosterior": "fpPagamentoPosterior", "fpPagInstantaneoPIXAutomatico": "fpPagInstantaneoPIXAutomatico", "fpTEFBookTransfer": "fpTEFBookTransfer" });
|
|
1951
|
+
var TpcnIndEscala = Object.freeze({ "ieRelevante": "ieRelevante", "ieNaoRelevante": "ieNaoRelevante", "ieNenhum": "ieNenhum" });
|
|
1952
|
+
var TpcnIndicadorPagamento = Object.freeze({ "ipVista": "ipVista", "ipPrazo": "ipPrazo", "ipOutras": "ipOutras", "ipNenhum": "ipNenhum" });
|
|
1953
|
+
var TpcnIndicadorProcesso = Object.freeze({ "ipSEFAZ": "ipSEFAZ", "ipJusticaFederal": "ipJusticaFederal", "ipJusticaEstadual": "ipJusticaEstadual", "ipSecexRFB": "ipSecexRFB", "ipCONFAZ": "ipCONFAZ", "ipOutros": "ipOutros" });
|
|
1954
|
+
var TpcnIndicadorTotal = Object.freeze({ "itSomaTotalNFe": "itSomaTotalNFe", "itNaoSomaTotalNFe": "itNaoSomaTotalNFe" });
|
|
1955
|
+
var TpcnindISS = Object.freeze({ "iiExigivel": "iiExigivel", "iiNaoIncidencia": "iiNaoIncidencia", "iiIsencao": "iiIsencao", "iiExportacao": "iiExportacao", "iiImunidade": "iiImunidade", "iiExigSuspDecisaoJudicial": "iiExigSuspDecisaoJudicial", "iiExigSuspProcessoAdm": "iiExigSuspProcessoAdm" });
|
|
1956
|
+
var TpcnindISSRet = Object.freeze({ "iirSim": "iirSim", "iirNao": "iirNao" });
|
|
1957
|
+
var TpcnISSQNcSitTrib = Object.freeze({ "ISSQNcSitTribVazio": "ISSQNcSitTribVazio", "ISSQNcSitTribNORMAL": "ISSQNcSitTribNORMAL", "ISSQNcSitTribRETIDA": "ISSQNcSitTribRETIDA", "ISSQNcSitTribSUBSTITUTA": "ISSQNcSitTribSUBSTITUTA", "ISSQNcSitTribISENTA": "ISSQNcSitTribISENTA" });
|
|
1958
|
+
var TpcnModalidadeFrete = Object.freeze({ "mfContaEmitente": "mfContaEmitente", "mfContaDestinatario": "mfContaDestinatario", "mfContaTerceiros": "mfContaTerceiros", "mfProprioRemetente": "mfProprioRemetente", "mfProprioDestinatario": "mfProprioDestinatario", "mfSemFrete": "mfSemFrete" });
|
|
1959
|
+
var TpcnMotivoDesoneracaoICMS = Object.freeze({ "mdiTaxi": "mdiTaxi", "mdiDeficienteFisico": "mdiDeficienteFisico", "mdiProdutorAgropecuario": "mdiProdutorAgropecuario", "mdiFrotistaLocadora": "mdiFrotistaLocadora", "mdiDiplomaticoConsular": "mdiDiplomaticoConsular", "mdiAmazoniaLivreComercio": "mdiAmazoniaLivreComercio", "mdiSuframa": "mdiSuframa", "mdiVendaOrgaosPublicos": "mdiVendaOrgaosPublicos", "mdiOutros": "mdiOutros", "mdiDeficienteCondutor": "mdiDeficienteCondutor", "mdiDeficienteNaoCondutor": "mdiDeficienteNaoCondutor", "mdiOrgaoFomento": "mdiOrgaoFomento", "mdiOlimpiadaRio2016": "mdiOlimpiadaRio2016", "mdiSolicitadoFisco": "mdiSolicitadoFisco" });
|
|
1960
|
+
var TpcnPresencaComprador = Object.freeze({ "pcNao": "pcNao", "pcPresencial": "pcPresencial", "pcInternet": "pcInternet", "pcTeleatendimento": "pcTeleatendimento", "pcEntregaDomicilio": "pcEntregaDomicilio", "pcPresencialForaEstabelecimento": "pcPresencialForaEstabelecimento", "pcOutros": "pcOutros" });
|
|
1961
|
+
var TpcnTipoArma = Object.freeze({ "taUsoPermitido": "taUsoPermitido", "taUsoRestrito": "taUsoRestrito" });
|
|
1962
|
+
var TpcnTipoIntermedio = Object.freeze({ "tiContaPropria": "tiContaPropria", "tiContaOrdem": "tiContaOrdem", "tiEncomenda": "tiEncomenda" });
|
|
1963
|
+
var TpcnTipoOperacao = Object.freeze({ "toVendaConcessionaria": "toVendaConcessionaria", "toFaturamentoDireto": "toFaturamentoDireto", "toVendaDireta": "toVendaDireta", "toOutros": "toOutros" });
|
|
1964
|
+
var TpcnTipoViaTransp = Object.freeze({ "tvMaritima": "tvMaritima", "tvFluvial": "tvFluvial", "tvLacustre": "tvLacustre", "tvAerea": "tvAerea", "tvPostal": "tvPostal", "tvFerroviaria": "tvFerroviaria", "tvRodoviaria": "tvRodoviaria", "tvConduto": "tvConduto", "tvMeiosProprios": "tvMeiosProprios", "tvEntradaSaidaFicta": "tvEntradaSaidaFicta", "tvCourier": "tvCourier", "tvEmMaos": "tvEmMaos", "tvPorReboque": "tvPorReboque" });
|
|
1965
|
+
var TRegTribISSQN = Object.freeze({ "RTISSMicroempresaMunicipal": "RTISSMicroempresaMunicipal", "RTISSEstimativa": "RTISSEstimativa", "RTISSSociedadeProfissionais": "RTISSSociedadeProfissionais", "RTISSCooperativa": "RTISSCooperativa", "RTISSMEI": "RTISSMEI", "RTISSMEEPP": "RTISSMEEPP", "RTISSNenhum": "RTISSNenhum" });
|
|
1966
|
+
var TTipoNFe = Object.freeze({ "tnEntrada": "tnEntrada", "tnSaida": "tnSaida" });
|
|
1967
|
+
var TtpALCZFMCBS = Object.freeze({ "tpALCZFMCBSnOpInd": "tpALCZFMCBSnOpInd", "tpALCZFMCBSOpInd": "tpALCZFMCBSOpInd" });
|
|
1968
|
+
var TtpAto = Object.freeze({ "taNenhum": "taNenhum", "taTermoAcordo": "taTermoAcordo", "taRegimeEspecial": "taRegimeEspecial", "taAutorizacaoEspecifica": "taAutorizacaoEspecifica", "taAjusteSNIEF": "taAjusteSNIEF", "taConvenioICMS": "taConvenioICMS" });
|
|
1969
|
+
var TTpCredPresIBSZFM = Object.freeze({ "tcpNenhum": "tcpNenhum", "tcpSemCredito": "tcpSemCredito", "tcpBensConsumoFinal": "tcpBensConsumoFinal", "tcpBensCapital": "tcpBensCapital", "tcpBensIntermediarios": "tcpBensIntermediarios", "tcpBensInformaticaOutros": "tcpBensInformaticaOutros" });
|
|
1970
|
+
var TtpEnteGov = Object.freeze({ "tcgNenhum": "tcgNenhum", "tcgUniao": "tcgUniao", "tcgEstados": "tcgEstados", "tcgDistritoFederal": "tcgDistritoFederal", "tcgMunicipios": "tcgMunicipios", "tcgConsorcioPublico": "tcgConsorcioPublico", "tcgComiteGestorIBS": "tcgComiteGestorIBS" });
|
|
1971
|
+
var TtpGuia = Object.freeze({ "tpgNenhum": "tpgNenhum", "tpgGTA": "tpgGTA", "tpgTTA": "tpgTTA", "tpgDTA": "tpgDTA", "tpgATV": "tpgATV", "tpgPTV": "tpgPTV", "tpgGTV": "tpgGTV", "tpgGuiaFlorestal": "tpgGuiaFlorestal" });
|
|
1972
|
+
var TtpIntegra = Object.freeze({ "tiNaoInformado": "tiNaoInformado", "tiPagIntegrado": "tiPagIntegrado", "tiPagNaoIntegrado": "tiPagNaoIntegrado" });
|
|
1973
|
+
var TtpNFCredito = Object.freeze({ "tcNenhum": "tcNenhum", "tcMultaJuros": "tcMultaJuros", "tcApropriacaoCreditoPresumido": "tcApropriacaoCreditoPresumido", "tcRetorno": "tcRetorno", "tcReducaoValores": "tcReducaoValores", "tcTransferenciaCreditoSucessao": "tcTransferenciaCreditoSucessao", "tcRetornoRecusaParcial": "tcRetornoRecusaParcial" });
|
|
1974
|
+
var TtpNFDebito = Object.freeze({ "tdNenhum": "tdNenhum", "tdTransferenciaCreditoCooperativa": "tdTransferenciaCreditoCooperativa", "tdAnulacao": "tdAnulacao", "tdDebitosNaoProcessadas": "tdDebitosNaoProcessadas", "tdMultaJuros": "tdMultaJuros", "tdTransferenciaCreditoSucessao": "tdTransferenciaCreditoSucessao", "tdPagamentoAntecipado": "tdPagamentoAntecipado", "tdPerdaEmEstoque": "tdPerdaEmEstoque", "tdDesenquadramentodoSN": "tdDesenquadramentodoSN" });
|
|
1975
|
+
var TtpOperGov = Object.freeze({ "togNenhum": "togNenhum", "togFornecimento": "togFornecimento", "togRecebimentoPag": "togRecebimentoPag", "togFornecimentoPagRealizado": "togFornecimentoPagRealizado", "togRecebimentoPagFornecPosterior": "togRecebimentoPagFornecPosterior" });
|
|
1976
|
+
|
|
1977
|
+
// src/contract-help.ts
|
|
1978
|
+
var FieldHelpError = class extends Error {
|
|
1979
|
+
constructor(code, message, details) {
|
|
1980
|
+
super(message);
|
|
1981
|
+
this.code = code;
|
|
1982
|
+
this.details = details;
|
|
1983
|
+
this.name = "FieldHelpError";
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1986
|
+
var kinds = /* @__PURE__ */ new Set(["string", "integer", "decimal", "datetime", "boolean", "enum", "object", "list"]);
|
|
1987
|
+
var identifier = /^[A-Za-z_]\w*$/;
|
|
1988
|
+
var sha256 = /^[a-f0-9]{64}$/;
|
|
1989
|
+
var fail = (message = "Os metadados do contrato s\xE3o inv\xE1lidos.") => {
|
|
1990
|
+
throw new FieldHelpError("CONTRATO_INVALIDO", message);
|
|
1991
|
+
};
|
|
1992
|
+
function validateContractMetadata(value) {
|
|
1993
|
+
const metadata = value;
|
|
1994
|
+
if (!metadata || metadata.formatVersion !== 1 || !Number.isSafeInteger(metadata.sourceRevision) || metadata.sourceRevision < 1 || !sha256.test(metadata.sourceHash ?? "") || !sha256.test(metadata.contractHash ?? "") || metadata.ir?.schemaVersion !== 1 || !identifier.test(metadata.ir.root ?? "") || !Array.isArray(metadata.ir.types) || metadata.ir.types.length === 0) fail();
|
|
1995
|
+
const digest = createHash("sha256").update(JSON.stringify({ sourceRevision: metadata.sourceRevision, sourceHash: metadata.sourceHash, ir: metadata.ir })).digest("hex");
|
|
1996
|
+
if (digest !== metadata.contractHash) fail("O hash dos metadados diverge do contrato gerado.");
|
|
1997
|
+
const types = /* @__PURE__ */ new Map();
|
|
1998
|
+
for (const node of metadata.ir.types) {
|
|
1999
|
+
if (!node || typeof node.name !== "string" || !identifier.test(node.name) || types.has(node.name) || !["object", "list", "enum"].includes(node.kind)) fail();
|
|
2000
|
+
types.set(node.name, node);
|
|
2001
|
+
}
|
|
2002
|
+
if (types.get(metadata.ir.root)?.kind !== "object") fail();
|
|
2003
|
+
for (const node of types.values()) {
|
|
2004
|
+
if (node.kind === "enum") {
|
|
2005
|
+
if (!Array.isArray(node.values) || node.values.length === 0 || node.values.some((v) => typeof v !== "string" || !identifier.test(v)) || new Set(node.values).size !== node.values.length) fail();
|
|
2006
|
+
} else if (node.kind === "list") {
|
|
2007
|
+
if (!node.item || types.get(node.item)?.kind !== "object") fail();
|
|
2008
|
+
} else {
|
|
2009
|
+
if (!Array.isArray(node.properties)) fail();
|
|
2010
|
+
const names = /* @__PURE__ */ new Set();
|
|
2011
|
+
for (const property of node.properties) {
|
|
2012
|
+
if (!property || typeof property.name !== "string" || !identifier.test(property.name) || names.has(property.name.toLowerCase()) || !kinds.has(property.kind) || typeof property.type !== "string" || typeof property.readonly !== "boolean") fail();
|
|
2013
|
+
names.add(property.name.toLowerCase());
|
|
2014
|
+
if (["object", "list", "enum"].includes(property.kind) && (!property.ref || types.get(property.ref)?.kind !== property.kind)) fail();
|
|
2015
|
+
if (!["object", "list", "enum"].includes(property.kind) && property.ref !== void 0) fail();
|
|
2016
|
+
if (property.declaredDefault !== void 0 && typeof property.declaredDefault !== "string") fail();
|
|
2017
|
+
for (const key of ["min", "max", "scale"]) if (property[key] !== void 0 && !Number.isFinite(property[key])) fail();
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
return metadata;
|
|
2022
|
+
}
|
|
2023
|
+
function matchingPaths(types, root, field) {
|
|
2024
|
+
const paths = [];
|
|
2025
|
+
let incomplete = false;
|
|
2026
|
+
function visit(name, prefix, trail) {
|
|
2027
|
+
if (trail.has(name) || trail.size > 128 || paths.length > 1e3) {
|
|
2028
|
+
incomplete = true;
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
2031
|
+
const node = types.get(name);
|
|
2032
|
+
const next = new Set(trail).add(name);
|
|
2033
|
+
if (node.kind === "list") {
|
|
2034
|
+
visit(node.item, prefix + "[]", next);
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
if (node.kind !== "object") return;
|
|
2038
|
+
for (const property of node.properties) {
|
|
2039
|
+
const candidate = prefix ? prefix + "." + property.name : property.name;
|
|
2040
|
+
if (property.name === field) paths.push(candidate);
|
|
2041
|
+
if (property.ref && property.kind !== "enum") visit(property.ref, candidate, next);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
visit(root, "", /* @__PURE__ */ new Set());
|
|
2045
|
+
if (incomplete) throw new FieldHelpError("CAMINHO_COMPLETO_NECESSARIO", "O contrato cont\xE9m caminhos recursivos ou extensos. Informe o caminho completo.");
|
|
2046
|
+
return paths.sort();
|
|
2047
|
+
}
|
|
2048
|
+
function describeField(metadata, sdkVersion, query) {
|
|
2049
|
+
validateContractMetadata(metadata);
|
|
2050
|
+
if (typeof query !== "string" || query.length > 512 || !/^[A-Za-z_]\w*(?:\[(?:\d*)\])?(?:\.[A-Za-z_]\w*(?:\[(?:\d*)\])?)*$/.test(query))
|
|
2051
|
+
throw new FieldHelpError("CAMINHO_INVALIDO", "Use nomes de campos separados por ponto e [] para elementos de cole\xE7\xE3o.");
|
|
2052
|
+
const types = new Map(metadata.ir.types.map((node2) => [node2.name, node2]));
|
|
2053
|
+
const root = metadata.ir.root;
|
|
2054
|
+
const base = { formatVersion: 1, sdkVersion, sourceRevision: metadata.sourceRevision, sourceHash: metadata.sourceHash, contractHash: metadata.contractHash, root };
|
|
2055
|
+
let relative3 = query === root ? "" : query.startsWith(root + ".") ? query.slice(root.length + 1) : query;
|
|
2056
|
+
if (identifier.test(relative3) && !types.get(root).properties.some((property2) => property2.name === relative3)) {
|
|
2057
|
+
const matches = matchingPaths(types, root, relative3);
|
|
2058
|
+
if (matches.length > 1) throw new FieldHelpError("CAMPO_AMBIGUO", "O nome aparece em mais de um caminho. Informe o caminho completo.", { candidates: matches });
|
|
2059
|
+
if (matches.length === 1) relative3 = matches[0];
|
|
2060
|
+
}
|
|
2061
|
+
let node = types.get(root);
|
|
2062
|
+
let property;
|
|
2063
|
+
let readonly = false;
|
|
2064
|
+
const canonical = [];
|
|
2065
|
+
const parts = relative3 ? relative3.split(".") : [];
|
|
2066
|
+
for (let index = 0; index < parts.length; index++) {
|
|
2067
|
+
const segment = parts[index];
|
|
2068
|
+
const parsed = /^([A-Za-z_]\w*)(\[(?:\d*)\])?$/.exec(segment);
|
|
2069
|
+
if (node.kind !== "object") throw new FieldHelpError("CAMINHO_INVALIDO", "O caminho tenta acessar um campo de um valor simples.");
|
|
2070
|
+
property = node.properties.find((item) => item.name === parsed[1]);
|
|
2071
|
+
if (!property) throw new FieldHelpError("CAMPO_INEXISTENTE", "O campo n\xE3o existe nesse objeto do contrato.", { segment: parsed[1], ownerType: node.name, candidates: node.properties.map((item) => item.name) });
|
|
2072
|
+
readonly ||= property.readonly;
|
|
2073
|
+
canonical.push(property.name);
|
|
2074
|
+
const selected = parsed[2] !== void 0;
|
|
2075
|
+
if (selected && property.kind !== "list") throw new FieldHelpError("CAMPO_NAO_COLECAO", "[] ou \xEDndice foi usado em um campo que n\xE3o \xE9 cole\xE7\xE3o.");
|
|
2076
|
+
if (property.kind === "list") {
|
|
2077
|
+
node = types.get(property.ref);
|
|
2078
|
+
if (selected) {
|
|
2079
|
+
canonical[canonical.length - 1] += "[]";
|
|
2080
|
+
node = types.get(node.item);
|
|
2081
|
+
} else if (index < parts.length - 1) throw new FieldHelpError("COLECAO_REQUER_INDICE", "Use [] ou um \xEDndice para consultar campos do elemento da cole\xE7\xE3o.");
|
|
2082
|
+
} else if (property.ref) node = types.get(property.ref);
|
|
2083
|
+
else if (index < parts.length - 1) throw new FieldHelpError("CAMINHO_INVALIDO", "Um valor simples n\xE3o cont\xE9m outros campos.");
|
|
2084
|
+
}
|
|
2085
|
+
const selectedListItem = property?.kind === "list" && canonical[canonical.length - 1]?.endsWith("[]");
|
|
2086
|
+
const kind = selectedListItem ? "object" : property?.kind ?? "object";
|
|
2087
|
+
const description = {
|
|
2088
|
+
...base,
|
|
2089
|
+
path: [root, ...canonical].join("."),
|
|
2090
|
+
kind,
|
|
2091
|
+
pascalType: selectedListItem ? node.name : property?.type ?? node.name,
|
|
2092
|
+
inputType: kind === "integer" ? "number" : kind === "boolean" ? "boolean" : kind === "object" ? "object" : kind === "list" ? "array" : "string",
|
|
2093
|
+
readonly
|
|
2094
|
+
};
|
|
2095
|
+
if (property?.declaredDefault !== void 0) description.declaredDefault = property.declaredDefault;
|
|
2096
|
+
if (property?.ref) description.typeReference = selectedListItem ? node.name : property.ref;
|
|
2097
|
+
if (kind === "enum") description.values = [...node.values];
|
|
2098
|
+
const constraints = property && Object.fromEntries(["min", "max", "scale"].filter((key) => property[key] !== void 0).map((key) => [key, property[key]]));
|
|
2099
|
+
if (constraints && Object.keys(constraints).length) description.constraints = constraints;
|
|
2100
|
+
if (kind === "list") description.itemType = node.item;
|
|
2101
|
+
if (kind === "object") description.members = node.properties.map((item) => ({ name: item.name, kind: item.kind, pascalType: item.type, readonly: readonly || item.readonly }));
|
|
2102
|
+
return description;
|
|
2103
|
+
}
|
|
2104
|
+
async function describeInstalledField(query, packageRoot) {
|
|
2105
|
+
let metadata, pkg, lock;
|
|
2106
|
+
try {
|
|
2107
|
+
[metadata, pkg, lock] = await Promise.all(["dist/contract.json", "package.json", "acbr.lock.json"].map(async (filename) => JSON.parse(await readFile(path.join(packageRoot, filename), "utf8"))));
|
|
2108
|
+
} catch {
|
|
2109
|
+
throw new FieldHelpError("CONTRATO_INDISPONIVEL", "Os metadados empacotados n\xE3o est\xE3o dispon\xEDveis. Reinstale o pacote ou gere e compile o checkout.");
|
|
2110
|
+
}
|
|
2111
|
+
validateContractMetadata(metadata);
|
|
2112
|
+
if (typeof pkg.version !== "string" || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(pkg.version) || metadata.sourceRevision !== lock.source?.revision || metadata.sourceHash !== lock.source?.treeHash || metadata.sourceRevision !== ACBR_CONTRACT.sourceRevision || metadata.contractHash !== ACBR_CONTRACT.contractHash)
|
|
2113
|
+
throw new FieldHelpError("CONTRATO_INCOMPATIVEL", "Os metadados divergem da vers\xE3o instalada, do lock ou do validador gerado.");
|
|
2114
|
+
return describeField(metadata, pkg.version, query);
|
|
2115
|
+
}
|
|
2116
|
+
function formatFieldDescription(description) {
|
|
2117
|
+
const lines = [
|
|
2118
|
+
description.path,
|
|
2119
|
+
`Tipo: ${description.pascalType}${description.typeReference && description.typeReference !== description.pascalType ? ` [${description.typeReference}]` : ""} (${description.kind}; entrada ${description.inputType})`,
|
|
2120
|
+
`Somente leitura: ${description.readonly ? "sim" : "n\xE3o"}`
|
|
2121
|
+
];
|
|
2122
|
+
if (description.values) lines.push(`Valores permitidos na API: ${description.values.join(", ")}`);
|
|
2123
|
+
if (description.declaredDefault !== void 0) lines.push(`Padr\xE3o declarado no Pascal: ${description.declaredDefault} (n\xE3o substitui regras fiscais ou o construtor nativo).`);
|
|
2124
|
+
if (description.constraints) lines.push(`Limites do tipo: ${JSON.stringify(description.constraints)}`);
|
|
2125
|
+
if (description.itemType) lines.push(`Tipo do elemento: ${description.itemType}`);
|
|
2126
|
+
if (description.members) lines.push(`Campos: ${description.members.map((member) => member.name).join(", ")}`);
|
|
2127
|
+
lines.push(`SDK: ${description.sdkVersion}; revis\xE3o ACBr: ${description.sourceRevision}`, `Contrato: ${description.contractHash}`);
|
|
2128
|
+
return lines.join("\n");
|
|
2129
|
+
}
|
|
1793
2130
|
|
|
1794
2131
|
// src/cli.ts
|
|
1795
2132
|
var HELP = `acbr-node \u2014 compila\xE7\xE3o e contrato Node/ACBr NF-e
|
|
1796
2133
|
|
|
1797
2134
|
Uso:
|
|
2135
|
+
acbr-node help TAG Ide.tpNF [--json]
|
|
2136
|
+
acbr-node help TAG 'Det[].Imposto.PIS.CST' [--json]
|
|
1798
2137
|
acbr-node init [--config caminho] [--revision HEAD|n\xFAmero]
|
|
1799
2138
|
acbr-node source update [--config caminho] [--revision HEAD|n\xFAmero]
|
|
1800
2139
|
acbr-node source lock --revision n\xFAmero [--config caminho]
|
|
@@ -1806,6 +2145,7 @@ Uso:
|
|
|
1806
2145
|
source update consulta o SVN oficial e substitui apenas fontes verificadas pelo lock.
|
|
1807
2146
|
source lock registra um export existente cuja origem/revis\xE3o o operador j\xE1 conferiu.
|
|
1808
2147
|
generate/build/check nunca atualizam fontes. Nenhum comando transmite NF-e.
|
|
2148
|
+
help TAG consulta somente o contrato da vers\xE3o instalada, offline e sem runtime ou certificado.
|
|
1809
2149
|
`;
|
|
1810
2150
|
function revision(value) {
|
|
1811
2151
|
if (value === void 0) return void 0;
|
|
@@ -1835,9 +2175,17 @@ function parseArguments(args) {
|
|
|
1835
2175
|
}
|
|
1836
2176
|
return result;
|
|
1837
2177
|
}
|
|
1838
|
-
async function main(args = process.argv.slice(2), io = process) {
|
|
2178
|
+
async function main(args = process.argv.slice(2), io = process, dependencies = {}) {
|
|
2179
|
+
const initialCommand = args.filter((arg) => !["--json", "--help", "-h"].includes(arg));
|
|
2180
|
+
let jsonTag = args.includes("--json") && initialCommand[0]?.toLowerCase() === "help" && initialCommand[1]?.toLowerCase() === "tag";
|
|
1839
2181
|
try {
|
|
1840
|
-
|
|
2182
|
+
let options;
|
|
2183
|
+
try {
|
|
2184
|
+
options = parseArguments(args);
|
|
2185
|
+
} catch (error) {
|
|
2186
|
+
if (jsonTag) throw new FieldHelpError("USO_INVALIDO", "Argumentos inv\xE1lidos. Use acbr-node help TAG caminho [--json].");
|
|
2187
|
+
throw error;
|
|
2188
|
+
}
|
|
1841
2189
|
const command = options.command.join(" ");
|
|
1842
2190
|
if (options.help || !command) {
|
|
1843
2191
|
io.stdout.write(HELP);
|
|
@@ -1846,8 +2194,17 @@ async function main(args = process.argv.slice(2), io = process) {
|
|
|
1846
2194
|
const output = (value, text) => io.stdout.write(options.json ? `${JSON.stringify(value, null, 2)}
|
|
1847
2195
|
` : `${text}
|
|
1848
2196
|
`);
|
|
2197
|
+
if (options.command[0]?.toLowerCase() === "help" && options.command[1]?.toLowerCase() === "tag") {
|
|
2198
|
+
jsonTag = options.json;
|
|
2199
|
+
if (options.command.length !== 3) throw new FieldHelpError("USO_INVALIDO", "Use acbr-node help TAG caminho [--json].");
|
|
2200
|
+
if (options.revision !== void 0 || args.includes("--config")) throw new FieldHelpError("USO_INVALIDO", "help TAG usa o contrato instalado e n\xE3o aceita --config ou --revision.");
|
|
2201
|
+
const description = await describeInstalledField(options.command[2], dependencies.contractRoot ?? fileURLToPath3(new URL("../", import.meta.url)));
|
|
2202
|
+
output(description, formatFieldDescription(description));
|
|
2203
|
+
return 0;
|
|
2204
|
+
}
|
|
1849
2205
|
if (command === "init") {
|
|
1850
|
-
const
|
|
2206
|
+
const { initializeConfig: initializeConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2207
|
+
const config2 = await initializeConfig2(options.config, options.revision, fileURLToPath3(new URL("../", import.meta.url)));
|
|
1851
2208
|
output({ configPath: config2.configPath }, `Configura\xE7\xE3o criada: ${config2.configPath}
|
|
1852
2209
|
Pr\xF3ximo passo: acbr-node source update.`);
|
|
1853
2210
|
return 0;
|
|
@@ -1855,46 +2212,61 @@ Pr\xF3ximo passo: acbr-node source update.`);
|
|
|
1855
2212
|
if (!["source update", "source lock", "generate", "build", "check", "doctor"].includes(command)) throw new Error(`Comando desconhecido: ${command}. Use --help.`);
|
|
1856
2213
|
if (options.revision !== void 0 && !command.startsWith("source ")) throw new Error("--revision \xE9 aceito somente em init e source.");
|
|
1857
2214
|
if (command === "doctor") {
|
|
2215
|
+
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2216
|
+
const { doctor: doctor2 } = await Promise.resolve().then(() => (init_native_build(), native_build_exports));
|
|
1858
2217
|
let config2;
|
|
1859
2218
|
try {
|
|
1860
2219
|
await access4(resolve4(options.config));
|
|
1861
|
-
config2 = await
|
|
2220
|
+
config2 = await loadConfig3(options.config);
|
|
1862
2221
|
} catch (error) {
|
|
1863
2222
|
if (error.code !== "ENOENT") throw error;
|
|
1864
2223
|
}
|
|
1865
|
-
const report = await
|
|
2224
|
+
const report = await doctor2(config2);
|
|
1866
2225
|
output(report, report.map((item) => `${item.ok ? "OK" : "FALHA"} ${item.name}: ${item.detail}`).join("\n"));
|
|
1867
2226
|
return report.every((item) => item.ok) ? 0 : 1;
|
|
1868
2227
|
}
|
|
1869
|
-
const
|
|
2228
|
+
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2229
|
+
const config = await loadConfig2(options.config);
|
|
1870
2230
|
if (command === "source update") {
|
|
1871
|
-
const
|
|
2231
|
+
const { updateSource: updateSource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
2232
|
+
const lock = await updateSource2(config, options.revision);
|
|
1872
2233
|
output(lock, `Fontes oficiais registradas na revis\xE3o ${lock.source.revision}.
|
|
1873
2234
|
SHA256 da \xE1rvore: ${lock.source.treeHash}
|
|
1874
2235
|
Execute generate para atualizar o contrato.`);
|
|
1875
2236
|
} else if (command === "source lock") {
|
|
2237
|
+
const { lockExistingSource: lockExistingSource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
1876
2238
|
if (typeof options.revision !== "number") throw new Error("source lock exige --revision com o n\xFAmero verificado do export SVN.");
|
|
1877
2239
|
if (config.source.revision !== "HEAD" && config.source.revision !== options.revision) throw new Error("Revis\xE3o do export diverge da configura\xE7\xE3o.");
|
|
1878
|
-
const lock = await
|
|
2240
|
+
const lock = await lockExistingSource2(config, options.revision);
|
|
1879
2241
|
output(lock, `Export existente registrado na revis\xE3o ${lock.source.revision}; ${Object.keys(lock.source.files).length} arquivos protegidos por SHA256.`);
|
|
1880
2242
|
} else if (command === "generate") {
|
|
1881
|
-
const
|
|
2243
|
+
const { verifySource: verifySource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
2244
|
+
const lock = await verifySource2(config);
|
|
1882
2245
|
const { generateModel: generateModel2 } = await Promise.resolve().then(() => (init_generator(), generator_exports));
|
|
1883
2246
|
const result = await generateModel2({ acbrRoot: config.source.directory, outputDir: config.generator.outputDir, revision: String(lock.source.revision), sourceHash: lock.source.treeHash, fpcPath: config.native.fpc });
|
|
1884
2247
|
output(result, `Contrato ${result.contractHash}; ${result.models} modelos gerados.
|
|
1885
2248
|
Revise o relat\xF3rio: ${result.reportPath}`);
|
|
1886
2249
|
} else if (command === "build") {
|
|
1887
|
-
const
|
|
1888
|
-
|
|
2250
|
+
const { buildNative: buildNative2, runtimeDirectory: runtimeDirectory2 } = await Promise.resolve().then(() => (init_native_build(), native_build_exports));
|
|
2251
|
+
const result = await buildNative2(config);
|
|
2252
|
+
output(result, `Runtime compilado: ${runtimeDirectory2(config)}
|
|
1889
2253
|
ACBr revis\xE3o ${result.sourceRevision}; contrato ${result.contractHash}.`);
|
|
1890
2254
|
} else {
|
|
1891
|
-
const
|
|
1892
|
-
const
|
|
2255
|
+
const { checkBuild: checkBuild2 } = await Promise.resolve().then(() => (init_native_build(), native_build_exports));
|
|
2256
|
+
const { checkOffline: checkOffline2 } = await Promise.resolve().then(() => (init_offline_check(), offline_check_exports));
|
|
2257
|
+
const result = await checkBuild2(config);
|
|
2258
|
+
const offlineChecks = await checkOffline2(config, result);
|
|
1893
2259
|
output({ ...result, offlineChecks }, `Fontes, contrato e ${Object.keys(result.files).length} arquivos do runtime conferidos por SHA256.
|
|
1894
2260
|
${offlineChecks.length} verifica\xE7\xF5es offline do motor aprovadas; nenhuma transmiss\xE3o.`);
|
|
1895
2261
|
}
|
|
1896
2262
|
return 0;
|
|
1897
2263
|
} catch (error) {
|
|
2264
|
+
if (jsonTag) {
|
|
2265
|
+
const problem = error instanceof FieldHelpError ? { code: error.code, message: error.message, ...error.details } : { code: "HELP_INDISPONIVEL", message: "N\xE3o foi poss\xEDvel consultar o contrato instalado." };
|
|
2266
|
+
io.stderr.write(`${JSON.stringify({ ok: false, error: problem }, null, 2)}
|
|
2267
|
+
`);
|
|
2268
|
+
return 1;
|
|
2269
|
+
}
|
|
1898
2270
|
io.stderr.write(`Erro: ${error.message}
|
|
1899
2271
|
`);
|
|
1900
2272
|
return 1;
|