fix: fix master tag type

This commit is contained in:
master 2025-03-18 02:46:18 +08:00
parent 11fdb0f2fc
commit 9a5d025f40
24 changed files with 880 additions and 905 deletions

View File

@ -1,66 +1,55 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"extends": [
"ultracite"
],
"linter": {
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"extends": ["ultracite"],
"linter": {
"rules": {
"style": {
"noNonNullAssertion": "off",
"noParameterAssign": "off",
"useFilenamingConvention": "off",
"noParameterProperties": "off",
"useImportType": {
"level": "error",
"fix": "unsafe"
}
},
"suspicious": {
"noExplicitAny": "off"
},
"complexity": {
"noForEach": "off"
},
"correctness": {
"noUnusedImports": {
"fix": "none",
"level": "warn"
}
},
"nursery": {
"noEnum": "off",
"useConsistentMemberAccessibility": "off"
}
}
},
"files": {
"ignore": [".vscode/*.json"]
},
"overrides": [
{
"include": ["tests/**"],
"javascript": {
"globals": ["describe", "beforeEach", "it", "expect"]
},
"linter": {
"rules": {
"style": {
"noNonNullAssertion": "off",
"noParameterAssign": "off",
"useFilenamingConvention": "off",
"noParameterProperties": "off",
"useImportType": {
"level": "error",
"fix": "unsafe"
}
},
"suspicious": {
"noExplicitAny": "off"
},
"complexity": {
"noForEach": "off"
},
"correctness": {
"noUnusedImports": {
"fix": "none",
"level": "warn"
}
},
"nursery": {
"noEnum": "off",
"useConsistentMemberAccessibility": "off"
}
"performance": {
"useTopLevelRegex": "off"
},
"suspicious": {
"noMisplacedAssertion": "off"
}
}
},
"files": {
"ignore": [
".vscode/*.json"
]
},
"overrides": [
{
"include": [
"tests/**"
],
"javascript": {
"globals": [
"describe",
"beforeEach",
"it",
"expect"
]
},
"linter": {
"rules": {
"performance": {
"useTopLevelRegex": "off"
},
"suspicious": {
"noMisplacedAssertion": "off"
}
}
}
}
]
}
}
}
]
}

View File

@ -1,8 +1,8 @@
import fs from 'node:fs/promises';
import {
ReadableStream,
WritableStream,
type TransformStream,
WritableStream,
} from 'node:stream/web';
import { EbmlStreamDecoder } from 'konoebml';

View File

@ -1,6 +1,6 @@
{
"name": "konoebml",
"version": "0.1.0-rc.4",
"version": "0.1.0-rc.5",
"description": "A modern JavaScript implementation of EBML RFC8794",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
@ -20,8 +20,8 @@
"test": "vitest --coverage",
"test-ci": "vitest --watch=false --coverage",
"prepublishOnly": "npm run build",
"lint": "ultracite lint",
"format": "ultracite format",
"lint": "biome lint",
"lint-fix": "biome lint --fix",
"playground": "tsx --tsconfig=./tsconfig.example.json ./examples/playground.ts"
},
"repository": "github:dumtruck/konoebml",

View File

@ -1,124 +1,124 @@
import { type EbmlTagIdType, isEbmlMasterTagId } from './models/enums';
import type { DecodeContentOptions, EbmlTagTrait } from './models/tag-trait';
import type { FileDataViewController } from './adapters';
import {
checkVintSafeSize,
dataViewSlice,
readUnsigned,
readVint,
readVintLength,
type SafeSizeVint,
} from './tools';
import { EbmlTagPosition } from './models/enums';
import { createEbmlTag } from './factory';
import { UnreachableOrLogicError } from './errors';
export async function decodeEbmlTagHeader(
controller: FileDataViewController
): Promise<{
sizeVint: SafeSizeVint;
tagVint: { length: number };
tagId: EbmlTagIdType;
}> {
const offset = controller.getOffset();
let view = await controller.read(offset, 1);
const tagVintLength = readVintLength(view);
view =
tagVintLength > view.byteLength
? await controller.read(offset, tagVintLength)
: view;
const tagIdView = dataViewSlice(view, 0, tagVintLength);
view =
tagVintLength + 1 > view.byteLength
? await controller.read(offset, tagVintLength + 1)
: view;
const sizeVintLength = readVintLength(
dataViewSlice(view, tagVintLength, tagVintLength + 1)
);
view =
tagVintLength + sizeVintLength > view.byteLength
? await controller.read(offset, tagVintLength + sizeVintLength)
: view;
const sizeVint = readVint(
dataViewSlice(view, tagVintLength, tagVintLength + sizeVintLength)
)!;
if (!sizeVint) {
throw new UnreachableOrLogicError(
'size vint dataView length is invalid, check code logic!'
);
}
const tagId = readUnsigned(tagIdView);
const safeSizeVint = checkVintSafeSize(sizeVint, tagId);
return {
sizeVint: safeSizeVint,
tagVint: {
length: tagVintLength,
},
tagId,
};
}
export async function* decodeEbmlContent(
options: DecodeContentOptions
): AsyncGenerator<EbmlTagTrait, void, unknown> {
const controller = options.dataViewController;
while (true) {
const offset = controller.getOffset();
const peeked = await controller.peek(offset);
if (!peeked) {
break;
}
const vints = await decodeEbmlTagHeader(controller);
const { tagId, tagVint, sizeVint } = vints;
const headerLength = tagVint.length + sizeVint.length;
const contentLength = sizeVint.value;
const isMaster = isEbmlMasterTagId(tagId);
if (isMaster) {
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: EbmlTagPosition.Start,
parent: undefined,
});
yield tag;
}
await controller.seek(offset + headerLength);
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: isMaster ? EbmlTagPosition.End : EbmlTagPosition.Content,
parent: undefined,
});
for await (const item of tag.decodeContent(options)) {
yield item;
}
tag.endOffset = controller.getOffset();
yield tag;
}
}
import type { FileDataViewController } from './adapters';
import { UnreachableOrLogicError } from './errors';
import { createEbmlTag } from './factory';
import { type EbmlTagIdType, isEbmlMasterTagId } from './models/enums';
import { EbmlTagPosition } from './models/enums';
import type { DecodeContentOptions, EbmlTagTrait } from './models/tag-trait';
import {
type SafeSizeVint,
checkVintSafeSize,
dataViewSlice,
readUnsigned,
readVint,
readVintLength,
} from './tools';
export async function decodeEbmlTagHeader(
controller: FileDataViewController
): Promise<{
sizeVint: SafeSizeVint;
tagVint: { length: number };
tagId: EbmlTagIdType;
}> {
const offset = controller.getOffset();
let view = await controller.read(offset, 1);
const tagVintLength = readVintLength(view);
view =
tagVintLength > view.byteLength
? await controller.read(offset, tagVintLength)
: view;
const tagIdView = dataViewSlice(view, 0, tagVintLength);
view =
tagVintLength + 1 > view.byteLength
? await controller.read(offset, tagVintLength + 1)
: view;
const sizeVintLength = readVintLength(
dataViewSlice(view, tagVintLength, tagVintLength + 1)
);
view =
tagVintLength + sizeVintLength > view.byteLength
? await controller.read(offset, tagVintLength + sizeVintLength)
: view;
const sizeVint = readVint(
dataViewSlice(view, tagVintLength, tagVintLength + sizeVintLength)
)!;
if (!sizeVint) {
throw new UnreachableOrLogicError(
'size vint dataView length is invalid, check code logic!'
);
}
const tagId = readUnsigned(tagIdView);
const safeSizeVint = checkVintSafeSize(sizeVint, tagId);
return {
sizeVint: safeSizeVint,
tagVint: {
length: tagVintLength,
},
tagId,
};
}
export async function* decodeEbmlContent(
options: DecodeContentOptions
): AsyncGenerator<EbmlTagTrait, void, unknown> {
const controller = options.dataViewController;
while (true) {
const offset = controller.getOffset();
const peeked = await controller.peek(offset);
if (!peeked) {
break;
}
const vints = await decodeEbmlTagHeader(controller);
const { tagId, tagVint, sizeVint } = vints;
const headerLength = tagVint.length + sizeVint.length;
const contentLength = sizeVint.value;
const isMaster = isEbmlMasterTagId(tagId);
if (isMaster) {
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: EbmlTagPosition.Start,
parent: undefined,
});
yield tag;
}
await controller.seek(offset + headerLength);
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: isMaster ? EbmlTagPosition.End : EbmlTagPosition.Content,
parent: undefined,
});
for await (const item of tag.decodeContent(options)) {
yield item;
}
tag.endOffset = controller.getOffset();
yield tag;
}
}

