@lsst/pik-plugin-select 0.4.2
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 +11 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +224 -0
- package/dist/lib/commands/list.d.ts +4 -0
- package/dist/lib/commands/list.d.ts.map +1 -0
- package/dist/lib/commands/set.d.ts +4 -0
- package/dist/lib/commands/set.d.ts.map +1 -0
- package/dist/lib/commands/switch.d.ts +4 -0
- package/dist/lib/commands/switch.d.ts.map +1 -0
- package/dist/lib/plugin.d.ts +3 -0
- package/dist/lib/plugin.d.ts.map +1 -0
- package/dist/lib/scanner.d.ts +13 -0
- package/dist/lib/scanner.d.ts.map +1 -0
- package/dist/lib/types.d.ts +16 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# plugin-select
|
|
2
|
+
|
|
3
|
+
This library was generated with [Nx](https://nx.dev).
|
|
4
|
+
|
|
5
|
+
## Building
|
|
6
|
+
|
|
7
|
+
Run `nx build plugin-select` to build the library.
|
|
8
|
+
|
|
9
|
+
## Running unit tests
|
|
10
|
+
|
|
11
|
+
Run `nx test plugin-select` to execute the unit tests via [Vitest](https://vitest.dev/).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
import { extname, relative } from "path";
|
|
4
|
+
import { Parser, loadConfig, SingleSwitcher } from "@lsst/pik-core";
|
|
5
|
+
import { readFile, writeFile } from "fs/promises";
|
|
6
|
+
import { glob } from "glob";
|
|
7
|
+
import { select, Separator } from "@inquirer/prompts";
|
|
8
|
+
class Scanner {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
}
|
|
12
|
+
async scan(cwd = process.cwd()) {
|
|
13
|
+
const files = await glob(this.config.include, {
|
|
14
|
+
cwd,
|
|
15
|
+
absolute: true,
|
|
16
|
+
nodir: true
|
|
17
|
+
});
|
|
18
|
+
const results = [];
|
|
19
|
+
for (const filePath of files) {
|
|
20
|
+
const content = await readFile(filePath, "utf-8");
|
|
21
|
+
const extension = extname(filePath);
|
|
22
|
+
const parser = Parser.forExtension(extension);
|
|
23
|
+
const { selectors } = parser.parse(content);
|
|
24
|
+
if (selectors.length > 0) {
|
|
25
|
+
results.push({ path: filePath, selectors, content });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return results;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const listCommand = new Command("list").alias("ls").description("List all selectors and their current state").option("--json", "Output in JSON format").action(async (options) => {
|
|
32
|
+
const config = await loadConfig();
|
|
33
|
+
if (!config?.select) {
|
|
34
|
+
if (options.json) {
|
|
35
|
+
console.log(JSON.stringify({ error: 'No pik config found or missing "select" section' }));
|
|
36
|
+
} else {
|
|
37
|
+
console.error(pc.red('No pik config found or missing "select" section'));
|
|
38
|
+
}
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
const scanner = new Scanner(config.select);
|
|
42
|
+
const results = await scanner.scan();
|
|
43
|
+
if (options.json) {
|
|
44
|
+
const jsonOutput = results.flatMap(
|
|
45
|
+
(file) => file.selectors.map((selector) => ({
|
|
46
|
+
name: selector.name,
|
|
47
|
+
file: relative(process.cwd(), file.path),
|
|
48
|
+
line: selector.line,
|
|
49
|
+
activeOption: selector.options.find((o) => o.isActive)?.name ?? null,
|
|
50
|
+
options: selector.options.map((o) => ({
|
|
51
|
+
name: o.name,
|
|
52
|
+
isActive: o.isActive
|
|
53
|
+
}))
|
|
54
|
+
}))
|
|
55
|
+
);
|
|
56
|
+
console.log(JSON.stringify(jsonOutput, null, 2));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (results.length === 0) {
|
|
60
|
+
console.log(pc.yellow("No selectors found"));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
for (const file of results) {
|
|
64
|
+
const relativePath = relative(process.cwd(), file.path);
|
|
65
|
+
console.log(pc.cyan(relativePath));
|
|
66
|
+
for (const selector of file.selectors) {
|
|
67
|
+
const activeOption = selector.options.find((o) => o.isActive);
|
|
68
|
+
const activeLabel = activeOption ? pc.green(activeOption.name) : pc.yellow("none");
|
|
69
|
+
console.log(` ${pc.bold(selector.name)}: ${activeLabel}`);
|
|
70
|
+
for (const option of selector.options) {
|
|
71
|
+
const marker = option.isActive ? pc.green("●") : pc.dim("○");
|
|
72
|
+
console.log(` ${marker} ${option.name}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
console.log();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
const setCommand = new Command("set").description("Set a specific option for a selector").argument("<selector>", "Selector name").argument("<option>", "Option to activate").action(async (selectorName, optionName) => {
|
|
79
|
+
const config = await loadConfig();
|
|
80
|
+
if (!config?.select) {
|
|
81
|
+
console.error(pc.red('No pik config found or missing "select" section'));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
const scanner = new Scanner(config.select);
|
|
85
|
+
const results = await scanner.scan();
|
|
86
|
+
let found = false;
|
|
87
|
+
for (const file of results) {
|
|
88
|
+
const selector = file.selectors.find((s) => s.name === selectorName);
|
|
89
|
+
if (selector) {
|
|
90
|
+
found = true;
|
|
91
|
+
const extension = extname(file.path);
|
|
92
|
+
const switcher = SingleSwitcher.forExtension(extension);
|
|
93
|
+
try {
|
|
94
|
+
const newContent = switcher.switch(file.content, selector, optionName);
|
|
95
|
+
await writeFile(file.path, newContent);
|
|
96
|
+
const relativePath = relative(process.cwd(), file.path);
|
|
97
|
+
console.log(
|
|
98
|
+
pc.green(`✓ Set ${pc.bold(selectorName)} to ${pc.bold(optionName)} in ${relativePath}`)
|
|
99
|
+
);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (error instanceof Error) {
|
|
102
|
+
console.error(pc.red(error.message));
|
|
103
|
+
}
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!found) {
|
|
109
|
+
console.error(pc.red(`Selector "${selectorName}" not found`));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
const BACK_VALUE = /* @__PURE__ */ Symbol("back");
|
|
114
|
+
const EXIT_VALUE = /* @__PURE__ */ Symbol("exit");
|
|
115
|
+
function isExitPromptError(error) {
|
|
116
|
+
return error instanceof Error && error.name === "ExitPromptError";
|
|
117
|
+
}
|
|
118
|
+
const switchCommand = new Command("switch").alias("sw").description("Interactively switch options").action(async () => {
|
|
119
|
+
const config = await loadConfig();
|
|
120
|
+
if (!config?.select) {
|
|
121
|
+
console.error(pc.red('No pik config found or missing "select" section'));
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
const scanner = new Scanner(config.select);
|
|
125
|
+
const results = await scanner.scan();
|
|
126
|
+
if (results.length === 0) {
|
|
127
|
+
console.log(pc.yellow("No selectors found"));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const choices = [];
|
|
131
|
+
for (const file of results) {
|
|
132
|
+
for (const selector of file.selectors) {
|
|
133
|
+
choices.push({ file, selector });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
while (true) {
|
|
137
|
+
let selectedChoice;
|
|
138
|
+
try {
|
|
139
|
+
selectedChoice = await select({
|
|
140
|
+
message: "Select a selector to switch",
|
|
141
|
+
choices: [
|
|
142
|
+
...choices.map((choice) => {
|
|
143
|
+
const relativePath2 = relative(process.cwd(), choice.file.path);
|
|
144
|
+
const activeOption = choice.selector.options.find((o) => o.isActive);
|
|
145
|
+
const current = activeOption ? pc.dim(` (${activeOption.name})`) : "";
|
|
146
|
+
return {
|
|
147
|
+
name: `${choice.selector.name}${current} ${pc.dim(`- ${relativePath2}`)}`,
|
|
148
|
+
value: choice
|
|
149
|
+
};
|
|
150
|
+
}),
|
|
151
|
+
new Separator(),
|
|
152
|
+
{ name: pc.dim("Exit"), value: EXIT_VALUE }
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (isExitPromptError(error)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
if (selectedChoice === EXIT_VALUE) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
let selectedOption;
|
|
165
|
+
try {
|
|
166
|
+
selectedOption = await select({
|
|
167
|
+
message: `Select option for ${pc.bold(selectedChoice.selector.name)}`,
|
|
168
|
+
choices: [
|
|
169
|
+
...selectedChoice.selector.options.map((option) => ({
|
|
170
|
+
name: option.isActive ? `${option.name} ${pc.green("(current)")}` : option.name,
|
|
171
|
+
value: option.name
|
|
172
|
+
})),
|
|
173
|
+
new Separator(),
|
|
174
|
+
{ name: pc.dim("← Back"), value: BACK_VALUE }
|
|
175
|
+
]
|
|
176
|
+
});
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (isExitPromptError(error)) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
if (selectedOption === BACK_VALUE) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const extension = extname(selectedChoice.file.path);
|
|
187
|
+
const switcher = SingleSwitcher.forExtension(extension);
|
|
188
|
+
const newContent = switcher.switch(
|
|
189
|
+
selectedChoice.file.content,
|
|
190
|
+
selectedChoice.selector,
|
|
191
|
+
selectedOption
|
|
192
|
+
);
|
|
193
|
+
await writeFile(selectedChoice.file.path, newContent);
|
|
194
|
+
const relativePath = relative(process.cwd(), selectedChoice.file.path);
|
|
195
|
+
console.log(
|
|
196
|
+
pc.green(
|
|
197
|
+
`✓ Set ${pc.bold(selectedChoice.selector.name)} to ${pc.bold(selectedOption)} in ${relativePath}`
|
|
198
|
+
)
|
|
199
|
+
);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
const selectPlugin = {
|
|
204
|
+
name: "Select",
|
|
205
|
+
description: "Switch config options using @pik markers",
|
|
206
|
+
command: "select",
|
|
207
|
+
aliases: ["sel"],
|
|
208
|
+
register(program) {
|
|
209
|
+
const selectCmd = program.command("select").alias("sel").description("Switch config options using @pik markers");
|
|
210
|
+
selectCmd.addCommand(listCommand);
|
|
211
|
+
selectCmd.addCommand(setCommand);
|
|
212
|
+
selectCmd.addCommand(switchCommand);
|
|
213
|
+
selectCmd.action(async () => {
|
|
214
|
+
await switchCommand.parseAsync([], { from: "user" });
|
|
215
|
+
});
|
|
216
|
+
program.addCommand(listCommand.copyInheritedSettings(program), { hidden: true });
|
|
217
|
+
program.addCommand(setCommand.copyInheritedSettings(program), { hidden: true });
|
|
218
|
+
program.addCommand(switchCommand.copyInheritedSettings(program), { hidden: true });
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
export {
|
|
222
|
+
Scanner,
|
|
223
|
+
selectPlugin
|
|
224
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/lib/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,OAAO,aAAa,CAAC;AAMrB,eAAO,MAAM,WAAW,SA6DpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../../src/lib/commands/set.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,OAAO,aAAa,CAAC;AAErB,eAAO,MAAM,UAAU,SA8CnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../../src/lib/commands/switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,OAAO,aAAa,CAAC;AAcrB,eAAO,MAAM,aAAa,SA0GtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/lib/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD,eAAO,MAAM,YAAY,EAAE,SA4B1B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Selector } from '@lsst/pik-core';
|
|
2
|
+
import type { SelectConfig } from './types.js';
|
|
3
|
+
export interface FileResult {
|
|
4
|
+
path: string;
|
|
5
|
+
selectors: Selector[];
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class Scanner {
|
|
9
|
+
private readonly config;
|
|
10
|
+
constructor(config: SelectConfig);
|
|
11
|
+
scan(cwd?: string): Promise<FileResult[]>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/lib/scanner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAE3C,IAAI,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAsB/D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the select plugin
|
|
3
|
+
*/
|
|
4
|
+
export interface SelectConfig {
|
|
5
|
+
/** File patterns to scan for @pik markers */
|
|
6
|
+
include: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Extend PikConfig to include select plugin config
|
|
10
|
+
*/
|
|
11
|
+
declare module '@lsst/pik-core' {
|
|
12
|
+
interface PikConfig {
|
|
13
|
+
select?: SelectConfig;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,OAAO,QAAQ,gBAAgB,CAAC;IAC9B,UAAU,SAAS;QACjB,MAAM,CAAC,EAAE,YAAY,CAAC;KACvB;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lsst/pik-plugin-select",
|
|
3
|
+
"version": "0.4.2",
|
|
4
|
+
"description": "Config selector plugin for pik CLI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Yurii Tatar <lsst25@gmail.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/lsst25/pik.git",
|
|
11
|
+
"directory": "packages/plugin-select"
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
"./package.json": "./package.json",
|
|
18
|
+
".": {
|
|
19
|
+
"@pik/source": "./src/index.ts",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"!**/*.tsbuildinfo"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@lsst/pik-core": "*",
|
|
31
|
+
"@inquirer/prompts": "^8.1.0",
|
|
32
|
+
"commander": "^14.0.2",
|
|
33
|
+
"glob": "^10.5.0",
|
|
34
|
+
"picocolors": "^1.1.1"
|
|
35
|
+
}
|
|
36
|
+
}
|