Skip to content

Commit 9a8174d

Browse files
committed
feat!: nvton class initial implementation
1 parent aeb9ed4 commit 9a8174d

File tree

15 files changed

+184
-70
lines changed

15 files changed

+184
-70
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- ✅ Local or File Object
1515
- ✅ Support JSON
1616
- ✅ Exclude Wrong Data
17+
- ✅ Supports Node v18+
1718

1819
## Syntax
1920

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"build": "pnpm format && tsdown --minify",
3939
"test": "vitest run --coverage",
4040
"test:dev": "vitest",
41-
"format": "prettier --write src/ tests/",
41+
"format": "prettier --write src/ test/",
4242
"prepublishOnly": "pnpm build",
4343
"patch": "pnpm build && generi log patch",
4444
"minor": "pnpm build && generi log minor",

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ export const OPEN_BRACKET = '[';
22
export const CLOSE_BRACKET = ']';
33
export const OPEN_BRACE = '{';
44
export const CLOSE_BRACE = '}';
5+
export const OPEN_CALL = '(';
6+
export const CLOSE_CALL = ')';
57

68
export const BACKSLASH = '\\';
79
export const DOUBLE_QUOTE = '"';
@@ -16,3 +18,4 @@ export const COLON = ':';
1618
export const SPACE = ' ';
1719

1820
export const WRONG_KEY = '__WRONG_KEY__';
21+
export const NULL_KEY = '__NULL_KEY__';

src/data.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,41 @@
1+
import { LexerKey, LexerResult } from './types';
2+
13
export class NVTON {
2-
// TODO: type
3-
private data: Map<any, any>;
4+
// TODO: unknown deep type
5+
private data: Map<LexerKey, unknown>;
46

5-
constructor(_data: any[]) {
7+
constructor(lexeme: LexerResult) {
68
this.data = new Map();
9+
10+
this.set(lexeme);
11+
}
12+
13+
private set(lexeme: LexerResult) {
14+
lexeme.forEach((item) => {
15+
if (Array.isArray(item)) this.set(item);
16+
else {
17+
this.data.set(item.key, item.data);
18+
}
19+
});
20+
}
21+
22+
public get(target: number | string) {
23+
if (typeof target === 'number') {
24+
return target;
25+
/*
26+
let index = 0;
27+
28+
this.data.forEach((value, key) => {
29+
if (index === target) return value;
30+
31+
index++;
32+
});
33+
34+
// TODO: better tracking
35+
return undefined;
36+
*/
37+
}
38+
39+
return this.data.get(target);
740
}
841
}

src/lexer.ts

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,85 @@
11
import {
22
CLOSE_BRACE,
33
CLOSE_BRACKET,
4+
COMMA,
45
OPEN_BRACE,
56
OPEN_BRACKET,
7+
OPEN_CALL,
8+
PIPE,
69
WRONG_KEY,
710
} from './constants';
811
import { parseKey } from './parser';
12+
import { v4 } from 'uuid';
13+
import { LexerResult, LexerType } from './types';
914

10-
export const getNVTONType = (str: string) => {
15+
export const getNVTONType = (str: string): LexerType => {
1116
return str.startsWith(OPEN_BRACE) && str.endsWith(CLOSE_BRACE)
12-
? 'json'
17+
? 'object'
1318
: str.startsWith(OPEN_BRACKET) && str.endsWith(CLOSE_BRACKET)
14-
? 'object'
15-
: 'default';
19+
? 'tuple'
20+
: str.startsWith(OPEN_CALL)
21+
? 'function'
22+
: 'default';
1623
};
1724

1825
const getCommonTypeCase = (str: string) => {
1926
const type = getNVTONType(str);
2027

21-
if (type === 'default') {
28+
if (type === 'object' || type === 'default') {
2229
return {
23-
data: str,
24-
type,
25-
};
26-
}
27-
28-
if (type === 'json') {
29-
return {
30-
data: parseKey(str),
30+
key: type === 'default' ? str : v4(),
31+
data: parseKey(str, type),
3132
type,
3233
};
3334
}
3435

3536
return true;
3637
};
3738

38-
const normalizeStr = (str: string) => str.substring(1, str.length - 1);
39+
const normalize = (str: string) => str.substring(1, str.length - 1).trim();
3940

40-
// TODO: type
41-
export const lex = (raw: string): any[] => {
42-
return normalizeStr(raw)
43-
.split(/,/g)
41+
const isTuple = (tuple: string) =>
42+
tuple.startsWith(OPEN_BRACKET) && tuple.endsWith(CLOSE_BRACKET);
43+
44+
export const lex = (raw: string): LexerResult => {
45+
if (!isTuple(raw)) return [];
46+
47+
return normalize(raw)
48+
.split(`${COMMA} `)
4449
.map((str) => {
4550
const def = getCommonTypeCase(str);
4651

4752
if (def !== true) return def;
4853

49-
const tuples = normalizeStr(str)
50-
.split(/,/g)
54+
if (!isTuple(str)) return [];
55+
56+
const tuples = normalize(str)
57+
.split(`${COMMA} `)
5158
.map((tuple) => {
52-
const data = normalizeStr(tuple).split('|');
59+
const data = normalize(tuple)
60+
.split(PIPE)
61+
.map((tg) => tg.trim())
62+
.filter(Boolean);
5363

54-
if (data.length !== 2) return WRONG_KEY;
64+
if (data.length < 1 || data.length > 2) return WRONG_KEY;
5565

56-
const [key, value] = data;
66+
const structure =
67+
data.length === 1
68+
? { key: data[0], value: data[0] }
69+
: { key: data[0], value: data[1] };
5770

58-
const _def = getCommonTypeCase(value);
71+
const _def = getCommonTypeCase(structure.value);
5972

60-
if (_def !== true)
73+
if (_def !== true) {
6174
return {
62-
data: {
63-
key,
64-
value: _def.data,
65-
},
75+
key: structure.key,
76+
data: _def.data,
6677
type: _def.type,
6778
};
79+
}
80+
6881
// TODO: support recursive tuple format
69-
else return WRONG_KEY;
82+
return WRONG_KEY;
7083
})
7184
.filter((tuple) => tuple !== WRONG_KEY);
7285

src/parser.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import destr from 'destr';
1+
import { destr } from 'destr';
2+
import { LexerType } from './types';
23

3-
export function parseKey<T = unknown>(raw: string) {
4-
// TODO: strict: true with error support
5-
return destr<T>(raw, { strict: false });
4+
const stringObjectToObject = (raw: string) => {
5+
return raw.replace(/(\w+:)|(\w+ :)/g, (str) => {
6+
return '"' + str.substring(0, str.length - 1) + '":';
7+
});
8+
};
9+
10+
export function parseKey<T = unknown>(raw: string, type: LexerType = 'default') {
11+
return destr<T>(type === 'object' ? stringObjectToObject(raw) : raw, { strict: false });
612
}

src/pipeline.ts

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,18 @@
1-
import { existsSync, readFileSync } from 'fs-extra';
2-
import { getPath } from './utils';
3-
import { Maybe } from './types';
1+
import { getFile } from './utils';
42
import { lex } from './lexer';
53
import { NVTON } from './data';
64

7-
const getFile = (target: string): Maybe<string> => {
8-
const path = getPath(target);
5+
const get = (raw: string): NVTON => {
6+
const resolved = (raw.endsWith('.nvton') ? getFile(raw) : raw)?.trim();
97

10-
const existsPath = existsSync(path);
8+
if (!resolved && resolved !== '') {
9+
throw new Error(`${raw} file not found!`);
10+
}
1111

12-
if (!existsPath) return undefined;
12+
const data = lex(resolved);
1313

14-
return readFileSync(path).toString() || undefined;
14+
return new NVTON(data);
1515
};
1616

17-
const get = (raw: Maybe<string>) => {
18-
if (!raw) return undefined;
19-
20-
const data = lex(raw);
21-
22-
const nvton = new NVTON(data);
23-
};
24-
25-
export const nvton = (raw: string) => {
26-
get(raw);
27-
};
28-
29-
export const getNvton = (target: string) => {
30-
const raw = getFile(target);
31-
32-
if (!raw) return false;
33-
34-
get(raw);
35-
};
36-
37-
export const readNvton = () => {};
17+
export const nvton = (raw: string) => get(raw);
18+
export const write = () => {};

src/read.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1+
import { NVTON } from './data';
2+
13
export type Maybe<T = void> = T | undefined | null;
4+
5+
export type Nvton = typeof NVTON;
6+
7+
export type LexerType = 'object' | 'tuple' | 'function' | 'default';
8+
export type LexerKey = string | number;
9+
export type LexerCommon = { key: string; data: unknown; type: LexerType };
10+
export type LexerResult = (LexerCommon | LexerCommon[])[];

0 commit comments

Comments
 (0)