View File

@ -1,13 +1,13 @@
import { Queue } from 'mnemonist';
import type { FileDataViewController } from './adapters';
import { decodeEbmlContent } from './decode-utils';
import { StreamFlushReason, UnreachableOrLogicError } from './errors';
import type { EbmlTagType } from './models/tag';
import type {
DecodeContentCollectChildPredicate,
EbmlTagTrait,
} from './models/tag-trait';
import { decodeEbmlContent } from './decode-utils';
import { StreamFlushReason, UnreachableOrLogicError } from './errors';
import { dataViewSlice } from './tools';
import type { EbmlTagType } from './models/tag';
export type EbmlStreamDecoderChunkType =
| Uint8Array

View File

@ -1,9 +1,9 @@
import { Queue, Stack } from 'mnemonist';
import { EbmlTagTrait } from './models/tag-trait';
import { EbmlTagPosition } from './models/enums';
import { EbmlMasterTag } from './models/tag-master';
import { EbmlTreeMasterNotMatchError, UnreachableOrLogicError } from './errors';
import { EbmlTagPosition } from './models/enums';
import type { EbmlTagType } from './models/tag';
import { EbmlMasterTag } from './models/tag-master';
import { EbmlTagTrait } from './models/tag-trait';
export class EbmlEncodeStreamTransformer
implements Transformer<EbmlTagTrait | EbmlTagType, Uint8Array>

View File

