/** * WordPress dependencies */ import { BaseControl } from '@safe-wordpress/components'; import { _x } from '@safe-wordpress/i18n'; /** * External dependencies */ import { CompletionContext } from '@codemirror/autocomplete'; import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; import { CodeEditor, ConversionActionScope, ErrorText } from '@nab/components'; import type { CAEditProps } from '@nab/types'; /** * Internal dependencies */ import type { Attributes } from './types'; export const Edit = ( { attributes: { snippet }, scope, errors, setAttributes, setScope, }: CAEditProps< Attributes > ): JSX.Element => ( <> }> setAttributes( { snippet: value } ) } placeholder={ HELP } config={ { completions: [ customCompletions ], globals: [ 'convert', 'utils' ], rules: { 'detect-convert': { level: 'error', module: detectConvertRule, }, }, } } /> ); // ======= // HELPERS // ======= const detectConvertRule: TSESLint.RuleModule< 'missingConvert', [] > = { meta: { type: 'problem', docs: { description: _x( 'Ensure convert() is called', 'user', 'nelio-ab-testing' ), }, messages: { missingConvert: _x( 'The function convert() must be called at least once.', 'text', 'nelio-ab-testing' ), }, schema: [], // No schema, no options }, defaultOptions: [], create( context ) { let hasConvertCall = false; return { CallExpression( node: TSESTree.CallExpression ) { if ( // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison node.callee.type === 'Identifier' && node.callee.name === 'convert' ) { hasConvertCall = true; } }, 'Program:exit'() { if ( ! hasConvertCall ) { context.report( { loc: { line: 1, column: 0 }, messageId: 'missingConvert', } ); } }, }; }, }; function customCompletions( context: CompletionContext ) { const utils = context.matchBefore( /utils\.\w*/ ); if ( utils ) { return { from: utils.text.replace( /\w*$/, '' ).length + utils.from, options: [ { label: 'onVariantReady', type: 'function', apply: 'onVariantReady(() => {\n});', detail: '(callback:Function) => void', info: _x( 'Runs callback when variant is ready.', 'text', 'nelio-ab-testing' ), }, ], }; } const word = context.matchBefore( /\w*/ ); if ( ! word ) { return null; } if ( word.from === word.to && ! context.explicit ) { return null; } return { from: word.from, options: [ { label: 'convert', type: 'function', apply: 'convert()', detail: '() => void', info: _x( 'Triggers a conversion using the appropriate variant and goal settings.', 'text', 'nelio-ab-testing' ), }, { label: 'utils', type: 'variable', apply: 'utils', detail: 'Object', info: _x( 'Contains several helper functions.', 'text', 'nelio-ab-testing' ), }, ], }; } const HELP = _x( 'Write the logic for your conversion here and call “convert()” to actually trigger the conversion when necessary.', 'user', 'nelio-ab-testing' ) + ' ' + _x( 'Please keep in mind the code will not run until the DOM’s ready.', 'user', 'nelio-ab-testing' );