thunderous 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +99 -38
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +99 -38
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
@@ -358,8 +358,6 @@ if (typeof window !== "undefined") {
|
|
358
358
|
installScopedCreationMethod(ShadowRoot, "createElement", document);
|
359
359
|
installScopedCreationMethod(ShadowRoot, "importNode", document);
|
360
360
|
installScopedCreationMethod(Element, "insertAdjacentHTML");
|
361
|
-
installScopedCreationMethod(Node, "appendChild");
|
362
|
-
installScopedCreationMethod(Element, "append");
|
363
361
|
const installScopedCreationSetter = (ctor, name) => {
|
364
362
|
const descriptor = Object.getOwnPropertyDescriptor(ctor.prototype, name);
|
365
363
|
Object.defineProperty(ctor.prototype, name, {
|
@@ -701,20 +699,19 @@ var clientOnlyCallback = (fn) => {
|
|
701
699
|
};
|
702
700
|
|
703
701
|
// src/render.ts
|
702
|
+
var renderState = {
|
703
|
+
currentShadowRoot: null
|
704
|
+
};
|
704
705
|
var clearHTML = (element) => {
|
705
706
|
while (element.childNodes.length > 0) {
|
706
707
|
element.childNodes[0].remove();
|
707
708
|
}
|
708
709
|
};
|
709
710
|
var parseFragment = (htmlStr) => {
|
710
|
-
const
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
var setInnerHTML = (element, html2) => {
|
715
|
-
clearHTML(element);
|
716
|
-
const fragment = typeof html2 === "string" ? parseFragment(html2) : html2;
|
717
|
-
element.append(fragment);
|
711
|
+
const template = document.createElement("template");
|
712
|
+
template.innerHTML = htmlStr;
|
713
|
+
const fragment = renderState.currentShadowRoot === null ? template.content : renderState.currentShadowRoot.importNode(template.content, true);
|
714
|
+
return fragment;
|
718
715
|
};
|
719
716
|
var logValueError = (value) => {
|
720
717
|
console.error(
|
@@ -722,21 +719,82 @@ var logValueError = (value) => {
|
|
722
719
|
value
|
723
720
|
);
|
724
721
|
};
|
722
|
+
var arrayToDocumentFragment = (array, parent) => {
|
723
|
+
const documentFragment = new DocumentFragment();
|
724
|
+
let count = 0;
|
725
|
+
const keys = /* @__PURE__ */ new Set();
|
726
|
+
for (const item of array) {
|
727
|
+
const node = getNewNode(item, parent).cloneNode(true);
|
728
|
+
if (node instanceof DocumentFragment) {
|
729
|
+
const child = node.firstElementChild;
|
730
|
+
if (node.children.length > 1) {
|
731
|
+
console.error(
|
732
|
+
"When rendering arrays, fragments must contain only one top-level element at a time. Error occured in:",
|
733
|
+
parent
|
734
|
+
);
|
735
|
+
}
|
736
|
+
if (child === null) continue;
|
737
|
+
let key = child.getAttribute("key");
|
738
|
+
if (key === null) {
|
739
|
+
console.warn(
|
740
|
+
"When rendering arrays, a `key` attribute should be provided on each child element. An index was automatically applied, but this could result in unexpected behavior:",
|
741
|
+
child
|
742
|
+
);
|
743
|
+
key = String(count);
|
744
|
+
child.setAttribute("key", key);
|
745
|
+
}
|
746
|
+
if (keys.has(key)) {
|
747
|
+
console.warn(
|
748
|
+
`When rendering arrays, each child should have a unique \`key\` attribute. Duplicate key "${key}" found on:`,
|
749
|
+
child
|
750
|
+
);
|
751
|
+
}
|
752
|
+
keys.add(key);
|
753
|
+
count++;
|
754
|
+
}
|
755
|
+
documentFragment.append(node);
|
756
|
+
}
|
757
|
+
return documentFragment;
|
758
|
+
};
|
759
|
+
var getNewNode = (value, parent) => {
|
760
|
+
if (typeof value === "string") return new Text(value);
|
761
|
+
if (Array.isArray(value)) return arrayToDocumentFragment(value, parent);
|
762
|
+
if (value instanceof DocumentFragment) return value;
|
763
|
+
return new Text("");
|
764
|
+
};
|
725
765
|
var html = (strings, ...values) => {
|
726
766
|
let innerHTML = "";
|
727
767
|
const signalMap = /* @__PURE__ */ new Map();
|
728
|
-
|
729
|
-
|
768
|
+
const processValue = (value) => {
|
769
|
+
if (!isServer && value instanceof DocumentFragment) {
|
770
|
+
const tempDiv = document.createElement("div");
|
771
|
+
tempDiv.append(value.cloneNode(true));
|
772
|
+
return tempDiv.innerHTML;
|
773
|
+
}
|
730
774
|
if (typeof value === "function") {
|
775
|
+
const getter = value;
|
731
776
|
const uniqueKey = crypto.randomUUID();
|
732
|
-
signalMap.set(uniqueKey,
|
733
|
-
|
777
|
+
signalMap.set(uniqueKey, getter);
|
778
|
+
let result = getter();
|
779
|
+
if (Array.isArray(result)) {
|
780
|
+
result = result.map((item) => processValue(item)).join("");
|
781
|
+
}
|
782
|
+
return isServer ? String(result) : `{{signal:${uniqueKey}}}`;
|
734
783
|
}
|
735
784
|
if (typeof value === "object" && value !== null) {
|
736
785
|
logValueError(value);
|
737
|
-
|
786
|
+
return "";
|
787
|
+
}
|
788
|
+
return String(value);
|
789
|
+
};
|
790
|
+
strings.forEach((string, i) => {
|
791
|
+
let value = values[i] ?? "";
|
792
|
+
if (Array.isArray(value)) {
|
793
|
+
value = value.map((item) => processValue(item)).join("");
|
794
|
+
} else {
|
795
|
+
value = processValue(value);
|
738
796
|
}
|
739
|
-
innerHTML += string + String(value);
|
797
|
+
innerHTML += string + String(value === null ? "" : value);
|
740
798
|
});
|
741
799
|
if (isServer) {
|
742
800
|
return innerHTML;
|
@@ -748,24 +806,40 @@ var html = (strings, ...values) => {
|
|
748
806
|
for (const child of element.childNodes) {
|
749
807
|
if (child instanceof Text && signalBindingRegex.test(child.data)) {
|
750
808
|
const textList = child.data.split(signalBindingRegex);
|
809
|
+
const sibling = child.nextSibling;
|
751
810
|
textList.forEach((text, i) => {
|
752
811
|
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
753
812
|
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
|
754
813
|
const newValue = signal !== void 0 ? signal() : text;
|
755
|
-
const newNode = (
|
756
|
-
if (typeof newValue === "string") return new Text(newValue);
|
757
|
-
if (newValue instanceof DocumentFragment) return newValue;
|
758
|
-
return new Text("");
|
759
|
-
})();
|
814
|
+
const newNode = getNewNode(newValue, element);
|
760
815
|
if (i === 0) {
|
761
816
|
child.replaceWith(newNode);
|
762
817
|
} else {
|
763
|
-
element.insertBefore(newNode,
|
818
|
+
element.insertBefore(newNode, sibling);
|
764
819
|
}
|
765
820
|
if (signal !== void 0 && newNode instanceof Text) {
|
766
821
|
createEffect(() => {
|
767
822
|
newNode.data = signal();
|
768
823
|
});
|
824
|
+
} else if (signal !== void 0 && newNode instanceof DocumentFragment) {
|
825
|
+
createEffect(() => {
|
826
|
+
const result = signal();
|
827
|
+
const nextNode = getNewNode(result, element);
|
828
|
+
if (nextNode instanceof Text) {
|
829
|
+
throw new TypeError(
|
830
|
+
"Signal mismatch: expected DocumentFragment or Array<DocumentFragment>, but got Text"
|
831
|
+
);
|
832
|
+
}
|
833
|
+
let lastSibling = element.lastChild;
|
834
|
+
for (const child2 of nextNode.children) {
|
835
|
+
const key = child2.getAttribute("key");
|
836
|
+
const matchingNode = element.querySelector(`[key="${key}"]`);
|
837
|
+
if (matchingNode === null) continue;
|
838
|
+
lastSibling = matchingNode.nextSibling;
|
839
|
+
child2.replaceWith(matchingNode);
|
840
|
+
}
|
841
|
+
element.insertBefore(nextNode, lastSibling);
|
842
|
+
});
|
769
843
|
}
|
770
844
|
});
|
771
845
|
}
|
@@ -947,6 +1021,7 @@ var customElement = (render, options) => {
|
|
947
1021
|
});
|
948
1022
|
#render() {
|
949
1023
|
const root = this.#shadowRoot ?? this;
|
1024
|
+
renderState.currentShadowRoot = this.#shadowRoot;
|
950
1025
|
const fragment = render({
|
951
1026
|
elementRef: this,
|
952
1027
|
root,
|
@@ -1043,25 +1118,11 @@ You must set an initial value before calling a property signal's getter.
|
|
1043
1118
|
}
|
1044
1119
|
});
|
1045
1120
|
fragment.host = this;
|
1046
|
-
const registry = shadowRootOptions.registry instanceof CustomElementRegistry ? shadowRootOptions.registry : shadowRootOptions.registry?.eject();
|
1047
|
-
const tempContainer = document.createElement("div");
|
1048
|
-
tempContainer.append(fragment.cloneNode(true));
|
1049
|
-
const fragmentContent = tempContainer.innerHTML;
|
1050
|
-
root.innerHTML = fragmentContent;
|
1051
|
-
if (registry?.__tagNames !== void 0) {
|
1052
|
-
for (const tagName of registry.__tagNames) {
|
1053
|
-
const upgradedElements = root.querySelectorAll(tagName);
|
1054
|
-
const nonUpgradedElements = fragment.querySelectorAll(tagName);
|
1055
|
-
upgradedElements.forEach((upgradedElement, index) => {
|
1056
|
-
const nonUpgradedElement = nonUpgradedElements[index];
|
1057
|
-
nonUpgradedElement.replaceWith(upgradedElement);
|
1058
|
-
});
|
1059
|
-
}
|
1060
|
-
}
|
1061
1121
|
for (const fn of this.#clientOnlyCallbackFns) {
|
1062
1122
|
fn();
|
1063
1123
|
}
|
1064
|
-
|
1124
|
+
clearHTML(root);
|
1125
|
+
root.append(fragment);
|
1065
1126
|
}
|
1066
1127
|
static get formAssociated() {
|
1067
1128
|
return formAssociated;
|
package/dist/index.d.cts
CHANGED
@@ -439,9 +439,6 @@ if (typeof window !== 'undefined') {
|
|
439
439
|
installScopedCreationMethod(ShadowRoot, 'createElement', document);
|
440
440
|
installScopedCreationMethod(ShadowRoot, 'importNode', document);
|
441
441
|
installScopedCreationMethod(Element, 'insertAdjacentHTML');
|
442
|
-
installScopedCreationMethod(Node, 'appendChild');
|
443
|
-
installScopedCreationMethod(Element, 'append');
|
444
|
-
|
445
442
|
|
446
443
|
// Install scoped innerHTML on Element & ShadowRoot
|
447
444
|
const installScopedCreationSetter = (ctor, name) => {
|
@@ -589,6 +586,10 @@ declare global {
|
|
589
586
|
interface CustomElementRegistry {
|
590
587
|
__tagNames: Set<string>;
|
591
588
|
}
|
589
|
+
interface ShadowRoot {
|
590
|
+
// missing from typescript but present in the spec
|
591
|
+
importNode: <T = Node>(node: T, deep: boolean) => T;
|
592
|
+
}
|
592
593
|
}
|
593
594
|
|
594
595
|
type TagName = `${string}-${string}`;
|
package/dist/index.d.ts
CHANGED
@@ -439,9 +439,6 @@ if (typeof window !== 'undefined') {
|
|
439
439
|
installScopedCreationMethod(ShadowRoot, 'createElement', document);
|
440
440
|
installScopedCreationMethod(ShadowRoot, 'importNode', document);
|
441
441
|
installScopedCreationMethod(Element, 'insertAdjacentHTML');
|
442
|
-
installScopedCreationMethod(Node, 'appendChild');
|
443
|
-
installScopedCreationMethod(Element, 'append');
|
444
|
-
|
445
442
|
|
446
443
|
// Install scoped innerHTML on Element & ShadowRoot
|
447
444
|
const installScopedCreationSetter = (ctor, name) => {
|
@@ -589,6 +586,10 @@ declare global {
|
|
589
586
|
interface CustomElementRegistry {
|
590
587
|
__tagNames: Set<string>;
|
591
588
|
}
|
589
|
+
interface ShadowRoot {
|
590
|
+
// missing from typescript but present in the spec
|
591
|
+
importNode: <T = Node>(node: T, deep: boolean) => T;
|
592
|
+
}
|
592
593
|
}
|
593
594
|
|
594
595
|
type TagName = `${string}-${string}`;
|
package/dist/index.js
CHANGED
@@ -323,8 +323,6 @@ if (typeof window !== "undefined") {
|
|
323
323
|
installScopedCreationMethod(ShadowRoot, "createElement", document);
|
324
324
|
installScopedCreationMethod(ShadowRoot, "importNode", document);
|
325
325
|
installScopedCreationMethod(Element, "insertAdjacentHTML");
|
326
|
-
installScopedCreationMethod(Node, "appendChild");
|
327
|
-
installScopedCreationMethod(Element, "append");
|
328
326
|
const installScopedCreationSetter = (ctor, name) => {
|
329
327
|
const descriptor = Object.getOwnPropertyDescriptor(ctor.prototype, name);
|
330
328
|
Object.defineProperty(ctor.prototype, name, {
|
@@ -666,20 +664,19 @@ var clientOnlyCallback = (fn) => {
|
|
666
664
|
};
|
667
665
|
|
668
666
|
// src/render.ts
|
667
|
+
var renderState = {
|
668
|
+
currentShadowRoot: null
|
669
|
+
};
|
669
670
|
var clearHTML = (element) => {
|
670
671
|
while (element.childNodes.length > 0) {
|
671
672
|
element.childNodes[0].remove();
|
672
673
|
}
|
673
674
|
};
|
674
675
|
var parseFragment = (htmlStr) => {
|
675
|
-
const
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
var setInnerHTML = (element, html2) => {
|
680
|
-
clearHTML(element);
|
681
|
-
const fragment = typeof html2 === "string" ? parseFragment(html2) : html2;
|
682
|
-
element.append(fragment);
|
676
|
+
const template = document.createElement("template");
|
677
|
+
template.innerHTML = htmlStr;
|
678
|
+
const fragment = renderState.currentShadowRoot === null ? template.content : renderState.currentShadowRoot.importNode(template.content, true);
|
679
|
+
return fragment;
|
683
680
|
};
|
684
681
|
var logValueError = (value) => {
|
685
682
|
console.error(
|
@@ -687,21 +684,82 @@ var logValueError = (value) => {
|
|
687
684
|
value
|
688
685
|
);
|
689
686
|
};
|
687
|
+
var arrayToDocumentFragment = (array, parent) => {
|
688
|
+
const documentFragment = new DocumentFragment();
|
689
|
+
let count = 0;
|
690
|
+
const keys = /* @__PURE__ */ new Set();
|
691
|
+
for (const item of array) {
|
692
|
+
const node = getNewNode(item, parent).cloneNode(true);
|
693
|
+
if (node instanceof DocumentFragment) {
|
694
|
+
const child = node.firstElementChild;
|
695
|
+
if (node.children.length > 1) {
|
696
|
+
console.error(
|
697
|
+
"When rendering arrays, fragments must contain only one top-level element at a time. Error occured in:",
|
698
|
+
parent
|
699
|
+
);
|
700
|
+
}
|
701
|
+
if (child === null) continue;
|
702
|
+
let key = child.getAttribute("key");
|
703
|
+
if (key === null) {
|
704
|
+
console.warn(
|
705
|
+
"When rendering arrays, a `key` attribute should be provided on each child element. An index was automatically applied, but this could result in unexpected behavior:",
|
706
|
+
child
|
707
|
+
);
|
708
|
+
key = String(count);
|
709
|
+
child.setAttribute("key", key);
|
710
|
+
}
|
711
|
+
if (keys.has(key)) {
|
712
|
+
console.warn(
|
713
|
+
`When rendering arrays, each child should have a unique \`key\` attribute. Duplicate key "${key}" found on:`,
|
714
|
+
child
|
715
|
+
);
|
716
|
+
}
|
717
|
+
keys.add(key);
|
718
|
+
count++;
|
719
|
+
}
|
720
|
+
documentFragment.append(node);
|
721
|
+
}
|
722
|
+
return documentFragment;
|
723
|
+
};
|
724
|
+
var getNewNode = (value, parent) => {
|
725
|
+
if (typeof value === "string") return new Text(value);
|
726
|
+
if (Array.isArray(value)) return arrayToDocumentFragment(value, parent);
|
727
|
+
if (value instanceof DocumentFragment) return value;
|
728
|
+
return new Text("");
|
729
|
+
};
|
690
730
|
var html = (strings, ...values) => {
|
691
731
|
let innerHTML = "";
|
692
732
|
const signalMap = /* @__PURE__ */ new Map();
|
693
|
-
|
694
|
-
|
733
|
+
const processValue = (value) => {
|
734
|
+
if (!isServer && value instanceof DocumentFragment) {
|
735
|
+
const tempDiv = document.createElement("div");
|
736
|
+
tempDiv.append(value.cloneNode(true));
|
737
|
+
return tempDiv.innerHTML;
|
738
|
+
}
|
695
739
|
if (typeof value === "function") {
|
740
|
+
const getter = value;
|
696
741
|
const uniqueKey = crypto.randomUUID();
|
697
|
-
signalMap.set(uniqueKey,
|
698
|
-
|
742
|
+
signalMap.set(uniqueKey, getter);
|
743
|
+
let result = getter();
|
744
|
+
if (Array.isArray(result)) {
|
745
|
+
result = result.map((item) => processValue(item)).join("");
|
746
|
+
}
|
747
|
+
return isServer ? String(result) : `{{signal:${uniqueKey}}}`;
|
699
748
|
}
|
700
749
|
if (typeof value === "object" && value !== null) {
|
701
750
|
logValueError(value);
|
702
|
-
|
751
|
+
return "";
|
752
|
+
}
|
753
|
+
return String(value);
|
754
|
+
};
|
755
|
+
strings.forEach((string, i) => {
|
756
|
+
let value = values[i] ?? "";
|
757
|
+
if (Array.isArray(value)) {
|
758
|
+
value = value.map((item) => processValue(item)).join("");
|
759
|
+
} else {
|
760
|
+
value = processValue(value);
|
703
761
|
}
|
704
|
-
innerHTML += string + String(value);
|
762
|
+
innerHTML += string + String(value === null ? "" : value);
|
705
763
|
});
|
706
764
|
if (isServer) {
|
707
765
|
return innerHTML;
|
@@ -713,24 +771,40 @@ var html = (strings, ...values) => {
|
|
713
771
|
for (const child of element.childNodes) {
|
714
772
|
if (child instanceof Text && signalBindingRegex.test(child.data)) {
|
715
773
|
const textList = child.data.split(signalBindingRegex);
|
774
|
+
const sibling = child.nextSibling;
|
716
775
|
textList.forEach((text, i) => {
|
717
776
|
const uniqueKey = text.replace(/\{\{signal:(.+)\}\}/, "$1");
|
718
777
|
const signal = uniqueKey !== text ? signalMap.get(uniqueKey) : void 0;
|
719
778
|
const newValue = signal !== void 0 ? signal() : text;
|
720
|
-
const newNode = (
|
721
|
-
if (typeof newValue === "string") return new Text(newValue);
|
722
|
-
if (newValue instanceof DocumentFragment) return newValue;
|
723
|
-
return new Text("");
|
724
|
-
})();
|
779
|
+
const newNode = getNewNode(newValue, element);
|
725
780
|
if (i === 0) {
|
726
781
|
child.replaceWith(newNode);
|
727
782
|
} else {
|
728
|
-
element.insertBefore(newNode,
|
783
|
+
element.insertBefore(newNode, sibling);
|
729
784
|
}
|
730
785
|
if (signal !== void 0 && newNode instanceof Text) {
|
731
786
|
createEffect(() => {
|
732
787
|
newNode.data = signal();
|
733
788
|
});
|
789
|
+
} else if (signal !== void 0 && newNode instanceof DocumentFragment) {
|
790
|
+
createEffect(() => {
|
791
|
+
const result = signal();
|
792
|
+
const nextNode = getNewNode(result, element);
|
793
|
+
if (nextNode instanceof Text) {
|
794
|
+
throw new TypeError(
|
795
|
+
"Signal mismatch: expected DocumentFragment or Array<DocumentFragment>, but got Text"
|
796
|
+
);
|
797
|
+
}
|
798
|
+
let lastSibling = element.lastChild;
|
799
|
+
for (const child2 of nextNode.children) {
|
800
|
+
const key = child2.getAttribute("key");
|
801
|
+
const matchingNode = element.querySelector(`[key="${key}"]`);
|
802
|
+
if (matchingNode === null) continue;
|
803
|
+
lastSibling = matchingNode.nextSibling;
|
804
|
+
child2.replaceWith(matchingNode);
|
805
|
+
}
|
806
|
+
element.insertBefore(nextNode, lastSibling);
|
807
|
+
});
|
734
808
|
}
|
735
809
|
});
|
736
810
|
}
|
@@ -912,6 +986,7 @@ var customElement = (render, options) => {
|
|
912
986
|
});
|
913
987
|
#render() {
|
914
988
|
const root = this.#shadowRoot ?? this;
|
989
|
+
renderState.currentShadowRoot = this.#shadowRoot;
|
915
990
|
const fragment = render({
|
916
991
|
elementRef: this,
|
917
992
|
root,
|
@@ -1008,25 +1083,11 @@ You must set an initial value before calling a property signal's getter.
|
|
1008
1083
|
}
|
1009
1084
|
});
|
1010
1085
|
fragment.host = this;
|
1011
|
-
const registry = shadowRootOptions.registry instanceof CustomElementRegistry ? shadowRootOptions.registry : shadowRootOptions.registry?.eject();
|
1012
|
-
const tempContainer = document.createElement("div");
|
1013
|
-
tempContainer.append(fragment.cloneNode(true));
|
1014
|
-
const fragmentContent = tempContainer.innerHTML;
|
1015
|
-
root.innerHTML = fragmentContent;
|
1016
|
-
if (registry?.__tagNames !== void 0) {
|
1017
|
-
for (const tagName of registry.__tagNames) {
|
1018
|
-
const upgradedElements = root.querySelectorAll(tagName);
|
1019
|
-
const nonUpgradedElements = fragment.querySelectorAll(tagName);
|
1020
|
-
upgradedElements.forEach((upgradedElement, index) => {
|
1021
|
-
const nonUpgradedElement = nonUpgradedElements[index];
|
1022
|
-
nonUpgradedElement.replaceWith(upgradedElement);
|
1023
|
-
});
|
1024
|
-
}
|
1025
|
-
}
|
1026
1086
|
for (const fn of this.#clientOnlyCallbackFns) {
|
1027
1087
|
fn();
|
1028
1088
|
}
|
1029
|
-
|
1089
|
+
clearHTML(root);
|
1090
|
+
root.append(fragment);
|
1030
1091
|
}
|
1031
1092
|
static get formAssociated() {
|
1032
1093
|
return formAssociated;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "thunderous",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.1.1",
|
4
4
|
"description": "",
|
5
5
|
"type": "module",
|
6
6
|
"main": "./dist/index.cjs",
|
@@ -31,6 +31,7 @@
|
|
31
31
|
"license": "MIT",
|
32
32
|
"scripts": {
|
33
33
|
"demo": "cd demo && npm start",
|
34
|
+
"demo:ssr": "cd demo && npm run ssr",
|
34
35
|
"www": "cd www && npm run dev",
|
35
36
|
"build": "tsup src/index.ts --format cjs,esm --dts --no-clean",
|
36
37
|
"test": "find src -name '*.test.ts' | xargs c8 node --import tsx --test",
|