@ -1,21 +1,21 @@
import { InconsistentWellKnownEbmlTagTypeError } from './errors';
import {
type EbmlMasterTagIdType,
type EbmlDataTagIdType,
type EbmlBlockTagIdType,
type EbmlSimpleBlockTagIdType,
type EbmlDataTagIdType,
EbmlElementType,
type EbmlMasterTagIdType,
type EbmlSimpleBlockTagIdType,
EbmlTagIdEnum,
isEbmlBlockTagId,
isEbmlSimpleBlockTagId,
isEbmlMasterTagId,
isEbmlUintDataTagId,
isEbmlIntDataTagId,
isEbmlFloatDataTagId,
isEbmlStringDataTagId,
isEbmlUtf8DataTagId,
isEbmlDateDataTagId,
isEbmlBinaryDataTagId,
isEbmlBlockTagId,
isEbmlDateDataTagId,
isEbmlFloatDataTagId,
isEbmlIntDataTagId,
isEbmlMasterTagId,
isEbmlSimpleBlockTagId,
isEbmlStringDataTagId,
isEbmlUintDataTagId,
isEbmlUtf8DataTagId,
} from './models/enums';
import {
type CreateEbmlBlockTagOptions,

View File

@ -1,124 +1,124 @@
import { type CreateEbmlDataTagOptions, EbmlDataTag } from './tag-data';
import { EbmlBlockLacing } from './enums';
import {
dataViewSlice,
dataViewSliceToBuf,
readSigned,
readVint,
writeSigned,
writeVint,
} from '../tools';
import {
type EbmlBlockTagIdType,
type EbmlSimpleBlockTagIdType,
EbmlTagIdEnum,
} from './enums';
import { EbmlElementType } from './enums';
import type { DecodeContentOptions } from './tag-trait';
export interface CreateEbmlBlockTagOptions
extends Omit<CreateEbmlDataTagOptions, 'id' | 'type'> {
id?: EbmlBlockTagIdType | EbmlSimpleBlockTagIdType;
}
export class EbmlBlockTag extends EbmlDataTag {
payload = new Uint8Array(0);
track: number | bigint = 0;
value = 0;
invisible: boolean | undefined;
lacing: EbmlBlockLacing | undefined;
constructor(options: CreateEbmlBlockTagOptions) {
super({
...options,
id: options.id ?? EbmlTagIdEnum.Block,
type: EbmlElementType.Binary,
});
}
protected writeTrackBuffer(): Uint8Array {
return writeVint(this.track);
}
protected writeValueBuffer(): Uint8Array {
return writeSigned(this.value, 2);
}
protected writeFlagsBuffer(): Uint8Array {
let flags = 0x00;
if (this.invisible) {
flags |= 0x10;
}
switch (this.lacing) {
case EbmlBlockLacing.None:
break;
case EbmlBlockLacing.Xiph:
flags |= 0x04;
break;
case EbmlBlockLacing.EBML:
flags |= 0x08;
break;
case EbmlBlockLacing.FixedSize:
flags |= 0x0c;
break;
default:
}
return new Uint8Array([flags % 256]);
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
yield this.writeTrackBuffer();
yield this.writeValueBuffer();
yield this.writeFlagsBuffer();
yield this.payload;
}
// biome-ignore lint/correctness/useYield: <explanation>
async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const offset = controller.getOffset();
const view = await controller.read(offset, this.contentLength, true);
const track = readVint(view)!;
this.track = track.value;
this.value = Number(
readSigned(dataViewSlice(view, track.length, track.length + 2))
);
const flags: number = view.getUint8(track.length + 2);
this.invisible = Boolean(flags & 0x10);
switch (flags & 0x0c) {
case 0x00:
this.lacing = EbmlBlockLacing.None;
break;
case 0x04:
this.lacing = EbmlBlockLacing.Xiph;
break;
case 0x08:
this.lacing = EbmlBlockLacing.EBML;
break;
case 0x0c:
this.lacing = EbmlBlockLacing.FixedSize;
break;
default:
}
this.payload = dataViewSliceToBuf(view, track.length + 3, undefined);
await controller.seek(offset + view.byteLength);
}
override toDebugRecord() {
const s = super.toDebugRecord();
return {
...s,
payload: this.payload,
track: this.track,
value: this.value,
invisible: this.invisible,
lacing: EbmlBlockLacing[this.lacing!] || this.lacing,
};
}
}
import {
dataViewSlice,
dataViewSliceToBuf,
readSigned,
readVint,
writeSigned,
writeVint,
} from '../tools';
import { EbmlBlockLacing } from './enums';
import {
type EbmlBlockTagIdType,
type EbmlSimpleBlockTagIdType,
EbmlTagIdEnum,
} from './enums';
import { EbmlElementType } from './enums';
import { type CreateEbmlDataTagOptions, EbmlDataTag } from './tag-data';
import type { DecodeContentOptions } from './tag-trait';
export interface CreateEbmlBlockTagOptions
extends Omit<CreateEbmlDataTagOptions, 'id' | 'type'> {
id?: EbmlBlockTagIdType | EbmlSimpleBlockTagIdType;
}
export class EbmlBlockTag extends EbmlDataTag {
payload = new Uint8Array(0);
track: number | bigint = 0;
value = 0;
invisible: boolean | undefined;
lacing: EbmlBlockLacing | undefined;
constructor(options: CreateEbmlBlockTagOptions) {
super({
...options,
id: options.id ?? EbmlTagIdEnum.Block,
type: EbmlElementType.Binary,
});
}
protected writeTrackBuffer(): Uint8Array {
return writeVint(this.track);
}
protected writeValueBuffer(): Uint8Array {
return writeSigned(this.value, 2);
}
protected writeFlagsBuffer(): Uint8Array {
let flags = 0x00;
if (this.invisible) {
flags |= 0x10;
}
switch (this.lacing) {
case EbmlBlockLacing.None:
break;
case EbmlBlockLacing.Xiph:
flags |= 0x04;
break;
case EbmlBlockLacing.EBML:
flags |= 0x08;
break;
case EbmlBlockLacing.FixedSize:
flags |= 0x0c;
break;
default:
}
return new Uint8Array([flags % 256]);
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
yield this.writeTrackBuffer();
yield this.writeValueBuffer();
yield this.writeFlagsBuffer();
yield this.payload;
}
// biome-ignore lint/correctness/useYield: <explanation>
async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const offset = controller.getOffset();
const view = await controller.read(offset, this.contentLength, true);
const track = readVint(view)!;
this.track = track.value;
this.value = Number(
readSigned(dataViewSlice(view, track.length, track.length + 2))
);
const flags: number = view.getUint8(track.length + 2);
this.invisible = Boolean(flags & 0x10);
switch (flags & 0x0c) {
case 0x00:
this.lacing = EbmlBlockLacing.None;
break;
case 0x04:
this.lacing = EbmlBlockLacing.Xiph;
break;
case 0x08:
this.lacing = EbmlBlockLacing.EBML;
break;
case 0x0c:
this.lacing = EbmlBlockLacing.FixedSize;
break;
default:
}
this.payload = dataViewSliceToBuf(view, track.length + 3, undefined);
await controller.seek(offset + view.byteLength);
}
override toDebugRecord() {
const s = super.toDebugRecord();
return {
...s,
payload: this.payload,
track: this.track,
value: this.value,
invisible: this.invisible,
lacing: EbmlBlockLacing[this.lacing!] || this.lacing,
};
}
}

View File

