@lsst/pik-core 0.6.7 → 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,8 +1,10 @@
1
- export type { Option, 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';
5
6
  export { Switcher } from './lib/switcher.js';
6
7
  export { SingleSwitcher } from './lib/single-switcher.js';
8
+ export { BlockSwitcher } from './lib/block-switcher.js';
7
9
  export { CommentManipulator } from './lib/comment-manipulator.js';
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACrF,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;AAG1D,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,4 +1,231 @@
1
1
  import { cosmiconfig } from "cosmiconfig";
2
+ class BaseSelector {
3
+ constructor(name, line) {
4
+ this.name = name;
5
+ this.line = line;
6
+ }
7
+ /**
8
+ * Get the name of the currently active option, or null if none is active
9
+ */
10
+ getActiveOptionName() {
11
+ return this.options.find((o) => o.isActive)?.name ?? null;
12
+ }
13
+ /**
14
+ * Check if an option with the given name exists
15
+ */
16
+ optionExists(name) {
17
+ return this.options.some((o) => o.name === name);
18
+ }
19
+ }
20
+ class CommentManipulator {
21
+ constructor(commentStyle) {
22
+ this.commentStyle = commentStyle;
23
+ }
24
+ /**
25
+ * Check if a line is commented out (line or block comment)
26
+ */
27
+ isLineCommented(line) {
28
+ const trimmed = line.trimStart();
29
+ if (trimmed.startsWith(this.commentStyle.lineComment)) {
30
+ return true;
31
+ }
32
+ if (this.commentStyle.hasBlockComments) {
33
+ const { blockOpen, blockClose } = this.commentStyle;
34
+ if (trimmed.startsWith(blockOpen) && trimmed.includes(blockClose)) {
35
+ return true;
36
+ }
37
+ }
38
+ return false;
39
+ }
40
+ /**
41
+ * Check if a line uses block comment style
42
+ */
43
+ isBlockCommented(line) {
44
+ if (!this.commentStyle.hasBlockComments) {
45
+ return false;
46
+ }
47
+ const trimmed = line.trimStart();
48
+ const { blockOpen, blockClose } = this.commentStyle;
49
+ return trimmed.startsWith(blockOpen) && trimmed.includes(blockClose);
50
+ }
51
+ /**
52
+ * Check if a line is a line comment (not a block comment)
53
+ */
54
+ isLineComment(line) {
55
+ const trimmed = line.trimStart();
56
+ return trimmed.startsWith(this.commentStyle.lineComment);
57
+ }
58
+ /**
59
+ * Comment out a line if not already commented.
60
+ * Uses the same comment style as the original if block-commented,
61
+ * otherwise uses line comment style.
62
+ */
63
+ commentLine(line, useBlockStyle = false) {
64
+ const trimmed = line.trimStart();
65
+ if (trimmed.startsWith(this.commentStyle.lineComment)) {
66
+ return line;
67
+ }
68
+ if (this.isBlockCommented(line)) {
69
+ return line;
70
+ }
71
+ const indent = line.slice(0, line.length - trimmed.length);
72
+ if (useBlockStyle && this.commentStyle.hasBlockComments) {
73
+ const { blockOpen, blockClose } = this.commentStyle;
74
+ return `${indent}${blockOpen} ${trimmed} ${blockClose}`;
75
+ }
76
+ return `${indent}${this.commentStyle.lineComment} ${trimmed}`;
77
+ }
78
+ /**
79
+ * Uncomment a block comment
80
+ * @throws Error if the line is not a block comment
81
+ */
82
+ uncommentBlockComment(line) {
83
+ if (!this.isBlockCommented(line)) {
84
+ throw new Error("Expected line to be a block comment");
85
+ }
86
+ const trimmed = line.trimStart();
87
+ const indent = line.slice(0, line.length - trimmed.length);
88
+ const { blockOpen, blockClose } = this.commentStyle;
89
+ const afterOpen = trimmed.slice(blockOpen.length);
90
+ const closeIndex = afterOpen.indexOf(blockClose);
91
+ const content = afterOpen.slice(0, closeIndex).trim();
92
+ const rest = afterOpen.slice(closeIndex + blockClose.length);
93
+ return `${indent}${content}${rest}`;
94
+ }
95
+ /**
96
+ * Uncomment a line comment
97
+ * @throws Error if the line is not a line comment
98
+ */
99
+ uncommentLineComment(line) {
100
+ if (!this.isLineComment(line)) {
101
+ throw new Error("Expected line to be a line comment");
102
+ }
103
+ const trimmed = line.trimStart();
104
+ const indent = line.slice(0, line.length - trimmed.length);
105
+ const withoutComment = trimmed.slice(this.commentStyle.lineComment.length);
106
+ const content = withoutComment.startsWith(" ") ? withoutComment.slice(1) : withoutComment;
107
+ return `${indent}${content}`;
108
+ }
109
+ /**
110
+ * Uncomment a line if commented (handles both line and block comments)
111
+ */
112
+ uncommentLine(line) {
113
+ if (this.isBlockCommented(line)) {
114
+ return this.uncommentBlockComment(line);
115
+ }
116
+ if (this.isLineComment(line)) {
117
+ return this.uncommentLineComment(line);
118
+ }
119
+ return line;
120
+ }
121
+ }
122
+ class Switcher extends CommentManipulator {
123
+ /**
124
+ * Validate that the option exists in the selector
125
+ */
126
+ validateOption(selector, optionName) {
127
+ const option = selector.options.find((o) => o.name === optionName);
128
+ if (!option) {
129
+ throw new Error(
130
+ `Option "${optionName}" not found in selector "${selector.name}"`
131
+ );
132
+ }
133
+ }
134
+ }
135
+ class SingleSwitcher extends Switcher {
136
+ /**
137
+ * Create a switcher for a file path
138
+ */
139
+ static forFilePath(filePath) {
140
+ return new SingleSwitcher(CommentStyle.fromFilePath(filePath));
141
+ }
142
+ /**
143
+ * Switch to a specific option, deactivating all others
144
+ */
145
+ switch(content, selector, optionName) {
146
+ this.validateOption(selector, optionName);
147
+ const lines = content.split("\n");
148
+ const useBlockStyle = selector.options.some((opt) => {
149
+ const line = lines[opt.contentLine - 1];
150
+ return this.isBlockCommented(line);
151
+ });
152
+ for (const option of selector.options) {
153
+ const lineIndex = option.contentLine - 1;
154
+ const line = lines[lineIndex];
155
+ if (option.name === optionName) {
156
+ lines[lineIndex] = this.uncommentLine(line);
157
+ } else {
158
+ lines[lineIndex] = this.commentLine(line, useBlockStyle);
159
+ }
160
+ }
161
+ return lines.join("\n");
162
+ }
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
+ }
174
+ class BlockSwitcher extends CommentManipulator {
175
+ /**
176
+ * Create a switcher for a file path
177
+ */
178
+ static forFilePath(filePath) {
179
+ return new BlockSwitcher(CommentStyle.fromFilePath(filePath));
180
+ }
181
+ /**
182
+ * Switch to a specific block option, deactivating all others.
183
+ * - Selected block: all content lines uncommented
184
+ * - Other blocks: all content lines commented
185
+ */
186
+ switch(content, selector, blockName) {
187
+ this.validateBlockOption(selector, blockName);
188
+ const lines = content.split("\n");
189
+ const useBlockStyle = selector.options.some((block) => {
190
+ if (block.contentLines.length === 0) return false;
191
+ const line = lines[block.contentLines[0] - 1];
192
+ return this.isBlockCommented(line);
193
+ });
194
+ for (const block of selector.options) {
195
+ for (const lineNum of block.contentLines) {
196
+ const lineIndex = lineNum - 1;
197
+ const line = lines[lineIndex];
198
+ if (block.name === blockName) {
199
+ lines[lineIndex] = this.uncommentLine(line);
200
+ } else {
201
+ lines[lineIndex] = this.commentLine(line, useBlockStyle);
202
+ }
203
+ }
204
+ }
205
+ return lines.join("\n");
206
+ }
207
+ /**
208
+ * Validate that the block option exists in the selector
209
+ */
210
+ validateBlockOption(selector, blockName) {
211
+ const block = selector.options.find((b) => b.name === blockName);
212
+ if (!block) {
213
+ throw new Error(
214
+ `Block option "${blockName}" not found in selector "${selector.name}"`
215
+ );
216
+ }
217
+ }
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
+ }
2
229
  class CommentStyle {
3
230
  constructor(lineComment, blockOpen, blockClose) {
4
231
  this.lineComment = lineComment;
@@ -97,6 +324,8 @@ class Parser {
97
324
  }
98
325
  static SELECT_REGEX = /@pik:select\s+(\S+)/;
99
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/;
100
329
  /**
101
330
  * Create a parser for a file path
102
331
  */
@@ -110,41 +339,78 @@ class Parser {
110
339
  const lines = content.split("\n");
111
340
  const selectors = [];
112
341
  let currentSelector = null;
342
+ let pendingSelector = null;
343
+ let currentBlock = null;
113
344
  for (let i = 0; i < lines.length; i++) {
114
345
  const line = lines[i];
115
346
  const lineNumber = i + 1;
116
347
  const selectMatch = line.match(Parser.SELECT_REGEX);
117
348
  if (selectMatch) {
118
- currentSelector = {
119
- name: selectMatch[1],
120
- line: lineNumber,
121
- options: []
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: []
122
364
  };
123
- selectors.push(currentSelector);
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);
124
383
  continue;
125
384
  }
126
385
  const optionMatch = line.match(Parser.OPTION_REGEX);
127
- if (optionMatch && currentSelector) {
128
- const isStandalone = this.isStandaloneMarker(line);
129
- if (isStandalone && i + 1 < lines.length) {
130
- const contentLine = lines[i + 1];
131
- const option = {
132
- name: optionMatch[1],
133
- line: lineNumber,
134
- contentLine: lineNumber + 1,
135
- content: contentLine,
136
- isActive: !this.isLineCommented(contentLine)
137
- };
138
- currentSelector.options.push(option);
139
- } else {
140
- const option = {
141
- name: optionMatch[1],
142
- line: lineNumber,
143
- contentLine: lineNumber,
144
- content: line,
145
- isActive: !this.isLineCommented(line)
146
- };
147
- currentSelector.options.push(option);
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
+ }
148
414
  }
149
415
  }
150
416
  }
@@ -192,154 +458,14 @@ class Parser {
192
458
  return false;
193
459
  }
194
460
  }
195
- class CommentManipulator {
196
- constructor(commentStyle) {
197
- this.commentStyle = commentStyle;
198
- }
199
- /**
200
- * Check if a line is commented out (line or block comment)
201
- */
202
- isLineCommented(line) {
203
- const trimmed = line.trimStart();
204
- if (trimmed.startsWith(this.commentStyle.lineComment)) {
205
- return true;
206
- }
207
- if (this.commentStyle.hasBlockComments) {
208
- const { blockOpen, blockClose } = this.commentStyle;
209
- if (trimmed.startsWith(blockOpen) && trimmed.includes(blockClose)) {
210
- return true;
211
- }
212
- }
213
- return false;
214
- }
215
- /**
216
- * Check if a line uses block comment style
217
- */
218
- isBlockCommented(line) {
219
- if (!this.commentStyle.hasBlockComments) {
220
- return false;
221
- }
222
- const trimmed = line.trimStart();
223
- const { blockOpen, blockClose } = this.commentStyle;
224
- return trimmed.startsWith(blockOpen) && trimmed.includes(blockClose);
225
- }
226
- /**
227
- * Check if a line is a line comment (not a block comment)
228
- */
229
- isLineComment(line) {
230
- const trimmed = line.trimStart();
231
- return trimmed.startsWith(this.commentStyle.lineComment);
232
- }
233
- /**
234
- * Comment out a line if not already commented.
235
- * Uses the same comment style as the original if block-commented,
236
- * otherwise uses line comment style.
237
- */
238
- commentLine(line, useBlockStyle = false) {
239
- const trimmed = line.trimStart();
240
- if (trimmed.startsWith(this.commentStyle.lineComment)) {
241
- return line;
242
- }
243
- if (this.isBlockCommented(line)) {
244
- return line;
245
- }
246
- const indent = line.slice(0, line.length - trimmed.length);
247
- if (useBlockStyle && this.commentStyle.hasBlockComments) {
248
- const { blockOpen, blockClose } = this.commentStyle;
249
- return `${indent}${blockOpen} ${trimmed} ${blockClose}`;
250
- }
251
- return `${indent}${this.commentStyle.lineComment} ${trimmed}`;
252
- }
253
- /**
254
- * Uncomment a block comment
255
- * @throws Error if the line is not a block comment
256
- */
257
- uncommentBlockComment(line) {
258
- if (!this.isBlockCommented(line)) {
259
- throw new Error("Expected line to be a block comment");
260
- }
261
- const trimmed = line.trimStart();
262
- const indent = line.slice(0, line.length - trimmed.length);
263
- const { blockOpen, blockClose } = this.commentStyle;
264
- const afterOpen = trimmed.slice(blockOpen.length);
265
- const closeIndex = afterOpen.indexOf(blockClose);
266
- const content = afterOpen.slice(0, closeIndex).trim();
267
- const rest = afterOpen.slice(closeIndex + blockClose.length);
268
- return `${indent}${content}${rest}`;
269
- }
270
- /**
271
- * Uncomment a line comment
272
- * @throws Error if the line is not a line comment
273
- */
274
- uncommentLineComment(line) {
275
- if (!this.isLineComment(line)) {
276
- throw new Error("Expected line to be a line comment");
277
- }
278
- const trimmed = line.trimStart();
279
- const indent = line.slice(0, line.length - trimmed.length);
280
- const withoutComment = trimmed.slice(this.commentStyle.lineComment.length);
281
- const content = withoutComment.startsWith(" ") ? withoutComment.slice(1) : withoutComment;
282
- return `${indent}${content}`;
283
- }
284
- /**
285
- * Uncomment a line if commented (handles both line and block comments)
286
- */
287
- uncommentLine(line) {
288
- if (this.isBlockCommented(line)) {
289
- return this.uncommentBlockComment(line);
290
- }
291
- if (this.isLineComment(line)) {
292
- return this.uncommentLineComment(line);
293
- }
294
- return line;
295
- }
296
- }
297
- class Switcher extends CommentManipulator {
298
- /**
299
- * Validate that the option exists in the selector
300
- */
301
- validateOption(selector, optionName) {
302
- const option = selector.options.find((o) => o.name === optionName);
303
- if (!option) {
304
- throw new Error(
305
- `Option "${optionName}" not found in selector "${selector.name}"`
306
- );
307
- }
308
- }
309
- }
310
- class SingleSwitcher extends Switcher {
311
- /**
312
- * Create a switcher for a file path
313
- */
314
- static forFilePath(filePath) {
315
- return new SingleSwitcher(CommentStyle.fromFilePath(filePath));
316
- }
317
- /**
318
- * Switch to a specific option, deactivating all others
319
- */
320
- switch(content, selector, optionName) {
321
- this.validateOption(selector, optionName);
322
- const lines = content.split("\n");
323
- const useBlockStyle = selector.options.some((opt) => {
324
- const line = lines[opt.contentLine - 1];
325
- return this.isBlockCommented(line);
326
- });
327
- for (const option of selector.options) {
328
- const lineIndex = option.contentLine - 1;
329
- const line = lines[lineIndex];
330
- if (option.name === optionName) {
331
- lines[lineIndex] = this.uncommentLine(line);
332
- } else {
333
- lines[lineIndex] = this.commentLine(line, useBlockStyle);
334
- }
335
- }
336
- return lines.join("\n");
337
- }
338
- }
339
461
  export {
462
+ BaseSelector,
463
+ BlockSelector,
464
+ BlockSwitcher,
340
465
  CommentManipulator,
341
466
  CommentStyle,
342
467
  Parser,
468
+ Selector,
343
469
  SingleSwitcher,
344
470
  Switcher,
345
471
  defineConfig,
@@ -0,0 +1,22 @@
1
+ import type { BlockSelector } from './types/index.js';
2
+ import { CommentManipulator } from './comment-manipulator.js';
3
+ /**
4
+ * Switcher that handles multi-line block options
5
+ */
6
+ export declare class BlockSwitcher extends CommentManipulator {
7
+ /**
8
+ * Create a switcher for a file path
9
+ */
10
+ static forFilePath(filePath: string): BlockSwitcher;
11
+ /**
12
+ * Switch to a specific block option, deactivating all others.
13
+ * - Selected block: all content lines uncommented
14
+ * - Other blocks: all content lines commented
15
+ */
16
+ switch(content: string, selector: BlockSelector, blockName: string): string;
17
+ /**
18
+ * Validate that the block option exists in the selector
19
+ */
20
+ private validateBlockOption;
21
+ }
22
+ //# sourceMappingURL=block-switcher.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -7,6 +7,8 @@ export declare class Parser {
7
7
  private readonly commentStyle;
8
8
  private static readonly SELECT_REGEX;
9
9
  private static readonly OPTION_REGEX;
10
+ private static readonly BLOCK_START_REGEX;
11
+ private static readonly BLOCK_END_REGEX;
10
12
  constructor(commentStyle: CommentStyle);
11
13
  /**
12
14
  * Create a parser for a file path
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/lib/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,WAAW,EAAY,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;GAEG;AACH,qBAAa,MAAM;IAIL,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAyB;IAC7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAyB;gBAEhC,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;IAuDnC;;;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"}
@@ -0,0 +1,13 @@
1
+ import type { BaseOption } from './base-option.js';
2
+ /**
3
+ * Represents a multi-line block option within a selector
4
+ */
5
+ export interface BlockOption extends BaseOption {
6
+ /** Line number where @pik:block-start is located (1-based) */
7
+ startLine: number;
8
+ /** Line number where @pik:block-end is located (1-based) */
9
+ endLine: number;
10
+ /** Line numbers of content lines between start/end (1-based) */
11
+ contentLines: number[];
12
+ }
13
+ //# sourceMappingURL=block-option.d.ts.map
@@ -0,0 +1 @@
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,5 +1,7 @@
1
+ export type { BaseOption } from './base-option.js';
1
2
  export type { Option } from './option.js';
2
- export type { Selector } from './selector.js';
3
+ export type { BlockOption } from './block-option.js';
4
+ export { BaseSelector, Selector, BlockSelector } from '../selector/index.js';
3
5
  export type { ParseResult } from './parse-result.js';
4
6
  export { CommentStyle } from './comment-style.js';
5
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,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.6.7",
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,13 +0,0 @@
1
- import type { Option } from './option.js';
2
- /**
3
- * Represents a selector with its options
4
- */
5
- export interface Selector {
6
- /** Selector name (e.g., "Environment") */
7
- name: string;
8
- /** Line number where the selector is defined (1-based) */
9
- line: number;
10
- /** All options belonging to this selector */
11
- options: Option[];
12
- }
13
- //# 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;AAE1C;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB"}