|
1 | 1 | const fs = require('fs'); |
2 | 2 |
|
3 | | -const [libDirectoryPath] = process.argv.slice(2); |
| 3 | +const [directoryPath] = process.argv.slice(2); |
4 | 4 | const GENERATE_INDICATOR = "@automaticallyGeneratedExamples" |
5 | | -// https://regex101.com/r/rlqGTA/1 |
6 | | -const regexp = new RegExp(`(${GENERATE_INDICATOR}).*\\/`,"gs"); |
7 | | -const errors = []; |
| 5 | +// https://regex101.com/r/qxpfyX/1 |
| 6 | +const regexp = new RegExp(`(${GENERATE_INDICATOR}).*[*]\\/`,"gs"); |
8 | 7 |
|
9 | 8 | console.log('Generating examples...') |
10 | | -const filenames = fs |
11 | | -.readdirSync(libDirectoryPath) |
12 | | -.filter((jsonFilename, index, array) => jsonFilename.includes(".json") && array.find(tsFilename => tsFilename.replace('ts','json') === jsonFilename)) |
13 | | - |
14 | | -filenames.forEach(filename => { |
15 | | - try { |
16 | | - const tsFilepath = `${libDirectoryPath}${filename.replace('json','ts')}` |
17 | | - const tsFileContent = fs.readFileSync(tsFilepath).toString(); |
18 | | - if(!tsFileContent.includes(GENERATE_INDICATOR)) { |
19 | | - console.log(`file is missing '${GENERATE_INDICATOR}' and will be ignored ${filename.replace('json','ts')}`); |
20 | | - return; |
21 | | - } |
22 | | - const jsonFilepath = `${libDirectoryPath}${filename}` |
23 | | - const jsonFileContent = JSON.parse(fs.readFileSync(jsonFilepath)); |
24 | | - if(jsonFileContent.data === undefined) { |
25 | | - throw Error(`missing data field in file: ${filename}`); |
26 | | - } |
27 | | - if(!(jsonFileContent.data instanceof Array)) { |
28 | | - throw Error(`invalid data field, must be an array: ${filename}`); |
29 | | - } |
30 | | - fs.writeFileSync(tsFilepath, tsFileContent.replace(regexp, `${GENERATE_INDICATOR}\n * @example\n${jsonFileContent.data.slice(0,3).map(example => ` * ${example}\n`).join('')} */`)); |
31 | | - } catch(error) { |
32 | | - errors.push({filename, error}); |
| 9 | + |
| 10 | +const ERRORS = { |
| 11 | + missingIndicatorProperty: `'${GENERATE_INDICATOR}' is missing in jsdoc`, |
| 12 | + tsFileDoesNotExists: `corresponding ts file does not exists`, |
| 13 | + missingJsonDataField: `'json.data' field is missing`, |
| 14 | + jsonDataFieldValueMustBeArray: "'json.data' field value is not array", |
| 15 | + jsonDataMustNotBeEmptyArray: "'json.data' field value is empty array", |
| 16 | + tsFileDoesNotContainRandFunction: "ts file must contain function which name starts with 'rand'" |
| 17 | +}; |
| 18 | + |
| 19 | +const getFileContent = (filepath) => { |
| 20 | + try { |
| 21 | + return fs.readFileSync(filepath).toString() |
| 22 | + } catch(error) { |
| 23 | + if(error.message.startsWith("ENOENT")) { |
| 24 | + return null; |
33 | 25 | } |
34 | | - }); |
| 26 | + throw error; |
| 27 | + } |
| 28 | +}; |
35 | 29 |
|
36 | | - if(errors.length > 0) { |
37 | | - console.log(errors); |
| 30 | +const getExamplesFromJson = (json) => { |
| 31 | + if(json.data === undefined) { |
| 32 | + return [null, ERRORS.missingJsonDataField]; |
| 33 | + } |
| 34 | + if(!(json.data instanceof Array)) { |
| 35 | + return [null, ERRORS.jsonDataFieldValueMustBeArray] |
| 36 | + } |
| 37 | + const examples = json.data.slice(0,3); |
| 38 | + if(examples.length === 0) { |
| 39 | + return [null, ERRORS.jsonDataMustNotBeEmptyArray] |
38 | 40 | } |
39 | | - console.log(`Generating examples finished ${filenames.length - errors.length}/${filenames.length}`); |
| 41 | + return [examples, null]; |
| 42 | +}; |
| 43 | + |
| 44 | + |
| 45 | +const getExamplesFromTs = (tsContent) => { |
| 46 | + const [,randFunction] = Object.entries(tsContent).find(([key]) => key.startsWith('rand')); |
| 47 | + if(randFunction === undefined || typeof randFunction !== 'function') { |
| 48 | + return [null, ERRORS.tsFileDoesNotContainRandFunction] |
| 49 | + } |
| 50 | + return [Array.from({ length: 3 }, randFunction), null] |
| 51 | +}; |
| 52 | + |
| 53 | +const directoryFilenames = fs.readdirSync(directoryPath) |
| 54 | + .map(filename => filename.split('.')[0]) |
| 55 | + .filter((filename, index, filenames) => filenames.indexOf(filename) === index); |
| 56 | + |
| 57 | + |
| 58 | + const errors = directoryFilenames.reduce((acc, filename) => { |
| 59 | + const basePath = `${directoryPath}${filename}` |
| 60 | + const filePath = { |
| 61 | + ts: `${basePath}.ts`, |
| 62 | + json: `${basePath}.json`, |
| 63 | + }; |
| 64 | + const tsFileContent = getFileContent(filePath.ts); |
| 65 | + if(tsFileContent === null) { |
| 66 | + acc[ERRORS.tsFileDoesNotExists].push(filename); |
| 67 | + return acc; |
| 68 | + } |
| 69 | + if(!tsFileContent.includes(GENERATE_INDICATOR)) { |
| 70 | + acc[ERRORS.missingIndicatorProperty].push(filename); |
| 71 | + return acc; |
| 72 | + } |
| 73 | + const jsonFileContent = getFileContent(filePath.json); |
| 74 | + const [examples, error] = jsonFileContent === null |
| 75 | + ? getExamplesFromTs(require(`../${basePath}`)) |
| 76 | + : getExamplesFromJson(JSON.parse(jsonFileContent)); |
| 77 | + if(error !== null) { |
| 78 | + acc[error].push(filename); |
| 79 | + return acc; |
| 80 | + } |
| 81 | + |
| 82 | + const replacement = `${GENERATE_INDICATOR}\n * @example\n${examples.map(example => ` * ${example}\n`).join('')} */` |
| 83 | + fs.writeFileSync(`${basePath}.ts`, tsFileContent.replace(regexp, replacement)); |
| 84 | + return acc; |
| 85 | +}, Object.values(ERRORS).reduce((acc, errorText) => ({...acc, [errorText]: []}), {})); |
| 86 | + |
| 87 | +console.log(Object.entries(errors).reduce((acc, [key, value]) => `${acc}--> ${value.length} - ${key}:\n [${value.join(', ')}]\n` ,'<<-- Generator Errors -->>\n')); |
| 88 | +console.log(`<<-- Generator Result -->> |
| 89 | +--> generated: ${directoryFilenames.length - Object.values(errors).flat().length} |
| 90 | +--> files: ${directoryFilenames.length}`); |
| 91 | + |
0 commit comments