@lsst/pik-core 0.6.5 → 0.6.7

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
@@ -22,11 +22,11 @@ const env = 'LOCAL'; // @pik:option LOCAL
22
22
  `;
23
23
 
24
24
  // Parse content
25
- const parser = Parser.forExtension('ts');
25
+ const parser = Parser.forFilePath('config.ts');
26
26
  const { selectors } = parser.parse(content);
27
27
 
28
28
  // Switch option
29
- const switcher = SingleSwitcher.forExtension('ts');
29
+ const switcher = SingleSwitcher.forFilePath('config.ts');
30
30
  const newContent = switcher.switch(content, selectors[0], 'DEV');
31
31
  ```
32
32
 
@@ -84,8 +84,8 @@ export function myPlugin(config: MyPluginConfig): PikPlugin {
84
84
  ### Parser
85
85
 
86
86
  ```typescript
87
- // Create parser for file extension
88
- const parser = Parser.forExtension('ts');
87
+ // Create parser for file path
88
+ const parser = Parser.forFilePath('src/config.ts');
89
89
 
90
90
  // Parse content
91
91
  const result = parser.parse(content);
@@ -96,8 +96,8 @@ const result = parser.parse(content);
96
96
  ### SingleSwitcher
97
97
 
98
98
  ```typescript
99
- // Create switcher for file extension
100
- const switcher = SingleSwitcher.forExtension('ts');
99
+ // Create switcher for file path
100
+ const switcher = SingleSwitcher.forFilePath('src/config.ts');
101
101
 
102
102
  // Switch to option (deactivates all others)
103
103
  const newContent = switcher.switch(content, selector, 'optionName');
@@ -108,8 +108,8 @@ const newContent = switcher.switch(content, selector, 'optionName');
108
108
  ```typescript
109
109
  import { CommentStyle } from '@lsst/pik-core';
110
110
 
111
- // Get comment style for extension
112
- const style = CommentStyle.fromExtension('py'); // { lineComment: '#' }
111
+ // Get comment style for file path
112
+ const style = CommentStyle.fromFilePath('script.py'); // { lineComment: '#' }
113
113
 
114
114
  // Register custom style
115
115
  CommentStyle.register('custom', new CommentStyle(';;'));
package/dist/index.js CHANGED
@@ -40,11 +40,21 @@ class CommentStyle {
40
40
  return !!(this.blockOpen && this.blockClose);
41
41
  }
42
42
  /**
43
- * Get comment style for a file extension
43
+ * Get comment style for a file path.
44
+ *
45
+ * Handles dotfiles like `.env`, `.env.local`, `.env.development` correctly.
44
46
  */
45
- static fromExtension(extension) {
46
- const ext = extension.replace(/^\./, "").toLowerCase();
47
- return CommentStyle.styles[ext] ?? CommentStyle.defaultStyle;
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;
48
58
  }
49
59
  /**
50
60
  * Register a custom comment style for an extension
@@ -88,10 +98,10 @@ class Parser {
88
98
  static SELECT_REGEX = /@pik:select\s+(\S+)/;
89
99
  static OPTION_REGEX = /@pik:option\s+(\S+)/;
90
100
  /**
91
- * Create a parser for a specific file extension
101
+ * Create a parser for a file path
92
102
  */
93
- static forExtension(extension) {
94
- return new Parser(CommentStyle.fromExtension(extension));
103
+ static forFilePath(filePath) {
104
+ return new Parser(CommentStyle.fromFilePath(filePath));
95
105
  }
96
106
  /**
97
107
  * Parse content string for pik selectors and options
@@ -213,6 +223,13 @@ class CommentManipulator {
213
223
  const { blockOpen, blockClose } = this.commentStyle;
214
224
  return trimmed.startsWith(blockOpen) && trimmed.includes(blockClose);
215
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
+ }
216
233
  /**
217
234
  * Comment out a line if not already commented.
218
235
  * Uses the same comment style as the original if block-commented,
@@ -234,30 +251,48 @@ class CommentManipulator {
234
251
  return `${indent}${this.commentStyle.lineComment} ${trimmed}`;
235
252
  }
236
253
  /**
237
- * Uncomment a line if commented (handles both line and block comments)
254
+ * Uncomment a block comment
255
+ * @throws Error if the line is not a block comment
238
256
  */
239
- uncommentLine(line) {
257
+ uncommentBlockComment(line) {
258
+ if (!this.isBlockCommented(line)) {
259
+ throw new Error("Expected line to be a block comment");
260
+ }
240
261
  const trimmed = line.trimStart();
241
262
  const indent = line.slice(0, line.length - trimmed.length);
242
- if (this.commentStyle.hasBlockComments) {
243
- const { blockOpen, blockClose } = this.commentStyle;
244
- if (trimmed.startsWith(blockOpen)) {
245
- const afterOpen = trimmed.slice(blockOpen.length);
246
- const closeIndex = afterOpen.indexOf(blockClose);
247
- if (closeIndex !== -1) {
248
- const content2 = afterOpen.slice(0, closeIndex).trim();
249
- const rest = afterOpen.slice(closeIndex + blockClose.length);
250
- return `${indent}${content2}${rest}`;
251
- }
252
- }
253
- }
254
- if (!trimmed.startsWith(this.commentStyle.lineComment)) {
255
- return line;
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");
256
277
  }
278
+ const trimmed = line.trimStart();
279
+ const indent = line.slice(0, line.length - trimmed.length);
257
280
  const withoutComment = trimmed.slice(this.commentStyle.lineComment.length);
258
281
  const content = withoutComment.startsWith(" ") ? withoutComment.slice(1) : withoutComment;
259
282
  return `${indent}${content}`;
260
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
+ }
261
296
  }
262
297
  class Switcher extends CommentManipulator {
263
298
  /**
@@ -274,10 +309,10 @@ class Switcher extends CommentManipulator {
274
309
  }
275
310
  class SingleSwitcher extends Switcher {
276
311
  /**
277
- * Create a switcher for a specific file extension
312
+ * Create a switcher for a file path
278
313
  */
279
- static forExtension(extension) {
280
- return new SingleSwitcher(CommentStyle.fromExtension(extension));
314
+ static forFilePath(filePath) {
315
+ return new SingleSwitcher(CommentStyle.fromFilePath(filePath));
281
316
  }
282
317
  /**
283
318
  * Switch to a specific option, deactivating all others
@@ -13,12 +13,26 @@ export declare abstract class CommentManipulator {
13
13
  * Check if a line uses block comment style
14
14
  */
15
15
  protected isBlockCommented(line: string): boolean;
16
+ /**
17
+ * Check if a line is a line comment (not a block comment)
18
+ */
19
+ private isLineComment;
16
20
  /**
17
21
  * Comment out a line if not already commented.
18
22
  * Uses the same comment style as the original if block-commented,
19
23
  * otherwise uses line comment style.
20
24
  */
21
25
  protected commentLine(line: string, useBlockStyle?: boolean): string;
26
+ /**
27
+ * Uncomment a block comment
28
+ * @throws Error if the line is not a block comment
29
+ */
30
+ private uncommentBlockComment;
31
+ /**
32
+ * Uncomment a line comment
33
+ * @throws Error if the line is not a line comment
34
+ */
35
+ private uncommentLineComment;
22
36
  /**
23
37
  * Uncomment a line if commented (handles both line and block comments)
24
38
  */
@@ -1 +1 @@
1
- {"version":3,"file":"comment-manipulator.d.ts","sourceRoot":"","sources":["../../src/lib/comment-manipulator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;GAEG;AACH,8BAAsB,kBAAkB;IAC1B,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY;gBAA1B,YAAY,EAAE,YAAY;IAEzD;;OAEG;IACH,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAmBhD;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAUjD;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,MAAM;IAwBlE;;OAEG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAkC9C"}
1
+ {"version":3,"file":"comment-manipulator.d.ts","sourceRoot":"","sources":["../../src/lib/comment-manipulator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;GAEG;AACH,8BAAsB,kBAAkB;IAC1B,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY;gBAA1B,YAAY,EAAE,YAAY;IAEzD;;OAEG;IACH,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAmBhD;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAUjD;;OAEG;IACH,OAAO,CAAC,aAAa;IAKrB;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,MAAM;IAwBlE;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAiB5B;;OAEG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAa9C"}
@@ -9,9 +9,9 @@ export declare class Parser {
9
9
  private static readonly OPTION_REGEX;
10
10
  constructor(commentStyle: CommentStyle);
11
11
  /**
12
- * Create a parser for a specific file extension
12
+ * Create a parser for a file path
13
13
  */
14
- static forExtension(extension: string): Parser;
14
+ static forFilePath(filePath: string): Parser;
15
15
  /**
16
16
  * Parse content string for pik selectors and options
17
17
  */
@@ -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,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI9C;;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,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"}
@@ -5,9 +5,9 @@ import { Switcher } from './switcher.js';
5
5
  */
6
6
  export declare class SingleSwitcher extends Switcher {
7
7
  /**
8
- * Create a switcher for a specific file extension
8
+ * Create a switcher for a file path
9
9
  */
10
- static forExtension(extension: string): SingleSwitcher;
10
+ static forFilePath(filePath: string): SingleSwitcher;
11
11
  /**
12
12
  * Switch to a specific option, deactivating all others
13
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"single-switcher.d.ts","sourceRoot":"","sources":["../../src/lib/single-switcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC;;GAEG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc;IAItD;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;CAyBxE"}
1
+ {"version":3,"file":"single-switcher.d.ts","sourceRoot":"","sources":["../../src/lib/single-switcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC;;GAEG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc;IAIpD;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;CAyBxE"}
@@ -18,9 +18,11 @@ export declare class CommentStyle {
18
18
  */
19
19
  get hasBlockComments(): boolean;
20
20
  /**
21
- * Get comment style for a file extension
21
+ * Get comment style for a file path.
22
+ *
23
+ * Handles dotfiles like `.env`, `.env.local`, `.env.development` correctly.
22
24
  */
23
- static fromExtension(extension: string): CommentStyle;
25
+ static fromFilePath(filePath: string): CommentStyle;
24
26
  /**
25
27
  * Register a custom comment style for an extension
26
28
  */
@@ -1 +1 @@
1
- {"version":3,"file":"comment-style.d.ts","sourceRoot":"","sources":["../../../src/lib/types/comment-style.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,YAAY;IAiCrB,4CAA4C;aAC5B,WAAW,EAAE,MAAM;IAjCrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAsB5B;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAA0B;IAE9D,2CAA2C;IAC3C,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnC,0CAA0C;IAC1C,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;;IAGlC,4CAA4C;IAC5B,WAAW,EAAE,MAAM,EACnC,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM;IAMrB;;OAEG;IACH,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IAKrD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;CAI9D"}
1
+ {"version":3,"file":"comment-style.d.ts","sourceRoot":"","sources":["../../../src/lib/types/comment-style.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,YAAY;IAiCrB,4CAA4C;aAC5B,WAAW,EAAE,MAAM;IAjCrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAsB5B;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAA0B;IAE9D,2CAA2C;IAC3C,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnC,0CAA0C;IAC1C,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;;IAGlC,4CAA4C;IAC5B,WAAW,EAAE,MAAM,EACnC,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM;IAMrB;;OAEG;IACH,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY;IAkBnD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;CAI9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsst/pik-core",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Core library for parsing and switching @pik config markers",
5
5
  "type": "module",
6
6
  "license": "MIT",