Skip to content

Commit

Permalink
Smooth API Demo
Browse files Browse the repository at this point in the history
Looking into restructuring the layout of the public API, both in how you import from it, and how the exported functionalities are named. When I check out how people are using the library, it seems like they don't read the documentation too closely (understandable), so they use extra API calls that don't have to be there. It seems like people want to use `NBT.parse()` more than `NBT.read()`, while one is for binary files, and one is for SNBT files. I can see how they might think `read()` is for reading from the file system, and maybe instead they think `parse()` is to just read arbitrary data. NBTify is meant to be used specifically outside of the file system though, so neither API feature would worry about that. Not all libraries are like that though, so I can see why people think that.

#47

This is a demo I made the other day of how it might make sense to see the public API look. This commit experiments with that as a demo in mind.

```js
// @ts-check

import { Buffer } from "node:buffer";
import * as NBT from "nbtify";

const buffer = Buffer.alloc(25);
const data = await NBT.readBinary(buffer);

NBT.writeBinary; NBT.readString; NBT.writeString;
```
  • Loading branch information
Offroaders123 committed Aug 25, 2024
1 parent ebe570b commit 46d2271
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 34 deletions.
14 changes: 7 additions & 7 deletions src/bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { extname } from "node:path";
import { readFileSync } from "node:fs";
import { inspect, promisify } from "node:util";
import { read, write, parse, stringify, NBTData } from "../index.js";
import { readBinary, writeBinary, readString, writeString, NBTData } from "../index.js";
import { file, nbt, snbt, json, format, space } from "./args.js";

import type { RootTag } from "../index.js";
Expand Down Expand Up @@ -31,8 +31,8 @@ async function readExtension(buffer: Buffer, file: string): Promise<RootTag | NB
const extension: string = extname(file);
switch (extension) {
case ".json": return JSON.parse(buffer.toString("utf-8")) as RootTag;
case ".snbt": return parse(buffer.toString("utf-8"));
default: return read(buffer);
case ".snbt": return readString(buffer.toString("utf-8"));
default: return readBinary(buffer);
}
}

