openzca 0.1.31 → 0.1.33
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/cli.js +123 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
Gender,
|
|
16
16
|
Reactions,
|
|
17
17
|
ReviewPendingMemberRequestStatus,
|
|
18
|
+
TextStyle,
|
|
18
19
|
ThreadType
|
|
19
20
|
} from "zca-js";
|
|
20
21
|
|
|
@@ -704,6 +705,115 @@ function output(value, asJson = false) {
|
|
|
704
705
|
function asThreadType(groupFlag) {
|
|
705
706
|
return groupFlag ? ThreadType.Group : ThreadType.User;
|
|
706
707
|
}
|
|
708
|
+
function parseTextStyles(input) {
|
|
709
|
+
const allStyles = [];
|
|
710
|
+
const lines = input.split("\n");
|
|
711
|
+
const lineStyles = [];
|
|
712
|
+
const processedLines = [];
|
|
713
|
+
for (let i = 0; i < lines.length; i++) {
|
|
714
|
+
const line = lines[i];
|
|
715
|
+
const headingMatch = line.match(/^(#{1,3})\s(.*)$/);
|
|
716
|
+
if (headingMatch) {
|
|
717
|
+
const level = headingMatch[1].length;
|
|
718
|
+
lineStyles.push({ lineIndex: i, style: TextStyle.Bold });
|
|
719
|
+
if (level === 1) lineStyles.push({ lineIndex: i, style: TextStyle.Big });
|
|
720
|
+
if (level === 3) lineStyles.push({ lineIndex: i, style: TextStyle.Small });
|
|
721
|
+
processedLines.push(headingMatch[2]);
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
const olMatch = line.match(/^(\d+)\.\s(.*)$/);
|
|
725
|
+
if (olMatch) {
|
|
726
|
+
lineStyles.push({ lineIndex: i, style: TextStyle.OrderedList });
|
|
727
|
+
processedLines.push(olMatch[2]);
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
const ulMatch = line.match(/^-\s(.*)$/);
|
|
731
|
+
if (ulMatch) {
|
|
732
|
+
lineStyles.push({ lineIndex: i, style: TextStyle.UnorderedList });
|
|
733
|
+
processedLines.push(ulMatch[1]);
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
const indentMatch = line.match(/^(>+)\s?(.*)$/);
|
|
737
|
+
if (indentMatch) {
|
|
738
|
+
lineStyles.push({ lineIndex: i, style: TextStyle.Indent, indentSize: indentMatch[1].length });
|
|
739
|
+
processedLines.push(indentMatch[2]);
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
processedLines.push(line);
|
|
743
|
+
}
|
|
744
|
+
const inlineInput = processedLines.join("\n");
|
|
745
|
+
const colorMap = {
|
|
746
|
+
red: TextStyle.Red,
|
|
747
|
+
orange: TextStyle.Orange,
|
|
748
|
+
yellow: TextStyle.Yellow,
|
|
749
|
+
green: TextStyle.Green,
|
|
750
|
+
small: TextStyle.Small,
|
|
751
|
+
big: TextStyle.Big
|
|
752
|
+
};
|
|
753
|
+
const tagNames = Object.keys(colorMap).join("|");
|
|
754
|
+
const markers = [
|
|
755
|
+
// Tags first so inner markdown markers are preserved for subsequent passes
|
|
756
|
+
{ pattern: new RegExp(`\\{(${tagNames})\\}(.+?)\\{/\\1\\}`, "g"), style: null },
|
|
757
|
+
{ pattern: /\*\*\*(.+?)\*\*\*/g, style: TextStyle.Bold, extraStyles: [TextStyle.Italic] },
|
|
758
|
+
{ pattern: /\*\*(.+?)\*\*/g, style: TextStyle.Bold },
|
|
759
|
+
{ pattern: /\*(.+?)\*/g, style: TextStyle.Italic },
|
|
760
|
+
{ pattern: /__(.+?)__/g, style: TextStyle.Underline },
|
|
761
|
+
{ pattern: /~~(.+?)~~/g, style: TextStyle.StrikeThrough }
|
|
762
|
+
];
|
|
763
|
+
let segments = [{ text: inlineInput, styles: [] }];
|
|
764
|
+
for (const marker of markers) {
|
|
765
|
+
const next = [];
|
|
766
|
+
for (const seg of segments) {
|
|
767
|
+
let lastIndex = 0;
|
|
768
|
+
const regex = new RegExp(marker.pattern.source, marker.pattern.flags);
|
|
769
|
+
let m;
|
|
770
|
+
while ((m = regex.exec(seg.text)) !== null) {
|
|
771
|
+
if (m.index > lastIndex) {
|
|
772
|
+
next.push({ text: seg.text.slice(lastIndex, m.index), styles: [...seg.styles] });
|
|
773
|
+
}
|
|
774
|
+
const isTagPattern = marker.style === null;
|
|
775
|
+
const innerText = isTagPattern ? m[2] : m[1];
|
|
776
|
+
const resolvedStyle = isTagPattern ? colorMap[m[1]] : marker.style;
|
|
777
|
+
const combined = [...seg.styles, resolvedStyle];
|
|
778
|
+
if (marker.extraStyles) {
|
|
779
|
+
combined.push(...marker.extraStyles);
|
|
780
|
+
}
|
|
781
|
+
next.push({ text: innerText, styles: combined });
|
|
782
|
+
lastIndex = regex.lastIndex;
|
|
783
|
+
}
|
|
784
|
+
if (lastIndex < seg.text.length) {
|
|
785
|
+
next.push({ text: seg.text.slice(lastIndex), styles: [...seg.styles] });
|
|
786
|
+
} else if (lastIndex === 0) {
|
|
787
|
+
next.push(seg);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
segments = next;
|
|
791
|
+
}
|
|
792
|
+
let plainText = "";
|
|
793
|
+
for (const seg of segments) {
|
|
794
|
+
const start = plainText.length;
|
|
795
|
+
plainText += seg.text;
|
|
796
|
+
for (const st of seg.styles) {
|
|
797
|
+
allStyles.push({ start, len: seg.text.length, st });
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
const finalLines = plainText.split("\n");
|
|
801
|
+
let offset = 0;
|
|
802
|
+
for (let i = 0; i < finalLines.length; i++) {
|
|
803
|
+
const lineLen = finalLines[i].length;
|
|
804
|
+
for (const ls of lineStyles) {
|
|
805
|
+
if (ls.lineIndex === i && lineLen > 0) {
|
|
806
|
+
if (ls.style === TextStyle.Indent) {
|
|
807
|
+
allStyles.push({ start: offset, len: lineLen, st: TextStyle.Indent, indentSize: ls.indentSize });
|
|
808
|
+
} else {
|
|
809
|
+
allStyles.push({ start: offset, len: lineLen, st: ls.style });
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
offset += lineLen + 1;
|
|
814
|
+
}
|
|
815
|
+
return { text: plainText, styles: allStyles };
|
|
816
|
+
}
|
|
707
817
|
function parseBooleanFromEnv(name, fallback) {
|
|
708
818
|
const raw = process.env[name]?.trim();
|
|
709
819
|
if (!raw) return fallback;
|
|
@@ -2887,11 +2997,21 @@ auth.command("cache-clear").description("Clear local cache").action(
|
|
|
2887
2997
|
})
|
|
2888
2998
|
);
|
|
2889
2999
|
var msg = program.command("msg").description("Messaging commands");
|
|
2890
|
-
msg.command("send <threadId> <message>").option("-g, --group", "Send to group").description("Send text message").action(
|
|
3000
|
+
msg.command("send <threadId> <message>").option("-g, --group", "Send to group").option("--raw", "Send raw text without parsing formatting markers").description("Send text message with formatting (**bold** *italic* __underline__ ~~strike~~ {red}color{/red} {big}size{/big} lists indents)").action(
|
|
2891
3001
|
wrapAction(async (threadId, message, opts, command) => {
|
|
2892
3002
|
const { api } = await requireApi(command);
|
|
2893
|
-
|
|
2894
|
-
|
|
3003
|
+
if (opts.raw) {
|
|
3004
|
+
const response = await api.sendMessage(message, threadId, asThreadType(opts.group));
|
|
3005
|
+
output(response, false);
|
|
3006
|
+
} else {
|
|
3007
|
+
const { text, styles } = parseTextStyles(message);
|
|
3008
|
+
const response = await api.sendMessage(
|
|
3009
|
+
{ msg: text, styles: styles.length > 0 ? styles : void 0 },
|
|
3010
|
+
threadId,
|
|
3011
|
+
asThreadType(opts.group)
|
|
3012
|
+
);
|
|
3013
|
+
output(response, false);
|
|
3014
|
+
}
|
|
2895
3015
|
})
|
|
2896
3016
|
);
|
|
2897
3017
|
msg.command("image <threadId> [file]").option("-u, --url <url>", "Image URL (repeatable)", collectValues, []).option("-m, --message <message>", "Caption").option("-g, --group", "Send to group").description("Send image(s) from file or URL").action(
|