apotheke 0.1.1 → 0.1.3

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.
Files changed (3) hide show
  1. package/dist/cli.js +46 -27
  2. package/dist/index.js +46 -27
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -102,8 +102,12 @@ function deduplicateImports(imports) {
102
102
 
103
103
  // src/grouper.ts
104
104
  import path2 from "path";
105
- var SIDE_EFFECTS_GROUP = "SideEffects";
105
+
106
+ // src/types.ts
106
107
  var OTHERS_GROUP = "Others";
108
+ var SIDE_EFFECTS_BLOCK = "SideEffects";
109
+
110
+ // src/grouper.ts
107
111
  function groupImports(imports, config, options = {}) {
108
112
  const buckets = /* @__PURE__ */ new Map();
109
113
  for (const node of imports) {
@@ -112,9 +116,6 @@ function groupImports(imports, config, options = {}) {
112
116
  buckets.get(groupName).push(node);
113
117
  }
114
118
  const result = [];
115
- if (buckets.has(SIDE_EFFECTS_GROUP)) {
116
- result.push({ name: SIDE_EFFECTS_GROUP, imports: buckets.get(SIDE_EFFECTS_GROUP) });
117
- }
118
119
  for (const group of config.groups) {
119
120
  if (buckets.has(group.name)) {
120
121
  result.push({ name: group.name, imports: buckets.get(group.name) });
@@ -126,7 +127,6 @@ function groupImports(imports, config, options = {}) {
126
127
  return result;
127
128
  }
128
129
  function assignGroup(node, config, options) {
129
- if (node.isSideEffect) return SIDE_EFFECTS_GROUP;
130
130
  const canonicalPath = resolveCanonicalPath(node.specifier, config, options);
131
131
  for (const group of config.groups) {
132
132
  for (const pattern of group.match) {
@@ -224,7 +224,7 @@ function parseImports(source) {
224
224
  if (defaultImport) importNode.defaultImport = defaultImport;
225
225
  if (namespaceImport) importNode.namespaceImport = namespaceImport;
226
226
  const attached = findAttachedComment(source, node.start, comments);
227
- if (attached) importNode.attachedComment = attached;
227
+ if (attached !== void 0) importNode.attachedCommentStart = attached;
228
228
  nodes.push(importNode);
229
229
  }
230
230
  return nodes;
@@ -237,7 +237,7 @@ function findAttachedComment(source, importStart, comments) {
237
237
  const commentLines = source.slice(0, comment.end).split("\n");
238
238
  const commentLine = commentLines.length - 1;
239
239
  if (commentLine === importLine - 1) {
240
- return `//${comment.value}`;
240
+ return comment.start;
241
241
  }
242
242
  }
243
243
  return void 0;
@@ -257,9 +257,10 @@ function printGroups(groups, config, q = "'") {
257
257
  const parts = [];
258
258
  for (const group of groups) {
259
259
  const importLines = [];
260
+ const headed = useComments && group.name !== SIDE_EFFECTS_BLOCK;
260
261
  for (let i = 0; i < group.imports.length; i++) {
261
262
  const node = group.imports[i];
262
- if (i === 0 && useComments) {
263
+ if (i === 0 && headed) {
263
264
  importLines.push(`// ${group.name}
264
265
  ${buildImportStatement(node, q)}`);
265
266
  continue;
@@ -316,39 +317,57 @@ function collectOrphanSegments(source, imports) {
316
317
  const gapStart = imports[i].end;
317
318
  const gapEnd = imports[i + 1].start;
318
319
  if (gapEnd <= gapStart) continue;
319
- let gap = source.slice(gapStart, gapEnd);
320
- const nextComment = imports[i + 1].attachedComment;
321
- if (nextComment) {
322
- const commentText = nextComment.startsWith("//") ? nextComment.slice(2) : nextComment;
323
- const commentPattern = `// ${commentText.trim()}`;
324
- const idx = gap.lastIndexOf(commentPattern);
325
- if (idx !== -1) gap = gap.slice(0, idx);
326
- }
327
- const trimmed = gap.trim();
320
+ const commentStart = imports[i + 1].attachedCommentStart;
321
+ const cut = commentStart !== void 0 && commentStart >= gapStart && commentStart < gapEnd ? commentStart : gapEnd;
322
+ const trimmed = source.slice(gapStart, cut).trim();
328
323
  if (trimmed) orphans.push(trimmed);
329
324
  }
330
325
  return orphans;
331
326
  }
327
+ function buildBlocks(imports, config, options) {
328
+ const blocks = [];
329
+ let values = [];
330
+ let sideEffects = [];
331
+ function flushValues() {
332
+ if (values.length === 0) return;
333
+ for (const group of groupImports(values, config, options)) {
334
+ blocks.push({ ...group, imports: sortGroup(group.imports) });
335
+ }
336
+ values = [];
337
+ }
338
+ function flushSideEffects() {
339
+ if (sideEffects.length === 0) return;
340
+ blocks.push({ name: SIDE_EFFECTS_BLOCK, imports: sideEffects });
341
+ sideEffects = [];
342
+ }
343
+ for (const node of imports) {
344
+ if (node.isSideEffect) {
345
+ flushValues();
346
+ sideEffects.push(node);
347
+ } else {
348
+ flushSideEffects();
349
+ values.push(node);
350
+ }
351
+ }
352
+ flushSideEffects();
353
+ flushValues();
354
+ return blocks;
355
+ }
332
356
  function formatImports(source, config, options = {}) {
333
357
  const imports = parseImports(source);
334
358
  if (imports.length === 0) return source;
335
359
  const orphans = collectOrphanSegments(source, imports);
336
- const clean = imports.map((n) => ({ ...n, attachedComment: void 0 }));
360
+ const clean = imports.map((n) => ({ ...n, attachedCommentStart: void 0 }));
337
361
  const deduped = deduplicateImports(clean);
338
362
  const sorted = deduped.map(sortNamedImports);
339
- const grouped = groupImports(sorted, config, options);
340
- const sortedGroups = grouped.map(
341
- (g) => g.name === SIDE_EFFECTS_GROUP ? g : { ...g, imports: sortGroup(g.imports) }
342
- );
363
+ const blocks = buildBlocks(sorted, config, options);
343
364
  const q = detectQuoteChar(source);
344
- const newImportBlock = printGroups(sortedGroups, config, q);
365
+ const newImportBlock = printGroups(blocks, config, q);
345
366
  const firstImport = imports[0];
346
367
  const lastImport = imports[imports.length - 1];
347
368
  let regionStart = firstImport.start;
348
- if (firstImport.attachedComment) {
349
- const before2 = source.slice(0, firstImport.start);
350
- const commentLineStart = before2.lastIndexOf("\n", before2.length - 2) + 1;
351
- regionStart = commentLineStart;
369
+ if (firstImport.attachedCommentStart !== void 0) {
370
+ regionStart = source.lastIndexOf("\n", firstImport.attachedCommentStart) + 1;
352
371
  }
353
372
  let regionEnd = lastImport.end;
354
373
  if (source[regionEnd] === "\n") regionEnd++;
package/dist/index.js CHANGED
@@ -99,8 +99,12 @@ function deduplicateImports(imports) {
99
99
 
100
100
  // src/grouper.ts
101
101
  import path2 from "path";
102
- var SIDE_EFFECTS_GROUP = "SideEffects";
102
+
103
+ // src/types.ts
103
104
  var OTHERS_GROUP = "Others";
105
+ var SIDE_EFFECTS_BLOCK = "SideEffects";
106
+
107
+ // src/grouper.ts
104
108
  function groupImports(imports, config, options = {}) {
105
109
  const buckets = /* @__PURE__ */ new Map();
106
110
  for (const node of imports) {
@@ -109,9 +113,6 @@ function groupImports(imports, config, options = {}) {
109
113
  buckets.get(groupName).push(node);
110
114
  }
111
115
  const result = [];
112
- if (buckets.has(SIDE_EFFECTS_GROUP)) {
113
- result.push({ name: SIDE_EFFECTS_GROUP, imports: buckets.get(SIDE_EFFECTS_GROUP) });
114
- }
115
116
  for (const group of config.groups) {
116
117
  if (buckets.has(group.name)) {
117
118
  result.push({ name: group.name, imports: buckets.get(group.name) });
@@ -123,7 +124,6 @@ function groupImports(imports, config, options = {}) {
123
124
  return result;
124
125
  }
125
126
  function assignGroup(node, config, options) {
126
- if (node.isSideEffect) return SIDE_EFFECTS_GROUP;
127
127
  const canonicalPath = resolveCanonicalPath(node.specifier, config, options);
128
128
  for (const group of config.groups) {
129
129
  for (const pattern of group.match) {
@@ -221,7 +221,7 @@ function parseImports(source) {
221
221
  if (defaultImport) importNode.defaultImport = defaultImport;
222
222
  if (namespaceImport) importNode.namespaceImport = namespaceImport;
223
223
  const attached = findAttachedComment(source, node.start, comments);
224
- if (attached) importNode.attachedComment = attached;
224
+ if (attached !== void 0) importNode.attachedCommentStart = attached;
225
225
  nodes.push(importNode);
226
226
  }
227
227
  return nodes;
@@ -234,7 +234,7 @@ function findAttachedComment(source, importStart, comments) {
234
234
  const commentLines = source.slice(0, comment.end).split("\n");
235
235
  const commentLine = commentLines.length - 1;
236
236
  if (commentLine === importLine - 1) {
237
- return `//${comment.value}`;
237
+ return comment.start;
238
238
  }
239
239
  }
240
240
  return void 0;
@@ -254,9 +254,10 @@ function printGroups(groups, config, q = "'") {
254
254
  const parts = [];
255
255
  for (const group of groups) {
256
256
  const importLines = [];
257
+ const headed = useComments && group.name !== SIDE_EFFECTS_BLOCK;
257
258
  for (let i = 0; i < group.imports.length; i++) {
258
259
  const node = group.imports[i];
259
- if (i === 0 && useComments) {
260
+ if (i === 0 && headed) {
260
261
  importLines.push(`// ${group.name}
261
262
  ${buildImportStatement(node, q)}`);
262
263
  continue;
@@ -313,39 +314,57 @@ function collectOrphanSegments(source, imports) {
313
314
  const gapStart = imports[i].end;
314
315
  const gapEnd = imports[i + 1].start;
315
316
  if (gapEnd <= gapStart) continue;
316
- let gap = source.slice(gapStart, gapEnd);
317
- const nextComment = imports[i + 1].attachedComment;
318
- if (nextComment) {
319
- const commentText = nextComment.startsWith("//") ? nextComment.slice(2) : nextComment;
320
- const commentPattern = `// ${commentText.trim()}`;
321
- const idx = gap.lastIndexOf(commentPattern);
322
- if (idx !== -1) gap = gap.slice(0, idx);
323
- }
324
- const trimmed = gap.trim();
317
+ const commentStart = imports[i + 1].attachedCommentStart;
318
+ const cut = commentStart !== void 0 && commentStart >= gapStart && commentStart < gapEnd ? commentStart : gapEnd;
319
+ const trimmed = source.slice(gapStart, cut).trim();
325
320
  if (trimmed) orphans.push(trimmed);
326
321
  }
327
322
  return orphans;
328
323
  }
324
+ function buildBlocks(imports, config, options) {
325
+ const blocks = [];
326
+ let values = [];
327
+ let sideEffects = [];
328
+ function flushValues() {
329
+ if (values.length === 0) return;
330
+ for (const group of groupImports(values, config, options)) {
331
+ blocks.push({ ...group, imports: sortGroup(group.imports) });
332
+ }
333
+ values = [];
334
+ }
335
+ function flushSideEffects() {
336
+ if (sideEffects.length === 0) return;
337
+ blocks.push({ name: SIDE_EFFECTS_BLOCK, imports: sideEffects });
338
+ sideEffects = [];
339
+ }
340
+ for (const node of imports) {
341
+ if (node.isSideEffect) {
342
+ flushValues();
343
+ sideEffects.push(node);
344
+ } else {
345
+ flushSideEffects();
346
+ values.push(node);
347
+ }
348
+ }
349
+ flushSideEffects();
350
+ flushValues();
351
+ return blocks;
352
+ }
329
353
  function formatImports(source, config, options = {}) {
330
354
  const imports = parseImports(source);
331
355
  if (imports.length === 0) return source;
332
356
  const orphans = collectOrphanSegments(source, imports);
333
- const clean = imports.map((n) => ({ ...n, attachedComment: void 0 }));
357
+ const clean = imports.map((n) => ({ ...n, attachedCommentStart: void 0 }));
334
358
  const deduped = deduplicateImports(clean);
335
359
  const sorted = deduped.map(sortNamedImports);
336
- const grouped = groupImports(sorted, config, options);
337
- const sortedGroups = grouped.map(
338
- (g) => g.name === SIDE_EFFECTS_GROUP ? g : { ...g, imports: sortGroup(g.imports) }
339
- );
360
+ const blocks = buildBlocks(sorted, config, options);
340
361
  const q = detectQuoteChar(source);
341
- const newImportBlock = printGroups(sortedGroups, config, q);
362
+ const newImportBlock = printGroups(blocks, config, q);
342
363
  const firstImport = imports[0];
343
364
  const lastImport = imports[imports.length - 1];
344
365
  let regionStart = firstImport.start;
345
- if (firstImport.attachedComment) {
346
- const before2 = source.slice(0, firstImport.start);
347
- const commentLineStart = before2.lastIndexOf("\n", before2.length - 2) + 1;
348
- regionStart = commentLineStart;
366
+ if (firstImport.attachedCommentStart !== void 0) {
367
+ regionStart = source.lastIndexOf("\n", firstImport.attachedCommentStart) + 1;
349
368
  }
350
369
  let regionEnd = lastImport.end;
351
370
  if (source[regionEnd] === "\n") regionEnd++;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apotheke",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Prettier for imports — deterministic import organization as a Prettier plugin or CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",