mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			184 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| const path = require("path");
 | |
| const fs = require("fs");
 | |
| 
 | |
| // When --write is set, files will be written in place
 | |
| // Elsewise it only prints outdated files
 | |
| const doWrite = process.argv.includes("--write");
 | |
| 
 | |
| const allFiles = new Set();
 | |
| const findFiles = p => {
 | |
| 	const s = fs.statSync(p);
 | |
| 	if (s.isDirectory()) {
 | |
| 		for (const name of fs.readdirSync(p)) {
 | |
| 			if (name.startsWith(".")) continue;
 | |
| 			findFiles(path.join(p, name));
 | |
| 		}
 | |
| 	} else if (s.isFile()) {
 | |
| 		allFiles.add(p);
 | |
| 	}
 | |
| };
 | |
| findFiles(path.resolve(__dirname, "../lib"));
 | |
| 
 | |
| let canUpdateWithWrite = false;
 | |
| 
 | |
| const sortImport = (a, b) => {
 | |
| 	if (!a.key.startsWith(".") && b.key.startsWith(".")) return -1;
 | |
| 	if (a.key.startsWith(".") && !b.key.startsWith(".")) return 1;
 | |
| 	if (a.key < b.key) return -1;
 | |
| 	if (a.key > b.key) return 1;
 | |
| 	return 0;
 | |
| };
 | |
| 
 | |
| const execToArray = (content, regexp) => {
 | |
| 	const items = [];
 | |
| 	let match = regexp.exec(content);
 | |
| 	while (match) {
 | |
| 		items.push({
 | |
| 			content: match[0],
 | |
| 			key: match[1] + match[2]
 | |
| 		});
 | |
| 		match = regexp.exec(content);
 | |
| 	}
 | |
| 	return items;
 | |
| };
 | |
| 
 | |
