Path: blob/main/extensions/copilot/test/base/validate.ts
13388 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4export type KeywordPredicate =5| string6| { anyOf: readonly KeywordPredicate[] }7| { allOf: readonly KeywordPredicate[] }8| { not: readonly KeywordPredicate[] }9;1011export function validate(answer: string, predicate: readonly KeywordPredicate[] | object): string | undefined {12const predicates = Array.isArray(predicate) ? predicate : Object.entries(predicate).map(([key, value]) => ({ [key]: value }));13const errors = predicates.map(pred => validatePredicate(answer, pred)).filter(err => !!err);14if (errors.length) {15return `Failed checks:\n${errors.join('\n')}`;16}17return undefined;18}1920function validatePredicate(answer: string, predicate: KeywordPredicate): string | undefined {21if (typeof predicate === 'string') {22const startsWithWordChar = /^\w/.test(predicate);23const endsWithWordChar = /\w$/.test(predicate);24// Use word boundaries to prevent matching inside words25if (!new RegExp((startsWithWordChar ? '\\b' : '') + escapeRegExpCharacters(predicate) + (endsWithWordChar ? '\\b' : ''), 'i').test(answer)) {26return `Missing keyword: ${predicate}`;27}28return;29} else {30if ('anyOf' in predicate) {31const errors = (predicate.anyOf as readonly KeywordPredicate[])32.map(pred => validatePredicate(answer, pred));3334if (!errors.some(err => typeof err === 'undefined')) {35return `All anyOf checks failed:\n${errors.join('\n')}`;36}37}3839if ('allOf' in predicate) {40const result = validate(answer, predicate.allOf);41if (result?.length) {42return result;43}44}4546if ('not' in predicate) {47const result = validate(answer, predicate.not);48if (!result?.length) {49return 'Expected not';50}51}5253return;54}55}5657/**58* Escapes regular expression characters in a given string59*/60function escapeRegExpCharacters(value: string): string {61return value.replace(/[\\\{\}\*\+\?\|\^\$\.\[\]\(\)]/g, '\\$&');62}6364