arch-unit-js
v1.2.0
Published
ArchUnit clone for node.js projects
Maintainers
Readme
:page_facing_up: About
A JavaScript/TypeScript library for enforcing architectural rules and constraints in your codebase. Inspired by ArchUnit for Java, this tool provides a fluent API to define and validate architectural boundaries, naming conventions, and dependency rules. It is agnostic about the testing framework & OS systems ! Also provides support for both ESModules and CommonJS projects !
Note: Backend-focused (frontend support coming soon).
:hammer_and_wrench: Supported OS
- [x] Mac OS
- [x] Linux
- [x] Windows
:ledger: Features
- Dependency Rules: Control which modules can depend on others (
dependsOn,onlyDependsOn) - Naming Conventions: Enforce consistent file naming patterns (
haveName,onlyHaveName) - Code Metrics: Validate lines of code thresholds (
haveLocLessThan,haveLocGreaterThan) - Project Metrics: Validate code project percentage thresholds (
haveTotalProjectCodeLessThan,haveTotalProjectCodeLessOrEqualThan) - Cycle Detection: Prevent circular dependencies (
shouldNot.haveCycles) - Fluent API: Intuitive, readable syntax for defining architectural rules
:racing_car: Getting Started
Installation
Install using npm
npm install --save-dev arch-unit-jsJavaScript - (Basic Scenario)
Let's get started by writing a simple function that generates a UUID using the lib uuid. First, create a uuid.js file, inside a utils directory:
// file path: ./utils/uuid.js
const { v4 as uuidv4 } = require('uuid');
export function generateUUID() {
return uuidv4();
}Then create a test file utils-arch.spec.js in a tests directory, where we are going to test that all files inside the utils directory should have the uuid lib inside:
// file path: ./tests/utils-arch.spec.js
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['<rootDir>/**'], // Positive Glob pattern, where you specify all files and directories based on the project <rootDir>
ignoreMatcher: ['!**/node_modules/**'], // (Optional) - Negative Glob pattern, where you specify all files and directories you do NOT want to check
};
// We are using Jest, but you can use any other testing library
describe('Architecture Test', () => {
it('"./utils/uuid.js" file should depend on "uuid" lib', async () => {
await app(options).projectFiles().inDirectory('**/utils/**').should().dependsOn('uuid').check(); // No need to expect, if the dependency is not found it throws an error
});
});Now run the test and congrats 🥳, you just tested your application topology !
module-alias
arch-unit-jsalso provides support for applications which still use[email protected]!
Create a file register.js , in the root of your project, function which calls the module-alias first:
// file path: ./register.js
'use strict';
const path = require('path');
const moduleAlias = require('module-alias');
const baseDir = __dirname;
moduleAlias.addAliases({
'#domain': path.join(baseDir, 'domain'),
'#usecases': path.join(baseDir, 'use-cases'),
});Now let's create a simple domain layer in a directory with a file user.js:
// file path: ./domain/user.js
export class User {
constructor(id, name) {}
}To use the domain layer, create the use-cases layer within a directory with the same name, with a file called create-user.js:
// file path: ./use-cases/create-user.js
const { User } = require('#domain/user');
const createUserUseCase = () => new User(1, 'Roko');Now, let's test if create-user.js does depends on the #domain layer, create a tests directory and inside create a arch-use-case.test.js file.
// file path: ./tests/arch-use-case.test.js
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['<rootDir>/**'], // Positive Glob pattern, where you specify all files and directories based on the project <rootDir>
ignoreMatcher: ['!**/node_modules/**'], // (Optional) - Negative Glob pattern, where you specify all files and directories you do NOT want to check
};
// We are using Jest, but you can use any other testing library
describe('Architecture Test', () => {
beforeAll(() => {
require('../register'); // calls the `module-alias` and stores the alias in the node Modules package
});
it('"./createUserUseCase.js" file should depend on "#domain"', async () => {
await app(options)
.projectFiles()
.inFile('**/usecases/create-user.js')
.should()
.dependsOn('**/domain/**')
.check(); // No need to expect, if the dependency is not found it throws an error
});
});And there you have it congrats again 🥳 , you successfully tested your project dependencies which uses module-alias !
webpack
arch-unit-jsalso provides support for applications which use[email protected]!
In this section we are going to explore some scenarios using webpack. In the first example let's use a single build webpack.config.js file given in the example below.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// single - webpack.config.js
module.exports = {
entry: './main/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true,
},
resolve: {
extensions: ['.js'],
alias: {
'@domain': path.resolve(__dirname, 'domain'),
'@use-cases': path.resolve(__dirname, 'use-cases'),
'@infra': path.resolve(__dirname, 'infra'),
'@main': path.resolve(__dirname, 'main'),
},
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
],
},
plugins: [new HtmlWebpackPlugin({ template: './index.html' })],
devServer: {
static: path.resolve(__dirname, 'public'),
port: 5173,
historyApiFallback: true,
},
};In this example we wanna test if the files within the directory **/use-cases/** are using the files within **/domain/** to assert usage according to the 'clean architecture' standards. Since webpack is being used, we need to use let explicit within the path(options) using the following !
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['<rootDir>/**'], // Positive Glob pattern, where you specify all files and directories based on the project <rootDir>
ignoreMatcher: ['!**/node_modules/**'], // (Optional) - Negative Glob pattern, where you specify all files and directories you do NOT want to check
webpack: {
path: '<rootDir>/webpack.config.js', // Path to project 'webpack.config.js' - (using <rootDir> as wildcard)
},
};
// We are using Jest, but you can use any other testing library
describe('Architecture Test', () => {
it('"**/use-cases/**" files should depends on "@domain"', async () => {
await app(options)
.projectFiles()
.inDirectory('**/usecases/**')
.should()
.dependsOn('**/domain/**')
.check(); // No need to expect, if the dependency is not found it throws an error
});
});See, it is pretty easy !
In the next example let's explore a webpack.config.js file which has muiltiple builds down below.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// single - webpack.config.js
module.exports = [
{
name: 'client'
entry: './main/client.js',
output: {
path: path.resolve(__dirname, 'dist', 'client'),
filename: 'bundle.client.js',
clean: true,
},
resolve: {
extensions: ['.js'],
alias: {
'@domain': path.resolve(__dirname, 'domain'),
'@use-cases': path.resolve(__dirname, 'use-cases'),
'@infra': path.resolve(__dirname, 'infra'),
'@main': path.resolve(__dirname, 'main'),
},
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
],
},
plugins: [new HtmlWebpackPlugin({ template: './index.html' })],
devServer: {
static: path.resolve(__dirname, 'public'),
port: 5173,
historyApiFallback: true,
},
},
{
name: 'server'
entry: './main/server.js',
target: 'node',
output: {
path: path.resolve(__dirname, 'dist', 'server'),
filename: 'bundle.server.js',
clean: true,
},
resolve: {
extensions: ['.js'],
alias: {
'@domain': path.resolve(__dirname, 'domain'),
'@use-cases': path.resolve(__dirname, 'use-cases'),
'@infra': path.resolve(__dirname, 'infra'),
'@main': path.resolve(__dirname, 'main'),
},
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
devServer: {
port: 5174,
historyApiFallback: true,
},
}
]The webpack.config.js now uses a multi configuration set for the application building. To run arch-unit-js using a specific configuration from the webpack file use the webpack.names which is a way to tell arch-unit-js which configurations are going to be used in the aliases resolution during the test. To ilustrate let's use the same example where we want the files inside the **/use-cases/** to depend on the **/domain/** files !
Important: To use this feature, the
webpack.namesfromapp(options)must match the keynamefrom thewebpack.config.jsfile !
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['<rootDir>/**'], // Positive Glob pattern, where you specify all files and directories based on the project <rootDir>
ignoreMatcher: ['!**/node_modules/**'], // (Optional) - Negative Glob pattern, where you specify all files and directories you do NOT want to check
webpack: {
path: '<rootDir>/webpack.config.js', // Path to project 'webpack.config.js' - (using <rootDir> as wildcard)
names: ['server'], // Array of webpack config names from a 'webpack.config.js' file with multiple configurations
},
};
// We are using Jest, but you can use any other testing library
describe('Architecture Test', () => {
it('"**/use-cases/**" files should depends on "@domain"', async () => {
await app(options)
.projectFiles()
.inDirectory('**/usecases/**')
.should()
.dependsOn('**/domain/**')
.check(); // No need to expect, if the dependency is not found it throws an error
});
});Again, you successfully tested you application topology 🥳 , you getting the hang of it !
TypeScript - (Basic Scenario)
arch-unit-js also provides support for typescript. To include typescript support just provide the path to your tsconfig.json using the "typescriptPath"
import { Options } from 'arch-unit-js';
const options: Options = {
extensionTypes: ['**/*.ts'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['<rootDir>/**'], // Positive Glob pattern, where you specify all files and directories based on the project <rootDir>
typescriptPath: '<rootDir>/tsconfig.json', // Path to project 'tsconfig.json' - (using <rootDir> as wildcard)
};workspaces
Important: Ensure to install
arch-unit-jsin the rootpackage.jsonfile to ensure the dependency is hoisted for your monorepo project. If you're sure the dependency will not be hoisted and will be installed in the local project within the monorepo then you can skip the following steps and use the tool as is !
arch-unit-js also provides support for workspaces ! Given you're working in a workspace monorepo project ilustrated below:
project/
├── node_modules/
│ └ arch-unit-js/
├── packages/
│ ├── a/
│ │ ├── src/
│ │ └── package.json
│ ├── b/
│ │ ├── src/
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── c/
│ ├── src/
│ └── package.json
└── package.jsonSuppose you're testing the topology from package b ! To include support for the workspace you can use the following configuration:
import { Options } from 'arch-unit-js';
const options: Options = {
workspaceDir: '<rootDir>/packages/b',
extensionTypes: ['**/*.ts'],
includeMatcher: ['<rootDir>/packages/b/**'],
typescriptPath: '<rootDir>/packages/b/tsconfig.json',
};Or alternatively, you can also use the following configuration:
import { Options } from 'arch-unit-js';
const options: Options = {
workspaceDir: '<rootDir>/packages/b',
extensionTypes: ['**/*.ts'],
includeMatcher: ['<workspaceDir>/**'],
typescriptPath: '<workspaceDir>/tsconfig.json',
};Note: The annotation
<workspaceDir>works as an alias towards the path described in theOptions.workspaceDir!
:notebook: API Documentation
app(options)
When checking your architecture you need to test against your application and some of them have different folder structures. And here's where app comes to play.
The initial app API is the representation of your application and to define which files compose your application, you can use as parameter the 'options' to compose your application.
const { app } = require('arch-unit-js');
app({
workspaceDir: '<rootDir>/packages/a', // Optional,
extensionTypes: ['**/*.js'], // Required
includeMatcher: ['<rootDir>/**'], // Required
ignoreMatcher: ['!**/node_modules/**'], // Optional
typescriptPath: '<rootDir>/tsconfig.json', // Optional
webpack: {
path: '<rootDir>/webpack.config.js', // Optional
names: ['client', 'server'], // Optional
},
});The 'options' parameter is an object which has:
- The
workspaceDirwhich is a path likestring, representing the path to yourworkspaceyou're working on - The
extensionTypeswhich is astring[]of glob patterns, representing the allowed extensions which compose your project files - The
includeMatcherwhich is astring[]of glob patterns, representing the source directories of your application - The
ignoreMatcherwhich is astring[]of glob patterns, representing the resources you want to ignore - The
typescriptPathwhich is a path likestring, representing the path to yourtypescriptconfig file - The
webpack.pathwhich is a path likestring, representing the path to yourwebpackconfig file - The
webpack.nameswhich is an array telling whichwebpackconfigs to use in a multi config file
Note: All the patterns passed to the
ignoreMatchermust have a!, which indicates the given pattern must be ignored from the application !
Globals
projectFiles()
projectFiles() is the function used every time you want to make a broad test against your project structure. You will use it alongside with a "selector" to choose the files location which will be checked by a "matcher" !
To understand better, let's use an example, where you want to test to check if a file stringUtils.js has less than 50 L.O.C. - (Lines Of Code). Here's how to start.
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/stringUtils.js" file should have less than 50 - L.O.C.', async () => {
await app(options)
.projectFiles()
.inFile('**/stringUtils.js')
.should()
.haveLocLessThan(50)
.check();
});In this case we have the inFile as the "selector" which selects the files which will be tested by the "matcher" , in this case we are only targeting stringUtils.js. Then we have the should which is a "modifier" which indicates it is a positive test done by the "matcher". And finally there is the haveLocLessThan which is the "matcher" whose going to test if the selected files match the criteria !
Selectors
inDirectories(pattern: string[], excludePattern?: string[])
Use the inDirectories to select different files from multiple directories within your project. The "selectors" chains with the "modifiers" to indicate which will be the "matcher" behavior.
Let's say we have an application and we have the directories **/infra/repositories/** & **/infra/providers/**. We want to enforce the files inside this folders contains only very specific dependencies which are the mysql2 & crypto.
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/infra/repositories/**" & "**/infra/providers/**" should only depends on "mysql2" & "crypto"', async () => {
await app(options)
.projectFiles()
.inDirectories(['**/infra/repositories/**', '**/infra/providers/**'])
.should()
.onlyDependsOn(['mysql2', 'crypto'])
.check();
});Now, let's imagine the structure from the selected directories changed, and now they use barrel exports which means both have now an index.js file exporting all the files.
But the index.js does not comply with the checking "matcher" rule. For this scenario the inDirectories has a second parameter which is used to exclude files and folders you don't want to be checked by the "matcher".
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/infra/repositories/**" & "**/infra/providers/**" should only depends on "mysql2" & "crypto" , excluding "**/infra/**/index.js"', async () => {
await app(options)
.projectFiles()
.inDirectories(['**/infra/repositories/**', '**/infra/providers/**'], ['!**/infra/**/index.js'])
.should()
.onlyDependsOn(['mysql2', 'crypto'])
.check();
});Note: All the patterns passed to the
excludePatternmust have a!, which indicates the given pattern must be excluded from the "matcher" check !
inDirectory(pattern: string, excludePattern?: string[])
Use the inDirectory to select different files from a single directory within your project. It's behavior is the same as the one described for the inDirectories selector, with the exception the pattern parameter is a single string.
To ilustrate it's behavior let's use an example where we are going to have again a directory **/infra/repositories/** and we want to test it it's files use the mysql2, but to make interesting the files implementation are using mysql2/promise now.
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/infra/repositories/**" should depends on "mysql2/**"', async () => {
await app(options)
.projectFiles()
.inDirectory('**/infra/repositories/**')
.should()
.dependsOn('mysql2/**')
.check();
});Just like the previous example, let's imagine the structure from the selected directory changed, and now uses barrel exports which means it has an index.js file exporting all the other files. Given this scenario let's exclude the index.ts file from the "selectors" !
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/infra/repositories/**" should depends on "mysql2/*" , excluding "**/infra/repositories/**/index.js"', async () => {
await app(options)
.projectFiles()
.inDirectory('**/infra/repositories/**', ['!**/infra/repositories/**/index.js'])
.should()
.dependsOn('mysql2/**')
.check();
});inFiles(pattern: string[])
Use the inFiles to select different files from different parts of your project. It's behavior is similar than the one described by inDirectories, with the exception that it is not possible to exclude a given pattern with this "selector" !
To ilustrate it's behavior let's use an example where we wanna check if the files **/domain/entities/user.entity.js & **/domain/entities/address.entity.js depends on uuid & lodash.
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/domain/entities/user.entity.js" & "**/domain/entities/address.entity.js" should depends on "uuid", async () => {
await app(options)
.projectFiles()
.inFiles(['**/domain/entities/user.entity.js', '**/domain/entities/address.entity.js'])
.should()
.dependsOn(['uuid', 'lodash'])
.check();
});inFile(pattern: string)
Use the inFile to select different files OR a single file within your project. This selector is focused in selecting specific files or single file which match the pattern only, providing better semantics towards the test itself.
To ilustrate it's behavior let's use an example where we want to check if a file **/domain/entities/address.entity.js has more than 80 - L.O.C. - (Lines Of Code).
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/domain/entities/address.entity.js" should have more than 80 - L.O.C.', async () => {
await app(options)
.projectFiles()
.inFile('**/domain/entities/address.entity.js')
.should()
.haveLocGreaterThan(80)
.check();
});Modifiers
should()
Use the should modifier to indicate to "arch-unit-js" what the "matcher" should test. It chains with the "matcher" to indicate how the selected files will be checked !
We can use the another example, where we want all the files in a directory "utils" should match the name *.utils.js.
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"utils" directory should have all files matching the name "*.utils.js"', async () => {
await app(options)
.projectFiles()
.inDirectory('**/utils/**')
.should()
.haveName('*.utils.js')
.check();
});shouldNot()
The shouldNot modifier indicates the opposite of should , so it is a negative test modifier which tells the "matcher" the selected files should not match the checked pattern.
The code below test if a file numberUtils.js has 50 L.O.C. or more.
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/numberUtils.js" file should have less than 50 - L.O.C.', async () => {
await app(options)
.projectFiles()
.inFile('**/numberUtils.js')
.shouldNot()
.haveLocLessThan(50)
.check();
});By using the shouldNot "modifier" the "matcher" behave was modified to check if the selected files had a L.O.C. greater or equal than the specified value !
Aggregators
and()
The and is an "aggregator". An "aggregator" gives the ability to chain "selectors" with other "selectors" & chain "matchers" with other "matchers" creating more complex architecture rules to be validated !
In the example below we wanna check if files inside the **/domain/entities/** & **/services/contracts/** directories & **/shared/utils.js file have more than 30 - L.O.C. - (Lines Of Code) & less than 120 - L.O.C. - (Lines Of Code).
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['**/*.js'],
includeMatcher: ['<rootDir>/**'],
};
it('"**/domain/entities/**" & "**/services/contracts/**" & "**/shared/utils.js" files and directories have more than 30 L.O.C. & ;ess than 120 L.O.C.', async () => {
await app(options)
.projectFiles()
.inDirectories(['**/domain/entities/**', '**/services/contracts/**'])
.and()
.inFile('**/shared/utils.js')
.should()
.haveLocGreaterThan(30)
.and()
.haveLocLessThan(120)
.check();
});As demonstrated in the example "aggregators" are a powerful tool to create stronger architecture rules by combinig different "selectors" and "matchers" in more meaningful setences !
Matchers
dependsOn
should
- Project Files in Directories Should Depends On Specified Patterns
- Project Files in Directory Should Depends On Specified Patterns
- Project Files in Files Should Depends On Specified Patterns
- Project Files in File Should Depends On Specified Patterns
shouldNot
- Project Files in Directories Should NOT Depends On Specified Patterns
- Project Files in Directory Should NOT Depends On Specified Patterns
- Project Files in Files Should NOT Depends On Specified Patterns
- Project Files in File Should NOT Depends On Specified Patterns
onlyDependsOn
should
- Project Files in Directories Should Only Depends On Specified Patterns
- Project Files in Directory Should Only Depends On Specified Patterns
- Project Files in Files Should Only Depends On Specified Patterns
- Project Files in File Should Only Depends On Specified Patterns
shouldNot
- Project Files in Directories Should NOT Only Depends On Specified Patterns
- Project Files in Directory Should NOT Only Depends On Specific Patterns
- Project Files in Files Should NOT Only Depends On Specified Patterns
- Project Files in File Should NOT Only Depends On Specified Patterns
haveCycles
should
- Project Files in Directories Should Have Cycles
- Project Files in Directory Should Have Cycles
- Project Files in Files Should Have Cycles
- Project Files in File Should Have Cycles
shouldNot
- Project Files in Directories Should NOT Have Cycles
- Project Files in Directory Should NOT Have Cycles
- Project Files in Files Should NOT Have Cycles
- Project Files in File Should NOT Have Cycles
haveName
should
- Project Files in Directories Should Have Name with Specified Pattern
- Project Files in Directory Should Have Name with Specified Pattern
- Project Files in Files Should Have Name with Specified Pattern
- Project Files in File Should Have Name with Specified Pattern
shouldNot
- Project Files in Directories Should NOT Have Name with Specified Pattern
- Project Files in Directory Should Not Have Name with Specified Pattern
- Project Files in Files Should NOT Have Name with Specified Pattern
- Project Files in File Should NOT Have Name with Specified Pattern
onlyHaveName
should
- Project Files in Directories Should Only Have Name with Specified Pattern
- Project Files in Directory Should Only Have Name with Specified Pattern
- Project Files in Files Should Only Have Name with Specified Pattern
- Project Files in File Should Only Have Name with Specified Pattern
shouldNot
- Project Files in Directories Should NOT Only Have Name with Specified Pattern
- Project Files in Directory Should NOT Only Have Name with Specified Pattern
- Project Files in Files Should NOT Only Have Name with Specified Pattern
- Project Files in File Should NOT Only Have Name with Specified Pattern
haveLocLessThan
should
- Project Files in Directories Should Have Less L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should Have Less L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should Have Less L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should Have Less L.O.C. (Lines Of Code) Than Specified Value
shouldNot
- Project Files in Directories Should NOT Have Less L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should NOT Have Less L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should NOT Have Less L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should NOT Have Less L.O.C. (Lines Of Code) Than Specified Value
haveLocLessOrEqualThan
should
- Project Files in Directories Should Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
shouldNot
- Project Files in Directories Should NOT Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should NOT Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should NOT Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should NOT Have Less Or Equal L.O.C. (Lines Of Code) Than Specified Value
haveLocGreaterThan
should
- Project Files in Directories Should Have Greater L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should Have Greater L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should Have Greater L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should Have Greater L.O.C. (Lines Of Code) Than Specified Value
shouldNot
- Project Files in Directories Should NOT Have Greater L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should NOT Have Greater L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should NOT Have Greater L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should NOT Have Greater L.O.C. (Lines Of Code) Than Specified Value
haveLocGreaterOrEqualThan
should
- Project Files in Directories Should Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
shouldNot
- Project Files in Directories Should NOT Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Directory Should NOT Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in Files Should NOT Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
- Project Files in File Should NOT Have Greater Or Equal L.O.C. (Lines Of Code) Than Specified Value
haveTotalProjectCodeLessThan
should
- Project Files in Directories Should Have Total Project Code Less Than a Percentage Value
- Project Files in Directory Should Have Total Project Code Less Than a Percentage Value
- Project Files in Files Should Have Total Project Code Less Than a Percentage Value
- Project Files in File Should Have Total Project Code Less Than a Percentage Value
shouldNot
- Project Files in Directories Should NOT Have Total Project Code Less Than a Percentage Value
- Project Files in Directory Should NOT Have Total Project Code Less Than a Percentage Value
- Project Files in Files Should NOT Have Total Project Code Less Than a Percentage Value
- Project Files in File Should NOT Have Total Project Code Less Than a Percentage Value
haveTotalProjectCodeLessOrEqualThan
should
- Project Files in Directories Should Have Total Project Code Less Or Equal Than a Percentage Value
- Project Files in Directory Should Have Total Project Code Less Or Equal Than a Percentage Value
- Project Files in Files Should Have Total Project Code Less Or Equal Than a Percentage Value
- Project Files in File Should Have Total Project Code Less Or Equal Than a Percentage Value
shouldNot
- Project Files in Directories Should NOT Have Total Project Code Less Or Equal Than a Percentage Value
- Project Files in Directory Should NOT Have Total Project Code Less Or Equal Than a Percentage Value
- Project Files in Files Should NOT Have Total Project Code Less Or Equal Than a Percentage Value
- Project Files in File Should NOT Have Total Project Code Less Or Equal Than a Percentage Value
:memo: License
This project is under MIT license. See the LICENSE file for more details.
Made with lots of 🔥🔥🔥 by Gabriel Ferrari Tarallo Ferraz
