diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..7c52faa --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,42 @@ +{ + "root": true, + "ignorePatterns": ["**/*"], + "plugins": ["@nrwl/nx"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": { + "@nrwl/nx/enforce-module-boundaries": [ + "error", + { + "enforceBuildableLibDependency": true, + "allow": [], + "depConstraints": [ + { + "sourceTag": "*", + "onlyDependOnLibsWithTags": ["*"] + } + ] + } + ] + } + }, + { + "files": ["*.ts", "*.tsx"], + "extends": ["plugin:@nrwl/nx/typescript"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "extends": ["plugin:@nrwl/nx/javascript"], + "rules": {} + }, + { + "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], + "env": { + "jest": true + }, + "rules": {} + } + ] +} diff --git a/.gitignore b/.gitignore index acc453d..509f266 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ package-lock.json # System Files .DS_Store Thumbs.db + +.angular diff --git a/angular.json b/angular.json index bf35d46..751a40e 100644 --- a/angular.json +++ b/angular.json @@ -1,14 +1,42 @@ { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, + "version": 2, "newProjectRoot": "packages", "projects": { + "core": { + "root": "packages/core", + "sourceRoot": "packages/core/src", + "projectType": "library", + "prefix": "validation", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "packages/core/tsconfig.lib.json", + "project": "packages/core/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "packages/core/tsconfig.lib.prod.json" + } + } + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "packages/core/src/test.ts", + "tsConfig": "packages/core/tsconfig.spec.json", + "karmaConfig": "packages/core/karma.conf.js" + } + } + } + }, "ngx-validate": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app", - "schematics": { + "generators": { "@schematics/angular:class": { "skipTests": true }, @@ -29,9 +57,9 @@ "skipTests": true } }, - "architect": { + "targets": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "executor": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/ngx-validate", "index": "src/index.html", @@ -79,7 +107,7 @@ "defaultConfiguration": "" }, "serve": { - "builder": "@angular-devkit/build-angular:dev-server", + "executor": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "ngx-validate:build" }, @@ -90,13 +118,13 @@ } }, "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", + "executor": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "ngx-validate:build" } }, "test": { - "builder": "@angular-devkit/build-angular:karma", + "executor": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", @@ -109,36 +137,28 @@ } } }, - "core": { - "root": "packages/core", - "sourceRoot": "packages/core/src", + "validators": { "projectType": "library", - "prefix": "validation", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:ng-packagr", + "root": "packages/validators", + "sourceRoot": "packages/validators/src", + "prefix": "ngx-validate", + "targets": { + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "tsConfig": "packages/core/tsconfig.lib.json", - "project": "packages/core/ng-package.json" - }, - "configurations": { - "production": { - "tsConfig": "packages/core/tsconfig.lib.prod.json" - } + "jestConfig": "packages/validators/jest.config.ts", + "passWithNoTests": true } }, - "test": { - "builder": "@angular-devkit/build-angular:karma", + "lint": { + "executor": "@nrwl/linter:eslint", "options": { - "main": "packages/core/src/test.ts", - "tsConfig": "packages/core/tsconfig.spec.json", - "karmaConfig": "packages/core/karma.conf.js" + "lintFilePatterns": ["packages/validators/**/*.ts", "packages/validators/**/*.html"] } } - } + }, + "tags": [] } - }, - "cli": { - "analytics": false } } diff --git a/decorate-angular-cli.js b/decorate-angular-cli.js new file mode 100644 index 0000000..7e9dbc1 --- /dev/null +++ b/decorate-angular-cli.js @@ -0,0 +1,73 @@ +/** + * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching + * and faster execution of tasks. + * + * It does this by: + * + * - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command. + * - Symlinking the ng to nx command, so all commands run through the Nx CLI + * - Updating the package.json postinstall script to give you control over this script + * + * The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it. + * Every command you run should work the same when using the Nx CLI, except faster. + * + * Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case, + * will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked. + * The Nx CLI simply does some optimizations before invoking the Angular CLI. + * + * To opt out of this patch: + * - Replace occurrences of nx with ng in your package.json + * - Remove the script from your postinstall script in your package.json + * - Delete and reinstall your node_modules + */ + +const fs = require('fs'); +const os = require('os'); +const cp = require('child_process'); +const isWindows = os.platform() === 'win32'; +let output; +try { + output = require('@nrwl/workspace').output; +} catch (e) { + console.warn( + 'Angular CLI could not be decorated to enable computation caching. Please ensure @nrwl/workspace is installed.', + ); + process.exit(0); +} + +/** + * Symlink of ng to nx, so you can keep using `ng build/test/lint` and still + * invoke the Nx CLI and get the benefits of computation caching. + */ +function symlinkNgCLItoNxCLI() { + try { + const ngPath = './node_modules/.bin/ng'; + const nxPath = './node_modules/.bin/nx'; + if (isWindows) { + /** + * This is the most reliable way to create symlink-like behavior on Windows. + * Such that it works in all shells and works with npx. + */ + ['', '.cmd', '.ps1'].forEach(ext => { + if (fs.existsSync(nxPath + ext)) + fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext)); + }); + } else { + // If unix-based, symlink + cp.execSync(`ln -sf ./nx ${ngPath}`); + } + } catch (e) { + output.error({ + title: 'Unable to create a symlink from the Angular CLI to the Nx CLI:' + e.message, + }); + throw e; + } +} + +try { + symlinkNgCLItoNxCLI(); + require('nx/src/adapter/decorate-cli').decorateCli(); + output.log({ title: 'Angular CLI has been decorated to enable computation caching.' }); +} catch (e) { + output.error({ title: 'Decoration of the Angular CLI did not complete successfully' }); +} diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..2a738f7 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,5 @@ +import { getJestProjects } from '@nrwl/jest'; + +export default { + projects: getJestProjects(), +}; diff --git a/jest.preset.js b/jest.preset.js new file mode 100644 index 0000000..e6c8ebe --- /dev/null +++ b/jest.preset.js @@ -0,0 +1,3 @@ +const nxPreset = require('@nrwl/jest/preset').default; + +module.exports = { ...nxPreset }; diff --git a/nx.json b/nx.json new file mode 100644 index 0000000..be17b9b --- /dev/null +++ b/nx.json @@ -0,0 +1,55 @@ +{ + "npmScope": "ngx-validate", + "affected": { + "defaultBase": "main" + }, + "implicitDependencies": { + "package.json": { + "dependencies": "*", + "devDependencies": "*" + }, + ".eslintrc.json": "*" + }, + "tasksRunnerOptions": { + "default": { + "runner": "nx/tasks-runners/default", + "options": { + "cacheableOperations": ["build", "lint", "test", "e2e"] + } + } + }, + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + }, + "test": { + "inputs": ["default", "^default", "{workspaceRoot}/jest.preset.js"] + }, + "lint": { + "inputs": ["default", "{workspaceRoot}/.eslintrc.json"] + } + }, + "workspaceLayout": { + "appsDir": "packages", + "libsDir": "packages" + }, + "cli": { + "analytics": false + }, + "defaultProject": "ngx-validate", + "generators": { + "@nrwl/angular:application": { + "style": "css", + "linter": "eslint", + "unitTestRunner": "jest", + "e2eTestRunner": "none" + }, + "@nrwl/angular:library": { + "linter": "eslint", + "unitTestRunner": "jest" + }, + "@nrwl/angular:component": { + "style": "css" + } + } +} diff --git a/package.json b/package.json index 1afb309..7639027 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "ngx-validate", "version": "0.2.0", "scripts": { - "ng": "ng", + "ng": "nx", "start": "ng serve", "build:core": "ng build core --configuration=production", "build:demo": "ng build --configuration=production", @@ -13,40 +13,57 @@ "symlink": "symlink copy --angular --packages @ngx-validate/core", "symlink-ci": "symlink copy --angular --packages @ngx-validate/core --no-watch", "ci": "yarn test:ci && yarn run symlink-ci && yarn run build:demo", - "cz": "git cz" + "cz": "git cz", + "postinstall": "node ./decorate-angular-cli.js" }, "private": true, "dependencies": { - "@angular/animations": "^14.2.0", - "@angular/common": "^14.2.0", - "@angular/compiler": "^14.2.0", - "@angular/core": "^14.2.0", - "@angular/forms": "^14.2.0", - "@angular/platform-browser": "^14.2.0", - "@angular/platform-browser-dynamic": "^14.2.0", - "@angular/router": "^14.2.0", + "@angular/animations": "~15.0.0", + "@angular/common": "~15.0.0", + "@angular/compiler": "~15.0.0", + "@angular/core": "~15.0.0", + "@angular/forms": "~15.0.0", + "@angular/platform-browser": "~15.0.0", + "@angular/platform-browser-dynamic": "~15.0.0", + "@angular/router": "~15.0.0", + "@nrwl/angular": "^15.2.1", "bootstrap": "^4.3.1", "core-js": "^2.5.4", "jquery": "^3.5.0", "popper.js": "^1.14.7", - "rxjs": "~6.6.7", - "tslib": "^2.0.0", + "rxjs": "~7.5.0", + "tslib": "^2.3.0", "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "^14.2.1", - "@angular/cli": "^14.2.1", - "@angular/compiler-cli": "^14.2.0", - "@angular/language-service": "^14.2.0", + "@angular-devkit/build-angular": "~15.0.0", + "@angular-eslint/eslint-plugin": "~14.0.4", + "@angular-eslint/eslint-plugin-template": "~14.0.4", + "@angular-eslint/template-parser": "~14.0.4", + "@angular/cli": "~15.0.0", + "@angular/compiler-cli": "~15.0.0", + "@angular/language-service": "~15.0.0", "@ngneat/spectator": "^11.1.3", + "@nrwl/eslint-plugin-nx": "15.2.1", + "@nrwl/jest": "15.2.1", + "@nrwl/linter": "15.2.1", + "@nrwl/workspace": "15.2.1", "@types/jasmine": "~4.3.0", "@types/jasminewd2": "~2.0.3", - "@types/node": "^18.7.13", + "@types/jest": "28.1.1", + "@types/node": "16.11.7", + "@typescript-eslint/eslint-plugin": "^5.36.1", + "@typescript-eslint/parser": "^5.36.1", "codelyzer": "^6.0.0", "cz-conventional-changelog": "3.0.2", + "eslint": "~8.15.0", + "eslint-config-prettier": "8.1.0", "husky": "^3.0.7", "jasmine-core": "^4.0.0", "jasmine-spec-reporter": "~7.0.0", + "jest": "28.1.1", + "jest-environment-jsdom": "28.1.1", + "jest-preset-angular": "~12.2.2", "karma": "~6.4.0", "karma-chrome-launcher": "~3.1.0", "karma-coverage-istanbul-reporter": "~3.0.2", @@ -54,10 +71,12 @@ "karma-jasmine-html-reporter": "^2.0.0", "lint-staged": "^13.0.3", "ng-packagr": "^14.2.0", + "nx": "15.2.1", "prettier": "^2.7.1", "protractor": "~7.0.0", "symlink-manager": "^1.3.0", - "ts-node": "~10.9.1", + "ts-jest": "28.0.5", + "ts-node": "10.9.1", "tslint": "~6.1.0", "typescript": "~4.6.4" }, diff --git a/packages/core/package.json b/packages/core/package.json index 941cc49..0cbcad3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@ngx-validate/core", - "version": "0.2.0", + "version": "0.2.2", "license": "MIT", "repository": { "type": "git", diff --git a/packages/core/src/lib/validators/index.ts b/packages/core/src/lib/validators/index.ts deleted file mode 100644 index db8b6da..0000000 --- a/packages/core/src/lib/validators/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './password-validators'; diff --git a/packages/core/src/public_api.ts b/packages/core/src/public_api.ts index 43dffc8..e650e99 100644 --- a/packages/core/src/public_api.ts +++ b/packages/core/src/public_api.ts @@ -10,4 +10,3 @@ export * from './lib/directives'; export * from './lib/models'; export * from './lib/tokens'; export * from './lib/utils'; -export * from './lib/validators'; diff --git a/packages/validators/.eslintrc.json b/packages/validators/.eslintrc.json new file mode 100644 index 0000000..36ab5e3 --- /dev/null +++ b/packages/validators/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nrwl/nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "ngxValidate", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "ngx-validate", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nrwl/nx/angular-template"], + "rules": {} + } + ] +} diff --git a/packages/validators/README.md b/packages/validators/README.md new file mode 100644 index 0000000..4f56912 --- /dev/null +++ b/packages/validators/README.md @@ -0,0 +1,7 @@ +# validators + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test validators` to execute the unit tests. diff --git a/packages/validators/jest.config.ts b/packages/validators/jest.config.ts new file mode 100644 index 0000000..f6aa866 --- /dev/null +++ b/packages/validators/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'validators', + preset: '../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + globals: { + 'ts-jest': { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + }, + coverageDirectory: '../../coverage/packages/validators', + transform: { + '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/packages/validators/package.json b/packages/validators/package.json new file mode 100644 index 0000000..869cad9 --- /dev/null +++ b/packages/validators/package.json @@ -0,0 +1,18 @@ +{ + "name": "@ngx-validate/validators", + "version": "0.2.2", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/ng-turkey/ngx-validate.git" + }, + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=5.0.0", + "@angular/core": ">=5.0.0", + "@angular/forms": ">=5.0.0", + "rxjs": ">=6.0.0 || ^5.6.0-forward-compat.4" + } +} diff --git a/packages/validators/src/index.ts b/packages/validators/src/index.ts new file mode 100644 index 0000000..11aece6 --- /dev/null +++ b/packages/validators/src/index.ts @@ -0,0 +1 @@ +export * from './lib/index'; diff --git a/packages/validators/src/lib/compare-passwords.ts b/packages/validators/src/lib/compare-passwords.ts new file mode 100644 index 0000000..ae6df0a --- /dev/null +++ b/packages/validators/src/lib/compare-passwords.ts @@ -0,0 +1,18 @@ +import { AbstractControl, ValidatorFn } from '@angular/forms'; + +export function comparePasswords([controlName1, controlName2]: string[]): ValidatorFn { + return (group: AbstractControl) => { + if (!group) return null; + + const password = group.get(controlName1)?.value; + const repeat = group.get(controlName2)?.value; + + return !password || !repeat || password === repeat + ? null + : { + passwordMismatch: { + fields: [controlName1, controlName2], + }, + }; + }; +} diff --git a/packages/validators/src/lib/index.ts b/packages/validators/src/lib/index.ts new file mode 100644 index 0000000..14145b9 --- /dev/null +++ b/packages/validators/src/lib/index.ts @@ -0,0 +1,3 @@ +export * from './compare-passwords'; +export * from './validate-password'; +export * from './password-rules'; diff --git a/packages/validators/src/lib/password-rules.ts b/packages/validators/src/lib/password-rules.ts new file mode 100644 index 0000000..61ceac8 --- /dev/null +++ b/packages/validators/src/lib/password-rules.ts @@ -0,0 +1 @@ +export type PasswordRules = ('small' | 'capital' | 'number' | 'special')[]; diff --git a/packages/core/src/lib/validators/password-validators.ts b/packages/validators/src/lib/validate-password.ts similarity index 58% rename from packages/core/src/lib/validators/password-validators.ts rename to packages/validators/src/lib/validate-password.ts index e5b4895..55a7510 100644 --- a/packages/core/src/lib/validators/password-validators.ts +++ b/packages/validators/src/lib/validate-password.ts @@ -1,22 +1,6 @@ -import { AbstractControl, UntypedFormGroup, ValidatorFn } from '@angular/forms'; -import { addCommas, normalizeDiacritics } from '../utils'; - -export function comparePasswords([controlName1, controlName2]: string[]): ValidatorFn { - return (group: UntypedFormGroup) => { - const password = group.get(controlName1).value; - const repeat = group.get(controlName2).value; - - return !password || !repeat || password === repeat - ? null - : { - passwordMismatch: { - fields: [controlName1, controlName2], - }, - }; - }; -} - -export type PasswordRules = ('small' | 'capital' | 'number' | 'special')[]; +import { AbstractControl, ValidatorFn } from '@angular/forms'; +import { addCommas, normalizeDiacritics } from '@ngx-validate/core'; +import { PasswordRules } from './password-rules'; export function validatePassword( shouldContain: PasswordRules = ['small', 'capital', 'number', 'special'], @@ -47,7 +31,7 @@ export function validatePassword( capital: 'a capital', number: 'a number', special: 'a special character', - }[key]), + }[key] || key), ), ), }, diff --git a/packages/validators/src/test-setup.ts b/packages/validators/src/test-setup.ts new file mode 100644 index 0000000..1100b3e --- /dev/null +++ b/packages/validators/src/test-setup.ts @@ -0,0 +1 @@ +import 'jest-preset-angular/setup-jest'; diff --git a/packages/validators/tsconfig.json b/packages/validators/tsconfig.json new file mode 100644 index 0000000..a7f94ed --- /dev/null +++ b/packages/validators/tsconfig.json @@ -0,0 +1,29 @@ +{ + "extends": "../../tsconfig.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/packages/validators/tsconfig.lib.json b/packages/validators/tsconfig.lib.json new file mode 100644 index 0000000..719ef60 --- /dev/null +++ b/packages/validators/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts", "**/*.test.ts"], + "include": ["**/*.ts"] +} diff --git a/packages/validators/tsconfig.spec.json b/packages/validators/tsconfig.spec.json new file mode 100644 index 0000000..c5db027 --- /dev/null +++ b/packages/validators/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] +} diff --git a/tsconfig.json b/tsconfig.json index f6ca7c1..cead768 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,8 @@ "lib": ["es2018", "dom"], "paths": { "@ngx-validate/core": ["packages/core/src/public_api.ts"], - "@ngx-validate/core/*": ["packages/core/src/lib/*"] + "@ngx-validate/core/*": ["packages/core/src/lib/*"], + "@ngx-validate/validators": ["packages/validators/src/index.ts"] } } }