mirror of https://github.com/abpframework/abp
commit
752d98b261
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,4 +1,14 @@
|
||||
@media (min-width: 767px) {
|
||||
.box-articles {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.box-articles {
|
||||
h3 {
|
||||
a {
|
||||
color: #000;
|
||||
font-weight: 700;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,191 @@
|
||||
import { FormControl, Validators } from '@angular/forms';
|
||||
import { AbpValidators, validateRange } from '../validators';
|
||||
import { validateCreditCard } from '../validators/credit-card.validator';
|
||||
import { validateRequired } from '../validators/required.validator';
|
||||
import { validateStringLength } from '../validators/string-length.validator';
|
||||
import { validateUrl } from '../validators/url.validator';
|
||||
|
||||
describe('Validators', () => {
|
||||
describe('Credit Card Validator', () => {
|
||||
const error = { creditCard: true };
|
||||
|
||||
test.each`
|
||||
input | expected
|
||||
${undefined} | ${null}
|
||||
${null} | ${null}
|
||||
${''} | ${null}
|
||||
${'0'} | ${error}
|
||||
${'5105105105105100' /* Mastercard */} | ${null}
|
||||
${'5105105105105101' /* Mastercard */} | ${error}
|
||||
${'5105 1051 0510 5100'} | ${null}
|
||||
${'5105-1051-0510-5100'} | ${null}
|
||||
${'5105 - 1051 - 0510 - 5100'} | ${null}
|
||||
${'4111111111111111' /*Visa*/} | ${null}
|
||||
${'4111111111111112' /*Visa*/} | ${error}
|
||||
${'4012888888881881' /* Visa */} | ${null}
|
||||
${'4012888888881882' /* Visa */} | ${error}
|
||||
${'4222222222222' /* Visa */} | ${null}
|
||||
${'4222222222223' /* Visa */} | ${error}
|
||||
${'378282246310005' /* American Express */} | ${null}
|
||||
${'378282246310006' /* American Express */} | ${error}
|
||||
${'6011111111111117' /* Discover */} | ${null}
|
||||
${'6011111111111118' /* Discover */} | ${error}
|
||||
`('should return $expected when input is $input', ({ input, expected }) => {
|
||||
const control = new FormControl(input, [validateCreditCard()]);
|
||||
control.markAsDirty({ onlySelf: true });
|
||||
control.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
|
||||
expect(control.errors).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return null when control is pristine', () => {
|
||||
const invalidNumber = '5105105105105101';
|
||||
const control = new FormControl(invalidNumber, [validateCreditCard()]);
|
||||
// control is not dirty
|
||||
|
||||
expect(control.valid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Email Validator', () => {
|
||||
it('should return email validator of Angular', () => {
|
||||
expect(AbpValidators.emailAddress()).toBe(Validators.email);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Range Validator', () => {
|
||||
test.each`
|
||||
input | options | expected
|
||||
${null} | ${undefined} | ${null}
|
||||
${undefined} | ${undefined} | ${null}
|
||||
${''} | ${undefined} | ${null}
|
||||
${0} | ${undefined} | ${null}
|
||||
${Infinity} | ${undefined} | ${null}
|
||||
${'-1'} | ${{ minimum: 0 }} | ${{ range: { min: 0, max: Infinity } }}
|
||||
${-1} | ${{ minimum: 0 }} | ${{ range: { min: 0, max: Infinity } }}
|
||||
${2} | ${{ minimum: 3, maximum: 5 }} | ${{ range: { min: 3, max: 5 } }}
|
||||
${3} | ${{ minimum: 3, maximum: 5 }} | ${null}
|
||||
${5} | ${{ minimum: 3, maximum: 5 }} | ${null}
|
||||
${6} | ${{ minimum: 3, maximum: 5 }} | ${{ range: { min: 3, max: 5 } }}
|
||||
`(
|
||||
'should return $expected when input is $input and options are $options',
|
||||
({ input, options, expected }) => {
|
||||
const control = new FormControl(input, [validateRange(options)]);
|
||||
control.markAsDirty({ onlySelf: true });
|
||||
control.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
|
||||
expect(control.errors).toEqual(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it('should return null when control is pristine', () => {
|
||||
const invalidUrl = '';
|
||||
const control = new FormControl(invalidUrl, [validateRange({ minimum: 3 })]);
|
||||
// control is not dirty
|
||||
|
||||
expect(control.valid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Required Validator', () => {
|
||||
const error = { required: true };
|
||||
|
||||
test.each`
|
||||
input | options | expected
|
||||
${0} | ${undefined} | ${null}
|
||||
${false} | ${undefined} | ${null}
|
||||
${null} | ${undefined} | ${error}
|
||||
${undefined} | ${undefined} | ${error}
|
||||
${''} | ${undefined} | ${error}
|
||||
${''} | ${{}} | ${error}
|
||||
${''} | ${{ allowEmptyStrings: false }} | ${error}
|
||||
${''} | ${{ allowEmptyStrings: true }} | ${null}
|
||||
`(
|
||||
'should return $expected when input is $input and options are $options',
|
||||
({ input, options, expected }) => {
|
||||
const control = new FormControl(input, [validateRequired(options)]);
|
||||
control.markAsDirty({ onlySelf: true });
|
||||
control.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
|
||||
expect(control.errors).toEqual(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it('should return null when control is pristine', () => {
|
||||
const invalidUrl = '';
|
||||
const control = new FormControl(invalidUrl, [validateRequired()]);
|
||||
// control is not dirty
|
||||
|
||||
expect(control.valid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('String Length Validator', () => {
|
||||
test.each`
|
||||
input | options | expected
|
||||
${null} | ${undefined} | ${null}
|
||||
${undefined} | ${undefined} | ${null}
|
||||
${''} | ${undefined} | ${null}
|
||||
${'ab'} | ${{ minimumLength: 3 }} | ${{ minlength: { requiredLength: 3 } }}
|
||||
${'abp'} | ${{ minimumLength: 3 }} | ${null}
|
||||
${'abp'} | ${{ maximumLength: 2 }} | ${{ maxlength: { requiredLength: 2 } }}
|
||||
${'abp'} | ${{ maximumLength: 3 }} | ${null}
|
||||
`(
|
||||
'should return $expected when input is $input and options are $options',
|
||||
({ input, options, expected }) => {
|
||||
const control = new FormControl(input, [validateStringLength(options)]);
|
||||
control.markAsDirty({ onlySelf: true });
|
||||
control.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
|
||||
expect(control.errors).toEqual(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it('should return null when control is pristine', () => {
|
||||
const invalidUrl = '';
|
||||
const control = new FormControl(invalidUrl, [validateStringLength({ minimumLength: 3 })]);
|
||||
// control is not dirty
|
||||
|
||||
expect(control.valid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Url Validator', () => {
|
||||
const error = { url: true };
|
||||
|
||||
test.each`
|
||||
input | expected
|
||||
${undefined} | ${null}
|
||||
${null} | ${null}
|
||||
${''} | ${null}
|
||||
${'http://x'} | ${null}
|
||||
${'http:///x'} | ${error}
|
||||
${'https://x'} | ${null}
|
||||
${'https:///x'} | ${error}
|
||||
${'ftp://x'} | ${null}
|
||||
${'ftp:///x'} | ${error}
|
||||
${'http://x.com'} | ${null}
|
||||
${'http://x.photography'} | ${null}
|
||||
${'http://www.x.org'} | ${null}
|
||||
${'http://sub.x.gov.tr'} | ${null}
|
||||
${'x'} | ${error}
|
||||
${'x.com'} | ${error}
|
||||
${'www.x.org'} | ${error}
|
||||
${'sub.x.gov.tr'} | ${error}
|
||||
`('should return $expected when input is $input', ({ input, expected }) => {
|
||||
const control = new FormControl(input, [validateUrl()]);
|
||||
control.markAsDirty({ onlySelf: true });
|
||||
control.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
|
||||
expect(control.errors).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return null when control is pristine', () => {
|
||||
const invalidUrl = 'x';
|
||||
const control = new FormControl(invalidUrl, [validateUrl()]);
|
||||
// control is not dirty
|
||||
|
||||
expect(control.valid).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,34 @@
|
||||
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||
|
||||
export interface CreditCardError {
|
||||
creditCard: true;
|
||||
}
|
||||
|
||||
export function validateCreditCard(): ValidatorFn {
|
||||
return (control: AbstractControl): CreditCardError | null => {
|
||||
if (control.pristine) return null;
|
||||
|
||||
if (['', null, undefined].indexOf(control.value) > -1) return null;
|
||||
|
||||
return isValidCreditCard(String(control.value)) ? null : { creditCard: true };
|
||||
};
|
||||
}
|
||||
|
||||
function isValidCreditCard(value: string): boolean {
|
||||
value = value.replace(/[ -]/g, '');
|
||||
|
||||
if (!/^[0-9]{13,19}$/.test(value)) return false;
|
||||
|
||||
let checksum = 0;
|
||||
let multiplier = 1;
|
||||
|
||||
for (let i = value.length; i > 0; i--) {
|
||||
const digit = Number(value[i - 1]) * multiplier;
|
||||
/* tslint:disable-next-line:no-bitwise */
|
||||
checksum += (digit % 10) + ~~(digit / 10);
|
||||
|
||||
multiplier = (multiplier * 2) % 3;
|
||||
}
|
||||
|
||||
return checksum % 10 === 0;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
import { Validators } from '@angular/forms';
|
||||
import { validateCreditCard } from './credit-card.validator';
|
||||
import { validateRange } from './range.validator';
|
||||
import { validateRequired } from './required.validator';
|
||||
import { validateStringLength } from './string-length.validator';
|
||||
import { validateUrl } from './url.validator';
|
||||
export * from './credit-card.validator';
|
||||
export * from './range.validator';
|
||||
export * from './required.validator';
|
||||
export * from './string-length.validator';
|
||||
export * from './url.validator';
|
||||
|
||||
export const AbpValidators = {
|
||||
creditCard: validateCreditCard,
|
||||
emailAddress: () => Validators.email,
|
||||
range: validateRange,
|
||||
required: validateRequired,
|
||||
stringLength: validateStringLength,
|
||||
url: validateUrl,
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||
|
||||
export interface RangeError {
|
||||
range: {
|
||||
max: number;
|
||||
min: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RangeOptions {
|
||||
maximum?: number;
|
||||
minimum?: number;
|
||||
}
|
||||
|
||||
export function validateRange({ maximum = Infinity, minimum = 0 }: RangeOptions = {}): ValidatorFn {
|
||||
return (control: AbstractControl): RangeError | null => {
|
||||
if (control.pristine) return null;
|
||||
|
||||
if (['', null, undefined].indexOf(control.value) > -1) return null;
|
||||
|
||||
const value = Number(control.value);
|
||||
return getMinError(value, minimum, maximum) || getMaxError(value, maximum, minimum);
|
||||
};
|
||||
}
|
||||
|
||||
function getMaxError(value: number, max: number, min: number): RangeError {
|
||||
return value > max ? { range: { max, min } } : null;
|
||||
}
|
||||
|
||||
function getMinError(value: number, min: number, max: number): RangeError {
|
||||
return value < min ? { range: { min, max } } : null;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||
|
||||
export interface RequiredError {
|
||||
required: true;
|
||||
}
|
||||
|
||||
export interface RequiredOptions {
|
||||
allowEmptyStrings?: boolean;
|
||||
}
|
||||
|
||||
export function validateRequired({ allowEmptyStrings }: RequiredOptions = {}): ValidatorFn {
|
||||
return (control: AbstractControl): RequiredError | null => {
|
||||
return control.pristine || isValidRequired(control.value, allowEmptyStrings)
|
||||
? null
|
||||
: { required: true };
|
||||
};
|
||||
}
|
||||
|
||||
function isValidRequired(value: any, allowEmptyStrings: boolean): boolean {
|
||||
if (value || value === 0 || value === false) return true;
|
||||
|
||||
if (allowEmptyStrings && value === '') return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||
|
||||
export interface StringLengthError {
|
||||
maxlength?: {
|
||||
requiredLength: number;
|
||||
};
|
||||
minlength?: {
|
||||
requiredLength: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface StringLengthOptions {
|
||||
maximumLength?: number;
|
||||
minimumLength?: number;
|
||||
}
|
||||
|
||||
export function validateStringLength({
|
||||
maximumLength = Infinity,
|
||||
minimumLength = 0,
|
||||
}: StringLengthOptions = {}): ValidatorFn {
|
||||
return (control: AbstractControl): StringLengthError | null => {
|
||||
if (control.pristine) return null;
|
||||
|
||||
if (['', null, undefined].indexOf(control.value) > -1) return null;
|
||||
|
||||
const value = String(control.value);
|
||||
|
||||
return getMinLengthError(value, minimumLength) || getMaxLengthError(value, maximumLength);
|
||||
};
|
||||
}
|
||||
|
||||
function getMaxLengthError(value: string, requiredLength: number): StringLengthError {
|
||||
return value.length > requiredLength ? { maxlength: { requiredLength } } : null;
|
||||
}
|
||||
|
||||
function getMinLengthError(value: string, requiredLength: number): StringLengthError {
|
||||
return value.length < requiredLength ? { minlength: { requiredLength } } : null;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||
|
||||
export interface UrlError {
|
||||
url: true;
|
||||
}
|
||||
|
||||
export function validateUrl(): ValidatorFn {
|
||||
return (control: AbstractControl): UrlError | null => {
|
||||
if (control.pristine) return null;
|
||||
|
||||
if (['', null, undefined].indexOf(control.value) > -1) return null;
|
||||
|
||||
return isValidUrl(control.value) ? null : { url: true };
|
||||
};
|
||||
}
|
||||
|
||||
function isValidUrl(value: string): boolean {
|
||||
if (/^http(s)?:\/\/[^/]/.test(value) || /^ftp:\/\/[^/]/.test(value)) {
|
||||
const a = document.createElement('a');
|
||||
a.href = value;
|
||||
return !!a.host;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
import execa from 'execa';
|
||||
import fse from 'fs-extra';
|
||||
import glob from 'glob';
|
||||
|
||||
async function replace(filePath: string) {
|
||||
const pkg = await fse.readJson(filePath);
|
||||
|
||||
const { dependencies } = pkg;
|
||||
|
||||
if (!dependencies) return;
|
||||
|
||||
Object.keys(dependencies).forEach(key => {
|
||||
if (key.includes('@abp/') && key !== '@abp/utils') {
|
||||
dependencies[key] = dependencies[key].replace('^', '~');
|
||||
}
|
||||
});
|
||||
|
||||
await fse.writeJson(filePath, { ...pkg, dependencies }, { spaces: 2 });
|
||||
}
|
||||
|
||||
glob('../packages/**/package.json', {}, (er, files) => {
|
||||
files.forEach(path => {
|
||||
if (path.includes('node_modules')) {
|
||||
return;
|
||||
}
|
||||
|
||||
replace(path);
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue