@arkadia/data 0.1.7 → 0.1.9

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 (54) hide show
  1. package/.prettierrc +8 -0
  2. package/README.md +159 -112
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/core/Decoder.d.ts.map +1 -1
  6. package/dist/core/Decoder.js +123 -97
  7. package/dist/core/Decoder.js.map +1 -1
  8. package/dist/core/Encoder.d.ts +1 -2
  9. package/dist/core/Encoder.d.ts.map +1 -1
  10. package/dist/core/Encoder.js +74 -76
  11. package/dist/core/Encoder.js.map +1 -1
  12. package/dist/core/Parser.d.ts +1 -1
  13. package/dist/core/Parser.d.ts.map +1 -1
  14. package/dist/core/Parser.js +11 -11
  15. package/dist/core/Parser.js.map +1 -1
  16. package/dist/index.d.ts +4 -4
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +7 -8
  19. package/dist/index.js.map +1 -1
  20. package/dist/models/Meta.d.ts +3 -2
  21. package/dist/models/Meta.d.ts.map +1 -1
  22. package/dist/models/Meta.js +3 -3
  23. package/dist/models/Meta.js.map +1 -1
  24. package/dist/models/Node.d.ts +4 -3
  25. package/dist/models/Node.d.ts.map +1 -1
  26. package/dist/models/Node.js +29 -23
  27. package/dist/models/Node.js.map +1 -1
  28. package/dist/models/Schema.d.ts.map +1 -1
  29. package/dist/models/Schema.js +27 -21
  30. package/dist/models/Schema.js.map +1 -1
  31. package/eslint.config.mjs +42 -0
  32. package/package.json +11 -1
  33. package/scripts/verify-build.js +95 -92
  34. package/src/config.ts +75 -75
  35. package/src/core/Decoder.ts +984 -922
  36. package/src/core/Encoder.ts +364 -371
  37. package/src/core/Parser.ts +112 -112
  38. package/src/index.ts +18 -20
  39. package/src/models/Meta.ts +107 -107
  40. package/src/models/Node.ts +190 -185
  41. package/src/models/Schema.ts +198 -193
  42. package/tests/00.meta.test.ts +19 -25
  43. package/tests/00.node.test.ts +40 -48
  44. package/tests/00.primitive.test.ts +121 -95
  45. package/tests/00.schema.test.ts +28 -35
  46. package/tests/01.schema.test.ts +42 -52
  47. package/tests/02.data.test.ts +69 -75
  48. package/tests/03.errors.test.ts +53 -55
  49. package/tests/04.list.test.ts +192 -193
  50. package/tests/05.record.test.ts +54 -56
  51. package/tests/06.meta.test.ts +393 -389
  52. package/tests/utils.ts +47 -44
  53. package/tsconfig.json +27 -29
  54. package/vitest.config.ts +1 -1
@@ -1,222 +1,227 @@
1
1
  import { Meta, MetaInfo, MetaProps } from './Meta';
2
2
 
3
3
  export enum SchemaKind {
4
- PRIMITIVE = "PRIMITIVE", // int, string, bool, null
5
- RECORD = "RECORD", // User, Point, or anonymous <...>
6
- LIST = "LIST", // Array/Sequence
7
- DICT = "DICT", // Future-proofing: Key-Value pairs
8
- ANY = "ANY" // Fallback
4
+ PRIMITIVE = 'PRIMITIVE', // int, string, bool, null
5
+ RECORD = 'RECORD', // User, Point, or anonymous <...>
6
+ LIST = 'LIST', // Array/Sequence
7
+ DICT = 'DICT', // Future-proofing: Key-Value pairs
8
+ ANY = 'ANY', // Fallback
9
9
  }
10
10
 
11
11
  export interface SchemaProps extends MetaProps {
12
- typeName?: string;
13
- name?: string;
14
- fields?: Schema[];
15
- element?: Schema;
16
- key?: Schema;
17
- value?: Schema;
18
- required?: boolean;
12
+ typeName?: string;
13
+ name?: string;
14
+ fields?: Schema[];
15
+ element?: Schema;
16
+ key?: Schema;
17
+ value?: Schema;
18
+ required?: boolean;
19
19
  }
20
20
 
