adofai 2.9.11 → 2.9.12
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/README.md +20 -0
- package/package.json +1 -1
- package/src/parser/ArrayBufferParser.ts +101 -128
- package/src/parser/BufferParser.ts +16 -39
- package/src/parser/Parser.ts +4 -24
- package/src/parser/StringParser.ts +8 -15
- package/src/parser/index.ts +28 -0
- package/src/parser.ts +1 -1
- package/src/structure/Level.ts +2 -2
- package/test/Buffer.js +2030 -0
- package/test/index.html +7 -3
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# ADOFAI
|
|
2
|
+
|
|
3
|
+
A Javascript library for ADOFAI levels.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
Preview / Edit the `.adofai` file.
|
|
7
|
+
|
|
8
|
+
Re_ADOJAS(A Level Player of ADOFAI) uses `adofai` to parse ADOFAI Level file.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install adofai
|
|
14
|
+
# or
|
|
15
|
+
yarn add adofai
|
|
16
|
+
# or
|
|
17
|
+
pnpm install adofai
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
if you want to display highlight of adofai file, you can use `Rhythm Game Syntax Highlighter` vscode extension.
|
package/package.json
CHANGED
|
@@ -1,128 +1,101 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
case
|
|
53
|
-
|
|
54
|
-
break;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
+
import Parser from "./Parser";
|
|
2
|
+
import StringParser from "./StringParser";
|
|
3
|
+
|
|
4
|
+
const BOM = new Uint8Array([0xef, 0xbb, 0xbf]);
|
|
5
|
+
const COMMA = new Uint8Array([44]); // ASCII for ','
|
|
6
|
+
|
|
7
|
+
export class ArrayBufferParser extends Parser<ArrayBuffer | string, any> {
|
|
8
|
+
parse(input: ArrayBuffer | string): any {
|
|
9
|
+
if (typeof input === "string") {
|
|
10
|
+
return StringParser.prototype.parse.call(StringParser.prototype, input);
|
|
11
|
+
} else {
|
|
12
|
+
return StringParser.prototype.parse.call(StringParser.prototype, decodeStringFromUTF8BOM(normalizeJsonArrayBuffer(stripBOM(input))));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
stringify(obj: any): string {
|
|
16
|
+
return JSON.stringify(obj);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function stripBOM(buffer: ArrayBuffer): ArrayBuffer {
|
|
21
|
+
const view = new Uint8Array(buffer);
|
|
22
|
+
if (view.length >= 3 && view[0] === BOM[0] && view[1] === BOM[1] && view[2] === BOM[2]) {
|
|
23
|
+
return buffer.slice(3);
|
|
24
|
+
}
|
|
25
|
+
return buffer;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function normalizeJsonArrayBuffer(buffer: ArrayBuffer): ArrayBuffer {
|
|
29
|
+
const view = new Uint8Array(buffer);
|
|
30
|
+
let builder: Uint8Array[] = [];
|
|
31
|
+
let last: "other" | "string" | "escape" | "comma" = "other";
|
|
32
|
+
let from = 0;
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < view.length; i++) {
|
|
35
|
+
const charCode = view[i];
|
|
36
|
+
if (last == "escape") {
|
|
37
|
+
last = "string";
|
|
38
|
+
} else {
|
|
39
|
+
switch (charCode) {
|
|
40
|
+
case 34: // "
|
|
41
|
+
switch (last) {
|
|
42
|
+
case "string":
|
|
43
|
+
last = "other";
|
|
44
|
+
break;
|
|
45
|
+
case "comma":
|
|
46
|
+
builder.push(COMMA);
|
|
47
|
+
default:
|
|
48
|
+
last = "string";
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case 92: // \
|
|
53
|
+
if (last === "string") last = "escape";
|
|
54
|
+
break;
|
|
55
|
+
case 44: // ,
|
|
56
|
+
builder.push(view.subarray(from, i));
|
|
57
|
+
from = i + 1;
|
|
58
|
+
if (last === "other") last = "comma";
|
|
59
|
+
break;
|
|
60
|
+
case 93: // ]
|
|
61
|
+
case 125: // }
|
|
62
|
+
if (last === "comma") last = "other";
|
|
63
|
+
break;
|
|
64
|
+
case 9: // \t
|
|
65
|
+
case 10: // \n
|
|
66
|
+
case 11: // \v
|
|
67
|
+
case 12: // \f
|
|
68
|
+
case 13: // \r
|
|
69
|
+
case 32: // space
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
if (last === "comma") {
|
|
73
|
+
builder.push(COMMA);
|
|
74
|
+
last = "other";
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
builder.push(view.subarray(from));
|
|
81
|
+
|
|
82
|
+
let totalLength = 0;
|
|
83
|
+
for (const arr of builder) {
|
|
84
|
+
totalLength += arr.length;
|
|
85
|
+
}
|
|
86
|
+
const result = new Uint8Array(totalLength);
|
|
87
|
+
let offset = 0;
|
|
88
|
+
for (const arr of builder) {
|
|
89
|
+
result.set(arr, offset);
|
|
90
|
+
offset += arr.length;
|
|
91
|
+
}
|
|
92
|
+
return result.buffer;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function decodeStringFromUTF8BOM(buffer: ArrayBuffer): string {
|
|
96
|
+
const strippedBuffer = stripBOM(buffer);
|
|
97
|
+
const decoder = new TextDecoder('utf-8');
|
|
98
|
+
return decoder.decode(strippedBuffer);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default ArrayBufferParser;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import Parser from "./Parser";
|
|
2
|
+
import StringParser from "./StringParser";
|
|
1
3
|
|
|
2
4
|
let BOM: Buffer;
|
|
3
5
|
let COMMA: Buffer;
|
|
@@ -7,12 +9,23 @@ try {
|
|
|
7
9
|
COMMA = Buffer.from(",");
|
|
8
10
|
} catch (e) {
|
|
9
11
|
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
12
|
BOM = { equals: () => false, subarray: () => null } as any;
|
|
13
13
|
COMMA = { equals: () => false, subarray: () => null } as any;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export class BufferParser extends Parser<Buffer | string, any> {
|
|
17
|
+
parse(input: Buffer | string): any {
|
|
18
|
+
if (typeof input === "string") {
|
|
19
|
+
return StringParser.prototype.parse.call(StringParser.prototype, input);
|
|
20
|
+
} else {
|
|
21
|
+
return StringParser.prototype.parse.call(StringParser.prototype, decodeStringFromUTF8BOM(normalizeJsonBuffer(stripBOM(input))));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
stringify(obj: any): string {
|
|
25
|
+
return JSON.stringify(obj);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
export function stripBOM(buffer: Buffer): Buffer {
|
|
17
30
|
if (buffer.length >= 3 && BOM.equals(buffer.subarray(0, 3))) {
|
|
18
31
|
return buffer.subarray(3)
|
|
@@ -73,44 +86,8 @@ export function normalizeJsonBuffer(text: Buffer): Buffer {
|
|
|
73
86
|
return Buffer.concat(builder)
|
|
74
87
|
}
|
|
75
88
|
|
|
76
|
-
export function normalizeJsonString(text: string): string {
|
|
77
|
-
return normalizeJsonBuffer(Buffer.from(text, "utf-8")).toString("utf-8")
|
|
78
|
-
}
|
|
79
|
-
|
|
80
89
|
export function decodeStringFromUTF8BOM(buffer: Buffer): string {
|
|
81
90
|
return stripBOM(buffer).toString("utf-8")
|
|
82
91
|
}
|
|
83
92
|
|
|
84
|
-
export
|
|
85
|
-
return Buffer.concat([BOM, stripBOM(Buffer.from(text, "utf-8"))])
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function decodeJsonFromString(text: string): any {
|
|
89
|
-
return JSON.parse(normalizeJsonString(text))
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function decodeJsonFromBuffer(buffer: Buffer): any {
|
|
93
|
-
return JSON.parse(
|
|
94
|
-
decodeStringFromUTF8BOM(normalizeJsonBuffer(stripBOM(buffer))),
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function encodeJsonAsString(obj: any): string {
|
|
99
|
-
return JSON.stringify(obj)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function encodeJsonAsBufferUTF8BOM(obj: any): Buffer {
|
|
103
|
-
return encodeStringAsUTF8BOM(encodeJsonAsString(obj))
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function parse(text: string): any {
|
|
107
|
-
return decodeJsonFromString(text)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function stringify(obj: any): string {
|
|
111
|
-
return encodeJsonAsString(obj)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export default {parse,stringify}
|
|
115
|
-
|
|
116
|
-
//BufferParser by Yqloss
|
|
93
|
+
export default BufferParser;
|
package/src/parser/Parser.ts
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
}
|
|
1
|
+
abstract class Parser<TInput = any, TOutput = any> {
|
|
2
|
+
abstract parse(input: TInput): TOutput;
|
|
3
|
+
abstract stringify(obj: TOutput): TInput;
|
|
24
4
|
}
|
|
25
5
|
|
|
26
|
-
export default Parser
|
|
6
|
+
export default Parser;
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
static parse(text: string | null, reviver?: (key: string, value: any) => any): any {
|
|
3
|
-
if (text == null) return null;
|
|
4
|
-
const result = new ParserX(text).parseValue();
|
|
5
|
-
if (typeof reviver === "function") {
|
|
6
|
-
return this._applyReviver("", result, reviver);
|
|
7
|
-
}
|
|
8
|
-
return result;
|
|
9
|
-
}
|
|
1
|
+
import Parser from "./Parser";
|
|
10
2
|
|
|
11
|
-
|
|
3
|
+
class StringParser extends Parser<string, any> {
|
|
4
|
+
parse(text: string | null, reviver?: (key: string, value: any) => any): any {
|
|
12
5
|
if (text == null) return null;
|
|
13
|
-
const result = new ParserX(text
|
|
6
|
+
const result = new ParserX(text).parseValue();
|
|
14
7
|
if (typeof reviver === "function") {
|
|
15
|
-
return
|
|
8
|
+
return StringParser._applyReviver("", result, reviver);
|
|
16
9
|
}
|
|
17
10
|
return result;
|
|
18
11
|
}
|
|
19
12
|
|
|
20
|
-
|
|
13
|
+
stringify(value: any, replacer?: (key: string, value: any) => any, space?: string | number): string {
|
|
21
14
|
const serializer = new Serializer(replacer, space);
|
|
22
15
|
return serializer.serialize(value);
|
|
23
16
|
}
|
|
@@ -26,12 +19,12 @@ class StringParser {
|
|
|
26
19
|
if (value && typeof value === "object") {
|
|
27
20
|
if (Array.isArray(value)) {
|
|
28
21
|
for (let i = 0; i < value.length; i++) {
|
|
29
|
-
value[i] =
|
|
22
|
+
value[i] = StringParser._applyReviver(i.toString(), value[i], reviver);
|
|
30
23
|
}
|
|
31
24
|
} else {
|
|
32
25
|
for (const prop in value) {
|
|
33
26
|
if (Object.prototype.hasOwnProperty.call(value, prop)) {
|
|
34
|
-
value[prop] =
|
|
27
|
+
value[prop] = StringParser._applyReviver(prop, value[prop], reviver);
|
|
35
28
|
}
|
|
36
29
|
}
|
|
37
30
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import StringParser from './StringParser';
|
|
2
|
+
import { LevelOptions, ParseProvider } from '../structure';
|
|
3
|
+
|
|
4
|
+
class BaseParser {
|
|
5
|
+
static parseError(f: string) {
|
|
6
|
+
return f;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} t - Input Content
|
|
11
|
+
* @param {object} provider - ParserProvider
|
|
12
|
+
* @returns {LevelOptions} ADOFAI File Object
|
|
13
|
+
*/
|
|
14
|
+
static parseAsObject(t: string, provider?: ParseProvider): LevelOptions {
|
|
15
|
+
const parser = provider || new StringParser();
|
|
16
|
+
return parser.parse(BaseParser.parseAsText(t)) as LevelOptions;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} t - Input Content
|
|
21
|
+
* @returns {string} ADOFAI File Content
|
|
22
|
+
*/
|
|
23
|
+
static parseAsText(t: string) {
|
|
24
|
+
return this.parseError(t);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default BaseParser;
|
package/src/parser.ts
CHANGED
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 BaseParser 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 = BaseParser.parseAsObject(opt, this._provider) as LevelOptions;
|
|
44
44
|
} catch (e) {
|
|
45
45
|
reject(e);
|
|
46
46
|
return;
|