From d656b9ea0d698079520a390174324e5009b50969 Mon Sep 17 00:00:00 2001 From: Erwin G Date: Wed, 17 Jul 2024 18:55:21 -0500 Subject: [PATCH] new 2 version --- .directoryvalidator.json | 37 +--- biome.json | 28 +++ package.json | 3 +- src/_tests/program/index.test.ts | 2 +- src/_tests/validator/directory.ts | 40 +++- src/_tests/validator/fileDirectory.ts | 22 +- src/helpers/file.ts | 56 +++++ src/index.ts | 25 ++- src/program.ts | 42 ++-- src/validator.ts | 206 ++++++++++-------- testing-schema.json | 92 ++++++++ testing/empty_folder.zip | Bin 0 -> 691 bytes .../empty_folder/temp40/temp41/testfile.json | 113 ++++++++++ .../empty_folder/temp40/temp42/testfile.json | 113 ++++++++++ testing/empty_folder/testfile.json | 113 ++++++++++ testing/max_stack_folder.zip | Bin 0 -> 691 bytes testing/max_stack_folder/testfile.json | 113 ++++++++++ tsconfig.json | 2 +- 18 files changed, 826 insertions(+), 181 deletions(-) create mode 100644 biome.json create mode 100644 src/helpers/file.ts create mode 100644 testing-schema.json create mode 100644 testing/empty_folder.zip create mode 100644 testing/empty_folder/temp40/temp41/testfile.json create mode 100644 testing/empty_folder/temp40/temp42/testfile.json create mode 100644 testing/empty_folder/testfile.json create mode 100644 testing/max_stack_folder.zip create mode 100644 testing/max_stack_folder/testfile.json diff --git a/.directoryvalidator.json b/.directoryvalidator.json index e30d569..7032092 100644 --- a/.directoryvalidator.json +++ b/.directoryvalidator.json @@ -3,9 +3,10 @@ ".gitignore", ".directoryvalidator.json", "package-lock.json", - ".DS_Store" + ".DS_Store", + "**/.DS_Store" ], - "ignoreDirs": ["node_modules", "dist", ".git", ".github"], + "ignoreDirs": ["node_modules", "dist", ".git", ".github", "**/temp42"], "commonRules": { "rule_indexfile": { "type": "file", @@ -15,33 +16,17 @@ "rules": [ { "type": "file", - "name": "package.json" - }, - { - "type": "file", - "name": "LICENSE" - }, - { - "type": "file", - "name": "tsconfig.json" - }, - { - "type": "file", - "name": "jest.*.js" - }, - { - "type": "file", - "name": "*.md" - }, - { - "type": "file", - "name": ".prettier*" + "name": "testfile.json" }, { "type": "directory", - "name": "src", - "isOptional": true, - "rules": [] + "name": "temp2", + "rules": [ + { + "type": "directory", + "name": "temp3" + } + ] } ] } diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..d57dfab --- /dev/null +++ b/biome.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.8.2/schema.json", + "organizeImports": { + "enabled": true + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "complexity": { + "noForEach": "off" + }, + "correctness": { + "noUnusedImports": "error", + "noUnusedVariables": "error" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + } +} diff --git a/package.json b/package.json index c5e6b57..929143f 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,11 @@ "directory-validator": "dist/index.js" }, "scripts": { + "dev": "npx tsx src/index.ts", "build": "npm run clean && tsc && cp src/resources/* dist/resources", "clean": "rm -rf dist", "prettier": "prettier -c .", - "test": "npm run prettier && jest" + "test": "jest" }, "author": "Erwin Gaitan O ", "license": "MIT", diff --git a/src/_tests/program/index.test.ts b/src/_tests/program/index.test.ts index a8c889e..776fc58 100644 --- a/src/_tests/program/index.test.ts +++ b/src/_tests/program/index.test.ts @@ -1,4 +1,4 @@ -import * as path from 'path'; +import path from 'node:path'; import * as errors from '../../errors'; import * as program from '../../program'; diff --git a/src/_tests/validator/directory.ts b/src/_tests/validator/directory.ts index 18e55bd..e5adf8b 100644 --- a/src/_tests/validator/directory.ts +++ b/src/_tests/validator/directory.ts @@ -1,4 +1,4 @@ -import * as types from '../../types'; +import type * as types from '../../types'; import * as validator from '../../validator'; export function run() { @@ -61,7 +61,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - `${JSON.stringify(configObject[0])}, deep: 1, rule did not passed` + `${JSON.stringify(configObject[0])}, deep: 1, rule did not passed`, ); }); @@ -158,7 +158,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - '}, deep: 2, rule did not passed' + '}, deep: 2, rule did not passed', ); }); @@ -172,7 +172,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - `${JSON.stringify(configObject[0])}, deep: 1, rule did not passed` + `${JSON.stringify(configObject[0])}, deep: 1, rule did not passed`, ); }); @@ -233,7 +233,7 @@ export function run() { }); describe('EmptyDirs:', () => { - it('should validate empty dir has no rules', () => { + it('should validate empty dir with no rules', () => { const files: string[] = []; const emptyDirs = ['src']; @@ -245,7 +245,29 @@ export function run() { ]; expect(() => - validator.run(files, configObject, emptyDirs) + validator.run(files, configObject, emptyDirs), + ).not.toThrow(); + }); + + it('should validate nested empty dir with no rules', () => { + const files: string[] = []; + const emptyDirs = ['src/lol']; + const configObject: types.Rules = [ + { + name: 'src', + type: 'directory', + rules: [ + { + name: 'lol', + type: 'directory', + rules: [], + }, + ], + }, + ]; + + expect(() => + validator.run(files, configObject, emptyDirs), ).not.toThrow(); }); @@ -262,9 +284,9 @@ export function run() { ]; expect(() => - validator.run(files, configObject, emptyDirs) + validator.run(files, configObject, emptyDirs), ).toThrowError( - `${JSON.stringify(configObject[0])}, deep: 1, rule did not passed` + `${JSON.stringify(configObject[0])}, deep: 1, rule did not passed`, ); }); @@ -280,7 +302,7 @@ export function run() { ]; expect(() => - validator.run(files, configObject, emptyDirs) + validator.run(files, configObject, emptyDirs), ).toThrowError('src, was not validated'); }); }); diff --git a/src/_tests/validator/fileDirectory.ts b/src/_tests/validator/fileDirectory.ts index 5d1f3ef..5208c3d 100644 --- a/src/_tests/validator/fileDirectory.ts +++ b/src/_tests/validator/fileDirectory.ts @@ -132,7 +132,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - `${JSON.stringify(configObject[2])}, deep: 1, rule did not passed` + `${JSON.stringify(configObject[2])}, deep: 1, rule did not passed`, ); }); @@ -155,7 +155,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - `${files[3]}, was not validated` + `${files[3]}, was not validated`, ); }); @@ -211,7 +211,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - `${files[4]}, was not validated` + `${files[4]}, was not validated`, ); }); @@ -244,8 +244,8 @@ export function run() { expect(() => validator.run(files, configObject)).toThrowError( `${JSON.stringify( - (configObject[0] as types.DirectoryRule).rules![2] - )}, deep: 2, rule did not passed` + (configObject[0] as types.DirectoryRule).rules![2], + )}, deep: 2, rule did not passed`, ); }); @@ -273,8 +273,8 @@ export function run() { expect(() => validator.run(files, configObject)).toThrowError( `${JSON.stringify( - (configObject[0] as types.DirectoryRule).rules![0] - )}, deep: 2, rule did not passed` + (configObject[0] as types.DirectoryRule).rules![0], + )}, deep: 2, rule did not passed`, ); }); @@ -305,8 +305,8 @@ export function run() { expect(() => validator.run(files, configObject)).toThrowError( `${JSON.stringify( - (configObject[0] as types.DirectoryRule).rules![0] - )}, deep: 2, rule did not passed` + (configObject[0] as types.DirectoryRule).rules![0], + )}, deep: 2, rule did not passed`, ); }); }); @@ -357,7 +357,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - 'srrcNice/index.js, was not validated' + 'srrcNice/index.js, was not validated', ); }); }); @@ -393,7 +393,7 @@ export function run() { ]; expect(() => validator.run(files, configObject)).toThrowError( - 'SRC/index.js, was not validated' + 'SRC/index.js, was not validated', ); }); }); diff --git a/src/helpers/file.ts b/src/helpers/file.ts new file mode 100644 index 0000000..0b6c4f2 --- /dev/null +++ b/src/helpers/file.ts @@ -0,0 +1,56 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +type File = { + type: 'file'; + fullPath: string; + path: string; +}; + +type Directory = { + type: 'dir'; + fullPath: string; + path: string; + isEmpty: boolean; +}; + +export function getFilesAndDirectories( + dirPath: string, + options: { + recursive: boolean; + _initialPath?: string; + ignoreFilesAndDirectories?: string[]; + } = { recursive: true }, +): (File | Directory)[] { + const items = fs.readdirSync(dirPath); + options._initialPath = options._initialPath || dirPath; + const lPath = path.relative(options._initialPath, dirPath); + + if (options.ignoreFilesAndDirectories?.includes(lPath)) return []; + + const result: (File | Directory)[] = [ + { + type: 'dir', + fullPath: dirPath, + path: lPath, + isEmpty: items.length === 0, + }, + ]; + + for (const item of items) { + const fullPath = path.join(dirPath, item); + const itemStat = fs.statSync(fullPath); + const localPath = path.relative(options._initialPath, fullPath); + + if (itemStat.isDirectory()) { + if (!options.recursive) + result.push({ type: 'dir', fullPath, path: localPath, isEmpty: false }); + else result.push(...getFilesAndDirectories(fullPath, options)); + } else { + if (options.ignoreFilesAndDirectories?.includes(localPath)) continue; + result.push({ type: 'file', fullPath, path: localPath }); + } + } + + return result; +} diff --git a/src/index.ts b/src/index.ts index bbf39c8..4eaa3c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,9 +2,9 @@ import 'colors'; import { program as commanderProgram } from 'commander'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; import * as errors from './errors'; import * as program from './program'; @@ -31,13 +31,13 @@ function getDefaultConfigFilePath(dirPath: string) { export function writeDefaultConfigFile(parentPath: string) { fs.copyFileSync( path.join(__dirname, './resources/defaultConfig.json'), - parentPath + parentPath, ); } commanderProgram.version( JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8')) - .version + .version, ); commanderProgram @@ -46,11 +46,11 @@ commanderProgram .option('-p, --print', 'Print the directory structure validated') .option( '-f, --ignore-files ', - 'Ignore files (glob string) eg: -f "*.js"' + 'Ignore files (glob string) eg: -f "*.js"', ) .option( '-d, --ignore-dirs ', - 'Ignore directories (glob string) eg: -d "**/tests"' + 'Ignore directories (glob string) eg: -d "**/tests"', ) .option('-c, --config-file ', 'Path to the configuration file') .parse(process.argv); @@ -60,7 +60,7 @@ const selectedOptions = commanderProgram.opts(); if (selectedOptions.init) { fs.copyFileSync( path.join(__dirname, './resources/defaultConfig.json'), - path.join(process.cwd(), initConfigFilename) + path.join(process.cwd(), initConfigFilename), ); console.log('\n\t', initConfigFilename.red, 'created', '\n'); } else if (!commanderProgram.args.length) { @@ -86,12 +86,13 @@ if (selectedOptions.init) { results.asciiTree .replace(/\/fileIgnored/g, '[File Ignored]'.dim) .replace(/\/directoryIgnored/g, '[Directory Ignored]'.dim) - .replace(/\/emptyDirectory/g, '[Empty Directory]'.dim) + .replace(/\/emptyDirectory/g, '[Empty Directory]'.dim), ); } } catch (err) { const dash = '-'.bold; - const errorTitle = '\n\t' + 'Error:'.red.underline; + const errorTitle = `\n\t${'Error:'.red.underline}`; + if (err instanceof errors.JsonParseError) { console.error(errorTitle, 'at config file:'.red, err.filePath); @@ -100,7 +101,7 @@ if (selectedOptions.init) { } else if (err instanceof errors.ConfigJsonValidateError) { console.error(errorTitle, 'at config file:'.red, err.filePath); err.messages.forEach((el) => - console.error('\t', dash, `${el[0].red}:`, el[1]) + console.error('\t', dash, `${el[0].red}:`, el[1]), ); } else if (err instanceof errors.ValidatorRuleError) { console.error(errorTitle); @@ -112,7 +113,7 @@ if (selectedOptions.init) { 'Rule', rule.red, 'did not passed at:', - parentPath.red + parentPath.red, ); } else if (err instanceof errors.ValidatorInvalidPathError) { console.error(errorTitle); diff --git a/src/program.ts b/src/program.ts index a5161c1..c033b9f 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1,16 +1,13 @@ import Ajv from 'ajv'; -import * as fs from 'fs'; +import fs from 'node:fs'; import * as glob from 'glob'; -import { - generateAsciiTree, - getChildDirs, - getChildFiles, -} from 'goerwin-helpers/node/file'; +import { generateAsciiTree } from 'goerwin-helpers/node/file'; import * as _ from 'lodash'; import * as errors from './errors'; import schema from './resources/schema.json'; -import * as types from './types'; +import type * as types from './types'; import * as validator from './validator'; +import { getFilesAndDirectories } from './helpers/file'; function getConfig(rulesPath: string): types.Config { let configJson: any; @@ -29,7 +26,7 @@ function getConfig(rulesPath: string): types.Config { if (ajv.errors) { errorMessages = ajv.errors.map( - (el) => [`data${el.instancePath}`, `${el.message || ''}`] + (el) => [`data${el.instancePath}`, `${el.message || ''}`], // TODO: Verify // [`data${el.dataPath}`, `${el.message || ''}`] ); @@ -47,7 +44,7 @@ function getConfig(rulesPath: string): types.Config { if (!parsedRule) { throw new errors.ConfigJsonValidateError( [['Common Rule Invalid', JSON.stringify(rule)]], - rulesPath + rulesPath, ); } @@ -59,7 +56,9 @@ function getConfig(rulesPath: string): types.Config { : parsedRule.isOptional; return { ...parsedRule }; - } else if (rule.type === 'directory') { + } + + if (rule.type === 'directory') { rule.rules = parseCommonRules(rule.rules || []); } @@ -84,7 +83,7 @@ export function run( options: { ignoreDirsGlob?: string; ignoreFilesGlob?: string; - } = {} + } = {}, ) { const { ignoreFiles, ignoreDirs, rules } = getConfig(configPath); @@ -108,28 +107,17 @@ export function run( ? glob.sync(ignoreDirsGlob, { cwd: dirPath }) : []; - const files = getChildFiles(dirPath, { - recursive: true, - ignoreDirs: newIgnoreDirs, - ignoreFiles: newIgnoreFiles, - }); - - const emptyDirs = getChildDirs(dirPath, { + const filesAndDirs = getFilesAndDirectories(dirPath, { recursive: true, - ignoreDirs: newIgnoreDirs, - ignoreFiles: newIgnoreFiles, + ignoreFilesAndDirectories: [...newIgnoreFiles, ...newIgnoreDirs], }); - validator.run( - files.filter((el) => !el.isIgnored).map((el) => el.path), - rules, - emptyDirs.filter((el) => !el.isIgnored && el.isEmpty).map((el) => el.path) - ); + validator.run(filesAndDirs, rules); return { asciiTree: generateAsciiTree(dirPath, [ - ...files, - ...emptyDirs.filter((el) => el.isIgnored || el.isEmpty), + // ...files, + // ...dirs.filter((el) => el.isIgnored || el.isEmpty), ]), }; } diff --git a/src/validator.ts b/src/validator.ts index 96b535b..74e5595 100644 --- a/src/validator.ts +++ b/src/validator.ts @@ -1,7 +1,8 @@ -import * as _ from 'lodash'; -import * as path from 'path'; +import _ from 'lodash'; +import path from 'node:path'; import * as errors from './errors'; -import * as types from './types'; +import type * as types from './types'; +import type { getFilesAndDirectories } from './helpers/file'; function getCorrectStringRegexp(name: string | RegExp) { if (typeof name === 'string') { @@ -45,14 +46,14 @@ function getMultimatchName(nameRule: string) { leftSide: string; rightSide: string; } - | undefined + | undefined, ); } function getDirFiles( - files: types.ValidatableFile[], + files: { path: string; type: 'file' | 'dir' }[], paths: (string | RegExp)[], - isRecursive = false + isRecursive = false, ) { return files.filter((el) => { let pathSegments = el.path.split(path.sep); @@ -73,6 +74,17 @@ function getDirFiles( }); } +function getDirChildren( + filesAndDirs: { path: string; type: 'file' | 'dir' }[], + dirPath: string, +) { + return filesAndDirs.filter((item) => { + if (item.path.indexOf(dirPath) !== 0) return false; + if (item.path === dirPath) return false; + return item.path.indexOf('/', dirPath.length + 1) === -1; + }); +} + function isNameValid(nameRule: string | RegExp, name: string) { if (nameRule instanceof RegExp) { return nameRule.test(name); @@ -92,7 +104,7 @@ function isNameValid(nameRule: string | RegExp, name: string) { const filenameToValidate = name.substring( leftSide.length, - rightSideIndexOf + rightSideIndexOf, ); if (filenameToValidate.length === 0 && type !== '*') { return false; @@ -141,137 +153,145 @@ function getValidatableFiles(files: string[]): types.ValidatableFile[] { function getRuleError( rule: types.FileRule | types.DirectoryRule, - paths: (string | RegExp)[] + paths: (string | RegExp)[], ) { return new errors.ValidatorRuleError(rule, paths); } -function validatePath(element: { path: string; isGood: boolean }) { - if (!element.isGood) { +function validatePath(element: { path: string; isValid: boolean }) { + if (!element.isValid) { throw new errors.ValidatorInvalidPathError(element.path); } } export function run( - files: string[], + filesAndDirs: ReturnType, mainRules: types.Rules, - emptyDirs: string[] = [] ) { if (mainRules.length === 0) { return; } - const newFiles = getValidatableFiles(files); - const newEmptyDirs = emptyDirs.map((el) => ({ - path: path.normalize(el), - isGood: false, - })); + function validateRules(rules: types.Rules = [], dirPath = '') { + if (rules.length === 0) return; - function validateRules( - rules: types.Rules = [], - paths: (string | RegExp)[] = ['.'] - ) { - if (rules.length === 0) { - return; - } + const dirChildren = getDirChildren(filesAndDirs, dirPath); - rules.forEach((rule, idx) => { - if (rule.type === 'common') { - return; - } + rules.forEach((rule) => { + // todo: this should not ever be the case, common rules should be already be parsed + if (rule.type === 'common') return; rule.name = getCorrectStringRegexp(rule.name); if (rule.type === 'file') { - const dirFiles = getDirFiles(newFiles, paths); + // IF at least one file matches the rule then it passes + // also mark all files that were validated + const fileRulePassed = dirChildren.reduce((result, child) => { + if (child.type === 'dir') return result; - // IF more than one file matches the rule then it passes - const fileRulePassed = dirFiles.reduce((result, file) => { - const { base, name, ext } = path.parse(file.path); - let isFileValid; + const { base, name, ext } = path.parse(child.path); + let isFileValid = false; if (!rule.extension) { isFileValid = isNameValid(rule.name, base); - } else { + } else isFileValid = isNameValid(rule.name, name) && isFileExtValid( getCorrectStringRegexp(rule.extension), - ext.substring(1) + ext.substring(1), ); - } - file.isValidated = file.isValidated || isFileValid; + child.isValid = isFileValid; + return result || isFileValid; - }, newFiles.length === 0); + }, false); - if (!fileRulePassed && !rule.isOptional) { - throw getRuleError(rule, paths); - } + if (!fileRulePassed && !rule.isOptional) + throw getRuleError(rule, [dirPath]); - // Mark as good all files that were validated - dirFiles - .filter((el) => el.isValidated) - .forEach((el) => { - el.isGood = true; - }); + // // Mark as good all files that were validated + // dirFiles + // .filter((el) => el.isValidated) + // .forEach((el) => { + // el.isGood = true; + // }); - newFiles.forEach((el) => { - el.isValidated = false; - }); + // newFiles.forEach((el) => { + // el.isValidated = false; + // }); return; } // Directory Rule - const dirFiles = getDirFiles(newFiles, [...paths, rule.name], true); - const emptyDir = newEmptyDirs.find( - (el) => el.path === path.normalize([...paths, rule.name].join(path.sep)) - ); + // if at least one dir matches the rule then it passes + const dirRulePassed = dirChildren.reduce((result, child) => { + if (child.type === 'file') return result; - // If no rules for this dir, it should validate all of its files - if ((rule.rules || []).length === 0) { - dirFiles.forEach((el) => { - el.isGood = true; - }); + const dirName = child.path.split('/').at(-1); + if (!dirName) return result; - if (emptyDir) { - emptyDir.isGood = true; - return; - } - } + const isValid = isNameValid(rule.name, dirName); - // Dir does not exist - if (dirFiles.length === 0) { - // TODO: mmm This was making a test fail - // rule.isRecursive = false; + child.isValid = isValid; - if (rule.isOptional) { - return; - } - throw getRuleError(rule, paths); - } + return result || isValid; + }, false); - if (rule.name instanceof RegExp || getMultimatchName(rule.name)) { - const parentPaths = getFilesByParentDir(dirFiles); - const parentPathsArray = _.keys(parentPaths); - const nextDirNamesChecked: string[] = []; - - for (let i = 0; i < parentPathsArray.length; i += 1) { - // Only look for the nextDirName (no recursively) to form the new path. - // So it case we have a file 'a/b/c/d.js', we only iterate on [...paths, 'a'] - const nextDirName = parentPathsArray[i].split(path.sep)[ - paths.length - 1 - ]; - if (!nextDirNamesChecked.includes(nextDirName)) { - nextDirNamesChecked.push(nextDirName); - validateRules(rule.rules, [...paths, nextDirName]); - } - } + if (!dirRulePassed && !rule.isOptional) + throw getRuleError(rule, [dirPath]); - return; - } + // const dirFiles = getDirFiles(newFiles, [...paths, rule.name], true); + // const emptyDir = newEmptyDirs.find( + // (el) => + // el.path === path.normalize([...paths, rule.name].join(path.sep)), + // ); + + // If no rules for this dir, it should mark all its children as valid + // if ((rule.rules || []).length === 0) { + // dirChildren.forEach((child) => { + // child.isValid = true; + // }); + + // return; + // } + + // If dir is empty or only has other dirs/folders + // if (dirFiles.length === 0) { + // if (rule.isOptional) { + // return; + // } + + // throw getRuleError(rule, paths); + // // validateRules(rule.rules, [...paths, rule.name]); + // // return; + + // // throw getRuleError(rule, paths); + // } + + // console.log('bb', 3, rule.rules); + + // if (rule.name instanceof RegExp || getMultimatchName(rule.name)) { + // const parentPaths = getFilesByParentDir(dirFiles); + // const parentPathsArray = _.keys(parentPaths); + // const nextDirNamesChecked: string[] = []; + + // for (let i = 0; i < parentPathsArray.length; i += 1) { + // // Only look for the nextDirName (no recursively) to form the new path. + // // So in case we have a file 'a/b/c/d.js', we only iterate on [...paths, 'a'] + // const nextDirName = parentPathsArray[i].split(path.sep)[ + // paths.length - 1 + // ]; + // if (!nextDirNamesChecked.includes(nextDirName)) { + // nextDirNamesChecked.push(nextDirName); + // validateRules(rule.rules, [...paths, nextDirName]); + // } + // } + + // return; + // } if (rule.isRecursive) { // We force rule to optional so we avoid recursively looking for @@ -289,6 +309,6 @@ export function run( validateRules(mainRules); - newFiles.forEach(validatePath); - newEmptyDirs.forEach(validatePath); + // at the end, check that all files were validated + // filesAndDirs.forEach(validatePath); } diff --git a/testing-schema.json b/testing-schema.json new file mode 100644 index 0000000..80eb294 --- /dev/null +++ b/testing-schema.json @@ -0,0 +1,92 @@ +{ + "ignoreFiles": [], + "ignoreDirs": [], + "commonRules": {}, + "rules": [ + { + "type": "file", + "name": "CHANGELOG.md" + }, + { + "type": "file", + "name": "README.html" + }, + { + "type": "directory", + "name": "Binaries", + "rules": [ + { + "type": "file", + "name": "Prod.bin" + }, + { + "type": "file", + "name": "Prod.elf" + }, + { + "type": "file", + "name": "Prod.hex" + }, + { + "type": "file", + "name": "Prod.list" + }, + { + "type": "file", + "name": "Prod.map" + } + ] + }, + { + "type": "directory", + "name": "3rdParty", + "rules": [ + { + "type": "file", + "name": "*.md", + "isOptional": true + }, + { + "type": "file", + "name": "/Thing_v(.*)/", + "extension": "bin" + } + ] + }, + { + "type": "directory", + "name": "Doc", + "rules": [ + { + "type": "file", + "name": "Documentation.html" + }, + { + "type": "directory", + "name": "html", + "isRecursive": true + } + ] + }, + { + "type": "directory", + "name": "Tool2" + }, + { + "type": "directory", + "name": "APIDoc" + }, + { + "type": "directory", + "name": "Metrics" + }, + { + "type": "directory", + "name": "Scripts" + }, + { + "type": "directory", + "name": "TestReports" + } + ] +} diff --git a/testing/empty_folder.zip b/testing/empty_folder.zip new file mode 100644 index 0000000000000000000000000000000000000000..99edf033dfa5270df5c7c5d1daa1a1f9e14d1732 GIT binary patch literal 691 zcmWIWW@Zs#U|`^2aCZC{QF%k^NjW0}!$mFz23`gkhLY6clC;d6RK2X?{JhW*P6lSX zgz0G@Tw1}+z{v7~nSlXJ9G!YU`;dXa@%w+Zm-x^2XnmWTf6mH$hW(0no+%}7SF-yC zty`&a>3^-K=*(?`$8YKRpS`O(e|L@k%Y7F^4j&Q~XVI5%%CR+l-u=ygb8|`BSJvdF z-6s_*=F6QeF*&n&rQGk!;bIEqf*Sj`hDfZgefL=Ibj{xD?=mjb%k$@mMJ%7N@-TlJ&x8Zho645e&YxJ_vg#Rk{Xc~+&+Q@;oBcdkzKIuUi%)wNKJ938 zL8Nv*@9n5c#bcYo6h1Fvx;Ha5Fm1J6kikcfXMd({%ksXT=*)BMvB#nZaVwNmRRb=+ zEKkdRvikhlxp#NHpV5@4-FRHfdheni>q6D1D*uTJ4cgPfIDOu<$B!oJXuNjYwDOFM z9kbNzBdqodCCn4vOnTKagHzB>VyTAc)wz3OC+`ipCZMt~|6k@*uGzm@Ca&Q$YmV3@ zz`2WQ&6<99d6}h}D;C^q+I8A5bJhDT_k|lj^8T2==Zk0NTD{O+n!1;3^JSjBG!FpA z9x$qaz{LJz1egIO*ub%uTVSLQj<%54>1iO07Ht9Ej7)OOxZ+;|Y!)y%Fl=cAG0{>3 vDMjAVxAU2r&G0+y^wdBo*RBpjlX*$I1q>m3^-K=*(?`$8YKRpS`O(e|L@k%Y7F^4j&Q~XVI5%%CR+l-u=ygb8|`BSJvdF z-6s_*=F6QeF*&n&rQGk!;bIEqf*Sj`hDfZgefL=Ibj{xD?=mjb%k$@mMJ%7N@-TlJ&x8Zho645e&YxJ_vg#Rk{Xc~+&+Q@;oBcdkzKIuUi%)wNKJ938 zL8Nv*@9n5c#bcYo6h1Fvx;Ha5Fm1J6kikcfXMd({%ksXT=*)BMvB#nZaVwNmRRb=+ zEKkdRvikhlxp#NHpV5@4-FRHfdheni>q6D1D*uTJ4cgPfIDOu<$B!oJXuNjYwDOFM z9kbNzBdqodCCn4vOnTKagHzB>VyTAc)wz3OC+`ipCZMt~|6k@*uGzm@Ca&Q$YmV3@ zz`2WQ&6<99d6}h}D;C^q+I8A5bJhDT_k|lj^8T2==Zk0NTD{O+n!1;3^JSjBG!FpA z9x$qaz{LJz1egIO*ub%uTVSLQj<%54>1iO07Ht9Ej7)OOxZ+;|Y!)y%Fl=cAG0{>3 vDMjAVxAU2r&G0+y^wdBo*RBpjlX*$I1q>m