yoctomarkdown 0.0.2 → 0.0.4
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/.agents/commands/release.md +31 -0
- package/package.json +2 -2
- package/src/index.ts +16 -6
- package/tests/index.test.ts +116 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a new tagged npm release (patch/minor/major)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Create a new npm release for this repo. The bump type is: $1 (default to "patch" if not provided).
|
|
6
|
+
|
|
7
|
+
Steps to follow exactly:
|
|
8
|
+
|
|
9
|
+
1. Normalize bump type to one of `patch|minor|major`; if empty, use `patch`.
|
|
10
|
+
2. Verify git state before doing anything:
|
|
11
|
+
- current branch must be `main`
|
|
12
|
+
- working tree must be clean
|
|
13
|
+
- run `git fetch origin --tags` and ensure `HEAD` equals `origin/main`
|
|
14
|
+
If any check fails, stop and report.
|
|
15
|
+
3. Run the full repo check suit — stop and report failures.
|
|
16
|
+
4. Read `package.json` and capture both `name` and current `version`.
|
|
17
|
+
5. Compute the next semver version by bumping the selected part.
|
|
18
|
+
6. Guardrails before mutating files:
|
|
19
|
+
- ensure git tag `v<new-version>` does not exist locally or on origin
|
|
20
|
+
- ensure npm version does not already exist: `npm view <package-name>@<new-version> version`
|
|
21
|
+
If either exists, stop and report.
|
|
22
|
+
7. Update the `version` field in `package.json` to `<new-version>`.
|
|
23
|
+
8. Run `bun run build`.
|
|
24
|
+
9. Commit all staged and unstaged changes with message: `chore: release v<new-version>`.
|
|
25
|
+
10. Create annotated tag: `git tag -a v<new-version> -m "<small-changelog>"`.
|
|
26
|
+
11. Push explicitly to main and the exact tag:
|
|
27
|
+
- `git push origin main`
|
|
28
|
+
- `git push origin v<new-version>`
|
|
29
|
+
12. Post-push verification: run `npm view <package-name>@<new-version> version`.
|
|
30
|
+
- If it already exists, report that publish already happened and do **not** ask user to publish again.
|
|
31
|
+
- If it does not exist, run `npm publish`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yoctomarkdown",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"module": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"devDependencies": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"yoctocolors": "^2.1.2"
|
|
19
19
|
},
|
|
20
20
|
"bin": {
|
|
21
|
-
"yoctomarkdown": "
|
|
21
|
+
"yoctomarkdown": "src/cli.ts"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"typecheck": "tsc --noEmit",
|
package/src/index.ts
CHANGED
|
@@ -129,6 +129,14 @@ export function createHighlighter(options?: Options): Highlighter {
|
|
|
129
129
|
|
|
130
130
|
let hasPartial = false;
|
|
131
131
|
|
|
132
|
+
function redrawPartialPrefix(): string {
|
|
133
|
+
return hasPartial ? "\x1b8\x1b[J" : "";
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function renderPartial(line: string, isPartial: boolean): string {
|
|
137
|
+
return `\x1b7${parseLine(line, isPartial)}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
132
140
|
return {
|
|
133
141
|
write(chunk: string | Uint8Array): string {
|
|
134
142
|
const text =
|
|
@@ -138,17 +146,14 @@ export function createHighlighter(options?: Options): Highlighter {
|
|
|
138
146
|
const lines = buffer.split("\n");
|
|
139
147
|
buffer = lines.pop() ?? "";
|
|
140
148
|
|
|
141
|
-
let out =
|
|
142
|
-
if (hasPartial) {
|
|
143
|
-
out += "\x1b[2K\r";
|
|
144
|
-
}
|
|
149
|
+
let out = redrawPartialPrefix();
|
|
145
150
|
|
|
146
151
|
if (lines.length > 0) {
|
|
147
152
|
out += `${lines.map((line) => parseLine(line, false)).join("\n")}\n`;
|
|
148
153
|
}
|
|
149
154
|
|
|
150
155
|
if (buffer.length > 0) {
|
|
151
|
-
out +=
|
|
156
|
+
out += renderPartial(buffer, true);
|
|
152
157
|
hasPartial = true;
|
|
153
158
|
} else {
|
|
154
159
|
hasPartial = false;
|
|
@@ -160,7 +165,12 @@ export function createHighlighter(options?: Options): Highlighter {
|
|
|
160
165
|
if (buffer.length > 0) {
|
|
161
166
|
const out = parseLine(buffer, false);
|
|
162
167
|
buffer = "";
|
|
163
|
-
|
|
168
|
+
if (hasPartial) {
|
|
169
|
+
const redrawPrefix = redrawPartialPrefix();
|
|
170
|
+
hasPartial = false;
|
|
171
|
+
return redrawPrefix + out;
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
164
174
|
}
|
|
165
175
|
return "";
|
|
166
176
|
},
|
package/tests/index.test.ts
CHANGED
|
@@ -32,10 +32,107 @@ describe("Programmatic Usage: highlightSync", () => {
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
+
function renderTerminalOutput(
|
|
36
|
+
output: string,
|
|
37
|
+
columns = Number.POSITIVE_INFINITY,
|
|
38
|
+
) {
|
|
39
|
+
const screen: string[][] = [[]];
|
|
40
|
+
let row = 0;
|
|
41
|
+
let column = 0;
|
|
42
|
+
let savedCursor: { row: number; column: number } | null = null;
|
|
43
|
+
|
|
44
|
+
function ensureRow(targetRow: number) {
|
|
45
|
+
while (screen.length <= targetRow) {
|
|
46
|
+
screen.push([]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function writeChar(char: string) {
|
|
51
|
+
if (column >= columns) {
|
|
52
|
+
row += 1;
|
|
53
|
+
column = 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
ensureRow(row);
|
|
57
|
+
if (!screen[row]) {
|
|
58
|
+
screen[row] = [];
|
|
59
|
+
}
|
|
60
|
+
const currentLine = screen[row];
|
|
61
|
+
if (!currentLine) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
currentLine[column] = char;
|
|
65
|
+
column += 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (let i = 0; i < output.length; i += 1) {
|
|
69
|
+
const rest = output.slice(i);
|
|
70
|
+
|
|
71
|
+
if (rest.startsWith("\x1b7")) {
|
|
72
|
+
savedCursor = { row, column };
|
|
73
|
+
i += 1;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (rest.startsWith("\x1b8")) {
|
|
78
|
+
if (savedCursor) {
|
|
79
|
+
row = savedCursor.row;
|
|
80
|
+
column = savedCursor.column;
|
|
81
|
+
}
|
|
82
|
+
i += 1;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (rest.startsWith("\x1b[J")) {
|
|
87
|
+
ensureRow(row);
|
|
88
|
+
screen[row] = (screen[row] ?? []).slice(0, column);
|
|
89
|
+
for (let clearRow = row + 1; clearRow < screen.length; clearRow += 1) {
|
|
90
|
+
screen[clearRow] = [];
|
|
91
|
+
}
|
|
92
|
+
i += 2;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (rest.startsWith("\x1b[2K")) {
|
|
97
|
+
ensureRow(row);
|
|
98
|
+
screen[row] = [];
|
|
99
|
+
i += 3;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (rest.startsWith("\x1b[1A")) {
|
|
104
|
+
row = Math.max(0, row - 1);
|
|
105
|
+
i += 3;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const char = output[i];
|
|
110
|
+
if (char === "\n") {
|
|
111
|
+
row += 1;
|
|
112
|
+
column = 0;
|
|
113
|
+
ensureRow(row);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (char === "\r") {
|
|
118
|
+
column = 0;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (char !== undefined && char !== "\x1b") {
|
|
123
|
+
writeChar(char);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return screen
|
|
128
|
+
.map((line) => line.join("").replace(/\s+$/u, ""))
|
|
129
|
+
.join("\n")
|
|
130
|
+
.replace(/\n+$/u, "");
|
|
131
|
+
}
|
|
132
|
+
|
|
35
133
|
function expectStreamMatch(res: string, markdown: string) {
|
|
36
134
|
const expected = highlightSync(markdown, { theme: "none" });
|
|
37
|
-
|
|
38
|
-
expect(res.replace(/[^\n]*\x1b\[2K\r/g, "")).toBe(expected);
|
|
135
|
+
expect(renderTerminalOutput(res)).toBe(renderTerminalOutput(expected));
|
|
39
136
|
}
|
|
40
137
|
|
|
41
138
|
describe("Programmatic Usage: createHighlighter (Streaming)", () => {
|
|
@@ -81,4 +178,21 @@ describe("Programmatic Usage: createHighlighter (Streaming)", () => {
|
|
|
81
178
|
|
|
82
179
|
expectStreamMatch(res, markdown);
|
|
83
180
|
});
|
|
181
|
+
|
|
182
|
+
test("should redraw wrapped partial lines after an external prefix", () => {
|
|
183
|
+
const prefix = "◆ ";
|
|
184
|
+
const markdown =
|
|
185
|
+
"No `\\x1b[2K` or `\\r` sequences in the streamed text. The ANSI colour codes remain (intentional — those are static style codes from yoctocolors, not cursor-control sequences).\n";
|
|
186
|
+
const splitAt = 134;
|
|
187
|
+
|
|
188
|
+
const highlighter = createHighlighter({ theme: "none" });
|
|
189
|
+
let res = prefix;
|
|
190
|
+
res += highlighter.write(markdown.slice(0, splitAt));
|
|
191
|
+
res += highlighter.write(markdown.slice(splitAt));
|
|
192
|
+
res += highlighter.end();
|
|
193
|
+
|
|
194
|
+
expect(renderTerminalOutput(res, 120)).toBe(
|
|
195
|
+
renderTerminalOutput(`${prefix}${markdown}`, 120),
|
|
196
|
+
);
|
|
197
|
+
});
|
|
84
198
|
});
|