Пакет веб-багов: карточка, лента, вики-разметка, состояние модулей (#124) #125
@ -211,3 +211,8 @@ vitest, для окна карточки дополнительно e2e. Сер
|
||||
- R-19: N-1 (пере-ревью финальной волны) — в режиме `anyAttachment` ветка `!имя!` принимает любую пару «!», поэтому в ленте
|
||||
«Срочно! Проверьте! Ок» теряет восклицательные знаки — отложено в follow-up (требовать расширение файла в имени);
|
||||
второй волны правок нет. Цена ошибки — искажённые «!» в тексте строки ленты, данные не страдают.
|
||||
- R-20 (design #6, 26.10.2026, решение владельца по R-19): N-1 исправлена до PR, а не отложена. В режиме `anyAttachment`
|
||||
`!имя!` без списка вложений считается вложением, только если имя — имя файла с расширением без пробелов по краям
|
||||
(`FILE_NAME` в `inline.ts`); `[^имя]` — явная ссылка на вложение, проверка к ней не применяется. Обоснование: ветка
|
||||
сама внесла искажение «!» в строке ленты, владелец не хочет таких ошибок. Цена ошибки — `!слово.слово!` в обычном
|
||||
тексте ленты («Ура!Сделано.ру!») прочитается как имя вложения без «!»; данные не страдают.
|
||||
|
||||
@ -26,6 +26,8 @@ const URL = /https?:\/\/[^\s\]|<>"]+/y;
|
||||
const URL_TAIL = /[.,;:!?)]+$/;
|
||||
const IMAGE = /!([^!|\n]+)(?:\|[^!\n]*)?!/y;
|
||||
const ATT_LINK = /^(?:([^|]*)\|)?\^(.+)$/;
|
||||
// имя файла с расширением, без пробелов по краям: только такое `!имя!` без списка вложений — вложение (N-1)
|
||||
const FILE_NAME = /^\S(?:.*\S)?\.[\p{L}\p{N}]{1,10}$/u;
|
||||
|
||||
// схема ссылки — только http, https, mailto (спека «Разметка Jira в карточке»); иначе ссылки нет
|
||||
function safeHref(raw: string): string | null {
|
||||
@ -33,10 +35,11 @@ function safeHref(raw: string): string | null {
|
||||
return /^(https?:\/\/|mailto:)\S/i.test(href) ? href : null;
|
||||
}
|
||||
|
||||
// вложение по имени: несколько с одним именем — первое в порядке хаба
|
||||
function findAttachment(opts: WikiOptions, name: string): string | null {
|
||||
// вложение по имени: несколько с одним именем — первое в порядке хаба; image — `!имя!`, без списка только имя файла,
|
||||
// иначе «Срочно! Проверьте!» в ленте теряет «!» (N-1)
|
||||
function findAttachment(opts: WikiOptions, name: string, image = false): string | null {
|
||||
const found = (opts.attachments ?? []).find((a) => a.filename === name)?.id;
|
||||
return found ?? (opts.anyAttachment ? "" : null);
|
||||
return found ?? (opts.anyAttachment && (!image || FILE_NAME.test(name)) ? "" : null);
|
||||
}
|
||||
|
||||
function keyPattern(projectKey: string | undefined): RegExp | null {
|
||||
@ -86,7 +89,7 @@ export function parseInline(line: string, opts: WikiOptions = {}, label = false)
|
||||
if (c === "!" && !label && (opts.attachments?.length || opts.anyAttachment)) {
|
||||
IMAGE.lastIndex = i;
|
||||
const m = IMAGE.exec(line);
|
||||
const id = m && !m[1].includes("://") ? findAttachment(opts, m[1]) : null;
|
||||
const id = m && !m[1].includes("://") ? findAttachment(opts, m[1], true) : null;
|
||||
if (m && id !== null) { out.push({ t: "attachment", id, children: [{ t: "text", text: m[1] }] }); i += m[0].length; continue; }
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,11 @@ describe("wikiPlain", () => {
|
||||
it("вложение, которого нет в списке, — именем (I-1)", () => {
|
||||
expect(wikiPlain("!скрин.png|width=50! [текст|^отчёт.pdf] [^а.txt]").trim()).toBe("скрин.png текст а.txt");
|
||||
});
|
||||
it("«!» в обычном тексте без списка вложений остаются (N-1)", () => {
|
||||
expect(wikiPlain("Срочно! Проверьте! Ок").trim()).toBe("Срочно! Проверьте! Ок");
|
||||
expect(wikiPlain("Готово! см. лог.txt!").trim()).toBe("Готово! см. лог.txt!");
|
||||
expect(wikiPlain("Ура!Сделано!").trim()).toBe("Ура!Сделано!");
|
||||
});
|
||||
it("незакрытая и неизвестная разметка — как есть, пустой текст — пусто (Review Focus 3)", () => {
|
||||
expect(wikiPlain("{color:red}важно *без конца").trim()).toBe("{color:red}важно *без конца");
|
||||
expect(wikiPlain("")).toBe("");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user