@ -1,95 +1,95 @@
import {
type CreateEbmlTagOptions,
type DecodeContentOptions,
EbmlTagTrait,
} from './tag-trait';
import { EbmlElementType } from './enums';
import {
dataViewSliceToBuf,
readAscii,
readFloat,
readSigned,
readUnsigned,
readUtf8,
writeAscii,
writeFloat,
writeSigned,
writeUnsigned,
writeUtf8,
} from '../tools';
import { EbmlTagPosition } from './enums';
export type CreateEbmlDataTagOptions = Omit<CreateEbmlTagOptions, 'position'>;
export class EbmlDataTag extends EbmlTagTrait {
data: number | string | bigint | null | Uint8Array | undefined;
constructor(options: CreateEbmlDataTagOptions) {
super({
...options,
position: EbmlTagPosition.Content,
});
}
// biome-ignore lint/correctness/useYield: <explanation>
override async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const offset = controller.getOffset();
const view = await controller.read(offset, this.contentLength, true);
switch (this.type) {
case EbmlElementType.UnsignedInt:
this.data = readUnsigned(view);
break;
case EbmlElementType.Float:
this.data = readFloat(view);
break;
case EbmlElementType.Integer:
this.data = readSigned(view);
break;
case EbmlElementType.Ascii:
this.data = readAscii(view);
break;
case EbmlElementType.UTF8:
this.data = readUtf8(view);
break;
default:
this.data = dataViewSliceToBuf(view, undefined, undefined);
break;
}
await controller.seek(offset + view.byteLength);
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
switch (this.type) {
case EbmlElementType.UnsignedInt:
yield writeUnsigned(this.data as any);
break;
case EbmlElementType.Float:
yield writeFloat(this.data as any);
break;
case EbmlElementType.Integer:
yield writeSigned(this.data as any);
break;
case EbmlElementType.Ascii:
yield writeAscii(this.data as any);
break;
case EbmlElementType.UTF8:
yield writeUtf8(this.data as any);
break;
default:
yield this.data as Uint8Array;
break;
}
}
override toDebugRecord() {
return {
...super.toDebugRecord(),
data: this.data,
};
}
toJSON() {
return JSON.stringify(this.toDebugRecord(), null, 2);
}
}
import {
dataViewSliceToBuf,
readAscii,
readFloat,
readSigned,
readUnsigned,
readUtf8,
writeAscii,
writeFloat,
writeSigned,
writeUnsigned,
writeUtf8,
} from '../tools';
import { EbmlElementType } from './enums';
import { EbmlTagPosition } from './enums';
import {
type CreateEbmlTagOptions,
type DecodeContentOptions,
EbmlTagTrait,
} from './tag-trait';
export type CreateEbmlDataTagOptions = Omit<CreateEbmlTagOptions, 'position'>;
export class EbmlDataTag extends EbmlTagTrait {
data: number | string | bigint | null | Uint8Array | undefined;
constructor(options: CreateEbmlDataTagOptions) {
super({
...options,
position: EbmlTagPosition.Content,
});
}
// biome-ignore lint/correctness/useYield: <explanation>
override async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const offset = controller.getOffset();
const view = await controller.read(offset, this.contentLength, true);
switch (this.type) {
case EbmlElementType.UnsignedInt:
this.data = readUnsigned(view);
break;
case EbmlElementType.Float:
this.data = readFloat(view);
break;
case EbmlElementType.Integer:
this.data = readSigned(view);
break;
case EbmlElementType.Ascii:
this.data = readAscii(view);
break;
case EbmlElementType.UTF8:
this.data = readUtf8(view);
break;
default:
this.data = dataViewSliceToBuf(view, undefined, undefined);
break;
}
await controller.seek(offset + view.byteLength);
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
switch (this.type) {
case EbmlElementType.UnsignedInt:
yield writeUnsigned(this.data as any);
break;
case EbmlElementType.Float:
yield writeFloat(this.data as any);
break;
case EbmlElementType.Integer:
yield writeSigned(this.data as any);
break;
case EbmlElementType.Ascii:
yield writeAscii(this.data as any);
break;
case EbmlElementType.UTF8:
yield writeUtf8(this.data as any);
break;
default:
yield this.data as Uint8Array;
break;
}
}
override toDebugRecord() {
return {
...super.toDebugRecord(),
data: this.data,
};
}
toJSON() {
return JSON.stringify(this.toDebugRecord(), null, 2);
}
}

View File

@ -1,107 +1,107 @@
import {
type CreateEbmlTagOptions,
type DecodeContentOptions,
EbmlTagTrait,
} from './tag-trait';
import { EbmlElementType, EbmlTagPosition, isEbmlMasterTagId } from './enums';
import { decodeEbmlTagHeader } from '../decode-utils';
import { createEbmlTag } from 'src/factory';
import type { EbmlMasterTagIdType } from './enums';
export interface CreateEbmlMasterTagOptions
extends Omit<CreateEbmlTagOptions, 'position' | 'type' | 'id'> {
id: EbmlMasterTagIdType;
}
export class EbmlMasterTag extends EbmlTagTrait {
private _children: EbmlTagTrait[] = [];
get children(): EbmlTagTrait[] {
return this._children;
}
set children(value: EbmlTagTrait[]) {
this._children = value;
}
constructor(options: CreateEbmlMasterTagOptions) {
super({
...options,
id: options.id,
type: EbmlElementType.Master,
});
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
for (const child of this.children) {
yield* child.encode();
}
}
async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const collectChild = options.collectChild;
while (true) {
const offset = controller.getOffset();
if (offset >= this.endOffset) {
break;
}
const peeked = await controller.peek(offset);
if (!peeked) {
break;
}
const vints = await decodeEbmlTagHeader(controller);
const { tagId, tagVint, sizeVint } = vints;
const headerLength = tagVint.length + sizeVint.length;
const contentLength = sizeVint.value;
const isMaster = isEbmlMasterTagId(tagId);
if (isMaster) {
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: EbmlTagPosition.Start,
parent: this,
});
yield tag;
}
await controller.seek(offset + headerLength);
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: isMaster ? EbmlTagPosition.End : EbmlTagPosition.Content,
parent: this,
});
for await (const item of tag.decodeContent(options)) {
yield item;
}
tag.endOffset = controller.getOffset();
let shouldCollectChild: boolean;
if (typeof collectChild === 'function') {
shouldCollectChild = !!collectChild(tag, this);
} else {
shouldCollectChild = !!collectChild;
}
if (shouldCollectChild) {
this._children.push(tag);
}
yield tag;
}
}
}
import { createEbmlTag } from 'src/factory';
import { decodeEbmlTagHeader } from '../decode-utils';
import { EbmlElementType, EbmlTagPosition, isEbmlMasterTagId } from './enums';
import type { EbmlMasterTagIdType } from './enums';
import {
type CreateEbmlTagOptions,
type DecodeContentOptions,
EbmlTagTrait,
} from './tag-trait';
export interface CreateEbmlMasterTagOptions
extends Omit<CreateEbmlTagOptions, 'position' | 'type' | 'id'> {
id: EbmlMasterTagIdType;
}
export class EbmlMasterTag extends EbmlTagTrait {
private _children: EbmlTagTrait[] = [];
get children(): EbmlTagTrait[] {
return this._children;
}
set children(value: EbmlTagTrait[]) {
this._children = value;
}
constructor(options: CreateEbmlMasterTagOptions) {
super({
...options,
id: options.id,
type: EbmlElementType.Master,
});
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
for (const child of this.children) {
yield* child.encode();
}
}
async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const collectChild = options.collectChild;
while (true) {
const offset = controller.getOffset();
if (offset >= this.endOffset) {
break;
}
const peeked = await controller.peek(offset);
if (!peeked) {
break;
}
const vints = await decodeEbmlTagHeader(controller);
const { tagId, tagVint, sizeVint } = vints;
const headerLength = tagVint.length + sizeVint.length;
const contentLength = sizeVint.value;
const isMaster = isEbmlMasterTagId(tagId);
if (isMaster) {
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: EbmlTagPosition.Start,
parent: this,
});
yield tag;
}
await controller.seek(offset + headerLength);
const tag: EbmlTagTrait = createEbmlTag(tagId, {
headerLength,
contentLength,
startOffset: offset,
position: isMaster ? EbmlTagPosition.End : EbmlTagPosition.Content,
parent: this,
});
for await (const item of tag.decodeContent(options)) {
yield item;
}
tag.endOffset = controller.getOffset();
let shouldCollectChild: boolean;
if (typeof collectChild === 'function') {
shouldCollectChild = !!collectChild(tag, this);
} else {
shouldCollectChild = !!collectChild;
}
if (shouldCollectChild) {
this._children.push(tag);
}
yield tag;
}
}
}

