cosmemilton-acbr-node 0.1.0 → 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 +1511 -895
- package/dist/cli.js.map +4 -4
- package/dist/contract.json +1 -0
- package/dist/index.cjs +320 -46
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +317 -46
- package/dist/index.js.map +4 -4
- package/dist/runtime.cjs +254 -35
- package/dist/runtime.cjs.map +3 -3
- package/dist/runtime.js +251 -34
- package/dist/runtime.js.map +3 -3
- package/dist/types/generated/acbr/index.d.ts +15 -1
- package/dist/types/generated/acbr/models.d.ts +32 -0
- package/dist/types/src/cli.d.ts +4 -2
- package/dist/types/src/contract-help.d.ts +53 -0
- package/dist/types/src/diagnostics.d.ts +8 -0
- package/dist/types/src/generator.d.ts +3 -0
- package/dist/types/src/index.d.ts +13 -0
- package/dist/types/src/runtime.d.ts +1 -0
- package/dist/types/src/types.d.ts +34 -1
- package/docs/API.md +58 -0
- package/docs/CI.md +6 -0
- package/docs/CLI.md +52 -32
- package/docs/VALIDACAO.md +3 -1
- package/package.json +6 -4
package/dist/cli.js
CHANGED
|
@@ -9,612 +9,282 @@ 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
|
-
|
|
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
|
|
21
21
|
});
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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}]`));
|
|
37
62
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (found.type.kind === "alias") {
|
|
43
|
-
trail.add(key);
|
|
44
|
-
return resolve5(found.type.target, found.unit, trail);
|
|
45
|
-
}
|
|
46
|
-
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}]`));
|
|
47
67
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!values.length) throw new Error("Enum sem valores: " + key);
|
|
63
|
-
generated.set(key, { name: key, unit: declUnit.name, kind: "enum", values });
|
|
64
|
-
return { kind: "enum", ref: key };
|
|
65
|
-
}
|
|
66
|
-
if (type.kind !== "class") throw new Error("Declara\xE7\xE3o Pascal n\xE3o suportada: " + declUnit.name + "." + key + " (" + (type.declarationKind ?? type.kind) + ")");
|
|
67
|
-
const creator = type.methods?.find((m) => m.name.toLowerCase() === "new" && m.arguments === 0);
|
|
68
|
-
const indexed = type.properties?.find((p) => p.indexed && p.name.toLowerCase() === "items");
|
|
69
|
-
if (creator || indexed) {
|
|
70
|
-
if (!creator || !indexed || !indexed.readable) throw new Error("Cole\xE7\xE3o sem contrato New/Items tipado: " + key);
|
|
71
|
-
const item = resolve5(creator.result, declUnit), itemProperty = resolve5(indexed.type, declUnit);
|
|
72
|
-
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);
|
|
73
|
-
generated.set(key, { name: key, unit: declUnit.name, kind: "list", item: item.type.name, factory: creator.name });
|
|
74
|
-
if (visit(creator.result, declUnit).kind !== "object") throw new Error("Item de cole\xE7\xE3o n\xE3o \xE9 objeto: " + key);
|
|
75
|
-
return { kind: "list", ref: key };
|
|
76
|
-
}
|
|
77
|
-
const node = { name: key, unit: declUnit.name, kind: "object", properties: [] };
|
|
78
|
-
generated.set(key, node);
|
|
79
|
-
let inherited = [];
|
|
80
|
-
if (type.ancestor && !bases.has(type.ancestor.toLowerCase())) {
|
|
81
|
-
const ancestor = visit(type.ancestor, declUnit);
|
|
82
|
-
if (ancestor.kind !== "object") throw new Error("Heran\xE7a n\xE3o suportada: " + key);
|
|
83
|
-
inherited = generated.get(ancestor.ref).properties;
|
|
84
|
-
}
|
|
85
|
-
const props = new Map(inherited.map((p) => [p.name.toLowerCase(), p]));
|
|
86
|
-
for (const p of type.properties ?? []) {
|
|
87
|
-
if (p.indexed) throw new Error("Propriedade indexada fora de cole\xE7\xE3o: " + key + "." + p.name);
|
|
88
|
-
if (!p.readable) throw new Error("Propriedade sem leitura: " + key + "." + p.name);
|
|
89
|
-
const resolved = visit(p.type, declUnit);
|
|
90
|
-
const readonly = !p.writable && !["object", "list"].includes(resolved.kind) || key === raw.root && ["signature", "procnfe", "infnfesupl"].includes(p.name.toLowerCase());
|
|
91
|
-
props.set(p.name.toLowerCase(), { name: p.name, type: p.type, ...resolved, readonly, ...p.default ? { declaredDefault: p.default } : {} });
|
|
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 } : {}
|
|
92
82
|
}
|
|
93
|
-
|
|
94
|
-
|
|
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 });
|
|
95
92
|
}
|
|
96
|
-
|
|
97
|
-
|
|
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);
|
|
98
100
|
}
|
|
99
|
-
function
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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) });
|
|
107
130
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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;
|
|
111
141
|
}
|
|
112
|
-
if (type.kind === "object") {
|
|
113
|
-
const a = new Map(before.properties.map((p) => [p.name, p])), b = new Map(type.properties.map((p) => [p.name, p]));
|
|
114
|
-
for (const [field, p] of b) {
|
|
115
|
-
if (!a.has(field)) additions.push(name + "." + field);
|
|
116
|
-
else if (stable(a.get(field)) !== stable(p)) changes.push(name + "." + field);
|
|
117
|
-
}
|
|
118
|
-
for (const field of a.keys()) if (!b.has(field)) removals.push(name + "." + field);
|
|
119
|
-
} else if (type.kind === "enum") {
|
|
120
|
-
for (const v of type.values) if (!before.values.includes(v)) additions.push(name + "." + v);
|
|
121
|
-
for (const v of before.values) if (!type.values.includes(v)) removals.push(name + "." + v);
|
|
122
|
-
} else if (type.item !== before.item) changes.push(name + ":item");
|
|
123
142
|
}
|
|
124
|
-
for (const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (t.kind === "enum") {
|
|
131
|
-
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 + "];");
|
|
132
|
-
} else if (t.kind === "list") {
|
|
133
|
-
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; }", "}");
|
|
134
|
-
} else {
|
|
135
|
-
out.push("export interface " + t.name + "Input {");
|
|
136
|
-
for (const p of t.properties.filter((p2) => !p2.readonly)) out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
137
|
-
out.push("}", "export class " + t.name + " {");
|
|
138
|
-
for (const p of t.properties) {
|
|
139
|
-
if (p.readonly) {
|
|
140
|
-
out.push(" readonly " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
if (p.declaredDefault) out.push(" /** Pascal streaming default: " + p.declaredDefault.replaceAll("*/", "") + ". Omission preserves the native constructor. */");
|
|
144
|
-
if (p.kind === "object" || p.kind === "list") out.push(" " + JSON.stringify(p.name) + " = new " + p.ref + "();");
|
|
145
|
-
else out.push(" " + JSON.stringify(p.name) + "?: " + tsType(p) + ";");
|
|
146
|
-
}
|
|
147
|
-
out.push(" constructor(input: " + t.name + "Input = {}) {", " validateModel(" + JSON.stringify(t.name) + ", input);");
|
|
148
|
-
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
149
|
-
const access5 = "input[" + JSON.stringify(p.name) + "]", target = "this[" + JSON.stringify(p.name) + "]";
|
|
150
|
-
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) + ";");
|
|
151
|
-
}
|
|
152
|
-
out.push(" }", "}");
|
|
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;
|
|
153
149
|
}
|
|
154
150
|
}
|
|
155
|
-
out.push("const MODEL_SCHEMA: Record<string, any> = " + stable(Object.fromEntries(ir.types.map((t) => [t.name, t]))) + ";");
|
|
156
|
-
out.push(String.raw`
|
|
157
|
-
export function validateModel(model: string, value: unknown, at=model): void {
|
|
158
|
-
const schema=MODEL_SCHEMA[model]; if(!schema)throw new TypeError('Modelo desconhecido: '+model);
|
|
159
|
-
if(schema.kind==='enum'){ if(typeof value!=='string'||!schema.values.includes(value))throw new TypeError(at+': enum inválido'); return; }
|
|
160
|
-
if(schema.kind==='list'){ if(!Array.isArray(value))throw new TypeError(at+': esperado array'); value.forEach((item,index)=>validateModel(schema.item,item,at+'['+index+']'));return; }
|
|
161
|
-
if(value===null||typeof value!=='object'||Array.isArray(value))throw new TypeError(at+': esperado objeto');
|
|
162
|
-
const fields=new Map<string,any>(schema.properties.filter((p:any)=>!p.readonly).map((p:any)=>[p.name,p]));
|
|
163
|
-
for(const [name,v] of Object.entries(value)){
|
|
164
|
-
if(v===undefined)continue;
|
|
165
|
-
const p=fields.get(name);if(!p)throw new TypeError(at+'.'+name+': propriedade desconhecida ou somente leitura');
|
|
166
|
-
if(v===undefined)continue;
|
|
167
|
-
const field=at+'.'+name;
|
|
168
|
-
if(p.ref){validateModel(p.ref,v,field);continue;}
|
|
169
|
-
if(p.kind==='integer'){if(typeof v!=='number'||!Number.isSafeInteger(v)||v<p.min||v>p.max)throw new TypeError(field+': inteiro fora do intervalo');}
|
|
170
|
-
else if(p.kind==='boolean'){if(typeof v!=='boolean')throw new TypeError(field+': esperado boolean');}
|
|
171
|
-
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 TypeError(field+': esperado decimal em string'+(p.scale!==undefined?' de até '+p.scale+' casas':''));}
|
|
172
|
-
else if(p.kind==='datetime'){
|
|
173
|
-
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 TypeError(field+': esperado data/hora civil ISO (sem timezone)');
|
|
174
|
-
const date=new Date(v+(v.length===10?'T00:00:00Z':'Z'));if(date.toISOString().slice(0,10)!==v.slice(0,10))throw new TypeError(field+': data inválida');
|
|
175
|
-
}else if(typeof v!=='string')throw new TypeError(field+': esperado string');
|
|
176
|
-
}
|
|
177
151
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
function Arr(D:TJSONData;const P:string):TJSONArray;
|
|
191
|
-
begin if (D=nil) or (D.JSONType<>jtArray) then Bad(P,'esperado array');Result:=TJSONArray(D) end;
|
|
192
|
-
function Text(D:TJSONData;const P:string):string;
|
|
193
|
-
begin if (D=nil) or (D.JSONType<>jtString) then Bad(P,'esperado string');Result:=D.AsString end;
|
|
194
|
-
function IntValue(D:TJSONData;const P:string;MinV,MaxV:Int64):Int64;
|
|
195
|
-
var V:Extended;
|
|
196
|
-
begin
|
|
197
|
-
if (D=nil) or (D.JSONType<>jtNumber) then Bad(P,'esperado inteiro');
|
|
198
|
-
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');
|
|
199
|
-
Result:=D.AsInt64;
|
|
200
|
-
end;
|
|
201
|
-
function BoolValue(D:TJSONData;const P:string):boolean;
|
|
202
|
-
begin if (D=nil) or (D.JSONType<>jtBoolean) then Bad(P,'esperado boolean');Result:=D.AsBoolean end;
|
|
203
|
-
function DecimalText(D:TJSONData;const P:string;Scale:integer):string;
|
|
204
|
-
var I,PointPos:integer;
|
|
205
|
-
begin
|
|
206
|
-
Result:=Text(D,P);PointPos:=0;
|
|
207
|
-
if (Result='') or (Length(Result)>64) then Bad(P,'decimal inválido');
|
|
208
|
-
for I:=1 to Length(Result) do begin
|
|
209
|
-
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
|
|
210
|
-
else if (Result[I]='-') and (I=1) then begin if Length(Result)=1 then Bad(P,'decimal inválido') end
|
|
211
|
-
else if not (Result[I] in ['0'..'9']) then Bad(P,'decimal inválido');
|
|
212
|
-
end;
|
|
213
|
-
if (PointPos>0) and (Scale>=0) and (Length(Result)-PointPos>Scale) then Bad(P,'casas decimais excedidas');
|
|
214
|
-
end;
|
|
215
|
-
function FloatValue(D:TJSONData;const P:string):Extended;
|
|
216
|
-
var F:TFormatSettings;S:string;
|
|
217
|
-
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,-1);
|
|
218
|
-
if not TryStrToFloat(S,Result,F) or IsNan(Result) or IsInfinite(Result) then Bad(P,'decimal fora do intervalo');
|
|
219
|
-
end;
|
|
220
|
-
function CurrencyValue(D:TJSONData;const P:string):Currency;
|
|
221
|
-
var F:TFormatSettings;S:string;
|
|
222
|
-
begin F:=DefaultFormatSettings;F.DecimalSeparator:='.';F.ThousandSeparator:=#0;S:=DecimalText(D,P,4);
|
|
223
|
-
if not TryStrToCurr(S,Result,F) then Bad(P,'currency fora do intervalo');
|
|
224
|
-
end;
|
|
225
|
-
function DateValue(D:TJSONData;const P:string):TDateTime;
|
|
226
|
-
var S:string;I:integer;
|
|
227
|
-
begin
|
|
228
|
-
S:=Text(D,P);
|
|
229
|
-
if not (Length(S) in [10,19,21,22,23]) then Bad(P,'esperado data/hora civil ISO sem timezone');
|
|
230
|
-
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');
|
|
231
|
-
if not TryISO8601ToDate(S,Result,true) then Bad(P,'data ISO inválida');
|
|
232
|
-
end;
|
|
233
|
-
`);
|
|
234
|
-
const q = (s) => "'" + s.replaceAll("'", "''") + "'";
|
|
235
|
-
for (const t of classes) out.push("procedure Load_" + t.name + "(D:TJSONObject;destino:" + t.unit + "." + t.name + ";const P:string); forward;");
|
|
236
|
-
for (const t of classes) {
|
|
237
|
-
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;");
|
|
238
|
-
let index = 0;
|
|
239
|
-
for (const p of t.properties.filter((p2) => !p2.readonly)) {
|
|
240
|
-
out.push(" " + (index++ ? "else " : "") + "if K=" + q(p.name) + " then begin");
|
|
241
|
-
const target = "destino." + p.name;
|
|
242
|
-
if (p.kind === "object") out.push(" Load_" + p.ref + "(Obj(V,At)," + target + ",At);");
|
|
243
|
-
else if (p.kind === "list") {
|
|
244
|
-
const list = byName.get(p.ref);
|
|
245
|
-
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)+']');");
|
|
246
|
-
} else if (p.kind === "enum") {
|
|
247
|
-
const enumeration = byName.get(p.ref);
|
|
248
|
-
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');");
|
|
249
|
-
} 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] + ";");
|
|
250
|
-
out.push(" end");
|
|
251
|
-
}
|
|
252
|
-
out.push((index ? " else " : " ") + "Bad(At,'propriedade desconhecida ou somente leitura');", " end;", "end;");
|
|
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
|
+
};
|
|
253
164
|
}
|
|
254
|
-
|
|
255
|
-
|
|
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
|
+
});
|
|
256
212
|
}
|
|
257
|
-
function
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
"import { ACBR_CONTRACT, validateTNFe, type TNFeInput } from " + JSON.stringify("./models.js") + ";",
|
|
262
|
-
"export * from " + JSON.stringify("./models.js") + ";",
|
|
263
|
-
"export function criarEmissor(options: Omit<OpcoesEmissor, " + JSON.stringify("contrato") + " | " + JSON.stringify("validaDocumento") + ">) {",
|
|
264
|
-
" const emissor=criarRuntime({...options, contrato:ACBR_CONTRACT, validaDocumento:validateTNFe});",
|
|
265
|
-
" return {...emissor, gerarXml(documento:TNFeInput, opcoes?:OpcoesOperacao) { return emissor.gerarXml(documento as unknown as Record<string,unknown>, opcoes); }};",
|
|
266
|
-
"}"
|
|
267
|
-
].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");
|
|
268
217
|
}
|
|
269
|
-
async function
|
|
270
|
-
const files =
|
|
271
|
-
async function
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (entry.
|
|
275
|
-
|
|
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}.`);
|
|
276
229
|
}
|
|
277
230
|
}
|
|
278
|
-
await
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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 };
|
|
235
|
+
}
|
|
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.");
|
|
283
242
|
}
|
|
284
|
-
|
|
243
|
+
if (lock.source.parts.join("\n") !== SOURCE_PARTS.join("\n")) throw new Error("Partes ACBr divergentes no lock.");
|
|
244
|
+
return lock;
|
|
285
245
|
}
|
|
286
|
-
async function
|
|
287
|
-
|
|
288
|
-
const models = path2.resolve(root, options.modelOutputDir ?? "generated/acbr"), native = path2.resolve(root, options.nativeOutputDir ?? "native/generated");
|
|
289
|
-
await Promise.all([mkdir4(cache, { recursive: true }), mkdir4(bin, { recursive: true }), mkdir4(models, { recursive: true }), mkdir4(native, { recursive: true })]);
|
|
290
|
-
const extractor = options.extractorPath ?? fileURLToPath2(new URL("../tools/extract-model.lpr", import.meta.url));
|
|
291
|
-
const executable = path2.join(bin, "extract-model" + (process.platform === "win32" ? ".exe" : ""));
|
|
246
|
+
async function readSourceLock(config) {
|
|
247
|
+
let lock;
|
|
292
248
|
try {
|
|
293
|
-
await
|
|
294
|
-
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")));
|
|
295
250
|
} catch (error) {
|
|
296
|
-
|
|
297
|
-
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 });
|
|
298
252
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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) {
|
|
304
258
|
try {
|
|
305
|
-
|
|
259
|
+
await access2(`${config.lockPath}.operation`);
|
|
306
260
|
} catch (error) {
|
|
307
|
-
if (error.code
|
|
261
|
+
if (error.code === "ENOENT") return verifySourceContents(config);
|
|
262
|
+
throw error;
|
|
308
263
|
}
|
|
309
|
-
|
|
310
|
-
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("\\", "/"));
|
|
311
|
-
const content = [renderTypeScript(ir, sourceRevision, contractHash), renderClientIndex(), renderPascal(ir, sourceRevision, contractHash)];
|
|
312
|
-
const fileHashes = Object.fromEntries(files.map((file, index) => [file, hash(content[index])]));
|
|
313
|
-
await Promise.all([
|
|
314
|
-
...files.map((file, index) => writeFile4(path2.resolve(root, file), content[index], "utf8")),
|
|
315
|
-
writeFile4(path2.join(cache, "model.ir.json"), JSON.stringify(ir, null, 2) + "\n", "utf8"),
|
|
316
|
-
writeFile4(reportPath, JSON.stringify(report, null, 2) + "\n", "utf8"),
|
|
317
|
-
writeFile4(manifestPath, JSON.stringify({ schemaVersion: 1, sourceRevision, sourceHash, contractHash, root: ir.root, models: ir.types.length, files, fileHashes }, null, 2) + "\n", "utf8")
|
|
318
|
-
]);
|
|
319
|
-
return { contractHash, sourceHash, models: ir.types.length, reportPath, manifestPath };
|
|
264
|
+
throw new Error("Atualiza\xE7\xE3o de fontes ACBr em andamento. Aguarde o CLI concluir.");
|
|
320
265
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
string: { kind: "string" },
|
|
329
|
-
ansistring: { kind: "string" },
|
|
330
|
-
unicodestring: { kind: "string" },
|
|
331
|
-
widestring: { kind: "string" },
|
|
332
|
-
boolean: { kind: "boolean" },
|
|
333
|
-
byte: { kind: "integer", min: 0, max: 255 },
|
|
334
|
-
word: { kind: "integer", min: 0, max: 65535 },
|
|
335
|
-
integer: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
336
|
-
longint: { kind: "integer", min: -2147483648, max: 2147483647 },
|
|
337
|
-
smallint: { kind: "integer", min: -32768, max: 32767 },
|
|
338
|
-
shortint: { kind: "integer", min: -128, max: 127 },
|
|
339
|
-
cardinal: { kind: "integer", min: 0, max: 4294967295 },
|
|
340
|
-
longword: { kind: "integer", min: 0, max: 4294967295 },
|
|
341
|
-
int64: { kind: "integer", min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER },
|
|
342
|
-
qword: { kind: "integer", min: 0, max: Number.MAX_SAFE_INTEGER },
|
|
343
|
-
double: { kind: "decimal" },
|
|
344
|
-
extended: { kind: "decimal" },
|
|
345
|
-
single: { kind: "decimal" },
|
|
346
|
-
currency: { kind: "decimal", scale: 4 },
|
|
347
|
-
tdatetime: { kind: "datetime" },
|
|
348
|
-
tdate: { kind: "datetime" },
|
|
349
|
-
ttime: { kind: "datetime" }
|
|
350
|
-
};
|
|
351
|
-
stable = (value) => JSON.stringify(value);
|
|
352
|
-
hash = (value) => createHash3("sha256").update(value).digest("hex");
|
|
353
|
-
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";
|
|
266
|
+
async function verifySourceContents(config) {
|
|
267
|
+
const lock = await readSourceLock(config);
|
|
268
|
+
const snapshot = await snapshotSource(config.source.directory);
|
|
269
|
+
if (snapshot.treeHash !== lock.source.treeHash) {
|
|
270
|
+
const names = /* @__PURE__ */ new Set([...Object.keys(snapshot.files), ...Object.keys(lock.source.files)]);
|
|
271
|
+
const changed = [...names].filter((path4) => snapshot.files[path4] !== lock.source.files[path4]);
|
|
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.`);
|
|
354
273
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
// src/cli.ts
|
|
358
|
-
import { access as access4 } from "node:fs/promises";
|
|
359
|
-
import { resolve as resolve4 } from "node:path";
|
|
360
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
361
|
-
|
|
362
|
-
// src/config.ts
|
|
363
|
-
import { readFile, writeFile, mkdir, readdir, access } from "node:fs/promises";
|
|
364
|
-
import { dirname, isAbsolute, resolve } from "node:path";
|
|
365
|
-
var OFFICIAL_ACBR_URL = "https://svn.code.sf.net/p/acbr/code/trunk2";
|
|
366
|
-
var SOURCE_PARTS = ["Fontes", "Exemplos/ACBrDFe/Schemas/NFe", "Doctos/LICENSE.TXT"];
|
|
367
|
-
var DEFAULT = {
|
|
368
|
-
formatVersion: 1,
|
|
369
|
-
source: { url: OFFICIAL_ACBR_URL, revision: "HEAD", directory: ".acbr/source" },
|
|
370
|
-
generator: { outputDir: "." },
|
|
371
|
-
native: { project: "native/acbr-worker.lpr", outputDir: ".acbr/runtime", fpc: "fpc" }
|
|
372
|
-
};
|
|
373
|
-
function defaultConfig() {
|
|
374
|
-
return structuredClone(DEFAULT);
|
|
274
|
+
return lock;
|
|
375
275
|
}
|
|
376
|
-
function
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
function parseConfig(input, configPath) {
|
|
389
|
-
const root = record(input, "configura\xE7\xE3o");
|
|
390
|
-
keys(root, ["formatVersion", "source", "generator", "native"], "configura\xE7\xE3o");
|
|
391
|
-
if (root.formatVersion !== 1) throw new Error("formatVersion deve ser 1.");
|
|
392
|
-
const source = record(root.source, "source");
|
|
393
|
-
keys(source, ["url", "revision", "directory"], "source");
|
|
394
|
-
const generator = record(root.generator, "generator");
|
|
395
|
-
keys(generator, ["outputDir"], "generator");
|
|
396
|
-
const native = record(root.native, "native");
|
|
397
|
-
keys(native, ["project", "outputDir", "fpc", "lazarusRoot", "libraryFiles", "providerFiles"], "native");
|
|
398
|
-
const url = string(source.url, "source.url").replace(/\/+$/, "");
|
|
399
|
-
if (url !== OFFICIAL_ACBR_URL) throw new Error(`source.url deve apontar ao reposit\xF3rio oficial ${OFFICIAL_ACBR_URL}.`);
|
|
400
|
-
const revision2 = source.revision;
|
|
401
|
-
if (revision2 !== "HEAD" && (!Number.isSafeInteger(revision2) || Number(revision2) < 1)) throw new Error("source.revision deve ser HEAD ou uma revis\xE3o SVN positiva.");
|
|
402
|
-
const absoluteConfig = resolve(configPath);
|
|
403
|
-
const projectRoot = dirname(absoluteConfig);
|
|
404
|
-
const localPath = (value, label) => resolve(projectRoot, string(value, label));
|
|
405
|
-
const fpcInput = string(native.fpc, "native.fpc");
|
|
406
|
-
const fpc = isAbsolute(fpcInput) || /[\\/]/.test(fpcInput) ? resolve(projectRoot, fpcInput) : fpcInput;
|
|
407
|
-
let libraryFiles;
|
|
408
|
-
if (native.libraryFiles !== void 0) {
|
|
409
|
-
if (!Array.isArray(native.libraryFiles)) throw new Error("native.libraryFiles deve ser uma lista de caminhos.");
|
|
410
|
-
libraryFiles = native.libraryFiles.map((item, i) => localPath(item, `native.libraryFiles[${i}]`));
|
|
411
|
-
}
|
|
412
|
-
let providerFiles;
|
|
413
|
-
if (native.providerFiles !== void 0) {
|
|
414
|
-
if (!Array.isArray(native.providerFiles)) throw new Error("native.providerFiles deve ser uma lista de caminhos.");
|
|
415
|
-
providerFiles = native.providerFiles.map((item, i) => localPath(item, `native.providerFiles[${i}]`));
|
|
416
|
-
}
|
|
417
|
-
return {
|
|
418
|
-
formatVersion: 1,
|
|
419
|
-
configPath: absoluteConfig,
|
|
420
|
-
projectRoot,
|
|
421
|
-
lockPath: resolve(projectRoot, "acbr.lock.json"),
|
|
422
|
-
source: { url, revision: revision2, directory: localPath(source.directory, "source.directory") },
|
|
423
|
-
generator: { outputDir: localPath(generator.outputDir, "generator.outputDir") },
|
|
424
|
-
native: {
|
|
425
|
-
project: localPath(native.project, "native.project"),
|
|
426
|
-
outputDir: localPath(native.outputDir, "native.outputDir"),
|
|
427
|
-
fpc,
|
|
428
|
-
...native.lazarusRoot !== void 0 ? { lazarusRoot: localPath(native.lazarusRoot, "native.lazarusRoot") } : {},
|
|
429
|
-
...libraryFiles !== void 0 ? { libraryFiles } : {},
|
|
430
|
-
...providerFiles !== void 0 ? { providerFiles } : {}
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
async function loadConfig(path3 = "acbr.config.json") {
|
|
435
|
-
const configPath = resolve(path3);
|
|
436
|
-
let contents;
|
|
437
|
-
try {
|
|
438
|
-
contents = await readFile(configPath, "utf8");
|
|
439
|
-
} catch (error) {
|
|
440
|
-
throw new Error(`N\xE3o foi poss\xEDvel ler ${configPath}. Execute acbr-node init.`, { cause: error });
|
|
441
|
-
}
|
|
442
|
-
let value;
|
|
443
|
-
try {
|
|
444
|
-
value = JSON.parse(contents);
|
|
445
|
-
} catch (error) {
|
|
446
|
-
throw new Error(`JSON inv\xE1lido em ${configPath}.`, { cause: error });
|
|
447
|
-
}
|
|
448
|
-
return parseConfig(value, configPath);
|
|
449
|
-
}
|
|
450
|
-
async function initializeConfig(path3 = "acbr.config.json", revision2 = "HEAD", assetRoot) {
|
|
451
|
-
const configPath = resolve(path3);
|
|
452
|
-
const config = defaultConfig();
|
|
453
|
-
config.source.revision = revision2;
|
|
454
|
-
parseConfig(config, configPath);
|
|
455
|
-
await mkdir(dirname(configPath), { recursive: true });
|
|
456
|
-
try {
|
|
457
|
-
await access(configPath);
|
|
458
|
-
throw Object.assign(new Error(`EEXIST: configura\xE7\xE3o j\xE1 existe: ${configPath}`), { code: "EEXIST" });
|
|
459
|
-
} catch (error) {
|
|
460
|
-
if (error.code !== "ENOENT") throw error;
|
|
461
|
-
}
|
|
462
|
-
const resolved = parseConfig(config, configPath);
|
|
463
|
-
if (assetRoot) await copyInitAssets(assetRoot, resolved.projectRoot);
|
|
464
|
-
await writeFile(configPath, `${JSON.stringify(config, null, 2)}
|
|
465
|
-
`, { flag: "wx" });
|
|
466
|
-
await mkdir(resolve(resolved.projectRoot, ".acbr/generated"), { recursive: true });
|
|
467
|
-
await mkdir(resolve(resolved.projectRoot, "generated/acbr"), { recursive: true });
|
|
468
|
-
return resolved;
|
|
469
|
-
}
|
|
470
|
-
async function copyInitAssets(assetRoot, targetRoot) {
|
|
471
|
-
const entries = [];
|
|
472
|
-
async function scan(current, target) {
|
|
473
|
-
for (const entry of await readdir(current, { withFileTypes: true })) {
|
|
474
|
-
if (entry.name === "generated" || entry.name.startsWith(".")) continue;
|
|
475
|
-
const source = resolve(current, entry.name);
|
|
476
|
-
const destination = resolve(target, entry.name);
|
|
477
|
-
if (entry.isDirectory()) await scan(source, destination);
|
|
478
|
-
else if (entry.isFile() && /\.(pas|lpr|inc|lpi)$/i.test(entry.name)) entries.push({ source, destination, content: await readFile(source) });
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
await scan(resolve(assetRoot, "native"), resolve(targetRoot, "native"));
|
|
482
|
-
if (!entries.some((entry) => entry.source.endsWith("acbr-worker.lpr"))) throw new Error("Assets do pacote n\xE3o cont\xEAm native/acbr-worker.lpr.");
|
|
483
|
-
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")) });
|
|
484
|
-
for (const entry of entries) {
|
|
485
|
-
try {
|
|
486
|
-
const existing = await readFile(entry.destination);
|
|
487
|
-
if (!existing.equals(entry.content)) throw new Error(`init preservou arquivo existente divergente: ${entry.destination}.`);
|
|
488
|
-
} catch (error) {
|
|
489
|
-
if (error.code !== "ENOENT") throw error;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
for (const entry of entries) {
|
|
493
|
-
await mkdir(dirname(entry.destination), { recursive: true });
|
|
494
|
-
try {
|
|
495
|
-
await writeFile(entry.destination, entry.content, { flag: "wx" });
|
|
496
|
-
} catch (error) {
|
|
497
|
-
if (error.code !== "EEXIST") throw error;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// src/native-build.ts
|
|
503
|
-
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";
|
|
504
|
-
import { basename, dirname as dirname3, join as join2, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
505
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
506
|
-
import { fileURLToPath } from "node:url";
|
|
507
|
-
|
|
508
|
-
// src/source.ts
|
|
509
|
-
import { spawn } from "node:child_process";
|
|
510
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
511
|
-
import { createReadStream } from "node:fs";
|
|
512
|
-
import { access as access2, mkdir as mkdir2, readdir as readdir2, readFile as readFile2, rename, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
513
|
-
import { dirname as dirname2, join, relative, resolve as resolve2, sep } from "node:path";
|
|
514
|
-
async function runCommand(command, args, options = {}) {
|
|
515
|
-
return new Promise((done, fail2) => {
|
|
516
|
-
const child = spawn(command, args, { cwd: options.cwd, env: options.env ?? process.env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, shell: false });
|
|
517
|
-
let stdout = "";
|
|
518
|
-
let stderr = "";
|
|
519
|
-
let overflow = false;
|
|
520
|
-
const maximum = options.maxOutputBytes ?? 16 * 1024 * 1024;
|
|
521
|
-
const append = (kind, data) => {
|
|
522
|
-
if (overflow) return;
|
|
523
|
-
if (kind === "stdout") stdout += data.toString("utf8");
|
|
524
|
-
else stderr += data.toString("utf8");
|
|
525
|
-
if (Buffer.byteLength(stdout) + Buffer.byteLength(stderr) > maximum) {
|
|
526
|
-
overflow = true;
|
|
527
|
-
child.kill();
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
child.stdout.on("data", (data) => append("stdout", data));
|
|
531
|
-
child.stderr.on("data", (data) => append("stderr", data));
|
|
532
|
-
child.on("error", (error) => fail2(new Error(`N\xE3o foi poss\xEDvel executar ${command}: ${error.message}`, { cause: error })));
|
|
533
|
-
child.on("close", (code) => {
|
|
534
|
-
if (overflow) fail2(new Error(`Sa\xEDda de ${command} excedeu o limite de ${maximum} bytes.`));
|
|
535
|
-
else if (code !== 0) {
|
|
536
|
-
const diagnostic = (stderr || stdout).split("\n").slice(-80).join("\n").slice(-16e3);
|
|
537
|
-
fail2(Object.assign(new Error(`${command} terminou com c\xF3digo ${code}:
|
|
538
|
-
${diagnostic}`), { stdout, stderr }));
|
|
539
|
-
} else done({ stdout, stderr });
|
|
540
|
-
});
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
async function fileHash(path3) {
|
|
544
|
-
const hash2 = createHash("sha256");
|
|
545
|
-
for await (const chunk of createReadStream(path3)) hash2.update(chunk);
|
|
546
|
-
return hash2.digest("hex");
|
|
547
|
-
}
|
|
548
|
-
async function snapshotSource(directory) {
|
|
549
|
-
const files = /* @__PURE__ */ Object.create(null);
|
|
550
|
-
async function scan(current) {
|
|
551
|
-
const entries = (await readdir2(current, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name, "en"));
|
|
552
|
-
for (const entry of entries) {
|
|
553
|
-
if (entry.name === ".svn") continue;
|
|
554
|
-
const path3 = join(current, entry.name);
|
|
555
|
-
if (entry.isSymbolicLink()) throw new Error(`Fonte ACBr cont\xE9m link simb\xF3lico: ${path3}.`);
|
|
556
|
-
if (entry.isDirectory()) await scan(path3);
|
|
557
|
-
else if (entry.isFile()) files[relative(directory, path3).split(sep).join("/")] = await fileHash(path3);
|
|
558
|
-
else throw new Error(`Fonte ACBr cont\xE9m arquivo especial: ${path3}.`);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
await scan(resolve2(directory));
|
|
562
|
-
const sortedFiles = Object.fromEntries(Object.entries(files).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
563
|
-
const treeHash = createHash("sha256").update(JSON.stringify(sortedFiles)).digest("hex");
|
|
564
|
-
return { treeHash, files: sortedFiles };
|
|
565
|
-
}
|
|
566
|
-
function validateLock(value) {
|
|
567
|
-
if (!value || typeof value !== "object") throw new Error("Lock ACBr inv\xE1lido.");
|
|
568
|
-
const lock = value;
|
|
569
|
-
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.");
|
|
570
|
-
for (const [path3, hash2] of Object.entries(lock.source.files)) {
|
|
571
|
-
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.");
|
|
572
|
-
}
|
|
573
|
-
if (lock.source.parts.join("\n") !== SOURCE_PARTS.join("\n")) throw new Error("Partes ACBr divergentes no lock.");
|
|
574
|
-
return lock;
|
|
575
|
-
}
|
|
576
|
-
async function readSourceLock(config) {
|
|
577
|
-
let lock;
|
|
578
|
-
try {
|
|
579
|
-
lock = validateLock(JSON.parse(await readFile2(config.lockPath, "utf8")));
|
|
580
|
-
} catch (error) {
|
|
581
|
-
throw new Error(`N\xE3o foi poss\xEDvel ler ${config.lockPath}. Execute acbr-node source update.`, { cause: error });
|
|
582
|
-
}
|
|
583
|
-
if (lock.source.url !== config.source.url) throw new Error("URL ACBr do lock diverge da configura\xE7\xE3o.");
|
|
584
|
-
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.");
|
|
585
|
-
return lock;
|
|
586
|
-
}
|
|
587
|
-
async function verifySource(config) {
|
|
588
|
-
try {
|
|
589
|
-
await access2(`${config.lockPath}.operation`);
|
|
590
|
-
} catch (error) {
|
|
591
|
-
if (error.code === "ENOENT") return verifySourceContents(config);
|
|
592
|
-
throw error;
|
|
593
|
-
}
|
|
594
|
-
throw new Error("Atualiza\xE7\xE3o de fontes ACBr em andamento. Aguarde o CLI concluir.");
|
|
595
|
-
}
|
|
596
|
-
async function verifySourceContents(config) {
|
|
597
|
-
const lock = await readSourceLock(config);
|
|
598
|
-
const snapshot = await snapshotSource(config.source.directory);
|
|
599
|
-
if (snapshot.treeHash !== lock.source.treeHash) {
|
|
600
|
-
const names = /* @__PURE__ */ new Set([...Object.keys(snapshot.files), ...Object.keys(lock.source.files)]);
|
|
601
|
-
const changed = [...names].filter((path3) => snapshot.files[path3] !== lock.source.files[path3]);
|
|
602
|
-
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.`);
|
|
603
|
-
}
|
|
604
|
-
return lock;
|
|
605
|
-
}
|
|
606
|
-
async function writeLock(config, snapshot, revision2) {
|
|
607
|
-
const lock = { formatVersion: 1, source: { url: config.source.url, revision: revision2, parts: [...SOURCE_PARTS], ...snapshot } };
|
|
608
|
-
await mkdir2(dirname2(config.lockPath), { recursive: true });
|
|
609
|
-
const temporary = `${config.lockPath}.${randomUUID()}.tmp`;
|
|
610
|
-
await writeFile2(temporary, `${JSON.stringify(lock, null, 2)}
|
|
611
|
-
`, { flag: "wx" });
|
|
612
|
-
try {
|
|
613
|
-
await rename(temporary, config.lockPath);
|
|
614
|
-
} finally {
|
|
615
|
-
await rm(temporary, { force: true });
|
|
616
|
-
}
|
|
617
|
-
return lock;
|
|
276
|
+
async function writeLock(config, snapshot, revision2) {
|
|
277
|
+
const lock = { formatVersion: 1, source: { url: config.source.url, revision: revision2, parts: [...SOURCE_PARTS], ...snapshot } };
|
|
278
|
+
await mkdir2(dirname2(config.lockPath), { recursive: true });
|
|
279
|
+
const temporary = `${config.lockPath}.${randomUUID()}.tmp`;
|
|
280
|
+
await writeFile2(temporary, `${JSON.stringify(lock, null, 2)}
|
|
281
|
+
`, { flag: "wx" });
|
|
282
|
+
try {
|
|
283
|
+
await rename(temporary, config.lockPath);
|
|
284
|
+
} finally {
|
|
285
|
+
await rm(temporary, { force: true });
|
|
286
|
+
}
|
|
287
|
+
return lock;
|
|
618
288
|
}
|
|
619
289
|
async function lockExistingSource(config, revision2) {
|
|
620
290
|
return withSourceOperation(config, () => performLockExistingSource(config, revision2));
|
|
@@ -669,7 +339,7 @@ async function performUpdateSource(config, revision2, runner) {
|
|
|
669
339
|
await mkdir2(stage, { recursive: true });
|
|
670
340
|
let previousLock;
|
|
671
341
|
try {
|
|
672
|
-
previousLock = await
|
|
342
|
+
previousLock = await readFile3(config.lockPath, "utf8");
|
|
673
343
|
} catch (error) {
|
|
674
344
|
if (error.code !== "ENOENT") throw error;
|
|
675
345
|
}
|
|
@@ -708,7 +378,7 @@ async function performUpdateSource(config, revision2, runner) {
|
|
|
708
378
|
}
|
|
709
379
|
}
|
|
710
380
|
async function persistRevision(config, revision2) {
|
|
711
|
-
const original = JSON.parse(await
|
|
381
|
+
const original = JSON.parse(await readFile3(config.configPath, "utf8"));
|
|
712
382
|
original.source.revision = revision2;
|
|
713
383
|
const temporary = `${config.configPath}.${randomUUID()}.tmp`;
|
|
714
384
|
await writeFile2(temporary, `${JSON.stringify(original, null, 2)}
|
|
@@ -719,29 +389,47 @@ async function persistRevision(config, revision2) {
|
|
|
719
389
|
await rm(temporary, { force: true });
|
|
720
390
|
}
|
|
721
391
|
}
|
|
392
|
+
var init_source = __esm({
|
|
393
|
+
"src/source.ts"() {
|
|
394
|
+
"use strict";
|
|
395
|
+
init_config();
|
|
396
|
+
}
|
|
397
|
+
});
|
|
722
398
|
|
|
723
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";
|
|
724
412
|
function runtimeDirectory(config) {
|
|
725
413
|
return join2(config.native.outputDir, `${process.platform}-${process.arch}`);
|
|
726
414
|
}
|
|
727
|
-
async function exists(
|
|
415
|
+
async function exists(path4) {
|
|
728
416
|
try {
|
|
729
|
-
await access3(
|
|
417
|
+
await access3(path4);
|
|
730
418
|
return true;
|
|
731
419
|
} catch {
|
|
732
420
|
return false;
|
|
733
421
|
}
|
|
734
422
|
}
|
|
735
423
|
async function findLazarus(config) {
|
|
736
|
-
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));
|
|
737
425
|
for (const candidate of candidates) if (await exists(join2(candidate, "components/lazutils"))) return realpath(candidate);
|
|
738
426
|
throw new Error("Lazarus n\xE3o encontrado. Defina native.lazarusRoot em acbr.config.json ou LAZARUS_ROOT.");
|
|
739
427
|
}
|
|
740
428
|
async function generatedManifest(config) {
|
|
741
|
-
const
|
|
429
|
+
const path4 = join2(config.generator.outputDir, ".acbr/generated/manifest.json");
|
|
742
430
|
let value;
|
|
743
431
|
try {
|
|
744
|
-
value = JSON.parse(await
|
|
432
|
+
value = JSON.parse(await readFile4(path4, "utf8"));
|
|
745
433
|
} catch (error) {
|
|
746
434
|
throw new Error("Contrato gerado ausente ou inv\xE1lido. Execute acbr-node generate.", { cause: error });
|
|
747
435
|
}
|
|
@@ -755,23 +443,21 @@ async function generatedManifest(config) {
|
|
|
755
443
|
}
|
|
756
444
|
return value;
|
|
757
445
|
}
|
|
758
|
-
async function subdirectories(
|
|
759
|
-
const result = [
|
|
760
|
-
for (const entry of (await readdir3(
|
|
761
|
-
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)));
|
|
762
450
|
}
|
|
763
451
|
return result;
|
|
764
452
|
}
|
|
765
|
-
var REQUIRED_DYNAMIC = ["libssl.so.3", "libcrypto.so.3", "libxml2.so.2"];
|
|
766
|
-
var CORE_SYSTEM = /^(?:lib(?:c|m|pthread|dl|rt|resolv|anl|util)\.so(?:\.|$)|ld-linux|linux-vdso)/;
|
|
767
453
|
async function copyLinuxLibraries(stage) {
|
|
768
454
|
const { stdout } = await runCommand("ldconfig", ["-p"]);
|
|
769
455
|
const libraries = /* @__PURE__ */ new Map();
|
|
770
456
|
for (const name of REQUIRED_DYNAMIC) {
|
|
771
457
|
const line = stdout.split("\n").find((value) => value.trim().startsWith(`${name} `) && value.includes("x86-64"));
|
|
772
|
-
const
|
|
773
|
-
if (!
|
|
774
|
-
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));
|
|
775
461
|
}
|
|
776
462
|
const modules = "/usr/lib/x86_64-linux-gnu/ossl-modules";
|
|
777
463
|
if (!await exists(join2(modules, "legacy.so"))) throw new Error("Provider legacy OpenSSL 3 ausente. Instale o pacote libssl3/libssl3t64 completo.");
|
|
@@ -779,9 +465,9 @@ async function copyLinuxLibraries(stage) {
|
|
|
779
465
|
const systemDependencies = /* @__PURE__ */ new Set();
|
|
780
466
|
const inspected = /* @__PURE__ */ new Set();
|
|
781
467
|
while (inspected.size < libraries.size) {
|
|
782
|
-
const [name,
|
|
468
|
+
const [name, path4] = [...libraries].find(([name2]) => !inspected.has(name2));
|
|
783
469
|
inspected.add(name);
|
|
784
|
-
const dependencies = await runCommand("ldd", [
|
|
470
|
+
const dependencies = await runCommand("ldd", [path4]);
|
|
785
471
|
for (const line of dependencies.stdout.split("\n")) {
|
|
786
472
|
if (line.includes("not found")) throw new Error(`Depend\xEAncia transitiva ausente: ${line.trim()}.`);
|
|
787
473
|
const match = /^\s*(\S+)\s+=>\s+(\S+)/.exec(line);
|
|
@@ -799,17 +485,17 @@ async function copyLinuxLibraries(stage) {
|
|
|
799
485
|
const licenseDir = join2(stage, "licenses");
|
|
800
486
|
await mkdir3(licenseDir, { recursive: true });
|
|
801
487
|
const provenance = {};
|
|
802
|
-
for (const [name,
|
|
488
|
+
for (const [name, path4] of libraries) {
|
|
803
489
|
const destination = name.startsWith("ossl-modules/") ? join2(stage, name) : join2(stage, "lib", name);
|
|
804
490
|
await mkdir3(dirname3(destination), { recursive: true });
|
|
805
|
-
await copyFile2(
|
|
491
|
+
await copyFile2(path4, destination);
|
|
806
492
|
const aliases = name === "libssl.so.3" ? ["libssl.so"] : name === "libcrypto.so.3" ? ["libcrypto.so"] : name === "libxml2.so.2" ? ["libxml2.so"] : [];
|
|
807
|
-
for (const alias of aliases) await copyFile2(
|
|
493
|
+
for (const alias of aliases) await copyFile2(path4, join2(stage, "lib", alias));
|
|
808
494
|
let owner;
|
|
809
495
|
try {
|
|
810
|
-
owner = (await runCommand("dpkg-query", ["-S",
|
|
496
|
+
owner = (await runCommand("dpkg-query", ["-S", path4])).stdout.split("\n")[0].split(": ")[0];
|
|
811
497
|
} catch (error) {
|
|
812
|
-
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 });
|
|
813
499
|
}
|
|
814
500
|
const pkg = owner.split(":")[0];
|
|
815
501
|
const copyright = `/usr/share/doc/${pkg}/copyright`;
|
|
@@ -851,10 +537,10 @@ async function copyExplicitLibraries(config, stage) {
|
|
|
851
537
|
for (const source of files) {
|
|
852
538
|
await copyFile2(source, join2(stage, directory, basename(source)));
|
|
853
539
|
await copyFile2(`${source}.LICENSE`, join2(stage, "licenses", `${basename(source)}.txt`));
|
|
854
|
-
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"));
|
|
855
541
|
}
|
|
856
542
|
}
|
|
857
|
-
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.");
|
|
858
544
|
await mkdir3(join2(stage, "sources"), { recursive: true });
|
|
859
545
|
await writeFile3(join2(stage, "sources/native-dependencies.json"), `${JSON.stringify(sources, null, 2)}
|
|
860
546
|
`);
|
|
@@ -891,8 +577,8 @@ async function buildNative(config, options = {}) {
|
|
|
891
577
|
`-FU${units}`,
|
|
892
578
|
`-FE${stage}`,
|
|
893
579
|
`-o${executable}`,
|
|
894
|
-
...searchPaths.map((
|
|
895
|
-
...fontPaths.map((
|
|
580
|
+
...searchPaths.map((path4) => `-Fu${path4}`),
|
|
581
|
+
...fontPaths.map((path4) => `-Fi${path4}`),
|
|
896
582
|
config.native.project
|
|
897
583
|
];
|
|
898
584
|
const responseFile = join2(stage, ".compiler.rsp");
|
|
@@ -986,186 +672,753 @@ async function copyTree(source, target) {
|
|
|
986
672
|
if (entry.isDirectory()) await copyTree(join2(source, entry.name), join2(target, entry.name));
|
|
987
673
|
else if (entry.isFile()) await copyFile2(join2(source, entry.name), join2(target, entry.name));
|
|
988
674
|
}
|
|
989
|
-
}
|
|
990
|
-
async function replaceRuntime(stage, target) {
|
|
991
|
-
const backup = `${target}.${randomUUID2()}.backup`;
|
|
992
|
-
const hadTarget = await exists(target);
|
|
993
|
-
if (hadTarget) await rename2(target, backup);
|
|
675
|
+
}
|
|
676
|
+
async function replaceRuntime(stage, target) {
|
|
677
|
+
const backup = `${target}.${randomUUID2()}.backup`;
|
|
678
|
+
const hadTarget = await exists(target);
|
|
679
|
+
if (hadTarget) await rename2(target, backup);
|
|
680
|
+
try {
|
|
681
|
+
await rename2(stage, target);
|
|
682
|
+
} catch (error) {
|
|
683
|
+
if (hadTarget) await rename2(backup, target);
|
|
684
|
+
throw error;
|
|
685
|
+
}
|
|
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";
|
|
1071
|
+
}
|
|
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";
|
|
1085
|
+
}
|
|
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);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
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));
|
|
1100
|
+
}
|
|
1101
|
+
return digest.digest("hex");
|
|
1102
|
+
}
|
|
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);
|
|
1115
|
+
}
|
|
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;
|
|
994
1121
|
try {
|
|
995
|
-
await
|
|
1122
|
+
previous = JSON.parse(await readFile5(path2.join(cache, "model.ir.json"), "utf8"));
|
|
996
1123
|
} catch (error) {
|
|
997
|
-
if (
|
|
998
|
-
throw error;
|
|
1124
|
+
if (error.code !== "ENOENT") throw error;
|
|
999
1125
|
}
|
|
1000
|
-
|
|
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 };
|
|
1001
1139
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
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";
|
|
1011
1173
|
}
|
|
1012
|
-
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
// src/diagnostics.ts
|
|
1177
|
+
function etapaDaOperacao(comando) {
|
|
1178
|
+
return { gerarXml: "geracao", validar: "validacao", assinar: "assinatura", transmitir: "transmissao", consultar: "consulta", cancelar: "cancelamento", cartaCorrecao: "carta_correcao", inutilizar: "inutilizacao" }[comando] ?? "operacao";
|
|
1013
1179
|
}
|
|
1014
|
-
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
const lock = await verifySource(config);
|
|
1032
|
-
items.push({ name: "Fontes ACBr", ok: true, detail: `revis\xE3o ${lock.source.revision}, ${lock.source.treeHash}` });
|
|
1033
|
-
} catch (error) {
|
|
1034
|
-
items.push({ name: "Fontes ACBr", ok: false, detail: error.message });
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
if (process.platform === "linux") {
|
|
1038
|
-
try {
|
|
1039
|
-
const result = await runCommand("ldconfig", ["-p"]);
|
|
1040
|
-
const missing = REQUIRED_DYNAMIC.filter((name) => !result.stdout.includes(name));
|
|
1041
|
-
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: missing.length === 0, detail: missing.length ? `Ausentes: ${missing.join(", ")}` : REQUIRED_DYNAMIC.join(", ") });
|
|
1042
|
-
} catch (error) {
|
|
1043
|
-
items.push({ name: "OpenSSL/libxml2 din\xE2micos", ok: false, detail: error.message });
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
return items;
|
|
1180
|
+
function criarDiagnosticoErro(codigo, desconhecido = false, detalhes = {}) {
|
|
1181
|
+
const safeCode = Object.hasOwn(CATALOGO, codigo) ? codigo : "FALHA_LOCAL";
|
|
1182
|
+
const [defaultStage, mensagem, defaultAction] = CATALOGO[safeCode];
|
|
1183
|
+
const etapa = detalhes.etapa && ETAPAS.has(detalhes.etapa) ? detalhes.etapa : defaultStage;
|
|
1184
|
+
const campo = detalhes.campo && CAMPOS.has(detalhes.campo) ? detalhes.campo : void 0;
|
|
1185
|
+
const acoesConfig = { cnpj: "Informe o CNPJ como texto com 14 d\xEDgitos.", uf: "Informe a sigla da UF em letras mai\xFAsculas, por exemplo PE.", modelo: "Informe o n\xFAmero 55 para NF-e ou 65 para NFC-e, sem aspas.", ambiente: "Informe o n\xFAmero 2 para homologa\xE7\xE3o ou 1 para produ\xE7\xE3o, sem aspas.", timeoutMs: "Informe um n\xFAmero inteiro de 1 a 120000 milissegundos.", limiteFila: "Informe um n\xFAmero inteiro de 0 a 1000.", limiteBytes: "Informe um n\xFAmero inteiro de 256 a 8388608 bytes.", runtimeDirectory: "Informe o diret\xF3rio do runtime como texto n\xE3o vazio." };
|
|
1186
|
+
const acao = safeCode === "CONFIGURACAO_INVALIDA" && campo && Object.hasOwn(acoesConfig, campo) ? acoesConfig[campo] : defaultAction;
|
|
1187
|
+
const causa = Object.freeze({ codigo: safeCode, etapa, ...campo ? { campo } : {} });
|
|
1188
|
+
return Object.freeze({
|
|
1189
|
+
codigo: safeCode,
|
|
1190
|
+
etapa,
|
|
1191
|
+
...campo ? { campo } : {},
|
|
1192
|
+
mensagem,
|
|
1193
|
+
acao: desconhecido ? "Consulte a situa\xE7\xE3o fiscal antes de repetir. O envio pode ter ocorrido; n\xE3o retransmita automaticamente." : acao,
|
|
1194
|
+
statusEnvio: desconhecido ? "resultado_incerto" : "nao_enviado",
|
|
1195
|
+
causa
|
|
1196
|
+
});
|
|
1047
1197
|
}
|
|
1048
|
-
|
|
1049
|
-
const
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
const
|
|
1065
|
-
const
|
|
1066
|
-
|
|
1067
|
-
|
|
1198
|
+
function adicionarDiagnosticoLimpeza(diagnostico) {
|
|
1199
|
+
const acao = diagnostico.statusEnvio === "resultado_incerto" ? "Encerre esta aplica\xE7\xE3o antes de iniciar outro motor e consulte a situa\xE7\xE3o fiscal antes de repetir qualquer envio." : "Encerre esta aplica\xE7\xE3o antes de iniciar outro motor. As pr\xF3ximas opera\xE7\xF5es deste emissor foram bloqueadas.";
|
|
1200
|
+
const limpeza = Object.freeze({ codigo: "ENCERRAMENTO_MOTOR_NAO_CONFIRMADO", etapa: "limpeza", mensagem: "N\xE3o foi poss\xEDvel confirmar o encerramento do motor fiscal.", acao });
|
|
1201
|
+
return Object.freeze({ ...diagnostico, acao, limpeza });
|
|
1202
|
+
}
|
|
1203
|
+
function diagnosticarResultado(resultado, comando) {
|
|
1204
|
+
const etapa = etapaDaOperacao(comando);
|
|
1205
|
+
if (!resultado || typeof resultado !== "object") return criarDiagnosticoErro("FALHA_LOCAL", true, { etapa });
|
|
1206
|
+
if (resultado.envioIniciado !== void 0 && typeof resultado.envioIniciado !== "boolean") return criarDiagnosticoErro("RESPOSTA_INVALIDA", true, { etapa });
|
|
1207
|
+
let statusEnvio = "resultado_incerto", codigo = "RESULTADO_INCERTO";
|
|
1208
|
+
let mensagem = "A situa\xE7\xE3o fiscal ainda n\xE3o foi confirmada.";
|
|
1209
|
+
let acao = "Consulte a situa\xE7\xE3o fiscal antes de repetir. N\xE3o retransmita automaticamente.";
|
|
1210
|
+
const local = comando === "gerarXml" && resultado.estado === "XML_GERADO" || comando === "validar" && resultado.estado === "VALIDADO" || comando === "assinar" && resultado.estado === "ASSINADO";
|
|
1211
|
+
const semEvento = resultado.envioIniciado === false || resultado.envioIniciado === void 0;
|
|
1212
|
+
const protocolo = typeof resultado.protocolo === "string" && /^\d{15}$/.test(resultado.protocolo);
|
|
1213
|
+
const chave = typeof resultado.chave === "string" && /^\d{44}$/.test(resultado.chave);
|
|
1214
|
+
const autorizacao = (comando === "transmitir" || comando === "consultar") && resultado.estado === "AUTORIZADO" && [100, 150].includes(resultado.cStat) && protocolo && chave && (comando === "consultar" || resultado.envioIniciado !== false);
|
|
1215
|
+
const evento = comando === "cancelar" && resultado.estado === "CANCELADO" && [135, 136].includes(resultado.cStat) && chave || comando === "cartaCorrecao" && resultado.estado === "EVENTO_REGISTRADO" && resultado.cStat === 135 && chave || comando === "inutilizar" && resultado.estado === "INUTILIZADO" && resultado.cStat === 102;
|
|
1216
|
+
if (local && resultado.sucesso === true && semEvento) {
|
|
1217
|
+
statusEnvio = "nao_enviado";
|
|
1218
|
+
codigo = "ETAPA_LOCAL_CONCLUIDA";
|
|
1219
|
+
mensagem = "A etapa local foi conclu\xEDda; esta opera\xE7\xE3o n\xE3o transmitiu a nota.";
|
|
1220
|
+
acao = "Confira o resultado antes de seguir para a pr\xF3xima etapa.";
|
|
1221
|
+
} else if (resultado.sucesso === true && (autorizacao || evento && protocolo && resultado.envioIniciado !== false)) {
|
|
1222
|
+
statusEnvio = "autorizado";
|
|
1223
|
+
codigo = "OPERACAO_CONFIRMADA";
|
|
1224
|
+
mensagem = { AUTORIZADO: "A nota foi autorizada.", CANCELADO: "O cancelamento foi confirmado.", EVENTO_REGISTRADO: "O evento foi registrado.", INUTILIZADO: "A faixa foi inutilizada." }[resultado.estado];
|
|
1225
|
+
acao = "Guarde o resultado fiscal. N\xE3o repita esta opera\xE7\xE3o.";
|
|
1226
|
+
} else if (resultado.sucesso === false && (comando === "consultar" || resultado.envioIniciado !== false) && ["transmitir", "consultar", "cancelar", "cartaCorrecao", "inutilizar"].includes(comando) && Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 && (resultado.estado === "DENEGADO" && [110, 301, 302].includes(resultado.cStat) || resultado.estado === "REJEITADO" && ![100, 150, 110, 301, 302, 101, 151, 155, 103, 104, 105, 108, 109, 204, 539, 573, 135, 136, 102, 217].includes(resultado.cStat))) {
|
|
1227
|
+
statusEnvio = "rejeitado";
|
|
1228
|
+
codigo = resultado.estado === "DENEGADO" ? "NOTA_DENEGADA" : "OPERACAO_REJEITADA";
|
|
1229
|
+
mensagem = resultado.estado === "DENEGADO" ? "A nota foi denegada." : "A opera\xE7\xE3o foi rejeitada.";
|
|
1230
|
+
acao = resultado.estado === "DENEGADO" ? "Consulte a situa\xE7\xE3o fiscal e a orienta\xE7\xE3o respons\xE1vel antes de usar a numera\xE7\xE3o." : "Confira o cStat e revise os dados antes de decidir uma nova tentativa.";
|
|
1231
|
+
} else if (resultado.estado === "ERRO" && resultado.envioIniciado === false) {
|
|
1232
|
+
if (typeof resultado.codigo === "string" && Object.hasOwn(CATALOGO, resultado.codigo)) return criarDiagnosticoErro(resultado.codigo, false, { etapa });
|
|
1233
|
+
statusEnvio = "nao_enviado";
|
|
1234
|
+
codigo = "FALHA_ANTES_ENVIO";
|
|
1235
|
+
mensagem = "O motor informou falha antes de iniciar o envio desta opera\xE7\xE3o.";
|
|
1236
|
+
acao = "Revise a configura\xE7\xE3o e os dados antes de continuar.";
|
|
1237
|
+
}
|
|
1238
|
+
const cStat = Number.isInteger(resultado.cStat) && Number(resultado.cStat) > 0 && Number(resultado.cStat) <= 9999 ? resultado.cStat : void 0;
|
|
1239
|
+
return Object.freeze({ codigo, etapa, mensagem, acao, statusEnvio, ...cStat !== void 0 ? { cStat } : {} });
|
|
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
|
+
};
|
|
1068
1296
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
// src/types.ts
|
|
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
|
+
};
|
|
1076
1328
|
}
|
|
1077
|
-
|
|
1078
|
-
`);
|
|
1079
|
-
}
|
|
1329
|
+
});
|
|
1080
1330
|
|
|
1081
1331
|
// src/runtime.ts
|
|
1082
1332
|
import { spawn as spawn2 } from "node:child_process";
|
|
1083
|
-
import { readFile as
|
|
1084
|
-
import
|
|
1333
|
+
import { readFile as readFile6, stat as stat3 } from "node:fs/promises";
|
|
1334
|
+
import path3 from "node:path";
|
|
1085
1335
|
import { createRequire } from "node:module";
|
|
1086
|
-
import { createHash as
|
|
1336
|
+
import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
|
|
1087
1337
|
import { TextDecoder } from "node:util";
|
|
1088
|
-
|
|
1089
|
-
// src/types.ts
|
|
1090
|
-
var ErroAcbrNode = class extends Error {
|
|
1091
|
-
constructor(codigo, mensagem, resultadoDesconhecido = false, xmlBase64) {
|
|
1092
|
-
super(mensagem);
|
|
1093
|
-
this.codigo = codigo;
|
|
1094
|
-
this.resultadoDesconhecido = resultadoDesconhecido;
|
|
1095
|
-
this.xmlBase64 = xmlBase64;
|
|
1096
|
-
}
|
|
1097
|
-
name = "ErroAcbrNode";
|
|
1098
|
-
};
|
|
1099
|
-
|
|
1100
|
-
// src/runtime.ts
|
|
1101
|
-
var STATES = /* @__PURE__ */ new Set(["DENEGADO", "XML_GERADO", "VALIDADO", "ASSINADO", "AUTORIZADO", "REJEITADO", "PENDENTE", "INDETERMINADO", "CONSULTADO", "CANCELADO", "EVENTO_REGISTRADO", "INUTILIZADO", "ERRO"]);
|
|
1102
|
-
var 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(" "));
|
|
1103
|
-
var MAX_BYTES = 8 * 1024 * 1024;
|
|
1104
|
-
var plain = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
1105
|
-
var validContract = (v) => plain(v) && Number.isInteger(v.sourceRevision) && Number(v.sourceRevision) > 0 && typeof v.contractHash === "string" && /^[a-f0-9]{64}$/.test(v.contractHash);
|
|
1106
|
-
var fail = (code, message, req, unknown = false) => new ErroAcbrNode(code, message, unknown, req?.comando === "transmitir" ? req.xmlBase64 : void 0);
|
|
1107
1338
|
function confined(root, relative3) {
|
|
1108
|
-
const file =
|
|
1109
|
-
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.");
|
|
1110
1341
|
return file;
|
|
1111
1342
|
}
|
|
1112
1343
|
async function resolveRuntime(directory, contract) {
|
|
1113
|
-
if (!validContract(contract)) throw
|
|
1344
|
+
if (!validContract(contract)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1114
1345
|
let root = directory;
|
|
1115
1346
|
if (!root) {
|
|
1116
|
-
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.");
|
|
1117
1348
|
try {
|
|
1118
1349
|
const require2 = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url);
|
|
1119
|
-
root =
|
|
1350
|
+
root = path3.join(path3.dirname(require2.resolve("cosmemilton-acbr-node-" + process.platform + "-x64/package.json")), "runtime");
|
|
1120
1351
|
} catch {
|
|
1121
|
-
throw
|
|
1352
|
+
throw fail2("RUNTIME_AUSENTE", "Instale o pacote de runtime da plataforma ou informe runtimeDirectory.");
|
|
1122
1353
|
}
|
|
1123
1354
|
}
|
|
1124
|
-
root =
|
|
1355
|
+
root = path3.resolve(root);
|
|
1125
1356
|
let m;
|
|
1126
1357
|
try {
|
|
1127
|
-
m = JSON.parse(await
|
|
1358
|
+
m = JSON.parse(await readFile6(path3.join(root, "manifest.json"), "utf8"));
|
|
1128
1359
|
} catch {
|
|
1129
|
-
throw
|
|
1360
|
+
throw fail2("RUNTIME_AUSENTE", "Manifesto do runtime n\xE3o encontrado.");
|
|
1130
1361
|
}
|
|
1131
|
-
if (!validContract(m) || m.formatVersion !== 1 || !plain(m.files) || typeof m.executable !== "string" || m.platform !== process.platform || m.arch !== process.arch) throw
|
|
1132
|
-
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.");
|
|
1133
1364
|
for (const [name, hash2] of Object.entries(m.files)) {
|
|
1134
|
-
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.");
|
|
1135
1366
|
const file = confined(root, name);
|
|
1136
1367
|
let data;
|
|
1137
1368
|
try {
|
|
1138
1369
|
if (!(await stat3(file)).isFile()) throw Error();
|
|
1139
|
-
data = await
|
|
1370
|
+
data = await readFile6(file);
|
|
1140
1371
|
} catch {
|
|
1141
|
-
throw
|
|
1372
|
+
throw fail2("RUNTIME_INCOMPLETO", "Arquivo do runtime ausente.");
|
|
1142
1373
|
}
|
|
1143
|
-
if (
|
|
1374
|
+
if (createHash4("sha256").update(data).digest("hex") !== hash2) throw fail2("RUNTIME_ALTERADO", "O runtime n\xE3o corresponde ao manifesto distribu\xEDdo.");
|
|
1144
1375
|
}
|
|
1145
|
-
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.");
|
|
1146
1377
|
return { directory: root, executable: confined(root, m.executable) };
|
|
1147
1378
|
}
|
|
1148
1379
|
function criarEmissor(options) {
|
|
1149
|
-
|
|
1150
|
-
if (!
|
|
1380
|
+
const configFail = (campo) => fail2("CONFIGURACAO_INVALIDA", "Informe campos e tipos v\xE1lidos na configura\xE7\xE3o.", void 0, false, { etapa: "configuracao", campo });
|
|
1381
|
+
if (!plain(options)) throw configFail();
|
|
1382
|
+
if (typeof options.cnpj !== "string" || !/^\d{14}$/.test(options.cnpj)) throw configFail("cnpj");
|
|
1383
|
+
if (typeof options.uf !== "string" || !UFS.has(options.uf)) throw configFail("uf");
|
|
1384
|
+
if (![55, 65].includes(options.modelo)) throw configFail("modelo");
|
|
1385
|
+
if (![1, 2].includes(options.ambiente)) throw configFail("ambiente");
|
|
1386
|
+
if (!validContract(options.contrato)) throw fail2("CONTRATO_INVALIDO", "Contrato gerado inv\xE1lido.");
|
|
1151
1387
|
const cert = options.certificado;
|
|
1152
|
-
if (cert && (typeof cert.senha !== "string" || !!cert.pfx === !!cert.arquivo || cert.pfx && !(cert.pfx instanceof Uint8Array))) throw
|
|
1153
|
-
if (options.csc && (!/^\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" });
|
|
1390
|
+
if (options.runtimeDirectory !== void 0 && (typeof options.runtimeDirectory !== "string" || !options.runtimeDirectory)) throw configFail("runtimeDirectory");
|
|
1391
|
+
if (options.validaDocumento !== void 0 && typeof options.validaDocumento !== "function" || options.criaProcesso !== void 0 && typeof options.criaProcesso !== "function") throw configFail();
|
|
1154
1392
|
const cfg = { cnpj: options.cnpj, uf: options.uf, modelo: options.modelo, ambiente: options.ambiente, csc: options.csc ? { ...options.csc } : void 0 };
|
|
1155
1393
|
const certificate = cert ? { ...cert, pfx: cert.pfx ? Buffer.from(cert.pfx) : void 0 } : void 0;
|
|
1156
1394
|
const contract = { ...options.contrato };
|
|
1157
1395
|
const timeout = options.timeoutMs ?? 12e4, capacity = options.limiteFila ?? 32, bytesLimit = options.limiteBytes ?? MAX_BYTES;
|
|
1158
|
-
if (!Number.isInteger(timeout) || timeout < 1 || timeout > 12e4
|
|
1396
|
+
if (!Number.isInteger(timeout) || timeout < 1 || timeout > 12e4) throw configFail("timeoutMs");
|
|
1397
|
+
if (!Number.isInteger(capacity) || capacity < 0 || capacity > 1e3) throw configFail("limiteFila");
|
|
1398
|
+
if (!Number.isInteger(bytesLimit) || bytesLimit < 256 || bytesLimit > MAX_BYTES) throw configFail("limiteBytes");
|
|
1159
1399
|
const launch = options.criaProcesso ?? ((exe, args, config) => spawn2(exe, args, { ...config, stdio: ["pipe", "pipe", "pipe"] }));
|
|
1160
|
-
let runtimePromise, closed = false, current;
|
|
1400
|
+
let runtimePromise, closed = false, teardownFailed = false, current;
|
|
1161
1401
|
const queue = [];
|
|
1402
|
+
const closedError = () => {
|
|
1403
|
+
const error = fail2("EMISSOR_FECHADO", "Emissor encerrado.");
|
|
1404
|
+
if (teardownFailed) error.anotarFalhaLimpeza();
|
|
1405
|
+
return error;
|
|
1406
|
+
};
|
|
1407
|
+
const rejectQueue = () => {
|
|
1408
|
+
for (const item of queue.splice(0)) {
|
|
1409
|
+
item.signal?.removeEventListener("abort", item.abort);
|
|
1410
|
+
item.bytes.fill(0);
|
|
1411
|
+
item.reject(closedError());
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1162
1414
|
async function execute2(item) {
|
|
1163
|
-
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.");
|
|
1164
1416
|
const runtime = await (runtimePromise ??= resolveRuntime(options.runtimeDirectory, contract));
|
|
1165
|
-
if (closed || item.signal?.aborted) throw
|
|
1166
|
-
await new Promise((done) => {
|
|
1417
|
+
if (closed || item.signal?.aborted) throw fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o.");
|
|
1418
|
+
return await new Promise((done, rejectExecution) => {
|
|
1167
1419
|
let stopError;
|
|
1168
1420
|
let child, finished = false, started = false, sending = false, total = 0, rest = Buffer.alloc(0), result;
|
|
1421
|
+
let teardownTimer;
|
|
1169
1422
|
let finishCurrent;
|
|
1170
1423
|
const doneCurrent = new Promise((r) => {
|
|
1171
1424
|
finishCurrent = r;
|
|
@@ -1175,46 +1428,91 @@ function criarEmissor(options) {
|
|
|
1175
1428
|
if (finished) return;
|
|
1176
1429
|
finished = true;
|
|
1177
1430
|
clearTimeout(timer);
|
|
1431
|
+
clearTimeout(teardownTimer);
|
|
1178
1432
|
item.signal?.removeEventListener("abort", abort);
|
|
1179
1433
|
item.bytes.fill(0);
|
|
1180
1434
|
if (current?.done === doneCurrent) current = void 0;
|
|
1181
1435
|
finishCurrent();
|
|
1182
|
-
error ?
|
|
1183
|
-
|
|
1436
|
+
error ? rejectExecution(error) : done(result);
|
|
1437
|
+
};
|
|
1438
|
+
const detachOwnedChild = () => {
|
|
1439
|
+
for (const pipe of [child?.stdin, child?.stdout, child?.stderr]) {
|
|
1440
|
+
try {
|
|
1441
|
+
pipe?.destroy();
|
|
1442
|
+
} catch {
|
|
1443
|
+
}
|
|
1444
|
+
try {
|
|
1445
|
+
pipe?.unref?.();
|
|
1446
|
+
} catch {
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
try {
|
|
1450
|
+
child?.unref();
|
|
1451
|
+
} catch {
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
const teardownFallback = () => {
|
|
1455
|
+
if (finished) return;
|
|
1456
|
+
stopError ??= fail2("FALHA_MOTOR", "O motor n\xE3o foi encerrado.", item.req, uncertain());
|
|
1457
|
+
stopError.anotarFalhaLimpeza();
|
|
1458
|
+
teardownFailed = true;
|
|
1459
|
+
closed = true;
|
|
1460
|
+
rejectQueue();
|
|
1461
|
+
certificate?.pfx?.fill(0);
|
|
1462
|
+
finish(stopError);
|
|
1463
|
+
detachOwnedChild();
|
|
1184
1464
|
};
|
|
1185
1465
|
const stop = (code, message) => {
|
|
1186
1466
|
if (finished || stopError) return;
|
|
1187
|
-
stopError =
|
|
1188
|
-
if (child?.pid)
|
|
1189
|
-
|
|
1467
|
+
stopError = fail2(code, message, item.req, uncertain());
|
|
1468
|
+
if (!child?.pid) {
|
|
1469
|
+
finish(stopError);
|
|
1470
|
+
detachOwnedChild();
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
teardownTimer = setTimeout(teardownFallback, MAX_TEARDOWN_MS);
|
|
1474
|
+
try {
|
|
1475
|
+
if (child.kill("SIGKILL") !== true) teardownFallback();
|
|
1476
|
+
} catch {
|
|
1477
|
+
teardownFallback();
|
|
1478
|
+
}
|
|
1190
1479
|
};
|
|
1191
1480
|
const abort = () => stop("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada; confira a situa\xE7\xE3o fiscal quando o envio foi iniciado.");
|
|
1192
1481
|
const timer = setTimeout(() => stop("TIMEOUT_MOTOR", "O motor excedeu o prazo; consulte a situa\xE7\xE3o antes de transmitir novamente."), timeout);
|
|
1193
1482
|
current = { stop: () => stop("EMISSOR_FECHADO", "Emissor encerrado."), done: doneCurrent };
|
|
1194
1483
|
const env = {};
|
|
1195
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];
|
|
1196
|
-
if (process.platform === "linux") env.LD_LIBRARY_PATH =
|
|
1485
|
+
if (process.platform === "linux") env.LD_LIBRARY_PATH = path3.join(runtime.directory, "lib");
|
|
1197
1486
|
if (process.platform === "win32") {
|
|
1198
1487
|
const inheritedPath = env.Path ?? env.PATH ?? "";
|
|
1199
1488
|
delete env.Path;
|
|
1200
|
-
env.PATH =
|
|
1489
|
+
env.PATH = path3.join(runtime.directory, "lib") + ";" + runtime.directory + ";" + inheritedPath;
|
|
1201
1490
|
}
|
|
1202
|
-
const modules =
|
|
1491
|
+
const modules = path3.join(runtime.directory, "ossl-modules");
|
|
1203
1492
|
env.OPENSSL_MODULES = modules;
|
|
1204
|
-
env.OPENSSL_CONF =
|
|
1493
|
+
env.OPENSSL_CONF = path3.join(runtime.directory, "openssl.cnf");
|
|
1205
1494
|
try {
|
|
1206
1495
|
child = launch(runtime.executable, ["--parent-pid", String(process.pid)], { cwd: runtime.directory, env, windowsHide: true, shell: false, stdio: ["pipe", "pipe", "pipe"] });
|
|
1207
1496
|
started = typeof child.pid === "number";
|
|
1208
1497
|
} catch {
|
|
1209
|
-
finish(
|
|
1498
|
+
finish(fail2("FALHA_INICIAR_MOTOR", "N\xE3o foi poss\xEDvel iniciar o motor.", item.req));
|
|
1210
1499
|
return;
|
|
1211
1500
|
}
|
|
1212
1501
|
item.signal?.addEventListener("abort", abort, { once: true });
|
|
1213
1502
|
child.on("spawn", () => {
|
|
1214
1503
|
started = true;
|
|
1215
1504
|
});
|
|
1216
|
-
child.on("error", () =>
|
|
1505
|
+
child.on("error", () => {
|
|
1506
|
+
if (finished) return;
|
|
1507
|
+
if (stopError) {
|
|
1508
|
+
teardownFallback();
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
stop("FALHA_INICIAR_MOTOR", "N\xE3o foi poss\xEDvel iniciar o motor.");
|
|
1512
|
+
});
|
|
1217
1513
|
child.stdin.on("error", () => stop("FALHA_PIPE", "N\xE3o foi poss\xEDvel comunicar com o motor."));
|
|
1514
|
+
child.stdout.on("error", () => stop("FALHA_PIPE", "N\xE3o foi poss\xEDvel comunicar com o motor."));
|
|
1515
|
+
child.stderr.on("error", () => stop("FALHA_PIPE", "N\xE3o foi poss\xEDvel comunicar com o motor."));
|
|
1218
1516
|
child.stderr.on("data", () => {
|
|
1219
1517
|
});
|
|
1220
1518
|
child.stdout.on("data", (chunk) => {
|
|
@@ -1240,7 +1538,9 @@ function criarEmissor(options) {
|
|
|
1240
1538
|
if (result || frame.versao !== 1 || frame.sourceRevision !== contract.sourceRevision || frame.contractHash !== contract.contractHash || typeof frame.sucesso !== "boolean" || !STATES.has(String(frame.estado))) throw Error();
|
|
1241
1539
|
if (frame.xmlBase64 !== void 0 && (typeof frame.xmlBase64 !== "string" || !frame.xmlBase64.length || Buffer.from(frame.xmlBase64, "base64").toString("base64") !== frame.xmlBase64)) throw Error();
|
|
1242
1540
|
if (frame.cStat !== void 0 && (!Number.isInteger(frame.cStat) || Number(frame.cStat) < 1 || Number(frame.cStat) > 9999)) throw Error();
|
|
1243
|
-
|
|
1541
|
+
if (frame.envioIniciado !== void 0 && typeof frame.envioIniciado !== "boolean" || sending && frame.envioIniciado === false) throw Error();
|
|
1542
|
+
const fiscal = frame;
|
|
1543
|
+
result = { ...fiscal, diagnostico: diagnosticarResultado(sending ? { ...fiscal, envioIniciado: true } : fiscal, item.req.comando) };
|
|
1244
1544
|
} catch {
|
|
1245
1545
|
stop("RESPOSTA_INVALIDA", "O motor retornou uma resposta inv\xE1lida.");
|
|
1246
1546
|
return;
|
|
@@ -1254,7 +1554,7 @@ function criarEmissor(options) {
|
|
|
1254
1554
|
return;
|
|
1255
1555
|
}
|
|
1256
1556
|
if (code !== 0 || rest.length || !result) {
|
|
1257
|
-
finish(
|
|
1557
|
+
finish(fail2("FALHA_MOTOR", "O motor encerrou sem resposta fiscal v\xE1lida.", item.req, uncertain()));
|
|
1258
1558
|
return;
|
|
1259
1559
|
}
|
|
1260
1560
|
finish();
|
|
@@ -1271,7 +1571,8 @@ function criarEmissor(options) {
|
|
|
1271
1571
|
busy = true;
|
|
1272
1572
|
item.signal?.removeEventListener("abort", item.abort);
|
|
1273
1573
|
try {
|
|
1274
|
-
await execute2(item);
|
|
1574
|
+
const result = await execute2(item);
|
|
1575
|
+
item.resolve(result);
|
|
1275
1576
|
} catch (e) {
|
|
1276
1577
|
item.bytes.fill(0);
|
|
1277
1578
|
item.reject(e);
|
|
@@ -1281,19 +1582,23 @@ function criarEmissor(options) {
|
|
|
1281
1582
|
}
|
|
1282
1583
|
}
|
|
1283
1584
|
async function request(command, data, operation = {}) {
|
|
1284
|
-
|
|
1285
|
-
if (
|
|
1286
|
-
|
|
1585
|
+
const rawOperation = operation;
|
|
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" });
|
|
1587
|
+
const signal = operation.signal;
|
|
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" });
|
|
1589
|
+
if (closed) throw closedError();
|
|
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.");
|
|
1287
1592
|
if (command === "gerarXml") options.validaDocumento?.(data.documento);
|
|
1288
1593
|
const config = { ...cfg };
|
|
1289
1594
|
if (certificate) {
|
|
1290
1595
|
let pfx;
|
|
1291
1596
|
try {
|
|
1292
|
-
pfx = certificate.pfx ?? await
|
|
1597
|
+
pfx = certificate.pfx ?? await readFile6(certificate.arquivo);
|
|
1293
1598
|
} catch {
|
|
1294
|
-
throw
|
|
1599
|
+
throw fail2("CERTIFICADO_AUSENTE", "N\xE3o foi poss\xEDvel ler o A1 configurado.");
|
|
1295
1600
|
}
|
|
1296
|
-
if (pfx.length > 2 * 1024 * 1024) throw
|
|
1601
|
+
if (pfx.length > 2 * 1024 * 1024) throw fail2("CERTIFICADO_EXCESSIVO", "Certificado excede o limite.");
|
|
1297
1602
|
config.certificado = { pfxBase64: pfx.toString("base64"), senha: certificate.senha };
|
|
1298
1603
|
}
|
|
1299
1604
|
let bytes, req;
|
|
@@ -1302,17 +1607,17 @@ function criarEmissor(options) {
|
|
|
1302
1607
|
if (bytes.length > bytesLimit) throw Error();
|
|
1303
1608
|
req = JSON.parse(bytes.toString("utf8"));
|
|
1304
1609
|
} catch {
|
|
1305
|
-
throw
|
|
1610
|
+
throw fail2("REQUISICAO_INVALIDA", "Dados da opera\xE7\xE3o inv\xE1lidos ou acima do limite.");
|
|
1306
1611
|
}
|
|
1307
1612
|
return new Promise((resolve5, reject) => {
|
|
1308
1613
|
if (closed) {
|
|
1309
1614
|
bytes.fill(0);
|
|
1310
|
-
reject(
|
|
1615
|
+
reject(closedError());
|
|
1311
1616
|
return;
|
|
1312
1617
|
}
|
|
1313
1618
|
if (busy && queue.length >= capacity) {
|
|
1314
1619
|
bytes.fill(0);
|
|
1315
|
-
reject(
|
|
1620
|
+
reject(fail2("FILA_CHEIA", "A fila fiscal est\xE1 cheia."));
|
|
1316
1621
|
return;
|
|
1317
1622
|
}
|
|
1318
1623
|
const item = { req, bytes, signal: operation.signal, resolve: resolve5, reject };
|
|
@@ -1322,7 +1627,7 @@ function criarEmissor(options) {
|
|
|
1322
1627
|
queue.splice(i, 1);
|
|
1323
1628
|
bytes.fill(0);
|
|
1324
1629
|
operation.signal?.removeEventListener("abort", item.abort);
|
|
1325
|
-
reject(
|
|
1630
|
+
reject(fail2("OPERACAO_CANCELADA", "Opera\xE7\xE3o cancelada antes da execu\xE7\xE3o."));
|
|
1326
1631
|
}
|
|
1327
1632
|
};
|
|
1328
1633
|
operation.signal?.addEventListener("abort", item.abort, { once: true });
|
|
@@ -1332,14 +1637,17 @@ function criarEmissor(options) {
|
|
|
1332
1637
|
});
|
|
1333
1638
|
}
|
|
1334
1639
|
const xmlData = (xml) => {
|
|
1335
|
-
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" });
|
|
1336
1641
|
return { xmlBase64: Buffer.from(xml, "utf8").toString("base64") };
|
|
1337
1642
|
};
|
|
1338
1643
|
const checkKey = (key) => {
|
|
1339
|
-
if (!/^\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" });
|
|
1340
1645
|
};
|
|
1341
1646
|
const reason = (value) => {
|
|
1342
|
-
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" });
|
|
1648
|
+
};
|
|
1649
|
+
const checkObject = (data, campo) => {
|
|
1650
|
+
if (!plain(data)) throw fail2("OPERACAO_INVALIDA", "Informe os par\xE2metros da opera\xE7\xE3o como objeto.", void 0, false, { campo });
|
|
1343
1651
|
};
|
|
1344
1652
|
return {
|
|
1345
1653
|
gerarXml: (documento, op) => request("gerarXml", { documento }, op),
|
|
@@ -1347,154 +1655,185 @@ function criarEmissor(options) {
|
|
|
1347
1655
|
assinar: (xml, op) => request("assinar", xmlData(xml), op),
|
|
1348
1656
|
transmitir: (xml, op) => request("transmitir", xmlData(xml), op),
|
|
1349
1657
|
consultar: (consulta, op) => {
|
|
1658
|
+
checkObject(consulta, "consulta");
|
|
1350
1659
|
checkKey(consulta.chave);
|
|
1351
|
-
if (consulta.recibo && !/^\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" });
|
|
1352
1661
|
return request("consultar", consulta, op);
|
|
1353
1662
|
},
|
|
1354
1663
|
cancelar: (data, op) => {
|
|
1664
|
+
checkObject(data, "cancelamento");
|
|
1355
1665
|
checkKey(data.chave);
|
|
1356
1666
|
reason(data.justificativa);
|
|
1357
|
-
if (!/^\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" });
|
|
1358
1668
|
return request("cancelar", data, op);
|
|
1359
1669
|
},
|
|
1360
1670
|
cartaCorrecao: (data, op) => {
|
|
1361
|
-
|
|
1671
|
+
checkObject(data, "cartaCorrecao");
|
|
1672
|
+
if (cfg.modelo !== 55) throw fail2("OPERACAO_NAO_SUPORTADA", "Carta de corre\xE7\xE3o exige NF-e modelo 55.");
|
|
1362
1673
|
checkKey(data.chave);
|
|
1363
|
-
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" });
|
|
1364
1675
|
return request("cartaCorrecao", { ...data, sequenciaEvento: data.sequenciaEvento ?? 1 }, op);
|
|
1365
1676
|
},
|
|
1366
1677
|
inutilizar: (data, op) => {
|
|
1678
|
+
checkObject(data, "inutilizacao");
|
|
1367
1679
|
reason(data.justificativa);
|
|
1368
|
-
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" });
|
|
1369
1681
|
return request("inutilizar", { inutilizacao: { ano: data.ano, serie: data.serie, numeroInicial: data.numeroInicial, numeroFinal: data.numeroFinal }, justificativa: data.justificativa }, op);
|
|
1370
1682
|
},
|
|
1371
1683
|
async fechar() {
|
|
1372
|
-
if (closed)
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
item.signal?.removeEventListener("abort", item.abort);
|
|
1376
|
-
item.bytes.fill(0);
|
|
1377
|
-
item.reject(fail("EMISSOR_FECHADO", "Emissor encerrado."));
|
|
1684
|
+
if (!closed) {
|
|
1685
|
+
closed = true;
|
|
1686
|
+
rejectQueue();
|
|
1378
1687
|
}
|
|
1379
1688
|
const running = current;
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1689
|
+
try {
|
|
1690
|
+
running?.stop();
|
|
1691
|
+
if (running) await running.done;
|
|
1692
|
+
} finally {
|
|
1693
|
+
certificate?.pfx?.fill(0);
|
|
1694
|
+
}
|
|
1383
1695
|
}
|
|
1384
1696
|
};
|
|
1385
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
|
+
});
|
|
1386
1715
|
|
|
1387
1716
|
// src/offline-fixture.ts
|
|
1388
|
-
var OFFLINE_DOCUMENT
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
"IE": "123456789",
|
|
1416
|
-
"CRT": "crtSimplesNacional",
|
|
1417
|
-
"EnderEmit": {
|
|
1418
|
-
"xLgr": "RUA TESTE",
|
|
1419
|
-
"nro": "1",
|
|
1420
|
-
"xBairro": "TESTE",
|
|
1421
|
-
"cMun": 2304400,
|
|
1422
|
-
"xMun": "FORTALEZA",
|
|
1423
|
-
"UF": "CE",
|
|
1424
|
-
"CEP": 6e7,
|
|
1425
|
-
"cPais": 1058,
|
|
1426
|
-
"xPais": "BRASIL"
|
|
1427
|
-
}
|
|
1428
|
-
},
|
|
1429
|
-
"Dest": {
|
|
1430
|
-
"CNPJCPF": "12345678909",
|
|
1431
|
-
"xNome": "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL",
|
|
1432
|
-
"indIEDest": "inNaoContribuinte",
|
|
1433
|
-
"EnderDest": {
|
|
1434
|
-
"xLgr": "RUA TESTE",
|
|
1435
|
-
"nro": "2",
|
|
1436
|
-
"xBairro": "TESTE",
|
|
1437
|
-
"cMun": 2304400,
|
|
1438
|
-
"xMun": "FORTALEZA",
|
|
1439
|
-
"UF": "CE",
|
|
1440
|
-
"CEP": 6e7,
|
|
1441
|
-
"cPais": 1058,
|
|
1442
|
-
"xPais": "BRASIL"
|
|
1443
|
-
}
|
|
1444
|
-
},
|
|
1445
|
-
"Det": [
|
|
1446
|
-
{
|
|
1447
|
-
"Prod": {
|
|
1448
|
-
"nItem": 1,
|
|
1449
|
-
"cProd": "TESTE",
|
|
1450
|
-
"cEAN": "SEM GTIN",
|
|
1451
|
-
"xProd": "Caf\xE9 S\xE3o Jos\xE9 PRODUTO SINT\xC9TICO OFFLINE",
|
|
1452
|
-
"NCM": "22021000",
|
|
1453
|
-
"CFOP": "5102",
|
|
1454
|
-
"uCom": "UN",
|
|
1455
|
-
"qCom": "1",
|
|
1456
|
-
"vUnCom": "10",
|
|
1457
|
-
"vProd": "10",
|
|
1458
|
-
"cEANTrib": "SEM GTIN",
|
|
1459
|
-
"uTrib": "UN",
|
|
1460
|
-
"qTrib": "1",
|
|
1461
|
-
"vUnTrib": "10",
|
|
1462
|
-
"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"
|
|
1463
1744
|
},
|
|
1464
|
-
"
|
|
1465
|
-
"
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
"
|
|
1470
|
-
"
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
"
|
|
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"
|
|
1474
1760
|
}
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
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
|
+
});
|
|
1496
1831
|
|
|
1497
1832
|
// src/offline-check.ts
|
|
1833
|
+
var offline_check_exports = {};
|
|
1834
|
+
__export(offline_check_exports, {
|
|
1835
|
+
checkOffline: () => checkOffline
|
|
1836
|
+
});
|
|
1498
1837
|
async function checkOffline(config, manifest) {
|
|
1499
1838
|
const emitter = criarEmissor({
|
|
1500
1839
|
cnpj: "11222333000181",
|
|
@@ -1529,11 +1868,246 @@ async function checkOffline(config, manifest) {
|
|
|
1529
1868
|
await emitter.fechar();
|
|
1530
1869
|
}
|
|
1531
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
|
+
}
|
|
1532
2104
|
|
|
1533
2105
|
// src/cli.ts
|
|
1534
2106
|
var HELP = `acbr-node \u2014 compila\xE7\xE3o e contrato Node/ACBr NF-e
|
|
1535
2107
|
|
|
1536
2108
|
Uso:
|
|
2109
|
+
acbr-node help TAG Ide.tpNF [--json]
|
|
2110
|
+
acbr-node help TAG 'Det[].Imposto.PIS.CST' [--json]
|
|
1537
2111
|
acbr-node init [--config caminho] [--revision HEAD|n\xFAmero]
|
|
1538
2112
|
acbr-node source update [--config caminho] [--revision HEAD|n\xFAmero]
|
|
1539
2113
|
acbr-node source lock --revision n\xFAmero [--config caminho]
|
|
@@ -1545,6 +2119,7 @@ Uso:
|
|
|
1545
2119
|
source update consulta o SVN oficial e substitui apenas fontes verificadas pelo lock.
|
|
1546
2120
|
source lock registra um export existente cuja origem/revis\xE3o o operador j\xE1 conferiu.
|
|
1547
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.
|
|
1548
2123
|
`;
|
|
1549
2124
|
function revision(value) {
|
|
1550
2125
|
if (value === void 0) return void 0;
|
|
@@ -1574,9 +2149,17 @@ function parseArguments(args) {
|
|
|
1574
2149
|
}
|
|
1575
2150
|
return result;
|
|
1576
2151
|
}
|
|
1577
|
-
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";
|
|
1578
2155
|
try {
|
|
1579
|
-
|
|
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
|
+
}
|
|
1580
2163
|
const command = options.command.join(" ");
|
|
1581
2164
|
if (options.help || !command) {
|
|
1582
2165
|
io.stdout.write(HELP);
|
|
@@ -1585,8 +2168,17 @@ async function main(args = process.argv.slice(2), io = process) {
|
|
|
1585
2168
|
const output = (value, text) => io.stdout.write(options.json ? `${JSON.stringify(value, null, 2)}
|
|
1586
2169
|
` : `${text}
|
|
1587
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
|
+
}
|
|
1588
2179
|
if (command === "init") {
|
|
1589
|
-
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)));
|
|
1590
2182
|
output({ configPath: config2.configPath }, `Configura\xE7\xE3o criada: ${config2.configPath}
|
|
1591
2183
|
Pr\xF3ximo passo: acbr-node source update.`);
|
|
1592
2184
|
return 0;
|
|
@@ -1594,52 +2186,76 @@ Pr\xF3ximo passo: acbr-node source update.`);
|
|
|
1594
2186
|
if (!["source update", "source lock", "generate", "build", "check", "doctor"].includes(command)) throw new Error(`Comando desconhecido: ${command}. Use --help.`);
|
|
1595
2187
|
if (options.revision !== void 0 && !command.startsWith("source ")) throw new Error("--revision \xE9 aceito somente em init e source.");
|
|
1596
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));
|
|
1597
2191
|
let config2;
|
|
1598
2192
|
try {
|
|
1599
2193
|
await access4(resolve4(options.config));
|
|
1600
|
-
config2 = await
|
|
2194
|
+
config2 = await loadConfig3(options.config);
|
|
1601
2195
|
} catch (error) {
|
|
1602
2196
|
if (error.code !== "ENOENT") throw error;
|
|
1603
2197
|
}
|
|
1604
|
-
const report = await
|
|
2198
|
+
const report = await doctor2(config2);
|
|
1605
2199
|
output(report, report.map((item) => `${item.ok ? "OK" : "FALHA"} ${item.name}: ${item.detail}`).join("\n"));
|
|
1606
2200
|
return report.every((item) => item.ok) ? 0 : 1;
|
|
1607
2201
|
}
|
|
1608
|
-
const
|
|
2202
|
+
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2203
|
+
const config = await loadConfig2(options.config);
|
|
1609
2204
|
if (command === "source update") {
|
|
1610
|
-
const
|
|
2205
|
+
const { updateSource: updateSource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
2206
|
+
const lock = await updateSource2(config, options.revision);
|
|
1611
2207
|
output(lock, `Fontes oficiais registradas na revis\xE3o ${lock.source.revision}.
|
|
1612
2208
|
SHA256 da \xE1rvore: ${lock.source.treeHash}
|
|
1613
2209
|
Execute generate para atualizar o contrato.`);
|
|
1614
2210
|
} else if (command === "source lock") {
|
|
2211
|
+
const { lockExistingSource: lockExistingSource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
1615
2212
|
if (typeof options.revision !== "number") throw new Error("source lock exige --revision com o n\xFAmero verificado do export SVN.");
|
|
1616
2213
|
if (config.source.revision !== "HEAD" && config.source.revision !== options.revision) throw new Error("Revis\xE3o do export diverge da configura\xE7\xE3o.");
|
|
1617
|
-
const lock = await
|
|
2214
|
+
const lock = await lockExistingSource2(config, options.revision);
|
|
1618
2215
|
output(lock, `Export existente registrado na revis\xE3o ${lock.source.revision}; ${Object.keys(lock.source.files).length} arquivos protegidos por SHA256.`);
|
|
1619
2216
|
} else if (command === "generate") {
|
|
1620
|
-
const
|
|
2217
|
+
const { verifySource: verifySource2 } = await Promise.resolve().then(() => (init_source(), source_exports));
|
|
2218
|
+
const lock = await verifySource2(config);
|
|
1621
2219
|
const { generateModel: generateModel2 } = await Promise.resolve().then(() => (init_generator(), generator_exports));
|
|
1622
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 });
|
|
1623
2221
|
output(result, `Contrato ${result.contractHash}; ${result.models} modelos gerados.
|
|
1624
2222
|
Revise o relat\xF3rio: ${result.reportPath}`);
|
|
1625
2223
|
} else if (command === "build") {
|
|
1626
|
-
const
|
|
1627
|
-
|
|
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)}
|
|
1628
2227
|
ACBr revis\xE3o ${result.sourceRevision}; contrato ${result.contractHash}.`);
|
|
1629
2228
|
} else {
|
|
1630
|
-
const
|
|
1631
|
-
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);
|
|
1632
2233
|
output({ ...result, offlineChecks }, `Fontes, contrato e ${Object.keys(result.files).length} arquivos do runtime conferidos por SHA256.
|
|
1633
2234
|
${offlineChecks.length} verifica\xE7\xF5es offline do motor aprovadas; nenhuma transmiss\xE3o.`);
|
|
1634
2235
|
}
|
|
1635
2236
|
return 0;
|
|
1636
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
|
+
}
|
|
1637
2244
|
io.stderr.write(`Erro: ${error.message}
|
|
1638
2245
|
`);
|
|
1639
2246
|
return 1;
|
|
1640
2247
|
}
|
|
1641
2248
|
}
|
|
1642
|
-
|
|
2249
|
+
function isDirectInvocation() {
|
|
2250
|
+
const entry = process.argv[1];
|
|
2251
|
+
if (!entry) return false;
|
|
2252
|
+
try {
|
|
2253
|
+
return realpathSync(resolve4(entry)) === realpathSync(fileURLToPath3(import.meta.url));
|
|
2254
|
+
} catch {
|
|
2255
|
+
return false;
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
if (isDirectInvocation()) {
|
|
1643
2259
|
main().then((code) => {
|
|
1644
2260
|
process.exitCode = code;
|
|
1645
2261
|
});
|