Expand All @@ -41,9 +41,9 @@ async function readBuffer(buffer: Buffer): Promise<RootTag | NBTData> {
return JSON.parse(buffer.toString("utf-8")) as RootTag;
} catch {
try {
return parse(buffer.toString("utf-8"));
return readString(buffer.toString("utf-8"));
} catch {
return read(buffer);
return readBinary(buffer);
}
}
}
Expand All @@ -60,6 +60,6 @@ const stdoutWriteAsync = promisify(process.stdout.write.bind(process.stdout));
const result: string | Uint8Array = json
? `${JSON.stringify(output.data, null, space)}\n`
: snbt
? `${stringify(output, { space })}\n`
: await write(output);
? `${writeString(output, { space })}\n`
: await writeBinary(output);
await stdoutWriteAsync(result);
2 changes: 1 addition & 1 deletion src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const UNQUOTED_STRING_PATTERN = /^[0-9A-Za-z.+_-]+$/;
/**
* Converts an SNBT string into an NBT object.
*/
export function parse<T extends RootTagLike = RootTag>(data: string): T {
export function readString<T extends RootTagLike = RootTag>(data: string): T {
if (typeof data !== "string") {
data satisfies never;
throw new TypeError("First parameter must be a string");
Expand Down
16 changes: 8 additions & 8 deletions src/read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface ReadOptions {
*
* If a format option isn't specified, the function will attempt reading the data using all options until it either throws or returns successfully.
*/
export async function read<T extends RootTagLike = RootTag>(data: Uint8Array | ArrayBufferLike | Blob, options: Partial<ReadOptions> = {}): Promise<NBTData<T>> {
export async function readBinary<T extends RootTagLike = RootTag>(data: Uint8Array | ArrayBufferLike | Blob, options: Partial<ReadOptions> = {}): Promise<NBTData<T>> {
if (data instanceof Blob) {
data = await data.arrayBuffer();
}
Expand Down Expand Up @@ -64,10 +64,10 @@ export async function read<T extends RootTagLike = RootTag>(data: Uint8Array | A
case reader.hasZlibHeader(): compression = "deflate"; break compression;
}
try {
return await read<T>(data, { ...options, compression: null });
return await readBinary<T>(data, { ...options, compression: null });
} catch (error) {
try {
return await read<T>(data, { ...options, compression: "deflate-raw" });
return await readBinary<T>(data, { ...options, compression: "deflate-raw" });
} catch {
throw error;
}
Expand All @@ -78,13 +78,13 @@ export async function read<T extends RootTagLike = RootTag>(data: Uint8Array | A

if (endian === undefined) {
try {
return await read<T>(data, { ...options, endian: "big" });
return await readBinary<T>(data, { ...options, endian: "big" });
} catch (error) {
try {
return await read<T>(data, { ...options, endian: "little" });
return await readBinary<T>(data, { ...options, endian: "little" });
} catch {
try {
return await read<T>(data, { ...options, endian: "little-varint" });
return await readBinary<T>(data, { ...options, endian: "little-varint" });
} catch {
throw error;
}
Expand All @@ -96,10 +96,10 @@ export async function read<T extends RootTagLike = RootTag>(data: Uint8Array | A

if (rootName === undefined) {
try {
return await read<T>(data, { ...options, rootName: true });
return await readBinary<T>(data, { ...options, rootName: true });
} catch (error) {
try {
return await read<T>(data, { ...options, rootName: false });
return await readBinary<T>(data, { ...options, rootName: false });
} catch {
throw error;
}
Expand Down
4 changes: 2 additions & 2 deletions src/stringify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export interface StringifyOptions {
/**
* Converts an NBT object into an SNBT string.
*/
export function stringify<T extends RootTagLike = RootTag>(data: T | NBTData<T>, options?: StringifyOptions): string;
export function stringify<T extends RootTagLike = RootTag>(data: T | NBTData<T>, { space = "" }: StringifyOptions = {}): string {
export function writeString<T extends RootTagLike = RootTag>(data: T | NBTData<T>, options?: StringifyOptions): string;
export function writeString<T extends RootTagLike = RootTag>(data: T | NBTData<T>, { space = "" }: StringifyOptions = {}): string {
if (data instanceof NBTData) {
data = data.data;
}
Expand Down
2 changes: 1 addition & 1 deletion src/write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { Tag, RootTag, RootTagLike, ByteTag, BooleanTag, ShortTag, IntTag,
*
* If a format option isn't specified, the value of the equivalent property on the NBTData object will be used.
*/
export async function write<T extends RootTagLike = RootTag>(data: T | NBTData<T>, options: NBTDataOptions = {}): Promise<Uint8Array> {
export async function writeBinary<T extends RootTagLike = RootTag>(data: T | NBTData<T>, options: NBTDataOptions = {}): Promise<Uint8Array> {
data = new NBTData(data, options);

const { rootName, endian, compression, bedrockLevel } = data as NBTData<T>;
Expand Down
8 changes: 4 additions & 4 deletions test/builder-class.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { write, Int32 } from "../src/index.js";
import { writeBinary, Int32 } from "../src/index.js";

import type { Tag, RootTagLike, IntTag, CompoundTag } from "../src/index.js";

Expand All @@ -20,11 +20,11 @@ levelDat.Difficulty;
// @ts-expect-error - Property 'NON_THINGO' comes from an index signature. ts(4111)
levelDat.NON_THINGO

await write(levelDat);
await writeBinary(levelDat);

// Using classes to build NBT objects is supported too, but less declarative, so I don't recommend it as much.

// Fixed! - // @ts-expect-error - Index signature for type 'string' is missing in type '(Anonymous class)'. ts(1360)
await write(new class {} satisfies RootTagLike);
await writeBinary(new class {} satisfies RootTagLike);

await write(new class { [name: string]: Tag; } satisfies RootTagLike);
await writeBinary(new class { [name: string]: Tag; } satisfies RootTagLike);
16 changes: 8 additions & 8 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,28 @@ describe("Read, Stringify, Parse and Write", () => {
/** Reads the NBT file buffer by auto-detecting the file format. */
const result: void | NBT.RootTag | NBT.NBTData = (snbt)
? (listItemAssertion)
? throws(() => NBT.parse<NBT.RootTag>(buffer.toString("utf-8")), `'${name}' parses from SNBT when it shouldn't`)
: NBT.parse<NBT.RootTag>(buffer.toString("utf-8"))
: await NBT.read<NBT.RootTag>(buffer, { strict });
? throws(() => NBT.readString<NBT.RootTag>(buffer.toString("utf-8")), `'${name}' parses from SNBT when it shouldn't`)
: NBT.readString<NBT.RootTag>(buffer.toString("utf-8"))
: await NBT.readBinary<NBT.RootTag>(buffer, { strict });
if (result === undefined) return;

/** Stringifies the NBTData result to an SNBT string. */
const stringified: string | void = (listItemAssertion)
? throws(() => NBT.stringify(result), `'${name}' stringifies to SNBT when it shouldn't`)
: NBT.stringify(result);
? throws(() => NBT.writeString(result), `'${name}' stringifies to SNBT when it shouldn't`)
: NBT.writeString(result);
if (stringified === undefined) return;

/** Parses the SNBT string to a new NBTData result. */
const parsed: NBT.RootTag = NBT.parse<NBT.RootTag>(stringified);
const parsed: NBT.RootTag = NBT.readString<NBT.RootTag>(stringified);

/** Writes the new NBTData result to a recompiled NBT buffer. */
const recompile: Buffer | Uint8Array = (snbt)
? Buffer.from(NBT.stringify(parsed,
? Buffer.from(NBT.writeString(parsed,
(snbt)
? undefined
: { space: 2 }
))
: await NBT.write(
: await NBT.writeBinary(
(emptyList)
? result
: parsed
Expand Down
6 changes: 3 additions & 3 deletions test/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { readFile } from "node:fs/promises";
import { parse, stringify } from "../src/index.js";
import { readString, writeString } from "../src/index.js";

const bigtest = new URL("./nbt/bigtest.snbt", import.meta.url);

const data = await readFile(bigtest);
console.log(data);

const result = parse(data.toString());
const result = readString(data.toString());
// console.log(result);

const stringy = stringify(result, { space: 2 });
const stringy = writeString(result, { space: 2 });
console.log(stringy);

0 comments on commit 46d2271

Please sign in to comment.