Skip to content

Commit 85925a0

Browse files
committed
Make Concordance extensible
Basic API for augmenting the themes and appending plugins. Fixes #1861.
1 parent 6b63b1b commit 85925a0

File tree

5 files changed

+91
-7
lines changed

5 files changed

+91
-7
lines changed

entrypoints/plugin.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import * as plugin from '../lib/worker/plugin.cjs';
22

3-
const {registerSharedWorker} = plugin;
4-
export {registerSharedWorker};
3+
const {extendCondordance, registerSharedWorker} = plugin;
4+
export {extendCondordance, registerSharedWorker};

lib/concordance-options.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,48 @@ const colorTheme = {
8585
undefined: ansiStyles.yellow,
8686
};
8787

88-
const plainTheme = JSON.parse(JSON.stringify(colorTheme), value => typeof value === 'string' ? stripAnsi(value) : value);
88+
const stripColor = colorTheme => JSON.parse(JSON.stringify(colorTheme), value => typeof value === 'string' ? stripAnsi(value) : value);
8989

90-
const theme = chalk.level > 0 ? colorTheme : plainTheme;
90+
const plainTheme = stripColor(colorTheme);
91+
92+
let plugins = [];
9193

9294
const concordanceOptions = {
9395
// Use Node's object inspection depth, clamped to a minimum of 3
9496
get maxDepth() {
9597
return Math.max(3, inspect.defaultOptions.depth);
9698
},
97-
theme,
99+
plugins,
100+
theme: chalk.level > 0 ? colorTheme : plainTheme,
98101
};
99102

100103
export default concordanceOptions;
101104

102-
export const snapshotManager = {theme: plainTheme};
105+
export const snapshotManager = {plugins, theme: plainTheme};
106+
107+
export const maxColorLevel = forceColor.level;
108+
109+
export function extendTheme(theme) {
110+
for (const [key, value] of theme) {
111+
if (typeof value === 'object') {
112+
colorTheme[key] = {...colorTheme[key], ...value};
113+
plainTheme[key] = {...plainTheme[key], ...stripColor(value)};
114+
} else {
115+
colorTheme[key] = value;
116+
plainTheme[key] = stripColor({value}).value;
117+
}
118+
}
119+
120+
// The theme object is used as a cache key so it needs to be changed for
121+
// changes to take effect.
122+
concordanceOptions.theme = {...concordanceOptions.theme};
123+
snapshotManager.theme = {...snapshotManager.theme};
124+
}
125+
126+
export function appendPlugin(plugin) {
127+
// The plugins array is used as a cache key so it needs to be changed for
128+
// changes to take effect.
129+
plugins = [...plugins, plugin];
130+
concordanceOptions.plugins = plugins;
131+
snapshotManager.plugins = plugins;
132+
}

lib/worker/base.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {workerData} from 'node:worker_threads';
66
import setUpCurrentlyUnhandled from 'currently-unhandled';
77

88
import {set as setChalk} from '../chalk.js';
9+
import * as concordanceOptions from '../concordance-options.js';
910
import nowAndTimers from '../now-and-timers.cjs';
1011
import providerManager from '../provider-manager.js';
1112
import Runner from '../runner.js';
@@ -24,6 +25,8 @@ const run = async options => {
2425
setOptions(options);
2526
setChalk(options.chalkOptions);
2627

28+
refs.concordanceOptions = concordanceOptions;
29+
2730
if (options.chalkOptions.level > 0) {
2831
const {stdout, stderr} = process;
2932
global.console = Object.assign(global.console, new console.Console({stdout, stderr, colorMode: true}));

lib/worker/plugin.cjs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const pkg = require('../../package.json');
22

33
const {registerSharedWorker: register} = require('./channel.cjs');
44
const options = require('./options.cjs');
5-
const {sharedWorkerTeardowns, waitForReady} = require('./state.cjs');
5+
const {refs, sharedWorkerTeardowns, waitForReady} = require('./state.cjs');
66

77
require('./guard-environment.cjs'); // eslint-disable-line import/no-unassigned-import
88

@@ -128,3 +128,23 @@ function registerSharedWorker({
128128
}
129129

130130
exports.registerSharedWorker = registerSharedWorker;
131+
132+
function extendConcordance({supportedProtocols}) {
133+
if (!supportedProtocols.includes('ava-4.1')) {
134+
throw new Error(`This version of AVA (${pkg.version}) does not support any of the desired Concordance extension protocols: ${supportedProtocols.join(',')}`);
135+
}
136+
137+
return {
138+
maxColorLevel: refs.concordanceOptions.maxColorLevel,
139+
140+
extendTheme(theme) {
141+
refs.concordanceOptions.extendTheme(theme);
142+
},
143+
144+
appendPlugin(plugin) {
145+
refs.concordanceOptions.appendPlugin(plugin);
146+
},
147+
};
148+
}
149+
150+
exports.extendConcordance = extendConcordance;

plugin.d.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,34 @@ export namespace SharedWorker {
7575

7676
export function registerSharedWorker<Data = unknown>(options: SharedWorker.Plugin.RegistrationOptions<'ava-4', Data>): SharedWorker.Plugin.Protocol<Data>;
7777
// Add overloads for additional protocols.
78+
79+
export namespace Concordance {
80+
export type ProtocolIdentifier = 'ava-4.1';
81+
82+
export type RegistrationOptions<Identifier extends ProtocolIdentifier> = {
83+
readonly supportedProtocols: readonly Identifier[];
84+
};
85+
86+
export interface Theme { // eslint-disable-line @typescript-eslint/consistent-indexed-object-style
87+
[field: string]: string | Theme;
88+
}
89+
90+
// N.B. Concordance doesn't have a type definition we can re-export.
91+
export type Plugin = {
92+
name: string;
93+
apiVersion: number;
94+
minimalConcordanceVersion?: string;
95+
serializerVersion: number;
96+
theme?: Theme;
97+
register: (api: Record<string, unknown>) => (value: unknown) => Function | null; // eslint-disable-line @typescript-eslint/ban-types
98+
};
99+
100+
export type Protocol = {
101+
readonly maxColorLevel: number;
102+
extendTheme: (theme: Theme) => void;
103+
appendPlugin: (plugin: Plugin) => void;
104+
};
105+
}
106+
107+
export function extendConcordance(options: Concordance.RegistrationOptions<'ava-4.1'>): Concordance.Protocol;
108+
// Add overloads for additional protocols.

0 commit comments

Comments
 (0)