View File

@ -1,55 +1,55 @@
import { readVint } from '../tools';
import { type CreateEbmlBlockTagOptions, EbmlBlockTag } from './tag-block';
import type { EbmlSimpleBlockTagIdType } from './enums';
import type { DecodeContentOptions } from './tag-trait';
export interface CreateEbmlSimpleBlockTagOptions
extends Omit<CreateEbmlBlockTagOptions, 'id'> {
id?: EbmlSimpleBlockTagIdType;
}
export class EbmlSimpleBlockTag extends EbmlBlockTag {
discardable: boolean | undefined;
keyframe: boolean | undefined;
// biome-ignore lint/complexity/noUselessConstructor: <explanation>
constructor(options: CreateEbmlSimpleBlockTagOptions) {
super(options);
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
const flags = this.writeFlagsBuffer();
if (this.keyframe) {
flags[0] |= 0x80;
}
if (this.discardable) {
flags[0] |= 0x01;
}
yield this.writeTrackBuffer();
yield this.writeValueBuffer();
yield flags;
yield this.payload;
}
async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const offset = controller.getOffset();
const view = await controller.read(offset, this.contentLength, true);
for await (const item of super.decodeContentImpl(options)) {
yield item;
}
const trackVint = readVint(view)!;
const flags: number = view.getUint8(trackVint.length + 2);
this.keyframe = Boolean(flags & 0x80);
this.discardable = Boolean(flags & 0x01);
// seeked by block tag
// await controller.seek(offset + this.contentLength);
}
}
import { readVint } from '../tools';
import type { EbmlSimpleBlockTagIdType } from './enums';
import { type CreateEbmlBlockTagOptions, EbmlBlockTag } from './tag-block';
import type { DecodeContentOptions } from './tag-trait';
export interface CreateEbmlSimpleBlockTagOptions
extends Omit<CreateEbmlBlockTagOptions, 'id'> {
id?: EbmlSimpleBlockTagIdType;
}
export class EbmlSimpleBlockTag extends EbmlBlockTag {
discardable: boolean | undefined;
keyframe: boolean | undefined;
// biome-ignore lint/complexity/noUselessConstructor: <explanation>
constructor(options: CreateEbmlSimpleBlockTagOptions) {
super(options);
}
*encodeContent(): Generator<Uint8Array, void, unknown> {
const flags = this.writeFlagsBuffer();
if (this.keyframe) {
flags[0] |= 0x80;
}
if (this.discardable) {
flags[0] |= 0x01;
}
yield this.writeTrackBuffer();
yield this.writeValueBuffer();
yield flags;
yield this.payload;
}
async *decodeContentImpl(options: DecodeContentOptions) {
const controller = options.dataViewController;
const offset = controller.getOffset();
const view = await controller.read(offset, this.contentLength, true);
for await (const item of super.decodeContentImpl(options)) {
yield item;
}
const trackVint = readVint(view)!;
const flags: number = view.getUint8(trackVint.length + 2);
this.keyframe = Boolean(flags & 0x80);
this.discardable = Boolean(flags & 0x01);
// seeked by block tag
// await controller.seek(offset + this.contentLength);
}
}

View File

@ -1,213 +1,213 @@
import { EbmlTagPosition } from './enums';
import { EbmlTagIdEnum, type EbmlTagIdType } from './enums';
import type { EbmlElementType } from './enums';
import { hexStringToBuf, UNKNOWN_SIZE_VINT_BUF, writeVint } from '../tools';
import type { FileDataViewController } from '../adapters';
import { InconsistentOffsetOnDecodingContentError } from '../errors';
import type { EbmlMasterTag } from './tag-master';
export interface CreateEbmlTagOptions {
id: EbmlTagIdType;
type?: EbmlElementType;
position?: EbmlTagPosition;
headerLength: number;
contentLength: number;
startOffset: number;
endOffset?: number;
parent?: EbmlMasterTag;
}
export type DecodeContentCollectChildPredicate =
| boolean
| ((child: EbmlTagTrait, parent: EbmlMasterTag) => boolean);
export interface DecodeContentOptions {
collectChild?: DecodeContentCollectChildPredicate;
dataViewController: FileDataViewController;
}
export abstract class EbmlTagTrait {
/**
* The id of the EBML tag.
* In most documentation this number is in hexadecimal format
*/
id: EbmlTagIdType;
/**
* The data type of the EBML tag
*/
type?: EbmlElementType;
/**
* The position of this EBML tag.
* Currently, one of "Start", "Content", or "End".
* "Start" and "End" only for Master type
*/
position: EbmlTagPosition;
/**
* Size vint length + tag vint length
*/
headerLength: number;
/**
* Start offset relative to context (stream or file) start
*/
startOffset: number;
/**
* Parent node
*/
parent?: EbmlTagTrait;
/**
* Content length in ebml data
* Return Number.POSITIVE_INFINITY as "unknown"
*/
private _contentLength: number;
/**
* Caculated end offset when
*/
private _endOffset?: number;
constructor(options: CreateEbmlTagOptions) {
this.id = options.id;
this.type = options.type;
this.position = options.position ?? EbmlTagPosition.Content;
this.parent = options.parent;
this.startOffset = options.startOffset;
this.headerLength = options.headerLength;
this._contentLength = options.contentLength;
this._endOffset = options.endOffset;
}
public set contentLength(value: number) {
this._contentLength = value;
}
/**
* After caculated or known, manually set endOffset
*/
public set endOffset(offset: number) {
this._endOffset = offset;
}
/**
* End offset relative to context (stream or file) start
* Calcalate from self _contentLength and parent end offset
* Return Number.POSITIVE_INFINITY as "unknown"
*/
public get endOffset(): number {
if (this._endOffset) {
return this._endOffset;
}
if (this._contentLength === Number.POSITIVE_INFINITY) {
return this.parent?.endOffset ?? Number.POSITIVE_INFINITY;
}
return this.startOffset + this.headerLength + this._contentLength;
}
/**
* Header length + Content Length
* Calcalate from self _contentLength and parent end offset
* Return Number.POSITIVE_INFINITY as "unknown"
*/
public get totalLength(): number {
return this.endOffset - this.startOffset;
}
/**
* Content Length
* Calcalate from self _contentLength and parent end offset
* Return Number.POSITIVE_INFINITY as "unknown"
*/
public get contentLength(): number {
return this.totalLength - this.headerLength;
}
protected abstract encodeContent(): Generator<Uint8Array, void, unknown>;
/**
* Deep traversal and parse all descendants then yield as AsyncGenerator
* @param controller DataView controller, simulate async filesystem file
*/
protected abstract decodeContentImpl(
options: DecodeContentOptions
): AsyncGenerator<EbmlTagTrait, void, unknown>;
/**
* Wrap of abstract decode content impl function, add before and after lifecircle check
* @param controller DataView controller, simulate async filesystem file
* @returns Deep traversal async iterators of all descendants
*/
public async *decodeContent(
options: DecodeContentOptions
): AsyncGenerator<EbmlTagTrait, void, unknown> {
const controller = options.dataViewController;
if (this.contentLength === 0 || this.position === EbmlTagPosition.Start) {
return;
}
const startOffset = controller.getOffset();
for await (const tag of this.decodeContentImpl(options)) {
yield tag;
}
const endOffset = controller.getOffset();
if (
startOffset + this.contentLength !== endOffset &&
this.contentLength !== Number.POSITIVE_INFINITY
) {
throw new InconsistentOffsetOnDecodingContentError(this, endOffset);
}
}
private getTagDeclaration(): Uint8Array {
let tagHex = this.id.toString(16);
if (tagHex.length % 2 !== 0) {
tagHex = `0${tagHex}`;
}
return hexStringToBuf(tagHex);
}
public *encodeHeader(): Generator<Uint8Array, void, unknown> {
const tagEncoded = this.getTagDeclaration();
yield tagEncoded;
if (this._contentLength === Number.POSITIVE_INFINITY) {
const mayBeSizeLength = this.headerLength - tagEncoded.byteLength;
if (mayBeSizeLength > 0 && mayBeSizeLength <= 8) {
yield UNKNOWN_SIZE_VINT_BUF[mayBeSizeLength];
} else {
yield UNKNOWN_SIZE_VINT_BUF[2];
}
} else {
yield writeVint(this._contentLength);
}
}
public *encode(): Generator<Uint8Array, void, unknown> {
if (this._contentLength === Number.POSITIVE_INFINITY) {
yield* this.encodeHeader();
for (const part of this.encodeContent()) {
yield part;
}
} else {
let size = 0;
const parts: Uint8Array[] = [];
for (const part of this.encodeContent()) {
parts.push(part);
size += part.byteLength;
}
this._contentLength = size;
yield* this.encodeHeader();
for (const part of parts) {
yield part;
}
}
}
public toDebugRecord(): Record<string, any> {
return {
id: EbmlTagIdEnum[this.id as any] || this.id,
type: this.type,
position: EbmlTagPosition[this.position],
contentLength: this.contentLength,
headerLength: this.headerLength,
startOffset: this.startOffset,
endOffset: this.endOffset,
};
}
}
import type { FileDataViewController } from '../adapters';
import { InconsistentOffsetOnDecodingContentError } from '../errors';
import { UNKNOWN_SIZE_VINT_BUF, hexStringToBuf, writeVint } from '../tools';
import { EbmlTagPosition } from './enums';
import { EbmlTagIdEnum, type EbmlTagIdType } from './enums';
import type { EbmlElementType } from './enums';
import type { EbmlMasterTag } from './tag-master';
export interface CreateEbmlTagOptions {
id: EbmlTagIdType;
type?: EbmlElementType;
position?: EbmlTagPosition;
headerLength: number;
contentLength: number;
startOffset: number;
endOffset?: number;
parent?: EbmlMasterTag;
}
export type DecodeContentCollectChildPredicate =
| boolean
| ((child: EbmlTagTrait, parent: EbmlMasterTag) => boolean);
export interface DecodeContentOptions {
collectChild?: DecodeContentCollectChildPredicate;
dataViewController: FileDataViewController;
}
export abstract class EbmlTagTrait {
/**
* The id of the EBML tag.
* In most documentation this number is in hexadecimal format
*/
id: EbmlTagIdType;
/**
* The data type of the EBML tag
*/
type?: EbmlElementType;
/**
* The position of this EBML tag.
* Currently, one of "Start", "Content", or "End".
* "Start" and "End" only for Master type
*/
position: EbmlTagPosition;
/**
* Size vint length + tag vint length
*/
headerLength: number;
/**
* Start offset relative to context (stream or file) start
*/
startOffset: number;
/**
* Parent node
*/
parent?: EbmlTagTrait;
/**
* Content length in ebml data
* Return Number.POSITIVE_INFINITY as "unknown"
*/
private _contentLength: number;
/**
* Caculated end offset when
*/
private _endOffset?: number;
constructor(options: CreateEbmlTagOptions) {
this.id = options.id;
this.type = options.type;
this.position = options.position ?? EbmlTagPosition.Content;
this.parent = options.parent;
this.startOffset = options.startOffset;
this.headerLength = options.headerLength;
this._contentLength = options.contentLength;
this._endOffset = options.endOffset;
}
public set contentLength(value: number) {
this._contentLength = value;
}
/**
* After caculated or known, manually set endOffset
*/
public set endOffset(offset: number) {
this._endOffset = offset;
}
/**
* End offset relative to context (stream or file) start
* Calcalate from self _contentLength and parent end offset
* Return Number.POSITIVE_INFINITY as "unknown"
*/
public get endOffset(): number {
if (this._endOffset) {
return this._endOffset;
}
if (this._contentLength === Number.POSITIVE_INFINITY) {
return this.parent?.endOffset ?? Number.POSITIVE_INFINITY;
}
return this.startOffset + this.headerLength + this._contentLength;
}
/**
* Header length + Content Length
* Calcalate from self _contentLength and parent end offset
* Return Number.POSITIVE_INFINITY as "unknown"
*/
public get totalLength(): number {
return this.endOffset - this.startOffset;
}
/**
* Content Length
* Calcalate from self _contentLength and parent end offset
* Return Number.POSITIVE_INFINITY as "unknown"
*/
public get contentLength(): number {
return this.totalLength - this.headerLength;
}
protected abstract encodeContent(): Generator<Uint8Array, void, unknown>;
/**
* Deep traversal and parse all descendants then yield as AsyncGenerator
* @param controller DataView controller, simulate async filesystem file
*/
protected abstract decodeContentImpl(
options: DecodeContentOptions
): AsyncGenerator<EbmlTagTrait, void, unknown>;
/**
* Wrap of abstract decode content impl function, add before and after lifecircle check
* @param controller DataView controller, simulate async filesystem file
* @returns Deep traversal async iterators of all descendants
*/
public async *decodeContent(
options: DecodeContentOptions
): AsyncGenerator<EbmlTagTrait, void, unknown> {
const controller = options.dataViewController;
if (this.contentLength === 0 || this.position === EbmlTagPosition.Start) {
return;
}
const startOffset = controller.getOffset();
for await (const tag of this.decodeContentImpl(options)) {
yield tag;
}
const endOffset = controller.getOffset();
if (
startOffset + this.contentLength !== endOffset &&
this.contentLength !== Number.POSITIVE_INFINITY
) {
throw new InconsistentOffsetOnDecodingContentError(this, endOffset);
}
}
private getTagDeclaration(): Uint8Array {
let tagHex = this.id.toString(16);
if (tagHex.length % 2 !== 0) {
tagHex = `0${tagHex}`;
}
return hexStringToBuf(tagHex);
}
public *encodeHeader(): Generator<Uint8Array, void, unknown> {
const tagEncoded = this.getTagDeclaration();
yield tagEncoded;
if (this._contentLength === Number.POSITIVE_INFINITY) {
const mayBeSizeLength = this.headerLength - tagEncoded.byteLength;
if (mayBeSizeLength > 0 && mayBeSizeLength <= 8) {
yield UNKNOWN_SIZE_VINT_BUF[mayBeSizeLength];
} else {
yield UNKNOWN_SIZE_VINT_BUF[2];
}
} else {
yield writeVint(this._contentLength);
}
}
public *encode(): Generator<Uint8Array, void, unknown> {
if (this._contentLength === Number.POSITIVE_INFINITY) {
yield* this.encodeHeader();
for (const part of this.encodeContent()) {
yield part;
}
} else {
let size = 0;
const parts: Uint8Array[] = [];
for (const part of this.encodeContent()) {
parts.push(part);
size += part.byteLength;
}
this._contentLength = size;
yield* this.encodeHeader();
for (const part of parts) {
yield part;
}
}
}
public toDebugRecord(): Record<string, any> {
return {
id: EbmlTagIdEnum[this.id as any] || this.id,
type: this.type,
position: EbmlTagPosition[this.position],
contentLength: this.contentLength,
headerLength: this.headerLength,
startOffset: this.startOffset,
endOffset: this.endOffset,
};
}
}