21
21
  export class Schema extends Meta {
22
- kind: SchemaKind;
23
- typeName: string;
24
- name: string;
25
-
26
- // Structure references
27
- element: Schema | null;
28
- key: Schema | null;
29
- value: Schema | null;
30
-
31
- // Flags
32
- required: boolean;
33
-
34
- // Internal fields storage
35
- private _fieldsList: Schema[] = [];
36
- private _fieldsMap: Map<string, Schema> = new Map();
37
-
38
- constructor(kind: SchemaKind, props: SchemaProps = {}) {
39
- super(props);
40
-
41
- this.kind = kind;
42
- this.typeName = props.typeName || "any";
43
- this.name = props.name || "";
44
-
45
- this.element = props.element || null;
46
- this.key = props.key || null;
47
- this.value = props.value || null;
48
- this.required = props.required || false;
49
-
50
- if (props.fields) {
51
- props.fields.forEach(f => this.addField(f));
52
- }
53
- }
22
+ kind: SchemaKind;
23
+ typeName: string;
24
+ name: string;
54
25
 
55
- // -----------------------------------------------------------
56
- // Properties (Is...)
57
- // -----------------------------------------------------------
58
-
59
- get isPrimitive(): boolean { return this.kind === SchemaKind.PRIMITIVE; }
60
- get isRecord(): boolean { return this.kind === SchemaKind.RECORD; }
61
- get isList(): boolean { return this.kind === SchemaKind.LIST; }
62
-
63
- get isAny(): boolean {
64
- return (
65
- this.kind === SchemaKind.ANY ||
66
- (this.typeName === "any" && this.kind === SchemaKind.PRIMITIVE) ||
67
- (this.typeName === "any" && this.kind === SchemaKind.RECORD)
68
- );
69
- }
26
+ // Structure references
27
+ element: Schema | null;
28
+ key: Schema | null;
29
+ value: Schema | null;
70
30
 
71
- get fields(): Schema[] {
72
- return this._fieldsList;
73
- }
31
+ // Flags
32
+ required: boolean;
74
33
 
75
- // -----------------------------------------------------------
76
- // Field Management
77
- // -----------------------------------------------------------
34
+ // Internal fields storage
35
+ private _fieldsList: Schema[] = [];
36
+ private _fieldsMap: Map<string, Schema> = new Map();
78
37
 
79
- clearFields(): void {
80
- this._fieldsList = [];
81
- this._fieldsMap.clear();
82
- }
38
+ constructor(kind: SchemaKind, props: SchemaProps = {}) {
39
+ super(props);
83
40
 
84
- addField(field: Schema): void {
85
- // Python logic: Auto-switch to RECORD if adding fields
86
- if (this.kind !== SchemaKind.RECORD) {
87
- this.kind = SchemaKind.RECORD;
88
- }
41
+ this.kind = kind;
42
+ this.typeName = props.typeName || 'any';
43
+ this.name = props.name || '';
89
44
 
90
- // Auto-naming if missing
91
- const fName = field.name || String(this._fieldsList.length);
92
- field.name = fName;
45
+ this.element = props.element || null;
46
+ this.key = props.key || null;
47
+ this.value = props.value || null;
48
+ this.required = props.required || false;
93
49
 
94
- this._fieldsList.push(field);
95
- this._fieldsMap.set(fName, field);
50
+ if (props.fields) {
51
+ props.fields.forEach((f) => this.addField(f));
96
52
  }
97
-
98
- /**
99
- * Equivalent to Python's __getitem__.
100
- * Allows access by numeric index or field name string.
101
- */
102
- getField(key: number | string): Schema | undefined {
103
- if (!this.isRecord) {
104
- throw new Error(`Schema kind ${this.kind} is not subscriptable (not a RECORD).`);
105
- }
106
- if (typeof key === 'number') {
107
- return this._fieldsList[key];
108
- }
109
- return this._fieldsMap.get(key);
53
+ }
54
+
55
+ // -----------------------------------------------------------
56
+ // Properties (Is...)
57
+ // -----------------------------------------------------------
58
+
59
+ get isPrimitive(): boolean {
60
+ return this.kind === SchemaKind.PRIMITIVE;
61
+ }
62
+ get isRecord(): boolean {
63
+ return this.kind === SchemaKind.RECORD;
64
+ }
65
+ get isList(): boolean {
66
+ return this.kind === SchemaKind.LIST;
67
+ }
68
+
69
+ get isAny(): boolean {
70
+ return (
71
+ this.kind === SchemaKind.ANY ||
72
+ (this.typeName === 'any' && this.kind === SchemaKind.PRIMITIVE) ||
73
+ (this.typeName === 'any' && this.kind === SchemaKind.RECORD)
74
+ );
75
+ }
76
+
77
+ get fields(): Schema[] {
78
+ return this._fieldsList;
79
+ }
80
+
81
+ // -----------------------------------------------------------
82
+ // Field Management
83
+ // -----------------------------------------------------------
84
+
85
+ clearFields(): void {
86
+ this._fieldsList = [];
87
+ this._fieldsMap.clear();
88
+ }
89
+
90
+ addField(field: Schema): void {
91
+ // Python logic: Auto-switch to RECORD if adding fields
92
+ if (this.kind !== SchemaKind.RECORD) {
93
+ this.kind = SchemaKind.RECORD;
110
94
  }
111
95
 
112
- /**
113
- * Replaces an existing field with a new definition based on field.name.
114
- * Preserves the original order in the fields list.
115
- * If the field does not exist, it appends it (like addField).
116
- */
117
- replaceField(field: Schema): void {
118
- const fName = field.name;
119
- if (!fName) {
120
- throw new Error("Cannot replace a field without a name.");
121
- }
122
-
123
- if (this._fieldsMap.has(fName)) {
124
- // 1. Retrieve the old object to find its index
125
- const oldField = this._fieldsMap.get(fName)!;
126
- const idx = this._fieldsList.indexOf(oldField);
127
-
128
- if (idx !== -1) {
129
- // 2. Replace in list (preserve order)
130
- this._fieldsList[idx] = field;
131
- } else {
132
- // Fallback safety (should not happen if map/list synced)
133
- this._fieldsList.push(field);
134
- }
135
-
136
- // 3. Update map
137
- this._fieldsMap.set(fName, field);
138
- } else {
139
- // Field doesn't exist, treat as add
140
- this.addField(field);
141
- }
96
+ // Auto-naming if missing
97
+ const fName = field.name || String(this._fieldsList.length);
98
+ field.name = fName;
99
+
100
+ this._fieldsList.push(field);
101
+ this._fieldsMap.set(fName, field);
102
+ }
103
+
104
+ /**
105
+ * Equivalent to Python's __getitem__.
106
+ * Allows access by numeric index or field name string.
107
+ */
108
+ getField(key: number | string): Schema | undefined {
109
+ if (!this.isRecord) {
110
+ throw new Error(`Schema kind ${this.kind} is not subscriptable (not a RECORD).`);
111
+ }
112
+ if (typeof key === 'number') {
113
+ return this._fieldsList[key];
114
+ }
115
+ return this._fieldsMap.get(key);
116
+ }
117
+
118
+ /**
119
+ * Replaces an existing field with a new definition based on field.name.
120
+ * Preserves the original order in the fields list.
121
+ * If the field does not exist, it appends it (like addField).
122
+ */
123
+ replaceField(field: Schema): void {
124
+ const fName = field.name;
125
+ if (!fName) {
126
+ throw new Error('Cannot replace a field without a name.');
142
127
  }
143
128
 
144
- // -----------------------------------------------------------
145
- // Meta Management
146
- // -----------------------------------------------------------
129
+ if (this._fieldsMap.has(fName)) {
130
+ // 1. Retrieve the old object to find its index
131
+ const oldField = this._fieldsMap.get(fName)!;
132
+ const idx = this._fieldsList.indexOf(oldField);
147
133
 
148
- clearMeta(): void {
149
- this.clearCommonMeta();
150
- this.required = false;
134
+ if (idx !== -1) {
135
+ // 2. Replace in list (preserve order)
136
+ this._fieldsList[idx] = field;
137
+ } else {
138
+ // Fallback safety (should not happen if map/list synced)
139
+ this._fieldsList.push(field);
140
+ }
141
+
142
+ // 3. Update map
143
+ this._fieldsMap.set(fName, field);
144
+ } else {
145
+ // Field doesn't exist, treat as add
146
+ this.addField(field);
151
147
  }
148
+ }
149
+
150
+ // -----------------------------------------------------------
151
+ // Meta Management
152
+ // -----------------------------------------------------------
152
153
 
153
- applyMeta(info: MetaInfo | Schema | undefined): void {
154
- if(!info) return;
155
- // 1. Apply common stuff (meta dict, comments, tags)
156
- this.applyCommonMeta(info);
154
+ clearMeta(): void {
155
+ this.clearCommonMeta();
156
+ this.required = false;
157
+ }
157
158
 
158
- // 2. Apply Schema-specific constraints
159
- if (info.required) {
160
- this.required = true;
161
- }
159
+ applyMeta(info: MetaInfo | Schema | undefined): void {
160
+ if (!info) return;
161
+ // 1. Apply common stuff (meta dict, comments, tags)
162
+ this.applyCommonMeta(info);
163
+
164
+ // 2. Apply Schema-specific constraints
165
+ if (info.required) {
166
+ this.required = true;
167
+ }
168
+ }
169
+
170
+ // -----------------------------------------------------------
171
+ // Debug / Representation
172
+ // -----------------------------------------------------------
173
+
174
+ /**
175
+ * Technical debug representation.
176
+ * Format: <Schema(KIND:type_name) name='...' details...>
177
+ */
178
+ toString(): string {
179
+ // 1. Basic Info: Kind and TypeName
180
+ const kindStr = this.kind;
181
+
182
+ let typeLabel = '';
183
+ if (this.typeName && this.typeName !== 'any' && this.typeName !== this.kind) {
184
+ typeLabel = `:${this.typeName}`;
162
185
  }
163
186
 
164
- // -----------------------------------------------------------
165
- // Debug / Representation
166
- // -----------------------------------------------------------
167
-
168
- /**
169
- * Technical debug representation.
170
- * Format: <Schema(KIND:type_name) name='...' details...>
171
- */
172
- toString(): string {
173
- // 1. Basic Info: Kind and TypeName
174
- const kindStr = this.kind;
175
-
176
- let typeLabel = "";
177
- if (this.typeName && this.typeName !== "any" && this.typeName !== this.kind) {
178
- typeLabel = `:${this.typeName}`;
179
- }
180
-
181
- const header = `<Schema(${kindStr}${typeLabel})`;
182
-
183
- // 2. Field Name
184
- const nameStr = this.name ? ` name="${this.name}"` : "";
185
-
186
- // 3. Details
187
- const details: string[] = [];
188
-
189
- if (this.required) details.push("!required");
190
-
191
- const attrKeys = Object.keys(this.attr);
192
- if (attrKeys.length > 0) details.push(`attr=[${attrKeys.map(a => '"' + a + '"').join(', ')}]`);
193
-
194
- if (this.tags.length > 0) details.push(`tags=[${this.tags.join(', ')}]`);
195
- if (this.comments.length > 0) details.push(`comments=${this.comments.length}`);
196
-
197
- // Structure: Record
198
- if (this.isRecord) {
199
- const count = this._fieldsList.length;
200
- if (count > 0) {
201
- const limit = 3;
202
- const fieldNames = this._fieldsList.slice(0, limit).map(f => f.name);
203
- if (count > limit) fieldNames.push("...");
204
- details.push(`fields(${count})=[${fieldNames.join(', ')}]`);
205
- } else {
206
- details.push("fields=[]");
207
- }
208
- }
209
- // Structure: List
210
- else if (this.isList) {
211
- const elType = this.element ? (this.element.typeName || "None") : "None";
212
- const elKind = this.element ? this.element.kind : "ANY";
213
- details.push(`element=${elKind}:${elType}`);
214
- }
215
-
216
- const detailsStr = details.length > 0 ? " " + details.join(" ") : "";
217
-
218
- return `${header}${nameStr}${detailsStr}>`;
187
+ const header = `<Schema(${kindStr}${typeLabel})`;
188
+
189
+ // 2. Field Name
190
+ const nameStr = this.name ? ` name="${this.name}"` : '';
191
+
192
+ // 3. Details
193
+ const details: string[] = [];
194
+
195
+ if (this.required) details.push('!required');
196
+
197
+ const attrKeys = Object.keys(this.attr);
198
+ if (attrKeys.length > 0)
199
+ details.push(`attr=[${attrKeys.map((a) => '"' + a + '"').join(', ')}]`);
200
+
201
+ if (this.tags.length > 0) details.push(`tags=[${this.tags.join(', ')}]`);
202
+ if (this.comments.length > 0) details.push(`comments=${this.comments.length}`);
203
+
204
+ // Structure: Record
205
+ if (this.isRecord) {
206
+ const count = this._fieldsList.length;
207
+ if (count > 0) {
208
+ const limit = 3;
209
+ const fieldNames = this._fieldsList.slice(0, limit).map((f) => f.name);
210
+ if (count > limit) fieldNames.push('...');
211
+ details.push(`fields(${count})=[${fieldNames.join(', ')}]`);
212
+ } else {
213
+ details.push('fields=[]');
214
+ }
215
+ }
216
+ // Structure: List
217
+ else if (this.isList) {
218
+ const elType = this.element ? this.element.typeName || 'None' : 'None';
219
+ const elKind = this.element ? this.element.kind : 'ANY';
220
+ details.push(`element=${elKind}:${elType}`);
219
221
  }
220
222
 
221
-
222
- }
223
+ const detailsStr = details.length > 0 ? ' ' + details.join(' ') : '';
224
+
225
+ return `${header}${nameStr}${detailsStr}>`;
226
+ }
227
+ }
@@ -2,30 +2,24 @@ import { describe, it, expect } from 'vitest';
2
2
  import { MetaInfo } from '../src/index';
3
3
 
4
4
  describe('AK Data Meta', () => {
5
- it('should Meta be properly formatted', () => {
6
- const meta = new MetaInfo({
7
-
8
- comments: ["This is a comment"],
9
- attr: { foo: "bar" },
10
- tags: ["tag1", "tag2"],
11
- required: true
12
- });
13
- const expected = '<MetaInfo !required #tag1 #tag2 $foo="bar" /* This is a comme.. */>';
14
- // const expectedJSON
15
- const expected_val = {
16
- "comments": [
17
- "This is a comment"
18
- ],
19
- "attr": {
20
- "foo": "bar"
21
- },
22
- "tags": [
23
- "tag1",
24
- "tag2"
25
- ],
26
- "required": true
27
- }
28
- expect(meta).toMatchObject(expected_val);
29
- expect(meta.toString()).toBe(expected);
5
+ it('should Meta be properly formatted', () => {
6
+ const meta = new MetaInfo({
7
+ comments: ['This is a comment'],
8
+ attr: { foo: 'bar' },
9
+ tags: ['tag1', 'tag2'],
10
+ required: true,
30
11
  });
12
+ const expected = '<MetaInfo !required #tag1 #tag2 $foo="bar" /* This is a comme.. */>';
13
+ // const expectedJSON
14
+ const expected_val = {
15
+ comments: ['This is a comment'],
16
+ attr: {
17
+ foo: 'bar',
18
+ },
19
+ tags: ['tag1', 'tag2'],
20
+ required: true,
21
+ };
22
+ expect(meta).toMatchObject(expected_val);
23
+ expect(meta.toString()).toBe(expected);
24
+ });
31
25
  });
@@ -2,53 +2,45 @@ import { describe, it, expect } from 'vitest';
2
2
  import { Schema, SchemaKind, Node } from '../src/index';
3
3
 
4
4
  describe('AI Node test', () => {
5
- it('should encode raw object', () => {
6
- const schema = new Schema(
7
- SchemaKind.DICT,
8
- {
9
- name: "TestSchema",
10
- comments: ["This is a comment"],
11
- attr: { foo: "bar" },
12
- tags: ["tag1", "tag2"],
13
- required: true
14
-
15
- });
16
- const node = new Node(schema, {
17
- value: 3,
18
- })
19
-
20
- const expected = '<Node(DICT:any) val=3>';
21
- const expected_val = {
22
- "comments": [],
23
- "attr": {},
24
- "tags": [],
25
- "schema": {
26
- "comments": [
27
- "This is a comment"
28
- ],
29
- "attr": {
30
- "foo": "bar"
31
- },
32
- "tags": [
33
- "tag1",
34
- "tag2"
35
- ],
36
- "_fieldsList": [],
37
- "_fieldsMap": {},
38
- "kind": "DICT",
39
- "typeName": "any",
40
- "name": "TestSchema",
41
- "element": null,
42
- "key": null,
43
- "value": null,
44
- "required": true
45
- },
46
- "name": "",
47
- "value": 3,
48
- "fields": {},
49
- "elements": []
50
- }
51
- expect(node).toMatchObject(expected_val);
52
- expect(node.toString()).toBe(expected);
5
+ it('should encode raw object', () => {
6
+ const schema = new Schema(SchemaKind.DICT, {
7
+ name: 'TestSchema',
8
+ comments: ['This is a comment'],
9
+ attr: { foo: 'bar' },
10
+ tags: ['tag1', 'tag2'],
11
+ required: true,
53
12
  });
13
+ const node = new Node(schema, {
14
+ value: 3,
15
+ });
16
+
17
+ const expected = '<Node(DICT:any) val=3>';
18
+ const expected_val = {
19
+ comments: [],
20
+ attr: {},
21
+ tags: [],
22
+ schema: {
23
+ comments: ['This is a comment'],
24
+ attr: {
25
+ foo: 'bar',
26
+ },
27
+ tags: ['tag1', 'tag2'],
28
+ _fieldsList: [],
29
+ _fieldsMap: {},
30
+ kind: 'DICT',
31
+ typeName: 'any',
32
+ name: 'TestSchema',
33
+ element: null,
34
+ key: null,
35
+ value: null,
36
+ required: true,
37
+ },
38
+ name: '',
39
+ value: 3,
40
+ fields: {},
41
+ elements: [],
42
+ };
43
+ expect(node).toMatchObject(expected_val);
44
+ expect(node.toString()).toBe(expected);
45
+ });
54
46
  });