Skip to content

Commit 7f6d579

Browse files
devvaannshabose
authored andcommitted
fix: file modified issue
1 parent ca43858 commit 7f6d579

File tree

1 file changed

+130
-42
lines changed

1 file changed

+130
-42
lines changed

build/api-docs-generator.js

Lines changed: 130 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,49 @@ const fs = require('fs').promises;
22
const path = require('path');
33
const glob = require('glob');
44
const util = require('util');
5+
const crypto = require('crypto');
56
const exec = util.promisify(require('child_process').exec);
67

8+
// Promisify the glob function to enable async/await usage
9+
const globPromise = util.promisify(glob);
10+
11+
// Constants
712
const SRC_DIR = './src';
813
const BUILD_DIR = './build';
914
const TEMP_DIR = path.join(BUILD_DIR, 'temp');
1015
const MD_FILES_DIR = path.join('./docs', 'API-Reference');
16+
const TEMP_CHECK_DIR = path.join(BUILD_DIR, 'check_copy');
17+
const BATCH_SIZE = 12;
18+
19+
20+
/**
21+
* Create directory
22+
* @param {string} dirPath - The path where the directory will be created
23+
*/
24+
async function createDir(dirPath) {
25+
await fs.mkdir(dirPath, { recursive: true });
26+
}
27+
28+
29+
/**
30+
* Remove directory
31+
* @param {string} dirPath - The path to the directory to remove
32+
*/
33+
async function removeDir(dirPath) {
34+
await fs.rm(dirPath, { recursive: true, force: true });
35+
}
1136

12-
const globPromise = util.promisify(glob);
1337

