@contract-case/case-plugin-base
Version:
Plugin framework for writing plugins for the ContractCase test framework
246 lines • 10.1 kB
TypeScript
import { InternalContractCaseCoreSetup } from '@contract-case/case-plugin-dsl-types';
export type PluginDslDeclaration = {
/**
* The author's namespace for these DSL classes.
*
* This is the prefix that all the type
* constants in this package will have.
*
* For the Core plugins, this is shared, but for user generated plugins
* you should provide your own. Must be a unique string.
*
* We recommend the github organisation or username used for your repository.
*/
readonly namespace: string;
/**
* The category within the namespace,
* used for grouping related matchers
* together (eg arrays)
*/
readonly category: string;
/**
* An array of all the matcher DSL objects declared by this
* plugin.
*
* Note that these don't need to map 1:1 to your matcher
* executors - multiple matcher DSL objects may share the same type.
*/
readonly matchers: MatcherDslDeclaration[];
/**
* An array of all the interaction DSL objects declared by this
* plugin.
*
* Note that, like matchers, these don't need to map 1:1 to your
* mock executors - you can have multiple interaction DSL objects
* point to the same executor, but with different properties.
*/
readonly interactions: InteractionDslDeclaration[];
/**
* This allows your plugin to describe extra state objects.
* Most users won't want to do this, as state objects need to be
* known by the core engine.
*/
readonly states?: StateObjectDeclaration[];
};
/**
* ParameterType tells us what type a parameter is.
*
* Possible string values:
* - `'AnyCaseMatcherOrData'`: Matches arbitrary
* data or a ContractCase matcher.
* This is ContractCase's most generic unknown type.
* - `'AnyData'`: Matches any data value only, ie, can't be a matcher.
* This is like saying "any json object".
* - `'integer'`: Matches integer numbers
* - `'string'`: Matches string values
* - `'boolean'`: Matches boolean values
* - `'number'`: Matches any numeric value.
* Because the contract serialises to json, this
* practically means double precision floating point; although
* the json spec doesn't actually specify, most implementations
* are restricted to double precision floating point.
* - `'null'`: Matches `null` values. Friends don't let friends match
* null values.
* - `'InternalContractCaseCoreSetup'`: This is the complex json that tells
* contractcase how to setup itself. This is here for completeness, but you
* probably don't want to declare it in your own types.
* If you are implementing a DSL generator for a new language, treat this as
* whatever a json object would naturally be (eg, a map or dictionary).
*
* See {@link TypeContainer} for complex types.
*/
export type ParameterType = TypeContainer | PassToMatcher | 'AnyCaseMatcherOrData' | 'AnyData' | 'integer' | 'string' | 'boolean' | 'number' | 'null' | 'InternalContractCaseCoreSetup';
/**
* Indicates a container type.
*
* Currently only supports arrays, but in the future may allow specific
* matchers.
*
* Implementations should switch on `kind` and fail if they get a kind that they
* don't recognise.
*
* If you have a use-case that needs more complex container types, please raise
* an issue.
*/
export type TypeContainer = {
/** What kind of container this is. Future unions of this type will always have this parameter */
readonly kind: 'array';
/** The type of the elements contained within this container */
readonly type: ParameterType;
};
/** A MatcherReference uniquely identifies a matcher and allows generated code to import and use it */
export type MatcherReference = {
/** The name of the matcher to pass the parameters to */
readonly name: string;
/** The category of the matcher */
readonly category: string;
/** The namespace of the matcher */
readonly namespace: string;
};
/**
* Indicates a parameter type which assigns the given parameter(s) to a matcher.
*
* This is useful for making composite matchers.
*
* See the definition of the core function plugin for an example.
*/
export type PassToMatcher = {
/** What kind of container this is. Future unions of this type will always have this parameter */
readonly kind: 'PassToMatcher';
/**
* The type of the parameters to pass to the matcher.
*
* These are passed to the matcher's constructor in order.
*
* Make sure they are correct, and in the correct order - no checking of the
* parameters is done by the generator. We recommend that you generally
* only reference matchers within the same package, to avoid breaking changes.
*/
readonly exposedParams: ParameterDeclaration[];
/** Identifies the matcher to pass these parameters to */
readonly matcherReference: MatcherReference;
};
/**
* Type guard function that determines whether a ParameterType is a TypeContainer
* or a plain string type.
*
* @param parameterType - The parameter type to check
* @returns true if the parameter is a TypeContainer, false if it's a string
*/
export declare const isTypeContainer: (parameterType: ParameterType) => parameterType is TypeContainer;
export declare const isPassToMatcher: (parameterType: ParameterType) => parameterType is PassToMatcher;
/**
* Declares a parameter for a matcher
*/
export type ParameterDeclaration = {
/**
* The name of the parameter, used for documentation, actual method
* declaration, and any builders.
*
* These must be unique within a single matcher definition.
*
* Must contain only alphanumeric characters (no spaces or other characters),
* and must begin with a letter. If there are mutliple words, use camelCase.
*
* Note that there are some reserved names or names with side effects:
*
* - `type`: Reserved for the matcher type
* - `example`: Allowed, but will be used as the rendered example for this node.
* - `resolvesTo`: Allowed, but will control what ContractCase thinks the type of
* the example is.
*
* If you use this any of these as a parameter name, and don't want the additional
* behaviour, you must supply a jsonPropertyName.
*/
readonly name: string;
/**
* Documentation for the parameter.
*
* Yes, this is required. We're not sorry about that,
* and the users of your plugin won't be sorry about it either.
*/
readonly documentation: string;
/** Type of this parameter */
readonly type: ParameterType;
/**
* If set, whether or not this parameter is optional. Optional parameters must
* be the last ones in order. Defaults to required if not set
*
* Note: Optional parameters are not supported for pass-to-matcher parameters
*/
readonly optional?: boolean;
/** If set, will override the generated json property name for this parameter */
readonly jsonPropertyName?: string;
};
/** Defines an object. */
export type DslObjectDeclaration = {
readonly name: string;
/**
* The type constant for your matcher, without the namespace.
* Along with the namespace, this is what ContractCase uses to
* determine which implementation to use at match time.
*
* Although these must be globally unique for matcher _implementations_,
* here we're defining the matcher _DSL_. This means that more
* than one MatcherDslDeclaration can share the same type constant.
*
* This is useful if you want to have different defaults or different
* names in the DSL for the same matcher.
*/
readonly type: string;
/**
* Documentation for this object. Yes, this is required. We're not sorry about that,
* and the users of your plugin won't be sorry about it either.
*/
readonly documentation: string;
/** An ordered array of parameter declarations. If any parameters are optional, they must be at the end. */
readonly params: ParameterDeclaration[];
};
/**
* Defines the DSL for a matcher.
*
* Note that more than one Matcher DSL can point
* to the same matcher implementation - that is, you might have
* multiple DSL objects with the same type.
*/
export type MatcherDslDeclaration = DslObjectDeclaration & {
/**
* A map of constant parameters to add to the matcher.
* These are parameters that are always the same for all instances of the matcher.
*
* See the notes about reserved names on {@link ParameterDeclaration}
*
* Currently only strings are supported. If you have a more complex use case, please raise an issue.
*/
readonly constantParams?: Record<string, string> & {
/**
* If specified, sets the `matcher:resolvesTo` value.
*
* This tells ContractCase that the example will always resolve to this specific type.
*
* It's mostly useful for generating a type-safe DSL, although some matchers
* may also read it for validation purposes.
*/
readonly resolvesTo?: Extract<ParameterType, 'string' | 'boolean' | 'number' | 'integer' | 'null'>;
};
/**
* A map of context modifiers to add to the `'_case:context'`
* context object. These control ContractCase's matching behaviour
*/
readonly contextModifiers?: Record<string, string>;
/**
* A map of modifiers to add to the current run
* context, `'_case:currentRun:context'` These can be used to
* add matchers that change the user configuration below it.
* Most of the time you won't need to provide these.
*/
readonly currentRunModifiers?: Record<string, string>;
};
export type StateObjectDeclaration = DslObjectDeclaration;
export type InteractionDslDeclaration = DslObjectDeclaration & {
/**
* Controls the behaviour of the mocked interaction for definition and verification
*/
readonly setup: InternalContractCaseCoreSetup;
};
//# sourceMappingURL=types.d.ts.map