Skip to content

Commit

Permalink
resolve faker 9 breaking changes (#27368)
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima authored Oct 2, 2024
1 parent ed25314 commit 547c270
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 41 deletions.
6 changes: 5 additions & 1 deletion generators/base-application/support/prepare-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ export default function prepareEntity(entityWithConfig, generator, application)
mutateData(entityWithConfig, entityDefaultConfig, BASE_TEMPLATE_DATA);

if (entityWithConfig.changelogDate) {
entityWithConfig.changelogDateForRecent = parseChangelog(String(entityWithConfig.changelogDate));
try {
entityWithConfig.changelogDateForRecent = parseChangelog(String(entityWithConfig.changelogDate));
} catch (error: unknown) {
throw new Error(`Error parsing changelog date for entity ${entityName}: ${(error as Error).message}`, { cause: error });
}
}

entityWithConfig.entityAngularJSSuffix = entityWithConfig.angularJSSuffix;
Expand Down
63 changes: 44 additions & 19 deletions generators/base-application/support/prepare-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type CoreGenerator from '../../base-core/generator.js';
import type { Field } from '../../../lib/types/application/field.js';
import type { Entity } from '../../../lib/types/application/entity.js';
import { fieldTypeValues, isFieldEnumType } from '../../../lib/application/field-types.js';
import type { FakerWithRandexp } from '../../base/support/faker.js';
import { prepareProperty } from './prepare-property.js';

const { BlobTypes, CommonDBTypes, RelationalOnlyDBTypes } = fieldTypes;
Expand Down Expand Up @@ -106,16 +107,25 @@ const fakeStringTemplateForFieldName = columnName => {
* @param {string} type csv, cypress, json-serializable, ts
* @returns fake value
*/
function generateFakeDataForField(this: CoreGenerator, field, faker, changelogDate, type = 'csv') {
function generateFakeDataForField(this: CoreGenerator, field: Field, faker: FakerWithRandexp, changelogDate, type = 'csv') {
let data;
for (const prop of ['fieldValidateRulesMax', 'fieldValidateRulesMin', 'fieldValidateRulesMaxlength', 'fieldValidateRulesMinlength']) {
if (prop in field) {
try {
field[prop] = parseInt(field[prop], 10);
} catch {
throw new Error(`Error parsing ${prop} for field ${field.fieldName}`);
}
}
}

if (field.fakerTemplate) {
data = faker.faker(field.fakerTemplate);
} else if (field.fieldValidate && field.fieldValidateRules.includes('pattern')) {
const re = field.createRandexp();
if (!re) {
data = faker.helpers.fake(field.fakerTemplate);
} else if (field.fieldValidate && field.fieldValidateRules?.includes('pattern')) {
const generated = field.generateFakeDataFromPattern!();
if (!generated) {
return undefined;
}
const generated = re.gen();
if (type === 'csv' || type === 'cypress') {
data = generated.replace(/"/g, '');
} else {
Expand All @@ -126,7 +136,7 @@ function generateFakeDataForField(this: CoreGenerator, field, faker, changelogDa
data = undefined;
}
} else if (field.fieldIsEnum) {
if (field.fieldValues.length !== 0) {
if (field.enumValues && field.enumValues.length > 0) {
const enumValues = field.enumValues;
data = enumValues[faker.number.int(enumValues.length - 1)].name;
} else {
Expand All @@ -139,14 +149,14 @@ function generateFakeDataForField(this: CoreGenerator, field, faker, changelogDa
// eslint-disable-next-line no-template-curly-in-string
} else if ([FLOAT, '${floatType}', DOUBLE, BIG_DECIMAL].includes(field.fieldType)) {
data = faker.number.float({
max: field.fieldValidateRulesMax ? parseInt(field.fieldValidateRulesMax, 10) : 32767,
min: field.fieldValidateRulesMin ? parseInt(field.fieldValidateRulesMin, 10) : 0,
max: field.fieldValidateRulesMax ?? 32767,
min: field.fieldValidateRulesMin ?? 0,
multipleOf: 0.01,
});
} else if ([INTEGER, LONG, DURATION].includes(field.fieldType)) {
data = faker.number.int({
max: field.fieldValidateRulesMax ? parseInt(field.fieldValidateRulesMax, 10) : 32767,
min: field.fieldValidateRulesMin ? parseInt(field.fieldValidateRulesMin, 10) : 0,
max: field.fieldValidateRulesMax ?? 32767,
min: field.fieldValidateRulesMin ?? 0,
});
} else if ([INSTANT, ZONED_DATE_TIME, LOCAL_DATE].includes(field.fieldType)) {
// Iso: YYYY-MM-DDTHH:mm:ss.sssZ
Expand All @@ -171,7 +181,7 @@ function generateFakeDataForField(this: CoreGenerator, field, faker, changelogDa
} else if (field.fieldTypeBinary && field.fieldTypeBlobContent === TEXT) {
data = '../fake-data/blob/hipster.txt';
} else if (field.fieldType === STRING) {
data = field.id ? faker.string.uuid() : faker.helpers.fake(fakeStringTemplateForFieldName(field.columnName));
data = field.id ? faker.string.uuid() : faker.helpers.fake(fakeStringTemplateForFieldName(field.columnName!));
} else if (field.fieldType === UUID) {
data = faker.string.uuid();
} else if (field.fieldType === BOOLEAN) {
Expand All @@ -185,17 +195,17 @@ function generateFakeDataForField(this: CoreGenerator, field, faker, changelogDa
}

// Validation rules
if (data !== undefined && field.fieldValidate === true) {
if (data !== undefined && field.fieldValidate === true && field.fieldValidateRules) {
const { fieldValidateRulesMinlength = 0, fieldValidateRulesMaxlength } = field;
// manage String max length
if (field.fieldValidateRules.includes(MAXLENGTH)) {
if (field.fieldValidateRules.includes(MAXLENGTH) && fieldValidateRulesMaxlength !== undefined) {
const maxlength = field.fieldValidateRulesMaxlength;
data = data.substring(0, maxlength);
}

// manage String min length
if (field.fieldValidateRules.includes(MINLENGTH)) {
const minlength = field.fieldValidateRulesMinlength;
data = data.length > minlength ? data : data + 'X'.repeat(minlength - data.length);
if (field.fieldValidateRules.includes(MINLENGTH) && fieldValidateRulesMinlength !== undefined) {
data = data.length > fieldValidateRulesMinlength ? data : data + 'X'.repeat(fieldValidateRulesMinlength - data.length);
}

// test if generated data is still compatible with the regexp as we potentially modify it with min/maxLength
Expand All @@ -207,7 +217,7 @@ function generateFakeDataForField(this: CoreGenerator, field, faker, changelogDa
// eslint-disable-next-line no-template-curly-in-string
if (type === 'ts' && ![BOOLEAN, INTEGER, LONG, FLOAT, '${floatType}', DOUBLE, BIG_DECIMAL].includes(field.fieldType)) {
data = `'${typeof data === 'string' ? data.replace(/\\/g, '\\\\').replace(/'/g, "\\'") : data}'`;
} else if (type === 'csv' && field.fieldValidate && field.fieldValidateRules.includes(PATTERN)) {
} else if (type === 'csv' && field.fieldValidate && field.fieldValidateRules?.includes(PATTERN)) {
data = `"${typeof data === 'string' ? data.replace(/"/g, '\\"') : data}"`;
}
}
Expand Down Expand Up @@ -315,6 +325,21 @@ function prepareCommonFieldForTemplates(entityWithConfig: Entity, field: Field,
}

const faker = entityWithConfig.faker;
field.generateFakeDataFromPattern = () => {
// check if regex is valid. If not, issue warning and we skip fake data generation.
try {
new RegExp(field.fieldValidateRulesPattern!);
} catch {
generator.log.warn(`${field.fieldName} pattern is not valid: ${field.fieldValidateRulesPattern}. Skipping generating fake data. `);
return undefined;
}
const re = faker.createRandexp(field.fieldValidateRulesPattern!);
if (!re) {
generator.log.warn(`Error creating generator for pattern ${field.fieldValidateRulesPattern}`);
}
return re?.gen();
};

field.createRandexp = () => {
// check if regex is valid. If not, issue warning and we skip fake data generation.
try {
Expand All @@ -323,7 +348,7 @@ function prepareCommonFieldForTemplates(entityWithConfig: Entity, field: Field,
generator.log.warn(`${field.fieldName} pattern is not valid: ${field.fieldValidateRulesPattern}. Skipping generating fake data. `);
return undefined;
}
const re = faker.createRandexp(field.fieldValidateRulesPattern);
const re = faker.createRandexp(field.fieldValidateRulesPattern!);
if (!re) {
generator.log.warn(`Error creating generator for pattern ${field.fieldValidateRulesPattern}`);
}
Expand Down
2 changes: 1 addition & 1 deletion generators/base/support/faker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class RandexpWithFaker extends Randexp {
}
}

class FakerWithRandexp extends Faker {
export class FakerWithRandexp extends Faker {
createRandexp(regexp: string | RegExp, flags?: string) {
return new RandexpWithFaker(regexp, flags, this);
}
Expand Down
15 changes: 10 additions & 5 deletions generators/base/support/timestamp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,16 @@ export function parseChangelog(changelogDate: string): Date {
if (changelogDate.length !== 14) {
throw new Error(`changelogDate ${changelogDate} is not a valid changelogDate.`);
}
const formattedDate = `${changelogDate.substring(0, 4)}-${changelogDate.substring(4, 6)}-${changelogDate.substring(
6,
8,
)}T${changelogDate.substring(8, 10)}:${changelogDate.substring(10, 12)}:${changelogDate.substring(12, 14)}+00:00`;
return new Date(Date.parse(formattedDate));
const zeroFallback = (val: string, fallback: string) => (/^0+$/.test(val) ? fallback : val);
const year = zeroFallback(changelogDate.substring(0, 4), '2024');
const month = zeroFallback(changelogDate.substring(4, 6), '01');
const day = zeroFallback(changelogDate.substring(6, 8), '01');
const formattedDate = `${year}-${month}-${day}T${changelogDate.substring(8, 10)}:${changelogDate.substring(10, 12)}:${changelogDate.substring(12, 14)}+00:00`;
const parsedTimestamp = Date.parse(formattedDate);
if (isNaN(parsedTimestamp)) {
throw new Error(`changelogDate ${changelogDate} is not a valid date.`);
}
return new Date(parsedTimestamp);
}

/**
Expand Down
12 changes: 9 additions & 3 deletions generators/bootstrap-application-base/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { PaginationTypes } from '../../lib/jhipster/entity-options.js';
import { LOGIN_REGEX, LOGIN_REGEX_JS } from '../generator-constants.js';
import { getDatabaseTypeData } from '../server/support/database.js';
import type BaseApplicationGenerator from '../base-application/generator.js';
import { formatDateForChangelog } from '../base/support/timestamp.js';

const { CASSANDRA } = databaseTypes;
const { OAUTH2 } = authenticationTypes;
Expand Down Expand Up @@ -83,12 +84,13 @@ export function createUserEntity(this: BaseApplicationGenerator, customUserData
}
}

const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now());
const cassandraOrNoDatabase = application.databaseTypeNo || application.databaseTypeCassandra;
// Create entity definition for built-in entity to make easier to deal with relationships.
const user = {
name: 'User',
builtIn: true,
changelogDate: '00000000000100',
changelogDate: formatDateForChangelog(creationTimestamp),
entityTableName: `${application.jhiTablePrefix}_user`,
relationships: [],
fields: userEntityDefinition ? userEntityDefinition.fields || [] : [],
Expand Down Expand Up @@ -206,12 +208,14 @@ export function createUserManagementEntity(this: BaseApplicationGenerator, custo
}
}

const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now());
creationTimestamp.setMinutes(creationTimestamp.getMinutes() + 1);
const userManagement = {
...user,
name: 'UserManagement',
skipClient: true,
skipServer: true,
changelogDate: '00000000000150',
changelogDate: formatDateForChangelog(creationTimestamp),
clientRootFolder: 'admin',
entityAngularName: 'UserManagement',
entityApiUrl: 'admin/users',
Expand Down Expand Up @@ -248,13 +252,15 @@ export function createAuthorityEntity(this: BaseApplicationGenerator, customAuth
}
}

const creationTimestamp = new Date(this.jhipsterConfig.creationTimestamp ?? Date.now());
creationTimestamp.setMinutes(creationTimestamp.getMinutes() + 2);
// Create entity definition for built-in entity to make easier to deal with relationships.
const authorityEntity = {
name: authorityEntityName,
entitySuffix: '',
clientRootFolder: 'admin',
builtIn: true,
changelogDate: '00000000000200',
changelogDate: formatDateForChangelog(creationTimestamp),
adminEntity: true,
entityTableName: `${application.jhiTablePrefix}_authority`,
relationships: [],
Expand Down
10 changes: 10 additions & 0 deletions generators/bootstrap-application/generator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"id": true,
"javaFieldType": "UUID",
"javaValueGenerator": "UUID.randomUUID()",
Expand Down Expand Up @@ -417,6 +418,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": true,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"javaFieldType": "String",
"javaValueGenerator": "UUID.randomUUID().toString()",
"javaValueSample1": ""login1"",
Expand Down Expand Up @@ -503,6 +505,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"javaFieldType": "String",
"javaValueGenerator": "UUID.randomUUID().toString()",
"javaValueSample1": ""firstName1"",
Expand Down Expand Up @@ -588,6 +591,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"javaFieldType": "String",
"javaValueGenerator": "UUID.randomUUID().toString()",
"javaValueSample1": ""lastName1"",
Expand Down Expand Up @@ -677,6 +681,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": true,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"javaFieldType": "String",
"javaValueGenerator": "UUID.randomUUID().toString()",
"javaValueSample1": ""email1"",
Expand Down Expand Up @@ -763,6 +768,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"javaFieldType": "String",
"javaValueGenerator": "UUID.randomUUID().toString()",
"javaValueSample1": ""imageUrl1"",
Expand Down Expand Up @@ -845,6 +851,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"javaFieldType": "Boolean",
"liquibaseDefaultValueAttributeName": undefined,
"liquibaseDefaultValueAttributeValue": undefined,
Expand Down Expand Up @@ -926,6 +933,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"javaFieldType": "String",
"javaValueGenerator": "UUID.randomUUID().toString()",
"javaValueSample1": ""langKey1"",
Expand Down Expand Up @@ -1213,6 +1221,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"id": true,
"javaFieldType": "UUID",
"javaValueGenerator": "UUID.randomUUID()",
Expand Down Expand Up @@ -1556,6 +1565,7 @@ describe(`generator - ${generator}`, () => {
"fieldValidationUnique": false,
"fieldWithContentType": false,
"generateFakeData": Any<Function>,
"generateFakeDataFromPattern": [Function],
"id": true,
"javaFieldType": "UUID",
"javaValueGenerator": "UUID.randomUUID()",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,24 +329,25 @@ if (field.fieldTypeString || field.blobContentTypeText) {
// Generate Strings, using pattern
try {
const patternRegExp = new RegExp(field.fieldValidateRulesPattern);
const randExp = field.createRandexp();
// set infinite repetitions max range
if (!patternRegExp.test(sampleTextString.replace(/\\"/g, '"').replace(/\\\\/g, '\\'))) {
sampleTextString = randExp.gen().replace(/\\/g, '\\\\').replace(/"/g, '\\"');
const value = field.generateFakeDataFromPattern();
sampleTextString = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
if (!patternRegExp.test(updatedTextString.replace(/\\"/g, '"').replace(/\\\\/g, '\\'))) {
updatedTextString = randExp.gen().replace(/\\/g, '\\\\').replace(/"/g, '\\"');
const value = field.generateFakeDataFromPattern();
updatedTextString = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
}
} catch (error) {
log(this.chalkRed('Error generating test value for entity "' + entityClass +
this.log.warn('Error generating test value for entity "' + entityClass +
'" field "' + field.fieldName + '" with pattern "' + field.fieldValidateRulesPattern +
'", generating default values for this field. Detailed error message: "' + error.message + '".'));
'", generating default values for this field. Detailed error message: "' + error.message + '".');
}
if (sampleTextString === updatedTextString) {
updatedTextString = updatedTextString + "B";
log(this.chalkRed('Randomly generated first and second test values for entity "' + entityClass +
this.log.warn('Randomly generated first and second test values for entity "' + entityClass +
'" field "' + field.fieldName + '" with pattern "' + field.fieldValidateRulesPattern +
'" in file "' + entityClass + 'ResourceIT" where equal, added symbol "B" to second value.'));
'" in file "' + entityClass + 'ResourceIT" where equal, added symbol "B" to second value.');
}
} _%>

Expand Down
3 changes: 2 additions & 1 deletion lib/types/application/entity.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { SpringEntity } from '../../../generators/server/types.js';
import type { Field as BaseField } from '../base/field.js';
import type { Relationship as BaseRelationship } from '../base/relationship.js';
import type { FieldType } from '../../application/field-types.ts';
import type { FakerWithRandexp } from '../../../generators/base/support/faker.ts';
import type { Field } from './field.js';
import type { Relationship } from './relationship.js';

Expand Down Expand Up @@ -147,5 +148,5 @@ export interface Entity<F extends BaseField = Field, R extends BaseRelationship

propertyJavaFilteredType?: string;

faker: any;
faker: FakerWithRandexp;
}
Loading

0 comments on commit 547c270

Please sign in to comment.