@lamemind/loom-deck 0.73.0 → 0.73.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/task-edit.js +16 -21
- package/dist/tasks.js +46 -17
- package/package.json +1 -1
package/dist/task-edit.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// isolata in `writeTaskEdit`, così la grammatica delle sostituzioni è testabile
|
|
4
4
|
// senza toccare il filesystem.
|
|
5
5
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
6
|
-
import { TASK_ID_RE, findTaskFile,
|
|
6
|
+
import { TASK_ID_RE, findTaskFile, overviewRows } from './tasks.js';
|
|
7
7
|
// Il task file scrive la priorità per NOME (`- **Priority**: Med`), tasks.md la
|
|
8
8
|
// scrive come GLIFO (colonna Pri). Due rappresentazioni dello stesso valore →
|
|
9
9
|
// due mappe, entrambe keyed sul nome canonico di view.ts (unica fonte del rango).
|
|
@@ -83,10 +83,13 @@ export function initialDetail(current, prog, date = today()) {
|
|
|
83
83
|
* toccate restano i token grezzi originali: nessun re-flow della tabella, il
|
|
84
84
|
* diff resta di una riga. `ok:false` = id assente → il chiamante non scrive nulla.
|
|
85
85
|
*
|
|
86
|
-
* Le
|
|
87
|
-
* `parseTasks
|
|
88
|
-
*
|
|
89
|
-
*
|
|
86
|
+
* Le righe candidate vengono da `overviewRows`, lo stesso confine di
|
|
87
|
+
* `parseTasks`: solo dentro la Tasks Overview, con le colonne del suo HEADER e
|
|
88
|
+
* mai un indice cablato. Qui si SCRIVE su disco, quindi senza confine una riga
|
|
89
|
+
* cross-deps con lo stesso id (`| T07 | — | ✔️T08 |`) sopra la tabella verrebbe
|
|
90
|
+
* riscritta al posto della riga task, con Pri/Prog/titolo sopra le celle Parent e
|
|
91
|
+
* Cross Deps; e una colonna in più o in meno darebbe un titolo sovrascritto col
|
|
92
|
+
* glifo. Header assente → nessuna riga → `ok:false`, non si tira a indovinare.
|
|
90
93
|
*
|
|
91
94
|
* `desc` undefined ≠ `desc` vuota: la prima non tocca la cella (chiamata
|
|
92
95
|
* legacy, solo pri/prog), la seconda la svuota davvero.
|
|
@@ -104,23 +107,14 @@ export function updateTasksMdRow(content, id, priGlyph, progGlyph, desc) {
|
|
|
104
107
|
if (!TASK_ID_RE.test(id))
|
|
105
108
|
return { content, ok: false };
|
|
106
109
|
const lines = content.split('\n');
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
let ok = false;
|
|
111
|
-
const out = lines.map((line) => {
|
|
112
|
-
if (ok)
|
|
113
|
-
return line;
|
|
114
|
-
if (!line.trim().startsWith('|'))
|
|
115
|
-
return line;
|
|
110
|
+
for (const { index, line, id: rowId, cols } of overviewRows(lines)) {
|
|
111
|
+
if (rowId !== id)
|
|
112
|
+
continue;
|
|
116
113
|
const cells = line.split('|');
|
|
117
|
-
if ((cells[1] ?? '').trim() !== id)
|
|
118
|
-
return line;
|
|
119
114
|
// Serve la cella desc PIÙ la coda dopo il `|` finale: senza la coda lo
|
|
120
115
|
// splice inserirebbe invece di sostituire.
|
|
121
116
|
if (cells.length < cols.desc + 2)
|
|
122
|
-
|
|
123
|
-
ok = true;
|
|
117
|
+
continue; // riga malformata → non toccarla
|
|
124
118
|
cells[cols.pri] = ` ${priGlyph} `;
|
|
125
119
|
cells[cols.prog] = ` ${progGlyph} `;
|
|
126
120
|
if (desc !== undefined) {
|
|
@@ -128,9 +122,10 @@ export function updateTasksMdRow(content, id, priGlyph, progGlyph, desc) {
|
|
|
128
122
|
// ben formata) e va conservata, o la riga perderebbe il bordo destro.
|
|
129
123
|
cells.splice(cols.desc, cells.length - cols.desc - 1, ` ${sanitizeCell(desc)} `);
|
|
130
124
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
125
|
+
lines[index] = cells.join('|');
|
|
126
|
+
return { content: lines.join('\n'), ok: true };
|
|
127
|
+
}
|
|
128
|
+
return { content, ok: false };
|
|
134
129
|
}
|
|
135
130
|
/**
|
|
136
131
|
* Rende un testo scrivibile dentro una CELLA di tabella markdown. Due caratteri
|
package/dist/tasks.js
CHANGED
|
@@ -59,31 +59,60 @@ export function headerColumns(line) {
|
|
|
59
59
|
return null;
|
|
60
60
|
return { pri, prog, desc: prog + 1 };
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Le righe task della Tasks Overview: FONTE UNICA del confine della tabella,
|
|
64
|
+
* condivisa da `parseTasks` (lettura) e `updateTasksMdRow` (scrittura su disco),
|
|
65
|
+
* come `TASK_ID_RE` e `headerColumns` — due confini scritti in due posti
|
|
66
|
+
* divergerebbero, e quello dello scrittore è quello che fa danno.
|
|
67
|
+
*
|
|
68
|
+
* La tabella apre all'header (`headerColumns`) e chiude alla PRIMA riga che non
|
|
69
|
+
* inizia con `|`; un secondo header ne riapre una, con le proprie colonne. Il
|
|
70
|
+
* confine serve perché la prima cella `^T\d+$` non basta a riconoscere una riga
|
|
71
|
+
* task: le righe della tabella cross-deps dell'Execution Plan
|
|
72
|
+
* (`| T07 | — | ✔️T08 |`) hanno la stessa forma appena perdono il 🔒 davanti
|
|
73
|
+
* all'id, e senza confine diventavano task doppie con Pri = cella Parent e
|
|
74
|
+
* Prog = cella Cross Deps.
|
|
75
|
+
*
|
|
76
|
+
* Il titolo `## Tasks Overview` non entra nel criterio: il gate è l'header, così
|
|
77
|
+
* il deck non dipende dal nome della sezione. Il prezzo: una riga vuota o un
|
|
78
|
+
* commento DENTRO la tabella la chiude, e le righe sotto spariscono dal deck
|
|
79
|
+
* senza errore.
|
|
80
|
+
*/
|
|
81
|
+
export function overviewRows(lines) {
|
|
82
|
+
const rows = [];
|
|
70
83
|
let cols = null;
|
|
71
|
-
|
|
84
|
+
lines.forEach((line, index) => {
|
|
72
85
|
const header = headerColumns(line);
|
|
73
86
|
if (header) {
|
|
74
87
|
cols = header;
|
|
75
|
-
|
|
88
|
+
return;
|
|
76
89
|
}
|
|
77
90
|
if (!cols)
|
|
78
|
-
|
|
91
|
+
return;
|
|
79
92
|
const t = line.trim();
|
|
80
|
-
if (!t.startsWith('|'))
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
if (!t.startsWith('|')) {
|
|
94
|
+
cols = null;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// cells[0] = '' (prima del primo |): l'id è la seconda cella. Header e
|
|
98
|
+
// separatore non matchano `^T\d+$` → scartati.
|
|
99
|
+
const id = (t.split('|')[1] ?? '').trim();
|
|
100
|
+
if (TASK_ID_RE.test(id))
|
|
101
|
+
rows.push({ index, line, id, cols });
|
|
102
|
+
});
|
|
103
|
+
return rows;
|
|
104
|
+
}
|
|
105
|
+
// Estrae le righe `| Tnn | Pri | Prog | Task |` della Tasks Overview — il
|
|
106
|
+
// confine della tabella sta in `overviewRows`.
|
|
107
|
+
//
|
|
108
|
+
// Le righe si parsano solo DOPO aver incontrato l'header: senza indici derivati
|
|
109
|
+
// non si tira a indovinare, la lista resta vuota. Un fallimento visibile invece
|
|
110
|
+
// di una cella letta al posto sbagliato.
|
|
111
|
+
export function parseTasks(content) {
|
|
112
|
+
const tasks = [];
|
|
113
|
+
for (const { line, id, cols } of overviewRows(content.split('\n'))) {
|
|
83
114
|
// cells[0] = '' (prima del primo |), cells[last] = '' (dopo l'ultimo |)
|
|
84
|
-
const
|
|
85
|
-
if (!TASK_ID_RE.test(id))
|
|
86
|
-
continue;
|
|
115
|
+
const cells = line.trim().split('|').map((c) => c.trim());
|
|
87
116
|
const pri = cells[cols.pri] ?? '';
|
|
88
117
|
const prog = cells[cols.prog] ?? '';
|
|
89
118
|
// desc = colonna finale; join per resistere a eventuali `|` nella descrizione.
|
package/package.json
CHANGED