Skip to content

Commit

Permalink
Command plugin fixup (#989)
Browse files Browse the repository at this point in the history
* [PFX-813] ESM: Port plugin-metadata (#978)

* chore: convert to esm

* tests: added vitest

* chore: update changelog; remove jest deps

* fix: test

* chore: remove unused space

* [PFX-793] Dynamic plugins (#970)

* feat: dynamic plugins

* chore: add cjs tranpilation

* tests: default-plugins

* tests: core

* tests: dynamic index

* tests: prepare hook

* fix: lint

* chore: add types for dynamic plugins

* docs: dynamic plugins

* chore: update package.json

* docs: update changelog

* chore: switch to utilize sub-environments

* chore: add metadata

* fix: lint

* fix: test

* chore: remove cjs transpilation

* docs: update dynamic and core

* fix: test

* Update packages/gasket-plugin-dynamic-plugins/README.md

Co-authored-by: Andrew Gerard <[email protected]>

---------

Co-authored-by: Andrew Gerard <[email protected]>

* chore: remove depreacted http2 dep (#981)

* Normalized gasket request (#973)

* feat: normalized gasket request

* fix: attempt types adjustments

* fix: types adjustments

* test: the things

* docs: package docs

* fix: docs

* fix: one way to make

* fix: ensure expected defaults

* fix: better types

* fix: handle parallel executions

* fix: next request helper

* test: adjustments

* fix: unused import

* feat: add WeakPromiseKeeper for consistent promise to value caching

* fix: types

* fix: docs

* feat: handle IncomingMessage url

* fix: tighten types

* fix: test cruft

* docs: fix

* fix: only parse url when needed

* test: using gasket.symbol as weakmap key (#964)

* Separate https-proxy plugin (#982)

* feat: separate https-proxy plugin

* feat: use https-proxy with prompts

* fix: typos and grammar

* fix: avoid default export

* fix: return proxy server

* chore: upgrade lerna

* fix: publish issues for command plugin

* docs: next.config.js (#987)

* [PFX-507] Add DocSearch to Gasket Site (#984)

* change dynamic require to string interpolation (#985)

* pin react-intl version to 6.6.X (#988)

* feat: initial fixup for getting command name early and using prepare lifecycle as an async config

* Fix typo

* Tune types

* Opt for sync configure hook

* Clean up old references to command.id

* Add isReady, update command property

* Update readme

* Tune command plugin functionality

* Add temp logging for debug

* Cleanup debugs

* Persist commands config when commandId is undefined

* Tune tests

* lockfile

* remove duplicate tests from merge

* lockfile

* lockfile

* feat: initial fixup for getting command name early and using prepare lifecycle as an async config

* Fix typo

* Tune types

* Opt for sync configure hook

* Clean up old references to command.id

* Add isReady, update command property

* Update readme

* Tune command plugin functionality

* Add temp logging for debug

* Cleanup debugs

* Persist commands config when commandId is undefined

* Tune tests

* Import plugin command types

* Relax the regex for gasket file in argv

* Remove timing from ready hook

* fix test

---------

Co-authored-by: Jordan Pina <[email protected]>
Co-authored-by: Andrew Gerard <[email protected]>
Co-authored-by: Andrew Gerard <[email protected]>
Co-authored-by: Kawika Bader <[email protected]>
Co-authored-by: bbetts-godaddy <[email protected]>
  • Loading branch information
6 people authored Dec 11, 2024
1 parent 110d5fd commit c380187
Show file tree
Hide file tree
Showing 23 changed files with 196 additions and 58 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Available actions
| [getPublicGasketData] | Get the public Gasket data |
| [getSWRegisterScript] | Get the service worker registration script |
| [getWebpackConfig] | Get the webpack config |
| [startProxyServer] | Start the proxy server |
| [startServer] | Start the server |

## Lifecycles
Expand All @@ -107,6 +108,7 @@ Available lifecycles
| [express] | Modify the Express instance to for adding endpoints |
| [fastify] | Modify the Fastify instance to for adding endpoints |
| [gasketData] | Adjust app level data after merged for the env |
| [httpsProxy] | Setup the httpsProxy options |
| [initReduxState] | Initializes state of the Redux store |
| [initReduxStore] | Plugin access to Redux store instance |
| [initWebpack] | Create a webpack config |
Expand Down Expand Up @@ -224,6 +226,7 @@ Available configuration options in the `gasket.js`
| [docusaurus.host] | Hostname to serve the docs from | string | localhost |
| [docusaurus.port] | Port number to serve docs site | number | 3000 |
| [docusaurus.rootDir] | Root Docusaurus directory | string | .docs |
| [dynamicPlugins] | Specify which plugins to load dynamically into gasket | array | |
| [elasticAPM] | Configuration to provide additional setup helpers | object | |
| [elasticAPM.sensitiveCookies] | List of sensitive cookies to filter | string[] | [] |
| [express][6] | Express plugin configuration | object | |
Expand All @@ -236,6 +239,7 @@ Available configuration options in the `gasket.js`
| [http] | HTTP port or config object | number | object | |
| [http2] | HTTP2 config object | object | |
| [https] | HTTPS config object | object | |
| [httpsProxy][8] | http-proxy config object | object | |
| [intl] | Intl config object | object | |
| [intl.defaultLocale] | Locale to fallback to when loading files | string | en |
| [intl.defaultLocaleFilePath] | Lookup path to locale files | string | locales |
Expand Down Expand Up @@ -301,6 +305,7 @@ Available configuration options in the `gasket.js`
[getPublicGasketData]:/packages/gasket-plugin-data/README.md#getPublicGasketData
[getSWRegisterScript]:/packages/gasket-plugin-service-worker/README.md#getSWRegisterScript
[getWebpackConfig]:/packages/gasket-plugin-webpack/README.md#getWebpackConfig
[startProxyServer]:/packages/gasket-plugin-https-proxy/README.md#startProxyServer
[startServer]:/packages/gasket-plugin-https/README.md#startServer
[apmTransaction]:/packages/gasket-plugin-elastic-apm/README.md#apmtransaction
[1]:/packages/gasket-plugin-command/README.md#build
Expand All @@ -317,6 +322,7 @@ Available configuration options in the `gasket.js`
[express]:/packages/gasket-plugin-express/README.md#express
[fastify]:/packages/gasket-plugin-fastify/README.md#express
[gasketData]:/packages/gasket-plugin-data/README.md#gasketData
[httpsProxy]:/packages/gasket-plugin-https-proxy/README.md#httpsProxy
[initReduxState]:/packages/gasket-plugin-redux/README.md#initReduxState
[initReduxStore]:/packages/gasket-plugin-redux/README.md#initReduxStore
[initWebpack]:/packages/gasket-plugin-webpack/README.md#initwebpack
Expand Down Expand Up @@ -356,12 +362,14 @@ Available configuration options in the `gasket.js`
[@gasket/plugin-docs]:/packages/gasket-plugin-docs/README.md
[@gasket/plugin-docs-graphs]:/packages/gasket-plugin-docs-graphs/README.md
[@gasket/plugin-docusaurus]:/packages/gasket-plugin-docusaurus/README.md
[@gasket/plugin-dynamic-plugins]:/packages/gasket-plugin-dynamic-plugins/README.md
[@gasket/plugin-elastic-apm]:/packages/gasket-plugin-elastic-apm/README.md
[@gasket/plugin-express]:/packages/gasket-plugin-express/README.md
[@gasket/plugin-fastify]:/packages/gasket-plugin-fastify/README.md
[@gasket/plugin-git]:/packages/gasket-plugin-git/README.md
[@gasket/plugin-happyfeet]:/packages/gasket-plugin-happyfeet/README.md
[@gasket/plugin-https]:/packages/gasket-plugin-https/README.md
[@gasket/plugin-https-proxy]:/packages/gasket-plugin-https-proxy/README.md
[@gasket/plugin-intl]:/packages/gasket-plugin-intl/README.md
[@gasket/plugin-jest]:/packages/gasket-plugin-jest/README.md
[@gasket/plugin-lint]:/packages/gasket-plugin-lint/README.md
Expand All @@ -386,6 +394,7 @@ Available configuration options in the `gasket.js`
[@gasket/nextjs]:/packages/gasket-nextjs/README.md
[@gasket/react-intl]:/packages/gasket-react-intl/README.md
[@gasket/redux]:/packages/gasket-redux/README.md
[@gasket/request]:/packages/gasket-request/README.md
[@gasket/utils]:/packages/gasket-utils/README.md
[bundleAnalyzerConfig]:/packages/gasket-plugin-analyze/README.md#configuration
[5]:/packages/gasket-plugin-docs/README.md#configuration
Expand All @@ -395,6 +404,7 @@ Available configuration options in the `gasket.js`
[docusaurus.host]:/packages/gasket-plugin-docusaurus/README.md#configuration
[docusaurus.port]:/packages/gasket-plugin-docusaurus/README.md#configuration
[docusaurus.rootDir]:/packages/gasket-plugin-docusaurus/README.md#configuration
[dynamicPlugins]:/packages/gasket-plugin-dynamic-plugins/README.md#configuration
[elasticAPM]:/packages/gasket-plugin-elastic-apm/README.md#configuration
[elasticAPM.sensitiveCookies]:/packages/gasket-plugin-elastic-apm/README.md#configuration
[6]:/packages/gasket-plugin-express/README.md#configuration
Expand All @@ -407,6 +417,7 @@ Available configuration options in the `gasket.js`
[http]:/packages/gasket-plugin-https/README.md#configuration
[http2]:/packages/gasket-plugin-https/README.md#configuration
[https]:/packages/gasket-plugin-https/README.md#configuration
[8]:/packages/gasket-plugin-https-proxy/README.md#configuration
[intl]:/packages/gasket-plugin-intl/README.md#configuration
[intl.defaultLocale]:/packages/gasket-plugin-intl/README.md#configuration
[intl.defaultLocaleFilePath]:/packages/gasket-plugin-intl/README.md#configuration
Expand Down
1 change: 1 addition & 0 deletions docs/generated-docs/lifecycle-graphs.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ createServers -- exec --> errorMiddleware;
createServers -- exec --> express;
createServers -- exec --> fastify;
gasket/plugin-data -- execWaterfall --> gasketData;
gasket/plugin-https-proxy -- execWaterfall --> httpsProxy;
middleware -- execWaterfall --> initReduxState;
middleware -- exec --> initReduxStore;
build-cmd(build) --> initWebpack;
Expand Down
3 changes: 1 addition & 2 deletions packages/gasket-core/lib/gasket.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ export class Gasket {

this.hook = this.engine.hook.bind(this.engine);
this.config = config;
this.command = null;

// Can be used as a key to identify a gasket instance
this.symbol = Symbol('gasket');
Expand All @@ -66,7 +65,7 @@ export class Gasket {
this.isReady = new Promise((resolve) => {
(async () => {
// @ts-ignore - attached lifecycle trace methods
await this.exec('prepare');
this.config = await this.execWaterfall('prepare', this.config);
// @ts-ignore - attached lifecycle trace methods
await this.exec('ready');
resolve();
Expand Down
5 changes: 2 additions & 3 deletions packages/gasket-core/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ declare module '@gasket/core' {
constructor(config: GasketConfigDefinition);
new (config: GasketConfigDefinition): Gasket

command: {
id: string;
};
isReady: Promise<void>;
command: string;
config: GasketConfig;
engine: GasketEngine;
symbol: Symbol;
Expand Down
5 changes: 1 addition & 4 deletions packages/gasket-nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ the [@gasket/data] package.
**Props**

- `[options]` - (object) Optional configuration
- `index` - (number) Force the script to be inject at a certain child index of the body
- `index` - (number) Force the script to be inject at a certain child index of the body

#### Example

Expand Down Expand Up @@ -141,7 +141,6 @@ In this example, the `gasketData` script will be injected after the custom
This is especially useful if you are somehow nesting or extending the `<Main/>`
and `<NextScript/>` components and the decorator cannot find the right place to inject the script.


---

### withGasketDataProvider
Expand Down Expand Up @@ -174,7 +173,6 @@ Use this hook to access the gasketData provided by the `withGasketDataProvider`

#### Example


```jsx
// MyComponent.js
import { useGasketData } from '@gasket/nextjs';
Expand Down Expand Up @@ -202,7 +200,6 @@ The `useGasketData` will provided access to the gasket data within the context o

> Please see @gasket/data docs for examples on adding data during SSR lifecycle

## License

[MIT](./LICENSE.md)
Expand Down
22 changes: 22 additions & 0 deletions packages/gasket-plugin-command/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,27 @@ export default {
};
```

### Command-based Configuration

The commands property in the `gasket.js` file allows you to define configurations that are specific to individual commands. This means that when a particular command is executed, the corresponding configuration values will be applied, ensuring that each command can have its own tailored settings. This helps in managing command-specific behaviors and settings efficiently within your Gasket application.

#### Example

Define a command-based configuration in the `gasket.js` file:

```js
// gasket.js
import { makeGasket } from '@gasket/core';

export default makeGasket({
message: 'Default message',
commands: {
'example-cmd': {
message: 'Hello, World!' // when the `example-cmd` command is executed, this message will be displayed
}
}
});
```

<!-- Links -->
[Commander.js]: https://github.com/tj/commander.js?tab=readme-ov-file#commanderjs
37 changes: 37 additions & 0 deletions packages/gasket-plugin-command/lib/configure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// @ts-nocheck
/* eslint-disable no-unused-vars, no-sync */
import { applyConfigOverrides } from '@gasket/utils';
import { gasketBin, processCommand } from './cli.js';
const isGasketCommand = /gasket[.-\w]*\.(js|ts|cjs|mjs)$/;

export default {
timing: {
first: true
},
/** @type {import('@gasket/core').HookHandler<'configure'>} */
handler: function configure(gasket, config) {
const hasGasket = process.argv.some(arg => isGasketCommand.test(arg));

if (hasGasket) {
const cmds = gasket.execSync('commands');
const commandIds = cmds.reduce((acc, cmd) => {
acc[cmd.id] = true;
return acc;
}, Object());

cmds.forEach(cmd => {
const { command, hidden, isDefault } = processCommand(cmd);
gasketBin.addCommand(command, { hidden, isDefault });
});

const commandId = [...process.argv].filter(arg => commandIds[arg])[0];
return {
command: commandId,
...applyConfigOverrides(config, { env: gasket.config.env, commandId })
};
}

return config;
}
};

5 changes: 5 additions & 0 deletions packages/gasket-plugin-command/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export interface GasketCommandDefinition {
}

declare module '@gasket/core' {
/* Custom command name/id */
export interface GasketConfig {
command?: string;
}

interface HookExecTypes {
commands(): GasketCommandDefinition;
build(): void;
Expand Down
6 changes: 4 additions & 2 deletions packages/gasket-plugin-command/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/// <reference types="@gasket/plugin-metadata" />

import create from './create.js';
import ready from './ready.js';
import configure from './configure.js';
import commands from './commands.js';
import ready from './ready.js';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const { name, version, description } = require('../package.json');
Expand All @@ -14,8 +15,9 @@ export default {
description,
hooks: {
create,
ready,
configure,
commands,
ready,
metadata(gasket, meta) {
return {
...meta,
Expand Down
18 changes: 4 additions & 14 deletions packages/gasket-plugin-command/lib/ready.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
/* eslint-disable no-unused-vars, no-sync */
import { gasketBin, processCommand } from './cli.js';
const isGasketCommand = /\/gasket\.(js|ts|cjs|mjs)$/;
import { gasketBin } from './cli.js';

/** @type {import('@gasket/core').HookHandler<'ready'>} */
export default async function readyHook(gasket) {
const hasGasket = process.argv.some(arg => isGasketCommand.test(arg));

if (hasGasket) {
const cmds = await gasket.exec('commands');
cmds.forEach(cmd => {
const { command, hidden, isDefault } = processCommand(cmd);
gasketBin.addCommand(command, { hidden, isDefault });
});

export default async function ready(gasket) {
gasket.isReady.then(() => {
gasketBin.parse();
}
});
}
55 changes: 55 additions & 0 deletions packages/gasket-plugin-command/test/configure.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/* eslint-disable no-sync */
import { jest } from '@jest/globals';

const mockAddCommand = jest.fn();
const mockParse = jest.fn();
const mockProcessCommand = jest.fn();

jest.unstable_mockModule('../lib/cli.js', () => {

return {
gasketBin: {
addCommand: mockAddCommand,
parse: mockParse
},
processCommand: mockProcessCommand.mockReturnValue({ command: 'test', hidden: false, isDefault: false })
};
});

const configure = ((await import('../lib/configure.js')).default).handler;

describe('configure', () => {
let mockGasket, mockConfig;

beforeEach(() => {
jest.clearAllMocks();
mockGasket = {
execSync: jest.fn().mockReturnValue([{ id: 'test', description: 'test', action: jest.fn() }]),
config: {
env: 'development'
}
};
mockConfig = {};
});

it('should be a function', () => {
expect(configure).toEqual(expect.any(Function));
});

it('should not exec commands if not a gasket command', () => {
configure(mockGasket, mockConfig);
expect(mockGasket.execSync).not.toHaveBeenCalled();
});

it('should execute on gasket command', () => {
process.argv = ['node', '/path/to/gasket.js'];
configure(mockGasket, mockConfig);
expect(mockGasket.execSync).toHaveBeenCalled();
});

it('should add commands to gasketBin', () => {
process.argv = ['node', '/path/to/gasket.js'];
configure(mockGasket, mockConfig);
expect(mockAddCommand).toHaveBeenCalled();
});
});
28 changes: 9 additions & 19 deletions packages/gasket-plugin-command/test/ready.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable no-sync */
import { jest } from '@jest/globals';

const mockAddCommand = jest.fn();
Expand All @@ -24,34 +23,25 @@ describe('ready', () => {
beforeEach(() => {
jest.clearAllMocks();
mockGasket = {
exec: jest.fn().mockReturnValue([{ id: 'test', description: 'test', action: jest.fn() }])
isReady: Promise.resolve(),
execSync: jest.fn().mockReturnValue([{ id: 'test', description: 'test', action: jest.fn() }]),
config: {
env: 'development'
}
};
});

it('should be a function', () => {
expect(ready).toEqual(expect.any(Function));
});

it('should not exec commands if not a gasket command', () => {
ready(mockGasket);
expect(mockGasket.exec).not.toHaveBeenCalled();
});

it('should execute on gasket command', () => {
process.argv = ['node', '/path/to/gasket.js'];
ready(mockGasket);
expect(mockGasket.exec).toHaveBeenCalled();
});

it('should add commands to gasketBin', async () => {
process.argv = ['node', '/path/to/gasket.js'];
it('should parse gasketBin', async () => {
await ready(mockGasket);
expect(mockAddCommand).toHaveBeenCalled();
expect(mockParse).toHaveBeenCalled();
});

it('should parse commands', async () => {
process.argv = ['node', '/path/to/gasket.js'];
it('should wait for gasket to be ready', async () => {
await ready(mockGasket);
expect(mockParse).toHaveBeenCalled();
await expect(mockGasket.isReady).resolves.toBeUndefined();
});
});
5 changes: 2 additions & 3 deletions packages/gasket-plugin-data/lib/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ const { baseDataMap } = require('./actions');
* @type {import('@gasket/core').HookHandler<'configure'>}
*/
function configure(gasket, baseConfig) {
const { command, config: { env } } = gasket;
const commandId = command && command.id;
const { config: { env, command } } = gasket;
if ('data' in baseConfig) {
const data = applyConfigOverrides(
baseConfig.data,
{ env, commandId }
{ env, commandId: command }
);

baseDataMap.set(gasket.symbol, data);
Expand Down
Loading

0 comments on commit c380187

Please sign in to comment.