@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.
Files changed (56) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +73 -0
  3. package/assets/guide/authoring.md +125 -0
  4. package/dist/application.js +34 -0
  5. package/dist/application.js.map +1 -0
  6. package/dist/assets.js +20 -0
  7. package/dist/assets.js.map +1 -0
  8. package/dist/bin.js +9 -0
  9. package/dist/bin.js.map +1 -0
  10. package/dist/cli.js +150 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/content.js +47 -0
  13. package/dist/content.js.map +1 -0
  14. package/dist/io.js +76 -0
  15. package/dist/io.js.map +1 -0
  16. package/dist/json.js +291 -0
  17. package/dist/json.js.map +1 -0
  18. package/dist/limits.js +15 -0
  19. package/dist/limits.js.map +1 -0
  20. package/dist/logger.js +26 -0
  21. package/dist/logger.js.map +1 -0
  22. package/dist/node-services.js +9 -0
  23. package/dist/node-services.js.map +1 -0
  24. package/dist/pathless.js +72 -0
  25. package/dist/pathless.js.map +1 -0
  26. package/dist/process.js +317 -0
  27. package/dist/process.js.map +1 -0
  28. package/dist/record-validation.js +44 -0
  29. package/dist/record-validation.js.map +1 -0
  30. package/dist/render.js +250 -0
  31. package/dist/render.js.map +1 -0
  32. package/dist/validation/calculate.js +102 -0
  33. package/dist/validation/calculate.js.map +1 -0
  34. package/dist/validation/decimal.js +63 -0
  35. package/dist/validation/decimal.js.map +1 -0
  36. package/dist/validation/identity.js +4 -0
  37. package/dist/validation/identity.js.map +1 -0
  38. package/dist/validation/model.js +10 -0
  39. package/dist/validation/model.js.map +1 -0
  40. package/dist/validation/schema.js +106 -0
  41. package/dist/validation/schema.js.map +1 -0
  42. package/dist/validation/semantic.js +179 -0
  43. package/dist/validation/semantic.js.map +1 -0
  44. package/dist/validation/snapshot.js +74 -0
  45. package/dist/validation/snapshot.js.map +1 -0
  46. package/dist/validation/validate.js +154 -0
  47. package/dist/validation/validate.js.map +1 -0
  48. package/dist/writer.js +107 -0
  49. package/dist/writer.js.map +1 -0
  50. package/examples/README.md +37 -0
  51. package/examples/manufacturing-group.json +439 -0
  52. package/examples/minimal.json +45 -0
  53. package/package.json +80 -0
  54. package/schema/fs-document.schema.json +335 -0
  55. package/schema/snapshot-diff.schema.json +96 -0
  56. 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.