1438
/**
1539
* Responsible to get the JS Files that are to be included in API DOCS
16-
* @returns {Promise<string[]>} Promise resolving to list of JS Files for API Docs
40+
* @returns {Promise<string[]>} Promise resolving,list of JS Files for API Docs
1741
*/
1842
async function getJsFiles() {
1943
const allJsFiles = await globPromise(`${SRC_DIR}/**/*.js`);
2044
const requiredJSfiles = [];
2145

2246
await Promise.all(allJsFiles.map(async (file) => {
47+
// Check if the path points to a valid file
2348
const stats = await fs.stat(file);
2449
if (stats.isFile()) {
2550
const content = await fs.readFile(file, 'utf-8');
@@ -32,32 +57,18 @@ async function getJsFiles() {
3257
return requiredJSfiles;
3358
}
3459

35-
/**
36-
* Creates a directory
37-
* @param {string} dirPath creates dir at the given path
38-
*/
39-
async function createDir(dirPath) {
40-
await fs.mkdir(dirPath, { recursive: true });
41-
}
42-
43-
/**
44-
* Deletes a directory
45-
* @param {string} dirPath deletes dir from the given path
46-
*/
47-
async function removeDir(dirPath) {
48-
await fs.rm(dirPath, { recursive: true, force: true });
49-
}
5060

5161
/**
5262
* Adjusts JavaScript content for compatibility with jsdoc-to-markdown
5363
* @param {string} content The content to be modified
54-
* @param {string} fileName To replace the define block with this name
5564
* @returns {string} Updated content
5665
*/
57-
function modifyJs(content, fileName) {
66+
function modifyJs(content) {
5867
if (content.includes('\n(function () {')) {
5968
content = content.replace(/\(function \(\) \{/, '');
69+
6070
if (content.trim().endsWith('}());')) {
71+
// Remove trailing IIFE closing
6172
content = content.trim().slice(0, -5);
6273
}
6374

@@ -67,35 +78,42 @@ function modifyJs(content, fileName) {
6778
bracketCount++;
6879
} else if (content[indx] === '}') {
6980
bracketCount--;
70-
if (bracketCount < 0) {
71-
let tempIndx = indx;
72-
while (content[indx] && content[indx] !== ')') {
73-
indx--;
74-
}
75-
content = content.slice(0, indx) + content.slice(tempIndx + 1);
76-
bracketCount++;
77-
break;
81+
}
82+
83+
// Remove any unmatched closing brackets
84+
if (bracketCount < 0) {
85+
let tempIndx = indx;
86+
while (content[indx] && content[indx] !== ')') {
87+
indx--;
7888
}
89+
content = content.slice(0, indx) + content.slice(tempIndx + 1);
90+
bracketCount++;
91+
break;
7992
}
8093
}
8194
} else if (content.includes('define(function')) {
8295
content = content.replace(/define\(function\s*\([^)]*\)\s*{/, '');
8396
if (content.trim().endsWith('});')) {
97+
// Remove AMD-style wrapper
8498
content = content.trim().slice(0, -3);
8599
}
86100
}
87101
return content;
88102
}
89103

104+
90105
/**
91-
* Modifies markdown content for compatibility with docusaurus
92-
* @param {string} content markdown file content
93-
* @param {string} relativePath Relative path of the file from MD_FILES_DIR
94-
* @returns {string} updated markdown file content
106+
* Adjusts markdown content for compatibility with Docusaurus
107+
* Adds import examples and fixes formatting issues
108+
* @param {string} content - Original markdown content
109+
* @param {string} relativePath - Relative path to the JS file
110+
* @returns {string} - Modified markdown content
95111
*/
96112
function modifyMarkdown(content, relativePath) {
97113
const anchorIndex = content.indexOf('<a name');
98114
if (anchorIndex !== -1) {
115+
// Remove every content that appears before anchor tag
116+
// as non-required content might get generated
99117
content = content.slice(anchorIndex);
100118
}
101119

@@ -104,13 +122,47 @@ function modifyMarkdown(content, relativePath) {
104122
path.basename(relativePath, '.md')
105123
).replace(/\\/g, '/');
106124

107-
const importStatement = '### Import :\n' +
108-
`\`\`\`js\nconst ${path.basename(relativePath, '.md')} = ` +
125+
const importStatement = `### Import :\n` +
126+
`\`\`\`js\n` +
127+
`const ${path.basename(relativePath, '.md')} = ` +
109128
`brackets.getModule("${modulePath}")\n\`\`\`\n\n`;
110129

130+
// brackets~getModule is wrong
131+
// brackets.getModule
111132
return importStatement + content.replace(/~/g, '.');
112133
}
113134

135+
136+
/**
137+
* Normalizes line endings to LF (\n)
138+
* to ensure consistent comparisons between files
139+
* @param {string} content - Content with potentially mixed line endings
140+
* @returns {string} - Content with normalized line endings
141+
*/
142+
function normalizeLineEndings(content) {
143+
return content.replace(/\r\n|\r/g, '\n');
144+
}
145+
146+
147+
/**
148+
* Compare two files based on their MD5 hash values
149+
* @param {string} file1 - Path to the first file
150+
* @param {string} file2 - Path to the second file
151+
* @returns {Promise<boolean>} - True if files are different, false otherwise
152+
*/
153+
async function areFilesDifferent(file1, file2) {
154+
const [content1, content2] = await Promise.all([
155+
fs.readFile(file1, 'utf-8').then(normalizeLineEndings),
156+
fs.readFile(file2, 'utf-8').then(normalizeLineEndings)
157+
]);
158+
159+
const hash1 = crypto.createHash('md5').update(content1).digest('hex');
160+
const hash2 = crypto.createHash('md5').update(content2).digest('hex');
161+
162+
return hash1 !== hash2;
163+
}
164+
165+
114166
/**
115167
* Generates markdown documentation for a given JavaScript file
116168
* @param {string} file Path to the JavaScript file
@@ -127,15 +179,50 @@ async function generateMarkdown(file, relativePath) {
127179
await createDir(outputDir);
128180

129181
const outputFileName = path.join(outputDir, `${fileName}.md`);
130-
await exec(`npx jsdoc-to-markdown ${file} > ${outputFileName}`);
182+
const tempOutputFileName = path.join(
183+
TEMP_CHECK_DIR, `${fileName}_temp.md`
184+
);
185+
186+
await createDir(TEMP_CHECK_DIR);
187+
188+
// Generate markdown to a temporary file
189+
await exec(`npx jsdoc-to-markdown ${file} > ${tempOutputFileName}`);
190+
191+
let markdownContent = await fs.readFile(tempOutputFileName, 'utf-8');
192+
const updatedMarkdownContent = modifyMarkdown(
193+
markdownContent, path.join(relativePath, fileName)
194+
);
195+
196+
await fs.writeFile(tempOutputFileName, updatedMarkdownContent, 'utf-8');
197+
198+
const fileExists = await fs.access(outputFileName).then(() => true).catch(
199+
() => false
200+
);
201+
202+
const shouldUpdate = !fileExists || await areFilesDifferent(
203+
outputFileName, tempOutputFileName
204+
);
131205

132-
const markdownContent = await fs.readFile(outputFileName, 'utf-8');
133-
const updatedMarkdownContent = modifyMarkdown(markdownContent, path.join(relativePath, fileName));
134-
await fs.writeFile(outputFileName, updatedMarkdownContent, 'utf-8');
206+
if (shouldUpdate) {
207+
await fs.rename(tempOutputFileName, outputFileName);
208+
console.log(`Updated ${outputFileName}`);
209+
} else {
210+
await fs.unlink(tempOutputFileName);
211+
console.log(`No changes in ${outputFileName}`);
212+
}
135213
}
136214

215+
216+
/**
217+
* Cleans up temp directories
218+
*/
219+
async function cleanupTempDir() {
220+
await removeDir(TEMP_CHECK_DIR);
221+
}
222+
223+
137224
/**
138-
* Handles the execution and control flow of the program
225+
* Driver function
139226
*/
140227
async function driver() {
141228
try {
@@ -146,12 +233,12 @@ async function driver() {
146233
await createDir(TEMP_DIR);
147234
await createDir(MD_FILES_DIR);
148235

149-
// Process files in batches to avoid overwhelming the system
150-
const BATCH_SIZE = 12;
151236
for (let i = 0; i < jsFiles.length; i += BATCH_SIZE) {
152237
const batch = jsFiles.slice(i, i + BATCH_SIZE);
153238
await Promise.all(batch.map(async (file) => {
154-
const relativePath = path.relative(SRC_DIR, path.dirname(file));
239+
const relativePath = path.relative(
240+
SRC_DIR, path.dirname(file)
241+
);
155242
const tempDirPath = path.join(TEMP_DIR, relativePath);
156243
await createDir(tempDirPath);
157244

@@ -165,11 +252,12 @@ async function driver() {
165252
}
166253

167254
await removeDir(TEMP_DIR);
255+
await cleanupTempDir();
168256
console.log("All files processed successfully!");
169257
} catch (error) {
170258
console.error("An error occurred:", error);
171-
// Cleanup temp directory in case of error
172259
await removeDir(TEMP_DIR).catch(() => { });
260+
await cleanupTempDir().catch(() => { });
173261
}
174262
}
175263

0 commit comments

Comments
 (0)