diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd724fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,132 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + +# profiling files +chrome-profiler-events*.json +speed-measure-plugin*.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock + +# Logs +/libpeerconnection.log +logs +*.log +npm-debug.log* +testem.log +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +#DynamoDB Local files +.dynamodb/ + +# OS generated files +Thumbs.db +.DS_Store + +# Ignored files +/.vscode/* +*.code-workspace +!.vscode/tasks.json +build +dist +graphics +fonts +*.ignore* + +# demos +demo diff --git a/LICENSE b/LICENSE index 1b01fe0..5c0c291 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 angular package +Copyright (c) 2021 angular-package Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..509bd5e --- /dev/null +++ b/README.md @@ -0,0 +1,546 @@ +# Packages + +Useful and simple to use packages based on the [angular.io][angulario]. + +| Package | Description | Status | +| :----------------------------------- | :------------------------------------------------------ | -----: | +| [callback][callback-github-readme] | Manages the callback [`function`][js-function]. | [![npm version][callback-npm-badge-svg]][callback-npm-badge] | +| [change-detection][cd-github-readme] | Improves application performance. | [![npm version][cd-npm-badge-svg]][cd-npm-badge] | +| [component-loader][cl-github-readme] | Handles dynamic loading components. | [![npm version][cl-npm-badge-svg]][cl-npm-badge] | +| [core][core-github-readme] | Core features. | [![npm version][core-npm-badge-svg]][core-npm-badge] | +| [error][error-github-readme] | Manages an [`Error`][js-error]. | [![npm version][error-npm-badge-svg]][error-npm-badge] | +| [prism][prism-github-readme] | [`Prism`][prism-js] highlighter module. | [![npm version][prism-npm-badge-svg]][prism-npm-badge] | +| [property][property-github-readme] | Handles object properties. | [![npm version][property-npm-badge-svg]][property-npm-badge] | +| [reactive][reactive-github-readme] | Automatize the process of creating some rxjs features. | [![npm version][reactive-npm-badge-svg]][reactive-npm-badge] | +| [testing][testing-github-readme] | Support for testing other packages. | [![npm version][testing-npm-badge-svg]][testing-npm-badge] | +| [type][type-github-readme] | Common types, type guards, and type checkers. | [![npm version][type-npm-badge-svg]][type-npm-badge] | +| [ui][ui-github-readme] | User interface. | *In Progress* | + +> Click on the package name to visit its [GitHub](https://github.com/) page. + +## angular-package/error + +Manages an [`Error`][js-error]. + + +[![npm version][error-npm-badge-svg]][error-npm-badge] + +[![GitHub issues][error-badge-issues]][error-issues] +[![GitHub forks][error-badge-forks]][error-forks] +[![GitHub stars][error-badge-stars]][error-stars] +[![GitHub license][error-badge-license]][error-license] + +[![GitHub sponsors][github-badge-sponsor]][github-sponsor-link] +[![Support me on Patreon][patreon-badge]][patreon-link] + +---- + +## Table of contents + +* [Basic concepts](#basic-concepts) +* [Skeleton](#skeleton) +* [Installation](#installation) +* [Api](#api) +* [`ValidationError`](#validationerror) +* [Interface](#interface) +* [Git](#git) + * [Commit](#commit) + * [Versioning](#versioning) +* [License](#license) + +---- + +
+ +## Basic concepts + +Checks +> It's to check the provided value to be **the same** as **expected**. + +Type guard (constrain) +> Constrains the parameter type to **not let** input **unexpected** value in the **code editor**. + +Guards +> It's a **combination** of both above, **constrains** the type of the parameter in the **code editor**, and checks its provided argument. + +Sets +> Sets the existing given value in the `object`. + +Defines +> Returns defined value from the method of the `object`. +> Defines the new value in the `object`. +> Both above at the same time. + +
+ +## Skeleton + +This package was built by the [library skeleton][skeleton] which was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.1.1. + +Copy this package to the `packages/error` folder of the [library skeleton][skeleton] then run the commands below. + +### Build + +Run `ng build error` to build the package. The build artifacts will be stored in the `dist/` directory. + +### Running unit tests + +Run `ng test error` to execute the unit tests via [Karma](https://karma-runner.github.io). + +
+ +## Installation + +Install `@angular-package/error` package with command: + +```bash +npm i --save @angular-package/error +``` + +
+ +## Api + +```typescript +import { + // Class. + ValidationError, + // Interface. + ErrorMessage, +} from '@angular-package/error'; +``` + +
+ +## `ValidationError` + +Manages an [`Error`][js-error] of the validation. + +**Static methods:** + +| Methods | Description | +| :----------------------------------------------------------------- | :---------- | +| [`ValidationError.defineMessage()`](#validationerrordefinemessage) | Defines the validation error message of a [`string`][js-string] type from the provided `message` of the [`ErrorMessage`](#errormessage) interface | + +**Constructor:** + +| Constructor | Description | +| :-------------------------------------------------- | :---------- | +| [`ValidationError()`](#validationerror-constructor) | Creates a new instance with the message. If the provided `message` is an [`object`][js-object], then its properties are assigned to the instance | + +
+ +## `ValidationError` static properties + +### `ValidationError.template` + +Template of the error message with the replaceable `[problem]` and `[fix]`. By default, it's set to `Problem: [problem] => Fix: [fix]`. + +```typescript +static template = `Problem: [problem] => Fix: [fix]`; +``` + +
+ +## `ValidationError` instance public properties + +### `ValidationError.prototype.fix` + +A possible solution to the described problem of a [`string`][js-string] type. By default, it's an empty [`string`][js-string]. + +```typescript +public fix = ''; +``` + +
+ +### `ValidationError.prototype.name` + +Error name of a [`string`][js-string] type that is being thrown. By default, it's [`ValidationError`](#validationerror). + +```typescript +public name = ValidationError.name; +``` + +
+ +### `ValidationError.prototype.problem` + +The validation problem of a [`string`][js-string] type. By default, it's an empty [`string`][js-string]. + +```typescript +public problem = ''; +``` + +
+ +## `ValidationError` static methods + +### `ValidationError.defineMessage()` + +Defines the validation error message of a [`string`][js-string] type from the provided `message` of the [`ErrorMessage`](#errormessage) interface. + +```typescript +static defineMessage( + message: ErrorMessage, + template: string = ValidationError.template, + callback?: ResultCallback +): string { + if (is.objectKey(message, ['fix', 'problem'], callback)) { + if (is.string(template)) { + return template + .replace(`[fix]`, message.fix) + .replace(`[problem]`, message.problem); + } + } + return ''; +} +``` + +**Parameters:** + +| Name: type | Description | +| :-------------------------- | :---------- | +| `message: ErrorMessage` | An [`object`][js-object] of the [`ErrorMessage`](#errormessage) interface to build a message of a [`string`][js-string] type. The value is checked against the proper [`object`][js-object] | +| `template: string` | A message template of a [`string`][js-string] type with replaceable `[problem]` and `[fix]` from the given `message`. The value is checked against a [`string`][js-string]. By default, it's set to `Problem: [problem] => Fix: [fix]` | +| `callback?: ResultCallback` | An optional callback function of [`ResultCallback`][package-type-resultcallback] type to handle the check whether the provided message contains required `problem` and `fix` properties | + +**Returns:** + +The **return value** is a message of a `string` type created from the provided `message` of [`ErrorMessage`](#errormessage) interface, or it's an empty [`string`][js-string] if the provided message [`object`][js-object] isn't proper. + +**Usage:** + +```typescript +// Example usage. +import { ValidationError } from '@angular-package/core'; + +const fix = 'There is no solution to the described problem.'; +const problem = 'The problem has no solution.'; + +/** + * Returns + * -------- + * Problem: The problem has no solution. => Fix: There is no solution to the described problem. + */ +const errorMessage = ValidationError.defineMessage({ fix, problem }); +``` + +
+ +## `ValidationError` constructor + +### `ValidationError()` + +Creates a new instance with the message. If the provided `message` is an [`object`][js-object], then its properties are assigned to the instance. + +```typescript +new ValidationError(message: string | ErrorMessage) { + super( + is.string(message) ? message : ValidationError.defineMessage(message) + ); + if (is.object(message)) { + Object.assign(this, { + problem: message.problem, + fix: message.fix, + }); + } +} +``` + +**Parameters:** + +| Name: type | Description | +| :-------------------------------- | :---------- | +| `message: string \| ErrorMessage` | The message of a [`string`][js-string] type or of an [`ErrorMessage`](#errormessage) interface that is used to throw with an [`error`][js-error] | + +**Returns:** + +The **return value** is an instance of [`ValidationError`](#validationerror). + +**Usage:** + +```typescript +// Example usage. +import { ValidationError } from '@angular-package/core'; + +const fix = 'There is no solution to the described problem.'; +const problem = 'The problem has no solution.'; +const validationError = new ValidationError({ fix, problem }); +``` + +
+ +## Interface + +### ErrorMessage + +The shape of an [`object`][js-object] for an [`error`][js-error] message that contains a possible solution to the described problem. + +```typescript +interface ErrorMessage { + /** + * Possible solution to the described problem of a `string` type. + */ + fix: string; + /** + * Error problem of a `string` type. + */ + problem: string; +} +``` + +
+ +## GIT + +### Commit + +* [AngularJS Git Commit Message Conventions][git-commit-angular] +* [Karma Git Commit Msg][git-commit-karma] +* [Conventional Commits][git-commit-conventional] + +### Versioning + +[Semantic Versioning 2.0.0][git-semver] + +**Given a version number MAJOR.MINOR.PATCH, increment the:** + +* MAJOR version when you make incompatible API changes, +* MINOR version when you add functionality in a backwards-compatible manner, and +* PATCH version when you make backwards-compatible bug fixes. + +Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. + +**FAQ** +How should I deal with revisions in the 0.y.z initial development phase? + +> The simplest thing to do is start your initial development release at 0.1.0 and then increment the minor version for each subsequent release. + +How do I know when to release 1.0.0? + +> If your software is being used in production, it should probably already be 1.0.0. If you have a stable API on which users have come to depend, you should be 1.0.0. If you’re worrying a lot about backwards compatibility, you should probably already be 1.0.0. + +## License + +MIT © angular-package ([license][error-license]) + + +[github-badge-sponsor]: https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&link=https://github.com/sponsors/angular-package +[github-sponsor-link]: https://github.com/sponsors/angular-package +[patreon-badge]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dsciborrudnicki%26type%3Dpatrons&style=flat +[patreon-link]: https://patreon.com/sciborrudnicki + +[angulario]: https://angular.io +[skeleton]: https://github.com/angular-package/skeleton + + +[fix]: https://img.shields.io/badge/-fix-red +[new]: https://img.shields.io/badge/-new-green +[update]: https://img.shields.io/badge/-update-red + + +[git-semver]: http://semver.org/ + + +[git-commit-angular]: https://gist.github.com/stephenparish/9941e89d80e2bc58a153 +[git-commit-karma]: http://karma-runner.github.io/0.10/dev/git-commit-msg.html +[git-commit-conventional]: https://www.conventionalcommits.org/en/v1.0.0/ + + + + [error-badge-issues]: https://img.shields.io/github/issues/angular-package/error + [error-badge-forks]: https://img.shields.io/github/forks/angular-package/error + [error-badge-stars]: https://img.shields.io/github/stars/angular-package/error + [error-badge-license]: https://img.shields.io/github/license/angular-package/error + + [error-issues]: https://github.com/angular-package/error/issues + [error-forks]: https://github.com/angular-package/error/network + [error-license]: https://github.com/angular-package/error/blob/master/LICENSE + [error-stars]: https://github.com/angular-package/error/stargazers + + + + + [callback-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Fcallback.svg + [callback-npm-badge]: https://badge.fury.io/js/%40angular-package%2Fcallback + [callback-npm-readme]: https://www.npmjs.com/package/@angular-package/callback#readme + + + [callback-github-readme]: https://github.com/angular-package/callback#readme + + + + [cd-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Fchange-detection.svg + [cd-npm-badge]: https://badge.fury.io/js/%40angular-package%2Fchange-detection + [cd-npm-readme]: https://www.npmjs.com/package/@angular-package/change-detection#readme + + + [cd-github-readme]: https://github.com/angular-package/change-detection#readme + + + + [cl-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Fcomponent-loader.svg + [cl-npm-badge]: https://badge.fury.io/js/%40angular-package%2Fcomponent-loader + [cl-npm-readme]: https://www.npmjs.com/package/@angular-package/component-loader#readme + + + [cl-github-readme]: https://github.com/angular-package/component-loader#readme + + + + [core-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Fcore.svg + [core-npm-badge]: https://badge.fury.io/js/%40angular-package%2Fcore + [core-npm-readme]: https://www.npmjs.com/package/@angular-package/core#readme + + + [core-github-readme]: https://github.com/angular-package/core#readme + + + + [error-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Ferror.svg + [error-npm-badge]: https://badge.fury.io/js/%40angular-package%2Ferror + [error-npm-readme]: https://www.npmjs.com/package/@angular-package/error#readme + + + [error-github-readme]: https://github.com/angular-package/error#readme + + + + [prism-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Fprism.svg + [prism-npm-badge]: https://badge.fury.io/js/%40angular-package%2Fprism + [prism-npm-readme]: https://www.npmjs.com/package/@angular-package/prism#readme + + + [prism-github-readme]: https://github.com/angular-package/prism#readme + + + + [property-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Fproperty.svg + [property-npm-badge]: https://badge.fury.io/js/%40angular-package%2Fproperty + [property-npm-readme]: https://www.npmjs.com/package/@angular-package/property#readme + + + [property-github-readme]: https://github.com/angular-package/property#readme + + + + [reactive-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Freactive.svg + [reactive-npm-badge]: https://badge.fury.io/js/%40angular-package%2Freactive + [reactive-npm-readme]: https://www.npmjs.com/package/@angular-package/reactive#readme + + + [reactive-github-readme]: https://github.com/angular-package/reactive#readme + + + + [testing-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Ftesting.svg + [testing-npm-badge]: https://badge.fury.io/js/%40angular-package%2Ftesting + [testing-npm-readme]: https://www.npmjs.com/package/@angular-package/testing#readme + + + [testing-github-readme]: https://github.com/angular-package/testing#readme + + + + [type-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Ftype.svg + [type-npm-badge]: https://badge.fury.io/js/%40angular-package%2Ftype + [type-npm-readme]: https://www.npmjs.com/package/@angular-package/type#readme + + + [type-github-readme]: https://github.com/angular-package/type#readme + + [package-type-resultcallback]: https://github.com/angular-package/type#resultcallback + [package-type-key]: https://github.com/angular-package/type#key + + + + [ui-npm-badge-svg]: https://badge.fury.io/js/%40angular-package%2Fui.svg + [ui-npm-badge]: https://badge.fury.io/js/%40angular-package%2Fui + [ui-npm-readme]: https://www.npmjs.com/package/@angular-package/ui#readme + + + [ui-github-readme]: https://github.com/angular-package/ui#readme + + +[angular-component-factory-resolver]: https://angular.io/api/core/ComponentFactoryResolver +[angular-view-container-ref]: https://angular.io/api/core/ViewContainerRef + + +[jasmine-describe]: https://jasmine.github.io/api/3.8/global.html#describe +[jasmine-expect]: https://jasmine.github.io/api/3.8/global.html#expect +[jasmine-it]: https://jasmine.github.io/api/3.8/global.html#it + + +[js-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array +[js-array-every]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every +[js-array-some]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some + +[js-bigint]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt +[js-bigintconstructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt + +[js-boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean +[js-booleanconstructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/Boolean + +[js-classes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes + +[js-date]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date + +[js-error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error + +[js-function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions +[js-function-rest-parameter]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters + +[js-getter]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get +[js-object-getownpropertydescriptor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor +[js-object-getOwnpropertydescriptors]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors + +[js-setter]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set + +[js-hasownproperty]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty + +[js-instanceof]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof +[js-in-operator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in + +[js-map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map + +[js-null]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null +[js-number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number +[js-numberconstructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/Number + +[js-object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object +[js-object-define-property]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty + +[js-primitive]: https://developer.mozilla.org/en-US/docs/Glossary/Primitive +[js-promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise + +[js-rangeerror]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError +[js-referenceerror]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError +[js-regexp]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp + +[js-set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set +[js-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage +[js-string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String +[js-stringconstructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/String + +[js-symbol]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol +[js-symbolconstructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/Symbol +[js-syntaxerror]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError + +[js-typeerror]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError + +[js-undefined]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined +[js-urlerror]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError + +[js-weakset]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet + + +[karma]: http://karma-runner.github.io/0.10/index.html + + +[prism-js]: https://prismjs.com/ + + +[ts-classes]: https://www.typescriptlang.org/docs/handbook/2/classes.html +[ts-function]: https://www.typescriptlang.org/docs/handbook/2/functions.html +[ts-interface]: https://www.typescriptlang.org/docs/handbook/interfaces.html#our-first-interface diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..be9ad6b --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,44 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, '../../coverage/error'), + subdir: '.', + reporters: [ + { type: 'html' }, + { type: 'text-summary' } + ] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/ng-package.json b/ng-package.json new file mode 100644 index 0000000..5dbe8d1 --- /dev/null +++ b/ng-package.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/error", + "lib": { + "entryFile": "src/public-api.ts", + "umdModuleIds": { + "@angular-package/type": "angular-package.type" + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6b06213 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,427 @@ +{ + "name": "error", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "license": "MIT", + "dependencies": { + "tslib": "^2.2.0" + }, + "devDependencies": { + "@angular-package/testing": "^1.1.0" + }, + "peerDependencies": { + "@angular-package/type": "^4.2.0", + "@angular/common": "^12.1.1", + "@angular/core": "^12.1.1" + }, + "version": "1.0.0" + }, + "node_modules/@angular-package/testing": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@angular-package/testing/-/testing-1.1.0.tgz", + "integrity": "sha512-N/c75WBG4GPcgj7NYWAKSE9IwcPSqVMOYjkZ3RU4rUZW5equkjZvQ4zWKc8S4lbxr1wPD6KxPy3T52xTsBW3Dw==", + "dev": true, + "dependencies": { + "tslib": "^2.2.0" + }, + "peerDependencies": { + "@angular-package/type": ">= 4.2.0", + "jasmine": "^3.8.0" + } + }, + "node_modules/@angular-package/type": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@angular-package/type/-/type-4.2.0.tgz", + "integrity": "sha512-Y7HT94Gia4soR2ynwK8qva0WTOplau++gInEQCwDnhXmYy/r/1J/XhW0+aVj5XIa3SLWWa70nHvI0ivBM7O1nw==", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular/common": { + "version": "12.1.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-12.1.4.tgz", + "integrity": "sha512-cyh2m5veGgWRFsrmPnwB/Ised90bFNZAjZepvW8WXrpEUa/tmi1yWU9+8ayRG7ztE08lyXncJSSut2Ss2PEhTA==", + "peer": true, + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0" + }, + "peerDependencies": { + "@angular/core": "12.1.4", + "rxjs": "^6.5.3" + } + }, + "node_modules/@angular/core": { + "version": "12.1.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-12.1.4.tgz", + "integrity": "sha512-dG7KtW0l3jI8lapmenSu1wV/d3VOphAjDxVqWOrwh+kI0da7677cEg0Ms5YIF8Nf/++WleyNxk6AIHbDIig+Sw==", + "peer": true, + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": "^12.14.1 || >=14.0.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3", + "zone.js": "~0.11.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "peer": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true, + "peer": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true, + "peer": true + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "peer": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "peer": true + }, + "node_modules/jasmine": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.8.0.tgz", + "integrity": "sha512-kdQ3SfcNpMbbMdgJPLyFe9IksixdnrgYaCJapP9sS0aLgdWdIZADNXEr+11Zafxm1VDfRSC5ZL4fzXT0bexzXw==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.1.6", + "jasmine-core": "~3.8.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.8.0.tgz", + "integrity": "sha512-zl0nZWDrmbCiKns0NcjkFGYkVTGCPUgoHypTaj+G2AzaWus7QGoXARSlYsSle2VRpSdfJmM+hzmFKzQNhF2kHg==", + "dev": true, + "peer": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "peer": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true, + "peer": true + }, + "node_modules/zone.js": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.4.tgz", + "integrity": "sha512-DDh2Ab+A/B+9mJyajPjHFPWfYU1H+pdun4wnnk0OcQTNjem1XQSZ2CDW+rfZEUDjv5M19SBqAkjZi0x5wuB5Qw==", + "peer": true, + "dependencies": { + "tslib": "^2.0.0" + } + } + }, + "dependencies": { + "@angular-package/testing": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@angular-package/testing/-/testing-1.1.0.tgz", + "integrity": "sha512-N/c75WBG4GPcgj7NYWAKSE9IwcPSqVMOYjkZ3RU4rUZW5equkjZvQ4zWKc8S4lbxr1wPD6KxPy3T52xTsBW3Dw==", + "dev": true, + "requires": { + "tslib": "^2.2.0" + } + }, + "@angular-package/type": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@angular-package/type/-/type-4.2.0.tgz", + "integrity": "sha512-Y7HT94Gia4soR2ynwK8qva0WTOplau++gInEQCwDnhXmYy/r/1J/XhW0+aVj5XIa3SLWWa70nHvI0ivBM7O1nw==", + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "@angular/common": { + "version": "12.1.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-12.1.4.tgz", + "integrity": "sha512-cyh2m5veGgWRFsrmPnwB/Ised90bFNZAjZepvW8WXrpEUa/tmi1yWU9+8ayRG7ztE08lyXncJSSut2Ss2PEhTA==", + "peer": true, + "requires": { + "tslib": "^2.2.0" + } + }, + "@angular/core": { + "version": "12.1.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-12.1.4.tgz", + "integrity": "sha512-dG7KtW0l3jI8lapmenSu1wV/d3VOphAjDxVqWOrwh+kI0da7677cEg0Ms5YIF8Nf/++WleyNxk6AIHbDIig+Sw==", + "peer": true, + "requires": { + "tslib": "^2.2.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "peer": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true, + "peer": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true, + "peer": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "peer": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "peer": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "peer": true + }, + "jasmine": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.8.0.tgz", + "integrity": "sha512-kdQ3SfcNpMbbMdgJPLyFe9IksixdnrgYaCJapP9sS0aLgdWdIZADNXEr+11Zafxm1VDfRSC5ZL4fzXT0bexzXw==", + "dev": true, + "peer": true, + "requires": { + "glob": "^7.1.6", + "jasmine-core": "~3.8.0" + } + }, + "jasmine-core": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.8.0.tgz", + "integrity": "sha512-zl0nZWDrmbCiKns0NcjkFGYkVTGCPUgoHypTaj+G2AzaWus7QGoXARSlYsSle2VRpSdfJmM+hzmFKzQNhF2kHg==", + "dev": true, + "peer": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "peer": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "peer": true + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "peer": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "peer": true + } + } + }, + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true, + "peer": true + }, + "zone.js": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.4.tgz", + "integrity": "sha512-DDh2Ab+A/B+9mJyajPjHFPWfYU1H+pdun4wnnk0OcQTNjem1XQSZ2CDW+rfZEUDjv5M19SBqAkjZi0x5wuB5Qw==", + "peer": true, + "requires": { + "tslib": "^2.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1ffbc4e --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "@angular-package/error", + "version": "1.0.0", + "description": "Manages the callback function.", + "author": "Angular Package (https://wvvw.dev)", + "homepage": "https://github.com/angular-package/testing#readme", + "peerDependencies": { + "@angular-package/type": "^4.2.0", + "@angular/common": "^12.1.1", + "@angular/core": "^12.1.1" + }, + "dependencies": { + "tslib": "^2.2.0" + }, + "devDependencies": { + "@angular-package/testing": "^1.1.0" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, + "keywords": [ + "@angular", + "@angular-package", + "@angular-package/error", + "angular-package", + "Error" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/angular-package/error.git" + }, + "bugs": { + "url": "https://github.com/angular-package/error/issues" + }, + "license": "MIT" +} diff --git a/src/interface/error-message.interface.ts b/src/interface/error-message.interface.ts new file mode 100644 index 0000000..614e954 --- /dev/null +++ b/src/interface/error-message.interface.ts @@ -0,0 +1,13 @@ +/** + * The shape of an `object` for the error message that contains a possible solution to the described problem. + */ +export interface ErrorMessage { + /** + * Possible solution to the described problem of a `string` type. + */ + fix: string; + /** + * Error problem of a `string` type. + */ + problem: string; +} diff --git a/src/lib/validation-error.class.ts b/src/lib/validation-error.class.ts new file mode 100644 index 0000000..e702681 --- /dev/null +++ b/src/lib/validation-error.class.ts @@ -0,0 +1,74 @@ +// Object. +import { is, ResultCallback } from '@angular-package/type'; +// Interface. +import { ErrorMessage } from '../interface/error-message.interface'; +/** + * Manages an `Error` of the validation. + */ +export class ValidationError extends Error { + /** + * Template of the error message with the replaceable [problem] and [fix]. + * By default, it's set to `Problem: [problem] => Fix: [fix]`. + */ + static template = `Problem: [problem] => Fix: [fix]`; + + /** + * A possible solution to the described problem of a `string` type. By default, it's an empty `string`. + */ + public fix = ''; + + /** + * Error name of a `string` type that is being thrown. By default, it's `ValidationError`. + */ + public name = ValidationError.name; + + /** + * The validation problem of a `string` type. By default, it's an empty `string`. + */ + public problem = ''; + + /** + * Defines the validation error message of a `string` type from the provided `message` of the `ErrorMessage` interface. + * @param message An object of an `ErrorMessage` interface to build the message of a `string` type. The value is checked against + * the proper `object`. + * @param template A message template of a `string` type with replaceable `[problem]` and `[fix]` from the given `message`. The value is + * checked against a `string`. By default, it's set to `Problem: [problem] => Fix: [fix]`. + * @param callback An optional callback function of `ResultCallback` type to handle the check whether the provided message contains + * required `problem` and `fix` properties. + * @returns The return value is a message of a `string` type created from the provided `message` of `ErrorMessage` interface or it's an + * empty `string` if the provided message object isn't proper. + * @angularpackage + */ + static defineMessage( + message: ErrorMessage, + template: string = ValidationError.template, + callback?: ResultCallback + ): string { + if (is.objectKey(message, ['fix', 'problem'], callback)) { + if (is.string(template)) { + return template + .replace(`[fix]`, message.fix) + .replace(`[problem]`, message.problem); + } + } + return ''; + } + + /** + * Creates a new instance with the message. If the provided `message` is an `object`, then its properties are assigned + * to the instance. + * @param message The message of a `string` type or of an `ErrorMessage` interface that is used to throw with an `error`. + * @angularpackage + */ + constructor(message: string | ErrorMessage) { + super( + is.string(message) ? message : ValidationError.defineMessage(message) + ); + if (is.object(message)) { + Object.assign(this, { + problem: message.problem, + fix: message.fix, + }); + } + } +} diff --git a/src/message-builder/index.ts b/src/message-builder/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/message-builder/interface/message-template.interface.ts b/src/message-builder/interface/message-template.interface.ts new file mode 100644 index 0000000..a2388da --- /dev/null +++ b/src/message-builder/interface/message-template.interface.ts @@ -0,0 +1,3 @@ +export interface MessageTemplate { + [index: string]: string; +} diff --git a/src/message-builder/interface/parameter.interface.ts b/src/message-builder/interface/parameter.interface.ts new file mode 100644 index 0000000..8d17d26 --- /dev/null +++ b/src/message-builder/interface/parameter.interface.ts @@ -0,0 +1,4 @@ +export interface Parameter { + name: string; + type: string; +} diff --git a/src/message-builder/src/message-builder-template.class.ts b/src/message-builder/src/message-builder-template.class.ts new file mode 100644 index 0000000..64022cb --- /dev/null +++ b/src/message-builder/src/message-builder-template.class.ts @@ -0,0 +1,29 @@ +// @angular-package/type +import { is } from '@angular-package/type'; +// Interface. +import { MessageTemplate } from '../interface/message-template.interface'; +/** + * + */ +export class MessageBuilderTemplate { + #template: MessageTemplate = { + class: `[class][method]([param.name][param.type])[return]`, // argument value is [value.type] type, must be [param.type] type + function: `[function]([param.name][param.type])[return]`, + method: `[method]([param.name][param.type])[return]` + }; + + #type!: keyof MessageTemplate; + + /** + * Gets privately stored template of the provided in the constructor type. + */ + get get(): string { + return this.#template[this.#type]; + } + + constructor(type: 'class' | 'function' | 'method') { + if (is.string(type)) { + this.#type = type; + } + } +} diff --git a/src/message-builder/src/message-builder.class.ts b/src/message-builder/src/message-builder.class.ts new file mode 100644 index 0000000..42d9a5d --- /dev/null +++ b/src/message-builder/src/message-builder.class.ts @@ -0,0 +1,91 @@ +// @angular-package/type +import { is, guard, ResultCallback } from '@angular-package/type'; +// Class. +import { MessageBuilderTemplate } from './message-builder-template.class'; + +// export type RegExpPreDefined = 'class' | 'function' | 'method' | 'param.name' | 'param.type'; + +export class MessageBuilder { + #regExp = { + class: /\[class\]/i, + function: /\[function\]/i, + method: /\[method\]/i, + param: { + name: /\[param.name\]/i, + type: /\[param.type\]/i, + }, + return: /\[return\]/i + }; + + #template: string; + + get get(): string { + return this.#template; + } + + constructor(template: 'class' | 'function' | 'method') { + this.#template = new MessageBuilderTemplate(template).get; + } + + public setClassName(name: string, callback?: ResultCallback): this { + if (guard.string(name, callback)) { + this.replace(this.#regExp.class, name); + } + return this; + } + + public setFunctionName(name: string, callback?: ResultCallback): this { + if (guard.string(name, callback)) { + this.replace(this.#regExp.function, name); + } + return this; + } + + public setMethodName(name: string, callback?: ResultCallback): this { + if (guard.string(name, callback)) { + this.replace(this.#regExp.method, name); + } + return this; + } + + public setParam(name: string, type: string = ''): this { + if (guard.string(name)) { + const param = `${name}${type}`; + this + .replace(this.#regExp.param.name, name) + .replace(this.#regExp.param.type, type); + + if (type.length > 0) { + this.replace(type, `: ${type}`); + } + } + return this; + } + + public setReturn(returns: string, callback?: ResultCallback): this { + if (guard.string(returns, callback)) { + this.replace(this.#regExp.return, returns); + if (returns.length > 0) { + this.replace(returns, `: ${returns}`); + } + } + return this; + } + + private replace(searchValue: string | RegExp, replaceValue: string): this { + if (is.defined(searchValue)) { + this.#template = this.#template.replace( + searchValue, + is.string(replaceValue) ? replaceValue : '' + ); + } + return this; + } +} + +// console.log( +// new MessageBuilder('function') +// .param('firstName?', 'string') +// .function('isComponentLoader') +// .get +// ); diff --git a/src/message-builder/src/message-class-builder.class.ts b/src/message-builder/src/message-class-builder.class.ts new file mode 100644 index 0000000..dcde20f --- /dev/null +++ b/src/message-builder/src/message-class-builder.class.ts @@ -0,0 +1,83 @@ +import { is, guard } from '@angular-package/type'; +import { MessageBuilderTemplate } from './message-builder-template.class'; +import { MessageBuilder } from './message-builder.class'; + +// export class MessageClassBuilder extends MessageBuilder { +// private class$$: string; +// private param$$: { +// name?: string; +// type?: string; +// } = {}; +// private method$$: string; + +// constructor() { +// super('class'); +// } + +// /** +// * Build class message. +// */ +// public build(): this { +// // class. +// // this.replace('class', this.class$$); +// // // method. +// // this.replace('method', is.string(this.method$$) && is.string(this.class$$) ? `.${this.method$$}` : this.method$$); +// // // param. +// // const param = `${this.param$$.name}${this.param$$.type}`; +// // this +// // .replace('param.type', this.param$$.type) +// // .replace('param.name', this.param$$.name) +// // .replace(param, `(${param})`) +// // .replace(this.param$$.type, `: ${this.param$$.type}`); +// return this; +// } + +// /** +// * Set class name to build message. +// * @param name Class name. +// * @returns this. +// */ +// public class(name: string): this { +// if (guard.is.string(name)) { +// this.class$$ = name; +// } +// return this; +// } + +// /** +// * Set class method name to build message. +// * @param name Class method name. +// * @returns this. +// */ +// public method(name: string): this { +// if (guard.is.string(name)) { +// this.method$$ = name; +// } +// return this; +// } + +// /** +// * Set method param name with type to build message. +// * @param name Method param name. +// * @param type Method param type. +// * @returns this. +// */ +// public param(name: string, type?: string): this { +// if (guard.is.string(name)) { +// this.param$$.name = name; +// } +// if (guard.is.string(type)) { +// this.param$$.type = type; +// } +// return this; +// } +// } + +// const messageBuilderClass: MessageClassBuilder = new MessageClassBuilder() +// .class('NameProperty') +// .method('set') +// .param('name', 'Array') +// .build(); + +// console.log(`messageBuilderClass`, messageBuilderClass.get); + diff --git a/src/message-builder/src/message-function-builder.class.ts b/src/message-builder/src/message-function-builder.class.ts new file mode 100644 index 0000000..e0d2451 --- /dev/null +++ b/src/message-builder/src/message-function-builder.class.ts @@ -0,0 +1,82 @@ +import { guard, is, ResultCallback } from '@angular-package/type'; +// Class. +import { MessageBuilder } from './message-builder.class'; +// Interface. +import { Parameter } from '../interface/parameter.interface'; +/** + * + */ +export class MessageFunctionBuilder { + #messageBuilder: MessageBuilder; + #name = ''; + #param: Parameter = { + name: '', + type: '' + }; + #return = ''; + + get get(): string { + return this.#messageBuilder.get; + } + + constructor() { + this.#messageBuilder = new MessageBuilder('function'); + } + + /** + * Build function message. + */ + public build(): this { + this + .#messageBuilder + .setFunctionName(this.#name) + .setParam(this.#param.name, this.#param.type) + .setReturn(this.#return); + return this; + } + + /** + * Sets the function name to build message. + * @param name Function name of a `string` type. + * @param callback + * @returns The return value is an instance of `MessageBuilderFunction`. + */ + public setName(name: string, callback?: ResultCallback): this { + if (guard.string(name, callback)) { + this.#name = name; + } + // this.setFunction(name); + return this; + } + + /** + * Set method param name with type to build message. + * @param name Method param name. + * @param type Method param type. + * @returns this. + */ + public setParam(name: string, type?: string, callback?: ResultCallback): this { + if (guard.string(name, callback)) { + this.#param.name = name; + if (is.string(type)) { + this.#param.type = type; + } + } + return this; + } + + public setReturn(returns: string, callback?: ResultCallback): this { + if (guard.string(returns, callback)) { + this.#return = returns; + } + return this; + } +} + +const messageBuilderFunction = new MessageFunctionBuilder(); +messageBuilderFunction + .setName('isString') + .setParam('one', 'string') + .setReturn('this') + .build(); +console.log(messageBuilderFunction.get); diff --git a/src/public-api.ts b/src/public-api.ts new file mode 100644 index 0000000..b43a6fd --- /dev/null +++ b/src/public-api.ts @@ -0,0 +1,7 @@ +/* + * Public API Surface of error + */ +// Class. +export { ValidationError } from './lib/validation-error.class'; +// Interface. +export { ErrorMessage } from './interface/error-message.interface'; diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 0000000..52e5516 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,26 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js'; +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: { + context(path: string, deep?: boolean, filter?: RegExp): { + keys(): string[]; + (id: string): T; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/src/test/validation-error.spec.ts b/src/test/validation-error.spec.ts new file mode 100644 index 0000000..6edc5f9 --- /dev/null +++ b/src/test/validation-error.spec.ts @@ -0,0 +1,93 @@ +// External class. +import { Testing, TestingToBeMatchers } from '@angular-package/testing'; +// Class. +import { ValidationError } from '../lib/validation-error.class'; +/** + * Initialize `Testing`. + */ +const testing = new Testing(true, true); +const toBe = new TestingToBeMatchers(); +/** + * Tests. + */ +testing.describe('ValidationError', () => { + testing.describe('throw', () => { + const problem = 'My callback problem'; + const fix = 'Possible fix does not exist'; + try { + throw new ValidationError({ problem, fix }); + } catch (e: any) { + testing + .toBeClass(ValidationError) + .toBe('instanceof ValidationError', e instanceof ValidationError, true) + .toBeStringType( + e.problem, + undefined, + '`e.problem` must be of a `string` type' + ) + .toBeStringType(e.fix, undefined, '`e.fix` must be of a `string` type'); + } + }); + + testing.describe('instantiate', () => { + let fix: any; + let problem: any; + let validationError: any; + + beforeEach(() => { + fix = 'There is no solution to the described problem.'; + problem = 'The problem has no solution.'; + validationError = new ValidationError({ fix, problem }); + }); + + testing.it(`with the message of a \`string\` type`, () => { + const message = 'Validation error message'; + validationError = new ValidationError(message); + toBe.string(validationError.message); + expect(validationError.message).toContain(message); + }); + + testing.it(`with the message of the \`ErrorMessage\` interface`, () => { + toBe + .string(validationError.message) + .string(validationError.problem) + .string(validationError.fix); + + // to Equal. + expect(validationError.problem).toEqual(problem); + expect(validationError.fix).toEqual(fix); + expect(validationError.message).toEqual( + ValidationError.template + .replace(`[fix]`, fix) + .replace(`[problem]`, problem) + ); + // toContain. + expect(validationError.message).toContain(fix); + expect(validationError.message).toContain(problem); + }); + }); + + testing.describe('static defineMessage()', () => { + let fix: any; + let problem: any; + let errorMessage: any; + + beforeEach(() => { + fix = 'There is no solution to the described problem.'; + problem = 'The problem has no solution.'; + errorMessage = ValidationError.defineMessage({ fix, problem }); + }); + + testing.it(`with the message of the \`ErrorMessage\` interface`, () => { + toBe.string(errorMessage); + expect(errorMessage).toEqual( + ValidationError.template + .replace(`[fix]`, fix) + .replace(`[problem]`, problem) + ); + // toContain. + expect(errorMessage).toContain(fix); + expect(errorMessage).toContain(problem); + }); + }); +}); diff --git a/tsconfig.lib.json b/tsconfig.lib.json new file mode 100644 index 0000000..1407202 --- /dev/null +++ b/tsconfig.lib.json @@ -0,0 +1,20 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/tsconfig.lib.prod.json b/tsconfig.lib.prod.json new file mode 100644 index 0000000..06de549 --- /dev/null +++ b/tsconfig.lib.prod.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/tsconfig.spec.json b/tsconfig.spec.json new file mode 100644 index 0000000..bc7fbe9 --- /dev/null +++ b/tsconfig.spec.json @@ -0,0 +1,20 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "paths": { + "@angular/*": [ "./node_modules/@angular/*" ] + }, + "types": [ + "jasmine" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +}