@retrobrainz/dat 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 - 2026-01-07
4
+
5
+ - Added `parse()` function
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # @retrobrainz/dat
2
+
3
+ ![Version](https://img.shields.io/npm/v/@retrobrainz/dat)
4
+ ![Downloads](https://img.shields.io/npm/dw/@retrobrainz/dat)
5
+
6
+ Your description...
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm i -S @retrobrainz/dat
12
+ ```
13
+
14
+ ## Example
15
+
16
+ ```js
17
+ import { parse } from '@retrobrainz/dat';
18
+ ```
@@ -0,0 +1,5 @@
1
+ export interface DatEntry {
2
+ $class: string;
3
+ $entries?: DatEntry[];
4
+ [key: string]: any;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export { default as parse } from './parse.js';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { default as parse } from './parse.js';
@@ -0,0 +1,2 @@
1
+ import { DatEntry } from './DatObject.js';
2
+ export default function parse(datContent: string): DatEntry[];
package/dist/parse.js ADDED
@@ -0,0 +1,51 @@
1
+ import readSegment from './readSegment.js';
2
+ export default function parse(datContent) {
3
+ let currentIndex = 0;
4
+ const result = [];
5
+ while (currentIndex < datContent.length) {
6
+ const { value, nextIndex } = parseObject(datContent, currentIndex);
7
+ if (value) {
8
+ result.push(value);
9
+ }
10
+ currentIndex = nextIndex;
11
+ }
12
+ return result;
13
+ }
14
+ function parseObject(text, startIndex) {
15
+ const value = { $class: '' };
16
+ let currentIndex = startIndex;
17
+ const typeResult = readSegment(text, startIndex);
18
+ if (!typeResult.key) {
19
+ return { value: null, nextIndex: typeResult.nextIndex };
20
+ }
21
+ const leftBracketResult = readSegment(text, typeResult.nextIndex);
22
+ if (leftBracketResult.key !== '(') {
23
+ return { value: null, nextIndex: leftBracketResult.nextIndex };
24
+ }
25
+ value.$class = typeResult.key;
26
+ currentIndex = leftBracketResult.nextIndex;
27
+ while (currentIndex < text.length) {
28
+ const keyResult = readSegment(text, currentIndex);
29
+ if (keyResult.key === ')') {
30
+ currentIndex = keyResult.nextIndex;
31
+ break;
32
+ }
33
+ const valueResult = readSegment(text, keyResult.nextIndex);
34
+ if (valueResult.key === '(') {
35
+ const entryResult = parseObject(text, currentIndex);
36
+ if (entryResult.value) {
37
+ if (!value.$entries) {
38
+ value.$entries = [];
39
+ }
40
+ value.$entries.push(entryResult.value);
41
+ }
42
+ currentIndex = entryResult.nextIndex;
43
+ continue;
44
+ }
45
+ if (keyResult.key) {
46
+ value[keyResult.key] = valueResult.key;
47
+ currentIndex = valueResult.nextIndex;
48
+ }
49
+ }
50
+ return { value, nextIndex: currentIndex };
51
+ }
@@ -0,0 +1,5 @@
1
+ export default function readKeyValue(text: string, startIndex: number): {
2
+ key: string;
3
+ value: string;
4
+ nextIndex: number;
5
+ };
@@ -0,0 +1,6 @@
1
+ import readSegment from './readSegment.js';
2
+ export default function readKeyValue(text, startIndex) {
3
+ const keyResult = readSegment(text, startIndex);
4
+ const valueResult = readSegment(text, keyResult.nextIndex);
5
+ return { key: keyResult.key, value: valueResult.key, nextIndex: valueResult.nextIndex };
6
+ }
@@ -0,0 +1,4 @@
1
+ export default function readSegment(text: string, startIndex: number): {
2
+ key: string;
3
+ nextIndex: number;
4
+ };
@@ -0,0 +1,34 @@
1
+ export default function readSegment(text, startIndex) {
2
+ let currentIndex = startIndex;
3
+ let key = '';
4
+ let quoted = false;
5
+ while (currentIndex < text.length) {
6
+ const char = text[currentIndex];
7
+ currentIndex++;
8
+ if (char === '"') {
9
+ if (quoted) {
10
+ break;
11
+ }
12
+ else {
13
+ quoted = true;
14
+ }
15
+ }
16
+ else if (char === ' ') {
17
+ if (quoted) {
18
+ key += char;
19
+ }
20
+ else if (key.length > 0) {
21
+ break;
22
+ }
23
+ }
24
+ else if (char === '\n') {
25
+ if (key.length > 0) {
26
+ break;
27
+ }
28
+ }
29
+ else {
30
+ key += char;
31
+ }
32
+ }
33
+ return { key: key.trim(), nextIndex: currentIndex };
34
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@retrobrainz/dat",
3
+ "version": "1.0.0",
4
+ "description": "read and write .dat files",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.js",
9
+ "types": "./dist/index.d.ts"
10
+ }
11
+ },
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "files": [
15
+ "dist",
16
+ "CHANGELOG.md",
17
+ "LICENSE",
18
+ "README.md"
19
+ ],
20
+ "commitlint": {
21
+ "extends": [
22
+ "@commitlint/config-conventional"
23
+ ]
24
+ },
25
+ "lint-staged": {
26
+ "*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}": "eslint --fix",
27
+ "*.{cjs,css,cts,html,js,json,jsx,less,md,mjs,mts,scss,ts,tsx,vue,yaml,yml}": "prettier --write"
28
+ },
29
+ "prettier": "prettier-config-ali",
30
+ "devDependencies": {
31
+ "@commitlint/cli": "^19.8.1",
32
+ "@commitlint/config-conventional": "^19.8.1",
33
+ "@mdx-js/react": "^3.1.1",
34
+ "@types/node": "^22.19.3",
35
+ "@types/react": "^18.3.27",
36
+ "@types/react-dom": "^18.3.7",
37
+ "@vitest/coverage-v8": "^3.2.4",
38
+ "@vitest/ui": "^3.2.4",
39
+ "eslint": "^9.39.2",
40
+ "eslint-config-ali": "^16.6.0",
41
+ "eslint-config-prettier": "^10.1.8",
42
+ "eslint-plugin-prettier": "^5.5.4",
43
+ "husky": "^9.1.7",
44
+ "lint-staged": "^16.2.7",
45
+ "prettier": "^3.7.4",
46
+ "prettier-config-ali": "^1.5.0",
47
+ "react": "^18.3.1",
48
+ "react-dom": "^18.3.1",
49
+ "rive": "^3.3.2",
50
+ "typescript": "^5.9.3",
51
+ "vitest": "^3.2.4"
52
+ },
53
+ "rive": {
54
+ "template": "node",
55
+ "doc": {
56
+ "basename": "/dat/"
57
+ }
58
+ },
59
+ "scripts": {
60
+ "build": "rive build",
61
+ "build:watch": "rive build --watch",
62
+ "ci:eslint": "eslint -f json src -o ./.ci/eslint.json",
63
+ "lint": "eslint .",
64
+ "lint:fix": "prettier --write . && eslint --fix .",
65
+ "start": "rive start",
66
+ "test": "vitest run",
67
+ "test:coverage": "vitest run --coverage",
68
+ "test:ui": "vitest --ui",
69
+ "test:watch": "vitest"
70
+ }
71
+ }