feat: add a new splice decorator mode

This commit is contained in:
dragonish 2026-01-09 19:27:54 +08:00
parent a1ab90397a
commit 138c7841c9
No known key found for this signature in database
GPG key ID: 6F42FA9E807A5177
13 changed files with 876 additions and 7 deletions

View file

@ -2,6 +2,8 @@ import type {
OrderedDecoratorOptions,
IndependentDecoratorOptions,
IndependentDecoratorSettings,
SpliceDecoratorOptions,
SpliceDecoratorSettings,
} from "./data";
import { getOrderedCustomIdents } from "./data";
import * as presets from "@jsamr/counter-style/presets";
@ -222,6 +224,89 @@ export class IndependentCounter extends Querier implements Counter {
}
}
export class SpliceCounter extends Querier implements Counter {
constructor(private decoratorOptions: SpliceDecoratorOptions) {
super(decoratorOptions?.allowZeroLevel, decoratorOptions?.maxRecLevel);
}
decorator(level: number): string {
let result = "";
if (level < 1 || level > this.maxRecLevel) {
return result;
}
const {
delimiter = ".",
trailingDelimiter = false,
customTrailingDelimiter = "",
leadingDelimiter = false,
customLeadingDelimiter = "",
h1 = {},
h2 = {},
h3 = {},
h4 = {},
h5 = {},
h6 = {},
ignoreTopLevel = 0,
} = this.decoratorOptions;
const levels = this.handler(level).slice(ignoreTopLevel);
const results = levels.map((l, i) => {
let r = "";
let used: Partial<SpliceDecoratorSettings>;
switch (i + ignoreTopLevel + 1) {
case 6:
used = h6;
break;
case 5:
used = h5;
break;
case 4:
used = h4;
break;
case 3:
used = h3;
break;
case 2:
used = h2;
break;
case 1:
default:
used = h1;
break;
}
const {
styleType = "decimal",
customIdents = "",
specifiedString = "#",
} = used;
switch (styleType) {
case "customIdent":
r = l > customIdents.length ? l.toString() : customIdents[l - 1];
break;
case "string":
r = specifiedString.trim() || "#";
break;
default:
r = presets[styleType].renderCounter(l);
break;
}
return r;
});
result = results.join(delimiter);
if (result.length > 0) {
result =
(leadingDelimiter ? customLeadingDelimiter || delimiter : "") +
result +
(trailingDelimiter ? customTrailingDelimiter || delimiter : "");
}
return result;
}
}
export class UnorderedCounter implements Counter {
constructor(private levelHeadings: HeadingTuple, private maxRecLevel = 6) {}

View file

@ -34,6 +34,12 @@ export interface IndependentDecoratorSettings {
specifiedString: string;
}
export interface SpliceDecoratorSettings {
styleType: OrderedCounterStyleType;
customIdents: string;
specifiedString: string;
}
export interface IndependentDecoratorOptions {
maxRecLevel?: number;
allowZeroLevel?: boolean;
@ -59,6 +65,40 @@ export interface IndependentSettings {
h6: IndependentDecoratorSettings;
}
export interface SpliceDecoratorOptions {
maxRecLevel?: number;
allowZeroLevel?: boolean;
ignoreTopLevel?: number;
delimiter?: string;
trailingDelimiter?: boolean;
customTrailingDelimiter?: string;
leadingDelimiter?: boolean;
customLeadingDelimiter?: string;
h1?: Partial<SpliceDecoratorSettings>;
h2?: Partial<SpliceDecoratorSettings>;
h3?: Partial<SpliceDecoratorSettings>;
h4?: Partial<SpliceDecoratorSettings>;
h5?: Partial<SpliceDecoratorSettings>;
h6?: Partial<SpliceDecoratorSettings>;
}
export interface SpliceSettings {
delimiter: string;
trailingDelimiter: boolean;
customTrailingDelimiter: string;
leadingDelimiter: boolean;
customLeadingDelimiter: string;
h1: SpliceDecoratorSettings;
h2: SpliceDecoratorSettings;
h3: SpliceDecoratorSettings;
h4: SpliceDecoratorSettings;
h5: SpliceDecoratorSettings;
h6: SpliceDecoratorSettings;
}
export interface HeadingDecoratorSettings {
enabledInEachNote?: boolean;
@ -83,6 +123,7 @@ export interface HeadingDecoratorSettings {
orderedSpecifiedString: string;
independentSettings?: IndependentSettings;
spliceSettings?: SpliceSettings;
unorderedLevelHeadings: string;
}
@ -176,6 +217,14 @@ function defaultIndependentDecoratorSettings(): IndependentDecoratorSettings {
};
}
function defaultSpliceDecoratorSettings(): SpliceDecoratorSettings {
return {
styleType: "decimal",
customIdents: defaultCustomidents,
specifiedString: "#",
};
}
/**
* Defaults independent settings
*
@ -193,6 +242,27 @@ export function defaultIndependentSettings(): IndependentSettings {
};
}
/**
* Defaults splice settings
*
* @returns splice settings
*/
export function defaultSpliceSettings(): SpliceSettings {
return {
delimiter: ".",
trailingDelimiter: false,
customTrailingDelimiter: "",
leadingDelimiter: false,
customLeadingDelimiter: "",
h1: defaultSpliceDecoratorSettings(),
h2: defaultSpliceDecoratorSettings(),
h3: defaultSpliceDecoratorSettings(),
h4: defaultSpliceDecoratorSettings(),
h5: defaultSpliceDecoratorSettings(),
h6: defaultSpliceDecoratorSettings(),
};
}
/**
* Default settings for heading decorator.
*
@ -219,6 +289,7 @@ export function defaultHeadingDecoratorSettings(): HeadingDecoratorSettings {
orderedIgnoreSingle: false,
orderedIgnoreMaximum: 6,
independentSettings: defaultIndependentSettings(),
spliceSettings: defaultSpliceSettings(),
unorderedLevelHeadings: defaultHeadingTuple.join(" "),
};
}

View file

@ -20,6 +20,7 @@ import {
UnorderedCounter,
OrderedCounter,
IndependentCounter,
SpliceCounter,
} from "../common/counter";
import { Heading } from "../common/heading";
@ -122,6 +123,7 @@ export class HeadingEditorViewPlugin implements PluginValue {
orderedAllowZeroLevel,
unorderedLevelHeadings,
independentSettings,
spliceSettings,
} = isLivePreviwMode
? pluginData.previewSettings
: pluginData.sourceSettings;
@ -175,6 +177,23 @@ export class HeadingEditorViewPlugin implements PluginValue {
h5: independentSettings?.h5,
h6: independentSettings?.h6,
});
} else if (decoratorMode === "splice") {
counter = new SpliceCounter({
maxRecLevel,
ignoreTopLevel,
allowZeroLevel: orderedAllowZeroLevel,
delimiter: spliceSettings?.delimiter,
trailingDelimiter: spliceSettings?.trailingDelimiter,
customTrailingDelimiter: spliceSettings?.customTrailingDelimiter,
leadingDelimiter: spliceSettings?.leadingDelimiter,
customLeadingDelimiter: spliceSettings?.customLeadingDelimiter,
h1: spliceSettings?.h1,
h2: spliceSettings?.h2,
h3: spliceSettings?.h3,
h4: spliceSettings?.h4,
h5: spliceSettings?.h5,
h6: spliceSettings?.h6,
});
} else {
counter = new OrderedCounter({
maxRecLevel,

View file

@ -10,6 +10,7 @@ import {
UnorderedCounter,
OrderedCounter,
IndependentCounter,
SpliceCounter,
} from "../common/counter";
/**
@ -46,6 +47,7 @@ export function fileExplorerHandler(
orderedAllowZeroLevel,
unorderedLevelHeadings,
independentSettings,
spliceSettings,
} = settings;
container.classList.add(className.fileExplorerContainer);
@ -87,6 +89,23 @@ export function fileExplorerHandler(
h5: independentSettings?.h5,
h6: independentSettings?.h6,
});
} else if (decoratorMode === "splice") {
counter = new SpliceCounter({
maxRecLevel,
ignoreTopLevel,
allowZeroLevel: orderedAllowZeroLevel,
delimiter: spliceSettings?.delimiter,
trailingDelimiter: spliceSettings?.trailingDelimiter,
customTrailingDelimiter: spliceSettings?.customTrailingDelimiter,
leadingDelimiter: spliceSettings?.leadingDelimiter,
customLeadingDelimiter: spliceSettings?.customLeadingDelimiter,
h1: spliceSettings?.h1,
h2: spliceSettings?.h2,
h3: spliceSettings?.h3,
h4: spliceSettings?.h4,
h5: spliceSettings?.h5,
h6: spliceSettings?.h6,
});
} else {
counter = new OrderedCounter({
maxRecLevel,

View file

@ -12,6 +12,7 @@ import {
UnorderedCounter,
OrderedCounter,
IndependentCounter,
SpliceCounter,
} from "../common/counter";
/**
@ -48,6 +49,7 @@ export function outlineHandler(
orderedAllowZeroLevel,
unorderedLevelHeadings,
independentSettings,
spliceSettings,
} = settings;
container.classList.add(className.outlineContainer);
@ -89,6 +91,23 @@ export function outlineHandler(
h5: independentSettings?.h5,
h6: independentSettings?.h6,
});
} else if (decoratorMode === "splice") {
counter = new SpliceCounter({
maxRecLevel,
ignoreTopLevel,
allowZeroLevel: orderedAllowZeroLevel,
delimiter: spliceSettings?.delimiter,
trailingDelimiter: spliceSettings?.trailingDelimiter,
customTrailingDelimiter: spliceSettings?.customTrailingDelimiter,
leadingDelimiter: spliceSettings?.leadingDelimiter,
customLeadingDelimiter: spliceSettings?.customLeadingDelimiter,
h1: spliceSettings?.h1,
h2: spliceSettings?.h2,
h3: spliceSettings?.h3,
h4: spliceSettings?.h4,
h5: spliceSettings?.h5,
h6: spliceSettings?.h6,
});
} else {
counter = new OrderedCounter({
maxRecLevel,

View file

@ -9,6 +9,7 @@ import {
UnorderedCounter,
OrderedCounter,
IndependentCounter,
SpliceCounter,
} from "../common/counter";
/**
@ -43,6 +44,7 @@ export function quietOutlineHandler(
orderedAllowZeroLevel,
unorderedLevelHeadings,
independentSettings,
spliceSettings,
} = settings;
container.classList.add(className.quietOutlineContainer);
@ -87,6 +89,23 @@ export function quietOutlineHandler(
h5: independentSettings?.h5,
h6: independentSettings?.h6,
});
} else if (decoratorMode === "splice") {
counter = new SpliceCounter({
maxRecLevel,
ignoreTopLevel,
allowZeroLevel: orderedAllowZeroLevel,
delimiter: spliceSettings?.delimiter,
trailingDelimiter: spliceSettings?.trailingDelimiter,
customTrailingDelimiter: spliceSettings?.customTrailingDelimiter,
leadingDelimiter: spliceSettings?.leadingDelimiter,
customLeadingDelimiter: spliceSettings?.customLeadingDelimiter,
h1: spliceSettings?.h1,
h2: spliceSettings?.h2,
h3: spliceSettings?.h3,
h4: spliceSettings?.h4,
h5: spliceSettings?.h5,
h6: spliceSettings?.h6,
});
} else {
counter = new OrderedCounter({
maxRecLevel,

View file

@ -12,6 +12,7 @@ import {
UnorderedCounter,
OrderedCounter,
IndependentCounter,
SpliceCounter,
} from "../common/counter";
/**
@ -47,6 +48,7 @@ export function readingOrderedHandler(
orderedBasedOnExisting,
orderedAllowZeroLevel,
independentSettings,
spliceSettings,
} = settings;
let ignoreTopLevel = 0;
@ -91,6 +93,23 @@ export function readingOrderedHandler(
h5: independentSettings?.h5,
h6: independentSettings?.h6,
});
} else if (decoratorMode === "splice") {
counter = new SpliceCounter({
maxRecLevel,
ignoreTopLevel,
allowZeroLevel: orderedAllowZeroLevel,
delimiter: spliceSettings?.delimiter,
trailingDelimiter: spliceSettings?.trailingDelimiter,
customTrailingDelimiter: spliceSettings?.customTrailingDelimiter,
leadingDelimiter: spliceSettings?.leadingDelimiter,
customLeadingDelimiter: spliceSettings?.customLeadingDelimiter,
h1: spliceSettings?.h1,
h2: spliceSettings?.h2,
h3: spliceSettings?.h3,
h4: spliceSettings?.h4,
h5: spliceSettings?.h5,
h6: spliceSettings?.h6,
});
} else {
counter = new OrderedCounter({
maxRecLevel,

View file

@ -4,9 +4,15 @@ import type {
OrderedCounterStyleType,
HeadingDecoratorSettings,
IndependentDecoratorSettings,
SpliceDecoratorSettings,
IndependentSettings,
SpliceSettings,
} from "../common/data";
import {
className,
defaultIndependentSettings,
defaultSpliceSettings,
} from "../common/data";
import { className, defaultIndependentSettings } from "../common/data";
import { getStyleTypeOptions } from "../common/options";
import { FolderSuggest } from "./suggest";
@ -435,7 +441,7 @@ export class HeadingSettingTab extends PluginSettingTab {
}
private isDecoratorModeValue(value: string): value is DecoratorMode {
return ["orderd", "independent", "unordered"].includes(value);
return ["orderd", "independent", "splice", "unordered"].includes(value);
}
private isPositionValue(value: string): value is PostionOptions {
@ -513,6 +519,7 @@ export class HeadingSettingTab extends PluginSettingTab {
const options: Record<DecoratorMode, string> = {
orderd: i18n.t("setting.ordered"),
independent: i18n.t("setting.independent"),
splice: i18n.t("setting.splice"),
unordered: i18n.t("setting.unordered"),
};
dropdown
@ -530,18 +537,28 @@ export class HeadingSettingTab extends PluginSettingTab {
orderedContainerEl.show();
logicContainerEl.show();
independentContainerEl.hide();
spliceContainerEl.hide();
unorderedContainerEl.hide();
break;
case "independent":
independentContainerEl.show();
logicContainerEl.show();
orderedContainerEl.hide();
spliceContainerEl.hide();
unorderedContainerEl.hide();
break;
case "splice":
spliceContainerEl.show();
logicContainerEl.show();
orderedContainerEl.hide();
independentContainerEl.hide();
unorderedContainerEl.hide();
break;
case "unordered":
unorderedContainerEl.show();
orderedContainerEl.hide();
independentContainerEl.hide();
spliceContainerEl.hide();
logicContainerEl.hide();
break;
}
@ -638,6 +655,18 @@ export class HeadingSettingTab extends PluginSettingTab {
independentContainerEl.hide();
}
const spliceContainerEl = containerEl.createDiv(className.settingContainer);
if (!settings[settingsType].spliceSettings) {
settings[settingsType].spliceSettings = defaultSpliceSettings();
}
this.spliceSettings(
spliceContainerEl,
settings[settingsType].spliceSettings
);
if (settings[settingsType].decoratorMode !== "splice") {
spliceContainerEl.hide();
}
const unorderedContainerEl = containerEl.createDiv(
className.settingContainer
);
@ -966,6 +995,121 @@ export class HeadingSettingTab extends PluginSettingTab {
);
}
private spliceSettings(containerEl: HTMLElement, settings: SpliceSettings) {
const {
plugin: { i18n },
} = this;
new Setting(containerEl).setName(i18n.t("setting.splice")).setHeading();
//* delimiter
new Setting(containerEl)
.setName(i18n.t("setting.orderedDelimiter"))
.setDesc(i18n.t("setting.orderedDelimiterDesc"))
.addText((text) =>
text.setValue(settings.delimiter).onChange((value) => {
settings.delimiter = value;
this.plugin.saveSettings();
})
);
//* trailingDelimiter
new Setting(containerEl)
.setName(i18n.t("setting.orderedTrailingDelimiter"))
.setDesc(i18n.t("setting.orderedTrailingDelimiterDesc"))
.addToggle((toggle) =>
toggle.setValue(settings.trailingDelimiter).onChange((value) => {
settings.trailingDelimiter = value;
value
? customTrailingDelimiterContainerEl.show()
: customTrailingDelimiterContainerEl.hide();
this.plugin.saveSettings();
})
);
const customTrailingDelimiterContainerEl = containerEl.createDiv(
className.settingItem
);
//* customTrailingDelimiter
new Setting(customTrailingDelimiterContainerEl)
.setName(i18n.t("setting.orderedCustomTrailingDelimiter"))
.setDesc(i18n.t("setting.orderedCustomTrailingDelimiterDesc"))
.addText((text) => {
text
.setValue(settings.customTrailingDelimiter || "")
.onChange((value) => {
settings.customTrailingDelimiter = value;
this.plugin.saveSettings();
});
});
if (!settings.trailingDelimiter) {
customTrailingDelimiterContainerEl.hide();
}
//* leadingDelimiter
new Setting(containerEl)
.setName(i18n.t("setting.orderedLeadingDelimiter"))
.setDesc(i18n.t("setting.orderedLeadingDelimiterDesc"))
.addToggle((toggle) =>
toggle
.setValue(settings.leadingDelimiter || false)
.onChange((value) => {
settings.leadingDelimiter = value;
value
? customLeadingDelimiterContainerEl.show()
: customLeadingDelimiterContainerEl.hide();
this.plugin.saveSettings();
})
);
const customLeadingDelimiterContainerEl = containerEl.createDiv(
className.settingItem
);
//* customLeadingDelimiter
new Setting(customLeadingDelimiterContainerEl)
.setName(i18n.t("setting.orderedCustomLeadingDelimiter"))
.setDesc(i18n.t("setting.orderedCustomLeadingDelimiterDesc"))
.addText((text) => {
text
.setValue(settings.customLeadingDelimiter || "")
.onChange((value) => {
settings.customLeadingDelimiter = value;
this.plugin.saveSettings();
});
});
if (!settings.leadingDelimiter) {
customLeadingDelimiterContainerEl.hide();
}
//* h1
new Setting(containerEl).setName(i18n.t("setting.h1")).setHeading();
this.spliceDecoratorSettings(containerEl, settings.h1);
//* h2
new Setting(containerEl).setName(i18n.t("setting.h2")).setHeading();
this.spliceDecoratorSettings(containerEl, settings.h2);
//* h3
new Setting(containerEl).setName(i18n.t("setting.h3")).setHeading();
this.spliceDecoratorSettings(containerEl, settings.h3);
//* h4
new Setting(containerEl).setName(i18n.t("setting.h4")).setHeading();
this.spliceDecoratorSettings(containerEl, settings.h4);
//* h5
new Setting(containerEl).setName(i18n.t("setting.h5")).setHeading();
this.spliceDecoratorSettings(containerEl, settings.h5);
//* h6
new Setting(containerEl).setName(i18n.t("setting.h6")).setHeading();
this.spliceDecoratorSettings(containerEl, settings.h6);
}
private manageFolderBlacklist(scrollToTop = false) {
const {
containerEl,
@ -1254,4 +1398,79 @@ export class HeadingSettingTab extends PluginSettingTab {
specifiedStringContainerEl.hide();
}
}
private spliceDecoratorSettings(
containerEl: HTMLElement,
settings: SpliceDecoratorSettings
) {
const {
plugin: { i18n },
} = this;
//* styleType
new Setting(containerEl)
.setName(i18n.t("setting.orderedStyleType"))
.setDesc(i18n.t("setting.orderedStyleTypeDesc"))
.addDropdown((dropdown) =>
dropdown
.addOptions(this.styleTypeOptions)
.setValue(settings.styleType)
.onChange((value: OrderedCounterStyleType) => {
settings.styleType = value;
switch (value) {
case "customIdent":
customIdentsContainerEl.show();
specifiedStringContainerEl.hide();
break;
case "string":
specifiedStringContainerEl.show();
customIdentsContainerEl.hide();
break;
default:
customIdentsContainerEl.hide();
specifiedStringContainerEl.hide();
break;
}
this.plugin.saveSettings();
})
);
const customIdentsContainerEl = containerEl.createDiv(
className.settingItem
);
//* customIdents
new Setting(customIdentsContainerEl)
.setName(i18n.t("setting.orderedCustomIdents"))
.setDesc(i18n.t("setting.orderedCustomIdentsDesc"))
.addText((text) =>
text.setValue(settings.customIdents).onChange((value) => {
settings.customIdents = value;
this.plugin.saveSettings();
})
);
if (settings.styleType !== "customIdent") {
customIdentsContainerEl.hide();
}
const specifiedStringContainerEl = containerEl.createDiv(
className.settingItem
);
//* specifiedString
new Setting(specifiedStringContainerEl)
.setName(i18n.t("setting.orderedSpecifiedString"))
.setDesc(i18n.t("setting.orderedSpecifiedStringDesc"))
.addText((text) =>
text.setValue(settings.specifiedString).onChange((value) => {
settings.specifiedString = value;
this.plugin.saveSettings();
})
);
if (settings.styleType !== "string") {
specifiedStringContainerEl.hide();
}
}
}

View file

@ -160,6 +160,7 @@
"h3": "H3",
"h4": "H4",
"h5": "H5",
"h6": "H6"
"h6": "H6",
"splice": "Splice"
}
}

View file

@ -160,6 +160,7 @@
"h3": "H3 級別",
"h4": "H4 級別",
"h5": "H5 級別",
"h6": "H6 級別"
"h6": "H6 級別",
"splice": "分層拼接"
}
}

View file

@ -160,6 +160,7 @@
"h3": "H3 级别",
"h4": "H4 级别",
"h5": "H5 级别",
"h6": "H6 级别"
"h6": "H6 级别",
"splice": "分层拼接"
}
}

View file

@ -1,11 +1,15 @@
import "mocha";
import { expect } from "chai";
import type { IndependentDecoratorSettings } from "../../common/data";
import type {
IndependentDecoratorSettings,
SpliceDecoratorSettings,
} from "../../common/data";
import {
Querier,
UnorderedCounter,
OrderedCounter,
IndependentCounter,
SpliceCounter,
} from "../../common/counter";
describe("common/counter", function () {
@ -1446,4 +1450,396 @@ describe("common/counter", function () {
expect(counter3.decorator(6)).to.equal("2.1.1.1.");
});
});
describe("SpliceCounter", function () {
const h1: Partial<SpliceDecoratorSettings> = {
styleType: "upperAlpha",
};
const h2: Partial<SpliceDecoratorSettings> = {
styleType: "lowerAlpha",
};
const h3: Partial<SpliceDecoratorSettings> = {
styleType: "upperRoman",
};
const h4: Partial<SpliceDecoratorSettings> = {
styleType: "lowerRoman",
};
const h5: Partial<SpliceDecoratorSettings> = {
styleType: "decimal",
};
const h6: Partial<SpliceDecoratorSettings> = {
styleType: "decimalLeadingZero",
};
it("SpliceCounter.decorator", function () {
const counter1 = new SpliceCounter({});
expect(counter1.decorator(-1)).to.be.empty;
expect(counter1.decorator(0)).to.be.empty;
expect(counter1.decorator(1)).to.equal("1");
expect(counter1.decorator(2)).to.equal("1.1");
expect(counter1.decorator(2)).to.equal("1.2");
expect(counter1.decorator(2)).to.equal("1.3");
expect(counter1.decorator(2)).to.equal("1.4");
expect(counter1.decorator(2)).to.equal("1.5");
expect(counter1.decorator(2)).to.equal("1.6");
expect(counter1.decorator(2)).to.equal("1.7");
expect(counter1.decorator(2)).to.equal("1.8");
expect(counter1.decorator(2)).to.equal("1.9");
expect(counter1.decorator(2)).to.equal("1.10");
expect(counter1.decorator(2)).to.equal("1.11");
expect(counter1.decorator(1)).to.equal("2");
expect(counter1.decorator(7)).to.be.empty;
const counter2 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
});
expect(counter2.decorator(-1)).to.be.empty;
expect(counter2.decorator(0)).to.be.empty;
expect(counter2.decorator(1)).to.equal("A");
expect(counter2.decorator(2)).to.equal("A.a");
expect(counter2.decorator(2)).to.equal("A.b");
expect(counter2.decorator(2)).to.equal("A.c");
expect(counter2.decorator(2)).to.equal("A.d");
expect(counter2.decorator(2)).to.equal("A.e");
expect(counter2.decorator(3)).to.equal("A.e.I");
expect(counter2.decorator(4)).to.equal("A.e.I.i");
expect(counter2.decorator(5)).to.equal("A.e.I.i.1");
expect(counter2.decorator(6)).to.equal("A.e.I.i.1.01");
expect(counter2.decorator(1)).to.equal("B");
expect(counter2.decorator(2)).to.equal("B.a");
expect(counter2.decorator(3)).to.equal("B.a.I");
expect(counter2.decorator(2)).to.equal("B.b");
});
it("SpliceCounter.decorator with custom delimiter", function () {
const counter = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
delimiter: ",",
});
expect(counter.decorator(-1)).to.be.empty;
expect(counter.decorator(0)).to.be.empty;
expect(counter.decorator(1)).to.equal("A");
expect(counter.decorator(2)).to.equal("A,a");
expect(counter.decorator(2)).to.equal("A,b");
expect(counter.decorator(2)).to.equal("A,c");
expect(counter.decorator(2)).to.equal("A,d");
expect(counter.decorator(2)).to.equal("A,e");
expect(counter.decorator(3)).to.equal("A,e,I");
expect(counter.decorator(4)).to.equal("A,e,I,i");
expect(counter.decorator(5)).to.equal("A,e,I,i,1");
expect(counter.decorator(6)).to.equal("A,e,I,i,1,01");
expect(counter.decorator(1)).to.equal("B");
expect(counter.decorator(2)).to.equal("B,a");
expect(counter.decorator(3)).to.equal("B,a,I");
expect(counter.decorator(2)).to.equal("B,b");
});
it("SpliceCounter.decorator with trailing delimiter", function () {
const counter1 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
delimiter: ".",
trailingDelimiter: true,
});
expect(counter1.decorator(-1)).to.be.empty;
expect(counter1.decorator(0)).to.be.empty;
expect(counter1.decorator(1)).to.equal("A.");
expect(counter1.decorator(2)).to.equal("A.a.");
expect(counter1.decorator(2)).to.equal("A.b.");
expect(counter1.decorator(2)).to.equal("A.c.");
expect(counter1.decorator(2)).to.equal("A.d.");
expect(counter1.decorator(2)).to.equal("A.e.");
expect(counter1.decorator(3)).to.equal("A.e.I.");
expect(counter1.decorator(4)).to.equal("A.e.I.i.");
expect(counter1.decorator(5)).to.equal("A.e.I.i.1.");
expect(counter1.decorator(6)).to.equal("A.e.I.i.1.01.");
expect(counter1.decorator(1)).to.equal("B.");
expect(counter1.decorator(2)).to.equal("B.a.");
expect(counter1.decorator(3)).to.equal("B.a.I.");
expect(counter1.decorator(2)).to.equal("B.b.");
const counter2 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
delimiter: ".",
trailingDelimiter: true,
customTrailingDelimiter: ",",
});
expect(counter2.decorator(-1)).to.be.empty;
expect(counter2.decorator(0)).to.be.empty;
expect(counter2.decorator(1)).to.equal("A,");
expect(counter2.decorator(2)).to.equal("A.a,");
expect(counter2.decorator(2)).to.equal("A.b,");
expect(counter2.decorator(2)).to.equal("A.c,");
expect(counter2.decorator(2)).to.equal("A.d,");
expect(counter2.decorator(2)).to.equal("A.e,");
expect(counter2.decorator(3)).to.equal("A.e.I,");
expect(counter2.decorator(4)).to.equal("A.e.I.i,");
expect(counter2.decorator(5)).to.equal("A.e.I.i.1,");
expect(counter2.decorator(6)).to.equal("A.e.I.i.1.01,");
expect(counter2.decorator(1)).to.equal("B,");
expect(counter2.decorator(2)).to.equal("B.a,");
expect(counter2.decorator(3)).to.equal("B.a.I,");
expect(counter2.decorator(2)).to.equal("B.b,");
});
it("SpliceCounter.decorator with leading delimiter", function () {
const counter1 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
delimiter: ".",
leadingDelimiter: true,
});
expect(counter1.decorator(-1)).to.be.empty;
expect(counter1.decorator(0)).to.be.empty;
expect(counter1.decorator(1)).to.equal(".A");
expect(counter1.decorator(2)).to.equal(".A.a");
expect(counter1.decorator(2)).to.equal(".A.b");
expect(counter1.decorator(2)).to.equal(".A.c");
expect(counter1.decorator(2)).to.equal(".A.d");
expect(counter1.decorator(2)).to.equal(".A.e");
expect(counter1.decorator(3)).to.equal(".A.e.I");
expect(counter1.decorator(4)).to.equal(".A.e.I.i");
expect(counter1.decorator(5)).to.equal(".A.e.I.i.1");
expect(counter1.decorator(6)).to.equal(".A.e.I.i.1.01");
expect(counter1.decorator(1)).to.equal(".B");
expect(counter1.decorator(2)).to.equal(".B.a");
expect(counter1.decorator(3)).to.equal(".B.a.I");
expect(counter1.decorator(2)).to.equal(".B.b");
const counter2 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
delimiter: ".",
leadingDelimiter: true,
customLeadingDelimiter: "> ",
});
expect(counter2.decorator(-1)).to.be.empty;
expect(counter2.decorator(0)).to.be.empty;
expect(counter2.decorator(1)).to.equal("> A");
expect(counter2.decorator(2)).to.equal("> A.a");
expect(counter2.decorator(2)).to.equal("> A.b");
expect(counter2.decorator(2)).to.equal("> A.c");
expect(counter2.decorator(2)).to.equal("> A.d");
expect(counter2.decorator(2)).to.equal("> A.e");
expect(counter2.decorator(3)).to.equal("> A.e.I");
expect(counter2.decorator(4)).to.equal("> A.e.I.i");
expect(counter2.decorator(5)).to.equal("> A.e.I.i.1");
expect(counter2.decorator(6)).to.equal("> A.e.I.i.1.01");
expect(counter2.decorator(1)).to.equal("> B");
expect(counter2.decorator(2)).to.equal("> B.a");
expect(counter2.decorator(3)).to.equal("> B.a.I");
expect(counter2.decorator(2)).to.equal("> B.b");
});
it("SpliceCounter.decorator with custom leading delimiter and trailing delimiter", function () {
const counter1 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
delimiter: ".",
trailingDelimiter: true,
leadingDelimiter: true,
});
expect(counter1.decorator(-1)).to.be.empty;
expect(counter1.decorator(0)).to.be.empty;
expect(counter1.decorator(1)).to.equal(".A.");
expect(counter1.decorator(2)).to.equal(".A.a.");
expect(counter1.decorator(2)).to.equal(".A.b.");
expect(counter1.decorator(2)).to.equal(".A.c.");
expect(counter1.decorator(2)).to.equal(".A.d.");
expect(counter1.decorator(2)).to.equal(".A.e.");
expect(counter1.decorator(3)).to.equal(".A.e.I.");
expect(counter1.decorator(4)).to.equal(".A.e.I.i.");
expect(counter1.decorator(5)).to.equal(".A.e.I.i.1.");
expect(counter1.decorator(6)).to.equal(".A.e.I.i.1.01.");
expect(counter1.decorator(1)).to.equal(".B.");
expect(counter1.decorator(2)).to.equal(".B.a.");
expect(counter1.decorator(3)).to.equal(".B.a.I.");
expect(counter1.decorator(2)).to.equal(".B.b.");
const counter2 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
delimiter: ".",
trailingDelimiter: true,
customTrailingDelimiter: ")",
leadingDelimiter: true,
customLeadingDelimiter: "(",
});
expect(counter2.decorator(-1)).to.be.empty;
expect(counter2.decorator(0)).to.be.empty;
expect(counter2.decorator(1)).to.equal("(A)");
expect(counter2.decorator(2)).to.equal("(A.a)");
expect(counter2.decorator(2)).to.equal("(A.b)");
expect(counter2.decorator(2)).to.equal("(A.c)");
expect(counter2.decorator(2)).to.equal("(A.d)");
expect(counter2.decorator(2)).to.equal("(A.e)");
expect(counter2.decorator(3)).to.equal("(A.e.I)");
expect(counter2.decorator(4)).to.equal("(A.e.I.i)");
expect(counter2.decorator(5)).to.equal("(A.e.I.i.1)");
expect(counter2.decorator(6)).to.equal("(A.e.I.i.1.01)");
expect(counter2.decorator(1)).to.equal("(B)");
expect(counter2.decorator(2)).to.equal("(B.a)");
expect(counter2.decorator(3)).to.equal("(B.a.I)");
expect(counter2.decorator(2)).to.equal("(B.b)");
});
it("SpliceCounter.decorator with ignoreTopLevel", function () {
const counter1 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
ignoreTopLevel: 1,
});
expect(counter1.decorator(1)).to.be.empty;
expect(counter1.decorator(2)).to.equal("a");
expect(counter1.decorator(3)).to.equal("a.I");
expect(counter1.decorator(4)).to.equal("a.I.i");
expect(counter1.decorator(5)).to.equal("a.I.i.1");
expect(counter1.decorator(6)).to.equal("a.I.i.1.01");
expect(counter1.decorator(7)).to.be.empty;
expect(counter1.decorator(2)).to.equal("b");
expect(counter1.decorator(3)).to.equal("b.I");
expect(counter1.decorator(4)).to.equal("b.I.i");
expect(counter1.decorator(5)).to.equal("b.I.i.1");
expect(counter1.decorator(6)).to.equal("b.I.i.1.01");
expect(counter1.decorator(7)).to.be.empty;
expect(counter1.decorator(2)).to.equal("c");
expect(counter1.decorator(6)).to.equal("c.I.i.1.01");
const counter2 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
ignoreTopLevel: 2,
});
expect(counter2.decorator(1)).to.be.empty;
expect(counter2.decorator(2)).to.be.empty;
expect(counter2.decorator(3)).to.equal("I");
expect(counter2.decorator(4)).to.equal("I.i");
expect(counter2.decorator(5)).to.equal("I.i.1");
expect(counter2.decorator(6)).to.equal("I.i.1.01");
expect(counter2.decorator(7)).to.be.empty;
expect(counter2.decorator(3)).to.equal("II");
expect(counter2.decorator(6)).to.equal("II.i.1.01");
});
it("SpliceCounter.decorator with allowZeroLevel", function () {
const counter = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
allowZeroLevel: true,
});
expect(counter.decorator(3)).to.equal("0.0.I");
expect(counter.decorator(4)).to.equal("0.0.I.i");
expect(counter.decorator(5)).to.equal("0.0.I.i.1");
expect(counter.decorator(6)).to.equal("0.0.I.i.1.01");
expect(counter.decorator(3)).to.equal("0.0.II");
expect(counter.decorator(4)).to.equal("0.0.II.i");
expect(counter.decorator(5)).to.equal("0.0.II.i.1");
expect(counter.decorator(6)).to.equal("0.0.II.i.1.01");
expect(counter.decorator(2)).to.equal("0.a");
expect(counter.decorator(5)).to.equal("0.a.0.0.1");
expect(counter.decorator(6)).to.equal("0.a.0.0.1.01");
});
it("SpliceCounter.decorator with maxRecLevel", function () {
const counter1 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
maxRecLevel: 4,
});
expect(counter1.decorator(1)).to.equal("A");
expect(counter1.decorator(2)).to.equal("A.a");
expect(counter1.decorator(3)).to.equal("A.a.I");
expect(counter1.decorator(4)).to.equal("A.a.I.i");
expect(counter1.decorator(5)).to.be.empty;
expect(counter1.decorator(6)).to.be.empty;
expect(counter1.decorator(7)).to.be.empty;
expect(counter1.decorator(2)).to.equal("A.b");
expect(counter1.decorator(3)).to.equal("A.b.I");
expect(counter1.decorator(4)).to.equal("A.b.I.i");
expect(counter1.decorator(5)).to.be.empty;
expect(counter1.decorator(6)).to.be.empty;
expect(counter1.decorator(2)).to.equal("A.c");
expect(counter1.decorator(6)).to.be.empty;
const counter2 = new SpliceCounter({
h1,
h2,
h3,
h4,
h5,
h6,
maxRecLevel: 4,
ignoreTopLevel: 2,
});
expect(counter2.decorator(1)).to.be.empty;
expect(counter2.decorator(2)).to.be.empty;
expect(counter2.decorator(3)).to.equal("I");
expect(counter2.decorator(4)).to.equal("I.i");
expect(counter2.decorator(5)).to.be.empty;
expect(counter2.decorator(6)).to.be.empty;
expect(counter2.decorator(7)).to.be.empty;
expect(counter2.decorator(3)).to.equal("II");
expect(counter2.decorator(4)).to.equal("II.i");
expect(counter2.decorator(6)).to.be.empty;
});
});
});

2
types.d.ts vendored
View file

@ -10,7 +10,7 @@ type _TupleOf<T, N extends number, R extends unknown[]> = R["length"] extends N
type LevelTuple = TupleOf<number, 6>;
type HeadingTuple = TupleOf<string, 6>;
type DecoratorMode = "orderd" | "independent" | "unordered";
type DecoratorMode = "orderd" | "independent" | "splice" | "unordered";
type OpacityOptions = 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100;
type PostionOptions = "before" | "before-inside" | "after" | "after-inside";
type RenderPolicy = "partial" | "full";