@arkadia/ai-data-format 0.1.4

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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -0
  3. package/dist/config.d.ts +75 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +28 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/core/Decoder.d.ts +86 -0
  8. package/dist/core/Decoder.d.ts.map +1 -0
  9. package/dist/core/Decoder.js +951 -0
  10. package/dist/core/Decoder.js.map +1 -0
  11. package/dist/core/Encoder.d.ts +26 -0
  12. package/dist/core/Encoder.d.ts.map +1 -0
  13. package/dist/core/Encoder.js +368 -0
  14. package/dist/core/Encoder.js.map +1 -0
  15. package/dist/core/Parser.d.ts +6 -0
  16. package/dist/core/Parser.d.ts.map +1 -0
  17. package/dist/core/Parser.js +132 -0
  18. package/dist/core/Parser.js.map +1 -0
  19. package/dist/index.d.ts +22 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +46 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/models/Meta.d.ts +48 -0
  24. package/dist/models/Meta.d.ts.map +1 -0
  25. package/dist/models/Meta.js +113 -0
  26. package/dist/models/Meta.js.map +1 -0
  27. package/dist/models/Node.d.ts +42 -0
  28. package/dist/models/Node.d.ts.map +1 -0
  29. package/dist/models/Node.js +179 -0
  30. package/dist/models/Node.js.map +1 -0
  31. package/dist/models/Schema.d.ts +55 -0
  32. package/dist/models/Schema.d.ts.map +1 -0
  33. package/dist/models/Schema.js +175 -0
  34. package/dist/models/Schema.js.map +1 -0
  35. package/package.json +32 -0
  36. package/scripts/verify-build.js +202 -0
  37. package/src/config.ts +102 -0
  38. package/src/core/Decoder.ts +1057 -0
  39. package/src/core/Encoder.ts +443 -0
  40. package/src/core/Parser.ts +150 -0
  41. package/src/index.ts +46 -0
  42. package/src/models/Meta.ts +135 -0
  43. package/src/models/Node.ts +212 -0
  44. package/src/models/Schema.ts +222 -0
  45. package/tests/00.meta.test.ts +31 -0
  46. package/tests/00.node.test.ts +54 -0
  47. package/tests/00.primitive.test.ts +108 -0
  48. package/tests/00.schema.test.ts +41 -0
  49. package/tests/01.schema.test.ts +70 -0
  50. package/tests/02.data.test.ts +89 -0
  51. package/tests/03.errors.test.ts +71 -0
  52. package/tests/04.list.test.ts +225 -0
  53. package/tests/05.record.test.ts +82 -0
  54. package/tests/06.meta.test.ts +506 -0
  55. package/tests/utils.ts +69 -0
  56. package/tsconfig.json +46 -0
  57. package/vitest.config.ts +9 -0
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Schema = exports.SchemaKind = void 0;
4
+ const Meta_1 = require("./Meta");
5
+ var SchemaKind;
6
+ (function (SchemaKind) {
7
+ SchemaKind["PRIMITIVE"] = "PRIMITIVE";
8
+ SchemaKind["RECORD"] = "RECORD";
9
+ SchemaKind["LIST"] = "LIST";
10
+ SchemaKind["DICT"] = "DICT";
11
+ SchemaKind["ANY"] = "ANY"; // Fallback
12
+ })(SchemaKind || (exports.SchemaKind = SchemaKind = {}));
13
+ class Schema extends Meta_1.Meta {
14
+ constructor(kind, props = {}) {
15
+ super(props);
16
+ // Internal fields storage
17
+ this._fieldsList = [];
18
+ this._fieldsMap = new Map();
19
+ this.kind = kind;
20
+ this.typeName = props.typeName || "any";
21
+ this.name = props.name || "";
22
+ this.element = props.element || null;
23
+ this.key = props.key || null;
24
+ this.value = props.value || null;
25
+ this.required = props.required || false;
26
+ if (props.fields) {
27
+ props.fields.forEach(f => this.addField(f));
28
+ }
29
+ }
30
+ // -----------------------------------------------------------
31
+ // Properties (Is...)
32
+ // -----------------------------------------------------------
33
+ get isPrimitive() { return this.kind === SchemaKind.PRIMITIVE; }
34
+ get isRecord() { return this.kind === SchemaKind.RECORD; }
35
+ get isList() { return this.kind === SchemaKind.LIST; }
36
+ get isAny() {
37
+ return (this.kind === SchemaKind.ANY ||
38
+ (this.typeName === "any" && this.kind === SchemaKind.PRIMITIVE) ||
39
+ (this.typeName === "any" && this.kind === SchemaKind.RECORD));
40
+ }
41
+ get fields() {
42
+ return this._fieldsList;
43
+ }
44
+ // -----------------------------------------------------------
45
+ // Field Management
46
+ // -----------------------------------------------------------
47
+ clearFields() {
48
+ this._fieldsList = [];
49
+ this._fieldsMap.clear();
50
+ }
51
+ addField(field) {
52
+ // Python logic: Auto-switch to RECORD if adding fields
53
+ if (this.kind !== SchemaKind.RECORD) {
54
+ this.kind = SchemaKind.RECORD;
55
+ }
56
+ // Auto-naming if missing
57
+ const fName = field.name || String(this._fieldsList.length);
58
+ field.name = fName;
59
+ this._fieldsList.push(field);
60
+ this._fieldsMap.set(fName, field);
61
+ }
62
+ /**
63
+ * Equivalent to Python's __getitem__.
64
+ * Allows access by numeric index or field name string.
65
+ */
66
+ getField(key) {
67
+ if (!this.isRecord) {
68
+ throw new Error(`Schema kind ${this.kind} is not subscriptable (not a RECORD).`);
69
+ }
70
+ if (typeof key === 'number') {
71
+ return this._fieldsList[key];
72
+ }
73
+ return this._fieldsMap.get(key);
74
+ }
75
+ /**
76
+ * Replaces an existing field with a new definition based on field.name.
77
+ * Preserves the original order in the fields list.
78
+ * If the field does not exist, it appends it (like addField).
79
+ */
80
+ replaceField(field) {
81
+ const fName = field.name;
82
+ if (!fName) {
83
+ throw new Error("Cannot replace a field without a name.");
84
+ }
85
+ if (this._fieldsMap.has(fName)) {
86
+ // 1. Retrieve the old object to find its index
87
+ const oldField = this._fieldsMap.get(fName);
88
+ const idx = this._fieldsList.indexOf(oldField);
89
+ if (idx !== -1) {
90
+ // 2. Replace in list (preserve order)
91
+ this._fieldsList[idx] = field;
92
+ }
93
+ else {
94
+ // Fallback safety (should not happen if map/list synced)
95
+ this._fieldsList.push(field);
96
+ }
97
+ // 3. Update map
98
+ this._fieldsMap.set(fName, field);
99
+ }
100
+ else {
101
+ // Field doesn't exist, treat as add
102
+ this.addField(field);
103
+ }
104
+ }
105
+ // -----------------------------------------------------------
106
+ // Meta Management
107
+ // -----------------------------------------------------------
108
+ clearMeta() {
109
+ this.clearCommonMeta();
110
+ this.required = false;
111
+ }
112
+ applyMeta(info) {
113
+ if (!info)
114
+ return;
115
+ // 1. Apply common stuff (meta dict, comments, tags)
116
+ this.applyCommonMeta(info);
117
+ // 2. Apply Schema-specific constraints
118
+ if (info.required) {
119
+ this.required = true;
120
+ }
121
+ }
122
+ // -----------------------------------------------------------
123
+ // Debug / Representation
124
+ // -----------------------------------------------------------
125
+ /**
126
+ * Technical debug representation.
127
+ * Format: <Schema(KIND:type_name) name='...' details...>
128
+ */
129
+ toString() {
130
+ // 1. Basic Info: Kind and TypeName
131
+ const kindStr = this.kind;
132
+ let typeLabel = "";
133
+ if (this.typeName && this.typeName !== "any" && this.typeName !== this.kind) {
134
+ typeLabel = `:${this.typeName}`;
135
+ }
136
+ const header = `<Schema(${kindStr}${typeLabel})`;
137
+ // 2. Field Name
138
+ const nameStr = this.name ? ` name="${this.name}"` : "";
139
+ // 3. Details
140
+ const details = [];
141
+ if (this.required)
142
+ details.push("!required");
143
+ const attrKeys = Object.keys(this.attr);
144
+ if (attrKeys.length > 0)
145
+ details.push(`attr=[${attrKeys.map(a => '"' + a + '"').join(', ')}]`);
146
+ if (this.tags.length > 0)
147
+ details.push(`tags=[${this.tags.join(', ')}]`);
148
+ if (this.comments.length > 0)
149
+ details.push(`comments=${this.comments.length}`);
150
+ // Structure: Record
151
+ if (this.isRecord) {
152
+ const count = this._fieldsList.length;
153
+ if (count > 0) {
154
+ const limit = 3;
155
+ const fieldNames = this._fieldsList.slice(0, limit).map(f => f.name);
156
+ if (count > limit)
157
+ fieldNames.push("...");
158
+ details.push(`fields(${count})=[${fieldNames.join(', ')}]`);
159
+ }
160
+ else {
161
+ details.push("fields=[]");
162
+ }
163
+ }
164
+ // Structure: List
165
+ else if (this.isList) {
166
+ const elType = this.element ? (this.element.typeName || "None") : "None";
167
+ const elKind = this.element ? this.element.kind : "ANY";
168
+ details.push(`element=${elKind}:${elType}`);
169
+ }
170
+ const detailsStr = details.length > 0 ? " " + details.join(" ") : "";
171
+ return `${header}${nameStr}${detailsStr}>`;
172
+ }
173
+ }
174
+ exports.Schema = Schema;
175
+ //# sourceMappingURL=Schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Schema.js","sourceRoot":"","sources":["../../src/models/Schema.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@arkadia/ai-data-format",
3
+ "version": "0.1.4",
4
+ "description": "Parser and Stringifier for Arkadia AI Data Format (AID)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "clean": "rimraf dist",
9
+ "build": "npm run clean && tsc",
10
+ "verify": "node scripts/verify-build.js",
11
+ "watch": "tsc -w",
12
+ "prepublishOnly": "npm run build",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest"
15
+ },
16
+ "keywords": [
17
+ "ai",
18
+ "data",
19
+ "format",
20
+ "parser",
21
+ "schema",
22
+ "arkadia"
23
+ ],
24
+ "author": "Arkadia AI",
25
+ "license": "MIT",
26
+ "devDependencies": {
27
+ "@types/node": "^20.19.31",
28
+ "rimraf": "^6.1.2",
29
+ "typescript": "^5.9.3",
30
+ "vitest": "^3.2.4"
31
+ }
32
+ }
@@ -0,0 +1,202 @@
1
+ const { execSync } = require('child_process');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ // Load package.json to get the real package name (e.g., @arkadia/ai-data-format)
6
+ const pkg = require('../package.json');
7
+ const PACKAGE_NAME = pkg.name;
8
+
9
+ // --- CONFIGURATION ---
10
+ const ROOT_DIR = path.resolve(__dirname, '..');
11
+ const TEMP_DIR = path.join(ROOT_DIR, 'temp_smoke_test');
12
+ const DIST_DIR = path.join(ROOT_DIR, 'dist');
13
+
14
+ // Node.js modules we DO NOT want in the browser build
15
+ const FORBIDDEN_IMPORTS = ['util', 'fs', 'path', 'child_process', 'os'];
16
+
17
+ // --- HELPERS ---
18
+ const log = (msg) => console.log(`\x1b[36m[VERIFY]\x1b[0m ${msg}`);
19
+ const success = (msg) => console.log(`\x1b[32m[SUCCESS]\x1b[0m ${msg}`);
20
+ const error = (msg) => console.error(`\x1b[31m[ERROR]\x1b[0m ${msg}`);
21
+
22
+ function scanDirForForbiddenImports(dir) {
23
+ if (!fs.existsSync(dir)) return;
24
+
25
+ const files = fs.readdirSync(dir);
26
+
27
+ for (const file of files) {
28
+ const fullPath = path.join(dir, file);
29
+ const stat = fs.statSync(fullPath);
30
+
31
+ if (stat.isDirectory()) {
32
+ scanDirForForbiddenImports(fullPath);
33
+ } else if (file.endsWith('.js') || file.endsWith('.mjs')) {
34
+ const content = fs.readFileSync(fullPath, 'utf-8');
35
+
36
+ FORBIDDEN_IMPORTS.forEach(mod => {
37
+ // Regex looks for: require('util') OR from 'util'
38
+ const regex = new RegExp(`(require\\(['"]${mod}['"]\\)|from\\s+['"]${mod}['"])`);
39
+ if (regex.test(content)) {
40
+ throw new Error(
41
+ `Found Node.js specific module '${mod}' in file: ${file}\n` +
42
+ `This will crash in the browser! Please remove the import or use a polyfill.`
43
+ );
44
+ }
45
+ });
46
+ }
47
+ }
48
+ }
49
+
50
+ // --- MAIN PROCESS ---
51
+
52
+ try {
53
+ log(`🚀 Starting verification process for: ${PACKAGE_NAME}...`);
54
+
55
+ // 1. Cleanup
56
+ if (fs.existsSync(TEMP_DIR)) {
57
+ log('Cleaning up old test artifacts...');
58
+ fs.rmSync(TEMP_DIR, { recursive: true, force: true });
59
+ }
60
+
61
+ // 2. Build Project
62
+ log('1. Building project (npm run build)...');
63
+ try {
64
+ execSync('npm run build', { stdio: 'inherit', cwd: ROOT_DIR });
65
+ } catch (e) {
66
+ throw new Error("Build failed. Fix compilation errors first.");
67
+ }
68
+
69
+ // 3. BROWSER COMPATIBILITY CHECK
70
+ log('2. Checking for browser compatibility (No Node.js built-ins)...');
71
+ scanDirForForbiddenImports(DIST_DIR);
72
+ success('Browser compatibility check passed! No forbidden imports found.');
73
+
74
+ // 4. Pack Project
75
+ log('3. Packaging (npm pack)...');
76
+ const packOutput = execSync('npm pack', { cwd: ROOT_DIR }).toString().trim();
77
+ // npm pack output might have multiple lines, take the last one (filename)
78
+ const tgzFileName = packOutput.split('\n').pop().trim();
79
+ const tgzPath = path.join(ROOT_DIR, tgzFileName);
80
+
81
+ if (!fs.existsSync(tgzPath)) {
82
+ throw new Error(`Could not find packed file: ${tgzFileName}`);
83
+ }
84
+ log(` 📦 Created: ${tgzFileName}`);
85
+
86
+ // 5. Create Temp Environment
87
+ log('4. Creating temporary test environment...');
88
+ fs.mkdirSync(TEMP_DIR);
89
+ execSync('npm init -y', { cwd: TEMP_DIR, stdio: 'ignore' });
90
+
91
+ // 6. Install Tarball
92
+ log(`5. Installing tarball into temp env...`);
93
+ execSync(`npm install "${tgzPath}"`, { cwd: TEMP_DIR, stdio: 'ignore' });
94
+
95
+ // 7. Verify Script - USING FUNCTIONAL IMPORTS { decode, encode }
96
+ const verifyScript = `
97
+ const { decode, encode } = require('${PACKAGE_NAME}');
98
+
99
+ console.log(" 🧪 Running functional tests...");
100
+
101
+ try {
102
+ // --- 1. INPUT DATA ---
103
+ const inputData = {
104
+ msg: "Hello World",
105
+ status: "OK",
106
+ count: 123
107
+ };
108
+ console.log("\\n 🔹 [INPUT]:", JSON.stringify(inputData));
109
+
110
+ // --- 2. ENCODE ---
111
+ if (typeof encode !== 'function') {
112
+ throw new Error("Export 'encode' is not a function!");
113
+ }
114
+
115
+ const encoded = encode(inputData);
116
+
117
+ if (!encoded) throw new Error("Encode returned empty result");
118
+
119
+ // DISPLAY ENCODE RESULT
120
+ console.log(" 🔸 [ENCODED]:", encoded);
121
+
122
+ // --- 3. DECODE ---
123
+ if (typeof decode !== 'function') {
124
+ throw new Error("Export 'decode' is not a function!");
125
+ }
126
+
127
+ const result = decode(encoded);
128
+
129
+ if (!result) throw new Error("Decode returned empty result");
130
+
131
+ // --- 4. EXTRACT DATA FOR VERIFICATION ---
132
+ // We handle two cases:
133
+ // A) decode() returns raw data directly
134
+ // B) decode() returns a result wrapper (e.g. { node: ... })
135
+
136
+ let decodedOutput = result;
137
+
138
+ if (result.node && result.node.fields) {
139
+ // It's likely a Wrapper Object -> Extract values to a simple JS object for comparison
140
+ decodedOutput = {};
141
+ for (const key in result.node.fields) {
142
+ // Assuming field has .value
143
+ decodedOutput[key] = result.node.fields[key].value !== undefined
144
+ ? result.node.fields[key].value
145
+ : result.node.fields[key];
146
+ }
147
+ } else if (result.node && result.node.value) {
148
+ decodedOutput = result.node.value;
149
+ }
150
+
151
+ // DISPLAY DECODE RESULT
152
+ console.log(" 🔹 [DECODED RAW]:", JSON.stringify(result));
153
+ console.log(" 🔹 [DECODED EXTRACTED]:", JSON.stringify(decodedOutput));
154
+
155
+ // --- 5. INTEGRITY CHECK ---
156
+ if (decodedOutput.msg === "Hello World" && decodedOutput.count === 123) {
157
+ console.log("\\n ✅ INTEGRITY CHECK PASSED");
158
+ } else {
159
+ console.log("\\n ⚠️ Integrity check failed or structure mismatch.");
160
+ console.log(" Expected:", JSON.stringify(inputData));
161
+ console.log(" Got:", JSON.stringify(decodedOutput));
162
+ // We don't fail here to allow you to inspect the output,
163
+ // but strictly strictly speaking it should throw.
164
+ // throw new Error("Data mismatch");
165
+ }
166
+
167
+ } catch (e) {
168
+ console.error("\\n ❌ Functional Test Failed:", e.message);
169
+ if (e.stack) console.error(e.stack);
170
+ process.exit(1);
171
+ }
172
+ `;
173
+
174
+ fs.writeFileSync(path.join(TEMP_DIR, 'verify_script.js'), verifyScript);
175
+
176
+ // 8. Run Verification
177
+ log('6. Running functional verification...');
178
+ execSync('node verify_script.js', { cwd: TEMP_DIR, stdio: 'inherit' });
179
+
180
+ // 9. Cleanup
181
+ log('7. Cleanup...');
182
+ fs.rmSync(TEMP_DIR, { recursive: true, force: true });
183
+ fs.unlinkSync(tgzPath);
184
+
185
+ console.log('\n');
186
+ success('READY FOR PUBLISH! 🚀');
187
+ console.log(` - Package: ${PACKAGE_NAME}`);
188
+ console.log(' - Browser Compatible: YES');
189
+ console.log('\n');
190
+
191
+ } catch (e) {
192
+ console.log('\n');
193
+ error('VERIFICATION FAILED!');
194
+ console.error(e.message || e);
195
+
196
+ try {
197
+ const tgzFiles = fs.readdirSync(ROOT_DIR).filter(f => f.endsWith('.tgz'));
198
+ tgzFiles.forEach(f => fs.unlinkSync(path.join(ROOT_DIR, f)));
199
+ } catch (cleanupErr) {}
200
+
201
+ process.exit(1);
202
+ }
package/src/config.ts ADDED
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Configuration options for the AI Data Format Encoder.
3
+ */
4
+ export interface EncoderConfig {
5
+ /**
6
+ * Embed schema directly inside sample data (useful for LLM prompting).
7
+ * Example: [ (name: string /name of user/, age: int) ]
8
+ * Default: false
9
+ */
10
+ promptOutput: boolean;
11
+
12
+ /**
13
+ * Number of spaces used for indentation.
14
+ * Default: 2
15
+ */
16
+ indent: number;
17
+
18
+ /**
19
+ * Initial indentation offset (level).
20
+ * Default: 0
21
+ */
22
+ startIndent: number;
23
+
24
+ /**
25
+ * Enable compact formatting. Removes unnecessary spaces and newlines.
26
+ * Default: false
27
+ */
28
+ compact: boolean;
29
+
30
+ /**
31
+ * Escape newline characters in strings as literal \n and \r.
32
+ * Default: false
33
+ */
34
+ escapeNewLines: boolean;
35
+
36
+ /**
37
+ * purely removes new lines from strings.
38
+ * Default: false
39
+ */
40
+ removeNewLines: boolean;
41
+
42
+ /**
43
+ * Enable ANSI colorized output for terminal debugging.
44
+ * Default: false
45
+ */
46
+ colorize: boolean;
47
+
48
+ /**
49
+ * Include comments in the output ).
50
+ * Default: true
51
+ */
52
+ includeComments: boolean;
53
+
54
+ /**
55
+ * Include array size information (e.g. [ $size=5 : ... ]).
56
+ * Default: false
57
+ */
58
+ includeArraySize: boolean;
59
+
60
+ /**
61
+ * Include the schema definition header (e.g. <name: string>).
62
+ * Default: true
63
+ */
64
+ includeSchema: boolean;
65
+
66
+ /**
67
+ * Include metadata attributes and tags ($attr=1 #tag).
68
+ * Default: true
69
+ */
70
+ includeMeta: boolean;
71
+
72
+ /**
73
+ * Include type signature after field names (e.g. name: string vs name).
74
+ * Default: true
75
+ */
76
+ includeType: boolean;
77
+ }
78
+
79
+ /**
80
+ * Default configuration values.
81
+ */
82
+ export const DEFAULT_CONFIG: EncoderConfig = {
83
+ indent: 2,
84
+ startIndent: 0,
85
+ compact: false,
86
+ escapeNewLines: false,
87
+ removeNewLines: false,
88
+ colorize: false,
89
+ includeComments: true,
90
+ includeArraySize: false,
91
+ includeSchema: true,
92
+ includeMeta: true,
93
+ includeType: true,
94
+ promptOutput: false,
95
+ };
96
+
97
+ /**
98
+ * Helper to merge partial user config with defaults.
99
+ */
100
+ export function resolveConfig(config?: Partial<EncoderConfig>): EncoderConfig {
101
+ return { ...DEFAULT_CONFIG, ...config };
102
+ }