| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- #!/usr/bin/env node
- 'use strict';
- const fs = require('fs');
- const path = require('path');
- const ROOT = 'd:/ylrz_saas_new/java';
- const IMPL_DIR = path.join(ROOT, 'fs-service/src/main/java/com/fs/company/service/workflow/impl');
- const WORKFLOW_DIR = path.join(ROOT, 'fs-service/src/main/java/com/fs/company/service/workflow');
- const COLON = '\uFF1A';
- const PERIOD = '\u3002';
- const ENUM_SEP = '\u3001';
- const STRINGS = JSON.parse(fs.readFileSync(path.join(ROOT, 'scripts/javadoc-strings.json'), 'utf8'));
- function getCallers(className) {
- const keys = [className, className.replace(/Impl$/, '')];
- if (!keys[1].startsWith('I')) keys.push('I' + keys[1]);
- for (const k of keys) {
- if (STRINGS.callers[k]) return STRINGS.callers[k];
- }
- return [STRINGS.springCaller || 'Spring \u5bb9\u5668\u6ce8\u5165\u8c03\u7528'];
- }
- function formatCallers(callers) {
- return callers.map(c => `{@code ${c}}`).join(ENUM_SEP);
- }
- function parseInterfaceMethods(className) {
- const iface = className.replace(/Impl$/, '');
- const candidates = [
- path.join(WORKFLOW_DIR, iface + '.java'),
- path.join(WORKFLOW_DIR, 'I' + iface + '.java'),
- ];
- const methods = {};
- for (const f of candidates) {
- if (!fs.existsSync(f)) continue;
- const text = fs.readFileSync(f, 'utf8');
- const re = /\/\*\*([\s\S]*?)\*\/\s*(?:@[\w.]+\s*)*[\w<>,\[\]\s.?]+\s+(\w+)\s*\([^)]*\)\s*;/g;
- let m;
- while ((m = re.exec(text))) {
- const first = m[1].split('\n').map(l => l.replace(/^\s*\*\s?/, '').trim())
- .find(l => l && !l.startsWith('@') && !l.startsWith('param') && !l.startsWith('return'));
- if (first) methods[m[2]] = first.replace(/\s*@param.*/, '').trim();
- }
- }
- return methods;
- }
- function methodPurpose(methodName, ifaceMethods) {
- if (ifaceMethods[methodName]) return ifaceMethods[methodName];
- if (methodName.startsWith('get') && methodName.length > 3) return `\u83b7\u53d6${methodName.slice(3)}\u3002`;
- if (methodName.startsWith('set') && methodName.length > 3) return `\u8bbe\u7f6e${methodName.slice(3)}\u3002`;
- if (methodName.startsWith('is') && methodName.length > 2) return `\u5224\u65ad\u662f\u5426${methodName.slice(2)}\u3002`;
- if (methodName.startsWith('list')) return `\u67e5\u8be2${methodName.slice(4)}\u5217\u8868\u3002`;
- if (methodName.startsWith('save') || methodName.startsWith('create')) return '\u4fdd\u5b58/\u521b\u5efa\u76f8\u5173\u6570\u636e\u3002';
- if (methodName.startsWith('delete') || methodName.startsWith('remove')) return '\u5220\u9664\u76f8\u5173\u6570\u636e\u3002';
- if (methodName.startsWith('update')) return `\u66f4\u65b0${methodName.slice(6)}\u3002`;
- if (methodName.startsWith('batch')) return `\u6279\u91cf${methodName.slice(5)}\u3002`;
- if (methodName.startsWith('run') || methodName.startsWith('test')) return '\u8fd0\u884c\u6d4b\u8bd5\u6216\u4efb\u52a1\u3002';
- return `${methodName} \u7684\u516c\u5171\u5165\u53e3\u3002`;
- }
- function hasJavadocBefore(lines, idx) {
- let j = idx - 1;
- while (j >= 0 && lines[j].trim() === '') j--;
- return j >= 0 && lines[j].trim().endsWith('*/');
- }
- function hasCallerInJavadoc(lines, idx) {
- let j = idx - 1;
- while (j >= 0) {
- const t = lines[j].trim();
- if (t.startsWith('/**')) break;
- if (t.includes(STRINGS.callerLabel) || t.includes(STRINGS.mainCallerLabel)) return true;
- j--;
- }
- return false;
- }
- function makeMethodJavadoc(className, methodName, ifaceMethods, indent) {
- const purpose = methodPurpose(methodName, ifaceMethods);
- const callers = formatCallers(getCallers(className));
- return [
- `${indent}/**`,
- `${indent} * ${purpose}`,
- `${indent} * <p>${STRINGS.callerLabel}${COLON}${callers}${PERIOD}`,
- `${indent} */`,
- ];
- }
- function makeClassJavadoc(className) {
- const desc = STRINGS.classDesc[className] || `${className}\uFF1Aworkflow impl \u5305 Spring \u670d\u52a1\u5b9e\u73b0\u3002`;
- const callers = formatCallers(getCallers(className));
- return ['/**', ` * ${desc}`, ` * <p>${STRINGS.mainCallerLabel}${COLON}${callers}${PERIOD}`, ' */'];
- }
- function extractMethodName(lines, startIdx) {
- let combined = lines[startIdx].trim();
- let k = startIdx;
- while (!/[;{]/.test(combined) && k + 1 < lines.length) {
- k++;
- combined += ' ' + lines[k].trim();
- }
- const mm = combined.match(/\b(\w+)\s*\(/);
- if (!mm || ['if', 'for', 'while', 'switch', 'catch', 'synchronized'].includes(mm[1])) return null;
- return mm[1];
- }
- function processFile(filePath) {
- const className = path.basename(filePath, '.java');
- if (className === 'package-info') return false;
- let lines = fs.readFileSync(filePath, 'utf8').split(/\n/);
- const ifaceMethods = parseInterfaceMethods(className);
- let classIdx = lines.findIndex(l => new RegExp(`public\\s+(?:final\\s+)?class\\s+${className}\\b`).test(l));
- if (classIdx < 0) return false;
- let modified = false;
- let hasClassDoc = false;
- {
- let j = classIdx - 1;
- while (j >= 0 && (lines[j].trim().startsWith('@') || lines[j].trim() === '')) j--;
- if (j >= 0 && (lines[j].trim().startsWith('/**') || lines[j].trim().endsWith('*/'))) hasClassDoc = true;
- }
- if (!hasClassDoc) {
- let insertAt = classIdx;
- while (insertAt > 0 && (lines[insertAt - 1].trim().startsWith('@') || lines[insertAt - 1].trim() === '')) insertAt--;
- const classDoc = makeClassJavadoc(className);
- lines.splice(insertAt, 0, ...classDoc);
- classIdx += classDoc.length;
- modified = true;
- } else if (!hasCallerInJavadoc(lines, classIdx)) {
- let j = classIdx - 1;
- while (j >= 0 && (lines[j].trim().startsWith('@') || lines[j].trim() === '')) j--;
- if (j >= 0 && lines[j].trim() === '*/') {
- const callers = formatCallers(getCallers(className));
- lines.splice(j, 0, ` * <p>${STRINGS.mainCallerLabel}${COLON}${callers}${PERIOD}`);
- modified = true;
- }
- }
- const out = [];
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i];
- const stripped = line.trim();
- // Method with one or more leading annotations (@Override, @Transactional, ...)
- if (stripped.startsWith('@') && i + 1 < lines.length) {
- let k = i;
- while (k < lines.length && lines[k].trim().startsWith('@')) k++;
- if (k < lines.length && /^public\s+/.test(lines[k].trim())) {
- if (!hasJavadocBefore(lines, i)) {
- const name = extractMethodName(lines, k);
- if (name) {
- const indent = (line.match(/^(\s*)/) || ['', ' '])[1];
- out.push(...makeMethodJavadoc(className, name, ifaceMethods, indent));
- modified = true;
- }
- } else if (!hasCallerInJavadoc(lines, i)) {
- let j = i - 1;
- while (j >= 0 && lines[j].trim() !== '*/') j--;
- if (j >= 0) {
- const indent = (lines[j].match(/^(\s*)/) || ['', ' '])[1];
- out.push(`${indent} * <p>${STRINGS.callerLabel}${COLON}${formatCallers(getCallers(className))}${PERIOD}`);
- modified = true;
- }
- }
- while (i <= k) {
- out.push(lines[i]);
- i++;
- }
- i--;
- continue;
- }
- }
- if (/^public\s+(?!class\b|interface\b|enum\b|static\s+class\b)/.test(stripped) && !stripped.startsWith('@')) {
- let prev = out.length - 1;
- while (prev >= 0 && out[prev].trim() === '') prev--;
- if (prev >= 0 && out[prev].trim().startsWith('@')) {
- out.push(line);
- continue;
- }
- if (!hasJavadocBefore(lines, i)) {
- const name = extractMethodName(lines, i);
- if (name) {
- const indent = (line.match(/^(\s*)/) || ['', ' '])[1];
- out.push(...makeMethodJavadoc(className, name, ifaceMethods, indent));
- modified = true;
- }
- } else if (!hasCallerInJavadoc(lines, i)) {
- let j = i - 1;
- while (j >= 0 && lines[j].trim() !== '*/') j--;
- if (j >= 0) {
- const indent = (lines[j].match(/^(\s*)/) || ['', ' '])[1];
- out.push(`${indent} * <p>${STRINGS.callerLabel}${COLON}${formatCallers(getCallers(className))}${PERIOD}`);
- modified = true;
- }
- }
- }
- out.push(line);
- }
- if (modified) {
- const text = out.join('\n');
- fs.writeFileSync(filePath, text.endsWith('\n') ? text : text + '\n', 'utf8');
- }
- return modified;
- }
- const modified = [];
- for (const f of fs.readdirSync(IMPL_DIR).filter(x => x.endsWith('.java')).sort()) {
- const fp = path.join(IMPL_DIR, f);
- if (processFile(fp)) {
- modified.push(f);
- console.log('MODIFIED: ' + f);
- } else {
- console.log('SKIP: ' + f);
- }
- }
- console.log('\nTotal modified: ' + modified.length);
|