cosmemilton-acbr-node 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -106
- package/dist/cli.js +1310 -964
- package/dist/cli.js.map +4 -4
- package/dist/contract.json +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/types/generated/acbr/index.d.ts +2 -2
- package/dist/types/src/cli.d.ts +4 -2
- package/dist/types/src/contract-help.d.ts +53 -0
- package/dist/types/src/generator.d.ts +2 -0
- package/dist/types/src/index.d.ts +2 -2
- package/docs/API.md +90 -90
- package/docs/CLI.md +52 -32
- package/package.json +6 -4
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");
|
|
@@ -1046,146 +683,497 @@ async function replaceRuntime(stage, target) {
|
|
|
1046
683
|
if (hadTarget) await rename2(backup, target);
|
|
1047
684
|
throw error;
|
|
1048
685
|
}
|
|
1049
|
-
if (hadTarget) await rm2(backup, { recursive: true, force: true });
|
|
686
|
+
if (hadTarget) await rm2(backup, { recursive: true, force: true });
|
|
687
|
+
}
|
|
688
|
+
async function checkBuild(config) {
|
|
689
|
+
const lock = await verifySource(config);
|
|
690
|
+
const generated = await generatedManifest(config);
|
|
691
|
+
const directory = runtimeDirectory(config);
|
|
692
|
+
const manifest = JSON.parse(await readFile4(join2(directory, "manifest.json"), "utf8"));
|
|
693
|
+
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) || typeof manifest.executable !== "string" || !manifest.files || !Object.hasOwn(manifest.files, manifest.executable)) throw new Error("Runtime diverge das fontes ou contrato. Execute build.");
|
|
694
|
+
for (const [path4, expected] of Object.entries(manifest.files)) {
|
|
695
|
+
if (path4.startsWith("/") || path4.includes("\\") || path4.split("/").includes("..") || !/^[a-f0-9]{64}$/.test(expected)) throw new Error(`Caminho/hash inv\xE1lido no runtime: ${path4}.`);
|
|
696
|
+
if (await fileHash(join2(directory, path4)) !== expected) throw new Error(`Hash inv\xE1lido no runtime: ${path4}.`);
|
|
697
|
+
}
|
|
698
|
+
return manifest;
|
|
699
|
+
}
|
|
700
|
+
async function doctor(config) {
|
|
701
|
+
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 }];
|
|
702
|
+
for (const [name, command, args] of [["SVN", "svn", ["--version", "--quiet"]], ["Free Pascal", config?.native.fpc ?? "fpc", ["-iV"]]]) {
|
|
703
|
+
try {
|
|
704
|
+
const result = await runCommand(command, [...args]);
|
|
705
|
+
items.push({ name, ok: true, detail: result.stdout.trim() });
|
|
706
|
+
} catch (error) {
|
|
707
|
+
items.push({ name, ok: false, detail: error.message });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
if (config) {
|
|
711
|
+
try {
|
|
712
|
+
items.push({ name: "Lazarus", ok: true, detail: await findLazarus(config) });
|
|
713
|
+
} catch (error) {
|
|
714
|
+
items.push({ name: "Lazarus", ok: false, detail: error.message });
|
|
715
|
+
}
|
|
716
|
+
try {
|
|
717
|
+
const lock = await verifySource(config);
|
|
718
|
+
items.push({ name: "Fontes ACBr", ok: true, detail: `revis\xE3o ${lock.source.revision}, ${lock.source.treeHash}` });
|
|
719
|
+
} catch (error) {
|
|
720
|
+
items.push({ name: "Fontes ACBr", ok: false, detail: error.message });
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
if (process.platform === "linux") {
|
|
724
|
+
try {
|
|
725
|
+
const result = await runCommand("ldconfig", ["-p"]);
|
|
726
|
+
const missing = REQUIRED_DYNAMIC.filter((name) => !result.stdout.includes(name));
|
|
727
|
+
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: missing.length === 0, detail: missing.length ? `Ausentes: ${missing.join(", ")}` : REQUIRED_DYNAMIC.join(", ") });
|
|
728
|
+
} catch (error) {
|
|
729
|
+
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: false, detail: error.message });
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return items;
|
|
733
|
+
}
|
|
734
|
+
async function copyCompilerLicenses(config, stage, lazarus) {
|
|
735
|
+
const packagedLazarus = fileURLToPath(new URL("../docs/licenses/lazarus/", import.meta.url));
|
|
736
|
+
const packagedFpc = fileURLToPath(new URL("../docs/licenses/fpc/", import.meta.url));
|
|
737
|
+
const notices = {};
|
|
738
|
+
async function copyNotice(name, candidates2) {
|
|
739
|
+
for (const source of candidates2) if (await exists(source)) {
|
|
740
|
+
await copyFile2(source, join2(stage, "licenses", name));
|
|
741
|
+
notices[name] = { source, sha256: await fileHash(source) };
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
throw new Error(`Notice obrigat\xF3rio ausente: ${name}.`);
|
|
745
|
+
}
|
|
746
|
+
for (const name of ["COPYING.txt", "COPYING.LGPL.txt", "COPYING.modifiedLGPL.txt"]) {
|
|
747
|
+
await copyNotice(`Lazarus-${name}`, [join2(lazarus, name), join2(lazarus, "docs", name), join2(packagedLazarus, name)]);
|
|
748
|
+
}
|
|
749
|
+
if (await exists(join2(packagedLazarus, "ORIGIN.json"))) await copyFile2(join2(packagedLazarus, "ORIGIN.json"), join2(stage, "licenses/Lazarus-notice-origin.json"));
|
|
750
|
+
const fpcRoot = resolve3(dirname3(config.native.fpc), "../..");
|
|
751
|
+
const sourceRoots = [join2(fpcRoot, "source"), join2(lazarus, "fpc/3.2.2/source"), "/usr/share/fpcsrc/3.2.2"];
|
|
752
|
+
for (const [name, sourceRelative] of [["COPYING.GPL.txt", "compiler/COPYING.txt"], ["COPYING.LGPL.txt", "rtl/COPYING.txt"], ["COPYING.FPC", "rtl/COPYING.FPC"]]) {
|
|
753
|
+
await copyNotice(`FPC-${name}`, [...sourceRoots.map((directory) => join2(directory, sourceRelative)), join2(packagedFpc, name)]);
|
|
754
|
+
}
|
|
755
|
+
if (await exists(join2(packagedFpc, "ORIGIN.json"))) await copyFile2(join2(packagedFpc, "ORIGIN.json"), join2(stage, "licenses/FPC-notice-origin.json"));
|
|
756
|
+
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"];
|
|
757
|
+
for (const directory of candidates) {
|
|
758
|
+
if (!await exists(directory)) continue;
|
|
759
|
+
for (const name of await readdir3(directory)) {
|
|
760
|
+
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}`));
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
await writeFile3(join2(stage, "licenses/toolchain-notices.json"), `${JSON.stringify(notices, null, 2)}
|
|
764
|
+
`);
|
|
765
|
+
}
|
|
766
|
+
var REQUIRED_DYNAMIC, CORE_SYSTEM;
|
|
767
|
+
var init_native_build = __esm({
|
|
768
|
+
"src/native-build.ts"() {
|
|
769
|
+
"use strict";
|
|
770
|
+
init_source();
|
|
771
|
+
REQUIRED_DYNAMIC = ["libssl.so.3", "libcrypto.so.3", "libxml2.so.2"];
|
|
772
|
+
CORE_SYSTEM = /^(?:lib(?:c|m|pthread|dl|rt|resolv|anl|util)\.so(?:\.|$)|ld-linux|linux-vdso)/;
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
// src/generator.ts
|
|
777
|
+
var generator_exports = {};
|
|
778
|
+
__export(generator_exports, {
|
|
779
|
+
buildModelIR: () => buildModelIR,
|
|
780
|
+
compareContracts: () => compareContracts,
|
|
781
|
+
generateModel: () => generateModel,
|
|
782
|
+
renderClientIndex: () => renderClientIndex,
|
|
783
|
+
renderContractMetadata: () => renderContractMetadata,
|
|
784
|
+
renderModelValidation: () => renderModelValidation,
|
|
785
|
+
renderPascal: () => renderPascal,
|
|
786
|
+
renderTypeScript: () => renderTypeScript
|
|
787
|
+
});
|
|
788
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
789
|
+
import { execFile } from "node:child_process";
|
|
790
|
+
import { promisify } from "node:util";
|
|
791
|
+
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4, readdir as readdir4 } from "node:fs/promises";
|
|
792
|
+
import path2 from "node:path";
|
|
793
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
794
|
+
function buildModelIR(raw) {
|
|
795
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
796
|
+
for (const unit of raw.units) for (const type of unit.types) declarations.set((unit.name + "." + type.name).toLowerCase(), { unit, type });
|
|
797
|
+
function find(name, unit) {
|
|
798
|
+
for (const key of [unit.name + "." + name, ...[...unit.uses].reverse().map((u) => u + "." + name), name]) {
|
|
799
|
+
const item = declarations.get(key.toLowerCase());
|
|
800
|
+
if (item) return item;
|
|
801
|
+
}
|
|
802
|
+
throw new Error("Tipo Pascal n\xE3o resolvido: " + unit.name + "." + name);
|
|
803
|
+
}
|
|
804
|
+
function resolve5(name, unit, trail = /* @__PURE__ */ new Set()) {
|
|
805
|
+
if (primitives[name.toLowerCase()]) return { primitive: name.toLowerCase() };
|
|
806
|
+
const found = find(name, unit), key = (found.unit.name + "." + found.type.name).toLowerCase();
|
|
807
|
+
if (trail.has(key)) throw new Error("Alias Pascal c\xEDclico: " + key);
|
|
808
|
+
if (found.type.kind === "alias") {
|
|
809
|
+
trail.add(key);
|
|
810
|
+
return resolve5(found.type.target, found.unit, trail);
|
|
811
|
+
}
|
|
812
|
+
return found;
|
|
813
|
+
}
|
|
814
|
+
const rootUnit = raw.units.find((u) => u.types.some((t) => t.name === raw.root));
|
|
815
|
+
if (!rootUnit) throw new Error("Modelo raiz ausente: " + raw.root);
|
|
816
|
+
const generated = /* @__PURE__ */ new Map();
|
|
817
|
+
function visit(name, unit) {
|
|
818
|
+
const found = resolve5(name, unit);
|
|
819
|
+
if ("primitive" in found) return primitives[found.primitive];
|
|
820
|
+
const { type, unit: declUnit } = found, key = type.name;
|
|
821
|
+
if (generated.has(key)) {
|
|
822
|
+
const node2 = generated.get(key);
|
|
823
|
+
if (node2.unit !== declUnit.name) throw new Error("Tipos hom\xF4nimos incompat\xEDveis: " + key);
|
|
824
|
+
return { kind: node2.kind === "object" ? "object" : node2.kind === "list" ? "list" : "enum", ref: key };
|
|
825
|
+
}
|
|
826
|
+
if (type.kind === "enum") {
|
|
827
|
+
const values = type.values.map((v) => v.name);
|
|
828
|
+
if (!values.length) throw new Error("Enum sem valores: " + key);
|
|
829
|
+
generated.set(key, { name: key, unit: declUnit.name, kind: "enum", values });
|
|
830
|
+
return { kind: "enum", ref: key };
|
|
831
|
+
}
|
|
832
|
+
if (type.kind !== "class") throw new Error("Declara\xE7\xE3o Pascal n\xE3o suportada: " + declUnit.name + "." + key + " (" + (type.declarationKind ?? type.kind) + ")");
|
|
833
|
+
const creator = type.methods?.find((m) => m.name.toLowerCase() === "new" && m.arguments === 0);
|
|
834
|
+
const indexed = type.properties?.find((p) => p.indexed && p.name.toLowerCase() === "items");
|
|
835
|
+
if (creator || indexed) {
|
|
836
|
+
if (!creator || !indexed || !indexed.readable) throw new Error("Cole\xE7\xE3o sem contrato New/Items tipado: " + key);
|
|
837
|
+
const item = resolve5(creator.result, declUnit), itemProperty = resolve5(indexed.type, declUnit);
|
|
838
|
+
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);
|
|
839
|
+
generated.set(key, { name: key, unit: declUnit.name, kind: "list", item: item.type.name, factory: creator.name });
|
|
840
|
+
if (visit(creator.result, declUnit).kind !== "object") throw new Error("Item de cole\xE7\xE3o n\xE3o \xE9 objeto: " + key);
|
|
841
|
+
return { kind: "list", ref: key };
|
|
842
|
+
}
|
|
843
|
+
const node = { name: key, unit: declUnit.name, kind: "object", properties: [] };
|
|
844
|
+
generated.set(key, node);
|
|
845
|
+
let inherited = [];
|
|
846
|
+
if (type.ancestor && !bases.has(type.ancestor.toLowerCase())) {
|
|
847
|
+
const ancestor = visit(type.ancestor, declUnit);
|
|
848
|
+
if (ancestor.kind !== "object") throw new Error("Heran\xE7a n\xE3o suportada: " + key);
|
|
849
|
+
inherited = generated.get(ancestor.ref).properties;
|
|
850
|
+
}
|
|
851
|
+
const props = new Map(inherited.map((p) => [p.name.toLowerCase(), p]));
|
|
852
|
+
for (const p of type.properties ?? []) {
|
|
853
|
+
if (p.indexed) throw new Error("Propriedade indexada fora de cole\xE7\xE3o: " + key + "." + p.name);
|
|
854
|
+
if (!p.readable) throw new Error("Propriedade sem leitura: " + key + "." + p.name);
|
|
855
|
+
const resolved = visit(p.type, declUnit);
|
|
856
|
+
const readonly = !p.writable && !["object", "list"].includes(resolved.kind) || key === raw.root && ["signature", "procnfe", "infnfesupl"].includes(p.name.toLowerCase());
|
|
857
|
+
props.set(p.name.toLowerCase(), { name: p.name, type: p.type, ...resolved, readonly, ...p.default ? { declaredDefault: p.default } : {} });
|
|
858
|
+
}
|
|
859
|
+
node.properties = [...props.values()].sort((a, b) => a.name.localeCompare(b.name, "en"));
|
|
860
|
+
return { kind: "object", ref: key };
|
|
861
|
+
}
|
|
862
|
+
visit(raw.root, rootUnit);
|
|
863
|
+
return { schemaVersion: 1, root: raw.root, types: [...generated.values()].sort((a, b) => a.name.localeCompare(b.name, "en")) };
|
|
864
|
+
}
|
|
865
|
+
function compareContracts(previous, current) {
|
|
866
|
+
const old = new Map(previous?.types.map((t) => [t.name, t]) ?? []), now = new Map(current.types.map((t) => [t.name, t]));
|
|
867
|
+
const additions = [], removals = [], changes = [];
|
|
868
|
+
for (const [name, type] of now) {
|
|
869
|
+
const before = old.get(name);
|
|
870
|
+
if (!before) {
|
|
871
|
+
additions.push(name);
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
if (type.kind !== before.kind) {
|
|
875
|
+
changes.push(name + ":kind");
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
if (type.kind === "object") {
|
|
879
|
+
const a = new Map(before.properties.map((p) => [p.name, p])), b = new Map(type.properties.map((p) => [p.name, p]));
|
|
880
|
+
for (const [field, p] of b) {
|
|
881
|
+
if (!a.has(field)) additions.push(name + "." + field);
|
|
882
|
+
else if (stable(a.get(field)) !== stable(p)) changes.push(name + "." + field);
|
|
883
|
+
}
|
|
884
|
+
for (const field of a.keys()) if (!b.has(field)) removals.push(name + "." + field);
|
|
885
|
+
} else if (type.kind === "enum") {
|
|
886
|
+
for (const v of type.values) if (!before.values.includes(v)) additions.push(name + "." + v);
|
|
887
|
+
for (const v of before.values) if (!type.values.includes(v)) removals.push(name + "." + v);
|
|
888
|
+
} else if (type.item !== before.item) changes.push(name + ":item");
|
|
889
|
+
}
|
|
890
|
+
for (const name of old.keys()) if (!now.has(name)) removals.push(name);
|
|
891
|
+
return { additions: additions.sort(), removals: removals.sort(), changes: changes.sort(), breaking: removals.length > 0 || changes.length > 0 };
|
|
892
|
+
}
|
|
893
|
+
function renderModelValidation() {
|
|
894
|
+
return String.raw`
|
|
895
|
+
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';
|
|
896
|
+
function campoConhecido(at: unknown): string | undefined {
|
|
897
|
+
if(typeof at!=='string'||at.length>512||! /^[A-Za-z_]\w*(?:(?:\.[A-Za-z_]\w*)|(?:\[\d{1,7}\]))*$/.test(at))return undefined;
|
|
898
|
+
const parts=at.replace(/\[(\d+)\]/g,'.$1').split('.');let schema=Object.hasOwn(MODEL_SCHEMA,parts[0])?MODEL_SCHEMA[parts[0]]:undefined;
|
|
899
|
+
if(!schema)return undefined;
|
|
900
|
+
for(const part of parts.slice(1)){
|
|
901
|
+
if(schema.kind==='list'){if(! /^\d+$/.test(part))return undefined;schema=MODEL_SCHEMA[schema.item];}
|
|
902
|
+
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};}
|
|
903
|
+
else return undefined;
|
|
904
|
+
}
|
|
905
|
+
return at;
|
|
906
|
+
}
|
|
907
|
+
/** TypeError compatível, com contexto seguro e sem o valor informado ou chaves desconhecidas. */
|
|
908
|
+
export class ErroValidacaoModelo extends TypeError {
|
|
909
|
+
readonly codigo: CodigoValidacaoModelo;
|
|
910
|
+
readonly diagnostico: Readonly<{codigo:CodigoValidacaoModelo;etapa:'documento';campo?:string;mensagem:string;acao:string;statusEnvio:'nao_enviado';causa:Readonly<{codigo:CodigoValidacaoModelo;etapa:'documento';campo?:string}>}>;
|
|
911
|
+
constructor(codigo: CodigoValidacaoModelo, at?: string) {
|
|
912
|
+
const catalogo:Record<CodigoValidacaoModelo,[string,string]>={
|
|
913
|
+
MODELO_DESCONHECIDO:['Modelo desconhecido.','Use um modelo exportado pelo cliente gerado.'],
|
|
914
|
+
ENUM_INVALIDO:['enum inválido','Use um dos valores textuais do enum exportado pelo cliente.'],
|
|
915
|
+
ARRAY_ESPERADO:['esperado array','Informe uma lista JSON entre colchetes.'],
|
|
916
|
+
OBJETO_ESPERADO:['esperado objeto','Informe um objeto JSON entre chaves.'],
|
|
917
|
+
CAMPO_DESCONHECIDO:['propriedade desconhecida','Confira os nomes permitidos neste grupo; a chave desconhecida não é registrada.'],
|
|
918
|
+
CAMPO_SOMENTE_LEITURA:['propriedade somente leitura','Remova este campo da entrada; o motor preenche seu resultado.'],
|
|
919
|
+
INTEIRO_INVALIDO:['inteiro fora do intervalo','Informe um número inteiro dentro do intervalo do campo.'],
|
|
920
|
+
BOOLEANO_ESPERADO:['esperado boolean','Informe true ou false como valor JSON, sem aspas.'],
|
|
921
|
+
DECIMAL_INVALIDO:['esperado decimal em string','Informe o decimal entre aspas, com ponto e a escala permitida pelo campo.'],
|
|
922
|
+
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.'],
|
|
923
|
+
DATA_INVALIDA:['data inválida','Confira dia, mês, ano e horário usando uma data civil válida.'],
|
|
924
|
+
TEXTO_ESPERADO:['esperado string','Informe texto entre aspas no JSON.']
|
|
925
|
+
};
|
|
926
|
+
const safeCode=Object.hasOwn(catalogo,codigo)?codigo:'MODELO_DESCONHECIDO';
|
|
927
|
+
const campo=campoConhecido(at),[texto,acao]=catalogo[safeCode],mensagem=(campo?campo+': ':'')+texto;
|
|
928
|
+
super(mensagem);this.codigo=safeCode;
|
|
929
|
+
const causa=Object.freeze({codigo:safeCode,etapa:'documento' as const,...(campo?{campo}:{})});
|
|
930
|
+
this.diagnostico=Object.freeze({codigo:safeCode,etapa:'documento' as const,...(campo?{campo}:{}),mensagem,acao,statusEnvio:'nao_enviado' as const,causa});
|
|
931
|
+
Object.defineProperty(this,'cause',{value:causa,enumerable:false});
|
|
932
|
+
}
|
|
933
|
+
toJSON(){return this.diagnostico;}
|
|
934
|
+
}
|
|
935
|
+
export function validateModel(model: string, value: unknown, at=model): void {
|
|
936
|
+
const schema=Object.hasOwn(MODEL_SCHEMA,model)?MODEL_SCHEMA[model]:undefined;
|
|
937
|
+
if(!schema)throw new ErroValidacaoModelo('MODELO_DESCONHECIDO');
|
|
938
|
+
at=campoConhecido(at)??model;
|
|
939
|
+
if(schema.kind==='enum'){if(typeof value!=='string'||!schema.values.includes(value))throw new ErroValidacaoModelo('ENUM_INVALIDO',at);return;}
|
|
940
|
+
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;}
|
|
941
|
+
if(value===null||typeof value!=='object'||Array.isArray(value))throw new ErroValidacaoModelo('OBJETO_ESPERADO',at);
|
|
942
|
+
const fields=new Map<string,any>(schema.properties.filter((p:any)=>!p.readonly).map((p:any)=>[p.name,p]));
|
|
943
|
+
for(const [name,v] of Object.entries(value)){
|
|
944
|
+
if(v===undefined)continue;
|
|
945
|
+
const p=fields.get(name);
|
|
946
|
+
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);}
|
|
947
|
+
const field=at+'.'+name;
|
|
948
|
+
if(p.ref){validateModel(p.ref,v,field);continue;}
|
|
949
|
+
if(p.kind==='integer'){if(typeof v!=='number'||!Number.isSafeInteger(v)||v<p.min||v>p.max)throw new ErroValidacaoModelo('INTEIRO_INVALIDO',field);}
|
|
950
|
+
else if(p.kind==='boolean'){if(typeof v!=='boolean')throw new ErroValidacaoModelo('BOOLEANO_ESPERADO',field);}
|
|
951
|
+
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);}
|
|
952
|
+
else if(p.kind==='datetime'){
|
|
953
|
+
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);
|
|
954
|
+
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);
|
|
955
|
+
}else if(typeof v!=='string')throw new ErroValidacaoModelo('TEXTO_ESPERADO',field);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
export function validateTNFe(value: unknown): asserts value is TNFeInput { validateModel('TNFe',value); }
|
|
959
|
+
`;
|
|
960
|
+
}
|
|
961
|
+
function renderTypeScript(ir, revision2, contractHash) {
|
|
962
|
+
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;"];
|
|
963
|
+
for (const t of ir.types) {
|
|
964
|
+
if (t.kind === "enum") {
|
|
965
|
+
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 + "];");
|
|
966
|
+
} else if (t.kind === "list") {
|
|
967
|
+
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; }", "}");
|
|
968
|
+
} else {
|
|
969
|
+
out.push("export interface " + t.name + "Input {");
|
|
970
|
+
for (const p of t.properties.filter((p2) => !p2.readonly)) out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
971
|
+
out.push("}", "export class " + t.name + " {");
|
|
972
|
+
for (const p of t.properties) {
|
|
973
|
+
if (p.readonly) {
|
|
974
|
+
out.push(" readonly " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
if (p.declaredDefault) out.push(" /** Pascal streaming default: " + p.declaredDefault.replaceAll("*/", "") + ". Omission preserves the native constructor. */");
|
|
978
|
+
if (p.kind === "object" || p.kind === "list") out.push(" " + JSON.stringify(p.name) + " = new " + p.ref + "();");
|
|
979
|
+
else out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
980
|
+
}
|
|
981
|
+
out.push(" constructor(input: " + t.name + "Input = {}) {", " validateModel(" + JSON.stringify(t.name) + ", input);");
|
|
982
|
+
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
983
|
+
const access5 = "input[" + JSON.stringify(p.name) + "]", target = "this[" + JSON.stringify(p.name) + "]";
|
|
984
|
+
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) + ";");
|
|
985
|
+
}
|
|
986
|
+
out.push(" }", "}");
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
out.push("const MODEL_SCHEMA: Record<string, any> = " + stable(Object.fromEntries(ir.types.map((t) => [t.name, t]))) + ";");
|
|
990
|
+
out.push(renderModelValidation());
|
|
991
|
+
return out.join("\n") + "\n";
|
|
992
|
+
}
|
|
993
|
+
function renderContractMetadata(ir, sourceRevision, sourceHash, contractHash) {
|
|
994
|
+
if (hash(stable({ sourceRevision, sourceHash, ir })) !== contractHash) throw new Error("Hash do contrato diverge dos metadados gerados.");
|
|
995
|
+
return stable({ formatVersion: 1, sourceRevision, sourceHash, contractHash, ir }) + "\n";
|
|
996
|
+
}
|
|
997
|
+
function renderPascal(ir, revision2, contractHash) {
|
|
998
|
+
const classes = ir.types.filter((t) => t.kind === "object"), byName = new Map(ir.types.map((t) => [t.name, t]));
|
|
999
|
+
const units = [...new Set(ir.types.map((t) => t.unit))].sort();
|
|
1000
|
+
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"];
|
|
1001
|
+
out.push(String.raw`
|
|
1002
|
+
procedure Bad(const P,M:string); begin raise Exception.Create(P+': '+M) end;
|
|
1003
|
+
function Obj(D:TJSONData;const P:string):TJSONObject;
|
|
1004
|
+
begin if (D=nil) or (D.JSONType<>jtObject) then Bad(P,'esperado objeto');Result:=TJSONObject(D) end;
|
|
1005
|
+
function Arr(D:TJSONData;const P:string):TJSONArray;
|
|
1006
|
+
begin if (D=nil) or (D.JSONType<>jtArray) then Bad(P,'esperado array');Result:=TJSONArray(D) end;
|
|
1007
|
+
function Text(D:TJSONData;const P:string):string;
|
|
1008
|
+
begin if (D=nil) or (D.JSONType<>jtString) then Bad(P,'esperado string');Result:=D.AsString end;
|
|
1009
|
+
function IntValue(D:TJSONData;const P:string;MinV,MaxV:Int64):Int64;
|
|
1010
|
+
var V:Extended;
|
|
1011
|
+
begin
|
|
1012
|
+
if (D=nil) or (D.JSONType<>jtNumber) then Bad(P,'esperado inteiro');
|
|
1013
|
+
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');
|
|
1014
|
+
Result:=D.AsInt64;
|
|
1015
|
+
end;
|
|
1016
|
+
function BoolValue(D:TJSONData;const P:string):boolean;
|
|
1017
|
+
begin if (D=nil) or (D.JSONType<>jtBoolean) then Bad(P,'esperado boolean');Result:=D.AsBoolean end;
|
|
1018
|
+
function DecimalText(D:TJSONData;const P:string;Scale:integer):string;
|
|
1019
|
+
var I,PointPos:integer;
|
|
1020
|
+
begin
|
|
1021
|
+
Result:=Text(D,P);PointPos:=0;
|
|
1022
|
+
if (Result='') or (Length(Result)>64) then Bad(P,'decimal inválido');
|
|
1023
|
+
for I:=1 to Length(Result) do begin
|
|
1024
|
+
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
|
|
1025
|
+
else if (Result[I]='-') and (I=1) then begin if Length(Result)=1 then Bad(P,'decimal inválido') end
|
|
1026
|
+
else if not (Result[I] in ['0'..'9']) then Bad(P,'decimal inválido');
|
|
1027
|
+
end;
|
|
1028
|
+
if (PointPos>0) and (Scale>=0) and (Length(Result)-PointPos>Scale) then Bad(P,'casas decimais excedidas');
|
|
1029
|
+
end;
|
|
1030
|
+
function FloatValue(D:TJSONData;const P:string):Extended;
|
|
1031
|
+
var F:TFormatSettings;S:string;
|
|
1032
|
+
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,-1);
|
|
1033
|
+
if not TryStrToFloat(S,Result,F) or IsNan(Result) or IsInfinite(Result) then Bad(P,'decimal fora do intervalo');
|
|
1034
|
+
end;
|
|
1035
|
+
function CurrencyValue(D:TJSONData;const P:string):Currency;
|
|
1036
|
+
var F:TFormatSettings;S:string;
|
|
1037
|
+
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,4);
|
|
1038
|
+
if not TryStrToCurr(S,Result,F) then Bad(P,'currency fora do intervalo');
|
|
1039
|
+
end;
|
|
1040
|
+
function DateValue(D:TJSONData;const P:string):TDateTime;
|
|
1041
|
+
var S:string;I:integer;
|
|
1042
|
+
begin
|
|
1043
|
+
S:=Text(D,P);
|
|
1044
|
+
if not (Length(S) in [10,19,21,22,23]) then Bad(P,'esperado data/hora civil ISO sem timezone');
|
|
1045
|
+
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');
|
|
1046
|
+
if not TryISO8601ToDate(S,Result,true) then Bad(P,'data ISO inválida');
|
|
1047
|
+
end;
|
|
1048
|
+
`);
|
|
1049
|
+
const q = (s) => "'" + s.replaceAll("'", "''") + "'";
|
|
1050
|
+
for (const t of classes) out.push("procedure Load_" + t.name + "(D:TJSONObject;destino:" + t.unit + "." + t.name + ";const P:string); forward;");
|
|
1051
|
+
for (const t of classes) {
|
|
1052
|
+
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;");
|
|
1053
|
+
let index = 0;
|
|
1054
|
+
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
1055
|
+
out.push(" " + (index++ ? "else " : "") + "if K=" + q(p.name) + " then begin");
|
|
1056
|
+
const target = "destino." + p.name;
|
|
1057
|
+
if (p.kind === "object") out.push(" Load_" + p.ref + "(Obj(V,At)," + target + ",At);");
|
|
1058
|
+
else if (p.kind === "list") {
|
|
1059
|
+
const list = byName.get(p.ref);
|
|
1060
|
+
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)+']');");
|
|
1061
|
+
} else if (p.kind === "enum") {
|
|
1062
|
+
const enumeration = byName.get(p.ref);
|
|
1063
|
+
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');");
|
|
1064
|
+
} 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] + ";");
|
|
1065
|
+
out.push(" end");
|
|
1066
|
+
}
|
|
1067
|
+
out.push((index ? " else " : " ") + "Bad(At,'propriedade desconhecida ou somente leitura');", " end;", "end;");
|
|
1068
|
+
}
|
|
1069
|
+
out.push("procedure preencherTNFe(documento:TJSONObject;destino:TNFe);", "begin if documento=nil then Bad('TNFe','esperado objeto');Load_TNFe(documento,destino,'TNFe') end;", "end.");
|
|
1070
|
+
return out.join("\n") + "\n";
|
|
1050
1071
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1072
|
+
function renderClientIndex() {
|
|
1073
|
+
return [
|
|
1074
|
+
"// Generated client bound to its own ACBr contract. Do not edit.",
|
|
1075
|
+
"import { criarEmissor as criarRuntime, diagnosticarErro as diagnosticarErroRuntime, diagnosticarResultado, type OpcoesEmissor, type OpcoesOperacao } from " + JSON.stringify("cosmemilton-acbr-node/runtime") + ";",
|
|
1076
|
+
"import { ACBR_CONTRACT, validateTNFe, ErroValidacaoModelo, type TNFeInput } from " + JSON.stringify("./models.js") + ";",
|
|
1077
|
+
"export * from " + JSON.stringify("./models.js") + ";",
|
|
1078
|
+
"export { diagnosticarResultado };",
|
|
1079
|
+
"export function diagnosticarErro(erro:unknown) { return erro instanceof ErroValidacaoModelo ? erro.diagnostico : diagnosticarErroRuntime(erro); }",
|
|
1080
|
+
"export function criarEmissor(options: Omit<OpcoesEmissor, " + JSON.stringify("contrato") + " | " + JSON.stringify("validaDocumento") + ">) {",
|
|
1081
|
+
" const emissor=criarRuntime({...options, contrato:ACBR_CONTRACT, validaDocumento:validateTNFe});",
|
|
1082
|
+
" return {...emissor, gerarXml(documento:TNFeInput, opcoes?:OpcoesOperacao) { return emissor.gerarXml(documento as unknown as Record<string,unknown>, opcoes); }};",
|
|
1083
|
+
"}"
|
|
1084
|
+
].join("\n") + "\n";
|
|
1062
1085
|
}
|
|
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 });
|
|
1086
|
+
async function fingerprint(dir) {
|
|
1087
|
+
const files = [];
|
|
1088
|
+
async function walk(d) {
|
|
1089
|
+
for (const entry of await readdir4(d, { withFileTypes: true })) {
|
|
1090
|
+
const f = path2.join(d, entry.name);
|
|
1091
|
+
if (entry.isDirectory()) await walk(f);
|
|
1092
|
+
else if (/\.(pas|pp|inc|xsd)$/i.test(entry.name)) files.push(f);
|
|
1084
1093
|
}
|
|
1085
1094
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
} catch (error) {
|
|
1092
|
-
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: false, detail: error.message });
|
|
1093
|
-
}
|
|
1095
|
+
await walk(dir);
|
|
1096
|
+
const digest = createHash3("sha256");
|
|
1097
|
+
for (const f of files.sort()) {
|
|
1098
|
+
digest.update(path2.relative(dir, f).replaceAll("\\", "/"));
|
|
1099
|
+
digest.update(await readFile5(f));
|
|
1094
1100
|
}
|
|
1095
|
-
return
|
|
1101
|
+
return digest.digest("hex");
|
|
1096
1102
|
}
|
|
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)]);
|
|
1103
|
+
async function generateModel(options) {
|
|
1104
|
+
const root = path2.resolve(options.outputDir), cache = path2.join(root, ".acbr/generated"), bin = path2.join(root, ".acbr/bin");
|
|
1105
|
+
const models = path2.resolve(root, options.modelOutputDir ?? "generated/acbr"), native = path2.resolve(root, options.nativeOutputDir ?? "native/generated");
|
|
1106
|
+
await Promise.all([mkdir4(cache, { recursive: true }), mkdir4(bin, { recursive: true }), mkdir4(models, { recursive: true }), mkdir4(native, { recursive: true })]);
|
|
1107
|
+
const extractor = options.extractorPath ?? fileURLToPath2(new URL("../tools/extract-model.lpr", import.meta.url));
|
|
1108
|
+
const executable = path2.join(bin, "extract-model" + (process.platform === "win32" ? ".exe" : ""));
|
|
1109
|
+
try {
|
|
1110
|
+
await execute(options.fpcPath ?? "fpc", ["-Mobjfpc", "-Sh", "-FU" + bin, "-FE" + bin, extractor], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
|
|
1111
|
+
await execute(executable, [path2.resolve(options.acbrRoot), path2.join(cache, "raw-model.json"), process.platform === "win32" ? "win64" : "linux"], { cwd: root, maxBuffer: 8 * 1024 * 1024 });
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
const e = error;
|
|
1114
|
+
throw new Error("Extra\xE7\xE3o FCL-passrc falhou: " + (e.stderr ?? "") + (e.stdout ?? "") + e.message);
|
|
1117
1115
|
}
|
|
1118
|
-
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1116
|
+
const raw = JSON.parse(await readFile5(path2.join(cache, "raw-model.json"), "utf8"));
|
|
1117
|
+
const ir = buildModelIR(raw), sourceRevision = Number(options.revision);
|
|
1118
|
+
if (!Number.isSafeInteger(sourceRevision) || sourceRevision < 1) throw new Error("Revis\xE3o SVN inv\xE1lida");
|
|
1119
|
+
const sourceHash = options.sourceHash ?? await fingerprint(options.acbrRoot), contractHash = hash(stable({ sourceRevision, sourceHash, ir }));
|
|
1120
|
+
let previous;
|
|
1121
|
+
try {
|
|
1122
|
+
previous = JSON.parse(await readFile5(path2.join(cache, "model.ir.json"), "utf8"));
|
|
1123
|
+
} catch (error) {
|
|
1124
|
+
if (error.code !== "ENOENT") throw error;
|
|
1125
1125
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1126
|
+
const report = compareContracts(previous, ir), reportPath = path2.join(cache, "changes.json"), manifestPath = path2.join(cache, "manifest.json");
|
|
1127
|
+
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("\\", "/"));
|
|
1128
|
+
const content = [renderTypeScript(ir, sourceRevision, contractHash), renderClientIndex(), renderPascal(ir, sourceRevision, contractHash)];
|
|
1129
|
+
const fileHashes = Object.fromEntries(files.map((file, index) => [file, hash(content[index])]));
|
|
1130
|
+
const metadataPath = path2.join(models, "contract.json"), metadataContent = renderContractMetadata(ir, sourceRevision, sourceHash, contractHash);
|
|
1131
|
+
await Promise.all([
|
|
1132
|
+
...files.map((file, index) => writeFile4(path2.resolve(root, file), content[index], "utf8")),
|
|
1133
|
+
writeFile4(path2.join(cache, "model.ir.json"), JSON.stringify(ir, null, 2) + "\n", "utf8"),
|
|
1134
|
+
writeFile4(metadataPath, metadataContent, "utf8"),
|
|
1135
|
+
writeFile4(reportPath, JSON.stringify(report, null, 2) + "\n", "utf8"),
|
|
1136
|
+
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")
|
|
1137
|
+
]);
|
|
1138
|
+
return { contractHash, sourceHash, models: ir.types.length, reportPath, manifestPath, metadataPath };
|
|
1128
1139
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1140
|
+
var execute, bases, primitives, stable, hash, tsType;
|
|
1141
|
+
var init_generator = __esm({
|
|
1142
|
+
"src/generator.ts"() {
|
|
1143
|
+
"use strict";
|
|
1144
|
+
execute = promisify(execFile);
|
|
1145
|
+
bases = /* @__PURE__ */ new Set(["tobject", "tpersistent", "tacbrobjectlist"]);
|
|
1146
|
+
primitives = {
|
|
1147
|
+
string: { kind: "string" },
|
|
1148
|
+
ansistring: { kind: "string" },
|
|
1149
|
+
unicodestring: { kind: "string" },
|
|
1150
|
+
widestring: { kind: "string" },
|
|
1151
|
+
boolean: { kind: "boolean" },
|
|
1152
|
+
byte: { kind: "integer", min: 0, max: 255 },
|
|
1153
|
+
word: { kind: "integer", min: 0, max: 65535 },
|
|
1154
|
+
integer: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
1155
|
+
longint: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
1156
|
+
smallint: { kind: "integer", min: -32768, max: 32767 },
|
|
1157
|
+
shortint: { kind: "integer", min: -128, max: 127 },
|
|
1158
|
+
cardinal: { kind: "integer", min: 0, max: 4294967295 },
|
|
1159
|
+
longword: { kind: "integer", min: 0, max: 4294967295 },
|
|
1160
|
+
int64: { kind: "integer", min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER },
|
|
1161
|
+
qword: { kind: "integer", min: 0, max: Number.MAX_SAFE_INTEGER },
|
|
1162
|
+
double: { kind: "decimal" },
|
|
1163
|
+
extended: { kind: "decimal" },
|
|
1164
|
+
single: { kind: "decimal" },
|
|
1165
|
+
currency: { kind: "decimal", scale: 4 },
|
|
1166
|
+
tdatetime: { kind: "datetime" },
|
|
1167
|
+
tdate: { kind: "datetime" },
|
|
1168
|
+
ttime: { kind: "datetime" }
|
|
1169
|
+
};
|
|
1170
|
+
stable = (value) => JSON.stringify(value);
|
|
1171
|
+
hash = (value) => createHash3("sha256").update(value).digest("hex");
|
|
1172
|
+
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";
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1137
1175
|
|
|
1138
1176
|
// src/diagnostics.ts
|
|
1139
|
-
var ETAPAS = /* @__PURE__ */ new Set(["configuracao", "documento", "runtime", "geracao", "validacao", "assinatura", "transmissao", "consulta", "cancelamento", "carta_correcao", "inutilizacao", "operacao", "limpeza"]);
|
|
1140
|
-
var 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"]);
|
|
1141
|
-
var CATALOGO = {
|
|
1142
|
-
CONFIGURACAO_INVALIDA: ["configuracao", "A configura\xE7\xE3o cont\xE9m um campo inv\xE1lido.", "Confira o campo indicado e seu tipo antes de continuar."],
|
|
1143
|
-
CONTRATO_INVALIDO: ["configuracao", "O contrato do cliente \xE9 inv\xE1lido.", "Use o contrato gerado junto com o cliente."],
|
|
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
|
-
};
|
|
1189
1177
|
function etapaDaOperacao(comando) {
|
|
1190
1178
|
return { gerarXml: "geracao", validar: "validacao", assinar: "assinatura", transmitir: "transmissao", consultar: "consulta", cancelar: "cancelamento", cartaCorrecao: "carta_correcao", inutilizar: "inutilizacao" }[comando] ?? "operacao";
|
|
1191
1179
|
}
|
|
@@ -1250,92 +1238,155 @@ function diagnosticarResultado(resultado, comando) {
|
|
|
1250
1238
|
const cStat = Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 ? resultado.cStat : void 0;
|
|
1251
1239
|
return Object.freeze({ codigo, etapa, mensagem, acao, statusEnvio, ...cStat !== void 0 ? { cStat } : {} });
|
|
1252
1240
|
}
|
|
1241
|
+
var ETAPAS, CAMPOS, CATALOGO;
|
|
1242
|
+
var init_diagnostics = __esm({
|
|
1243
|
+
"src/diagnostics.ts"() {
|
|
1244
|
+
"use strict";
|
|
1245
|
+
init_types();
|
|
1246
|
+
ETAPAS = /* @__PURE__ */ new Set(["configuracao", "documento", "runtime", "geracao", "validacao", "assinatura", "transmissao", "consulta", "cancelamento", "carta_correcao", "inutilizacao", "operacao", "limpeza"]);
|
|
1247
|
+
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"]);
|
|
1248
|
+
CATALOGO = {
|
|
1249
|
+
CONFIGURACAO_INVALIDA: ["configuracao", "A configura\xE7\xE3o cont\xE9m um campo inv\xE1lido.", "Confira o campo indicado e seu tipo antes de continuar."],
|
|
1250
|
+
CONTRATO_INVALIDO: ["configuracao", "O contrato do cliente \xE9 inv\xE1lido.", "Use o contrato gerado junto com o cliente."],
|
|
1251
|
+
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."],
|
|
1252
|
+
CERTIFICADO_DIVERGENTE: ["assinatura", "O certificado n\xE3o corresponde \xE0 raiz CNPJ do emitente.", "Confira o CNPJ configurado e selecione o A1 correspondente ao emitente."],
|
|
1253
|
+
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."],
|
|
1254
|
+
SCHEMAS_AUSENTES: ["runtime", "Os schemas fiscais n\xE3o est\xE3o dispon\xEDveis.", "Reinstale o runtime completo da plataforma."],
|
|
1255
|
+
SERVICOS_AUSENTES: ["runtime", "A configura\xE7\xE3o dos servi\xE7os fiscais n\xE3o est\xE1 dispon\xEDvel.", "Reinstale o runtime completo da plataforma."],
|
|
1256
|
+
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."],
|
|
1257
|
+
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."],
|
|
1258
|
+
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."],
|
|
1259
|
+
ASSINATURA_INVALIDA: ["assinatura", "A assinatura do XML n\xE3o foi validada.", "Confira o A1 correspondente e use o XML assinado sem altera\xE7\xF5es."],
|
|
1260
|
+
XML_NAO_ASSINADO: ["assinatura", "A opera\xE7\xE3o exige XML previamente assinado.", "Conclua a assinatura e a valida\xE7\xE3o antes de transmitir."],
|
|
1261
|
+
XML_ALTERADO: ["assinatura", "O XML assinado foi alterado.", "Use exatamente o XML assinado e persistido; n\xE3o edite seu conte\xFAdo."],
|
|
1262
|
+
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."],
|
|
1263
|
+
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."],
|
|
1264
|
+
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."],
|
|
1265
|
+
CSC_INVALIDO: ["configuracao", "A configura\xE7\xE3o do CSC \xE9 inv\xE1lida.", "Confira id e valor do CSC sem registrar seu conte\xFAdo."],
|
|
1266
|
+
PLATAFORMA_NAO_SUPORTADA: ["runtime", "A plataforma n\xE3o \xE9 suportada.", "Execute em Windows ou Linux x64 com Node.js 22.12 ou superior."],
|
|
1267
|
+
RUNTIME_AUSENTE: ["runtime", "O motor fiscal n\xE3o foi encontrado.", "Instale o runtime da plataforma incluindo depend\xEAncias opcionais."],
|
|
1268
|
+
RUNTIME_INVALIDO: ["runtime", "O runtime fiscal \xE9 inv\xE1lido.", "Use um runtime distribu\xEDdo e compat\xEDvel com a plataforma."],
|
|
1269
|
+
RUNTIME_INCOMPLETO: ["runtime", "Falta um arquivo do runtime fiscal.", "Reinstale o runtime da plataforma."],
|
|
1270
|
+
RUNTIME_ALTERADO: ["runtime", "A integridade do runtime fiscal n\xE3o foi confirmada.", "Reinstale o runtime; n\xE3o desative a verifica\xE7\xE3o dos hashes."],
|
|
1271
|
+
CONTRATO_DIVERGENTE: ["runtime", "Cliente e motor usam contratos diferentes.", "Use vers\xF5es compat\xEDveis ou regenere e recompile ambos."],
|
|
1272
|
+
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."],
|
|
1273
|
+
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."],
|
|
1274
|
+
OPERACAO_CANCELADA: ["operacao", "A opera\xE7\xE3o foi cancelada.", "Confira o estado do envio antes de decidir continuar."],
|
|
1275
|
+
TIMEOUT_MOTOR: ["runtime", "O motor excedeu o tempo de espera.", "Confira o estado do envio antes de repetir a opera\xE7\xE3o."],
|
|
1276
|
+
EMISSOR_FECHADO: ["operacao", "O emissor foi encerrado.", "Crie um novo emissor para continuar."],
|
|
1277
|
+
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."],
|
|
1278
|
+
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."],
|
|
1279
|
+
RESPOSTA_EXCESSIVA: ["runtime", "A resposta do motor excedeu o limite.", "Confira o tamanho da opera\xE7\xE3o e a vers\xE3o do runtime."],
|
|
1280
|
+
RESPOSTA_INVALIDA: ["runtime", "O motor devolveu uma resposta inv\xE1lida.", "Confira a compatibilidade do runtime e o estado do envio."],
|
|
1281
|
+
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."],
|
|
1282
|
+
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."],
|
|
1283
|
+
CERTIFICADO_EXCESSIVO: ["configuracao", "O certificado excede o limite de tamanho.", "Use um arquivo A1 de at\xE9 2 MiB."],
|
|
1284
|
+
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."],
|
|
1285
|
+
FILA_CHEIA: ["operacao", "A fila fiscal est\xE1 cheia.", "Aguarde a opera\xE7\xE3o atual terminar antes de iniciar outra."],
|
|
1286
|
+
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."],
|
|
1287
|
+
CHAVE_INVALIDA: ["documento", "A chave fiscal tem formato inv\xE1lido.", "Informe a chave como texto com 44 d\xEDgitos."],
|
|
1288
|
+
RECIBO_INVALIDO: ["documento", "O recibo tem formato inv\xE1lido.", "Informe o recibo como texto com 15 d\xEDgitos."],
|
|
1289
|
+
JUSTIFICATIVA_INVALIDA: ["documento", "A justificativa tem tamanho inv\xE1lido.", "Informe uma justificativa com 15 a 255 caracteres."],
|
|
1290
|
+
PROTOCOLO_INVALIDO: ["documento", "O protocolo tem formato inv\xE1lido.", "Informe o protocolo como texto com 15 d\xEDgitos."],
|
|
1291
|
+
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."],
|
|
1292
|
+
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."],
|
|
1293
|
+
INUTILIZACAO_INVALIDA: ["documento", "A faixa de inutiliza\xE7\xE3o \xE9 inv\xE1lida.", "Confira ano, s\xE9rie e n\xFAmeros inicial e final."],
|
|
1294
|
+
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."]
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1253
1298
|
|
|
1254
1299
|
// 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
|
-
|
|
1300
|
+
var ErroAcbrNode;
|
|
1301
|
+
var init_types = __esm({
|
|
1302
|
+
"src/types.ts"() {
|
|
1303
|
+
"use strict";
|
|
1304
|
+
init_diagnostics();
|
|
1305
|
+
ErroAcbrNode = class extends Error {
|
|
1306
|
+
constructor(codigo, mensagem, resultadoDesconhecido = false, xmlBase64, detalhes) {
|
|
1307
|
+
super(mensagem);
|
|
1308
|
+
this.codigo = codigo;
|
|
1309
|
+
this.resultadoDesconhecido = resultadoDesconhecido;
|
|
1310
|
+
this.xmlBase64 = xmlBase64;
|
|
1311
|
+
this.#diagnostico = criarDiagnosticoErro(codigo, resultadoDesconhecido, detalhes);
|
|
1312
|
+
Object.defineProperty(this, "xmlBase64", { value: xmlBase64, enumerable: false });
|
|
1313
|
+
Object.defineProperty(this, "cause", { value: this.diagnostico.causa, enumerable: false });
|
|
1314
|
+
}
|
|
1315
|
+
name = "ErroAcbrNode";
|
|
1316
|
+
#diagnostico;
|
|
1317
|
+
get diagnostico() {
|
|
1318
|
+
return this.#diagnostico;
|
|
1319
|
+
}
|
|
1320
|
+
/** Acrescenta apenas o aviso estático de limpeza, preservando o erro da operação. */
|
|
1321
|
+
anotarFalhaLimpeza() {
|
|
1322
|
+
this.#diagnostico = adicionarDiagnosticoLimpeza(this.#diagnostico);
|
|
1323
|
+
}
|
|
1324
|
+
toJSON() {
|
|
1325
|
+
return this.diagnostico;
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1276
1328
|
}
|
|
1277
|
-
};
|
|
1329
|
+
});
|
|
1278
1330
|
|
|
1279
1331
|
// 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 });
|
|
1332
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
1333
|
+
import { readFile as readFile6, stat as stat3 } from "node:fs/promises";
|
|
1334
|
+
import path3 from "node:path";
|
|
1335
|
+
import { createRequire } from "node:module";
|
|
1336
|
+
import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
|
|
1337
|
+
import { TextDecoder } from "node:util";
|
|
1287
1338
|
function confined(root, relative3) {
|
|
1288
|
-
const file =
|
|
1289
|
-
if (!relative3 ||
|
|
1339
|
+
const file = path3.resolve(root, relative3), part = path3.relative(root, file);
|
|
1340
|
+
if (!relative3 || path3.isAbsolute(relative3) || part === ".." || part.startsWith(".." + path3.sep)) throw fail2("RUNTIME_INVALIDO", "Caminho inv\xE1lido no runtime.");
|
|
1290
1341
|
return file;
|
|
1291
1342
|
}
|
|
1292
1343
|
async function resolveRuntime(directory, contract) {
|
|
1293
|
-
if (!validContract(contract)) throw
|
|
1344
|
+
if (!validContract(contract)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1294
1345
|
let root = directory;
|
|
1295
1346
|
if (!root) {
|
|
1296
|
-
if (!["linux", "win32"].includes(process.platform) || process.arch !== "x64") throw
|
|
1347
|
+
if (!["linux", "win32"].includes(process.platform) || process.arch !== "x64") throw fail2("PLATAFORMA_NAO_SUPORTADA", "Esta vers\xE3o exige Linux ou Windows x64.");
|
|
1297
1348
|
try {
|
|
1298
1349
|
const require2 = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url);
|
|
1299
|
-
root =
|
|
1350
|
+
root = path3.join(path3.dirname(require2.resolve("cosmemilton-acbr-node-" + process.platform + "-x64/package.json")), "runtime");
|
|
1300
1351
|
} catch {
|
|
1301
|
-
throw
|
|
1352
|
+
throw fail2("RUNTIME_AUSENTE", "Instale o pacote de runtime da plataforma ou informe runtimeDirectory.");
|
|
1302
1353
|
}
|
|
1303
1354
|
}
|
|
1304
|
-
root =
|
|
1355
|
+
root = path3.resolve(root);
|
|
1305
1356
|
let m;
|
|
1306
1357
|
try {
|
|
1307
|
-
m = JSON.parse(await
|
|
1358
|
+
m = JSON.parse(await readFile6(path3.join(root, "manifest.json"), "utf8"));
|
|
1308
1359
|
} catch {
|
|
1309
|
-
throw
|
|
1360
|
+
throw fail2("RUNTIME_AUSENTE", "Manifesto do runtime n\xE3o encontrado.");
|
|
1310
1361
|
}
|
|
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.sourceRevision !== contract.sourceRevision || m.contractHash !== contract.contractHash) throw
|
|
1362
|
+
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.");
|
|
1363
|
+
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
1364
|
for (const [name, hash2] of Object.entries(m.files)) {
|
|
1314
|
-
if (typeof hash2 !== "string" || !/^[a-f0-9]{64}$/.test(hash2)) throw
|
|
1365
|
+
if (typeof hash2 !== "string" || !/^[a-f0-9]{64}$/.test(hash2)) throw fail2("RUNTIME_INVALIDO", "Hash inv\xE1lido no runtime.");
|
|
1315
1366
|
const file = confined(root, name);
|
|
1316
1367
|
let data;
|
|
1317
1368
|
try {
|
|
1318
1369
|
if (!(await stat3(file)).isFile()) throw Error();
|
|
1319
|
-
data = await
|
|
1370
|
+
data = await readFile6(file);
|
|
1320
1371
|
} catch {
|
|
1321
|
-
throw
|
|
1372
|
+
throw fail2("RUNTIME_INCOMPLETO", "Arquivo do runtime ausente.");
|
|
1322
1373
|
}
|
|
1323
|
-
if (
|
|
1374
|
+
if (createHash4("sha256").update(data).digest("hex") !== hash2) throw fail2("RUNTIME_ALTERADO", "O runtime n\xE3o corresponde ao manifesto distribu\xEDdo.");
|
|
1324
1375
|
}
|
|
1325
|
-
if (!m.files[m.executable]) throw
|
|
1376
|
+
if (!m.files[m.executable]) throw fail2("RUNTIME_INVALIDO", "O execut\xE1vel n\xE3o consta no invent\xE1rio.");
|
|
1326
1377
|
return { directory: root, executable: confined(root, m.executable) };
|
|
1327
1378
|
}
|
|
1328
1379
|
function criarEmissor(options) {
|
|
1329
|
-
const configFail = (campo) =>
|
|
1380
|
+
const configFail = (campo) => fail2("CONFIGURACAO_INVALIDA", "Informe campos e tipos v\xE1lidos na configura\xE7\xE3o.", void 0, false, { etapa: "configuracao", campo });
|
|
1330
1381
|
if (!plain(options)) throw configFail();
|
|
1331
1382
|
if (typeof options.cnpj !== "string" || !/^\d{14}$/.test(options.cnpj)) throw configFail("cnpj");
|
|
1332
1383
|
if (typeof options.uf !== "string" || !UFS.has(options.uf)) throw configFail("uf");
|
|
1333
1384
|
if (![55, 65].includes(options.modelo)) throw configFail("modelo");
|
|
1334
1385
|
if (![1, 2].includes(options.ambiente)) throw configFail("ambiente");
|
|
1335
|
-
if (!validContract(options.contrato)) throw
|
|
1386
|
+
if (!validContract(options.contrato)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1336
1387
|
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
|
|
1388
|
+
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" });
|
|
1389
|
+
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
1390
|
if (options.runtimeDirectory !== void 0 && (typeof options.runtimeDirectory !== "string" || !options.runtimeDirectory)) throw configFail("runtimeDirectory");
|
|
1340
1391
|
if (options.validaDocumento !== void 0 && typeof options.validaDocumento !== "function" || options.criaProcesso !== void 0 && typeof options.criaProcesso !== "function") throw configFail();
|
|
1341
1392
|
const cfg = { cnpj: options.cnpj, uf: options.uf, modelo: options.modelo, ambiente: options.ambiente, csc: options.csc ? { ...options.csc } : void 0 };
|
|
@@ -1349,7 +1400,7 @@ function criarEmissor(options) {
|
|
|
1349
1400
|
let runtimePromise, closed = false, teardownFailed = false, current;
|
|
1350
1401
|
const queue = [];
|
|
1351
1402
|
const closedError = () => {
|
|
1352
|
-
const error =
|
|
1403
|
+
const error = fail2("EMISSOR_FECHADO", "Emissor encerrado.");
|
|
1353
1404
|
if (teardownFailed) error.anotarFalhaLimpeza();
|
|
1354
1405
|
return error;
|
|
1355
1406
|
};
|
|
@@ -1361,9 +1412,9 @@ function criarEmissor(options) {
|
|
|
1361
1412
|
}
|
|
1362
1413
|
};
|
|
1363
1414
|
async function execute2(item) {
|
|
1364
|
-
if (closed || item.signal?.aborted) throw
|
|
1415
|
+
if (closed || item.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
|
|
1365
1416
|
const runtime = await (runtimePromise ??= resolveRuntime(options.runtimeDirectory, contract));
|
|
1366
|
-
if (closed || item.signal?.aborted) throw
|
|
1417
|
+
if (closed || item.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
|
|
1367
1418
|
return await new Promise((done, rejectExecution) => {
|
|
1368
1419
|
let stopError;
|
|
1369
1420
|
let child, finished = false, started = false, sending = false, total = 0, rest = Buffer.alloc(0), result;
|
|
@@ -1402,7 +1453,7 @@ function criarEmissor(options) {
|
|
|
1402
1453
|
};
|
|
1403
1454
|
const teardownFallback = () => {
|
|
1404
1455
|
if (finished) return;
|
|
1405
|
-
stopError ??=
|
|
1456
|
+
stopError ??= fail2("FALHA_MOTOR", "O motor n\xE3o foi encerrado.", item.req, uncertain());
|
|
1406
1457
|
stopError.anotarFalhaLimpeza();
|
|
1407
1458
|
teardownFailed = true;
|
|
1408
1459
|
closed = true;
|
|
@@ -1413,7 +1464,7 @@ function criarEmissor(options) {
|
|
|
1413
1464
|
};
|
|
1414
1465
|
const stop = (code, message) => {
|
|
1415
1466
|
if (finished || stopError) return;
|
|
1416
|
-
stopError =
|
|
1467
|
+
stopError = fail2(code, message, item.req, uncertain());
|
|
1417
1468
|
if (!child?.pid) {
|
|
1418
1469
|
finish(stopError);
|
|
1419
1470
|
detachOwnedChild();
|
|
@@ -1431,20 +1482,20 @@ function criarEmissor(options) {
|
|
|
1431
1482
|
current = { stop: () => stop("EMISSOR_FECHADO", "Emissor encerrado."), done: doneCurrent };
|
|
1432
1483
|
const env = {};
|
|
1433
1484
|
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 =
|
|
1485
|
+
if (process.platform === "linux") env.LD_LIBRARY_PATH = path3.join(runtime.directory, "lib");
|
|
1435
1486
|
if (process.platform === "win32") {
|
|
1436
1487
|
const inheritedPath = env.Path ?? env.PATH ?? "";
|
|
1437
1488
|
delete env.Path;
|
|
1438
|
-
env.PATH =
|
|
1489
|
+
env.PATH = path3.join(runtime.directory, "lib") + ";" + runtime.directory + ";" + inheritedPath;
|
|
1439
1490
|
}
|
|
1440
|
-
const modules =
|
|
1491
|
+
const modules = path3.join(runtime.directory, "ossl-modules");
|
|
1441
1492
|
env.OPENSSL_MODULES = modules;
|
|
1442
|
-
env.OPENSSL_CONF =
|
|
1493
|
+
env.OPENSSL_CONF = path3.join(runtime.directory, "openssl.cnf");
|
|
1443
1494
|
try {
|
|
1444
1495
|
child = launch(runtime.executable, ["--parent-pid", String(process.pid)], { cwd: runtime.directory, env, windowsHide: true, shell: false, stdio: ["pipe", "pipe", "pipe"] });
|
|
1445
1496
|
started = typeof child.pid === "number";
|
|
1446
1497
|
} catch {
|
|
1447
|
-
finish(
|
|
1498
|
+
finish(fail2("FALHA_INICIAR_MOTOR", "N\xE3o foi poss\xEDvel iniciar o motor.", item.req));
|
|
1448
1499
|
return;
|
|
1449
1500
|
}
|
|
1450
1501
|
item.signal?.addEventListener("abort", abort, { once: true });
|
|
@@ -1503,7 +1554,7 @@ function criarEmissor(options) {
|
|
|
1503
1554
|
return;
|
|
1504
1555
|
}
|
|
1505
1556
|
if (code !== 0 || rest.length || !result) {
|
|
1506
|
-
finish(
|
|
1557
|
+
finish(fail2("FALHA_MOTOR", "O motor encerrou sem resposta fiscal v\xE1lida.", item.req, uncertain()));
|
|
1507
1558
|
return;
|
|
1508
1559
|
}
|
|
1509
1560
|
finish();
|
|
@@ -1532,22 +1583,22 @@ function criarEmissor(options) {
|
|
|
1532
1583
|
}
|
|
1533
1584
|
async function request(command, data, operation = {}) {
|
|
1534
1585
|
const rawOperation = operation;
|
|
1535
|
-
if (!plain(rawOperation)) throw
|
|
1586
|
+
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
1587
|
const signal = operation.signal;
|
|
1537
|
-
if (signal !== void 0 && (!plain(signal) || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function" || typeof signal.removeEventListener !== "function")) throw
|
|
1588
|
+
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
1589
|
if (closed) throw closedError();
|
|
1539
|
-
if (operation.signal?.aborted) throw
|
|
1540
|
-
if (["assinar", "transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(command) && !certificate) throw
|
|
1590
|
+
if (operation.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
|
|
1591
|
+
if (["assinar", "transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(command) && !certificate) throw fail2("CERTIFICADO_AUSENTE", "A opera\xE7\xE3o exige um certificado A1.");
|
|
1541
1592
|
if (command === "gerarXml") options.validaDocumento?.(data.documento);
|
|
1542
1593
|
const config = { ...cfg };
|
|
1543
1594
|
if (certificate) {
|
|
1544
1595
|
let pfx;
|
|
1545
1596
|
try {
|
|
1546
|
-
pfx = certificate.pfx ?? await
|
|
1597
|
+
pfx = certificate.pfx ?? await readFile6(certificate.arquivo);
|
|
1547
1598
|
} catch {
|
|
1548
|
-
throw
|
|
1599
|
+
throw fail2("CERTIFICADO_AUSENTE", "N\xE3o foi poss\xEDvel ler o A1 configurado.");
|
|
1549
1600
|
}
|
|
1550
|
-
if (pfx.length > 2 * 1024 * 1024) throw
|
|
1601
|
+
if (pfx.length > 2 * 1024 * 1024) throw fail2("CERTIFICADO_EXCESSIVO", "Certificado excede o limite.");
|
|
1551
1602
|
config.certificado = { pfxBase64: pfx.toString("base64"), senha: certificate.senha };
|
|
1552
1603
|
}
|
|
1553
1604
|
let bytes, req;
|
|
@@ -1556,7 +1607,7 @@ function criarEmissor(options) {
|
|
|
1556
1607
|
if (bytes.length > bytesLimit) throw Error();
|
|
1557
1608
|
req = JSON.parse(bytes.toString("utf8"));
|
|
1558
1609
|
} catch {
|
|
1559
|
-
throw
|
|
1610
|
+
throw fail2("REQUISICAO_INVALIDA", "Dados da opera\xE7\xE3o inv\xE1lidos ou acima do limite.");
|
|
1560
1611
|
}
|
|
1561
1612
|
return new Promise((resolve5, reject) => {
|
|
1562
1613
|
if (closed) {
|
|
@@ -1566,7 +1617,7 @@ function criarEmissor(options) {
|
|
|
1566
1617
|
}
|
|
1567
1618
|
if (busy && queue.length >= capacity) {
|
|
1568
1619
|
bytes.fill(0);
|
|
1569
|
-
reject(
|
|
1620
|
+
reject(fail2("FILA_CHEIA", "A fila fiscal est\xE1 cheia."));
|
|
1570
1621
|
return;
|
|
1571
1622
|
}
|
|
1572
1623
|
const item = { req, bytes, signal: operation.signal, resolve: resolve5, reject };
|
|
@@ -1576,7 +1627,7 @@ function criarEmissor(options) {
|
|
|
1576
1627
|
queue.splice(i, 1);
|
|
1577
1628
|
bytes.fill(0);
|
|
1578
1629
|
operation.signal?.removeEventListener("abort", item.abort);
|
|
1579
|
-
reject(
|
|
1630
|
+
reject(fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o."));
|
|
1580
1631
|
}
|
|
1581
1632
|
};
|
|
1582
1633
|
operation.signal?.addEventListener("abort", item.abort, { once: true });
|
|
@@ -1586,17 +1637,17 @@ function criarEmissor(options) {
|
|
|
1586
1637
|
});
|
|
1587
1638
|
}
|
|
1588
1639
|
const xmlData = (xml) => {
|
|
1589
|
-
if (typeof xml !== "string" || !xml.trim() || Buffer.byteLength(xml, "utf8") > 2 * 1024 * 1024) throw
|
|
1640
|
+
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
1641
|
return { xmlBase64: Buffer.from(xml, "utf8").toString("base64") };
|
|
1591
1642
|
};
|
|
1592
1643
|
const checkKey = (key) => {
|
|
1593
|
-
if (typeof key !== "string" || !/^\d{44}$/.test(key)) throw
|
|
1644
|
+
if (typeof key !== "string" || !/^\d{44}$/.test(key)) throw fail2("CHAVE_INVALIDA", "Chave fiscal inv\xE1lida.", void 0, false, { campo: "chave" });
|
|
1594
1645
|
};
|
|
1595
1646
|
const reason = (value) => {
|
|
1596
|
-
if (typeof value !== "string" || value.length < 15 || value.length > 255) throw
|
|
1647
|
+
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
1648
|
};
|
|
1598
1649
|
const checkObject = (data, campo) => {
|
|
1599
|
-
if (!plain(data)) throw
|
|
1650
|
+
if (!plain(data)) throw fail2("OPERACAO_INVALIDA", "Informe os par\xE2metros da opera\xE7\xE3o como objeto.", void 0, false, { campo });
|
|
1600
1651
|
};
|
|
1601
1652
|
return {
|
|
1602
1653
|
gerarXml: (documento, op) => request("gerarXml", { documento }, op),
|
|
@@ -1606,27 +1657,27 @@ function criarEmissor(options) {
|
|
|
1606
1657
|
consultar: (consulta, op) => {
|
|
1607
1658
|
checkObject(consulta, "consulta");
|
|
1608
1659
|
checkKey(consulta.chave);
|
|
1609
|
-
if (consulta.recibo !== void 0 && (typeof consulta.recibo !== "string" || !/^\d{15}$/.test(consulta.recibo))) throw
|
|
1660
|
+
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" });
|
|
1610
1661
|
return request("consultar", consulta, op);
|
|
1611
1662
|
},
|
|
1612
1663
|
cancelar: (data, op) => {
|
|
1613
1664
|
checkObject(data, "cancelamento");
|
|
1614
1665
|
checkKey(data.chave);
|
|
1615
1666
|
reason(data.justificativa);
|
|
1616
|
-
if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw
|
|
1667
|
+
if (typeof data.protocolo !== "string" || !/^\d{15}$/.test(data.protocolo)) throw fail2("PROTOCOLO_INVALIDO", "Protocolo inv\xE1lido.", void 0, false, { campo: "protocolo" });
|
|
1617
1668
|
return request("cancelar", data, op);
|
|
1618
1669
|
},
|
|
1619
1670
|
cartaCorrecao: (data, op) => {
|
|
1620
1671
|
checkObject(data, "cartaCorrecao");
|
|
1621
|
-
if (cfg.modelo !== 55) throw
|
|
1672
|
+
if (cfg.modelo !== 55) throw fail2("OPERACAO_NAO_SUPORTADA", "Carta de corre\xE7\xE3o exige NF-e modelo 55.");
|
|
1622
1673
|
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
|
|
1674
|
+
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" });
|
|
1624
1675
|
return request("cartaCorrecao", { ...data, sequenciaEvento: data.sequenciaEvento ?? 1 }, op);
|
|
1625
1676
|
},
|
|
1626
1677
|
inutilizar: (data, op) => {
|
|
1627
1678
|
checkObject(data, "inutilizacao");
|
|
1628
1679
|
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
|
|
1680
|
+
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
1681
|
return request("inutilizar", { inutilizacao: { ano: data.ano, serie: data.serie, numeroInicial: data.numeroInicial, numeroFinal: data.numeroFinal }, justificativa: data.justificativa }, op);
|
|
1631
1682
|
},
|
|
1632
1683
|
async fechar() {
|
|
@@ -1644,118 +1695,145 @@ function criarEmissor(options) {
|
|
|
1644
1695
|
}
|
|
1645
1696
|
};
|
|
1646
1697
|
}
|
|
1698
|
+
var STATES, UFS, MAX_BYTES, MAX_TEARDOWN_MS, plain, validContract, fail2;
|
|
1699
|
+
var init_runtime = __esm({
|
|
1700
|
+
"src/runtime.ts"() {
|
|
1701
|
+
"use strict";
|
|
1702
|
+
init_types();
|
|
1703
|
+
init_diagnostics();
|
|
1704
|
+
init_types();
|
|
1705
|
+
init_diagnostics();
|
|
1706
|
+
STATES = /* @__PURE__ */ new Set(["DENEGADO", "XML_GERADO", "VALIDADO", "ASSINADO", "AUTORIZADO", "REJEITADO", "PENDENTE", "INDETERMINADO", "CONSULTADO", "CANCELADO", "EVENTO_REGISTRADO", "INUTILIZADO", "ERRO"]);
|
|
1707
|
+
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(" "));
|
|
1708
|
+
MAX_BYTES = 8 * 1024 * 1024;
|
|
1709
|
+
MAX_TEARDOWN_MS = 1e3;
|
|
1710
|
+
plain = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
1711
|
+
validContract = (v) => plain(v) && Number.isInteger(v.sourceRevision) && Number(v.sourceRevision) > 0 && typeof v.contractHash === "string" && /^[a-f0-9]{64}$/.test(v.contractHash);
|
|
1712
|
+
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 });
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1647
1715
|
|
|
1648
1716
|
// 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"
|
|
1717
|
+
var OFFLINE_DOCUMENT, OFFLINE_SIGNED_XML;
|
|
1718
|
+
var init_offline_fixture = __esm({
|
|
1719
|
+
"src/offline-fixture.ts"() {
|
|
1720
|
+
"use strict";
|
|
1721
|
+
OFFLINE_DOCUMENT = {
|
|
1722
|
+
"infNFe": {
|
|
1723
|
+
"Versao": "4.00"
|
|
1724
|
+
},
|
|
1725
|
+
"Ide": {
|
|
1726
|
+
"cUF": 23,
|
|
1727
|
+
"cNF": 12345678,
|
|
1728
|
+
"natOp": "VENDA TESTE OFFLINE",
|
|
1729
|
+
"modelo": 55,
|
|
1730
|
+
"serie": 1,
|
|
1731
|
+
"nNF": 1,
|
|
1732
|
+
"dEmi": "2026-10-08T12:00:00",
|
|
1733
|
+
"tpNF": "tnSaida",
|
|
1734
|
+
"idDest": "doInterna",
|
|
1735
|
+
"cMunFG": 2304400,
|
|
1736
|
+
"tpImp": "tiRetrato",
|
|
1737
|
+
"tpEmis": "teNormal",
|
|
1738
|
+
"tpAmb": "taHomologacao",
|
|
1739
|
+
"finNFe": "fnNormal",
|
|
1740
|
+
"indFinal": "cfConsumidorFinal",
|
|
1741
|
+
"indPres": "pcPresencial",
|
|
1742
|
+
"procEmi": "peAplicativoContribuinte",
|
|
1743
|
+
"verProc": "ACBR-NODE-OFFLINE"
|
|
1724
1744
|
},
|
|
1725
|
-
"
|
|
1726
|
-
"
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
"
|
|
1731
|
-
"
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
"
|
|
1745
|
+
"Emit": {
|
|
1746
|
+
"CNPJCPF": "11222333000181",
|
|
1747
|
+
"xNome": "Caf\xE9 S\xE3o Jos\xE9 TESTE OFFLINE SEM VALOR FISCAL",
|
|
1748
|
+
"IE": "123456789",
|
|
1749
|
+
"CRT": "crtSimplesNacional",
|
|
1750
|
+
"EnderEmit": {
|
|
1751
|
+
"xLgr": "RUA TESTE",
|
|
1752
|
+
"nro": "1",
|
|
1753
|
+
"xBairro": "TESTE",
|
|
1754
|
+
"cMun": 2304400,
|
|
1755
|
+
"xMun": "FORTALEZA",
|
|
1756
|
+
"UF": "CE",
|
|
1757
|
+
"CEP": 6e7,
|
|
1758
|
+
"cPais": 1058,
|
|
1759
|
+
"xPais": "BRASIL"
|
|
1735
1760
|
}
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1761
|
+
},
|
|
1762
|
+
"Dest": {
|
|
1763
|
+
"CNPJCPF": "12345678909",
|
|
1764
|
+
"xNome": "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL",
|
|
1765
|
+
"indIEDest": "inNaoContribuinte",
|
|
1766
|
+
"EnderDest": {
|
|
1767
|
+
"xLgr": "RUA TESTE",
|
|
1768
|
+
"nro": "2",
|
|
1769
|
+
"xBairro": "TESTE",
|
|
1770
|
+
"cMun": 2304400,
|
|
1771
|
+
"xMun": "FORTALEZA",
|
|
1772
|
+
"UF": "CE",
|
|
1773
|
+
"CEP": 6e7,
|
|
1774
|
+
"cPais": 1058,
|
|
1775
|
+
"xPais": "BRASIL"
|
|
1776
|
+
}
|
|
1777
|
+
},
|
|
1778
|
+
"Det": [
|
|
1779
|
+
{
|
|
1780
|
+
"Prod": {
|
|
1781
|
+
"nItem": 1,
|
|
1782
|
+
"cProd": "TESTE",
|
|
1783
|
+
"cEAN": "SEM GTIN",
|
|
1784
|
+
"xProd": "Caf\xE9 S\xE3o Jos\xE9 PRODUTO SINT\xC9TICO OFFLINE",
|
|
1785
|
+
"NCM": "22021000",
|
|
1786
|
+
"CFOP": "5102",
|
|
1787
|
+
"uCom": "UN",
|
|
1788
|
+
"qCom": "1",
|
|
1789
|
+
"vUnCom": "10",
|
|
1790
|
+
"vProd": "10",
|
|
1791
|
+
"cEANTrib": "SEM GTIN",
|
|
1792
|
+
"uTrib": "UN",
|
|
1793
|
+
"qTrib": "1",
|
|
1794
|
+
"vUnTrib": "10",
|
|
1795
|
+
"IndTot": "itSomaTotalNFe"
|
|
1796
|
+
},
|
|
1797
|
+
"Imposto": {
|
|
1798
|
+
"ICMS": {
|
|
1799
|
+
"orig": "oeNacional",
|
|
1800
|
+
"CSOSN": "csosn102"
|
|
1801
|
+
},
|
|
1802
|
+
"PIS": {
|
|
1803
|
+
"CST": "pis07"
|
|
1804
|
+
},
|
|
1805
|
+
"COFINS": {
|
|
1806
|
+
"CST": "cof07"
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
],
|
|
1811
|
+
"Total": {
|
|
1812
|
+
"ICMSTot": {
|
|
1813
|
+
"vProd": "10",
|
|
1814
|
+
"vNF": "10"
|
|
1815
|
+
}
|
|
1816
|
+
},
|
|
1817
|
+
"Transp": {
|
|
1818
|
+
"modFrete": "mfSemFrete"
|
|
1819
|
+
},
|
|
1820
|
+
"pag": [
|
|
1821
|
+
{
|
|
1822
|
+
"tPag": "fpDinheiro",
|
|
1823
|
+
"indPag": "ipVista",
|
|
1824
|
+
"vPag": "10"
|
|
1825
|
+
}
|
|
1826
|
+
]
|
|
1827
|
+
};
|
|
1828
|
+
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>';
|
|
1829
|
+
}
|
|
1830
|
+
});
|
|
1757
1831
|
|
|
1758
1832
|
// src/offline-check.ts
|
|
1833
|
+
var offline_check_exports = {};
|
|
1834
|
+
__export(offline_check_exports, {
|
|
1835
|
+
checkOffline: () => checkOffline
|
|
1836
|
+
});
|
|
1759
1837
|
async function checkOffline(config, manifest) {
|
|
1760
1838
|
const emitter = criarEmissor({
|
|
1761
1839
|
cnpj: "11222333000181",
|
|
@@ -1790,11 +1868,246 @@ async function checkOffline(config, manifest) {
|
|
|
1790
1868
|
await emitter.fechar();
|
|
1791
1869
|
}
|
|
1792
1870
|
}
|
|
1871
|
+
var init_offline_check = __esm({
|
|
1872
|
+
"src/offline-check.ts"() {
|
|
1873
|
+
"use strict";
|
|
1874
|
+
init_native_build();
|
|
1875
|
+
init_runtime();
|
|
1876
|
+
init_offline_fixture();
|
|
1877
|
+
}
|
|
1878
|
+
});
|
|
1879
|
+
|
|
1880
|
+
// src/cli.ts
|
|
1881
|
+
import { realpathSync } from "node:fs";
|
|
1882
|
+
import { access as access4 } from "node:fs/promises";
|
|
1883
|
+
import { resolve as resolve4 } from "node:path";
|
|
1884
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1885
|
+
|
|
1886
|
+
// src/contract-help.ts
|
|
1887
|
+
import { createHash } from "node:crypto";
|
|
1888
|
+
import { readFile } from "node:fs/promises";
|
|
1889
|
+
import path from "node:path";
|
|
1890
|
+
|
|
1891
|
+
// generated/acbr/models.ts
|
|
1892
|
+
var ACBR_CONTRACT = { "sourceRevision": 48590, "contractHash": "e5a497cefe8e0e350a30da5cc04e88b35c38a98535893d52f878890260d1346d" };
|
|
1893
|
+
var SOURCE_REVISION = ACBR_CONTRACT.sourceRevision;
|
|
1894
|
+
var CONTRACT_HASH = ACBR_CONTRACT.contractHash;
|
|
1895
|
+
var TACBrProcessoEmissao = Object.freeze({ "peAplicativoContribuinte": "peAplicativoContribuinte", "peAvulsaFisco": "peAvulsaFisco", "peAvulsaContribuinte": "peAvulsaContribuinte", "peContribuinteAplicativoFisco": "peContribuinteAplicativoFisco", "peProvedorAssinaturaAutorizacao": "peProvedorAssinaturaAutorizacao" });
|
|
1896
|
+
var TACBrTipoAmbiente = Object.freeze({ "taProducao": "taProducao", "taHomologacao": "taHomologacao" });
|
|
1897
|
+
var TACBrTipoEmissao = Object.freeze({ "teNormal": "teNormal", "teContingencia": "teContingencia", "teSCAN": "teSCAN", "teDPEC": "teDPEC", "teFSDA": "teFSDA", "teSVCAN": "teSVCAN", "teSVCRS": "teSVCRS", "teSVCSP": "teSVCSP", "teOffLine": "teOffLine" });
|
|
1898
|
+
var TACBrTipoImpressao = Object.freeze({ "tiSemGeracao": "tiSemGeracao", "tiRetrato": "tiRetrato", "tiPaisagem": "tiPaisagem", "tiSimplificado": "tiSimplificado", "tiNFCe": "tiNFCe", "tiMsgEletronica": "tiMsgEletronica", "tiSimplificadoTipo2": "tiSimplificadoTipo2" });
|
|
1899
|
+
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" });
|
|
1900
|
+
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" });
|
|
1901
|
+
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" });
|
|
1902
|
+
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" });
|
|
1903
|
+
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" });
|
|
1904
|
+
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" });
|
|
1905
|
+
var TIndicadorEx = Object.freeze({ "tieNenhum": "tieNenhum", "tieSim": "tieSim", "tieNao": "tieNao" });
|
|
1906
|
+
var TindIEDest = Object.freeze({ "inContribuinte": "inContribuinte", "inIsento": "inIsento", "inNaoContribuinte": "inNaoContribuinte" });
|
|
1907
|
+
var TindImport = Object.freeze({ "iiNacional": "iiNacional", "iiImportado": "iiImportado" });
|
|
1908
|
+
var TindIncentivo = Object.freeze({ "iiSim": "iiSim", "iiNao": "iiNao" });
|
|
1909
|
+
var TindIntermed = Object.freeze({ "iiSemOperacao": "iiSemOperacao", "iiOperacaoSemIntermediador": "iiOperacaoSemIntermediador", "iiOperacaoComIntermediador": "iiOperacaoComIntermediador" });
|
|
1910
|
+
var TIndSomaCOFINSST = Object.freeze({ "iscNenhum": "iscNenhum", "iscCOFINSSTNaoCompoe": "iscCOFINSSTNaoCompoe", "iscCOFINSSTCompoe": "iscCOFINSSTCompoe" });
|
|
1911
|
+
var TIndSomaPISST = Object.freeze({ "ispNenhum": "ispNenhum", "ispPISSTNaoCompoe": "ispPISSTNaoCompoe", "ispPISSTCompoe": "ispPISSTCompoe" });
|
|
1912
|
+
var TmotRedAdRem = Object.freeze({ "motTranspColetivo": "motTranspColetivo", "motOutros": "motOutros" });
|
|
1913
|
+
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" });
|
|
1914
|
+
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" });
|
|
1915
|
+
var TpcnCondicaoVeiculo = Object.freeze({ "cvAcabado": "cvAcabado", "cvInacabado": "cvInacabado", "cvSemiAcabado": "cvSemiAcabado" });
|
|
1916
|
+
var TpcnConsumidorFinal = Object.freeze({ "cfNao": "cfNao", "cfConsumidorFinal": "cfConsumidorFinal" });
|
|
1917
|
+
var TpcnCRT = Object.freeze({ "crtSimplesNacional": "crtSimplesNacional", "crtSimplesExcessoReceita": "crtSimplesExcessoReceita", "crtRegimeNormal": "crtRegimeNormal", "crtMEI": "crtMEI" });
|
|
1918
|
+
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" });
|
|
1919
|
+
var TpcnDestinoOperacao = Object.freeze({ "doInterna": "doInterna", "doInterestadual": "doInterestadual", "doExterior": "doExterior" });
|
|
1920
|
+
var TpcnDeterminacaoBaseIcms = Object.freeze({ "dbiMargemValorAgregado": "dbiMargemValorAgregado", "dbiPauta": "dbiPauta", "dbiPrecoTabelado": "dbiPrecoTabelado", "dbiValorOperacao": "dbiValorOperacao", "dbiNenhum": "dbiNenhum" });
|
|
1921
|
+
var TpcnDeterminacaoBaseIcmsST = Object.freeze({ "dbisPrecoTabelado": "dbisPrecoTabelado", "dbisListaNegativa": "dbisListaNegativa", "dbisListaPositiva": "dbisListaPositiva", "dbisListaNeutra": "dbisListaNeutra", "dbisMargemValorAgregado": "dbisMargemValorAgregado", "dbisPauta": "dbisPauta", "dbisValordaOperacao": "dbisValordaOperacao" });
|
|
1922
|
+
var TpcnECFModRef = Object.freeze({ "ECFModRefVazio": "ECFModRefVazio", "ECFModRef2B": "ECFModRef2B", "ECFModRef2C": "ECFModRef2C", "ECFModRef2D": "ECFModRef2D" });
|
|
1923
|
+
var TpcnFinalidadeNFe = Object.freeze({ "fnNormal": "fnNormal", "fnComplementar": "fnComplementar", "fnAjuste": "fnAjuste", "fnDevolucao": "fnDevolucao", "fnCredito": "fnCredito", "fnDebito": "fnDebito" });
|
|
1924
|
+
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" });
|
|
1925
|
+
var TpcnIndEscala = Object.freeze({ "ieRelevante": "ieRelevante", "ieNaoRelevante": "ieNaoRelevante", "ieNenhum": "ieNenhum" });
|
|
1926
|
+
var TpcnIndicadorPagamento = Object.freeze({ "ipVista": "ipVista", "ipPrazo": "ipPrazo", "ipOutras": "ipOutras", "ipNenhum": "ipNenhum" });
|
|
1927
|
+
var TpcnIndicadorProcesso = Object.freeze({ "ipSEFAZ": "ipSEFAZ", "ipJusticaFederal": "ipJusticaFederal", "ipJusticaEstadual": "ipJusticaEstadual", "ipSecexRFB": "ipSecexRFB", "ipCONFAZ": "ipCONFAZ", "ipOutros": "ipOutros" });
|
|
1928
|
+
var TpcnIndicadorTotal = Object.freeze({ "itSomaTotalNFe": "itSomaTotalNFe", "itNaoSomaTotalNFe": "itNaoSomaTotalNFe" });
|
|
1929
|
+
var TpcnindISS = Object.freeze({ "iiExigivel": "iiExigivel", "iiNaoIncidencia": "iiNaoIncidencia", "iiIsencao": "iiIsencao", "iiExportacao": "iiExportacao", "iiImunidade": "iiImunidade", "iiExigSuspDecisaoJudicial": "iiExigSuspDecisaoJudicial", "iiExigSuspProcessoAdm": "iiExigSuspProcessoAdm" });
|
|
1930
|
+
var TpcnindISSRet = Object.freeze({ "iirSim": "iirSim", "iirNao": "iirNao" });
|
|
1931
|
+
var TpcnISSQNcSitTrib = Object.freeze({ "ISSQNcSitTribVazio": "ISSQNcSitTribVazio", "ISSQNcSitTribNORMAL": "ISSQNcSitTribNORMAL", "ISSQNcSitTribRETIDA": "ISSQNcSitTribRETIDA", "ISSQNcSitTribSUBSTITUTA": "ISSQNcSitTribSUBSTITUTA", "ISSQNcSitTribISENTA": "ISSQNcSitTribISENTA" });
|
|
1932
|
+
var TpcnModalidadeFrete = Object.freeze({ "mfContaEmitente": "mfContaEmitente", "mfContaDestinatario": "mfContaDestinatario", "mfContaTerceiros": "mfContaTerceiros", "mfProprioRemetente": "mfProprioRemetente", "mfProprioDestinatario": "mfProprioDestinatario", "mfSemFrete": "mfSemFrete" });
|
|
1933
|
+
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" });
|
|
1934
|
+
var TpcnPresencaComprador = Object.freeze({ "pcNao": "pcNao", "pcPresencial": "pcPresencial", "pcInternet": "pcInternet", "pcTeleatendimento": "pcTeleatendimento", "pcEntregaDomicilio": "pcEntregaDomicilio", "pcPresencialForaEstabelecimento": "pcPresencialForaEstabelecimento", "pcOutros": "pcOutros" });
|
|
1935
|
+
var TpcnTipoArma = Object.freeze({ "taUsoPermitido": "taUsoPermitido", "taUsoRestrito": "taUsoRestrito" });
|
|
1936
|
+
var TpcnTipoIntermedio = Object.freeze({ "tiContaPropria": "tiContaPropria", "tiContaOrdem": "tiContaOrdem", "tiEncomenda": "tiEncomenda" });
|
|
1937
|
+
var TpcnTipoOperacao = Object.freeze({ "toVendaConcessionaria": "toVendaConcessionaria", "toFaturamentoDireto": "toFaturamentoDireto", "toVendaDireta": "toVendaDireta", "toOutros": "toOutros" });
|
|
1938
|
+
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" });
|
|
1939
|
+
var TRegTribISSQN = Object.freeze({ "RTISSMicroempresaMunicipal": "RTISSMicroempresaMunicipal", "RTISSEstimativa": "RTISSEstimativa", "RTISSSociedadeProfissionais": "RTISSSociedadeProfissionais", "RTISSCooperativa": "RTISSCooperativa", "RTISSMEI": "RTISSMEI", "RTISSMEEPP": "RTISSMEEPP", "RTISSNenhum": "RTISSNenhum" });
|
|
1940
|
+
var TTipoNFe = Object.freeze({ "tnEntrada": "tnEntrada", "tnSaida": "tnSaida" });
|
|
1941
|
+
var TtpALCZFMCBS = Object.freeze({ "tpALCZFMCBSnOpInd": "tpALCZFMCBSnOpInd", "tpALCZFMCBSOpInd": "tpALCZFMCBSOpInd" });
|
|
1942
|
+
var TtpAto = Object.freeze({ "taNenhum": "taNenhum", "taTermoAcordo": "taTermoAcordo", "taRegimeEspecial": "taRegimeEspecial", "taAutorizacaoEspecifica": "taAutorizacaoEspecifica", "taAjusteSNIEF": "taAjusteSNIEF", "taConvenioICMS": "taConvenioICMS" });
|
|
1943
|
+
var TTpCredPresIBSZFM = Object.freeze({ "tcpNenhum": "tcpNenhum", "tcpSemCredito": "tcpSemCredito", "tcpBensConsumoFinal": "tcpBensConsumoFinal", "tcpBensCapital": "tcpBensCapital", "tcpBensIntermediarios": "tcpBensIntermediarios", "tcpBensInformaticaOutros": "tcpBensInformaticaOutros" });
|
|
1944
|
+
var TtpEnteGov = Object.freeze({ "tcgNenhum": "tcgNenhum", "tcgUniao": "tcgUniao", "tcgEstados": "tcgEstados", "tcgDistritoFederal": "tcgDistritoFederal", "tcgMunicipios": "tcgMunicipios", "tcgConsorcioPublico": "tcgConsorcioPublico", "tcgComiteGestorIBS": "tcgComiteGestorIBS" });
|
|
1945
|
+
var TtpGuia = Object.freeze({ "tpgNenhum": "tpgNenhum", "tpgGTA": "tpgGTA", "tpgTTA": "tpgTTA", "tpgDTA": "tpgDTA", "tpgATV": "tpgATV", "tpgPTV": "tpgPTV", "tpgGTV": "tpgGTV", "tpgGuiaFlorestal": "tpgGuiaFlorestal" });
|
|
1946
|
+
var TtpIntegra = Object.freeze({ "tiNaoInformado": "tiNaoInformado", "tiPagIntegrado": "tiPagIntegrado", "tiPagNaoIntegrado": "tiPagNaoIntegrado" });
|
|
1947
|
+
var TtpNFCredito = Object.freeze({ "tcNenhum": "tcNenhum", "tcMultaJuros": "tcMultaJuros", "tcApropriacaoCreditoPresumido": "tcApropriacaoCreditoPresumido", "tcRetorno": "tcRetorno", "tcReducaoValores": "tcReducaoValores", "tcTransferenciaCreditoSucessao": "tcTransferenciaCreditoSucessao", "tcRetornoRecusaParcial": "tcRetornoRecusaParcial" });
|
|
1948
|
+
var TtpNFDebito = Object.freeze({ "tdNenhum": "tdNenhum", "tdTransferenciaCreditoCooperativa": "tdTransferenciaCreditoCooperativa", "tdAnulacao": "tdAnulacao", "tdDebitosNaoProcessadas": "tdDebitosNaoProcessadas", "tdMultaJuros": "tdMultaJuros", "tdTransferenciaCreditoSucessao": "tdTransferenciaCreditoSucessao", "tdPagamentoAntecipado": "tdPagamentoAntecipado", "tdPerdaEmEstoque": "tdPerdaEmEstoque", "tdDesenquadramentodoSN": "tdDesenquadramentodoSN" });
|
|
1949
|
+
var TtpOperGov = Object.freeze({ "togNenhum": "togNenhum", "togFornecimento": "togFornecimento", "togRecebimentoPag": "togRecebimentoPag", "togFornecimentoPagRealizado": "togFornecimentoPagRealizado", "togRecebimentoPagFornecPosterior": "togRecebimentoPagFornecPosterior" });
|
|
1950
|
+
|
|
1951
|
+
// src/contract-help.ts
|
|
1952
|
+
var FieldHelpError = class extends Error {
|
|
1953
|
+
constructor(code, message, details) {
|
|
1954
|
+
super(message);
|
|
1955
|
+
this.code = code;
|
|
1956
|
+
this.details = details;
|
|
1957
|
+
this.name = "FieldHelpError";
|
|
1958
|
+
}
|
|
1959
|
+
};
|
|
1960
|
+
var kinds = /* @__PURE__ */ new Set(["string", "integer", "decimal", "datetime", "boolean", "enum", "object", "list"]);
|
|
1961
|
+
var identifier = /^[A-Za-z_]\w*$/;
|
|
1962
|
+
var sha256 = /^[a-f0-9]{64}$/;
|
|
1963
|
+
var fail = (message = "Os metadados do contrato s\xE3o inv\xE1lidos.") => {
|
|
1964
|
+
throw new FieldHelpError("CONTRATO_INVALIDO", message);
|
|
1965
|
+
};
|
|
1966
|
+
function validateContractMetadata(value) {
|
|
1967
|
+
const metadata = value;
|
|
1968
|
+
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();
|
|
1969
|
+
const digest = createHash("sha256").update(JSON.stringify({ sourceRevision: metadata.sourceRevision, sourceHash: metadata.sourceHash, ir: metadata.ir })).digest("hex");
|
|
1970
|
+
if (digest !== metadata.contractHash) fail("O hash dos metadados diverge do contrato gerado.");
|
|
1971
|
+
const types = /* @__PURE__ */ new Map();
|
|
1972
|
+
for (const node of metadata.ir.types) {
|
|
1973
|
+
if (!node || typeof node.name !== "string" || !identifier.test(node.name) || types.has(node.name) || !["object", "list", "enum"].includes(node.kind)) fail();
|
|
1974
|
+
types.set(node.name, node);
|
|
1975
|
+
}
|
|
1976
|
+
if (types.get(metadata.ir.root)?.kind !== "object") fail();
|
|
1977
|
+
for (const node of types.values()) {
|
|
1978
|
+
if (node.kind === "enum") {
|
|
1979
|
+
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();
|
|
1980
|
+
} else if (node.kind === "list") {
|
|
1981
|
+
if (!node.item || types.get(node.item)?.kind !== "object") fail();
|
|
1982
|
+
} else {
|
|
1983
|
+
if (!Array.isArray(node.properties)) fail();
|
|
1984
|
+
const names = /* @__PURE__ */ new Set();
|
|
1985
|
+
for (const property of node.properties) {
|
|
1986
|
+
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();
|
|
1987
|
+
names.add(property.name.toLowerCase());
|
|
1988
|
+
if (["object", "list", "enum"].includes(property.kind) && (!property.ref || types.get(property.ref)?.kind !== property.kind)) fail();
|
|
1989
|
+
if (!["object", "list", "enum"].includes(property.kind) && property.ref !== void 0) fail();
|
|
1990
|
+
if (property.declaredDefault !== void 0 && typeof property.declaredDefault !== "string") fail();
|
|
1991
|
+
for (const key of ["min", "max", "scale"]) if (property[key] !== void 0 && !Number.isFinite(property[key])) fail();
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
return metadata;
|
|
1996
|
+
}
|
|
1997
|
+
function matchingPaths(types, root, field) {
|
|
1998
|
+
const paths = [];
|
|
1999
|
+
let incomplete = false;
|
|
2000
|
+
function visit(name, prefix, trail) {
|
|
2001
|
+
if (trail.has(name) || trail.size > 128 || paths.length > 1e3) {
|
|
2002
|
+
incomplete = true;
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
const node = types.get(name);
|
|
2006
|
+
const next = new Set(trail).add(name);
|
|
2007
|
+
if (node.kind === "list") {
|
|
2008
|
+
visit(node.item, prefix + "[]", next);
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
if (node.kind !== "object") return;
|
|
2012
|
+
for (const property of node.properties) {
|
|
2013
|
+
const candidate = prefix ? prefix + "." + property.name : property.name;
|
|
2014
|
+
if (property.name === field) paths.push(candidate);
|
|
2015
|
+
if (property.ref && property.kind !== "enum") visit(property.ref, candidate, next);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
visit(root, "", /* @__PURE__ */ new Set());
|
|
2019
|
+
if (incomplete) throw new FieldHelpError("CAMINHO_COMPLETO_NECESSARIO", "O contrato cont\xE9m caminhos recursivos ou extensos. Informe o caminho completo.");
|
|
2020
|
+
return paths.sort();
|
|
2021
|
+
}
|
|
2022
|
+
function describeField(metadata, sdkVersion, query) {
|
|
2023
|
+
validateContractMetadata(metadata);
|
|
2024
|
+
if (typeof query !== "string" || query.length > 512 || !/^[A-Za-z_]\w*(?:\[(?:\d*)\])?(?:\.[A-Za-z_]\w*(?:\[(?:\d*)\])?)*$/.test(query))
|
|
2025
|
+
throw new FieldHelpError("CAMINHO_INVALIDO", "Use nomes de campos separados por ponto e [] para elementos de cole\xE7\xE3o.");
|
|
2026
|
+
const types = new Map(metadata.ir.types.map((node2) => [node2.name, node2]));
|
|
2027
|
+
const root = metadata.ir.root;
|
|
2028
|
+
const base = { formatVersion: 1, sdkVersion, sourceRevision: metadata.sourceRevision, sourceHash: metadata.sourceHash, contractHash: metadata.contractHash, root };
|
|
2029
|
+
let relative3 = query === root ? "" : query.startsWith(root + ".") ? query.slice(root.length + 1) : query;
|
|
2030
|
+
if (identifier.test(relative3) && !types.get(root).properties.some((property2) => property2.name === relative3)) {
|
|
2031
|
+
const matches = matchingPaths(types, root, relative3);
|
|
2032
|
+
if (matches.length > 1) throw new FieldHelpError("CAMPO_AMBIGUO", "O nome aparece em mais de um caminho. Informe o caminho completo.", { candidates: matches });
|
|
2033
|
+
if (matches.length === 1) relative3 = matches[0];
|
|
2034
|
+
}
|
|
2035
|
+
let node = types.get(root);
|
|
2036
|
+
let property;
|
|
2037
|
+
let readonly = false;
|
|
2038
|
+
const canonical = [];
|
|
2039
|
+
const parts = relative3 ? relative3.split(".") : [];
|
|
2040
|
+
for (let index = 0; index < parts.length; index++) {
|
|
2041
|
+
const segment = parts[index];
|
|
2042
|
+
const parsed = /^([A-Za-z_]\w*)(\[(?:\d*)\])?$/.exec(segment);
|
|
2043
|
+
if (node.kind !== "object") throw new FieldHelpError("CAMINHO_INVALIDO", "O caminho tenta acessar um campo de um valor simples.");
|
|
2044
|
+
property = node.properties.find((item) => item.name === parsed[1]);
|
|
2045
|
+
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) });
|
|
2046
|
+
readonly ||= property.readonly;
|
|
2047
|
+
canonical.push(property.name);
|
|
2048
|
+
const selected = parsed[2] !== void 0;
|
|
2049
|
+
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.");
|
|
2050
|
+
if (property.kind === "list") {
|
|
2051
|
+
node = types.get(property.ref);
|
|
2052
|
+
if (selected) {
|
|
2053
|
+
canonical[canonical.length - 1] += "[]";
|
|
2054
|
+
node = types.get(node.item);
|
|
2055
|
+
} 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.");
|
|
2056
|
+
} else if (property.ref) node = types.get(property.ref);
|
|
2057
|
+
else if (index < parts.length - 1) throw new FieldHelpError("CAMINHO_INVALIDO", "Um valor simples n\xE3o cont\xE9m outros campos.");
|
|
2058
|
+
}
|
|
2059
|
+
const selectedListItem = property?.kind === "list" && canonical[canonical.length - 1]?.endsWith("[]");
|
|
2060
|
+
const kind = selectedListItem ? "object" : property?.kind ?? "object";
|
|
2061
|
+
const description = {
|
|
2062
|
+
...base,
|
|
2063
|
+
path: [root, ...canonical].join("."),
|
|
2064
|
+
kind,
|
|
2065
|
+
pascalType: selectedListItem ? node.name : property?.type ?? node.name,
|
|
2066
|
+
inputType: kind === "integer" ? "number" : kind === "boolean" ? "boolean" : kind === "object" ? "object" : kind === "list" ? "array" : "string",
|
|
2067
|
+
readonly
|
|
2068
|
+
};
|
|
2069
|
+
if (property?.declaredDefault !== void 0) description.declaredDefault = property.declaredDefault;
|
|
2070
|
+
if (property?.ref) description.typeReference = selectedListItem ? node.name : property.ref;
|
|
2071
|
+
if (kind === "enum") description.values = [...node.values];
|
|
2072
|
+
const constraints = property && Object.fromEntries(["min", "max", "scale"].filter((key) => property[key] !== void 0).map((key) => [key, property[key]]));
|
|
2073
|
+
if (constraints && Object.keys(constraints).length) description.constraints = constraints;
|
|
2074
|
+
if (kind === "list") description.itemType = node.item;
|
|
2075
|
+
if (kind === "object") description.members = node.properties.map((item) => ({ name: item.name, kind: item.kind, pascalType: item.type, readonly: readonly || item.readonly }));
|
|
2076
|
+
return description;
|
|
2077
|
+
}
|
|
2078
|
+
async function describeInstalledField(query, packageRoot) {
|
|
2079
|
+
let metadata, pkg, lock;
|
|
2080
|
+
try {
|
|
2081
|
+
[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"))));
|
|
2082
|
+
} catch {
|
|
2083
|
+
throw new FieldHelpError("CONTRATO_INDISPONIVEL", "Os metadados empacotados n\xE3o est\xE3o dispon\xEDveis. Reinstale o pacote ou gere e compile o checkout.");
|
|
2084
|
+
}
|
|
2085
|
+
validateContractMetadata(metadata);
|
|
2086
|
+
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)
|
|
2087
|
+
throw new FieldHelpError("CONTRATO_INCOMPATIVEL", "Os metadados divergem da vers\xE3o instalada, do lock ou do validador gerado.");
|
|
2088
|
+
return describeField(metadata, pkg.version, query);
|
|
2089
|
+
}
|
|
2090
|
+
function formatFieldDescription(description) {
|
|
2091
|
+
const lines = [
|
|
2092
|
+
description.path,
|
|
2093
|
+
`Tipo: ${description.pascalType}${description.typeReference && description.typeReference !== description.pascalType ? ` [${description.typeReference}]` : ""} (${description.kind}; entrada ${description.inputType})`,
|
|
2094
|
+
`Somente leitura: ${description.readonly ? "sim" : "n\xE3o"}`
|
|
2095
|
+
];
|
|
2096
|
+
if (description.values) lines.push(`Valores permitidos na API: ${description.values.join(", ")}`);
|
|
2097
|
+
if (description.declaredDefault !== void 0) lines.push(`Padr\xE3o declarado no Pascal: ${description.declaredDefault} (n\xE3o substitui regras fiscais ou o construtor nativo).`);
|
|
2098
|
+
if (description.constraints) lines.push(`Limites do tipo: ${JSON.stringify(description.constraints)}`);
|
|
2099
|
+
if (description.itemType) lines.push(`Tipo do elemento: ${description.itemType}`);
|
|
2100
|
+
if (description.members) lines.push(`Campos: ${description.members.map((member) => member.name).join(", ")}`);
|
|
2101
|
+
lines.push(`SDK: ${description.sdkVersion}; revis\xE3o ACBr: ${description.sourceRevision}`, `Contrato: ${description.contractHash}`);
|
|
2102
|
+
return lines.join("\n");
|
|
2103
|
+
}
|
|
1793
2104
|
|
|
1794
2105
|
// src/cli.ts
|
|
1795
2106
|
var HELP = `acbr-node \u2014 compila\xE7\xE3o e contrato Node/ACBr NF-e
|
|
1796
2107
|
|
|
1797
2108
|
Uso:
|
|
2109
|
+
acbr-node help TAG Ide.tpNF [--json]
|
|
2110
|
+
acbr-node help TAG 'Det[].Imposto.PIS.CST' [--json]
|
|
1798
2111
|
acbr-node init [--config caminho] [--revision HEAD|n\xFAmero]
|
|
1799
2112
|
acbr-node source update [--config caminho] [--revision HEAD|n\xFAmero]
|
|
1800
2113
|
acbr-node source lock --revision n\xFAmero [--config caminho]
|
|
@@ -1806,6 +2119,7 @@ Uso:
|
|
|
1806
2119
|
source update consulta o SVN oficial e substitui apenas fontes verificadas pelo lock.
|
|
1807
2120
|
source lock registra um export existente cuja origem/revis\xE3o o operador j\xE1 conferiu.
|
|
1808
2121
|
generate/build/check nunca atualizam fontes. Nenhum comando transmite NF-e.
|
|
2122
|
+
help TAG consulta somente o contrato da vers\xE3o instalada, offline e sem runtime ou certificado.
|
|
1809
2123
|
`;
|
|
1810
2124
|
function revision(value) {
|
|
1811
2125
|
if (value === void 0) return void 0;
|
|
@@ -1835,9 +2149,17 @@ function parseArguments(args) {
|
|
|
1835
2149
|
}
|
|
1836
2150
|
return result;
|
|
1837
2151
|
}
|
|
1838
|
-
async function main(args = process.argv.slice(2), io = process) {
|
|
2152
|
+
async function main(args = process.argv.slice(2), io = process, dependencies = {}) {
|
|
2153
|
+
const initialCommand = args.filter((arg) => !["--json", "--help", "-h"].includes(arg));
|
|
2154
|
+
let jsonTag = args.includes("--json") && initialCommand[0]?.toLowerCase() === "help" && initialCommand[1]?.toLowerCase() === "tag";
|
|
1839
2155
|
try {
|
|
1840
|
-
|
|
2156
|
+
let options;
|
|
2157
|
+
try {
|
|
2158
|
+
options = parseArguments(args);
|
|
2159
|
+
} catch (error) {
|
|
2160
|
+
if (jsonTag) throw new FieldHelpError("USO_INVALIDO", "Argumentos inv\xE1lidos. Use acbr-node help TAG caminho [--json].");
|
|
2161
|
+
throw error;
|
|
2162
|
+
}
|
|
1841
2163
|
const command = options.command.join(" ");
|
|
1842
2164
|
if (options.help || !command) {
|
|
1843
2165
|
io.stdout.write(HELP);
|
|
@@ -1846,8 +2168,17 @@ async function main(args = process.argv.slice(2), io = process) {
|
|
|
1846
2168
|
const output = (value, text) => io.stdout.write(options.json ? `${JSON.stringify(value, null, 2)}
|
|
1847
2169
|
` : `${text}
|
|
1848
2170
|
`);
|
|
2171
|
+
if (options.command[0]?.toLowerCase() === "help" && options.command[1]?.toLowerCase() === "tag") {
|
|
2172
|
+
jsonTag = options.json;
|
|
2173
|
+
if (options.command.length !== 3) throw new FieldHelpError("USO_INVALIDO", "Use acbr-node help TAG caminho [--json].");
|
|
2174
|
+
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.");
|
|
2175
|
+
const description = await describeInstalledField(options.command[2], dependencies.contractRoot ?? fileURLToPath3(new URL("../", import.meta.url)));
|
|
2176
|
+
output(description, formatFieldDescription(description));
|
|
2177
|
+
return 0;
|
|
2178
|
+
}
|
|
1849
2179
|
if (command === "init") {
|
|
1850
|
-
const
|
|
2180
|
+
const { initializeConfig: initializeConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2181
|
+
const config2 = await initializeConfig2(options.config, options.revision, fileURLToPath3(new URL("../", import.meta.url)));
|
|
1851
2182
|
output({ configPath: config2.configPath }, `Configura\xE7\xE3o criada: ${config2.configPath}
|
|
1852
2183
|
Pr\xF3ximo passo: acbr-node source update.`);
|
|
1853
2184
|
return 0;
|
|
@@ -1855,46 +2186,61 @@ Pr\xF3ximo passo: acbr-node source update.`);
|
|
|
1855
2186
|
if (!["source update", "source lock", "generate", "build", "check", "doctor"].includes(command)) throw new Error(`Comando desconhecido: ${command}. Use --help.`);
|
|
1856
2187
|
if (options.revision !== void 0 && !command.startsWith("source ")) throw new Error("--revision \xE9 aceito somente em init e source.");
|
|
1857
2188
|
if (command === "doctor") {
|
|
2189
|
+
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2190
|
+
const { doctor: doctor2 } = await Promise.resolve().then(() => (init_native_build(), native_build_exports));
|
|
1858
2191
|
let config2;
|
|
1859
2192
|
try {
|
|
1860
2193
|
await access4(resolve4(options.config));
|
|
1861
|
-
config2 = await
|
|
2194
|
+
config2 = await loadConfig3(options.config);
|
|
1862
2195
|
} catch (error) {
|
|
1863
2196
|
if (error.code !== "ENOENT") throw error;
|
|
1864
2197
|
}
|
|
1865
|
-
const report = await
|
|
2198
|
+
const report = await doctor2(config2);
|
|
1866
2199
|
output(report, report.map((item) => `${item.ok ? "OK" : "FALHA"} ${item.name}: ${item.detail}`).join("\n"));
|
|
1867
2200
|
return report.every((item) => item.ok) ? 0 : 1;
|
|
1868
2201
|
}
|
|
1869
|
-
const
|
|
2202
|
+
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2203
|
+
const config = await loadConfig2(options.config);
|
|
1870
2204
|
if (command === "source update") {
|
|
1871
|
-
const
|
|
2205
|
+
const { updateSource: updateSource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
2206
|
+
const lock = await updateSource2(config, options.revision);
|
|
1872
2207
|
output(lock, `Fontes oficiais registradas na revis\xE3o ${lock.source.revision}.
|
|
1873
2208
|
SHA256 da \xE1rvore: ${lock.source.treeHash}
|
|
1874
2209
|
Execute generate para atualizar o contrato.`);
|
|
1875
2210
|
} else if (command === "source lock") {
|
|
2211
|
+
const { lockExistingSource: lockExistingSource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
1876
2212
|
if (typeof options.revision !== "number") throw new Error("source lock exige --revision com o n\xFAmero verificado do export SVN.");
|
|
1877
2213
|
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
|
|
2214
|
+
const lock = await lockExistingSource2(config, options.revision);
|
|
1879
2215
|
output(lock, `Export existente registrado na revis\xE3o ${lock.source.revision}; ${Object.keys(lock.source.files).length} arquivos protegidos por SHA256.`);
|
|
1880
2216
|
} else if (command === "generate") {
|
|
1881
|
-
const
|
|
2217
|
+
const { verifySource: verifySource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
2218
|
+
const lock = await verifySource2(config);
|
|
1882
2219
|
const { generateModel: generateModel2 } = await Promise.resolve().then(() => (init_generator(), generator_exports));
|
|
1883
2220
|
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
2221
|
output(result, `Contrato ${result.contractHash}; ${result.models} modelos gerados.
|
|
1885
2222
|
Revise o relat\xF3rio: ${result.reportPath}`);
|
|
1886
2223
|
} else if (command === "build") {
|
|
1887
|
-
const
|
|
1888
|
-
|
|
2224
|
+
const { buildNative: buildNative2, runtimeDirectory: runtimeDirectory2 } = await Promise.resolve().then(() => (init_native_build(), native_build_exports));
|
|
2225
|
+
const result = await buildNative2(config);
|
|
2226
|
+
output(result, `Runtime compilado: ${runtimeDirectory2(config)}
|
|
1889
2227
|
ACBr revis\xE3o ${result.sourceRevision}; contrato ${result.contractHash}.`);
|
|
1890
2228
|
} else {
|
|
1891
|
-
const
|
|
1892
|
-
const
|
|
2229
|
+
const { checkBuild: checkBuild2 } = await Promise.resolve().then(() => (init_native_build(), native_build_exports));
|
|
2230
|
+
const { checkOffline: checkOffline2 } = await Promise.resolve().then(() => (init_offline_check(), offline_check_exports));
|
|
2231
|
+
const result = await checkBuild2(config);
|
|
2232
|
+
const offlineChecks = await checkOffline2(config, result);
|
|
1893
2233
|
output({ ...result, offlineChecks }, `Fontes, contrato e ${Object.keys(result.files).length} arquivos do runtime conferidos por SHA256.
|
|
1894
2234
|
${offlineChecks.length} verifica\xE7\xF5es offline do motor aprovadas; nenhuma transmiss\xE3o.`);
|
|
1895
2235
|
}
|
|
1896
2236
|
return 0;
|
|
1897
2237
|
} catch (error) {
|
|
2238
|
+
if (jsonTag) {
|
|
2239
|
+
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." };
|
|
2240
|
+
io.stderr.write(`${JSON.stringify({ ok: false, error: problem }, null, 2)}
|
|
2241
|
+
`);
|
|
2242
|
+
return 1;
|
|
2243
|
+
}
|
|
1898
2244
|
io.stderr.write(`Erro: ${error.message}
|
|
1899
2245
|
`);
|
|
1900
2246
|
return 1;
|