ArchUnit clone for node.js projects
npm install arch-unit-js
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).
- [x] Mac OS
- [x] Linux
- [x] Windows
- 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
> ### Installation
Install using npm
``bash`
npm install --save-dev arch-unit-js
> ### JavaScript - (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:
`javascript
// 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:
`javascript
// 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: ['
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-aliasarch-unit-js
>
> also provides support for applications which still use module-alias@2.x.x !
Create a file register.js , in the root of your project, function which calls the module-alias first:
`javascript
// 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:
`javascript`
// 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:
`javascript
// 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.
`javascript
// 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: ['
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 !
> #### webpackarch-unit-js
>
> also provides support for applications which use webpack@2.2.x !
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.
`javascript
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 !
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['
ignoreMatcher: ['!/node_modules/'], // (Optional) - Negative Glob pattern, where you specify all files and directories you do NOT want to check
webpack: {
path: '
},
};
// 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.
`javascript
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.names from app(options) must match the key name from the webpack.config.js file !
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['
ignoreMatcher: ['!/node_modules/'], // (Optional) - Negative Glob pattern, where you specify all files and directories you do NOT want to check
webpack: {
path: '
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_"
`typescript
import { Options } from 'arch-unit-js';
const options: Options = {
extensionTypes: ['*/.ts'], // Positive Glob pattern, where you specify all extension types your application has
includeMatcher: ['
typescriptPath: '
};
`
> ### workspaces
> Important: Ensure to install arch-unit-js in the root package.json file 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.json
Suppose you're testing the topology from _package_ b ! To include support for the workspace you can use the following configuration:
`typescript
import { Options } from 'arch-unit-js';
const options: Options = {
workspaceDir: '
extensionTypes: ['*/.ts'],
includeMatcher: ['
typescriptPath: '
};
`
Or alternatively, you can also use the following configuration:
`typescript
import { Options } from 'arch-unit-js';
const options: Options = {
workspaceDir: '
extensionTypes: ['*/.ts'],
includeMatcher: ['
typescriptPath: '
};
`
> Note: The annotation works as an alias towards the path described in the Options.workspaceDir !
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.
`javascript
const { app } = require('arch-unit-js');
app({
workspaceDir: '
extensionTypes: ['*/.js'], // Required
includeMatcher: ['
ignoreMatcher: ['!/node_modules/'], // Optional
typescriptPath: '
webpack: {
path: '
names: ['client', 'server'], // Optional
},
});
`
The 'options' parameter is an object which has:
- The workspaceDir which is a path like string, representing the path to your workspace you're working onextensionTypes
- The which is a string[] of glob patterns, representing the allowed extensions which compose your project filesincludeMatcher
- The which is a string[] of glob patterns, representing the source directories of your applicationignoreMatcher
- The which is a string[] of glob patterns, representing the resources you want to ignoretypescriptPath
- The which is a path like string, representing the path to your typescript config filewebpack.path
- The which is a path like string, representing the path to your webpack config filewebpack.names
- The which is an array telling which webpack configs to use in a multi config file
> Note: All the patterns passed to the ignoreMatcher must have a ! , which indicates the given pattern must be ignored from the application !
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.
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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 !
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.
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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".
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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 excludePattern must have a ! , which indicates the given pattern must be excluded from the "matcher" check !
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.
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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" !
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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();
});
`
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.
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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();
});
`
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).
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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();
});
`
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_.
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
it('"utils" directory should have all files matching the name "*.utils.js"', async () => {
await app(options)
.projectFiles()
.inDirectory('/utils/')
.should()
.haveName('*.utils.js')
.check();
});
`
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.
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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 !
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).
`javascript
const { app } = require('arch-unit-js');
const options = {
extensionTypes: ['*/.js'],
includeMatcher: ['
};
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 !
> #### 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
> #### 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
> #### 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
> #### 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
> #### 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
> #### 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
> #### 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
> #### 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
> #### 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
> #### 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
> #### 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
---
This project is under MIT license. See the LICENSE file for more details.
---
Made with lots of 🔥🔥🔥 by Gabriel Ferrari Tarallo Ferraz