@sjunepark/fs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +73 -0
- package/assets/guide/authoring.md +125 -0
- package/dist/application.js +34 -0
- package/dist/application.js.map +1 -0
- package/dist/assets.js +20 -0
- package/dist/assets.js.map +1 -0
- package/dist/bin.js +9 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.js +150 -0
- package/dist/cli.js.map +1 -0
- package/dist/content.js +47 -0
- package/dist/content.js.map +1 -0
- package/dist/io.js +76 -0
- package/dist/io.js.map +1 -0
- package/dist/json.js +291 -0
- package/dist/json.js.map +1 -0
- package/dist/limits.js +15 -0
- package/dist/limits.js.map +1 -0
- package/dist/logger.js +26 -0
- package/dist/logger.js.map +1 -0
- package/dist/node-services.js +9 -0
- package/dist/node-services.js.map +1 -0
- package/dist/pathless.js +72 -0
- package/dist/pathless.js.map +1 -0
- package/dist/process.js +317 -0
- package/dist/process.js.map +1 -0
- package/dist/record-validation.js +44 -0
- package/dist/record-validation.js.map +1 -0
- package/dist/render.js +250 -0
- package/dist/render.js.map +1 -0
- package/dist/validation/calculate.js +102 -0
- package/dist/validation/calculate.js.map +1 -0
- package/dist/validation/decimal.js +63 -0
- package/dist/validation/decimal.js.map +1 -0
- package/dist/validation/identity.js +4 -0
- package/dist/validation/identity.js.map +1 -0
- package/dist/validation/model.js +10 -0
- package/dist/validation/model.js.map +1 -0
- package/dist/validation/schema.js +106 -0
- package/dist/validation/schema.js.map +1 -0
- package/dist/validation/semantic.js +179 -0
- package/dist/validation/semantic.js.map +1 -0
- package/dist/validation/snapshot.js +74 -0
- package/dist/validation/snapshot.js.map +1 -0
- package/dist/validation/validate.js +154 -0
- package/dist/validation/validate.js.map +1 -0
- package/dist/writer.js +107 -0
- package/dist/writer.js.map +1 -0
- package/examples/README.md +37 -0
- package/examples/manufacturing-group.json +439 -0
- package/examples/minimal.json +45 -0
- package/package.json +80 -0
- package/schema/fs-document.schema.json +335 -0
- package/schema/snapshot-diff.schema.json +96 -0
- package/schema/validation-result.schema.json +165 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { calculate } from "./calculate.js";
|
|
2
|
+
import { inputLimitFailure, inputLimits } from "../limits.js";
|
|
3
|
+
import { conformsToSchema, validateSchema } from "./schema.js";
|
|
4
|
+
import { conformsSemantically, validateSemantics } from "./semantic.js";
|
|
5
|
+
import { compareSnapshot } from "./snapshot.js";
|
|
6
|
+
const nonemptyErrors = (errors) => {
|
|
7
|
+
const [first, ...rest] = errors;
|
|
8
|
+
if (first === undefined)
|
|
9
|
+
throw new Error("Nonconforming validation lost its diagnostics");
|
|
10
|
+
return [first, ...rest];
|
|
11
|
+
};
|
|
12
|
+
const nonconforming = (errors) => ({
|
|
13
|
+
formatVersion: "0.1",
|
|
14
|
+
conformance: { status: "nonconforming", errors: nonemptyErrors(errors) },
|
|
15
|
+
calculations: { status: "not-run", applications: [] }
|
|
16
|
+
});
|
|
17
|
+
const diagnosticBytes = (errors) => Buffer.byteLength(JSON.stringify(errors), "utf8");
|
|
18
|
+
const diagnosticLimit = (errors) => diagnosticBytes(errors) > inputLimits.validationDiagnosticBytes
|
|
19
|
+
? inputLimitFailure("validation-diagnostic-bytes", inputLimits.validationDiagnosticBytes)
|
|
20
|
+
: undefined;
|
|
21
|
+
function* snapshotDecimals(snapshot) {
|
|
22
|
+
for (const application of snapshot.applications) {
|
|
23
|
+
if (application.status === "error")
|
|
24
|
+
continue;
|
|
25
|
+
yield application.actual;
|
|
26
|
+
yield application.expected;
|
|
27
|
+
yield application.difference;
|
|
28
|
+
yield application.tolerance;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function* documentDecimals(document) {
|
|
32
|
+
for (const unit of document.units) {
|
|
33
|
+
if (unit.defaultTolerance !== undefined)
|
|
34
|
+
yield unit.defaultTolerance;
|
|
35
|
+
}
|
|
36
|
+
for (const statement of document.statements) {
|
|
37
|
+
for (const item of statement.items) {
|
|
38
|
+
for (const value of Object.values(item.values)) {
|
|
39
|
+
if (typeof value === "string")
|
|
40
|
+
yield value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (document.validationSnapshot !== undefined) {
|
|
45
|
+
yield* snapshotDecimals(document.validationSnapshot);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const decimalBudgetFor = (decimals) => {
|
|
49
|
+
let total = 0;
|
|
50
|
+
for (const decimal of decimals) {
|
|
51
|
+
const digits = decimal.length - (decimal.startsWith("-") ? 1 : 0) - (decimal.includes(".") ? 1 : 0);
|
|
52
|
+
if (digits > inputLimits.decimalDigits) {
|
|
53
|
+
return inputLimitFailure("decimal-digits", inputLimits.decimalDigits);
|
|
54
|
+
}
|
|
55
|
+
total += digits;
|
|
56
|
+
if (total > inputLimits.totalDecimalDigits) {
|
|
57
|
+
return inputLimitFailure("total-decimal-digits", inputLimits.totalDecimalDigits);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
};
|
|
62
|
+
const snapshotDecimalBudget = (value) => {
|
|
63
|
+
if (value === null || typeof value !== "object" || !("validationSnapshot" in value))
|
|
64
|
+
return undefined;
|
|
65
|
+
const snapshot = value.validationSnapshot;
|
|
66
|
+
return snapshot === undefined ? undefined : decimalBudgetFor(snapshotDecimals(snapshot));
|
|
67
|
+
};
|
|
68
|
+
const structuralFailure = (value, schemaErrors) => {
|
|
69
|
+
const validation = nonconforming(schemaErrors);
|
|
70
|
+
const hasSnapshot = typeof value === "object" && value !== null && "validationSnapshot" in value;
|
|
71
|
+
const invalidSnapshot = schemaErrors.some((error) => error.path === "/validationSnapshot" || error.path.startsWith("/validationSnapshot/"));
|
|
72
|
+
if (hasSnapshot && invalidSnapshot) {
|
|
73
|
+
return {
|
|
74
|
+
validation,
|
|
75
|
+
snapshotDiff: { formatVersion: "0.1", status: "not-comparable", reason: "invalid-snapshot" }
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const snapshot = hasSnapshot
|
|
79
|
+
? value.validationSnapshot
|
|
80
|
+
: undefined;
|
|
81
|
+
return { validation, snapshotDiff: compareSnapshot(snapshot, validation) };
|
|
82
|
+
};
|
|
83
|
+
const conforming = (document) => {
|
|
84
|
+
const validation = {
|
|
85
|
+
formatVersion: "0.1",
|
|
86
|
+
conformance: { status: "conforming", errors: [] },
|
|
87
|
+
calculations: calculate(document)
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
document,
|
|
91
|
+
validation,
|
|
92
|
+
snapshotDiff: compareSnapshot(document.validationSnapshot, validation)
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const validateConformingShape = (document) => {
|
|
96
|
+
const semanticErrors = validateSemantics(document);
|
|
97
|
+
if (semanticErrors.length === 0)
|
|
98
|
+
return conforming(document);
|
|
99
|
+
const validation = nonconforming(semanticErrors);
|
|
100
|
+
return { validation, snapshotDiff: compareSnapshot(document.validationSnapshot, validation) };
|
|
101
|
+
};
|
|
102
|
+
const decimalBudget = (document) => {
|
|
103
|
+
return decimalBudgetFor(documentDecimals(document));
|
|
104
|
+
};
|
|
105
|
+
export const validateDocumentBounded = (value, jsonValues) => {
|
|
106
|
+
const complex = jsonValues > inputLimits.invalidDocumentValues;
|
|
107
|
+
const schemaErrors = complex
|
|
108
|
+
? conformsToSchema(value)
|
|
109
|
+
? []
|
|
110
|
+
: undefined
|
|
111
|
+
: validateSchema(value);
|
|
112
|
+
if (schemaErrors === undefined) {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
...inputLimitFailure("invalid-document-values", inputLimits.invalidDocumentValues)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (schemaErrors.length > 0) {
|
|
119
|
+
const invalidSnapshot = schemaErrors.some((error) => error.path === "/validationSnapshot" || error.path.startsWith("/validationSnapshot/"));
|
|
120
|
+
const snapshotLimit = invalidSnapshot ? undefined : snapshotDecimalBudget(value);
|
|
121
|
+
if (snapshotLimit !== undefined)
|
|
122
|
+
return { ok: false, ...snapshotLimit };
|
|
123
|
+
const limit = diagnosticLimit(schemaErrors);
|
|
124
|
+
return limit === undefined
|
|
125
|
+
? { ok: true, result: structuralFailure(value, schemaErrors) }
|
|
126
|
+
: { ok: false, ...limit };
|
|
127
|
+
}
|
|
128
|
+
const document = value;
|
|
129
|
+
const limit = decimalBudget(document);
|
|
130
|
+
if (limit !== undefined)
|
|
131
|
+
return { ok: false, ...limit };
|
|
132
|
+
if (complex) {
|
|
133
|
+
return conformsSemantically(document)
|
|
134
|
+
? { ok: true, result: conforming(document) }
|
|
135
|
+
: {
|
|
136
|
+
ok: false,
|
|
137
|
+
...inputLimitFailure("invalid-document-values", inputLimits.invalidDocumentValues)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const semanticErrors = validateSemantics(document);
|
|
141
|
+
if (semanticErrors.length === 0)
|
|
142
|
+
return { ok: true, result: conforming(document) };
|
|
143
|
+
const semanticLimit = diagnosticLimit(semanticErrors);
|
|
144
|
+
return semanticLimit === undefined
|
|
145
|
+
? { ok: true, result: structuralFailure(document, semanticErrors) }
|
|
146
|
+
: { ok: false, ...semanticLimit };
|
|
147
|
+
};
|
|
148
|
+
export const validateDocument = (value) => {
|
|
149
|
+
const schemaErrors = validateSchema(value);
|
|
150
|
+
return schemaErrors.length > 0
|
|
151
|
+
? structuralFailure(value, schemaErrors)
|
|
152
|
+
: validateConformingShape(value);
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/validation/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/writer.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { closeSync, fsyncSync, linkSync, lstatSync, openSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
export const outputEntryExists = (path) => {
|
|
5
|
+
try {
|
|
6
|
+
lstatSync(path);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
const code = errorCode(error);
|
|
11
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
12
|
+
return false;
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export const nodeWriterServices = {
|
|
17
|
+
exists: outputEntryExists,
|
|
18
|
+
isDirectory: (path) => statSync(path).isDirectory(),
|
|
19
|
+
openExclusive: (path) => openSync(path, "wx", 0o600),
|
|
20
|
+
write: writeFileSync,
|
|
21
|
+
sync: fsyncSync,
|
|
22
|
+
close: closeSync,
|
|
23
|
+
link: linkSync,
|
|
24
|
+
unlink: unlinkSync,
|
|
25
|
+
suffix: () => randomBytes(8).toString("hex")
|
|
26
|
+
};
|
|
27
|
+
const errorCode = (error) => typeof error === "object" && error !== null && "code" in error && typeof error.code === "string"
|
|
28
|
+
? error.code
|
|
29
|
+
: undefined;
|
|
30
|
+
const closeWithoutMasking = (descriptor, services) => {
|
|
31
|
+
if (descriptor === null)
|
|
32
|
+
return;
|
|
33
|
+
try {
|
|
34
|
+
services.close(descriptor);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// The primary write outcome remains authoritative.
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const unlinkWithoutMasking = (path, services) => {
|
|
41
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
42
|
+
try {
|
|
43
|
+
services.unlink(path);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Retry transient close/antivirus races before preserving the primary
|
|
48
|
+
// operation outcome.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
export const writeNewFile = (path, bytes, services = nodeWriterServices) => {
|
|
53
|
+
try {
|
|
54
|
+
if (services.exists(path))
|
|
55
|
+
return "output-exists";
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return "write-failed";
|
|
59
|
+
}
|
|
60
|
+
const parent = dirname(path);
|
|
61
|
+
try {
|
|
62
|
+
if (!services.isDirectory(parent))
|
|
63
|
+
return "output-parent-not-found";
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const code = errorCode(error);
|
|
67
|
+
return code === "ENOENT" || code === "ENOTDIR" ? "output-parent-not-found" : "write-failed";
|
|
68
|
+
}
|
|
69
|
+
let temporary;
|
|
70
|
+
try {
|
|
71
|
+
temporary = join(parent, `.fs-${services.suffix()}.tmp`);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return "write-failed";
|
|
75
|
+
}
|
|
76
|
+
let descriptor = null;
|
|
77
|
+
let ownsTemporary = false;
|
|
78
|
+
try {
|
|
79
|
+
descriptor = services.openExclusive(temporary);
|
|
80
|
+
ownsTemporary = true;
|
|
81
|
+
services.write(descriptor, bytes);
|
|
82
|
+
services.sync(descriptor);
|
|
83
|
+
services.close(descriptor);
|
|
84
|
+
descriptor = null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
closeWithoutMasking(descriptor, services);
|
|
88
|
+
if (ownsTemporary)
|
|
89
|
+
unlinkWithoutMasking(temporary, services);
|
|
90
|
+
return "write-failed";
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
services.link(temporary, path);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
unlinkWithoutMasking(temporary, services);
|
|
97
|
+
return errorCode(error) === "EEXIST" ? "output-exists" : "write-failed";
|
|
98
|
+
}
|
|
99
|
+
// Once the hard link succeeds, the destination is a synced, exact copy and
|
|
100
|
+
// the operation has committed. Cleanup must not turn that success into a
|
|
101
|
+
// reported failure or attempt to remove a destination another process can
|
|
102
|
+
// already observe. A persistent unlink fault can retain only the complete,
|
|
103
|
+
// private-mode temporary hard link; it cannot expose a partial destination.
|
|
104
|
+
unlinkWithoutMasking(temporary, services);
|
|
105
|
+
return null;
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../src/writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# V0 Examples
|
|
2
|
+
|
|
3
|
+
These examples provide conformance evidence for the current `0.1`
|
|
4
|
+
[semantic specification](https://cpaikr.github.io/fs/spec/0.1/). They
|
|
5
|
+
demonstrate complete artifacts rather than acting as partially completed
|
|
6
|
+
authoring templates. See the [bundled authoring guide](../assets/guide/authoring.md)
|
|
7
|
+
for the encoding workflow.
|
|
8
|
+
|
|
9
|
+
## Files
|
|
10
|
+
|
|
11
|
+
- `minimal.json` is the smallest complete statement-row document. It omits
|
|
12
|
+
optional identifiers, grouping columns, rollups, and validation snapshot, so
|
|
13
|
+
its calculation status is `not-defined`.
|
|
14
|
+
- `manufacturing-group.json` combines income, balance-sheet, cash-flow, equity,
|
|
15
|
+
and manufacturing statements for one entity. It carries the optional
|
|
16
|
+
canonical `$schema` discovery pointer, is structurally conforming, and is
|
|
17
|
+
deliberately calculation-inconsistent.
|
|
18
|
+
|
|
19
|
+
## Manufacturing Example Evidence
|
|
20
|
+
|
|
21
|
+
- Statements own their ordered items and select their display periods.
|
|
22
|
+
- Income uses a nested revenue and cost-of-sales subtotal graph; the explicit
|
|
23
|
+
2025 gross-profit value is deliberately inconsistent with its direct
|
|
24
|
+
children.
|
|
25
|
+
- Balance sheet, cash flow, equity, and manufacturing statements include
|
|
26
|
+
satisfied rollups alongside that failure.
|
|
27
|
+
- Item identifiers such as `materials` and `labor` repeat across statements,
|
|
28
|
+
proving item and rollup identity is statement-local.
|
|
29
|
+
- `majorGroup` and `valuation` demonstrate exact grouping maps, including null
|
|
30
|
+
grouping cells.
|
|
31
|
+
- Most rows use KRW millions while the EPS row uses KRW per share, proving
|
|
32
|
+
mixed-unit statement presentation without permitting mixed-unit rollup
|
|
33
|
+
edges.
|
|
34
|
+
- Values include exact decimals, signs, zero, and explicit unavailability.
|
|
35
|
+
|
|
36
|
+
Structural conformance and calculation consistency are separate outcomes; the
|
|
37
|
+
example is valid even though one rollup application is unsatisfied.
|