@lsst/pik-core 0.7.0 → 0.8.0

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/README.md CHANGED
@@ -37,7 +37,7 @@ Load pik configuration from project files:
37
37
  ```typescript
38
38
  import { loadConfig, defineConfig } from '@lsst/pik-core';
39
39
 
40
- // Load config (looks for pik.config.ts, .pik.config.ts, etc.)
40
+ // Load config (looks for pik.config.ts, .pikrc, etc.)
41
41
  const config = await loadConfig();
42
42
 
43
43
  // Type-safe config definition
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export type { Option, BlockOption, Selector, ParseResult, PikPlugin } from './lib/types/index.js';
1
+ export type { Option, BlockOption, ParseResult, PikPlugin } from './lib/types/index.js';
2
+ export { BaseSelector, Selector, BlockSelector } from './lib/types/index.js';
2
3
  export { CommentStyle } from './lib/types/index.js';
3
4
  export { defineConfig, loadConfig, findLocalConfig, isValidPlugin, type PikConfig, } from './lib/config.js';
4
5
  export { Parser } from './lib/parser.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EACL,YAAY,EACZ,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAGzC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EACL,YAAY,EACZ,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,SAAS,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAGzC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/index.js CHANGED
@@ -1,226 +1,20 @@
1
1
  import { cosmiconfig } from "cosmiconfig";
2
- class CommentStyle {
3
- constructor(lineComment, blockOpen, blockClose) {
4
- this.lineComment = lineComment;
5
- this.blockOpen = blockOpen;
6
- this.blockClose = blockClose;
7
- }
8
- static styles = {
9
- // JavaScript/TypeScript
10
- js: new CommentStyle("//"),
11
- ts: new CommentStyle("//"),
12
- jsx: new CommentStyle("//"),
13
- tsx: new CommentStyle("//"),
14
- mjs: new CommentStyle("//"),
15
- mts: new CommentStyle("//"),
16
- // HTML - supports both // (in script) and <!-- --> (in HTML)
17
- html: new CommentStyle("//", "<!--", "-->"),
18
- htm: new CommentStyle("//", "<!--", "-->"),
19
- // Config files
20
- yaml: new CommentStyle("#"),
21
- yml: new CommentStyle("#"),
22
- // Shell
23
- sh: new CommentStyle("#"),
24
- bash: new CommentStyle("#"),
25
- zsh: new CommentStyle("#"),
26
- // Python
27
- py: new CommentStyle("#"),
28
- // Env files
29
- env: new CommentStyle("#")
30
- };
31
- static defaultStyle = new CommentStyle("//");
32
- /** Block comment opening (e.g., "<!--") */
33
- blockOpen;
34
- /** Block comment closing (e.g., "-->") */
35
- blockClose;
36
- /**
37
- * Check if this style supports block comments
38
- */
39
- get hasBlockComments() {
40
- return !!(this.blockOpen && this.blockClose);
41
- }
42
- /**
43
- * Get comment style for a file path.
44
- *
45
- * Handles dotfiles like `.env`, `.env.local`, `.env.development` correctly.
46
- */
47
- static fromFilePath(filePath) {
48
- const basename = filePath.split(/[/\\]/).pop() ?? "";
49
- if (basename === ".env" || basename.startsWith(".env.")) {
50
- return CommentStyle.styles["env"] ?? CommentStyle.defaultStyle;
51
- }
52
- const lastDot = basename.lastIndexOf(".");
53
- if (lastDot > 0) {
54
- const ext = basename.slice(lastDot + 1).toLowerCase();
55
- return CommentStyle.styles[ext] ?? CommentStyle.defaultStyle;
56
- }
57
- return CommentStyle.defaultStyle;
58
- }
59
- /**
60
- * Register a custom comment style for an extension
61
- */
62
- static register(extension, style) {
63
- const ext = extension.replace(/^\./, "").toLowerCase();
64
- CommentStyle.styles[ext] = style;
65
- }
66
- }
67
- function defineConfig(config) {
68
- return config;
69
- }
70
- async function loadConfig(cwd = process.cwd()) {
71
- const explorer = cosmiconfig("pik", {
72
- searchStrategy: "global"
73
- });
74
- const result = await explorer.search(cwd);
75
- return result?.config ?? null;
76
- }
77
- async function findLocalConfig(cwd = process.cwd()) {
78
- const explorer = cosmiconfig("pik", {
79
- searchStrategy: "none"
80
- });
81
- const result = await explorer.search(cwd);
82
- if (result) {
83
- return result.filepath.split("/").pop() || null;
84
- }
85
- return null;
86
- }
87
- function isValidPlugin(obj) {
88
- if (typeof obj !== "object" || obj === null) {
89
- return false;
90
- }
91
- const plugin = obj;
92
- return typeof plugin.name === "string" && typeof plugin.description === "string" && typeof plugin.command === "string" && typeof plugin.register === "function";
93
- }
94
- class Parser {
95
- constructor(commentStyle) {
96
- this.commentStyle = commentStyle;
97
- }
98
- static SELECT_REGEX = /@pik:select\s+(\S+)/;
99
- static OPTION_REGEX = /@pik:option\s+(\S+)/;
100
- static BLOCK_START_REGEX = /@pik:block-start\s+(\S+)/;
101
- static BLOCK_END_REGEX = /@pik:block-end/;
102
- /**
103
- * Create a parser for a file path
104
- */
105
- static forFilePath(filePath) {
106
- return new Parser(CommentStyle.fromFilePath(filePath));
2
+ class BaseSelector {
3
+ constructor(name, line) {
4
+ this.name = name;
5
+ this.line = line;
107
6
  }
108
7
  /**
109
- * Parse content string for pik selectors and options
8
+ * Get the name of the currently active option, or null if none is active
110
9
  */
111
- parse(content) {
112
- const lines = content.split("\n");
113
- const selectors = [];
114
- let currentSelector = null;
115
- let currentBlock = null;
116
- for (let i = 0; i < lines.length; i++) {
117
- const line = lines[i];
118
- const lineNumber = i + 1;
119
- const selectMatch = line.match(Parser.SELECT_REGEX);
120
- if (selectMatch) {
121
- currentSelector = {
122
- name: selectMatch[1],
123
- line: lineNumber,
124
- options: [],
125
- blockOptions: []
126
- };
127
- selectors.push(currentSelector);
128
- continue;
129
- }
130
- const blockStartMatch = line.match(Parser.BLOCK_START_REGEX);
131
- if (blockStartMatch && currentSelector) {
132
- currentBlock = {
133
- name: blockStartMatch[1],
134
- startLine: lineNumber,
135
- contentLines: []
136
- };
137
- continue;
138
- }
139
- const blockEndMatch = line.match(Parser.BLOCK_END_REGEX);
140
- if (blockEndMatch && currentSelector && currentBlock) {
141
- const isActive = currentBlock.contentLines.length > 0 ? !this.isLineCommented(lines[currentBlock.contentLines[0] - 1]) : false;
142
- const blockOption = {
143
- name: currentBlock.name,
144
- startLine: currentBlock.startLine,
145
- endLine: lineNumber,
146
- contentLines: currentBlock.contentLines,
147
- isActive
148
- };
149
- currentSelector.blockOptions.push(blockOption);
150
- currentBlock = null;
151
- continue;
152
- }
153
- if (currentBlock) {
154
- currentBlock.contentLines.push(lineNumber);
155
- continue;
156
- }
157
- const optionMatch = line.match(Parser.OPTION_REGEX);
158
- if (optionMatch && currentSelector) {
159
- const isStandalone = this.isStandaloneMarker(line);
160
- if (isStandalone && i + 1 < lines.length) {
161
- const contentLine = lines[i + 1];
162
- const option = {
163
- name: optionMatch[1],
164
- line: lineNumber,
165
- contentLine: lineNumber + 1,
166
- content: contentLine,
167
- isActive: !this.isLineCommented(contentLine)
168
- };
169
- currentSelector.options.push(option);
170
- } else {
171
- const option = {
172
- name: optionMatch[1],
173
- line: lineNumber,
174
- contentLine: lineNumber,
175
- content: line,
176
- isActive: !this.isLineCommented(line)
177
- };
178
- currentSelector.options.push(option);
179
- }
180
- }
181
- }
182
- return { selectors, content };
183
- }
184
- /**
185
- * Check if a line contains only a standalone marker (no other content)
186
- * e.g., "<!-- @pik:option Name -->" or "# @pik:option Name"
187
- */
188
- isStandaloneMarker(line) {
189
- const trimmed = line.trim();
190
- if (this.commentStyle.hasBlockComments) {
191
- const { blockOpen, blockClose } = this.commentStyle;
192
- if (trimmed.startsWith(blockOpen) && trimmed.endsWith(blockClose)) {
193
- const inner = trimmed.slice(blockOpen.length, -blockClose.length).trim();
194
- const optionMatch = inner.match(Parser.OPTION_REGEX);
195
- if (optionMatch && inner === `@pik:option ${optionMatch[1]}`) {
196
- return true;
197
- }
198
- }
199
- }
200
- if (trimmed.startsWith(this.commentStyle.lineComment)) {
201
- const afterComment = trimmed.slice(this.commentStyle.lineComment.length).trim();
202
- const optionMatch = afterComment.match(Parser.OPTION_REGEX);
203
- if (optionMatch && afterComment === `@pik:option ${optionMatch[1]}`) {
204
- return true;
205
- }
206
- }
207
- return false;
10
+ getActiveOptionName() {
11
+ return this.options.find((o) => o.isActive)?.name ?? null;
208
12
  }
209
13
  /**
210
- * Check if a line is commented out
14
+ * Check if an option with the given name exists
211
15
  */
212
- isLineCommented(line) {
213
- const trimmed = line.trimStart();
214
- if (trimmed.startsWith(this.commentStyle.lineComment)) {
215
- return true;
216
- }
217
- if (this.commentStyle.hasBlockComments) {
218
- const { blockOpen, blockClose } = this.commentStyle;
219
- if (trimmed.startsWith(blockOpen) && trimmed.includes(blockClose)) {
220
- return true;
221
- }
222
- }
223
- return false;
16
+ optionExists(name) {
17
+ return this.options.some((o) => o.name === name);
224
18
  }
225
19
  }
226
20
  class CommentManipulator {
@@ -367,6 +161,16 @@ class SingleSwitcher extends Switcher {
367
161
  return lines.join("\n");
368
162
  }
369
163
  }
164
+ class Selector extends BaseSelector {
165
+ options = [];
166
+ constructor(name, line) {
167
+ super(name, line);
168
+ }
169
+ switchTo(content, optionName, filePath) {
170
+ const switcher = SingleSwitcher.forFilePath(filePath);
171
+ return switcher.switch(content, this, optionName);
172
+ }
173
+ }
370
174
  class BlockSwitcher extends CommentManipulator {
371
175
  /**
372
176
  * Create a switcher for a file path
@@ -382,12 +186,12 @@ class BlockSwitcher extends CommentManipulator {
382
186
  switch(content, selector, blockName) {
383
187
  this.validateBlockOption(selector, blockName);
384
188
  const lines = content.split("\n");
385
- const useBlockStyle = selector.blockOptions.some((block) => {
189
+ const useBlockStyle = selector.options.some((block) => {
386
190
  if (block.contentLines.length === 0) return false;
387
191
  const line = lines[block.contentLines[0] - 1];
388
192
  return this.isBlockCommented(line);
389
193
  });
390
- for (const block of selector.blockOptions) {
194
+ for (const block of selector.options) {
391
195
  for (const lineNum of block.contentLines) {
392
196
  const lineIndex = lineNum - 1;
393
197
  const line = lines[lineIndex];
@@ -404,7 +208,7 @@ class BlockSwitcher extends CommentManipulator {
404
208
  * Validate that the block option exists in the selector
405
209
  */
406
210
  validateBlockOption(selector, blockName) {
407
- const block = selector.blockOptions.find((b) => b.name === blockName);
211
+ const block = selector.options.find((b) => b.name === blockName);
408
212
  if (!block) {
409
213
  throw new Error(
410
214
  `Block option "${blockName}" not found in selector "${selector.name}"`
@@ -412,11 +216,256 @@ class BlockSwitcher extends CommentManipulator {
412
216
  }
413
217
  }
414
218
  }
219
+ class BlockSelector extends BaseSelector {
220
+ options = [];
221
+ constructor(name, line) {
222
+ super(name, line);
223
+ }
224
+ switchTo(content, optionName, filePath) {
225
+ const switcher = BlockSwitcher.forFilePath(filePath);
226
+ return switcher.switch(content, this, optionName);
227
+ }
228
+ }
229
+ class CommentStyle {
230
+ constructor(lineComment, blockOpen, blockClose) {
231
+ this.lineComment = lineComment;
232
+ this.blockOpen = blockOpen;
233
+ this.blockClose = blockClose;
234
+ }
235
+ static styles = {
236
+ // JavaScript/TypeScript
237
+ js: new CommentStyle("//"),
238
+ ts: new CommentStyle("//"),
239
+ jsx: new CommentStyle("//"),
240
+ tsx: new CommentStyle("//"),
241
+ mjs: new CommentStyle("//"),
242
+ mts: new CommentStyle("//"),
243
+ // HTML - supports both // (in script) and <!-- --> (in HTML)
244
+ html: new CommentStyle("//", "<!--", "-->"),
245
+ htm: new CommentStyle("//", "<!--", "-->"),
246
+ // Config files
247
+ yaml: new CommentStyle("#"),
248
+ yml: new CommentStyle("#"),
249
+ // Shell
250
+ sh: new CommentStyle("#"),
251
+ bash: new CommentStyle("#"),
252
+ zsh: new CommentStyle("#"),
253
+ // Python
254
+ py: new CommentStyle("#"),
255
+ // Env files
256
+ env: new CommentStyle("#")
257
+ };
258
+ static defaultStyle = new CommentStyle("//");
259
+ /** Block comment opening (e.g., "<!--") */
260
+ blockOpen;
261
+ /** Block comment closing (e.g., "-->") */
262
+ blockClose;
263
+ /**
264
+ * Check if this style supports block comments
265
+ */
266
+ get hasBlockComments() {
267
+ return !!(this.blockOpen && this.blockClose);
268
+ }
269
+ /**
270
+ * Get comment style for a file path.
271
+ *
272
+ * Handles dotfiles like `.env`, `.env.local`, `.env.development` correctly.
273
+ */
274
+ static fromFilePath(filePath) {
275
+ const basename = filePath.split(/[/\\]/).pop() ?? "";
276
+ if (basename === ".env" || basename.startsWith(".env.")) {
277
+ return CommentStyle.styles["env"] ?? CommentStyle.defaultStyle;
278
+ }
279
+ const lastDot = basename.lastIndexOf(".");
280
+ if (lastDot > 0) {
281
+ const ext = basename.slice(lastDot + 1).toLowerCase();
282
+ return CommentStyle.styles[ext] ?? CommentStyle.defaultStyle;
283
+ }
284
+ return CommentStyle.defaultStyle;
285
+ }
286
+ /**
287
+ * Register a custom comment style for an extension
288
+ */
289
+ static register(extension, style) {
290
+ const ext = extension.replace(/^\./, "").toLowerCase();
291
+ CommentStyle.styles[ext] = style;
292
+ }
293
+ }
294
+ function defineConfig(config) {
295
+ return config;
296
+ }
297
+ async function loadConfig(cwd = process.cwd()) {
298
+ const explorer = cosmiconfig("pik", {
299
+ searchStrategy: "global"
300
+ });
301
+ const result = await explorer.search(cwd);
302
+ return result?.config ?? null;
303
+ }
304
+ async function findLocalConfig(cwd = process.cwd()) {
305
+ const explorer = cosmiconfig("pik", {
306
+ searchStrategy: "none"
307
+ });
308
+ const result = await explorer.search(cwd);
309
+ if (result) {
310
+ return result.filepath.split("/").pop() || null;
311
+ }
312
+ return null;
313
+ }
314
+ function isValidPlugin(obj) {
315
+ if (typeof obj !== "object" || obj === null) {
316
+ return false;
317
+ }
318
+ const plugin = obj;
319
+ return typeof plugin.name === "string" && typeof plugin.description === "string" && typeof plugin.command === "string" && typeof plugin.register === "function";
320
+ }
321
+ class Parser {
322
+ constructor(commentStyle) {
323
+ this.commentStyle = commentStyle;
324
+ }
325
+ static SELECT_REGEX = /@pik:select\s+(\S+)/;
326
+ static OPTION_REGEX = /@pik:option\s+(\S+)/;
327
+ static BLOCK_START_REGEX = /@pik:block-start\s+(\S+)/;
328
+ static BLOCK_END_REGEX = /@pik:block-end/;
329
+ /**
330
+ * Create a parser for a file path
331
+ */
332
+ static forFilePath(filePath) {
333
+ return new Parser(CommentStyle.fromFilePath(filePath));
334
+ }
335
+ /**
336
+ * Parse content string for pik selectors and options
337
+ */
338
+ parse(content) {
339
+ const lines = content.split("\n");
340
+ const selectors = [];
341
+ let currentSelector = null;
342
+ let pendingSelector = null;
343
+ let currentBlock = null;
344
+ for (let i = 0; i < lines.length; i++) {
345
+ const line = lines[i];
346
+ const lineNumber = i + 1;
347
+ const selectMatch = line.match(Parser.SELECT_REGEX);
348
+ if (selectMatch) {
349
+ pendingSelector = { name: selectMatch[1], line: lineNumber };
350
+ currentSelector = null;
351
+ continue;
352
+ }
353
+ const blockStartMatch = line.match(Parser.BLOCK_START_REGEX);
354
+ if (blockStartMatch && (pendingSelector || currentSelector instanceof BlockSelector)) {
355
+ if (!currentSelector && pendingSelector) {
356
+ currentSelector = new BlockSelector(pendingSelector.name, pendingSelector.line);
357
+ selectors.push(currentSelector);
358
+ pendingSelector = null;
359
+ }
360
+ currentBlock = {
361
+ name: blockStartMatch[1],
362
+ startLine: lineNumber,
363
+ contentLines: []
364
+ };
365
+ continue;
366
+ }
367
+ const blockEndMatch = line.match(Parser.BLOCK_END_REGEX);
368
+ if (blockEndMatch && currentSelector instanceof BlockSelector && currentBlock) {
369
+ const isActive = currentBlock.contentLines.length > 0 ? !this.isLineCommented(lines[currentBlock.contentLines[0] - 1]) : false;
370
+ const blockOption = {
371
+ name: currentBlock.name,
372
+ startLine: currentBlock.startLine,
373
+ endLine: lineNumber,
374
+ contentLines: currentBlock.contentLines,
375
+ isActive
376
+ };
377
+ currentSelector.options.push(blockOption);
378
+ currentBlock = null;
379
+ continue;
380
+ }
381
+ if (currentBlock) {
382
+ currentBlock.contentLines.push(lineNumber);
383
+ continue;
384
+ }
385
+ const optionMatch = line.match(Parser.OPTION_REGEX);
386
+ if (optionMatch && (pendingSelector || currentSelector instanceof Selector)) {
387
+ if (!currentSelector && pendingSelector) {
388
+ currentSelector = new Selector(pendingSelector.name, pendingSelector.line);
389
+ selectors.push(currentSelector);
390
+ pendingSelector = null;
391
+ }
392
+ if (currentSelector instanceof Selector) {
393
+ const isStandalone = this.isStandaloneMarker(line);
394
+ if (isStandalone && i + 1 < lines.length) {
395
+ const contentLine = lines[i + 1];
396
+ const option = {
397
+ name: optionMatch[1],
398
+ line: lineNumber,
399
+ contentLine: lineNumber + 1,
400
+ content: contentLine,
401
+ isActive: !this.isLineCommented(contentLine)
402
+ };
403
+ currentSelector.options.push(option);
404
+ } else {
405
+ const option = {
406
+ name: optionMatch[1],
407
+ line: lineNumber,
408
+ contentLine: lineNumber,
409
+ content: line,
410
+ isActive: !this.isLineCommented(line)
411
+ };
412
+ currentSelector.options.push(option);
413
+ }
414
+ }
415
+ }
416
+ }
417
+ return { selectors, content };
418
+ }
419
+ /**
420
+ * Check if a line contains only a standalone marker (no other content)
421
+ * e.g., "<!-- @pik:option Name -->" or "# @pik:option Name"
422
+ */
423
+ isStandaloneMarker(line) {
424
+ const trimmed = line.trim();
425
+ if (this.commentStyle.hasBlockComments) {
426
+ const { blockOpen, blockClose } = this.commentStyle;
427
+ if (trimmed.startsWith(blockOpen) && trimmed.endsWith(blockClose)) {
428
+ const inner = trimmed.slice(blockOpen.length, -blockClose.length).trim();
429
+ const optionMatch = inner.match(Parser.OPTION_REGEX);
430
+ if (optionMatch && inner === `@pik:option ${optionMatch[1]}`) {
431
+ return true;
432
+ }
433
+ }
434
+ }
435
+ if (trimmed.startsWith(this.commentStyle.lineComment)) {
436
+ const afterComment = trimmed.slice(this.commentStyle.lineComment.length).trim();
437
+ const optionMatch = afterComment.match(Parser.OPTION_REGEX);
438
+ if (optionMatch && afterComment === `@pik:option ${optionMatch[1]}`) {
439
+ return true;
440
+ }
441
+ }
442
+ return false;
443
+ }
444
+ /**
445
+ * Check if a line is commented out
446
+ */
447
+ isLineCommented(line) {
448
+ const trimmed = line.trimStart();
449
+ if (trimmed.startsWith(this.commentStyle.lineComment)) {
450
+ return true;
451
+ }
452
+ if (this.commentStyle.hasBlockComments) {
453
+ const { blockOpen, blockClose } = this.commentStyle;
454
+ if (trimmed.startsWith(blockOpen) && trimmed.includes(blockClose)) {
455
+ return true;
456
+ }
457
+ }
458
+ return false;
459
+ }
460
+ }
415
461
  export {
462
+ BaseSelector,
463
+ BlockSelector,
416
464
  BlockSwitcher,
417
465
  CommentManipulator,
418
466
  CommentStyle,
419
467
  Parser,
468
+ Selector,
420
469
  SingleSwitcher,
421
470
  Switcher,
422
471
  defineConfig,
@@ -1,4 +1,4 @@
1
- import type { Selector } from './types/index.js';
1
+ import type { BlockSelector } from './types/index.js';
2
2
  import { CommentManipulator } from './comment-manipulator.js';
3
3
  /**
4
4
  * Switcher that handles multi-line block options
@@ -13,7 +13,7 @@ export declare class BlockSwitcher extends CommentManipulator {
13
13
  * - Selected block: all content lines uncommented
14
14
  * - Other blocks: all content lines commented
15
15
  */
16
- switch(content: string, selector: Selector, blockName: string): string;
16
+ switch(content: string, selector: BlockSelector, blockName: string): string;
17
17
  /**
18
18
  * Validate that the block option exists in the selector
19
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"block-switcher.d.ts","sourceRoot":"","sources":["../../src/lib/block-switcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D;;GAEG;AACH,qBAAa,aAAc,SAAQ,kBAAkB;IACnD;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa;IAInD;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IA4BtE;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAQ5B"}
1
+ {"version":3,"file":"block-switcher.d.ts","sourceRoot":"","sources":["../../src/lib/block-switcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D;;GAEG;AACH,qBAAa,aAAc,SAAQ,kBAAkB;IACnD;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa;IAInD;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IA4B3E;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAQ5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/lib/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,WAAW,EAAY,MAAM,kBAAkB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;GAEG;AACH,qBAAa,MAAM;IAML,OAAO,CAAC,QAAQ,CAAC,YAAY;IALzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAyB;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAyB;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAA8B;IACvE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAoB;gBAE9B,YAAY,EAAE,YAAY;IAEvD;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5C;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;IA8FnC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA6B1B;;OAEG;IACH,OAAO,CAAC,eAAe;CAkBxB"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/lib/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAOhD;;GAEG;AACH,qBAAa,MAAM;IAML,OAAO,CAAC,QAAQ,CAAC,YAAY;IALzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAyB;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAyB;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAA8B;IACvE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAoB;gBAE9B,YAAY,EAAE,YAAY;IAEvD;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5C;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;IA0GnC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA6B1B;;OAEG;IACH,OAAO,CAAC,eAAe;CAkBxB"}
@@ -0,0 +1,30 @@
1
+ import type { BaseOption } from '../types/base-option.js';
2
+ /**
3
+ * Base class for selectors
4
+ */
5
+ export declare abstract class BaseSelector {
6
+ /** Selector name (e.g., "Environment") */
7
+ readonly name: string;
8
+ /** Line number where the selector is defined (1-based) */
9
+ readonly line: number;
10
+ /** Options for this selector */
11
+ abstract readonly options: BaseOption[];
12
+ constructor(
13
+ /** Selector name (e.g., "Environment") */
14
+ name: string,
15
+ /** Line number where the selector is defined (1-based) */
16
+ line: number);
17
+ /**
18
+ * Get the name of the currently active option, or null if none is active
19
+ */
20
+ getActiveOptionName(): string | null;
21
+ /**
22
+ * Check if an option with the given name exists
23
+ */
24
+ optionExists(name: string): boolean;
25
+ /**
26
+ * Switch to a specific option, returning the modified content
27
+ */
28
+ abstract switchTo(content: string, optionName: string, filePath: string): string;
29
+ }
30
+ //# sourceMappingURL=base-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-selector.d.ts","sourceRoot":"","sources":["../../../src/lib/selector/base-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;GAEG;AACH,8BAAsB,YAAY;IAK9B,0CAA0C;aAC1B,IAAI,EAAE,MAAM;IAC5B,0DAA0D;aAC1C,IAAI,EAAE,MAAM;IAP9B,gCAAgC;IAChC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC;;IAGtC,0CAA0C;IAC1B,IAAI,EAAE,MAAM;IAC5B,0DAA0D;IAC1C,IAAI,EAAE,MAAM;IAG9B;;OAEG;IACH,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAIpC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAInC;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;CACjF"}
@@ -0,0 +1,11 @@
1
+ import type { BlockOption } from '../types/block-option.js';
2
+ import { BaseSelector } from './base-selector.js';
3
+ /**
4
+ * Selector with multi-line block options
5
+ */
6
+ export declare class BlockSelector extends BaseSelector {
7
+ readonly options: BlockOption[];
8
+ constructor(name: string, line: number);
9
+ switchTo(content: string, optionName: string, filePath: string): string;
10
+ }
11
+ //# sourceMappingURL=block-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-selector.d.ts","sourceRoot":"","sources":["../../../src/lib/selector/block-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;GAEG;AACH,qBAAa,aAAc,SAAQ,YAAY;IAC7C,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAM;gBAEzB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAItC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;CAIxE"}
@@ -0,0 +1,4 @@
1
+ export { BaseSelector } from './base-selector.js';
2
+ export { Selector } from './selector.js';
3
+ export { BlockSelector } from './block-selector.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/selector/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Option } from '../types/option.js';
2
+ import { BaseSelector } from './base-selector.js';
3
+ /**
4
+ * Selector with single-line options
5
+ */
6
+ export declare class Selector extends BaseSelector {
7
+ readonly options: Option[];
8
+ constructor(name: string, line: number);
9
+ switchTo(content: string, optionName: string, filePath: string): string;
10
+ }
11
+ //# sourceMappingURL=selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../../src/lib/selector/selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;GAEG;AACH,qBAAa,QAAS,SAAQ,YAAY;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAM;gBAEpB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAItC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;CAIxE"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Base interface for selector options (both single-line and block)
3
+ */
4
+ export interface BaseOption {
5
+ /** Option name (e.g., "DEV", "Production") */
6
+ name: string;
7
+ /** Whether this option is currently active */
8
+ isActive: boolean;
9
+ }
10
+ //# sourceMappingURL=base-option.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-option.d.ts","sourceRoot":"","sources":["../../../src/lib/types/base-option.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;CACnB"}
@@ -1,16 +1,13 @@
1
+ import type { BaseOption } from './base-option.js';
1
2
  /**
2
3
  * Represents a multi-line block option within a selector
3
4
  */
4
- export interface BlockOption {
5
- /** Option name (e.g., "Development", "Production") */
6
- name: string;
5
+ export interface BlockOption extends BaseOption {
7
6
  /** Line number where @pik:block-start is located (1-based) */
8
7
  startLine: number;
9
8
  /** Line number where @pik:block-end is located (1-based) */
10
9
  endLine: number;
11
10
  /** Line numbers of content lines between start/end (1-based) */
12
11
  contentLines: number[];
13
- /** Whether this block is currently active (content lines are not commented out) */
14
- isActive: boolean;
15
12
  }
16
13
  //# sourceMappingURL=block-option.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-option.d.ts","sourceRoot":"","sources":["../../../src/lib/types/block-option.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mFAAmF;IACnF,QAAQ,EAAE,OAAO,CAAC;CACnB"}
1
+ {"version":3,"file":"block-option.d.ts","sourceRoot":"","sources":["../../../src/lib/types/block-option.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB"}
@@ -1,6 +1,7 @@
1
+ export type { BaseOption } from './base-option.js';
1
2
  export type { Option } from './option.js';
2
3
  export type { BlockOption } from './block-option.js';
3
- export type { Selector } from './selector.js';
4
+ export { BaseSelector, Selector, BlockSelector } from '../selector/index.js';
4
5
  export type { ParseResult } from './parse-result.js';
5
6
  export { CommentStyle } from './comment-style.js';
6
7
  export type { PikPlugin } from './plugin.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -1,16 +1,13 @@
1
+ import type { BaseOption } from './base-option.js';
1
2
  /**
2
3
  * Represents a single option within a selector
3
4
  */
4
- export interface Option {
5
- /** Option name (e.g., "DEV", "LOCAL") */
6
- name: string;
5
+ export interface Option extends BaseOption {
7
6
  /** Line number where the marker is (1-based) */
8
7
  line: number;
9
8
  /** Line number where the content is (1-based). Same as `line` for inline markers, next line for standalone markers. */
10
9
  contentLine: number;
11
10
  /** Full content of the content line */
12
11
  content: string;
13
- /** Whether this option is currently active (not commented out) */
14
- isActive: boolean;
15
12
  }
16
13
  //# sourceMappingURL=option.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"option.d.ts","sourceRoot":"","sources":["../../../src/lib/types/option.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,uHAAuH;IACvH,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,QAAQ,EAAE,OAAO,CAAC;CACnB"}
1
+ {"version":3,"file":"option.d.ts","sourceRoot":"","sources":["../../../src/lib/types/option.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,MAAO,SAAQ,UAAU;IACxC,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,uHAAuH;IACvH,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB"}
@@ -1,10 +1,10 @@
1
- import type { Selector } from './selector.js';
1
+ import type { BaseSelector } from '../selector/index.js';
2
2
  /**
3
3
  * Result of parsing a file or content string
4
4
  */
5
5
  export interface ParseResult {
6
6
  /** All selectors found in the content */
7
- selectors: Selector[];
7
+ selectors: BaseSelector[];
8
8
  /** Original content that was parsed */
9
9
  content: string;
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parse-result.d.ts","sourceRoot":"","sources":["../../../src/lib/types/parse-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"parse-result.d.ts","sourceRoot":"","sources":["../../../src/lib/types/parse-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsst/pik-core",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Core library for parsing and switching @pik config markers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,16 +0,0 @@
1
- import type { Option } from './option.js';
2
- import type { BlockOption } from './block-option.js';
3
- /**
4
- * Represents a selector with its options
5
- */
6
- export interface Selector {
7
- /** Selector name (e.g., "Environment") */
8
- name: string;
9
- /** Line number where the selector is defined (1-based) */
10
- line: number;
11
- /** All single-line options belonging to this selector */
12
- options: Option[];
13
- /** All multi-line block options belonging to this selector */
14
- blockOptions: BlockOption[];
15
- }
16
- //# sourceMappingURL=selector.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../../src/lib/types/selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8DAA8D;IAC9D,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B"}