pi-roundtable 0.6.0 → 0.6.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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/cli/config-edit.ts +53 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.6.1] - 2026-10-02
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- `add plugin` and `add package` kept a one-line `plugins` list on one line however long it grew, so a project's `biome check` failed once the line passed 80 columns. A list that would pass 80 columns is now put one element a line, as the formatter writes it; a list already over several lines keeps its layout, and one holding a comment stays as it was.
|
|
13
|
+
|
|
8
14
|
## [0.6.0] - 2026-10-02
|
|
9
15
|
|
|
10
16
|
### Added
|
package/package.json
CHANGED
package/src/cli/config-edit.ts
CHANGED
|
@@ -115,6 +115,50 @@ function pluginList(object: Node): Node | undefined {
|
|
|
115
115
|
interface Insertion {
|
|
116
116
|
at: number;
|
|
117
117
|
text: string;
|
|
118
|
+
/** How many characters from `at` the text replaces; none when it only inserts. */
|
|
119
|
+
replaces?: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** The width the formatter gives a line: a tab counts as its default indent width of 2. */
|
|
123
|
+
const LINE_WIDTH = 80;
|
|
124
|
+
const width = (line: string): number => line.replaceAll("\t", " ").length;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The one-line list with `ident` added, put one element a line when the line it sits on would
|
|
128
|
+
* pass the formatter's width, as the project's formatter would; undefined when the list already
|
|
129
|
+
* spans lines, holds anything besides its elements and commas, or still fits.
|
|
130
|
+
*/
|
|
131
|
+
function expandedList(
|
|
132
|
+
source: string,
|
|
133
|
+
list: Node,
|
|
134
|
+
elements: readonly Node[],
|
|
135
|
+
ident: string,
|
|
136
|
+
): Insertion | undefined {
|
|
137
|
+
const inner = source.slice(list.start + 1, list.end - 1);
|
|
138
|
+
if (inner.includes("\n")) return undefined;
|
|
139
|
+
const items = elements.map((element) =>
|
|
140
|
+
source.slice(element.start, element.end),
|
|
141
|
+
);
|
|
142
|
+
// The text around and between the elements, which must be only commas and spaces.
|
|
143
|
+
const edges = [
|
|
144
|
+
list.start + 1,
|
|
145
|
+
...elements.flatMap((element) => [element.start, element.end]),
|
|
146
|
+
list.end - 1,
|
|
147
|
+
];
|
|
148
|
+
let gaps = "";
|
|
149
|
+
for (let index = 0; index < edges.length; index += 2)
|
|
150
|
+
gaps += source.slice(edges[index], edges[index + 1]);
|
|
151
|
+
if (!/^[\s,]*$/.test(gaps)) return undefined;
|
|
152
|
+
const lineStart = source.lastIndexOf("\n", list.start) + 1;
|
|
153
|
+
const lineEnd = source.indexOf("\n", list.end);
|
|
154
|
+
const line = `${source.slice(lineStart, list.start)}[${[...items, ident].join(", ")}]${source.slice(list.end, lineEnd === -1 ? undefined : lineEnd)}`;
|
|
155
|
+
if (width(line) <= LINE_WIDTH) return undefined;
|
|
156
|
+
const indent = /^[ \t]*/.exec(source.slice(lineStart, list.start))?.[0] ?? "";
|
|
157
|
+
return {
|
|
158
|
+
at: list.start,
|
|
159
|
+
replaces: list.end - list.start,
|
|
160
|
+
text: `[\n${[...items, ident].map((item) => `${indent}\t${item},\n`).join("")}${indent}]`,
|
|
161
|
+
};
|
|
118
162
|
}
|
|
119
163
|
|
|
120
164
|
/** The text to add so `ident` joins the list, in the list's own layout. */
|
|
@@ -122,6 +166,8 @@ function listInsertion(source: string, list: Node, ident: string): Insertion {
|
|
|
122
166
|
const elements = (list.elements as (Node | null)[]).filter(
|
|
123
167
|
(element): element is Node => element !== null,
|
|
124
168
|
);
|
|
169
|
+
const expanded = expandedList(source, list, elements, ident);
|
|
170
|
+
if (expanded) return expanded;
|
|
125
171
|
const last = elements.at(-1);
|
|
126
172
|
if (!last) return { at: list.start + 1, text: ident };
|
|
127
173
|
const between = source.slice(last.end, list.end - 1);
|
|
@@ -161,8 +207,9 @@ function importInsertion(
|
|
|
161
207
|
|
|
162
208
|
/**
|
|
163
209
|
* Adds the plugin's import line and lists it in the `plugins` array of the default export, in the
|
|
164
|
-
* file's own layout
|
|
165
|
-
*
|
|
210
|
+
* file's own layout; a one-line list that would pass 80 columns is put one element a line. It
|
|
211
|
+
* refuses, changing nothing, a file that does not parse, a default export with no `plugins` list
|
|
212
|
+
* it can find, and a name already bound.
|
|
166
213
|
*/
|
|
167
214
|
export function addPluginToConfig(
|
|
168
215
|
source: string,
|
|
@@ -192,7 +239,10 @@ export function addPluginToConfig(
|
|
|
192
239
|
].sort((a, b) => b.at - a.at);
|
|
193
240
|
let edited = source;
|
|
194
241
|
for (const edit of edits)
|
|
195
|
-
edited =
|
|
242
|
+
edited =
|
|
243
|
+
edited.slice(0, edit.at) +
|
|
244
|
+
edit.text +
|
|
245
|
+
edited.slice(edit.at + (edit.replaces ?? 0));
|
|
196
246
|
// A result that does not parse is a bug here; never write it.
|
|
197
247
|
parseModule(edited, file);
|
|
198
248
|
return edited;
|