flexdataset 0.4.1

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 (39) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +30 -0
  3. package/dist/src/cli.d.ts +9 -0
  4. package/dist/src/cli.js +179 -0
  5. package/dist/src/diagram/dag.d.ts +16 -0
  6. package/dist/src/diagram/dag.js +58 -0
  7. package/dist/src/diagram/er.d.ts +16 -0
  8. package/dist/src/diagram/er.js +62 -0
  9. package/dist/src/diagram/render.d.ts +16 -0
  10. package/dist/src/diagram/render.js +24 -0
  11. package/dist/src/iceberg.d.ts +85 -0
  12. package/dist/src/iceberg.js +221 -0
  13. package/dist/src/index.d.ts +18 -0
  14. package/dist/src/index.js +56 -0
  15. package/dist/src/loader.d.ts +26 -0
  16. package/dist/src/loader.js +239 -0
  17. package/dist/src/model.d.ts +104 -0
  18. package/dist/src/model.js +26 -0
  19. package/dist/src/schema/schema.schema.json +27 -0
  20. package/dist/src/schema/table.schema.json +128 -0
  21. package/dist/src/structural.d.ts +31 -0
  22. package/dist/src/structural.js +54 -0
  23. package/dist/src/table-type.d.ts +115 -0
  24. package/dist/src/table-type.js +275 -0
  25. package/dist/src/table-types/hive-parquet.d.ts +29 -0
  26. package/dist/src/table-types/hive-parquet.js +70 -0
  27. package/dist/src/table-types/iceberg-parquet.d.ts +41 -0
  28. package/dist/src/table-types/iceberg-parquet.js +103 -0
  29. package/dist/src/table-types/postgres-18.d.ts +25 -0
  30. package/dist/src/table-types/postgres-18.js +44 -0
  31. package/dist/src/table-types/registry.d.ts +13 -0
  32. package/dist/src/table-types/registry.js +36 -0
  33. package/dist/src/types.d.ts +11 -0
  34. package/dist/src/types.js +182 -0
  35. package/dist/src/validate.d.ts +13 -0
  36. package/dist/src/validate.js +30 -0
  37. package/dist/src/world.d.ts +39 -0
  38. package/dist/src/world.js +82 -0
  39. package/package.json +69 -0
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ /**
3
+ * Filesystem loader. Walks a dataset root, parses each JSON file, runs Layer 1
4
+ * structural validation, and normalizes everything into a `World` of
5
+ * concrete `TableTypeBase` instances that the semantic rules operate on.
6
+ *
7
+ * Parse errors, structural errors, and a missing schema-description file are
8
+ * reported here; all cross-field / cross-file logic lives in the table-type
9
+ * classes (`./table-type.ts`, `./table-types/*`).
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.loadRoot = loadRoot;
36
+ const fs = __importStar(require("fs"));
37
+ const path = __importStar(require("path"));
38
+ const structural_1 = require("./structural");
39
+ const registry_1 = require("./table-types/registry");
40
+ function asRecord(value) {
41
+ return value !== null && typeof value === 'object' ? value : {};
42
+ }
43
+ function asArray(value) {
44
+ return Array.isArray(value) ? value : [];
45
+ }
46
+ function asString(value) {
47
+ return typeof value === 'string' ? value : '';
48
+ }
49
+ function asBoolean(value) {
50
+ return typeof value === 'boolean' ? value : false;
51
+ }
52
+ function asStringArray(value) {
53
+ return asArray(value).filter((item) => typeof item === 'string');
54
+ }
55
+ function normalizeColumns(value) {
56
+ return asArray(value).map((raw) => {
57
+ const record = asRecord(raw);
58
+ return {
59
+ name: asString(record.name),
60
+ type: asString(record.type),
61
+ description: asString(record.description),
62
+ };
63
+ });
64
+ }
65
+ function normalizePartitions(value) {
66
+ return asArray(value).map((raw) => {
67
+ const record = asRecord(raw);
68
+ return {
69
+ name: asString(record.name),
70
+ type: asString(record.type),
71
+ description: asString(record.description),
72
+ };
73
+ });
74
+ }
75
+ function normalizeForeignKeys(value) {
76
+ return asArray(value).map((raw) => {
77
+ const record = asRecord(raw);
78
+ return {
79
+ sourceTable: asString(record.sourceTable),
80
+ sourceColumn: asString(record.sourceColumn),
81
+ localColumn: asString(record.localColumn),
82
+ allowNulls: asBoolean(record.allowNulls),
83
+ };
84
+ });
85
+ }
86
+ function normalizeTableDefinition(raw) {
87
+ const record = asRecord(raw);
88
+ return {
89
+ specVersion: asString(record.specVersion),
90
+ description: asString(record.description),
91
+ tableType: asString(record.tableType),
92
+ isRawData: asBoolean(record.isRawData),
93
+ columns: normalizeColumns(record.columns),
94
+ primaryKey: asStringArray(record.primaryKey),
95
+ partitions: normalizePartitions(record.partitions),
96
+ dependsOn: asStringArray(record.dependsOn),
97
+ foreignKeys: normalizeForeignKeys(record.foreignKeys),
98
+ };
99
+ }
100
+ function normalizeSchemaDescription(raw) {
101
+ const record = asRecord(raw);
102
+ return {
103
+ specVersion: asString(record.specVersion),
104
+ description: asString(record.description),
105
+ };
106
+ }
107
+ /// Schema and table names must be lowercase snake_case so they can be referenced
108
+ /// from `dependsOn` and foreign keys, whose patterns require the same shape.
109
+ const NAME_RE = /^[a-z0-9_]+$/;
110
+ /**
111
+ * Load a dataset root into a `World`.
112
+ *
113
+ * @param rootDir Absolute or relative path to the dataset root.
114
+ * @returns The loaded world plus load-time violations.
115
+ * @throws Error When `rootDir` is not an existing directory.
116
+ */
117
+ function loadRoot(rootDir) {
118
+ const absoluteRoot = path.resolve(rootDir);
119
+ if (!fs.existsSync(absoluteRoot) || !fs.statSync(absoluteRoot).isDirectory()) {
120
+ throw new Error(`dataset root is not a directory: ${absoluteRoot}`);
121
+ }
122
+ const violations = [];
123
+ const schemas = new Map();
124
+ const tables = new Map();
125
+ const schemaDirs = fs.readdirSync(absoluteRoot, {
126
+ withFileTypes: true,
127
+ }).filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))
128
+ .sort((a, b) => a.name.localeCompare(b.name));
129
+ for (const schemaDir of schemaDirs) {
130
+ const schemaName = schemaDir.name;
131
+ const dirPath = path.join(absoluteRoot, schemaName);
132
+ if (!NAME_RE.test(schemaName)) {
133
+ violations.push({
134
+ level: 'error',
135
+ code: 'SCHEMA_NAME_VALID',
136
+ schema: schemaName,
137
+ path: dirPath,
138
+ message: `schema name "${schemaName}" must be lowercase snake_case (matching ${NAME_RE})`,
139
+ });
140
+ }
141
+ const descFileName = `${schemaName}.json`;
142
+ const jsonFiles = fs.readdirSync(dirPath)
143
+ .filter((file) => file.endsWith('.json'))
144
+ .sort((a, b) => a.localeCompare(b));
145
+ let description = null;
146
+ const loadedTables = [];
147
+ for (const file of jsonFiles) {
148
+ const filePath = path.join(dirPath, file);
149
+ const text = fs.readFileSync(filePath, 'utf-8');
150
+ let parsed;
151
+ try {
152
+ parsed = JSON.parse(text);
153
+ }
154
+ catch (error) {
155
+ violations.push({
156
+ level: 'error',
157
+ code: 'FILE_PARSE_ERROR',
158
+ schema: schemaName,
159
+ path: filePath,
160
+ message: `invalid JSON: ${error.message}`,
161
+ });
162
+ continue;
163
+ }
164
+ if (file === descFileName) {
165
+ const structural = (0, structural_1.validateStructure)('schema', parsed);
166
+ for (const structuralError of structural.errors) {
167
+ violations.push({
168
+ level: 'error',
169
+ code: 'SCHEMA_VALIDATION',
170
+ schema: schemaName,
171
+ field: structuralError.field,
172
+ path: filePath,
173
+ message: structuralError.message,
174
+ });
175
+ }
176
+ description = normalizeSchemaDescription(parsed);
177
+ continue;
178
+ }
179
+ const tableName = file.slice(0, -'.json'.length);
180
+ const qualifiedName = `${schemaName}.${tableName}`;
181
+ if (!NAME_RE.test(tableName)) {
182
+ violations.push({
183
+ level: 'error',
184
+ code: 'TABLE_NAME_VALID',
185
+ schema: schemaName,
186
+ table: tableName,
187
+ path: filePath,
188
+ message: `table name "${tableName}" must be lowercase snake_case (matching ${NAME_RE})`,
189
+ });
190
+ }
191
+ const structural = (0, structural_1.validateStructure)('table', parsed);
192
+ for (const structuralError of structural.errors) {
193
+ violations.push({
194
+ level: 'error',
195
+ code: 'SCHEMA_VALIDATION',
196
+ schema: schemaName,
197
+ table: tableName,
198
+ field: structuralError.field,
199
+ path: filePath,
200
+ message: structuralError.message,
201
+ });
202
+ }
203
+ const loadedTable = (0, registry_1.createTableType)({
204
+ schema: schemaName,
205
+ name: tableName,
206
+ qualifiedName,
207
+ filePath,
208
+ structurallyValid: structural.valid,
209
+ definition: normalizeTableDefinition(parsed),
210
+ });
211
+ loadedTables.push(loadedTable);
212
+ tables.set(qualifiedName, loadedTable);
213
+ }
214
+ if (description === null) {
215
+ violations.push({
216
+ level: 'error',
217
+ code: 'SCHEMA_DESC_PRESENT',
218
+ schema: schemaName,
219
+ path: path.join(dirPath, descFileName),
220
+ message: `schema "${schemaName}" is missing its description file "${descFileName}"`,
221
+ });
222
+ }
223
+ schemas.set(schemaName, {
224
+ name: schemaName,
225
+ dirPath,
226
+ description,
227
+ tables: loadedTables,
228
+ });
229
+ }
230
+ return {
231
+ world: {
232
+ rootDir: absoluteRoot,
233
+ schemas,
234
+ tables,
235
+ },
236
+ violations,
237
+ };
238
+ }
239
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xvYWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7O0dBUUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE0SEgsNEJBd0lDO0FBbFFELHVDQUF5QjtBQUN6QiwyQ0FBNkI7QUFVN0IsNkNBRXNCO0FBSXRCLHFEQUVnQztBQWVoQyxTQUFTLFFBQVEsQ0FBQyxLQUFjO0lBQzVCLE9BQU8sS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQWdDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUMvRixDQUFDO0FBRUQsU0FBUyxPQUFPLENBQUMsS0FBYztJQUMzQixPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0FBQzdDLENBQUM7QUFFRCxTQUFTLFFBQVEsQ0FBQyxLQUFjO0lBQzVCLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUNsRCxDQUFDO0FBRUQsU0FBUyxTQUFTLENBQUMsS0FBYztJQUM3QixPQUFPLE9BQU8sS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFDdEQsQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFDLEtBQWM7SUFDakMsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFrQixFQUFFLENBQUMsT0FBTyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUM7QUFDckYsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQUMsS0FBYztJQUNwQyxPQUFPLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENB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T0FBTztZQUNQLFdBQVc7WUFDWCxNQUFNLEVBQUUsWUFBWTtTQUN2QixDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsT0FBTztRQUNILEtBQUssRUFBRTtZQUNILE9BQU8sRUFBRSxZQUFZO1lBQ3JCLE9BQU87WUFDUCxNQUFNO1NBQ1Q7UUFDRCxVQUFVO0tBQ2IsQ0FBQztBQUNOLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZpbGVzeXN0ZW0gbG9hZGVyLiBXYWxrcyBhIGRhdGFzZXQgcm9vdCwgcGFyc2VzIGVhY2ggSlNPTiBmaWxlLCBydW5zIExheWVyIDFcbiAqIHN0cnVjdHVyYWwgdmFsaWRhdGlvbiwgYW5kIG5vcm1hbGl6ZXMgZXZlcnl0aGluZyBpbnRvIGEgYFdvcmxkYCBvZlxuICogY29uY3JldGUgYFRhYmxlVHlwZUJhc2VgIGluc3RhbmNlcyB0aGF0IHRoZSBzZW1hbnRpYyBydWxlcyBvcGVyYXRlIG9uLlxuICpcbiAqIFBhcnNlIGVycm9ycywgc3RydWN0dXJhbCBlcnJvcnMsIGFuZCBhIG1pc3Npbmcgc2NoZW1hLWRlc2NyaXB0aW9uIGZpbGUgYXJlXG4gKiByZXBvcnRlZCBoZXJlOyBhbGwgY3Jvc3MtZmllbGQgLyBjcm9zcy1maWxlIGxvZ2ljIGxpdmVzIGluIHRoZSB0YWJsZS10eXBlXG4gKiBjbGFzc2VzIChgLi90YWJsZS10eXBlLnRzYCwgYC4vdGFibGUtdHlwZXMvKmApLlxuICovXG5cbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7XG4gICAgQ29sdW1uLFxuICAgIEZvcmVpZ25LZXksXG4gICAgUGFydGl0aW9uLFxuICAgIFNjaGVtYURlc2NyaXB0aW9uLFxuICAgIFRhYmxlRGVmaW5pdGlvbixcbiAgICBWaW9sYXRpb24sXG59IGZyb20gJy4vbW9kZWwnO1xuaW1wb3J0IHtcbiAgICB2YWxpZGF0ZVN0cnVjdHVyZSxcbn0gZnJvbSAnLi9zdHJ1Y3R1cmFsJztcbmltcG9ydCB7XG4gICAgVGFibGVUeXBlQmFzZSxcbn0gZnJvbSAnLi90YWJsZS10eXBlJztcbmltcG9ydCB7XG4gICAgY3JlYXRlVGFibGVUeXBlLFxufSBmcm9tICcuL3RhYmxlLXR5cGVzL3JlZ2lzdHJ5JztcbmltcG9ydCB7XG4gICAgTG9hZGVkU2NoZW1hLFxuICAgIFdvcmxkLFxufSBmcm9tICcuL3dvcmxkJztcblxuLyoqIFJlc3VsdCBvZiBsb2FkaW5nIGEgcm9vdDogdGhlIG1vZGVsIHBsdXMgYW55IGxvYWQtdGltZSB2aW9sYXRpb25zLiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2FkT3V0Y29tZSB7XG4gICAgLyoqIFRoZSBsb2FkZWQgbW9kZWwuICovXG4gICAgcmVhZG9ubHkgd29ybGQ6IFdvcmxkO1xuXG4gICAgLyoqIFBhcnNlLCBzdHJ1Y3R1cmFsLCBhbmQgbWlzc2luZy1kZXNjcmlwdGlvbiB2aW9sYXRpb25zLiAqL1xuICAgIHJlYWRvbmx5IHZpb2xhdGlvbnM6IFZpb2xhdGlvbltdO1xufVxuXG5mdW5jdGlvbiBhc1JlY29yZCh2YWx1ZTogdW5rbm93bik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgICByZXR1cm4gdmFsdWUgIT09IG51bGwgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyA/IHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IDoge307XG59XG5cbmZ1bmN0aW9uIGFzQXJyYXkodmFsdWU6IHVua25vd24pOiB1bmtub3duW10ge1xuICAgIHJldHVybiBBcnJheS5pc0FycmF5KHZhbHVlKSA/IHZhbHVlIDogW107XG59XG5cbmZ1bmN0aW9uIGFzU3RyaW5nKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/IHZhbHVlIDogJyc7XG59XG5cbmZ1bmN0aW9uIGFzQm9vbGVhbih2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdib29sZWFuJyA/IHZhbHVlIDogZmFsc2U7XG59XG5cbmZ1bmN0aW9uIGFzU3RyaW5nQXJyYXkodmFsdWU6IHVua25vd24pOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIGFzQXJyYXkodmFsdWUpLmZpbHRlcigoaXRlbSk6IGl0ZW0gaXMgc3RyaW5nID0+IHR5cGVvZiBpdGVtID09PSAnc3RyaW5nJyk7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZUNvbHVtbnModmFsdWU6IHVua25vd24pOiBDb2x1bW5bXSB7XG4gICAgcmV0dXJuIGFzQXJyYXkodmFsdWUpLm1hcCgocmF3KSA9PiB7XG4gICAgICAgIGNvbnN0IHJlY29yZCA9IGFzUmVjb3JkKHJhdyk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBuYW1lOiBhc1N0cmluZyhyZWNvcmQubmFtZSksXG4gICAgICAgICAgICB0eXBlOiBhc1N0cmluZyhyZWNvcmQudHlwZSksXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogYXNTdHJpbmcocmVjb3JkLmRlc2NyaXB0aW9uKSxcbiAgICAgICAgfTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplUGFydGl0aW9ucyh2YWx1ZTogdW5rbm93bik6IFBhcnRpdGlvbltdIHtcbiAgICByZXR1cm4gYXNBcnJheSh2YWx1ZSkubWFwKChyYXcpID0+IHtcbiAgICAgICAgY29uc3QgcmVjb3JkID0gYXNSZWNvcmQocmF3KTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG5hbWU6IGFzU3RyaW5nKHJlY29yZC5uYW1lKSxcbiAgICAgICAgICAgIHR5cGU6IGFzU3RyaW5nKHJlY29yZC50eXBlKSxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBhc1N0cmluZyhyZWNvcmQuZGVzY3JpcHRpb24pLFxuICAgICAgICB9O1xuICAgIH0pO1xufVxuXG5mdW5jdGlvbiBub3JtYWxpemVGb3JlaWduS2V5cyh2YWx1ZTogdW5rbm93bik6IEZvcmVpZ25LZXlbXSB7XG4gICAgcmV0dXJuIGFzQXJyYXkodmFsdWUpLm1hcCgocmF3KSA9PiB7XG4gICAgICAgIGNvbnN0IHJlY29yZCA9IGFzUmVjb3JkKHJhdyk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzb3VyY2VUYWJsZTogYXNTdHJpbmcocmVjb3JkLnNvdXJjZVRhYmxlKSxcbiAgICAgICAgICAgIHNvdXJjZUNvbHVtbjogYXNTdHJpbmcocmVjb3JkLnNvdXJjZUNvbHVtbiksXG4gICAgICAgICAgICBsb2NhbENvbHVtbjogYXNTdHJpbmcocmVjb3JkLmxvY2FsQ29sdW1uKSxcbiAgICAgICAgICAgIGFsbG93TnVsbHM6IGFzQm9vbGVhbihyZWNvcmQuYWxsb3dOdWxscyksXG4gICAgICAgIH07XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZVRhYmxlRGVmaW5pdGlvbihyYXc6IHVua25vd24pOiBUYWJsZURlZmluaXRpb24ge1xuICAgIGNvbnN0IHJlY29yZCA9IGFzUmVjb3JkKHJhdyk7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgc3BlY1ZlcnNpb246IGFzU3RyaW5nKHJlY29yZC5zcGVjVmVyc2lvbiksXG4gICAgICAgIGRlc2NyaXB0aW9uOiBhc1N0cmluZyhyZWNvcmQuZGVzY3JpcHRpb24pLFxuICAgICAgICB0YWJsZVR5cGU6IGFzU3RyaW5nKHJlY29yZC50YWJsZVR5cGUpLFxuICAgICAgICBpc1Jhd0RhdGE6IGFzQm9vbGVhbihyZWNvcmQuaXNSYXdEYXRhKSxcbiAgICAgICAgY29sdW1uczogbm9ybWFsaXplQ29sdW1ucyhyZWNvcmQuY29sdW1ucyksXG4gICAgICAgIHByaW1hcnlLZXk6IGFzU3RyaW5nQXJyYXkocmVjb3JkLnByaW1hcnlLZXkpLFxuICAgICAgICBwYXJ0aXRpb25zOiBub3JtYWxpemVQYXJ0aXRpb25zKHJlY29yZC5wYXJ0aXRpb25zKSxcbiAgICAgICAgZGVwZW5kc09uOiBhc1N0cmluZ0FycmF5KHJlY29yZC5kZXBlbmRzT24pLFxuICAgICAgICBmb3JlaWduS2V5czogbm9ybWFsaXplRm9yZWlnbktleXMocmVjb3JkLmZvcmVpZ25LZXlzKSxcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBub3JtYWxpemVTY2hlbWFEZXNjcmlwdGlvbihyYXc6IHVua25vd24pOiBTY2hlbWFEZXNjcmlwdGlvbiB7XG4gICAgY29uc3QgcmVjb3JkID0gYXNSZWNvcmQocmF3KTtcbiAgICByZXR1cm4ge1xuICAgICAgICBzcGVjVmVyc2lvbjogYXNTdHJpbmcocmVjb3JkLnNwZWNWZXJzaW9uKSxcbiAgICAgICAgZGVzY3JpcHRpb246IGFzU3RyaW5nKHJlY29yZC5kZXNjcmlwdGlvbiksXG4gICAgfTtcbn1cblxuLy8vIFNjaGVtYSBhbmQgdGFibGUgbmFtZXMgbXVzdCBiZSBsb3dlcmNhc2Ugc25ha2VfY2FzZSBzbyB0aGV5IGNhbiBiZSByZWZlcmVuY2VkXG4vLy8gZnJvbSBgZGVwZW5kc09uYCBhbmQgZm9yZWlnbiBrZXlzLCB3aG9zZSBwYXR0ZXJucyByZXF1aXJlIHRoZSBzYW1lIHNoYXBlLlxuY29uc3QgTkFNRV9SRSA9IC9eW2EtejAtOV9dKyQvO1xuXG4vKipcbiAqIExvYWQgYSBkYXRhc2V0IHJvb3QgaW50byBhIGBXb3JsZGAuXG4gKlxuICogQHBhcmFtIHJvb3REaXIgQWJzb2x1dGUgb3IgcmVsYXRpdmUgcGF0aCB0byB0aGUgZGF0YXNldCByb290LlxuICogQHJldHVybnMgVGhlIGxvYWRlZCB3b3JsZCBwbHVzIGxvYWQtdGltZSB2aW9sYXRpb25zLlxuICogQHRocm93cyBFcnJvciBXaGVuIGByb290RGlyYCBpcyBub3QgYW4gZXhpc3RpbmcgZGlyZWN0b3J5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gbG9hZFJvb3Qocm9vdERpcjogc3RyaW5nKTogTG9hZE91dGNvbWUge1xuICAgIGNvbnN0IGFic29sdXRlUm9vdCA9IHBhdGgucmVzb2x2ZShyb290RGlyKTtcbiAgICBpZiAoIWZzLmV4aXN0c1N5bmMoYWJzb2x1dGVSb290KSB8fCAhZnMuc3RhdFN5bmMoYWJzb2x1dGVSb290KS5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgZGF0YXNldCByb290IGlzIG5vdCBhIGRpcmVjdG9yeTogJHthYnNvbHV0ZVJvb3R9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgdmlvbGF0aW9uczogVmlvbGF0aW9uW10gPSBbXTtcbiAgICBjb25zdCBzY2hlbWFzID0gbmV3IE1hcDxzdHJpbmcsIExvYWRlZFNjaGVtYT4oKTtcbiAgICBjb25zdCB0YWJsZXMgPSBuZXcgTWFwPHN0cmluZywgVGFibGVUeXBlQmFzZT4oKTtcblxuICAgIGNvbnN0IHNjaGVtYURpcnMgPSBmcy5yZWFkZGlyU3luYyhhYnNvbHV0ZVJvb3QsIHtcbiAgICAgICAgd2l0aEZpbGVUeXBlczogdHJ1ZSxcbiAgICB9KS5maWx0ZXIoKGVudHJ5KSA9PiBlbnRyeS5pc0RpcmVjdG9yeSgpICYmICFlbnRyeS5uYW1lLnN0YXJ0c1dpdGgoJy4nKSlcbiAgICAgICAgLnNvcnQoKGEsIGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkpO1xuXG4gICAgZm9yIChjb25zdCBzY2hlbWFEaXIgb2Ygc2NoZW1hRGlycykge1xuICAgICAgICBjb25zdCBzY2hlbWFOYW1lID0gc2NoZW1hRGlyLm5hbWU7XG4gICAgICAgIGNvbnN0IGRpclBhdGggPSBwYXRoLmpvaW4oYWJzb2x1dGVSb290LCBzY2hlbWFOYW1lKTtcblxuICAgICAgICBpZiAoIU5BTUVfUkUudGVzdChzY2hlbWFOYW1lKSkge1xuICAgICAgICAgICAgdmlvbGF0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgICAgICBsZXZlbDogJ2Vycm9yJyxcbiAgICAgICAgICAgICAgICBjb2RlOiAnU0NIRU1BX05BTUVfVkFMSUQnLFxuICAgICAgICAgICAgICAgIHNjaGVtYTogc2NoZW1hTmFtZSxcbiAgICAgICAgICAgICAgICBwYXRoOiBkaXJQYXRoLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBzY2hlbWEgbmFtZSBcIiR7c2NoZW1hTmFtZX1cIiBtdXN0IGJlIGxvd2VyY2FzZSBzbmFrZV9jYXNlIChtYXRjaGluZyAke05BTUVfUkV9KWAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRlc2NGaWxlTmFtZSA9IGAke3NjaGVtYU5hbWV9Lmpzb25gO1xuICAgICAgICBjb25zdCBqc29uRmlsZXMgPSBmcy5yZWFkZGlyU3luYyhkaXJQYXRoKVxuICAgICAgICAgICAgLmZpbHRlcigoZmlsZSkgPT4gZmlsZS5lbmRzV2l0aCgnLmpzb24nKSlcbiAgICAgICAgICAgIC5zb3J0KChhLCBiKSA9PiBhLmxvY2FsZUNvbXBhcmUoYikpO1xuXG4gICAgICAgIGxldCBkZXNjcmlwdGlvbjogU2NoZW1hRGVzY3JpcHRpb24gfCBudWxsID0gbnVsbDtcbiAgICAgICAgY29uc3QgbG9hZGVkVGFibGVzOiBUYWJsZVR5cGVCYXNlW10gPSBbXTtcblxuICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YganNvbkZpbGVzKSB7XG4gICAgICAgICAgICBjb25zdCBmaWxlUGF0aCA9IHBhdGguam9pbihkaXJQYXRoLCBmaWxlKTtcbiAgICAgICAgICAgIGNvbnN0IHRleHQgPSBmcy5yZWFkRmlsZVN5bmMoZmlsZVBhdGgsICd1dGYtOCcpO1xuXG4gICAgICAgICAgICBsZXQgcGFyc2VkOiB1bmtub3duO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBwYXJzZWQgPSBKU09OLnBhcnNlKHRleHQpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICB2aW9sYXRpb25zLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBsZXZlbDogJ2Vycm9yJyxcbiAgICAgICAgICAgICAgICAgICAgY29kZTogJ0ZJTEVfUEFSU0VfRVJST1InLFxuICAgICAgICAgICAgICAgICAgICBzY2hlbWE6IHNjaGVtYU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgaW52YWxpZCBKU09OOiAkeyhlcnJvciBhcyBFcnJvcikubWVzc2FnZX1gLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoZmlsZSA9PT0gZGVzY0ZpbGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3RydWN0dXJhbCA9IHZhbGlkYXRlU3RydWN0dXJlKCdzY2hlbWEnLCBwYXJzZWQpO1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgc3RydWN0dXJhbEVycm9yIG9mIHN0cnVjdHVyYWwuZXJyb3JzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXZlbDogJ2Vycm9yJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvZGU6ICdTQ0hFTUFfVkFMSURBVElPTicsXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2hlbWE6IHNjaGVtYU5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBmaWVsZDogc3RydWN0dXJhbEVycm9yLmZpZWxkLFxuICAgICAgICAgICAgICAgICAgICAgICAgcGF0aDogZmlsZVBhdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBzdHJ1Y3R1cmFsRXJyb3IubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uID0gbm9ybWFsaXplU2NoZW1hRGVzY3JpcHRpb24ocGFyc2VkKTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgdGFibGVOYW1lID0gZmlsZS5zbGljZSgwLCAtJy5qc29uJy5sZW5ndGgpO1xuICAgICAgICAgICAgY29uc3QgcXVhbGlmaWVkTmFtZSA9IGAke3NjaGVtYU5hbWV9LiR7dGFibGVOYW1lfWA7XG5cbiAgICAgICAgICAgIGlmICghTkFNRV9SRS50ZXN0KHRhYmxlTmFtZSkpIHtcbiAgICAgICAgICAgICAgICB2aW9sYXRpb25zLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBsZXZlbDogJ2Vycm9yJyxcbiAgICAgICAgICAgICAgICAgICAgY29kZTogJ1RBQkxFX05BTUVfVkFMSUQnLFxuICAgICAgICAgICAgICAgICAgICBzY2hlbWE6IHNjaGVtYU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHRhYmxlOiB0YWJsZU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgdGFibGUgbmFtZSBcIiR7dGFibGVOYW1lfVwiIG11c3QgYmUgbG93ZXJjYXNlIHNuYWtlX2Nhc2UgKG1hdGNoaW5nICR7TkFNRV9SRX0pYCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3Qgc3RydWN0dXJhbCA9IHZhbGlkYXRlU3RydWN0dXJlKCd0YWJsZScsIHBhcnNlZCk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHN0cnVjdHVyYWxFcnJvciBvZiBzdHJ1Y3R1cmFsLmVycm9ycykge1xuICAgICAgICAgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGxldmVsOiAnZXJyb3InLFxuICAgICAgICAgICAgICAgICAgICBjb2RlOiAnU0NIRU1BX1ZBTElEQVRJT04nLFxuICAgICAgICAgICAgICAgICAgICBzY2hlbWE6IHNjaGVtYU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHRhYmxlOiB0YWJsZU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIGZpZWxkOiBzdHJ1Y3R1cmFsRXJyb3IuZmllbGQsXG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IGZpbGVQYXRoLFxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBzdHJ1Y3R1cmFsRXJyb3IubWVzc2FnZSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbG9hZGVkVGFibGUgPSBjcmVhdGVUYWJsZVR5cGUoe1xuICAgICAgICAgICAgICAgIHNjaGVtYTogc2NoZW1hTmFtZSxcbiAgICAgICAgICAgICAgICBuYW1lOiB0YWJsZU5hbWUsXG4gICAgICAgICAgICAgICAgcXVhbGlmaWVkTmFtZSxcbiAgICAgICAgICAgICAgICBmaWxlUGF0aCxcbiAgICAgICAgICAgICAgICBzdHJ1Y3R1cmFsbHlWYWxpZDogc3RydWN0dXJhbC52YWxpZCxcbiAgICAgICAgICAgICAgICBkZWZpbml0aW9uOiBub3JtYWxpemVUYWJsZURlZmluaXRpb24ocGFyc2VkKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgbG9hZGVkVGFibGVzLnB1c2gobG9hZGVkVGFibGUpO1xuICAgICAgICAgICAgdGFibGVzLnNldChxdWFsaWZpZWROYW1lLCBsb2FkZWRUYWJsZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZGVzY3JpcHRpb24gPT09IG51bGwpIHtcbiAgICAgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICAgICAgbGV2ZWw6ICdlcnJvcicsXG4gICAgICAgICAgICAgICAgY29kZTogJ1NDSEVNQV9ERVNDX1BSRVNFTlQnLFxuICAgICAgICAgICAgICAgIHNjaGVtYTogc2NoZW1hTmFtZSxcbiAgICAgICAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4oZGlyUGF0aCwgZGVzY0ZpbGVOYW1lKSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgc2NoZW1hIFwiJHtzY2hlbWFOYW1lfVwiIGlzIG1pc3NpbmcgaXRzIGRlc2NyaXB0aW9uIGZpbGUgXCIke2Rlc2NGaWxlTmFtZX1cImAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNjaGVtYXMuc2V0KHNjaGVtYU5hbWUsIHtcbiAgICAgICAgICAgIG5hbWU6IHNjaGVtYU5hbWUsXG4gICAgICAgICAgICBkaXJQYXRoLFxuICAgICAgICAgICAgZGVzY3JpcHRpb24sXG4gICAgICAgICAgICB0YWJsZXM6IGxvYWRlZFRhYmxlcyxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgd29ybGQ6IHtcbiAgICAgICAgICAgIHJvb3REaXI6IGFic29sdXRlUm9vdCxcbiAgICAgICAgICAgIHNjaGVtYXMsXG4gICAgICAgICAgICB0YWJsZXMsXG4gICAgICAgIH0sXG4gICAgICAgIHZpb2xhdGlvbnMsXG4gICAgfTtcbn1cbiJdfQ==
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Core data model for the Flexible Dataset Definition (FDD) standard.
3
+ *
4
+ * These interfaces describe the *pure data* shape of a dataset: columns,
5
+ * partitions, foreign keys, table definitions, and the violations the
6
+ * validator emits. The loaded world (schemas + table instances) and the
7
+ * abstract table base class live in `./world` and `./table-type` so this
8
+ * module stays a leaf with no behavior.
9
+ */
10
+ /** Table engine. Each value unlocks engine-specific semantic checks. */
11
+ export declare enum TableType {
12
+ HIVE_PARQUET = "hive_parquet",
13
+ ICEBERG_PARQUET = "iceberg_parquet",
14
+ POSTGRES_18 = "postgres_18"
15
+ }
16
+ /** Every known `tableType` string, for membership checks. */
17
+ export declare const TABLE_TYPES: readonly string[];
18
+ /** A single data column. */
19
+ export interface Column {
20
+ /** Column name (unique within a table). */
21
+ readonly name: string;
22
+ /** Engine-specific type string (e.g. `long`, `varchar(255)`). */
23
+ readonly type: string;
24
+ /** Human description. */
25
+ readonly description: string;
26
+ }
27
+ /**
28
+ * A partition entry. The meaning of `type` is engine-specific: for Hive it is a
29
+ * normal type on a new partition column; for Iceberg it is a transform applied
30
+ * to the data column named by `name`.
31
+ */
32
+ export interface Partition {
33
+ /** Hive: new partition column name. Iceberg: source (data) column name. */
34
+ readonly name: string;
35
+ /** Hive: a normal type. Iceberg: a transform (e.g. `day`, `bucket[16]`). */
36
+ readonly type: string;
37
+ /** Human description. */
38
+ readonly description: string;
39
+ }
40
+ /** A foreign-key reference to a column in another table. */
41
+ export interface ForeignKey {
42
+ /** Referenced table in `schema.table` format. */
43
+ readonly sourceTable: string;
44
+ /** Referenced column in the source table. */
45
+ readonly sourceColumn: string;
46
+ /** Local column that holds the reference. */
47
+ readonly localColumn: string;
48
+ /** Whether the local column may be null. */
49
+ readonly allowNulls: boolean;
50
+ }
51
+ /** Normalized table definition (optional arrays defaulted to empty). */
52
+ export interface TableDefinition {
53
+ /** Spec version of the file. */
54
+ readonly specVersion: string;
55
+ /** Human description. */
56
+ readonly description: string;
57
+ /** Engine. May be an unknown string if the file failed structural checks. */
58
+ readonly tableType: string;
59
+ /** Whether this table is the top of the pipeline. */
60
+ readonly isRawData: boolean;
61
+ /** Data columns. */
62
+ readonly columns: Column[];
63
+ /** Primary-key column names. */
64
+ readonly primaryKey: string[];
65
+ /** Partition entries (engine-specific semantics). */
66
+ readonly partitions: Partition[];
67
+ /** Upstream tables in `schema.table` format. */
68
+ readonly dependsOn: string[];
69
+ /** Foreign keys. */
70
+ readonly foreignKeys: ForeignKey[];
71
+ }
72
+ /** A schema-description file's normalized content. */
73
+ export interface SchemaDescription {
74
+ /** Spec version of the file. */
75
+ readonly specVersion: string;
76
+ /** Human description. */
77
+ readonly description: string;
78
+ }
79
+ /** Severity of a violation. */
80
+ export type ViolationLevel = 'error' | 'warning';
81
+ /** A single validation finding. */
82
+ export interface Violation {
83
+ /** Severity. `error` fails validation; `warning` does not. */
84
+ readonly level: ViolationLevel;
85
+ /** Stable machine-readable rule code (e.g. `PK_COLUMNS_EXIST`). */
86
+ readonly code: string;
87
+ /** Owning schema, if applicable. */
88
+ readonly schema?: string;
89
+ /** Owning table, if applicable. */
90
+ readonly table?: string;
91
+ /** Field path within the file, if applicable. */
92
+ readonly field?: string;
93
+ /** Source file path, if applicable. */
94
+ readonly path?: string;
95
+ /** Human-readable message. */
96
+ readonly message: string;
97
+ }
98
+ /** The aggregate result of validating a root. */
99
+ export interface ValidationResult {
100
+ /** True when there are no `error`-level violations. */
101
+ readonly ok: boolean;
102
+ /** All findings, errors and warnings. */
103
+ readonly violations: Violation[];
104
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /**
3
+ * Core data model for the Flexible Dataset Definition (FDD) standard.
4
+ *
5
+ * These interfaces describe the *pure data* shape of a dataset: columns,
6
+ * partitions, foreign keys, table definitions, and the violations the
7
+ * validator emits. The loaded world (schemas + table instances) and the
8
+ * abstract table base class live in `./world` and `./table-type` so this
9
+ * module stays a leaf with no behavior.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TABLE_TYPES = exports.TableType = void 0;
13
+ /** Table engine. Each value unlocks engine-specific semantic checks. */
14
+ var TableType;
15
+ (function (TableType) {
16
+ TableType["HIVE_PARQUET"] = "hive_parquet";
17
+ TableType["ICEBERG_PARQUET"] = "iceberg_parquet";
18
+ TableType["POSTGRES_18"] = "postgres_18";
19
+ })(TableType || (exports.TableType = TableType = {}));
20
+ /** Every known `tableType` string, for membership checks. */
21
+ exports.TABLE_TYPES = [
22
+ TableType.HIVE_PARQUET,
23
+ TableType.ICEBERG_PARQUET,
24
+ TableType.POSTGRES_18,
25
+ ];
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7OztHQVFHOzs7QUFFSCx3RUFBd0U7QUFDeEUsSUFBWSxTQUlYO0FBSkQsV0FBWSxTQUFTO0lBQ2pCLDBDQUE2QixDQUFBO0lBQzdCLGdEQUFtQyxDQUFBO0lBQ25DLHdDQUEyQixDQUFBO0FBQy9CLENBQUMsRUFKVyxTQUFTLHlCQUFULFNBQVMsUUFJcEI7QUFFRCw2REFBNkQ7QUFDaEQsUUFBQSxXQUFXLEdBQXNCO0lBQzFDLFNBQVMsQ0FBQyxZQUFZO0lBQ3RCLFNBQVMsQ0FBQyxlQUFlO0lBQ3pCLFNBQVMsQ0FBQyxXQUFXO0NBQ3hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcmUgZGF0YSBtb2RlbCBmb3IgdGhlIEZsZXhpYmxlIERhdGFzZXQgRGVmaW5pdGlvbiAoRkREKSBzdGFuZGFyZC5cbiAqXG4gKiBUaGVzZSBpbnRlcmZhY2VzIGRlc2NyaWJlIHRoZSAqcHVyZSBkYXRhKiBzaGFwZSBvZiBhIGRhdGFzZXQ6IGNvbHVtbnMsXG4gKiBwYXJ0aXRpb25zLCBmb3JlaWduIGtleXMsIHRhYmxlIGRlZmluaXRpb25zLCBhbmQgdGhlIHZpb2xhdGlvbnMgdGhlXG4gKiB2YWxpZGF0b3IgZW1pdHMuIFRoZSBsb2FkZWQgd29ybGQgKHNjaGVtYXMgKyB0YWJsZSBpbnN0YW5jZXMpIGFuZCB0aGVcbiAqIGFic3RyYWN0IHRhYmxlIGJhc2UgY2xhc3MgbGl2ZSBpbiBgLi93b3JsZGAgYW5kIGAuL3RhYmxlLXR5cGVgIHNvIHRoaXNcbiAqIG1vZHVsZSBzdGF5cyBhIGxlYWYgd2l0aCBubyBiZWhhdmlvci5cbiAqL1xuXG4vKiogVGFibGUgZW5naW5lLiBFYWNoIHZhbHVlIHVubG9ja3MgZW5naW5lLXNwZWNpZmljIHNlbWFudGljIGNoZWNrcy4gKi9cbmV4cG9ydCBlbnVtIFRhYmxlVHlwZSB7XG4gICAgSElWRV9QQVJRVUVUID0gJ2hpdmVfcGFycXVldCcsXG4gICAgSUNFQkVSR19QQVJRVUVUID0gJ2ljZWJlcmdfcGFycXVldCcsXG4gICAgUE9TVEdSRVNfMTggPSAncG9zdGdyZXNfMTgnLFxufVxuXG4vKiogRXZlcnkga25vd24gYHRhYmxlVHlwZWAgc3RyaW5nLCBmb3IgbWVtYmVyc2hpcCBjaGVja3MuICovXG5leHBvcnQgY29uc3QgVEFCTEVfVFlQRVM6IHJlYWRvbmx5IHN0cmluZ1tdID0gW1xuICAgIFRhYmxlVHlwZS5ISVZFX1BBUlFVRVQsXG4gICAgVGFibGVUeXBlLklDRUJFUkdfUEFSUVVFVCxcbiAgICBUYWJsZVR5cGUuUE9TVEdSRVNfMTgsXG5dO1xuXG4vKiogQSBzaW5nbGUgZGF0YSBjb2x1bW4uICovXG5leHBvcnQgaW50ZXJmYWNlIENvbHVtbiB7XG4gICAgLyoqIENvbHVtbiBuYW1lICh1bmlxdWUgd2l0aGluIGEgdGFibGUpLiAqL1xuICAgIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcblxuICAgIC8qKiBFbmdpbmUtc3BlY2lmaWMgdHlwZSBzdHJpbmcgKGUuZy4gYGxvbmdgLCBgdmFyY2hhcigyNTUpYCkuICovXG4gICAgcmVhZG9ubHkgdHlwZTogc3RyaW5nO1xuXG4gICAgLyoqIEh1bWFuIGRlc2NyaXB0aW9uLiAqL1xuICAgIHJlYWRvbmx5IGRlc2NyaXB0aW9uOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQSBwYXJ0aXRpb24gZW50cnkuIFRoZSBtZWFuaW5nIG9mIGB0eXBlYCBpcyBlbmdpbmUtc3BlY2lmaWM6IGZvciBIaXZlIGl0IGlzIGFcbiAqIG5vcm1hbCB0eXBlIG9uIGEgbmV3IHBhcnRpdGlvbiBjb2x1bW47IGZvciBJY2ViZXJnIGl0IGlzIGEgdHJhbnNmb3JtIGFwcGxpZWRcbiAqIHRvIHRoZSBkYXRhIGNvbHVtbiBuYW1lZCBieSBgbmFtZWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGFydGl0aW9uIHtcbiAgICAvKiogSGl2ZTogbmV3IHBhcnRpdGlvbiBjb2x1bW4gbmFtZS4gSWNlYmVyZzogc291cmNlIChkYXRhKSBjb2x1bW4gbmFtZS4gKi9cbiAgICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG5cbiAgICAvKiogSGl2ZTogYSBub3JtYWwgdHlwZS4gSWNlYmVyZzogYSB0cmFuc2Zvcm0gKGUuZy4gYGRheWAsIGBidWNrZXRbMTZdYCkuICovXG4gICAgcmVhZG9ubHkgdHlwZTogc3RyaW5nO1xuXG4gICAgLyoqIEh1bWFuIGRlc2NyaXB0aW9uLiAqL1xuICAgIHJlYWRvbmx5IGRlc2NyaXB0aW9uOiBzdHJpbmc7XG59XG5cbi8qKiBBIGZvcmVpZ24ta2V5IHJlZmVyZW5jZSB0byBhIGNvbHVtbiBpbiBhbm90aGVyIHRhYmxlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBGb3JlaWduS2V5IHtcbiAgICAvKiogUmVmZXJlbmNlZCB0YWJsZSBpbiBgc2NoZW1hLnRhYmxlYCBmb3JtYXQuICovXG4gICAgcmVhZG9ubHkgc291cmNlVGFibGU6IHN0cmluZztcblxuICAgIC8qKiBSZWZlcmVuY2VkIGNvbHVtbiBpbiB0aGUgc291cmNlIHRhYmxlLiAqL1xuICAgIHJlYWRvbmx5IHNvdXJjZUNvbHVtbjogc3RyaW5nO1xuXG4gICAgLyoqIExvY2FsIGNvbHVtbiB0aGF0IGhvbGRzIHRoZSByZWZlcmVuY2UuICovXG4gICAgcmVhZG9ubHkgbG9jYWxDb2x1bW46IHN0cmluZztcblxuICAgIC8qKiBXaGV0aGVyIHRoZSBsb2NhbCBjb2x1bW4gbWF5IGJlIG51bGwuICovXG4gICAgcmVhZG9ubHkgYWxsb3dOdWxsczogYm9vbGVhbjtcbn1cblxuLyoqIE5vcm1hbGl6ZWQgdGFibGUgZGVmaW5pdGlvbiAob3B0aW9uYWwgYXJyYXlzIGRlZmF1bHRlZCB0byBlbXB0eSkuICovXG5leHBvcnQgaW50ZXJmYWNlIFRhYmxlRGVmaW5pdGlvbiB7XG4gICAgLyoqIFNwZWMgdmVyc2lvbiBvZiB0aGUgZmlsZS4gKi9cbiAgICByZWFkb25seSBzcGVjVmVyc2lvbjogc3RyaW5nO1xuXG4gICAgLyoqIEh1bWFuIGRlc2NyaXB0aW9uLiAqL1xuICAgIHJlYWRvbmx5IGRlc2NyaXB0aW9uOiBzdHJpbmc7XG5cbiAgICAvKiogRW5naW5lLiBNYXkgYmUgYW4gdW5rbm93biBzdHJpbmcgaWYgdGhlIGZpbGUgZmFpbGVkIHN0cnVjdHVyYWwgY2hlY2tzLiAqL1xuICAgIHJlYWRvbmx5IHRhYmxlVHlwZTogc3RyaW5nO1xuXG4gICAgLyoqIFdoZXRoZXIgdGhpcyB0YWJsZSBpcyB0aGUgdG9wIG9mIHRoZSBwaXBlbGluZS4gKi9cbiAgICByZWFkb25seSBpc1Jhd0RhdGE6IGJvb2xlYW47XG5cbiAgICAvKiogRGF0YSBjb2x1bW5zLiAqL1xuICAgIHJlYWRvbmx5IGNvbHVtbnM6IENvbHVtbltdO1xuXG4gICAgLyoqIFByaW1hcnkta2V5IGNvbHVtbiBuYW1lcy4gKi9cbiAgICByZWFkb25seSBwcmltYXJ5S2V5OiBzdHJpbmdbXTtcblxuICAgIC8qKiBQYXJ0aXRpb24gZW50cmllcyAoZW5naW5lLXNwZWNpZmljIHNlbWFudGljcykuICovXG4gICAgcmVhZG9ubHkgcGFydGl0aW9uczogUGFydGl0aW9uW107XG5cbiAgICAvKiogVXBzdHJlYW0gdGFibGVzIGluIGBzY2hlbWEudGFibGVgIGZvcm1hdC4gKi9cbiAgICByZWFkb25seSBkZXBlbmRzT246IHN0cmluZ1tdO1xuXG4gICAgLyoqIEZvcmVpZ24ga2V5cy4gKi9cbiAgICByZWFkb25seSBmb3JlaWduS2V5czogRm9yZWlnbktleVtdO1xufVxuXG4vKiogQSBzY2hlbWEtZGVzY3JpcHRpb24gZmlsZSdzIG5vcm1hbGl6ZWQgY29udGVudC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2NoZW1hRGVzY3JpcHRpb24ge1xuICAgIC8qKiBTcGVjIHZlcnNpb24gb2YgdGhlIGZpbGUuICovXG4gICAgcmVhZG9ubHkgc3BlY1ZlcnNpb246IHN0cmluZztcblxuICAgIC8qKiBIdW1hbiBkZXNjcmlwdGlvbi4gKi9cbiAgICByZWFkb25seSBkZXNjcmlwdGlvbjogc3RyaW5nO1xufVxuXG4vKiogU2V2ZXJpdHkgb2YgYSB2aW9sYXRpb24uICovXG5leHBvcnQgdHlwZSBWaW9sYXRpb25MZXZlbCA9ICdlcnJvcicgfCAnd2FybmluZyc7XG5cbi8qKiBBIHNpbmdsZSB2YWxpZGF0aW9uIGZpbmRpbmcuICovXG5leHBvcnQgaW50ZXJmYWNlIFZpb2xhdGlvbiB7XG4gICAgLyoqIFNldmVyaXR5LiBgZXJyb3JgIGZhaWxzIHZhbGlkYXRpb247IGB3YXJuaW5nYCBkb2VzIG5vdC4gKi9cbiAgICByZWFkb25seSBsZXZlbDogVmlvbGF0aW9uTGV2ZWw7XG5cbiAgICAvKiogU3RhYmxlIG1hY2hpbmUtcmVhZGFibGUgcnVsZSBjb2RlIChlLmcuIGBQS19DT0xVTU5TX0VYSVNUYCkuICovXG4gICAgcmVhZG9ubHkgY29kZTogc3RyaW5nO1xuXG4gICAgLyoqIE93bmluZyBzY2hlbWEsIGlmIGFwcGxpY2FibGUuICovXG4gICAgcmVhZG9ubHkgc2NoZW1hPzogc3RyaW5nO1xuXG4gICAgLyoqIE93bmluZyB0YWJsZSwgaWYgYXBwbGljYWJsZS4gKi9cbiAgICByZWFkb25seSB0YWJsZT86IHN0cmluZztcblxuICAgIC8qKiBGaWVsZCBwYXRoIHdpdGhpbiB0aGUgZmlsZSwgaWYgYXBwbGljYWJsZS4gKi9cbiAgICByZWFkb25seSBmaWVsZD86IHN0cmluZztcblxuICAgIC8qKiBTb3VyY2UgZmlsZSBwYXRoLCBpZiBhcHBsaWNhYmxlLiAqL1xuICAgIHJlYWRvbmx5IHBhdGg/OiBzdHJpbmc7XG5cbiAgICAvKiogSHVtYW4tcmVhZGFibGUgbWVzc2FnZS4gKi9cbiAgICByZWFkb25seSBtZXNzYWdlOiBzdHJpbmc7XG59XG5cbi8qKiBUaGUgYWdncmVnYXRlIHJlc3VsdCBvZiB2YWxpZGF0aW5nIGEgcm9vdC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgLyoqIFRydWUgd2hlbiB0aGVyZSBhcmUgbm8gYGVycm9yYC1sZXZlbCB2aW9sYXRpb25zLiAqL1xuICAgIHJlYWRvbmx5IG9rOiBib29sZWFuO1xuXG4gICAgLyoqIEFsbCBmaW5kaW5ncywgZXJyb3JzIGFuZCB3YXJuaW5ncy4gKi9cbiAgICByZWFkb25seSB2aW9sYXRpb25zOiBWaW9sYXRpb25bXTtcbn1cbiJdfQ==
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://raw.githubusercontent.com/ksco92/eevee/main/packages/core/src/schema/schema.schema.json",
4
+ "title": "FDD Schema Description",
5
+ "description": "Structural schema (Layer 1) for an FDD schema-description file.",
6
+ "type": "object",
7
+ "required": [
8
+ "specVersion",
9
+ "description"
10
+ ],
11
+ "additionalProperties": false,
12
+ "properties": {
13
+ "$schema": {
14
+ "type": "string"
15
+ },
16
+ "specVersion": {
17
+ "type": "string",
18
+ "enum": [
19
+ "0"
20
+ ]
21
+ },
22
+ "description": {
23
+ "type": "string",
24
+ "minLength": 1
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,128 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://raw.githubusercontent.com/ksco92/eevee/main/packages/core/src/schema/table.schema.json",
4
+ "title": "FDD Table Definition",
5
+ "description": "Structural schema (Layer 1) for an FDD table-definition file.",
6
+ "type": "object",
7
+ "required": [
8
+ "specVersion",
9
+ "description",
10
+ "tableType",
11
+ "isRawData",
12
+ "columns",
13
+ "primaryKey"
14
+ ],
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "$schema": {
18
+ "type": "string"
19
+ },
20
+ "specVersion": {
21
+ "type": "string",
22
+ "enum": [
23
+ "0"
24
+ ]
25
+ },
26
+ "description": {
27
+ "type": "string",
28
+ "minLength": 1
29
+ },
30
+ "tableType": {
31
+ "type": "string",
32
+ "enum": [
33
+ "hive_parquet",
34
+ "iceberg_parquet",
35
+ "postgres_18"
36
+ ]
37
+ },
38
+ "isRawData": {
39
+ "type": "boolean"
40
+ },
41
+ "columns": {
42
+ "type": "array",
43
+ "minItems": 1,
44
+ "items": {
45
+ "$ref": "#/definitions/column"
46
+ }
47
+ },
48
+ "primaryKey": {
49
+ "type": "array",
50
+ "minItems": 1,
51
+ "items": {
52
+ "type": "string",
53
+ "minLength": 1
54
+ }
55
+ },
56
+ "partitions": {
57
+ "type": "array",
58
+ "items": {
59
+ "$ref": "#/definitions/column"
60
+ }
61
+ },
62
+ "dependsOn": {
63
+ "type": "array",
64
+ "items": {
65
+ "type": "string",
66
+ "pattern": "^[a-z0-9_]+\\.[a-z0-9_]+$"
67
+ }
68
+ },
69
+ "foreignKeys": {
70
+ "type": "array",
71
+ "items": {
72
+ "$ref": "#/definitions/foreignKey"
73
+ }
74
+ }
75
+ },
76
+ "definitions": {
77
+ "column": {
78
+ "type": "object",
79
+ "required": [
80
+ "name",
81
+ "type",
82
+ "description"
83
+ ],
84
+ "additionalProperties": false,
85
+ "properties": {
86
+ "name": {
87
+ "type": "string",
88
+ "minLength": 1
89
+ },
90
+ "type": {
91
+ "type": "string",
92
+ "minLength": 1
93
+ },
94
+ "description": {
95
+ "type": "string",
96
+ "minLength": 1
97
+ }
98
+ }
99
+ },
100
+ "foreignKey": {
101
+ "type": "object",
102
+ "required": [
103
+ "sourceTable",
104
+ "sourceColumn",
105
+ "localColumn",
106
+ "allowNulls"
107
+ ],
108
+ "additionalProperties": false,
109
+ "properties": {
110
+ "sourceTable": {
111
+ "type": "string",
112
+ "pattern": "^[a-z0-9_]+\\.[a-z0-9_]+$"
113
+ },
114
+ "sourceColumn": {
115
+ "type": "string",
116
+ "minLength": 1
117
+ },
118
+ "localColumn": {
119
+ "type": "string",
120
+ "minLength": 1
121
+ },
122
+ "allowNulls": {
123
+ "type": "boolean"
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Layer 1 (structural) validation, backed by JSON Schema via ajv.
3
+ *
4
+ * The schema files in `./schema` are the portable artifact: any language can
5
+ * validate a file natively against them. This module is the TypeScript core's
6
+ * own use of those same schemas.
7
+ */
8
+ /** Which structural schema to validate against. */
9
+ export type StructuralKind = 'table' | 'schema';
10
+ /** A single structural error, before file context is attached. */
11
+ export interface StructuralError {
12
+ /** JSON pointer to the offending field (empty string for the root). */
13
+ readonly field: string;
14
+ /** Human-readable description. */
15
+ readonly message: string;
16
+ }
17
+ /** Outcome of validating one file structurally. */
18
+ export interface StructuralResult {
19
+ /** True when the file matches its structural schema. */
20
+ readonly valid: boolean;
21
+ /** Errors found (empty when valid). */
22
+ readonly errors: StructuralError[];
23
+ }
24
+ /**
25
+ * Validate parsed JSON against a structural schema.
26
+ *
27
+ * @param kind Which schema to use.
28
+ * @param data Parsed JSON content.
29
+ * @returns Whether it is valid plus any structural errors.
30
+ */
31
+ export declare function validateStructure(kind: StructuralKind, data: unknown): StructuralResult;