/**
* 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'
);