-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validators #5
Validators #5
Conversation
sr480
commented
Oct 2, 2023
- Валидация Meta и Features
- Добавил форматы ошибок валидаторов,
- Добавил в cli команду validate
0ad9187
to
e1fdbbd
Compare
@@ -9,6 +9,7 @@ | |||
"dist" | |||
], | |||
"scripts": { | |||
"start": "NODE_TLS_REJECT_UNAUTHORIZED=0 ts-node ./src/cli.ts", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
добавил команду для запуска без аргументов, запускаю проверку вот так: npm start -- validate
src/commands/validate-only.ts
Outdated
|
||
const meta = await loadMeta(yml.metaPath, projectPath); | ||
|
||
const metaValidation = validateMeta(meta); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Отдельный набор ошибок по валидации Meta, тут же строю мапу для атрибутов-значений
Может стоит останавливать валидацию, если есть ошибки в Meta?
src/commands/validate-only.ts
Outdated
); | ||
|
||
console.log(metaValidation); | ||
console.log(featureValidation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Хочу получить ревью, до того как буду делать красивый вывод ошибок
src/lib/domain/index.ts
Outdated
const component = attributes?.component.join("-"); | ||
const subComponent = attributes?.["sub-component"].join("-"); | ||
code = `${component}_${subComponent}`; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Пришлось переписать, так как в моих yml нет таких атрибутов
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
я планировал этот код выпилить сегодня и брать значение только из поля code
(сделать его обязательным)
через пару часов пришлю PR
src/lib/domain/validators.ts
Outdated
attributeValuesMap: AttributeValuesMap | ||
): ValidationError[] => { | ||
const errors = new Array<ValidationError>(); | ||
const featureCodesUnique = new Map<string, Feature>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Строю мап фичей по кодам, чтобы проверять дубликаты и указывать на фичу первым встретившимся кодом
src/lib/validators.ts
Outdated
| FeatureMissingAttributeError | ||
| FeatureMissingAttributeValueError | ||
| CodeError; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Не добавлял filePath в ошибки, так как он содержится в Feature
src/lib/validators/index.ts
Outdated
|
||
if (feature.attributes) { | ||
for (const attribute in feature.attributes) { | ||
let valuesSet = this.metaAttributeValues.get(attribute); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Нужно ли проверять валидность кода атрибута? Все-равно выпадет ошибка, так как он не будет найден в мета, а там идет проверка формата кода атрибута.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
в месте использования валидность кода атрибута проверять не нужно — только в месте объявления атрибута
код значения нужно проверять, т.к. значения можно не объявлять в мете
): Promise<YamlFile> => { | ||
basePath: string = CWD, // TODO: перенести в resolvePath | ||
validationContext?: Validator | ||
): Promise<YamlFile | undefined> => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
я решил возвращать undefined, если отловил ошибку. из-за этого снаружи приходится фильтровать файлы перед последующей обработкой
|
||
const projectData = processYamlFiles(yamls, meta); | ||
const projectData = processYamlFiles(successYamls, meta); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Пришлось добавить код выбора только успешно декодированных yaml
src/lib/config/index.ts
Outdated
'config' | ||
); | ||
} else { | ||
throw error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
если не переда кнтекст валидации, то валимся с исключением, так как некому собирать ошибки
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю сделать контекст валидации обязательным параметром, чтобы логика работы sync и validate отличалась только наличием в конце операции выгрузки данных
}; | ||
} catch (error) { | ||
if (validationContext) { | ||
validationContext.registerLoaderError(error, relativePath, 'feature'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
тут аналогично, либо собираем ошибки в конексте валидации либо валимся с исключением
src/lib/domain/validators.ts
Outdated
}; | ||
errors.push(featureCodeError); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю вынести валидацию формата кода во всех сущностях на уровень проверки схемы
src/lib/domain/validators.ts
Outdated
feature, | ||
firstFeature: existingFeature, | ||
}; | ||
errors.push(featureCodeDuplicateError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
код может повторяться несколько раз
лучше бы выдавать ошибку вида:
повторяется код <код> в файлах: [ ... ]
src/lib/domain/validators.ts
Outdated
errors.push(missingAttribute); | ||
continue; | ||
} | ||
for (const attributeValue of feature.attributes[attribute]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
проверять наличие всех значений не нужно, т.к. частая ситуация, когда есть большое количество значений и они не описаны в конфиге — считаем, что это нормально и при выгрузке автоматом добавляем в базу недостающие занчения
с атрибутами так не прокатит, т.к. мы ссылаемся на атрибуты из других мест (например, из деревьев), поэтому проверяем наличие атрибутов
src/lib/domain/index.ts
Outdated
@@ -91,3 +94,5 @@ export const processYamlFiles = ( | |||
|
|||
return { features, attributes, trees }; | |||
}; | |||
|
|||
export * from './validators'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю все валидаторы вынести в отдельную папку validation
на одном уровне с папками config
и domain
src/commands/sync.ts
Outdated
@@ -21,8 +21,10 @@ export const cmdSync: CommandModule<{}, CommonOptions> = { | |||
const yamls = await Promise.all( | |||
files.map((path) => loadYaml(path, projectPath)) | |||
); | |||
const successYamls = new Array<YamlFile>(); | |||
yamls.forEach(yaml => yaml && successYamls.push(yaml)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю написать
const successYamls = yamls.filter(Boolean)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
не получится, тогда нужно еще map делать, так как тип у массива останется (YamlFile | undefined)[]
:(
src/lib/config/index.ts
Outdated
'config' | ||
); | ||
} else { | ||
throw error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю сделать контекст валидации обязательным параметром, чтобы логика работы sync и validate отличалась только наличием в конце операции выгрузки данных
src/lib/validators/index.ts
Outdated
|
||
if (feature.attributes) { | ||
for (const attribute in feature.attributes) { | ||
let valuesSet = this.metaAttributeValues.get(attribute); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
в месте использования валидность кода атрибута проверять не нужно — только в месте объявления атрибута
код значения нужно проверять, т.к. значения можно не объявлять в мете
src/lib/validators/index.ts
Outdated
|
||
export class Validator { | ||
private readonly featuresMap = new Map<string, Feature>(); | ||
private readonly metaAttributeValues = new Map<string, Set<string>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
немного смущает, что featuresMap
и metaAttributeValues
находятся в полях класса, к ним есть обращения из методов, но в момент обращения эти значения могут быть не заполнены данными
предлагаю объявить их как локальные переменные методов и явно передавать во вложенные методы как параметры
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
т.к. validateMeta
и validateFeatures
используются ровно в одном месте и вызываются вместе, то предлагаю объединить их в один метод и сделать featuresMap
и metaAttributeValues
его локальными переменными
также этот метод можно вынести в родителя из processYamlFiles
также вместо параметров meta
и fetures
в него можно передавать один параметр типа ProjectData
, который содержит всю ту же самую информацию (т.е. передать в него возвращаемое значение от метода processYamlFiles
)
c49d2a8
to
18fcd04
Compare
src/lib/config/index.ts
Outdated
return content || {}; | ||
} catch (error) { | ||
validationContext.registerLoaderError(error, filePath, 'config'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
если не загрузилась мета, нужно падать с ошибкой, т.к. без этого точно не пройдет валидация остальных файлов
src/lib/validators/index.ts
Outdated
| 'description' | ||
| 'title' | ||
| 'group.title' | ||
| 'group.description' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
вроде бы у группы нельзя задать description
src/lib/validators/index.ts
Outdated
const links = LINK_LIKE.exec(value); | ||
if (links) { | ||
for (let link of links) { | ||
link = link.substring(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
если regexp изменится, то никак нельзя догадаться, что нужно пойти в это место и поправить логику
предлагаю сделать группу в regex и вместо substring выбирать группу + оставить комментарий об этом в месте, где описан regex
src/lib/validators/index.ts
Outdated
import { Assertion, AssertionGroup, Feature } from '../domain'; | ||
import { printError } from './renderer'; | ||
|
||
export type AttributeDuplicateError = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю вынести валидатор в отдельный файл + вынести описание интерфейсов в файл model.ts
(по аналогии с другими частям проекта), а в index.ts
оставить только экспорт элементов, которые используются снаружи
src/lib/jest/index.ts
Outdated
@@ -50,14 +56,20 @@ export const applyJestReport = ( | |||
const parts = getKey(keyParts, assertionCtx, attributesCtx); | |||
const fullName = getFullName(...parts); | |||
|
|||
console.log("process: \x1b[36m%s\x1b[0m", fullName); | |||
console.log(`process: ${chalk.cyan(fullName)}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю этот console.log
убрать совсем — он был нужен, когда не было нормальной валидации, чтобы смотреть какие тесты не сматчились на фичи
src/commands/sync.ts
Outdated
const { yml, api, jest, projectPath } = await loadConfig(args.config); | ||
|
||
const meta = await loadMeta(yml.metaPath, projectPath); | ||
const meta = await loadMeta(validationContext, yml.metaPath, projectPath); | ||
const files = await glob(yml.files, { cwd: projectPath }); | ||
|
||
const yamls = await Promise.all( | ||
files.map((path) => loadYaml(path, projectPath)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
кажется, нужно в loadYaml
передать validationContext
src/lib/validators/renderer.ts
Outdated
@@ -1,50 +1,55 @@ | |||
import chalk from 'chalk'; | |||
import { ERROR_SEVERITY, ErrorSeverity, ValidationError, ValidationErrorTypes } from './models'; | |||
import { ERROR_SEVERITY, ErrorSeverity, ValidationError } from './models'; | |||
|
|||
const renderError = (e: ValidationError): string => { | |||
switch(e.type){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
изменен формат вывода ошибок:
- добавил разделение сообщений пустой строкой и яркий маркер начала нового сообщения
- сделал начало сообщений на одном уровне (раньше начало сообщения зависело отдлины пути к файлу)
- покрасил путь к файлу в серый (чтобы привлекал меньше внимания)
- вместо нескольких цветов все значения вывожу одним цветом
} | ||
} | ||
|
||
const path = (p: string) => chalk.gray(p); | ||
const strong = (p: string) => chalk.bold(p); | ||
const val = (p: string) => chalk.cyan(p); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
сделал семантические хелперы, чтобы при изменении формата он единообразно менялся во всех сообщениях
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
классно!
@@ -129,7 +128,8 @@ export class Validator { | |||
): ValidationError[] { | |||
const result = new Array<ValidationError>(); | |||
for (const attributeValue of attribute.values) { | |||
const valueValidation = this.validateCode(attribute.code, filePath); | |||
const valueValidation = this.validateCode(attributeValue.code, filePath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
была опечатка — вместо кода значения проверялся код атрибута
src/lib/validators/validator.ts
Outdated
for (const tree of trees) { | ||
const treeUnique = new Set<string>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
была опечатка — на каждом шаге цикла создавался новый set
src/lib/validators/validator.ts
Outdated
}; | ||
errors.push(groupDuplicateError); | ||
} | ||
groupsUnique.add(assertionGroup.title); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
выпилил эту проверку, т.к. список групп описывается как dictionary и если задублируются значения групп, то упадет проверка формата
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ага, я видел, что есть в yaml такое ограничение, но подумал оставить - вдруг формат yaml решим поменять, а для БД это критично
src/lib/validators/models.ts
Outdated
@@ -78,12 +78,7 @@ export type FeatureMissingLinkError = { | |||
| 'assert.description'; | |||
link: string; | |||
}; | |||
export type AssertionGroupDuplicateError = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Разве не стоит считать дубли групп ассертов ошибками?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
по идее, это ошибка, но уже есть два места, которые её обрабатывают:
- упадет разбор формата
- на сервере при экспорте одинаковые группы склеятся в одну
кажется, если мы добавим еще одну проверку, то в реальной жизни она никогда не сработает (и если она сломается, мы об этом не узнаем)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
т.е. суть предложения — не оставлять в проекте неиспользуемый код
} | ||
} | ||
|
||
const path = (p: string) => chalk.gray(p); | ||
const strong = (p: string) => chalk.bold(p); | ||
const val = (p: string) => chalk.cyan(p); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
классно!
src/lib/validators/validator.ts
Outdated
}; | ||
errors.push(groupDuplicateError); | ||
} | ||
groupsUnique.add(assertionGroup.title); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ага, я видел, что есть в yaml такое ограничение, но подумал оставить - вдруг формат yaml решим поменять, а для БД это критично
src/lib/config/index.ts
Outdated
|
||
try { | ||
validationContext.setMetaFilePath(filePath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
выпилить setMetaFilePath
?
src/lib/config/index.ts
Outdated
return content || {}; | ||
} catch (error) { | ||
printError(getLoaderError(error, filePath, 'config')); | ||
throw 'Ошибка загрузки файла конфигурации'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
давай, пожалуйста, в throw всегда будем передавать объект Error
?
throw new Error('Ошибка загрузки файла конфигурации');
src/lib/validators/validator.ts
Outdated
private metaFilePath = ''; | ||
|
||
get hasCriticalErrors(): boolean { | ||
let hasError = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
предлагаю написать так:
let hasError = [
...loaderErrors,
...metaErrors,
...featureErrors,
...jestUnusedTests].some(e => ERROR_SEVERITY[e.type] === 'error');
820a41f
to
72eb499
Compare