@octoberswimmer/aer-sf-plugin 0.0.3 → 0.0.4
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 +33 -8
- package/lib/commands/aer/lightning/dev/component.d.ts +17 -0
- package/lib/commands/aer/lightning/dev/component.js +160 -0
- package/lib/commands/aer/lightning/dev/component.js.map +1 -0
- package/lib/lwc.d.ts +7 -0
- package/lib/lwc.js +67 -0
- package/lib/lwc.js.map +1 -0
- package/messages/aer.lightning.dev.component.md +87 -0
- package/oclif.manifest.json +96 -1
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
# @octoberswimmer/aer-sf-plugin
|
|
2
2
|
|
|
3
3
|
A [Salesforce CLI](https://developer.salesforce.com/tools/salesforcecli) plugin
|
|
4
|
-
that runs Apex tests locally using
|
|
4
|
+
that runs Apex tests and previews Lightning Web Components locally using
|
|
5
|
+
[aer](https://github.com/octoberswimmer/aer-dist).
|
|
5
6
|
|
|
6
7
|
```
|
|
7
8
|
sf aer apex run test
|
|
8
9
|
```
|
|
9
10
|
|
|
10
|
-
works the same way as
|
|
11
|
+
works the same way as `sf apex run test`, but runs tests locally via `aer test`.
|
|
11
12
|
|
|
12
13
|
```
|
|
13
|
-
sf
|
|
14
|
+
sf aer lightning dev component
|
|
14
15
|
```
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
copy.
|
|
17
|
+
works the same way as `sf lightning dev component`, but previews LWC components
|
|
18
|
+
locally via `aer server`.
|
|
19
19
|
|
|
20
20
|
## Requirements
|
|
21
21
|
|
|
@@ -35,6 +35,8 @@ sf plugins install @octoberswimmer/aer-sf-plugin
|
|
|
35
35
|
|
|
36
36
|
## Usage
|
|
37
37
|
|
|
38
|
+
### Apex tests
|
|
39
|
+
|
|
38
40
|
Run every test in the project:
|
|
39
41
|
|
|
40
42
|
```
|
|
@@ -65,6 +67,30 @@ With code coverage:
|
|
|
65
67
|
sf aer apex run test --code-coverage --output-dir test-results
|
|
66
68
|
```
|
|
67
69
|
|
|
70
|
+
### LWC component preview
|
|
71
|
+
|
|
72
|
+
Select a component interactively and launch the preview:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
sf aer lightning dev component
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Preview a specific component by name:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
sf aer lightning dev component --name myComponent
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Open the component list in the browser instead of selecting interactively:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
sf aer lightning dev component --client-select
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The development server uses `aer server --watch` to serve your project's
|
|
91
|
+
source directly (no staging), so changes to component HTML, CSS, and
|
|
92
|
+
JavaScript are reflected immediately via hot module replacement.
|
|
93
|
+
|
|
68
94
|
## Locating the aer binary
|
|
69
95
|
|
|
70
96
|
When the plugin needs to invoke `aer`, it tries these sources in order:
|
|
@@ -173,5 +199,4 @@ node bin/dev.js aer apex run test --help
|
|
|
173
199
|
This plugin is open source, licensed under BSD-3-Clause.
|
|
174
200
|
|
|
175
201
|
Note that [aer](https://github.com/octoberswimmer/aer-dist) itself is not open
|
|
176
|
-
source — it is distributed as a binary under its own license.
|
|
177
|
-
and install aer separately for the plugin to do anything useful.
|
|
202
|
+
source — it is distributed as a binary under its own license.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
|
+
export type AerLightningDevComponentResult = {
|
|
3
|
+
exitCode: number;
|
|
4
|
+
};
|
|
5
|
+
export default class AerLightningDevComponent extends SfCommand<AerLightningDevComponentResult> {
|
|
6
|
+
static readonly summary: string;
|
|
7
|
+
static readonly description: string;
|
|
8
|
+
static readonly examples: string[];
|
|
9
|
+
static readonly flags: {
|
|
10
|
+
'target-org': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
'client-select': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<AerLightningDevComponentResult>;
|
|
15
|
+
private runServer;
|
|
16
|
+
private maybePromptForUpdate;
|
|
17
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { spawn, exec } from 'node:child_process';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
|
|
4
|
+
import { Messages, SfProject } from '@salesforce/core';
|
|
5
|
+
import select from '@inquirer/select';
|
|
6
|
+
import { discoverLwcComponents } from '../../../../lwc.js';
|
|
7
|
+
import { checkForUpdate, ensureAerBinary, installAerVersion, recordPromptedVersion, } from '../../../../aerBinary.js';
|
|
8
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
9
|
+
const messages = Messages.loadMessages('@octoberswimmer/aer-sf-plugin', 'aer.lightning.dev.component');
|
|
10
|
+
export default class AerLightningDevComponent extends SfCommand {
|
|
11
|
+
static summary = messages.getMessage('summary');
|
|
12
|
+
static description = messages.getMessage('description');
|
|
13
|
+
static examples = messages.getMessages('examples');
|
|
14
|
+
static flags = {
|
|
15
|
+
'target-org': Flags.string({
|
|
16
|
+
char: 'o',
|
|
17
|
+
summary: messages.getMessage('flags.target-org.summary'),
|
|
18
|
+
}),
|
|
19
|
+
name: Flags.string({
|
|
20
|
+
char: 'n',
|
|
21
|
+
summary: messages.getMessage('flags.name.summary'),
|
|
22
|
+
}),
|
|
23
|
+
'client-select': Flags.boolean({
|
|
24
|
+
char: 'c',
|
|
25
|
+
summary: messages.getMessage('flags.client-select.summary'),
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
async run() {
|
|
29
|
+
const { flags } = await this.parse(AerLightningDevComponent);
|
|
30
|
+
const project = await SfProject.resolve();
|
|
31
|
+
const projectRoot = project.getPath();
|
|
32
|
+
const contents = project.getSfProjectJson().getContents();
|
|
33
|
+
const packageDirectories = contents.packageDirectories ?? [];
|
|
34
|
+
if (flags['target-org']) {
|
|
35
|
+
this.warn(messages.getMessage('warn.ignoredFlags', ['--target-org']));
|
|
36
|
+
}
|
|
37
|
+
const interactive = Boolean(process.stdin.isTTY);
|
|
38
|
+
const aerPath = await ensureAerBinary({
|
|
39
|
+
allowPrompt: interactive,
|
|
40
|
+
confirm: (message) => this.confirm({ message, ms: 5 * 60 * 1000, defaultAnswer: false }),
|
|
41
|
+
log: (m) => this.log(m),
|
|
42
|
+
warn: (m) => this.warn(m),
|
|
43
|
+
});
|
|
44
|
+
const updateCheck = interactive
|
|
45
|
+
? checkForUpdate({ aerPath, log: (m) => this.log(m) }).catch(() => null)
|
|
46
|
+
: Promise.resolve(null);
|
|
47
|
+
let componentName = flags.name;
|
|
48
|
+
const clientSelect = flags['client-select'] ?? false;
|
|
49
|
+
if (!clientSelect) {
|
|
50
|
+
const components = await discoverLwcComponents(projectRoot, packageDirectories);
|
|
51
|
+
if (components.length === 0) {
|
|
52
|
+
throw messages.createError('error.noLwcComponents');
|
|
53
|
+
}
|
|
54
|
+
if (componentName) {
|
|
55
|
+
const match = components.find((c) => c.name === componentName);
|
|
56
|
+
if (!match) {
|
|
57
|
+
const available = components.map((c) => c.name).join(', ');
|
|
58
|
+
throw messages.createError('error.componentNotFound', [componentName, available]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
componentName = await select({
|
|
63
|
+
message: messages.getMessage('prompt.selectComponent'),
|
|
64
|
+
choices: components.map((c) => ({ name: c.name, value: c.name })),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const sourcePaths = packageDirectories.map((pd) => resolve(projectRoot, pd.path));
|
|
69
|
+
const args = ['server', ...sourcePaths, '--watch'];
|
|
70
|
+
const previewPath = componentName ? `/dev/lwc/${componentName}` : '/dev/lwc';
|
|
71
|
+
const exitCode = await this.runServer(aerPath, args, projectRoot, previewPath);
|
|
72
|
+
if (exitCode !== 0) {
|
|
73
|
+
this.warn(messages.getMessage('warn.aerExit', [String(exitCode)]));
|
|
74
|
+
}
|
|
75
|
+
await this.maybePromptForUpdate(updateCheck);
|
|
76
|
+
return { exitCode };
|
|
77
|
+
}
|
|
78
|
+
runServer(binaryPath, args, cwd, previewPath) {
|
|
79
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
80
|
+
const child = spawn(binaryPath, args, {
|
|
81
|
+
cwd,
|
|
82
|
+
stdio: ['inherit', 'inherit', 'pipe'],
|
|
83
|
+
env: {
|
|
84
|
+
...process.env,
|
|
85
|
+
AER_AUTOUPDATE_DISABLED: '1',
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
let opened = false;
|
|
89
|
+
let stderrBuf = '';
|
|
90
|
+
child.stderr?.on('data', (chunk) => {
|
|
91
|
+
const text = chunk.toString();
|
|
92
|
+
process.stderr.write(text);
|
|
93
|
+
if (!opened) {
|
|
94
|
+
stderrBuf += text;
|
|
95
|
+
const match = stderrBuf.match(/server listening on (\S+)/);
|
|
96
|
+
if (match) {
|
|
97
|
+
opened = true;
|
|
98
|
+
const addr = match[1];
|
|
99
|
+
const url = `http://${addr}${previewPath}`;
|
|
100
|
+
this.log(messages.getMessage('info.serverUrl', [url]));
|
|
101
|
+
openBrowser(url);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
child.on('error', (err) => {
|
|
106
|
+
if (err.code === 'ENOENT') {
|
|
107
|
+
rejectPromise(new Error(`Could not execute aer at ${binaryPath}. The file may have been moved or deleted.`));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
rejectPromise(err);
|
|
111
|
+
});
|
|
112
|
+
child.on('exit', (code, signal) => {
|
|
113
|
+
if (signal) {
|
|
114
|
+
resolvePromise(128 + (signal === 'SIGINT' ? 2 : signal === 'SIGTERM' ? 15 : 1));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
resolvePromise(code ?? 0);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async maybePromptForUpdate(check) {
|
|
123
|
+
let update;
|
|
124
|
+
try {
|
|
125
|
+
update = await check;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!update)
|
|
131
|
+
return;
|
|
132
|
+
this.log('');
|
|
133
|
+
const yes = await this.confirm({
|
|
134
|
+
message: messages.getMessage('prompt.updateAvailable', [update.installed, update.latest]),
|
|
135
|
+
ms: 5 * 60 * 1000,
|
|
136
|
+
defaultAnswer: false,
|
|
137
|
+
});
|
|
138
|
+
if (!yes) {
|
|
139
|
+
await recordPromptedVersion(update.latest).catch(() => { });
|
|
140
|
+
this.log(messages.getMessage('info.updateDeferred'));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const newPath = await installAerVersion(update.latest, { log: (m) => this.log(m) });
|
|
145
|
+
this.log(messages.getMessage('info.updateInstalled', [update.latest, newPath]));
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
this.warn(messages.getMessage('warn.updateFailed', [err.message]));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function openBrowser(url) {
|
|
153
|
+
const cmd = process.platform === 'darwin'
|
|
154
|
+
? 'open'
|
|
155
|
+
: process.platform === 'win32'
|
|
156
|
+
? 'start'
|
|
157
|
+
: 'xdg-open';
|
|
158
|
+
exec(`${cmd} ${JSON.stringify(url)}`);
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../../../../src/commands/aer/lightning/dev/component.ts"],"names":[],"mappings":"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"}
|
package/lib/lwc.d.ts
ADDED
package/lib/lwc.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
export async function discoverLwcComponents(projectRoot, packageDirectories) {
|
|
4
|
+
const seen = new Map();
|
|
5
|
+
for (const pd of packageDirectories) {
|
|
6
|
+
const absPdRoot = resolve(projectRoot, pd.path);
|
|
7
|
+
const lwcDirs = await findLwcDirs(absPdRoot);
|
|
8
|
+
for (const lwcDir of lwcDirs) {
|
|
9
|
+
let entries;
|
|
10
|
+
try {
|
|
11
|
+
entries = await readdir(lwcDir, { withFileTypes: true });
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
if (!entry.isDirectory())
|
|
18
|
+
continue;
|
|
19
|
+
const name = entry.name;
|
|
20
|
+
if (name.startsWith('__'))
|
|
21
|
+
continue;
|
|
22
|
+
const componentDir = join(lwcDir, name);
|
|
23
|
+
const hasMetaXml = await fileExists(join(componentDir, `${name}.js-meta.xml`));
|
|
24
|
+
if (!hasMetaXml)
|
|
25
|
+
continue;
|
|
26
|
+
seen.set(name, { name, path: componentDir });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
31
|
+
}
|
|
32
|
+
async function findLwcDirs(root) {
|
|
33
|
+
const results = [];
|
|
34
|
+
const stack = [root];
|
|
35
|
+
while (stack.length) {
|
|
36
|
+
const dir = stack.pop();
|
|
37
|
+
let entries;
|
|
38
|
+
try {
|
|
39
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (!entry.isDirectory())
|
|
46
|
+
continue;
|
|
47
|
+
const full = join(dir, entry.name);
|
|
48
|
+
if (entry.name === 'lwc') {
|
|
49
|
+
results.push(full);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
stack.push(full);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return results;
|
|
57
|
+
}
|
|
58
|
+
async function fileExists(filePath) {
|
|
59
|
+
try {
|
|
60
|
+
const s = await stat(filePath);
|
|
61
|
+
return s.isFile();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=lwc.js.map
|
package/lib/lwc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lwc.js","sourceRoot":"","sources":["../src/lwc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# summary
|
|
2
|
+
|
|
3
|
+
Preview Lightning Web Components locally using aer.
|
|
4
|
+
|
|
5
|
+
# description
|
|
6
|
+
|
|
7
|
+
Start a local development server powered by aer to preview Lightning Web Components in isolation with hot module replacement (HMR).
|
|
8
|
+
|
|
9
|
+
When running the development server, changes to component templates (HTML), styles (CSS), and JavaScript logic are automatically reflected in the browser.
|
|
10
|
+
|
|
11
|
+
If you run the command without flags, it displays a list of components found in your local DX project for you to choose to preview. Use the --name flag to bypass the prompt. Use --client-select to open the component list in the browser instead.
|
|
12
|
+
|
|
13
|
+
The `aer` binary is resolved in the same order as `<%= config.bin %> aer apex run test` — see that command's help for details.
|
|
14
|
+
|
|
15
|
+
# examples
|
|
16
|
+
|
|
17
|
+
- Select a component interactively and launch the preview:
|
|
18
|
+
|
|
19
|
+
<%= config.bin %> <%= command.id %>
|
|
20
|
+
|
|
21
|
+
- Preview a specific component:
|
|
22
|
+
|
|
23
|
+
<%= config.bin %> <%= command.id %> --name myComponent
|
|
24
|
+
|
|
25
|
+
- Open the component list in the browser:
|
|
26
|
+
|
|
27
|
+
<%= config.bin %> <%= command.id %> --client-select
|
|
28
|
+
|
|
29
|
+
# flags.target-org.summary
|
|
30
|
+
|
|
31
|
+
Username or alias of the target org. Accepted for compatibility with `sf lightning dev component`; aer runs locally and ignores this flag.
|
|
32
|
+
|
|
33
|
+
# flags.name.summary
|
|
34
|
+
|
|
35
|
+
Name of a component to preview.
|
|
36
|
+
|
|
37
|
+
# flags.client-select.summary
|
|
38
|
+
|
|
39
|
+
Open the component list in the browser instead of selecting interactively.
|
|
40
|
+
|
|
41
|
+
# prompt.selectComponent
|
|
42
|
+
|
|
43
|
+
Select a component to preview:
|
|
44
|
+
|
|
45
|
+
# info.serverListening
|
|
46
|
+
|
|
47
|
+
aer server listening. Opening browser…
|
|
48
|
+
|
|
49
|
+
# info.serverUrl
|
|
50
|
+
|
|
51
|
+
Preview available at %s
|
|
52
|
+
|
|
53
|
+
# info.serverStopped
|
|
54
|
+
|
|
55
|
+
aer server stopped.
|
|
56
|
+
|
|
57
|
+
# error.noLwcComponents
|
|
58
|
+
|
|
59
|
+
No Lightning Web Components found in the project's package directories.
|
|
60
|
+
|
|
61
|
+
# error.componentNotFound
|
|
62
|
+
|
|
63
|
+
Component "%s" was not found. Available components: %s
|
|
64
|
+
|
|
65
|
+
# warn.ignoredFlags
|
|
66
|
+
|
|
67
|
+
The following flags were accepted for compatibility but have no effect when running locally with aer: %s
|
|
68
|
+
|
|
69
|
+
# warn.aerExit
|
|
70
|
+
|
|
71
|
+
aer exited with non-zero status %s.
|
|
72
|
+
|
|
73
|
+
# prompt.updateAvailable
|
|
74
|
+
|
|
75
|
+
A newer aer release is available (installed: %s, latest: %s). Update now?
|
|
76
|
+
|
|
77
|
+
# info.updateDeferred
|
|
78
|
+
|
|
79
|
+
Skipping aer update. You'll be prompted again the next time a new release is published.
|
|
80
|
+
|
|
81
|
+
# info.updateInstalled
|
|
82
|
+
|
|
83
|
+
Installed aer %s to %s. The new version will be used on the next run.
|
|
84
|
+
|
|
85
|
+
# warn.updateFailed
|
|
86
|
+
|
|
87
|
+
Failed to update aer: %s
|
package/oclif.manifest.json
CHANGED
|
@@ -195,7 +195,102 @@
|
|
|
195
195
|
"test:run:aer:apex",
|
|
196
196
|
"test:run:apex:aer"
|
|
197
197
|
]
|
|
198
|
+
},
|
|
199
|
+
"aer:lightning:dev:component": {
|
|
200
|
+
"aliases": [],
|
|
201
|
+
"args": {},
|
|
202
|
+
"description": "Start a local development server powered by aer to preview Lightning Web Components in isolation with hot module replacement (HMR).\n\nWhen running the development server, changes to component templates (HTML), styles (CSS), and JavaScript logic are automatically reflected in the browser.\n\nIf you run the command without flags, it displays a list of components found in your local DX project for you to choose to preview. Use the --name flag to bypass the prompt. Use --client-select to open the component list in the browser instead.\n\nThe `aer` binary is resolved in the same order as `<%= config.bin %> aer apex run test` — see that command's help for details.",
|
|
203
|
+
"examples": [
|
|
204
|
+
"Select a component interactively and launch the preview:\n<%= config.bin %> <%= command.id %>",
|
|
205
|
+
"Preview a specific component:\n<%= config.bin %> <%= command.id %> --name myComponent",
|
|
206
|
+
"Open the component list in the browser:\n<%= config.bin %> <%= command.id %> --client-select"
|
|
207
|
+
],
|
|
208
|
+
"flags": {
|
|
209
|
+
"json": {
|
|
210
|
+
"description": "Format output as json.",
|
|
211
|
+
"helpGroup": "GLOBAL",
|
|
212
|
+
"name": "json",
|
|
213
|
+
"allowNo": false,
|
|
214
|
+
"type": "boolean"
|
|
215
|
+
},
|
|
216
|
+
"flags-dir": {
|
|
217
|
+
"helpGroup": "GLOBAL",
|
|
218
|
+
"name": "flags-dir",
|
|
219
|
+
"summary": "Import flag values from a directory.",
|
|
220
|
+
"hasDynamicHelp": false,
|
|
221
|
+
"multiple": false,
|
|
222
|
+
"type": "option"
|
|
223
|
+
},
|
|
224
|
+
"target-org": {
|
|
225
|
+
"char": "o",
|
|
226
|
+
"name": "target-org",
|
|
227
|
+
"summary": "Username or alias of the target org. Accepted for compatibility with `sf lightning dev component`; aer runs locally and ignores this flag.",
|
|
228
|
+
"hasDynamicHelp": false,
|
|
229
|
+
"multiple": false,
|
|
230
|
+
"type": "option"
|
|
231
|
+
},
|
|
232
|
+
"name": {
|
|
233
|
+
"char": "n",
|
|
234
|
+
"name": "name",
|
|
235
|
+
"summary": "Name of a component to preview.",
|
|
236
|
+
"hasDynamicHelp": false,
|
|
237
|
+
"multiple": false,
|
|
238
|
+
"type": "option"
|
|
239
|
+
},
|
|
240
|
+
"client-select": {
|
|
241
|
+
"char": "c",
|
|
242
|
+
"name": "client-select",
|
|
243
|
+
"summary": "Open the component list in the browser instead of selecting interactively.",
|
|
244
|
+
"allowNo": false,
|
|
245
|
+
"type": "boolean"
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"hasDynamicHelp": false,
|
|
249
|
+
"hiddenAliases": [],
|
|
250
|
+
"id": "aer:lightning:dev:component",
|
|
251
|
+
"pluginAlias": "@octoberswimmer/aer-sf-plugin",
|
|
252
|
+
"pluginName": "@octoberswimmer/aer-sf-plugin",
|
|
253
|
+
"pluginType": "core",
|
|
254
|
+
"strict": true,
|
|
255
|
+
"summary": "Preview Lightning Web Components locally using aer.",
|
|
256
|
+
"enableJsonFlag": true,
|
|
257
|
+
"isESM": true,
|
|
258
|
+
"relativePath": [
|
|
259
|
+
"lib",
|
|
260
|
+
"commands",
|
|
261
|
+
"aer",
|
|
262
|
+
"lightning",
|
|
263
|
+
"dev",
|
|
264
|
+
"component.js"
|
|
265
|
+
],
|
|
266
|
+
"aliasPermutations": [],
|
|
267
|
+
"permutations": [
|
|
268
|
+
"aer:lightning:dev:component",
|
|
269
|
+
"lightning:aer:dev:component",
|
|
270
|
+
"lightning:dev:aer:component",
|
|
271
|
+
"lightning:dev:component:aer",
|
|
272
|
+
"aer:dev:lightning:component",
|
|
273
|
+
"dev:aer:lightning:component",
|
|
274
|
+
"dev:lightning:aer:component",
|
|
275
|
+
"dev:lightning:component:aer",
|
|
276
|
+
"aer:dev:component:lightning",
|
|
277
|
+
"dev:aer:component:lightning",
|
|
278
|
+
"dev:component:aer:lightning",
|
|
279
|
+
"dev:component:lightning:aer",
|
|
280
|
+
"aer:lightning:component:dev",
|
|
281
|
+
"lightning:aer:component:dev",
|
|
282
|
+
"lightning:component:aer:dev",
|
|
283
|
+
"lightning:component:dev:aer",
|
|
284
|
+
"aer:component:lightning:dev",
|
|
285
|
+
"component:aer:lightning:dev",
|
|
286
|
+
"component:lightning:aer:dev",
|
|
287
|
+
"component:lightning:dev:aer",
|
|
288
|
+
"aer:component:dev:lightning",
|
|
289
|
+
"component:aer:dev:lightning",
|
|
290
|
+
"component:dev:aer:lightning",
|
|
291
|
+
"component:dev:lightning:aer"
|
|
292
|
+
]
|
|
198
293
|
}
|
|
199
294
|
},
|
|
200
|
-
"version": "0.0.
|
|
295
|
+
"version": "0.0.4"
|
|
201
296
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octoberswimmer/aer-sf-plugin",
|
|
3
|
-
"description": "Salesforce CLI plugin that runs Apex tests locally using aer.",
|
|
4
|
-
"version": "0.0.
|
|
3
|
+
"description": "Salesforce CLI plugin that runs Apex tests and previews LWC components locally using aer.",
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"author": "Christian G. Warden",
|
|
6
6
|
"bugs": "https://github.com/octoberswimmer/aer-sf-plugin/issues",
|
|
7
7
|
"homepage": "https://github.com/octoberswimmer/aer-sf-plugin",
|
|
@@ -51,6 +51,14 @@
|
|
|
51
51
|
"description": "Run Apex code or tests locally via aer."
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
},
|
|
55
|
+
"lightning": {
|
|
56
|
+
"description": "Work with Lightning Web Components locally via aer.",
|
|
57
|
+
"subtopics": {
|
|
58
|
+
"dev": {
|
|
59
|
+
"description": "Develop Lightning Web Components locally via aer."
|
|
60
|
+
}
|
|
61
|
+
}
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
64
|
}
|