@lsst/pik 0.0.1
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 +71 -0
- package/dist/bin/pik.d.ts +3 -0
- package/dist/bin/pik.d.ts.map +1 -0
- package/dist/bin/pik.js +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/lib/commands/list.d.ts +3 -0
- package/dist/lib/commands/list.d.ts.map +1 -0
- package/dist/lib/commands/list.js +37 -0
- package/dist/lib/commands/set.d.ts +3 -0
- package/dist/lib/commands/set.d.ts.map +1 -0
- package/dist/lib/commands/set.js +45 -0
- package/dist/lib/commands/switch.d.ts +3 -0
- package/dist/lib/commands/switch.d.ts.map +1 -0
- package/dist/lib/commands/switch.js +59 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +16 -0
- package/dist/lib/config.spec.d.ts +2 -0
- package/dist/lib/config.spec.d.ts.map +1 -0
- package/dist/lib/config.spec.js +35 -0
- package/dist/lib/program.d.ts +3 -0
- package/dist/lib/program.d.ts.map +1 -0
- package/dist/lib/program.js +16 -0
- package/dist/lib/scanner.d.ts +13 -0
- package/dist/lib/scanner.d.ts.map +1 -0
- package/dist/lib/scanner.js +28 -0
- package/dist/lib/scanner.spec.d.ts +2 -0
- package/dist/lib/scanner.spec.d.ts.map +1 -0
- package/dist/lib/scanner.spec.js +57 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @lsst/pik
|
|
2
|
+
|
|
3
|
+
CLI tool for switching config options in source files using `@pik` markers.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @lsst/pik
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### 1. Add markers to your files
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// @pik:select Environment
|
|
17
|
+
// const env = 'DEV'; // @pik:option DEV
|
|
18
|
+
const env = 'LOCAL'; // @pik:option LOCAL
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 2. Create a config file
|
|
22
|
+
|
|
23
|
+
Create `pik.config.ts` in your project root:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { defineConfig } from '@lsst/pik';
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
include: ['src/**/*.ts', '.env'],
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 3. Run commands
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# List all selectors and their current state
|
|
37
|
+
pik list
|
|
38
|
+
|
|
39
|
+
# Set a specific option
|
|
40
|
+
pik set Environment DEV
|
|
41
|
+
|
|
42
|
+
# Interactive mode
|
|
43
|
+
pik switch
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Commands
|
|
47
|
+
|
|
48
|
+
| Command | Alias | Description |
|
|
49
|
+
|---------|-------|-------------|
|
|
50
|
+
| `pik list` | `ls` | Show all selectors and their current state |
|
|
51
|
+
| `pik set <selector> <option>` | - | Set an option directly |
|
|
52
|
+
| `pik switch` | `sw` | Interactive selection mode |
|
|
53
|
+
| `pik` | - | Same as `pik switch` |
|
|
54
|
+
|
|
55
|
+
## Marker Syntax
|
|
56
|
+
|
|
57
|
+
- `@pik:select <name>` - Defines a selector group
|
|
58
|
+
- `@pik:option <name>` - Marks an option within a selector
|
|
59
|
+
|
|
60
|
+
Commented lines are inactive, uncommented lines are active.
|
|
61
|
+
|
|
62
|
+
## Supported Comment Styles
|
|
63
|
+
|
|
64
|
+
| Extensions | Comment Style |
|
|
65
|
+
|------------|---------------|
|
|
66
|
+
| `.ts`, `.js`, `.tsx`, `.jsx` | `//` |
|
|
67
|
+
| `.sh`, `.bash`, `.zsh`, `.py`, `.yaml`, `.yml`, `.env` | `#` |
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pik.d.ts","sourceRoot":"","sources":["../../src/bin/pik.ts"],"names":[],"mappings":""}
|
package/dist/bin/pik.js
ADDED
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,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -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;AAMpC,eAAO,MAAM,WAAW,SAuCpB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { relative } from 'path';
|
|
4
|
+
import { loadConfig } from '../config.js';
|
|
5
|
+
import { Scanner } from '../scanner.js';
|
|
6
|
+
export const listCommand = new Command('list')
|
|
7
|
+
.alias('ls')
|
|
8
|
+
.description('List all selectors and their current state')
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const config = await loadConfig();
|
|
11
|
+
if (!config) {
|
|
12
|
+
console.error(pc.red('No pik.config.ts found'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const scanner = new Scanner(config);
|
|
16
|
+
const results = await scanner.scan();
|
|
17
|
+
if (results.length === 0) {
|
|
18
|
+
console.log(pc.yellow('No selectors found'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
for (const file of results) {
|
|
22
|
+
const relativePath = relative(process.cwd(), file.path);
|
|
23
|
+
console.log(pc.cyan(relativePath));
|
|
24
|
+
for (const selector of file.selectors) {
|
|
25
|
+
const activeOption = selector.options.find((o) => o.isActive);
|
|
26
|
+
const activeLabel = activeOption
|
|
27
|
+
? pc.green(activeOption.name)
|
|
28
|
+
: pc.yellow('none');
|
|
29
|
+
console.log(` ${pc.bold(selector.name)}: ${activeLabel}`);
|
|
30
|
+
for (const option of selector.options) {
|
|
31
|
+
const marker = option.isActive ? pc.green('●') : pc.dim('○');
|
|
32
|
+
console.log(` ${marker} ${option.name}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
console.log();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
@@ -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;AAQpC,eAAO,MAAM,UAAU,SA8CnB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { writeFile } from 'fs/promises';
|
|
3
|
+
import { extname, relative } from 'path';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
import { SingleSwitcher } from '@lsst/pik-core';
|
|
6
|
+
import { loadConfig } from '../config.js';
|
|
7
|
+
import { Scanner } from '../scanner.js';
|
|
8
|
+
export const setCommand = new Command('set')
|
|
9
|
+
.description('Set a specific option for a selector')
|
|
10
|
+
.argument('<selector>', 'Selector name')
|
|
11
|
+
.argument('<option>', 'Option to activate')
|
|
12
|
+
.action(async (selectorName, optionName) => {
|
|
13
|
+
const config = await loadConfig();
|
|
14
|
+
if (!config) {
|
|
15
|
+
console.error(pc.red('No pik.config.ts found'));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const scanner = new Scanner(config);
|
|
19
|
+
const results = await scanner.scan();
|
|
20
|
+
let found = false;
|
|
21
|
+
for (const file of results) {
|
|
22
|
+
const selector = file.selectors.find((s) => s.name === selectorName);
|
|
23
|
+
if (selector) {
|
|
24
|
+
found = true;
|
|
25
|
+
const extension = extname(file.path);
|
|
26
|
+
const switcher = SingleSwitcher.forExtension(extension);
|
|
27
|
+
try {
|
|
28
|
+
const newContent = switcher.switch(file.content, selector, optionName);
|
|
29
|
+
await writeFile(file.path, newContent);
|
|
30
|
+
const relativePath = relative(process.cwd(), file.path);
|
|
31
|
+
console.log(pc.green(`✓ Set ${pc.bold(selectorName)} to ${pc.bold(optionName)} in ${relativePath}`));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof Error) {
|
|
35
|
+
console.error(pc.red(error.message));
|
|
36
|
+
}
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!found) {
|
|
42
|
+
console.error(pc.red(`Selector "${selectorName}" not found`));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
@@ -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;AAcpC,eAAO,MAAM,aAAa,SAoEtB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { writeFile } from 'fs/promises';
|
|
3
|
+
import { extname, relative } from 'path';
|
|
4
|
+
import { select } from '@inquirer/prompts';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
import { SingleSwitcher } from '@lsst/pik-core';
|
|
7
|
+
import { loadConfig } from '../config.js';
|
|
8
|
+
import { Scanner } from '../scanner.js';
|
|
9
|
+
export const switchCommand = new Command('switch')
|
|
10
|
+
.alias('sw')
|
|
11
|
+
.description('Interactively switch options')
|
|
12
|
+
.action(async () => {
|
|
13
|
+
const config = await loadConfig();
|
|
14
|
+
if (!config) {
|
|
15
|
+
console.error(pc.red('No pik.config.ts found'));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const scanner = new Scanner(config);
|
|
19
|
+
const results = await scanner.scan();
|
|
20
|
+
if (results.length === 0) {
|
|
21
|
+
console.log(pc.yellow('No selectors found'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Flatten all selectors with their file info
|
|
25
|
+
const choices = [];
|
|
26
|
+
for (const file of results) {
|
|
27
|
+
for (const selector of file.selectors) {
|
|
28
|
+
choices.push({ file, selector });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Select which selector to switch
|
|
32
|
+
const selectedChoice = await select({
|
|
33
|
+
message: 'Select a selector to switch',
|
|
34
|
+
choices: choices.map((choice) => {
|
|
35
|
+
const relativePath = relative(process.cwd(), choice.file.path);
|
|
36
|
+
const activeOption = choice.selector.options.find((o) => o.isActive);
|
|
37
|
+
const current = activeOption ? pc.dim(` (${activeOption.name})`) : '';
|
|
38
|
+
return {
|
|
39
|
+
name: `${choice.selector.name}${current} ${pc.dim(`- ${relativePath}`)}`,
|
|
40
|
+
value: choice,
|
|
41
|
+
};
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
// Select which option to activate
|
|
45
|
+
const selectedOption = await select({
|
|
46
|
+
message: `Select option for ${pc.bold(selectedChoice.selector.name)}`,
|
|
47
|
+
choices: selectedChoice.selector.options.map((option) => ({
|
|
48
|
+
name: option.isActive ? `${option.name} ${pc.green('(current)')}` : option.name,
|
|
49
|
+
value: option.name,
|
|
50
|
+
})),
|
|
51
|
+
});
|
|
52
|
+
// Apply the change
|
|
53
|
+
const extension = extname(selectedChoice.file.path);
|
|
54
|
+
const switcher = SingleSwitcher.forExtension(extension);
|
|
55
|
+
const newContent = switcher.switch(selectedChoice.file.content, selectedChoice.selector, selectedOption);
|
|
56
|
+
await writeFile(selectedChoice.file.path, newContent);
|
|
57
|
+
const relativePath = relative(process.cwd(), selectedChoice.file.path);
|
|
58
|
+
console.log(pc.green(`✓ Set ${pc.bold(selectedChoice.selector.name)} to ${pc.bold(selectedOption)} in ${relativePath}`));
|
|
59
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface PikConfig {
|
|
2
|
+
/** File patterns to scan for @pik markers */
|
|
3
|
+
include: string[];
|
|
4
|
+
}
|
|
5
|
+
export declare function defineConfig(config: PikConfig): PikConfig;
|
|
6
|
+
export declare function loadConfig(cwd?: string): Promise<PikConfig | null>;
|
|
7
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAEzD;AAID,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAWvF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { pathToFileURL } from 'url';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
export function defineConfig(config) {
|
|
5
|
+
return config;
|
|
6
|
+
}
|
|
7
|
+
const CONFIG_FILE = 'pik.config.ts';
|
|
8
|
+
export async function loadConfig(cwd = process.cwd()) {
|
|
9
|
+
const configPath = resolve(cwd, CONFIG_FILE);
|
|
10
|
+
if (!existsSync(configPath)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const configUrl = pathToFileURL(configPath).href;
|
|
14
|
+
const module = await import(configUrl);
|
|
15
|
+
return module.default;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.spec.d.ts","sourceRoot":"","sources":["../../src/lib/config.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { writeFile, mkdir, rm } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { loadConfig, defineConfig } from './config.js';
|
|
6
|
+
describe('config', () => {
|
|
7
|
+
let testDir;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
testDir = join(tmpdir(), `pik-test-${Date.now()}`);
|
|
10
|
+
await mkdir(testDir, { recursive: true });
|
|
11
|
+
});
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
await rm(testDir, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
describe('defineConfig', () => {
|
|
16
|
+
it('should return the config as-is', () => {
|
|
17
|
+
const config = defineConfig({ include: ['*.ts'] });
|
|
18
|
+
expect(config).toEqual({ include: ['*.ts'] });
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('loadConfig', () => {
|
|
22
|
+
it('should return null when no config file exists', async () => {
|
|
23
|
+
const config = await loadConfig(testDir);
|
|
24
|
+
expect(config).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
it('should load config from pik.config.ts', async () => {
|
|
27
|
+
const configContent = `
|
|
28
|
+
export default { include: ['src/**/*.ts'] };
|
|
29
|
+
`;
|
|
30
|
+
await writeFile(join(testDir, 'pik.config.ts'), configContent);
|
|
31
|
+
const config = await loadConfig(testDir);
|
|
32
|
+
expect(config).toEqual({ include: ['src/**/*.ts'] });
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/lib/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,OAAO,SAGG,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import pkg from '../../package.json' with { type: 'json' };
|
|
3
|
+
import { listCommand } from './commands/list.js';
|
|
4
|
+
import { setCommand } from './commands/set.js';
|
|
5
|
+
import { switchCommand } from './commands/switch.js';
|
|
6
|
+
export const program = new Command()
|
|
7
|
+
.name(pkg.name)
|
|
8
|
+
.description(pkg.description)
|
|
9
|
+
.version(pkg.version);
|
|
10
|
+
program.addCommand(listCommand);
|
|
11
|
+
program.addCommand(setCommand);
|
|
12
|
+
program.addCommand(switchCommand);
|
|
13
|
+
// Default command: interactive switch
|
|
14
|
+
program.action(async () => {
|
|
15
|
+
await switchCommand.parseAsync([]);
|
|
16
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Selector } from '@lsst/pik-core';
|
|
2
|
+
import type { PikConfig } from './config.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: PikConfig);
|
|
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,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,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,SAAS;IAExC,IAAI,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAsB/D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { glob } from 'glob';
|
|
3
|
+
import { extname } from 'path';
|
|
4
|
+
import { Parser } from '@lsst/pik-core';
|
|
5
|
+
export class Scanner {
|
|
6
|
+
config;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
}
|
|
10
|
+
async scan(cwd = process.cwd()) {
|
|
11
|
+
const files = await glob(this.config.include, {
|
|
12
|
+
cwd,
|
|
13
|
+
absolute: true,
|
|
14
|
+
nodir: true,
|
|
15
|
+
});
|
|
16
|
+
const results = [];
|
|
17
|
+
for (const filePath of files) {
|
|
18
|
+
const content = await readFile(filePath, 'utf-8');
|
|
19
|
+
const extension = extname(filePath);
|
|
20
|
+
const parser = Parser.forExtension(extension);
|
|
21
|
+
const { selectors } = parser.parse(content);
|
|
22
|
+
if (selectors.length > 0) {
|
|
23
|
+
results.push({ path: filePath, selectors, content });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return results;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.spec.d.ts","sourceRoot":"","sources":["../../src/lib/scanner.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { writeFile, mkdir, rm } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { Scanner } from './scanner.js';
|
|
6
|
+
describe('Scanner', () => {
|
|
7
|
+
let testDir;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
testDir = join(tmpdir(), `pik-scanner-test-${Date.now()}`);
|
|
10
|
+
await mkdir(testDir, { recursive: true });
|
|
11
|
+
});
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
await rm(testDir, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
it('should find files with pik selectors', async () => {
|
|
16
|
+
const fileContent = `
|
|
17
|
+
// @pik:select Environment
|
|
18
|
+
const env = 'DEV'; // @pik:option DEV
|
|
19
|
+
// const env = 'LOCAL'; // @pik:option LOCAL
|
|
20
|
+
`.trim();
|
|
21
|
+
await writeFile(join(testDir, 'config.ts'), fileContent);
|
|
22
|
+
const scanner = new Scanner({ include: ['*.ts'] });
|
|
23
|
+
const results = await scanner.scan(testDir);
|
|
24
|
+
expect(results).toHaveLength(1);
|
|
25
|
+
expect(results[0].selectors).toHaveLength(1);
|
|
26
|
+
expect(results[0].selectors[0].name).toBe('Environment');
|
|
27
|
+
});
|
|
28
|
+
it('should return empty array when no selectors found', async () => {
|
|
29
|
+
await writeFile(join(testDir, 'empty.ts'), 'const x = 1;');
|
|
30
|
+
const scanner = new Scanner({ include: ['*.ts'] });
|
|
31
|
+
const results = await scanner.scan(testDir);
|
|
32
|
+
expect(results).toHaveLength(0);
|
|
33
|
+
});
|
|
34
|
+
it('should scan multiple files', async () => {
|
|
35
|
+
const file1 = `
|
|
36
|
+
// @pik:select Theme
|
|
37
|
+
const theme = 'dark'; // @pik:option dark
|
|
38
|
+
`.trim();
|
|
39
|
+
const file2 = `
|
|
40
|
+
// @pik:select Mode
|
|
41
|
+
const mode = 'dev'; // @pik:option dev
|
|
42
|
+
`.trim();
|
|
43
|
+
await writeFile(join(testDir, 'theme.ts'), file1);
|
|
44
|
+
await writeFile(join(testDir, 'mode.ts'), file2);
|
|
45
|
+
const scanner = new Scanner({ include: ['*.ts'] });
|
|
46
|
+
const results = await scanner.scan(testDir);
|
|
47
|
+
expect(results).toHaveLength(2);
|
|
48
|
+
});
|
|
49
|
+
it('should respect include patterns', async () => {
|
|
50
|
+
await writeFile(join(testDir, 'included.ts'), '// @pik:select A\nconst a = 1; // @pik:option a');
|
|
51
|
+
await writeFile(join(testDir, 'excluded.js'), '// @pik:select B\nconst b = 1; // @pik:option b');
|
|
52
|
+
const scanner = new Scanner({ include: ['*.ts'] });
|
|
53
|
+
const results = await scanner.scan(testDir);
|
|
54
|
+
expect(results).toHaveLength(1);
|
|
55
|
+
expect(results[0].selectors[0].name).toBe('A');
|
|
56
|
+
});
|
|
57
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lsst/pik",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI tool for switching config options in source files",
|
|
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/cli"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"cli",
|
|
15
|
+
"config",
|
|
16
|
+
"configuration",
|
|
17
|
+
"switch",
|
|
18
|
+
"toggle",
|
|
19
|
+
"environment",
|
|
20
|
+
"env"
|
|
21
|
+
],
|
|
22
|
+
"bin": {
|
|
23
|
+
"pik": "./dist/bin/pik.js"
|
|
24
|
+
},
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"module": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
"./package.json": "./package.json",
|
|
30
|
+
".": {
|
|
31
|
+
"@pik/source": "./src/index.ts",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js",
|
|
34
|
+
"default": "./dist/index.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"!**/*.tsbuildinfo"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@inquirer/prompts": "^8.1.0",
|
|
43
|
+
"@lsst/pik-core": "^0.0.1",
|
|
44
|
+
"commander": "^14.0.2",
|
|
45
|
+
"glob": "^10.5.0",
|
|
46
|
+
"picocolors": "^1.1.1",
|
|
47
|
+
"tslib": "^2.3.0"
|
|
48
|
+
}
|
|
49
|
+
}
|