Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolve faker 9 breaking changes #27368

Merged
merged 7 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading