fix: fix master tag type
This commit is contained in:
parent
11fdb0f2fc
commit
9a5d025f40
115
biome.jsonc
115
biome.jsonc
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import fs from 'node:fs/promises';
|
||||
import {
|
||||
ReadableStream,
|
||||
WritableStream,
|
||||
type TransformStream,
|
||||
WritableStream,
|
||||
} from 'node:stream/web';
|
||||
import { EbmlStreamDecoder } from 'konoebml';
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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> & {
|
||||
|
@ -1,13 +1,13 @@
|
||||
import {
|
||||
VintOutOfRangeError,
|
||||
VintLengthOutOfRangeError,
|
||||
ElementIdVintDataAllOnesError,
|
||||
ElementIdVintDataAllZerosError,
|
||||
ElementIdVintDataNotShortestError,
|
||||
UnsupportLengthForElementTypeError,
|
||||
OutOfRangeForElementTypeError,
|
||||
SizeUnitOutOfSafeIntegerRangeError,
|
||||
UnreachableOrLogicError,
|
||||
UnsupportLengthForElementTypeError,
|
||||
VintLengthOutOfRangeError,
|
||||
VintOutOfRangeError,
|
||||
} from './errors';
|
||||
import {
|
||||
EbmlElementType,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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"]
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -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": []
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user