| const schema = [
 | |
| 	{
 | |
| 		title: "license comment",
 | |
| 		regexp: /\/\*\n\s*MIT License http:\/\/www\.opensource\.org\/licenses\/mit-license\.php\n\s*(?:(Authors? .+)\n)?\s*\*\/\n/g,
 | |
| 		updateMessage: "update the license comment",
 | |
| 		update(content, author) {
 | |
| 			return (
 | |
| 				[
 | |
| 					"/*",
 | |
| 					"\tMIT License http://www.opensource.org/licenses/mit-license.php",
 | |
| 					author && `\t${author}`,
 | |
| 					"*/"
 | |
| 				]
 | |
| 					.filter(Boolean)
 | |
| 					.join("\n") + "\n"
 | |
| 			);
 | |
| 		}
 | |
| 	},
 | |
| 	{
 | |
| 		title: "new line after license comment",
 | |
| 		regexp: /\n?/g,
 | |
| 		updateMessage: "insert a new line after the license comment",
 | |
| 		update() {
 | |
| 			return "\n";
 | |
| 		}
 | |
| 	},
 | |
| 	{
 | |
| 		title: "strict mode",
 | |
| 		regexp: /"use strict";\n/g
 | |
| 	},
 | |
| 	{
 | |
| 		title: "new line after strict mode",
 | |
| 		regexp: /\n?/g,
 | |
| 		updateMessage: 'insert a new line after "use strict"',
 | |
| 		update() {
 | |
| 			return "\n";
 | |
| 		}
 | |
| 	},
 | |
| 	{
 | |
| 		title: "imports",
 | |
| 		regexp: /(const (\{\s+\w+(,\s+\w+)*\s+\}|\w+) = (\/\*\* @type \{TODO\} \*\/\s\()?require\("[^"]+"\)\)?(\.\w+)*;\n)+\n/g,
 | |
| 		updateMessage: "sort imports alphabetically",
 | |
| 		update(content) {
 | |
| 			const items = execToArray(
 | |
| 				content,
 | |
| 				/const (?:\{\s+\w+(?:,\s+\w+)*\s+\}|\w+) = (?:\/\*\* @type \{TODO\} \*\/\s\()?require\("([^"]+)"\)\)?((?:\.\w+)*);\n/g
 | |
| 			);
 | |
| 			items.sort(sortImport);
 | |
| 			return items.map(item => item.content).join("") + "\n";
 | |
| 		},
 | |
| 		optional: true,
 | |
| 		repeat: true
 | |
| 	},
 | |
| 	{
 | |
| 		title: "type imports",
 | |
| 		regexp: /(\/\*\* (?:@template \w+ )*@typedef \{import\("[^"]+"\)(\.\w+)*(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)?\} \w+(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)? \*\/\n)+\n/g,
 | |
| 		updateMessage: "sort type imports alphabetically",
 | |
| 		update(content) {
 | |
| 			const items = execToArray(
 | |
| 				content,
 | |
| 				/\/\*\* (?:@template \w+ )*@typedef \{import\("([^"]+)"\)((?:\.\w+)*(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)?)\} \w+(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)? \*\/\n/g
 | |
| 			);
 | |
| 			items.sort(sortImport);
 | |
| 			return items.map(item => item.content).join("") + "\n";
 | |
| 		},
 | |
| 		optional: true,
 | |
| 		repeat: true
 | |
| 	}
 | |
| ];
 | |
| 
 | |
| for (const filePath of allFiles) {
 | |
| 	let content = fs.readFileSync(filePath, "utf-8");
 | |
| 	const nl = /(\r?\n)/.exec(content);
 | |
| 	content = content.replace(/\r?\n/g, "\n");
 | |
| 	let newContent = content;
 | |
| 
 | |
| 	let state = 0;
 | |
| 	let pos = 0;
 | |
| 	// eslint-disable-next-line no-constant-condition
 | |
| 	while (true) {
 | |
| 		const current = schema[state];
 | |
| 		if (!current) break;
 | |
| 		current.regexp.lastIndex = pos;
 | |
| 		const match = current.regexp.exec(newContent);
 | |
| 		if (!match) {
 | |
| 			if (current.optional) {
 | |
| 				state++;
 | |
| 				continue;
 | |
| 			}
 | |
| 			console.log(`${filePath}: Missing ${current.title} at ${pos}`);
 | |
| 			process.exitCode = 1;
 | |
| 			break;
 | |
| 		}
 | |
| 		if (match.index !== pos) {
 | |
| 			console.log(
 | |
| 				`${filePath}: Unexpected code at ${pos}-${match.index}, expected ${current.title}`
 | |
| 			);
 | |
| 			process.exitCode = 1;
 | |
| 			pos = match.index;
 | |
| 		}
 | |
| 		if (!current.repeat) {
 | |
| 			state++;
 | |
| 		}
 | |
| 		if (current.update) {
 | |
| 			const update = current.update(...match);
 | |
| 			if (update !== match[0]) {
 | |
| 				newContent =
 | |
| 					newContent.substr(0, pos) +
 | |
| 					update +
 | |
| 					newContent.slice(pos + match[0].length);
 | |
| 				pos += update.length;
 | |
| 				if (!doWrite) {
 | |
| 					const updateMessage =
 | |
| 						current.updateMessage || `${current.title} need to be updated`;
 | |
| 					console.log(`${filePath}: ${updateMessage}`);
 | |
| 				}
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 		pos += match[0].length;
 | |
| 	}
 | |
| 
 | |
| 	if (newContent !== content) {
 | |
| 		if (doWrite) {
 | |
| 			if (nl) {
 | |
| 				newContent = newContent.replace(/\n/g, nl[0]);
 | |
| 			}
 | |
| 			fs.writeFileSync(filePath, newContent, "utf-8");
 | |
| 			console.log(filePath);
 | |
| 		} else {
 | |
| 			canUpdateWithWrite = true;
 | |
| 			process.exitCode = 1;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| if (canUpdateWithWrite) {
 | |
| 	console.log("Run 'yarn fix' to try to fix the problem automatically");
 | |
| }
 |