Skip to content

Commit

Permalink
feat: example generator v2
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz.klejszta committed Jul 1, 2022
1 parent 2564054 commit fb642a3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 32 deletions.
2 changes: 1 addition & 1 deletion packages/falso/src/lib/abbreviation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { data } from './abbreviation.json';
* @example
*
* randAbbreviation({ length: 10 })
*
*
* @automaticallyGeneratedExamples
* @example
* SCSI
Expand Down
6 changes: 6 additions & 0 deletions packages/falso/src/lib/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ export interface AccountOptions extends FakeOptions {
*
* randAccount({ length: 10 })
*
* @automaticallyGeneratedExamples
* @example
* 752923821
* 334864247
* 556647372
*/

export function randAccount<Options extends AccountOptions = never>(
options?: Options
) {
Expand Down
114 changes: 83 additions & 31 deletions scripts/example-generator.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,91 @@
const fs = require('fs');

const [libDirectoryPath] = process.argv.slice(2);
const [directoryPath] = process.argv.slice(2);
const GENERATE_INDICATOR = "@automaticallyGeneratedExamples"
// https://regex101.com/r/rlqGTA/1
const regexp = new RegExp(`(${GENERATE_INDICATOR}).*\\/`,"gs");
const errors = [];
// https://regex101.com/r/qxpfyX/1
const regexp = new RegExp(`(${GENERATE_INDICATOR}).*[*]\\/`,"gs");

console.log('Generating examples...')
const filenames = fs
.readdirSync(libDirectoryPath)
.filter((jsonFilename, index, array) => jsonFilename.includes(".json") && array.find(tsFilename => tsFilename.replace('ts','json') === jsonFilename))

filenames.forEach(filename => {
try {
const tsFilepath = `${libDirectoryPath}${filename.replace('json','ts')}`
const tsFileContent = fs.readFileSync(tsFilepath).toString();
if(!tsFileContent.includes(GENERATE_INDICATOR)) {
console.log(`file is missing '${GENERATE_INDICATOR}' and will be ignored ${filename.replace('json','ts')}`);
return;
}
const jsonFilepath = `${libDirectoryPath}${filename}`
const jsonFileContent = JSON.parse(fs.readFileSync(jsonFilepath));
if(jsonFileContent.data === undefined) {
throw Error(`missing data field in file: ${filename}`);
}
if(!(jsonFileContent.data instanceof Array)) {
throw Error(`invalid data field, must be an array: ${filename}`);
}
fs.writeFileSync(tsFilepath, tsFileContent.replace(regexp, `${GENERATE_INDICATOR}\n * @example\n${jsonFileContent.data.slice(0,3).map(example => ` * ${example}\n`).join('')} */`));
} catch(error) {
errors.push({filename, error});

const ERRORS = {
missingIndicatorProperty: `'${GENERATE_INDICATOR}' is missing in jsdoc`,
tsFileDoesNotExists: `corresponding ts file does not exists`,
missingJsonDataField: `'json.data' field is missing`,
jsonDataFieldValueMustBeArray: "'json.data' field value is not array",
jsonDataMustNotBeEmptyArray: "'json.data' field value is empty array",
tsFileDoesNotContainRandFunction: "ts file must contain function which name starts with 'rand'"
};

const getFileContent = (filepath) => {
try {
return fs.readFileSync(filepath).toString()
} catch(error) {
if(error.message.startsWith("ENOENT")) {
return null;
}
});
throw error;
}
};

if(errors.length > 0) {
console.log(errors);
const getExamplesFromJson = (json) => {
if(json.data === undefined) {
return [null, ERRORS.missingJsonDataField];
}
if(!(json.data instanceof Array)) {
return [null, ERRORS.jsonDataFieldValueMustBeArray]
}
const examples = json.data.slice(0,3);
if(examples.length === 0) {
return [null, ERRORS.jsonDataMustNotBeEmptyArray]
}
console.log(`Generating examples finished ${filenames.length - errors.length}/${filenames.length}`);
return [examples, null];
};


const getExamplesFromTs = (tsContent) => {
const [,randFunction] = Object.entries(tsContent).find(([key]) => key.startsWith('rand'));
if(randFunction === undefined || typeof randFunction !== 'function') {
return [null, ERRORS.tsFileDoesNotContainRandFunction]
}
return [Array.from({ length: 3 }, randFunction), null]
};

const directoryFilenames = fs.readdirSync(directoryPath)
.map(filename => filename.split('.')[0])
.filter((filename, index, filenames) => filenames.indexOf(filename) === index);


const errors = directoryFilenames.reduce((acc, filename) => {
const basePath = `${directoryPath}${filename}`
const filePath = {
ts: `${basePath}.ts`,
json: `${basePath}.json`,
};
const tsFileContent = getFileContent(filePath.ts);
if(tsFileContent === null) {
acc[ERRORS.tsFileDoesNotExists].push(filename);
return acc;
}
if(!tsFileContent.includes(GENERATE_INDICATOR)) {
acc[ERRORS.missingIndicatorProperty].push(filename);
return acc;
}
const jsonFileContent = getFileContent(filePath.json);
const [examples, error] = jsonFileContent === null
? getExamplesFromTs(require(`../${basePath}`))
: getExamplesFromJson(JSON.parse(jsonFileContent));
if(error !== null) {
acc[error].push(filename);
return acc;
}

const replacement = `${GENERATE_INDICATOR}\n * @example\n${examples.map(example => ` * ${example}\n`).join('')} */`
fs.writeFileSync(`${basePath}.ts`, tsFileContent.replace(regexp, replacement));
return acc;
}, Object.values(ERRORS).reduce((acc, errorText) => ({...acc, [errorText]: []}), {}));

console.log(Object.entries(errors).reduce((acc, [key, value]) => `${acc}--> ${value.length} - ${key}:\n [${value.join(', ')}]\n` ,'<<-- Generator Errors -->>\n'));
console.log(`<<-- Generator Result -->>
--> generated: ${directoryFilenames.length - Object.values(errors).flat().length}
--> files: ${directoryFilenames.length}`);

0 comments on commit fb642a3

Please sign in to comment.