adofai 2.9.7 → 2.9.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.
- package/package.json +1 -1
- package/src/parser/ArrayBufferParser.ts +128 -0
- package/src/parser/BufferParser.ts +14 -2
- package/src/parser/Parser.ts +26 -0
- package/src/parser/StringParser.ts +99 -122
- package/src/parser.ts +5 -2
- package/src/structure/Level.ts +2 -2
- package/src/structure/interfaces.ts +2 -2
- package/test/index.html +2 -2
package/package.json
CHANGED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const BOM = new Uint8Array([0xef, 0xbb, 0xbf]);
|
|
2
|
+
const COMMA = new Uint8Array([44]); // ASCII for ','
|
|
3
|
+
|
|
4
|
+
export function stripBOM(buffer: ArrayBuffer): ArrayBuffer {
|
|
5
|
+
const view = new Uint8Array(buffer);
|
|
6
|
+
if (view.length >= 3 && view[0] === BOM[0] && view[1] === BOM[1] && view[2] === BOM[2]) {
|
|
7
|
+
return buffer.slice(3);
|
|
8
|
+
}
|
|
9
|
+
return buffer;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function normalizeJsonArrayBuffer(buffer: ArrayBuffer): ArrayBuffer {
|
|
13
|
+
const view = new Uint8Array(buffer);
|
|
14
|
+
let builder: Uint8Array[] = [];
|
|
15
|
+
let last: "other" | "string" | "escape" | "comma" = "other";
|
|
16
|
+
let from = 0;
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < view.length; i++) {
|
|
19
|
+
const charCode = view[i];
|
|
20
|
+
if (last == "escape") {
|
|
21
|
+
last = "string";
|
|
22
|
+
} else {
|
|
23
|
+
switch (charCode) {
|
|
24
|
+
case 34: // "
|
|
25
|
+
switch (last) {
|
|
26
|
+
case "string":
|
|
27
|
+
last = "other";
|
|
28
|
+
break;
|
|
29
|
+
case "comma":
|
|
30
|
+
builder.push(COMMA);
|
|
31
|
+
default:
|
|
32
|
+
last = "string";
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
case 92: // \
|
|
37
|
+
if (last === "string") last = "escape";
|
|
38
|
+
break;
|
|
39
|
+
case 44: // ,
|
|
40
|
+
builder.push(view.subarray(from, i));
|
|
41
|
+
from = i + 1;
|
|
42
|
+
if (last === "other") last = "comma";
|
|
43
|
+
break;
|
|
44
|
+
case 93: // ]
|
|
45
|
+
case 125: // }
|
|
46
|
+
if (last === "comma") last = "other";
|
|
47
|
+
break;
|
|
48
|
+
case 9: // \t
|
|
49
|
+
case 10: // \n
|
|
50
|
+
case 11: // \v
|
|
51
|
+
case 12: // \f
|
|
52
|
+
case 13: // \r
|
|
53
|
+
case 32: // space
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
if (last === "comma") {
|
|
57
|
+
builder.push(COMMA);
|
|
58
|
+
last = "other";
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
builder.push(view.subarray(from));
|
|
65
|
+
|
|
66
|
+
let totalLength = 0;
|
|
67
|
+
for (const arr of builder) {
|
|
68
|
+
totalLength += arr.length;
|
|
69
|
+
}
|
|
70
|
+
const result = new Uint8Array(totalLength);
|
|
71
|
+
let offset = 0;
|
|
72
|
+
for (const arr of builder) {
|
|
73
|
+
result.set(arr, offset);
|
|
74
|
+
offset += arr.length;
|
|
75
|
+
}
|
|
76
|
+
return result.buffer;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function normalizeJsonString(text: string): string {
|
|
80
|
+
const encoder = new TextEncoder();
|
|
81
|
+
const encoded = encoder.encode(text);
|
|
82
|
+
const normalizedBuffer = normalizeJsonArrayBuffer(encoded.buffer);
|
|
83
|
+
const decoder = new TextDecoder('utf-8');
|
|
84
|
+
return decoder.decode(normalizedBuffer);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function decodeStringFromUTF8BOM(buffer: ArrayBuffer): string {
|
|
88
|
+
const strippedBuffer = stripBOM(buffer);
|
|
89
|
+
const decoder = new TextDecoder('utf-8');
|
|
90
|
+
return decoder.decode(strippedBuffer);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function encodeStringAsUTF8BOM(text: string): ArrayBuffer {
|
|
94
|
+
const encoder = new TextEncoder();
|
|
95
|
+
const encoded = encoder.encode(text);
|
|
96
|
+
const bomAndText = new Uint8Array(BOM.length + encoded.length);
|
|
97
|
+
bomAndText.set(BOM, 0);
|
|
98
|
+
bomAndText.set(encoded, BOM.length);
|
|
99
|
+
return bomAndText.buffer;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function decodeJsonFromString(text: string): any {
|
|
103
|
+
return JSON.parse(normalizeJsonString(text));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function decodeJsonFromArrayBuffer(buffer: ArrayBuffer): any {
|
|
107
|
+
return JSON.parse(
|
|
108
|
+
decodeStringFromUTF8BOM(normalizeJsonArrayBuffer(stripBOM(buffer))),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function encodeJsonAsString(obj: any): string {
|
|
113
|
+
return JSON.stringify(obj);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function encodeJsonAsArrayBufferUTF8BOM(obj: any): ArrayBuffer {
|
|
117
|
+
return encodeStringAsUTF8BOM(encodeJsonAsString(obj));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function parse(text: string): any {
|
|
121
|
+
return decodeJsonFromString(text);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function stringify(obj: any): string {
|
|
125
|
+
return encodeJsonAsString(obj);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default { parse, stringify };
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
|
|
2
|
+
let BOM: Buffer;
|
|
3
|
+
let COMMA: Buffer;
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
BOM = Buffer.of(0xef, 0xbb, 0xbf);
|
|
7
|
+
COMMA = Buffer.from(",");
|
|
8
|
+
} catch (e) {
|
|
9
|
+
console.warn('Buffer is not available in current environment, try to use ArrayBufferParser');
|
|
10
|
+
|
|
11
|
+
// Provide dummy implementations to avoid errors during module loading
|
|
12
|
+
BOM = { equals: () => false, subarray: () => null } as any;
|
|
13
|
+
COMMA = { equals: () => false, subarray: () => null } as any;
|
|
14
|
+
}
|
|
3
15
|
|
|
4
16
|
export function stripBOM(buffer: Buffer): Buffer {
|
|
5
17
|
if (buffer.length >= 3 && BOM.equals(buffer.subarray(0, 3))) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import StringParser from './StringParser';
|
|
2
|
+
|
|
3
|
+
class Parser {
|
|
4
|
+
static parseError(f: string) {
|
|
5
|
+
return f;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} t - Input Content
|
|
10
|
+
* @param {object} provider - Third-party JSON Parser
|
|
11
|
+
* @returns {object} ADOFAI File Object
|
|
12
|
+
*/
|
|
13
|
+
static parseAsObject(t: string, provider?: any) {
|
|
14
|
+
return (typeof provider == 'undefined' ? StringParser : provider).parse(Parser.parseAsText(t));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} t - Input Content
|
|
19
|
+
* @returns {string} ADOFAI File Content
|
|
20
|
+
*/
|
|
21
|
+
static parseAsText(t: string) {
|
|
22
|
+
return this.parseError(t);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default Parser
|
|
@@ -1,167 +1,144 @@
|
|
|
1
|
-
class
|
|
1
|
+
class StringParser {
|
|
2
2
|
static parse(text: string | null, reviver?: (key: string, value: any) => any): any {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
if (text == null) return null
|
|
4
|
+
|
|
5
|
+
const result = new ParserX(text).parseValue()
|
|
6
|
+
|
|
7
|
+
// Apply reviver function if provided (similar to JSON.parse)
|
|
8
|
+
if (typeof reviver === "function") {
|
|
9
|
+
return this._applyReviver("", result, reviver)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return result
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
static parsePartially(text: string | null, upToSection: string | null, reviver?: (key: string, value: any) => any): any {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
if (text == null) return null
|
|
17
|
+
|
|
18
|
+
const result = new ParserX(text, upToSection).parseValue()
|
|
19
|
+
|
|
20
|
+
if (typeof reviver === "function") {
|
|
21
|
+
return this._applyReviver("", result, reviver)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return result
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
static stringify(value: any, replacer?: (key: string, value: any) => any, space?: string | number): string {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const serializer = new Serializer(replacer, space)
|
|
29
|
+
return serializer.serialize(value)
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// Helper method for reviver function
|
|
33
33
|
static _applyReviver(key: string, value: any, reviver: (key: string, value: any) => any): any {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
if (value && typeof value === "object") {
|
|
35
|
+
if (Array.isArray(value)) {
|
|
36
|
+
const arrValue = value as any[];
|
|
37
|
+
for (let i = 0; i < arrValue.length; i++) {
|
|
38
|
+
arrValue[i] = this._applyReviver(i.toString(), arrValue[i], reviver)
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
const objValue = value as Record<string, any>;
|
|
42
|
+
for (const prop in objValue) {
|
|
43
|
+
if (Object.prototype.hasOwnProperty.call(objValue, prop)) {
|
|
44
|
+
objValue[prop] = this._applyReviver(prop, objValue[prop], reviver)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
45
47
|
}
|
|
46
|
-
}
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
-
return reviver(key, value)
|
|
49
|
+
return reviver(key, value)
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class ParserX {
|
|
54
54
|
static WHITE_SPACE = " \t\n\r\uFEFF"
|
|
55
55
|
static WORD_BREAK = ' \t\n\r{}[],:\"'
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
static TOKEN = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
NONE: 0,
|
|
59
|
+
CURLY_OPEN: 1,
|
|
60
|
+
CURLY_CLOSE: 2,
|
|
61
|
+
SQUARED_OPEN: 3,
|
|
62
|
+
SQUARED_CLOSE: 4,
|
|
63
|
+
COLON: 5,
|
|
64
|
+
COMMA: 6,
|
|
65
|
+
STRING: 7,
|
|
66
|
+
NUMBER: 8,
|
|
67
|
+
TRUE: 9,
|
|
68
|
+
FALSE: 10,
|
|
69
|
+
NULL: 11,
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
private json: string;
|
|
73
73
|
private position: number;
|
|
74
74
|
private endSection: string | null;
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
constructor(jsonString: string, endSection: string | null = null) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
this.json = jsonString
|
|
78
|
+
this.position = 0
|
|
79
|
+
this.endSection = endSection
|
|
80
|
+
|
|
81
|
+
// Skip BOM if present
|
|
82
|
+
if (this.peek() === 0xfeff) {
|
|
83
|
+
this.read()
|
|
84
|
+
}
|
|
85
85
|
}
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
parseValue(): any {
|
|
88
|
-
|
|
88
|
+
return this.parseByToken(this.nextToken)
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
parseObject(): Record<string, any> | null {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
92
|
+
const obj: Record<string, any> = {}
|
|
93
|
+
this.read() // consume '{'
|
|
94
|
+
|
|
95
|
+
while (true) {
|
|
96
|
+
let nextToken
|
|
97
|
+
do {
|
|
98
|
+
nextToken = this.nextToken
|
|
99
|
+
if (nextToken === ParserX.TOKEN.NONE) {
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
if (nextToken === ParserX.TOKEN.CURLY_CLOSE) {
|
|
103
|
+
return obj
|
|
104
|
+
}
|
|
105
|
+
} while (nextToken === ParserX.TOKEN.COMMA)
|
|
106
|
+
|
|
107
|
+
// Rest of the parser implementation would go here
|
|
108
|
+
// This is a placeholder for the remaining parser code
|
|
109
|
+
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// Placeholder for other methods that would be in the Parser class
|
|
113
113
|
private get nextToken(): number {
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
// Implementation would go here
|
|
115
|
+
return 0;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
private read(): number {
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
// Implementation would go here
|
|
120
|
+
return 0;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
private peek(): number {
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
// Implementation would go here
|
|
125
|
+
return 0;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
private parseByToken(token: number): any {
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
// Implementation would go here
|
|
130
|
+
return null;
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
}
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
class Serializer {
|
|
135
135
|
constructor(replacer?: (key: string, value: any) => any, space?: string | number) {
|
|
136
|
-
|
|
136
|
+
// Implementation would go here
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
serialize(value: any): string {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
class StringParser {
|
|
146
|
-
static parseError(f: string) {
|
|
147
|
-
return f;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* @param {string} t - Input Content
|
|
152
|
-
* @param {object} provider - Third-party JSON Parser
|
|
153
|
-
* @returns {object} ADOFAI File Object
|
|
154
|
-
*/
|
|
155
|
-
static parseAsObject(t: string, provider?: any) {
|
|
156
|
-
return (typeof provider == 'undefined' ? ADOFAIX : provider).parse(StringParser.parseAsText(t));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* @param {string} t - Input Content
|
|
161
|
-
* @returns {string} ADOFAI File Content
|
|
162
|
-
*/
|
|
163
|
-
static parseAsText(t: string) {
|
|
164
|
-
return this.parseError(t);
|
|
140
|
+
// Implementation would go here
|
|
141
|
+
return "";
|
|
165
142
|
}
|
|
166
143
|
}
|
|
167
144
|
|
package/src/parser.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Parser from "./parser/Parser";
|
|
2
2
|
import BufferParser from './parser/BufferParser';
|
|
3
|
+
import ArrayBufferParser from "./parser/ArrayBufferParser";
|
|
4
|
+
import StringParser from "./parser/StringParser";
|
|
3
5
|
|
|
4
|
-
export {StringParser, BufferParser}
|
|
6
|
+
export {StringParser, BufferParser, ArrayBufferParser}
|
|
7
|
+
export default Parser;
|
package/src/structure/Level.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AdofaiEvent, LevelOptions, EventCallback, GuidCallback, Tile, ParseProvider } from './interfaces';
|
|
2
2
|
import pathData from '../pathdata';
|
|
3
3
|
import exportAsADOFAI from '../format'
|
|
4
|
-
import
|
|
4
|
+
import Parser from '../parser';
|
|
5
5
|
import effectProcessor from '../effectProcessor';
|
|
6
6
|
import * as presets from '../presets';
|
|
7
7
|
|
|
@@ -40,7 +40,7 @@ export class Level {
|
|
|
40
40
|
switch (typeof opt) {
|
|
41
41
|
case 'string':
|
|
42
42
|
try {
|
|
43
|
-
options =
|
|
43
|
+
options = Parser.parseAsObject(opt, this._provider);
|
|
44
44
|
} catch (e) {
|
|
45
45
|
reject(e);
|
|
46
46
|
return;
|
package/test/index.html
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<input type="file" id="inputFile">
|
|
2
2
|
<button id="export">Export as ADOFAI</button>
|
|
3
|
-
<script
|
|
4
|
-
|
|
3
|
+
<script type="module">
|
|
4
|
+
import * as ADOFAI from '../dist/index.js'
|
|
5
5
|
let fl, reader;
|
|
6
6
|
document.querySelector('#inputFile').addEventListener('change', f => {
|
|
7
7
|
fl = f.target.files[0];
|