@lsst/pik-core 0.4.1 → 0.5.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/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export type { Option, Selector, ParseResult } from './lib/types/index.js';
1
+ export type { Option, Selector, ParseResult, PikPlugin } from './lib/types/index.js';
2
2
  export { CommentStyle } from './lib/types/index.js';
3
+ export { defineConfig, loadConfig, type PikConfig } from './lib/config.js';
3
4
  export { Parser } from './lib/parser.js';
4
5
  export { Switcher } from './lib/switcher.js';
5
6
  export { SingleSwitcher } from './lib/single-switcher.js';
@@ -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,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,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,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG3E,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"}
package/dist/index.js CHANGED
@@ -1,160 +1,204 @@
1
- class n {
2
- constructor(t) {
3
- this.lineComment = t;
1
+ import { pathToFileURL } from "url";
2
+ import { existsSync } from "fs";
3
+ import { resolve } from "path";
4
+ class CommentStyle {
5
+ constructor(lineComment) {
6
+ this.lineComment = lineComment;
4
7
  }
5
8
  static styles = {
6
9
  // JavaScript/TypeScript
7
- js: new n("//"),
8
- ts: new n("//"),
9
- jsx: new n("//"),
10
- tsx: new n("//"),
11
- mjs: new n("//"),
12
- mts: new n("//"),
10
+ js: new CommentStyle("//"),
11
+ ts: new CommentStyle("//"),
12
+ jsx: new CommentStyle("//"),
13
+ tsx: new CommentStyle("//"),
14
+ mjs: new CommentStyle("//"),
15
+ mts: new CommentStyle("//"),
13
16
  // HTML (for script tags)
14
- html: new n("//"),
15
- htm: new n("//"),
17
+ html: new CommentStyle("//"),
18
+ htm: new CommentStyle("//"),
16
19
  // Config files
17
- yaml: new n("#"),
18
- yml: new n("#"),
20
+ yaml: new CommentStyle("#"),
21
+ yml: new CommentStyle("#"),
19
22
  // Shell
20
- sh: new n("#"),
21
- bash: new n("#"),
22
- zsh: new n("#"),
23
+ sh: new CommentStyle("#"),
24
+ bash: new CommentStyle("#"),
25
+ zsh: new CommentStyle("#"),
23
26
  // Python
24
- py: new n("#"),
27
+ py: new CommentStyle("#"),
25
28
  // Env files
26
- env: new n("#")
29
+ env: new CommentStyle("#")
27
30
  };
28
- static defaultStyle = new n("//");
31
+ static defaultStyle = new CommentStyle("//");
29
32
  /**
30
33
  * Get comment style for a file extension
31
34
  */
32
- static fromExtension(t) {
33
- const s = t.replace(/^\./, "").toLowerCase();
34
- return n.styles[s] ?? n.defaultStyle;
35
+ static fromExtension(extension) {
36
+ const ext = extension.replace(/^\./, "").toLowerCase();
37
+ return CommentStyle.styles[ext] ?? CommentStyle.defaultStyle;
35
38
  }
36
39
  /**
37
40
  * Register a custom comment style for an extension
38
41
  */
39
- static register(t, s) {
40
- const i = t.replace(/^\./, "").toLowerCase();
41
- n.styles[i] = s;
42
+ static register(extension, style) {
43
+ const ext = extension.replace(/^\./, "").toLowerCase();
44
+ CommentStyle.styles[ext] = style;
42
45
  }
43
46
  }
44
- class a {
45
- constructor(t) {
46
- this.commentStyle = t;
47
+ function defineConfig(config) {
48
+ return config;
49
+ }
50
+ const CONFIG_FILES = [
51
+ "pik.config.mts",
52
+ "pik.config.ts",
53
+ "pik.config.mjs",
54
+ "pik.config.js",
55
+ ".pik.config.mts",
56
+ ".pik.config.ts",
57
+ ".pik.config.mjs",
58
+ ".pik.config.js"
59
+ ];
60
+ async function loadConfig(cwd = process.cwd()) {
61
+ for (const configFile of CONFIG_FILES) {
62
+ const configPath = resolve(cwd, configFile);
63
+ if (existsSync(configPath)) {
64
+ const configUrl = pathToFileURL(configPath).href;
65
+ const module = await import(configUrl);
66
+ return module.default;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ class Parser {
72
+ constructor(commentStyle) {
73
+ this.commentStyle = commentStyle;
47
74
  }
48
75
  static SELECT_REGEX = /@pik:select\s+(\S+)/;
49
76
  static OPTION_REGEX = /@pik:option\s+(\S+)/;
50
77
  /**
51
78
  * Create a parser for a specific file extension
52
79
  */
53
- static forExtension(t) {
54
- return new a(n.fromExtension(t));
80
+ static forExtension(extension) {
81
+ return new Parser(CommentStyle.fromExtension(extension));
55
82
  }
56
83
  /**
57
84
  * Parse content string for pik selectors and options
58
85
  */
59
- parse(t) {
60
- const s = t.split(`
61
- `), i = [];
62
- let e = null;
63
- for (let o = 0; o < s.length; o++) {
64
- const c = s[o], r = o + 1, l = c.match(a.SELECT_REGEX);
65
- if (l) {
66
- e = {
67
- name: l[1],
68
- line: r,
86
+ parse(content) {
87
+ const lines = content.split("\n");
88
+ const selectors = [];
89
+ let currentSelector = null;
90
+ for (let i = 0; i < lines.length; i++) {
91
+ const line = lines[i];
92
+ const lineNumber = i + 1;
93
+ const selectMatch = line.match(Parser.SELECT_REGEX);
94
+ if (selectMatch) {
95
+ currentSelector = {
96
+ name: selectMatch[1],
97
+ line: lineNumber,
69
98
  options: []
70
- }, i.push(e);
99
+ };
100
+ selectors.push(currentSelector);
71
101
  continue;
72
102
  }
73
- const h = c.match(a.OPTION_REGEX);
74
- if (h && e) {
75
- const w = {
76
- name: h[1],
77
- line: r,
78
- content: c,
79
- isActive: !this.isLineCommented(c)
103
+ const optionMatch = line.match(Parser.OPTION_REGEX);
104
+ if (optionMatch && currentSelector) {
105
+ const option = {
106
+ name: optionMatch[1],
107
+ line: lineNumber,
108
+ content: line,
109
+ isActive: !this.isLineCommented(line)
80
110
  };
81
- e.options.push(w);
111
+ currentSelector.options.push(option);
82
112
  }
83
113
  }
84
- return { selectors: i, content: t };
114
+ return { selectors, content };
85
115
  }
86
116
  /**
87
117
  * Check if a line is commented out
88
118
  */
89
- isLineCommented(t) {
90
- return t.trimStart().startsWith(this.commentStyle.lineComment);
119
+ isLineCommented(line) {
120
+ return line.trimStart().startsWith(this.commentStyle.lineComment);
91
121
  }
92
122
  }
93
- class p {
94
- constructor(t) {
95
- this.commentStyle = t;
123
+ class CommentManipulator {
124
+ constructor(commentStyle) {
125
+ this.commentStyle = commentStyle;
96
126
  }
97
127
  /**
98
128
  * Check if a line is commented out
99
129
  */
100
- isLineCommented(t) {
101
- return t.trimStart().startsWith(this.commentStyle.lineComment);
130
+ isLineCommented(line) {
131
+ return line.trimStart().startsWith(this.commentStyle.lineComment);
102
132
  }
103
133
  /**
104
134
  * Comment out a line if not already commented
105
135
  */
106
- commentLine(t) {
107
- const s = t.trimStart();
108
- return s.startsWith(this.commentStyle.lineComment) ? t : `${t.slice(0, t.length - s.length)}${this.commentStyle.lineComment} ${s}`;
136
+ commentLine(line) {
137
+ const trimmed = line.trimStart();
138
+ if (trimmed.startsWith(this.commentStyle.lineComment)) {
139
+ return line;
140
+ }
141
+ const indent = line.slice(0, line.length - trimmed.length);
142
+ return `${indent}${this.commentStyle.lineComment} ${trimmed}`;
109
143
  }
110
144
  /**
111
145
  * Uncomment a line if commented
112
146
  */
113
- uncommentLine(t) {
114
- const s = t.trimStart();
115
- if (!s.startsWith(this.commentStyle.lineComment))
116
- return t;
117
- const i = t.slice(0, t.length - s.length), e = s.slice(this.commentStyle.lineComment.length), o = e.startsWith(" ") ? e.slice(1) : e;
118
- return `${i}${o}`;
147
+ uncommentLine(line) {
148
+ const trimmed = line.trimStart();
149
+ if (!trimmed.startsWith(this.commentStyle.lineComment)) {
150
+ return line;
151
+ }
152
+ const indent = line.slice(0, line.length - trimmed.length);
153
+ const withoutComment = trimmed.slice(this.commentStyle.lineComment.length);
154
+ const content = withoutComment.startsWith(" ") ? withoutComment.slice(1) : withoutComment;
155
+ return `${indent}${content}`;
119
156
  }
120
157
  }
121
- class f extends p {
158
+ class Switcher extends CommentManipulator {
122
159
  /**
123
160
  * Validate that the option exists in the selector
124
161
  */
125
- validateOption(t, s) {
126
- if (!t.options.find((e) => e.name === s))
162
+ validateOption(selector, optionName) {
163
+ const option = selector.options.find((o) => o.name === optionName);
164
+ if (!option) {
127
165
  throw new Error(
128
- `Option "${s}" not found in selector "${t.name}"`
166
+ `Option "${optionName}" not found in selector "${selector.name}"`
129
167
  );
168
+ }
130
169
  }
131
170
  }
132
- class m extends f {
171
+ class SingleSwitcher extends Switcher {
133
172
  /**
134
173
  * Create a switcher for a specific file extension
135
174
  */
136
- static forExtension(t) {
137
- return new m(n.fromExtension(t));
175
+ static forExtension(extension) {
176
+ return new SingleSwitcher(CommentStyle.fromExtension(extension));
138
177
  }
139
178
  /**
140
179
  * Switch to a specific option, deactivating all others
141
180
  */
142
- switch(t, s, i) {
143
- this.validateOption(s, i);
144
- const e = t.split(`
145
- `);
146
- for (const o of s.options) {
147
- const c = o.line - 1, r = e[c];
148
- o.name === i ? e[c] = this.uncommentLine(r) : e[c] = this.commentLine(r);
181
+ switch(content, selector, optionName) {
182
+ this.validateOption(selector, optionName);
183
+ const lines = content.split("\n");
184
+ for (const option of selector.options) {
185
+ const lineIndex = option.line - 1;
186
+ const line = lines[lineIndex];
187
+ if (option.name === optionName) {
188
+ lines[lineIndex] = this.uncommentLine(line);
189
+ } else {
190
+ lines[lineIndex] = this.commentLine(line);
191
+ }
149
192
  }
150
- return e.join(`
151
- `);
193
+ return lines.join("\n");
152
194
  }
153
195
  }
154
196
  export {
155
- p as CommentManipulator,
156
- n as CommentStyle,
157
- a as Parser,
158
- m as SingleSwitcher,
159
- f as Switcher
197
+ CommentManipulator,
198
+ CommentStyle,
199
+ Parser,
200
+ SingleSwitcher,
201
+ Switcher,
202
+ defineConfig,
203
+ loadConfig
160
204
  };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Base config interface - plugins extend this via declaration merging
3
+ */
4
+ export interface PikConfig {
5
+ [pluginName: string]: unknown;
6
+ }
7
+ /**
8
+ * Helper function for type-safe config definition
9
+ */
10
+ export declare function defineConfig<T extends PikConfig>(config: T): T;
11
+ /**
12
+ * Load pik config from the current directory
13
+ */
14
+ export declare function loadConfig(cwd?: string): Promise<PikConfig | null>;
15
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAE9D;AAaD;;GAEG;AACH,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAYvF"}
@@ -2,4 +2,5 @@ export type { Option } from './option.js';
2
2
  export type { Selector } from './selector.js';
3
3
  export type { ParseResult } from './parse-result.js';
4
4
  export { CommentStyle } from './comment-style.js';
5
+ export type { PikPlugin } from './plugin.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -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"}
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"}
@@ -0,0 +1,20 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Plugin interface for pik CLI plugins.
4
+ */
5
+ export interface PikPlugin {
6
+ /** Display name of the plugin */
7
+ name: string;
8
+ /** Short description shown in help and menu */
9
+ description: string;
10
+ /** Command name used to invoke the plugin (e.g., "select", "worktree") */
11
+ command: string;
12
+ /** Alternative command names */
13
+ aliases?: string[];
14
+ /**
15
+ * Register the plugin's commands with the CLI.
16
+ * @param program - The commander program or command to attach to
17
+ */
18
+ register: (program: Command) => void;
19
+ }
20
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/types/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IAEb,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IAEpB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAEhB,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lsst/pik-core",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Core library for parsing and switching @pik config markers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -33,5 +33,7 @@
33
33
  "dist",
34
34
  "!**/*.tsbuildinfo"
35
35
  ],
36
- "dependencies": {}
36
+ "dependencies": {
37
+ "commander": "^14.0.0"
38
+ }
37
39
  }