Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: methods for read/write sfProjectJson.plugins #1094

Merged
merged 2 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions src/sfProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,21 @@ export type ProjectJson = ConfigContents & ProjectJsonSchema;
* The sfdx-project.json config object. This file determines if a folder is a valid sfdx project.
*
* *Note:* Any non-standard (not owned by Salesforce) properties stored in sfdx-project.json should
* be in a top level property that represents your project or plugin.
* be in a top level property that represents your project.
* Plugins should store their configuration @see SfProject.getPluginConfiguration and @see SfProject.setPluginConfiguration
*
* @example reading a standard property
* ```
* const project = await SfProject.resolve();
* const projectJson = await project.resolveProjectConfig();
* const myPluginProperties = projectJson.get('myplugin') || {};
* myPluginProperties.myprop = 'someValue';
* projectJson.set('myplugin', myPluginProperties);
* const namespace = projectJson.get('namespace');
* ```
*
* ```
* @example writing
* const project = await SfProject.resolve();
* const projectJson = await project.resolveProjectConfig();
* projectJson.set('namespace', 'new');
* await projectJson.write();
* ```
*
Expand Down Expand Up @@ -712,6 +719,48 @@ export class SfProject {
.filter(([, value]) => value?.startsWith(id))
.map(([key]) => key);
}

/**
* retrieve the configuration for a named plugin from sfdx-project.json.plugins.pluginName
*
* @example
* ```
* const project = await SfProject.resolve();
* const pluginConfig = await project.getPluginConfiguration('myPlugin');
* ```
*
* optionally pass a type parameter for your plugin configuration's schema
* */
public async getPluginConfiguration<T extends Record<string, unknown>>(pluginName: string): Promise<Readonly<T>> {
await this.retrieveSfProjectJson();
const plugins = this.sfProjectJson.get('plugins');
if (!plugins) {
throw new SfError('No plugins defined in sfdx-project.json', 'NoPluginsDefined');
}
if (!plugins[pluginName]) {
throw new SfError(`No configuration defined in sfdx-project.json for plugin ${pluginName}`, 'PluginNotFound');
}
return plugins[pluginName] as T;
}

/**
* set the configuration for a named plugin from sfdx-project.json.plugins.pluginName, overwriting existing configuration
*
* @example
* ```
* const project = await SfProject.resolve();
* const pluginConfig = await project.setPluginConfiguration('myPlugin', {foo: 'bar', myLimit: 25});
* ```
*
* optionally pass a type parameter for your plugin configuration's schema
* */
public async setPluginConfiguration<T extends Record<string, unknown>>(pluginName: string, config: T): Promise<void> {
await this.retrieveSfProjectJson();
const plugins = this.getSfProjectJson().get('plugins') ?? {};
const modified = { ...plugins, [pluginName]: config };
this.sfProjectJson.set('plugins', modified);
this.sfProjectJson.writeSync();
}
}

/** differentiate between the Base PackageDir (path, maybe default) and the Packaging version (package and maybe a LOT of other fields) by whether is has the `package` property */
Expand Down
75 changes: 75 additions & 0 deletions test/unit/projectTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -890,4 +890,79 @@ describe('SfProject', () => {
expect(foundPkg?.default).to.be.false;
});
});

describe('plugins', () => {
describe('read', () => {
it('throws on read when no existing plugins', async () => {
$$.setConfigStubContents('SfProjectJson', {
contents: {},
});
const project = SfProject.getInstance();
try {
await project.getPluginConfiguration('fooPlugin');
assert.fail('Expected error to be thrown');
} catch (e) {
assert(e instanceof SfError);
expect(e.name).to.equal('NoPluginsDefined');
}
});
it('throws on read when no existing plugin when named', async () => {
$$.setConfigStubContents('SfProjectJson', {
contents: {
plugins: { someOtherPlugin: {} },
},
});
const project = SfProject.getInstance();
try {
await project.getPluginConfiguration('fooPlugin');
assert.fail('Expected error to be thrown');
} catch (e) {
assert(e instanceof SfError);
expect(e.name).to.equal('PluginNotFound');
}
});
it('read returns valid data', async () => {
$$.setConfigStubContents('SfProjectJson', {
contents: {
plugins: { someOtherPlugin: {}, fooPlugin: { foo: 'bar' } },
},
});
const project = SfProject.getInstance();
const config = await project.getPluginConfiguration('fooPlugin');
expect(config).to.deep.equal({ foo: 'bar' });
});
});
describe('write', () => {
it('write when no existing plugins', async () => {
$$.setConfigStubContents('SfProjectJson', {
contents: {},
});
const project = SfProject.getInstance();
await project.setPluginConfiguration('fooPlugin', { foo: 'bar' });
expect($$.getConfigStubContents('SfProjectJson').plugins).to.deep.equal({ fooPlugin: { foo: 'bar' } });
});
it('write new plugin', async () => {
$$.setConfigStubContents('SfProjectJson', {
contents: { plugins: { otherPlugin: {} } },
});
const project = SfProject.getInstance();
await project.setPluginConfiguration('fooPlugin', { foo: 'bar' });
expect($$.getConfigStubContents('SfProjectJson').plugins).to.deep.equal({
otherPlugin: {},
fooPlugin: { foo: 'bar' },
});
});
it('update existing plugin', async () => {
$$.setConfigStubContents('SfProjectJson', {
contents: { plugins: { otherPlugin: {}, fooPlugin: { foo: 'bat', removeMe: 0 } } },
});
const project = SfProject.getInstance();
await project.setPluginConfiguration('fooPlugin', { foo: 'bar' });
expect($$.getConfigStubContents('SfProjectJson').plugins).to.deep.equal({
otherPlugin: {},
fooPlugin: { foo: 'bar' },
});
});
});
});
});
Loading