View File

@ -23,7 +23,8 @@ export type EbmlTagExcludeField =
| 'position'
| 'parent'
| 'type'
| 'data';
| 'data'
| 'children';
export type EbmlUintTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
id: EbmlUintDataTagIdType;
@ -31,6 +32,7 @@ export type EbmlUintTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type: EbmlElementType.UnsignedInt;
data: number | bigint;
children?: [];
};
export type EbmlIntTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
@ -39,6 +41,7 @@ export type EbmlIntTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type: EbmlElementType.Integer;
data: number | bigint;
children?: [];
};
export type EbmlUtf8TagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
@ -47,6 +50,7 @@ export type EbmlUtf8TagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type: EbmlElementType.UTF8;
data: string;
children?: [];
};
export type EbmlAsciiTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
@ -55,6 +59,7 @@ export type EbmlAsciiTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type: EbmlElementType.Ascii;
data: string;
children?: [];
};
export type EbmlDateTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
@ -63,6 +68,7 @@ export type EbmlDateTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type: EbmlElementType.Date;
data: Uint8Array;
children?: [];
};
export type EbmlFloatTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
@ -71,6 +77,7 @@ export type EbmlFloatTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type: EbmlElementType.Float;
data: number;
children?: [];
};
export type EbmlBinaryTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
@ -79,6 +86,7 @@ export type EbmlBinaryTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type: EbmlElementType.Binary;
data: Uint8Array;
children?: [];
};
export type EbmlUnknownTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
@ -87,6 +95,7 @@ export type EbmlUnknownTagType = Omit<EbmlDataTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type?: undefined;
data: Uint8Array;
children?: [];
};
export type EbmlDataTagType =
@ -104,6 +113,7 @@ export type EbmlBlockTagType = Omit<EbmlBlockTag, EbmlTagExcludeField> & {
parent?: EbmlMasterTag;
type?: undefined;
data?: undefined;
children?: [];
};
export type EbmlSimpleBlockTagType = Omit<
@ -115,6 +125,7 @@ export type EbmlSimpleBlockTagType = Omit<
parent?: EbmlMasterTag;
type?: undefined;
data?: undefined;
children?: [];
};
export type EbmlMasterTagType = Omit<EbmlMasterTag, EbmlTagExcludeField> & {

View File

@ -1,13 +1,13 @@
import {
VintOutOfRangeError,
VintLengthOutOfRangeError,
ElementIdVintDataAllOnesError,
ElementIdVintDataAllZerosError,
ElementIdVintDataNotShortestError,
UnsupportLengthForElementTypeError,
OutOfRangeForElementTypeError,
SizeUnitOutOfSafeIntegerRangeError,
UnreachableOrLogicError,
UnsupportLengthForElementTypeError,
VintLengthOutOfRangeError,
VintOutOfRangeError,
} from './errors';
import {
EbmlElementType,

View File

@ -1,11 +1,11 @@
import { assert, describe, it } from 'vitest';
import {
EbmlTagPosition,
EbmlElementType,
EbmlStreamDecoder as Decoder,
EbmlDataTag,
EbmlElementType,
EbmlTagPosition,
type EbmlTagType,
} from 'konoebml';
import { assert, describe, it } from 'vitest';
const bufFrom = (data: Uint8Array | readonly number[]): ArrayBuffer =>
new Uint8Array(data).buffer;

View File

@ -1,11 +1,11 @@
import { assert, expect, describe, it } from 'vitest';
import {
EbmlStreamEncoder,
EbmlTagIdEnum,
EbmlTagPosition,
type EbmlTagTrait,
EbmlTagIdEnum,
createEbmlTagForManuallyBuild,
EbmlStreamEncoder,
} from 'konoebml';
import { assert, describe, expect, it } from 'vitest';
const invalidTag: EbmlTagTrait = <EbmlTagTrait>(<any>{
id: undefined,

View File

@ -1,14 +1,14 @@
import { assert, describe, it, expect } from 'vitest';
import {
type EbmlBlockTag,
EbmlStreamDecoder,
EbmlStreamEncoder,
type EbmlTagTrait,
EbmlTagIdEnum,
type EbmlBlockTag,
createEbmlTagForManuallyBuild,
type EbmlTagTrait,
type EbmlTagType,
createEbmlTagForManuallyBuild,
} from 'konoebml';
import { concatArrayBuffers } from 'konoebml/tools';
import { assert, describe, expect, it } from 'vitest';
describe('EBML Pipeline', () => {
async function assertPipelineOutputEquals(

View File

@ -1,4 +1,3 @@
import { assert, describe, it } from 'vitest';
import {
readAscii,
readElementIdVint,
@ -9,6 +8,7 @@ import {
readVint,
writeVint,
} from 'konoebml/tools';
import { assert, describe, it } from 'vitest';
function bufFrom(data: Uint8Array | readonly number[]): Uint8Array {
return new Uint8Array(data);

View File

@ -1,14 +1,14 @@
import fs from 'node:fs';
import { assert, describe, it } from 'vitest';
import {
EbmlStreamDecoder,
EbmlTagIdEnum,
EbmlSimpleBlockTag as SimpleBlock,
EbmlDataTag,
type EbmlTagType,
} from 'konoebml';
import { Readable } from 'node:stream';
import { WritableStream } from 'node:stream/web';
import {
EbmlDataTag,
EbmlStreamDecoder,
EbmlTagIdEnum,
type EbmlTagType,
EbmlSimpleBlockTag as SimpleBlock,
} from 'konoebml';
import { assert, describe, it } from 'vitest';
process.setMaxListeners(Number.POSITIVE_INFINITY);

View File

@ -1,19 +1,15 @@
{
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"useDefineForClassFields": true,
"resolveJsonModule": true,
"moduleResolution": "bundler",
"target": "ES2021",
"module": "ESNext",
"lib": [
"ES2021",
"DOM",
"DOM.Iterable"
]
}
}
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"useDefineForClassFields": true,
"resolveJsonModule": true,
"moduleResolution": "bundler",
"target": "ES2021",
"module": "ESNext",
"lib": ["ES2021", "DOM", "DOM.Iterable"]
}
}

View File

@ -1,28 +1,20 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": true,
"rootDir": ".",
"types": [
"node"
],
"noEmit": true,
"paths": {
"konoebml": [
"./src/index.ts"
],
"konoebml/*": [
"./src/*"
]
}
},
"files": [],
"include": [
"examples/*"
],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": true,
"rootDir": ".",
"types": ["node"],
"noEmit": true,
"paths": {
"konoebml": ["./src/index.ts"],
"konoebml/*": ["./src/*"]
}
},
"files": [],
"include": ["examples/*"],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}

View File

@ -2,9 +2,7 @@
"extends": "./tsconfig.base.json",
"files": [],
"include": [],
"exclude": [
"node_modules"
],
"exclude": ["node_modules"],
"references": [
{
"path": "./tsconfig.lib.json"
@ -16,4 +14,4 @@
"path": "./tsconfig.example.json"
}
]
}
}

View File

@ -1,17 +1,15 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": true,
"rootDir": "./src",
"baseUrl": ".",
"declarationDir": "./dist",
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true
},
"include": [
"src"
],
"exclude": []
}
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": true,
"rootDir": "./src",
"baseUrl": ".",
"declarationDir": "./dist",
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true
},
"include": ["src"],
"exclude": []
}

View File

@ -3,27 +3,18 @@
"compilerOptions": {
"composite": true,
"rootDir": ".",
"types": [
"vitest/globals",
"node"
],
"types": ["vitest/globals", "node"],
"noEmit": true,
"paths": {
"konoebml": [
"./src/index.ts"
],
"konoebml/*": [
"./src/*"
]
"konoebml": ["./src/index.ts"],
"konoebml/*": ["./src/*"]
}
},
"files": [],
"include": [
"tests/*"
],
"include": ["tests/*"],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}
}