Skip to main content
Glama

analyze_modernization

Analyzes JavaScript/TypeScript code to identify outdated patterns and third-party libraries that can be replaced with native browser Web APIs, reducing bundle size and improving performance.

Instructions

分析 JavaScript/TypeScript 程式碼現代化機會,找出可被瀏覽器原生 Web API 替代的第三方函式庫,減少 npm bundle 大小,包括 jQuery、Moment.js、Lodash、XMLHttpRequest 等過時模式的現代化建議

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectPathYes專案目錄路徑
includePatternsNo要掃描的檔案模式,支援 glob 語法,如 ["src/**/*.js", "src/**/*.ts"] 掃描 src 目錄下的 JavaScript/TypeScript 檔案
excludePatternsNo要排除的檔案模式 (預設: ["node_modules/**", "dist/**", "build/**"])
reportFormatNo報告格式markdown

Implementation Reference

  • Primary MCP tool handler for 'analyze_modernization'. Validates arguments, invokes ModernizationAnalyzer.analyze on the project, enhances with CanIUse category data, formats the report in specified format, and handles errors.
    private async handleModernizationAnalysis(args: unknown) { try { // 驗證輸入參數 const validatedArgs = this.validateModernizationArgs(args); const { projectPath, includePatterns = ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx'], excludePatterns = ['node_modules/**', 'dist/**', 'build/**'], reportFormat = 'markdown' } = validatedArgs; // 步驟 1: 先取得所有可用的 API 類別 let allCategories: Array<{ name: string; count: number; description?: string }> = []; let apiCategoryMap = new Map<string, string[]>(); // API 名稱 -> 類別列表 try { allCategories = await this.canIUseService.getAllCategories(); // 步驟 2: 分析專案中的現代化 API,找出它們的類別 const analysis = await this.modernizationAnalyzer.analyze( projectPath, includePatterns, excludePatterns ); // 收集所有提到的現代 API const modernApis = new Set<string>(); for (const file of analysis.fileAnalysis) { for (const api of file.modernizableApis) { modernApis.add(api.modernApi); } } // 為每個現代 API 找出對應的類別 for (const apiName of modernApis) { const categories: string[] = []; // 從知識庫中查找 API const api = this.apiKnowledge.getApi(apiName); if (api) { categories.push(api.category); } else { // 如果知識庫中沒有,嘗試從 Can I Use 資料庫查找 try { // 嘗試搜尋 feature ID const featureIds = await this.canIUseService.searchFeature(apiName); if (featureIds.length > 0) { const featureSupport = await this.canIUseService.getFeatureSupport(featureIds[0]); if (featureSupport && featureSupport.categories) { categories.push(...featureSupport.categories); } } } catch (error) { // 忽略錯誤,繼續處理下一個 API } } if (categories.length > 0) { apiCategoryMap.set(apiName, categories); } } // 將類別資訊添加到分析結果中 const enhancedAnalysis = { ...analysis, categoryInfo: { totalCategories: allCategories.length, apiCategories: Object.fromEntries(apiCategoryMap), allCategories: allCategories.map(cat => ({ name: cat.name, count: cat.count, description: cat.description })) } }; return { content: [ { type: 'text', text: this.formatModernizationReport(enhancedAnalysis, reportFormat), }, ], }; } catch (categoryError) { // 如果取得類別失敗,仍然返回分析結果(不包含類別資訊) console.warn('無法取得類別資訊,將返回不含類別的分析結果:', categoryError); const analysis = await this.modernizationAnalyzer.analyze( projectPath, includePatterns, excludePatterns ); return { content: [ { type: 'text', text: this.formatModernizationReport(analysis, reportFormat), }, ], }; } } catch (error) { const errorMessage = error instanceof ValidationError ? `參數驗證失敗: ${error.message}` : `分析失敗: ${error instanceof Error ? error.message : String(error)}`; return { content: [ { type: 'text', text: errorMessage, }, ], isError: true, }; } }
  • Input schema definition for the analyze_modernization tool, specifying parameters like projectPath (required), includePatterns, excludePatterns, and reportFormat.
    inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: '專案目錄路徑', }, includePatterns: { type: 'array', items: { type: 'string' }, description: '要掃描的檔案模式,支援 glob 語法,如 ["src/**/*.js", "src/**/*.ts"] 掃描 src 目錄下的 JavaScript/TypeScript 檔案', default: ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx'] }, excludePatterns: { type: 'array', items: { type: 'string' }, description: '要排除的檔案模式 (預設: ["node_modules/**", "dist/**", "build/**"])', default: ['node_modules/**', 'dist/**', 'build/**'] }, reportFormat: { type: 'string', description: '報告格式', enum: ['markdown', 'json', 'html', 'text'], default: 'markdown' } }, required: ['projectPath'],
  • src/server.ts:113-144 (registration)
    Tool registration in the ListToolsRequestSchema response, defining name, description, and linking to the input schema.
    { name: 'analyze_modernization', description: '分析 JavaScript/TypeScript 程式碼現代化機會,找出可被瀏覽器原生 Web API 替代的第三方函式庫,減少 npm bundle 大小,包括 jQuery、Moment.js、Lodash、XMLHttpRequest 等過時模式的現代化建議', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: '專案目錄路徑', }, includePatterns: { type: 'array', items: { type: 'string' }, description: '要掃描的檔案模式,支援 glob 語法,如 ["src/**/*.js", "src/**/*.ts"] 掃描 src 目錄下的 JavaScript/TypeScript 檔案', default: ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx'] }, excludePatterns: { type: 'array', items: { type: 'string' }, description: '要排除的檔案模式 (預設: ["node_modules/**", "dist/**", "build/**"])', default: ['node_modules/**', 'dist/**', 'build/**'] }, reportFormat: { type: 'string', description: '報告格式', enum: ['markdown', 'json', 'html', 'text'], default: 'markdown' } }, required: ['projectPath'], }, },
  • Core implementation of the modernization analysis logic in ModernizationAnalyzer.analyze(). Parses project files using CodeParser, analyzes imports/APIs/code patterns in each file, aggregates suggestions, computes performance summary and risk assessment.
    async analyze( projectPath: string, includePatterns: string[], excludePatterns: string[] ): Promise<ModernizationAnalysis> { // 解析專案檔案 const parsedFiles = await this.parser.parseProject(projectPath, includePatterns, excludePatterns); // 分析每個檔案 const fileAnalysis: FileModernizationResult[] = []; const allSuggestions: ModernizationSuggestion[] = []; for (const file of parsedFiles) { const result = this.analyzeFile(file); fileAnalysis.push(result); allSuggestions.push(...result.suggestions); } // 彙總分析結果 const summary = this.generateSummary(fileAnalysis, allSuggestions); const riskAssessment = this.assessRisk(allSuggestions); return { summary, suggestions: allSuggestions, fileAnalysis, riskAssessment }; }
  • Supporting data class ModernizationRules that defines and provides access to all library and API modernization rules used by the analyzer to detect and suggest replacements (e.g., jQuery -> native DOM, Moment -> date-fns).
    export class ModernizationRules { private libraryRules: Map<string, ModernizationRule> = new Map(); private apiRules: Map<string, ModernizationRule> = new Map(); constructor() { this.initializeLibraryRules(); this.initializeApiRules(); } /** * 初始化函式庫規則 */ private initializeLibraryRules() { const rules: Array<[string, ModernizationRule]> = [ // jQuery 相關 - 最大的 bundle 減少機會 ['jquery', { name: 'jQuery', modernAlternative: '原生 DOM API / 現代框架', reason: 'jQuery (約85KB) 在現代瀏覽器中已不再必要,原生 API 已足夠強大,可大幅減少 bundle 大小', compatibility: '所有現代瀏覽器', impact: { performance: 15, bundle: 85, maintainability: 3 }, difficulty: 'moderate', breaking: true, deprecated: false, severity: 'medium', migrationExample: `// 舊版 $('#element').addClass('active'); $('.items').each(function() { ... }); // 現代版 document.getElementById('element').classList.add('active'); document.querySelectorAll('.items').forEach(el => { ... });`, references: ['https://youmightnotneedjquery.com/'] }], // Moment.js ['moment', { name: 'Moment.js', modernAlternative: 'Date-fns / Dayjs / 原生 Temporal API', reason: 'Moment.js 體積過大且不支援 tree-shaking,現代替代方案更輕量', compatibility: '現代瀏覽器支援', impact: { performance: 25, bundle: 65, maintainability: 4 }, difficulty: 'simple', breaking: true, deprecated: true, severity: 'high', migrationExample: `// 舊版 (Moment.js) moment().format('YYYY-MM-DD'); // 現代版 (Date-fns) import { format } from 'date-fns'; format(new Date(), 'yyyy-MM-dd'); // 未來 (Temporal) Temporal.now.plainDateISO().toString();`, references: ['https://momentjs.com/docs/#/-project-status/'] }], // Lodash ['lodash', { name: 'Lodash', modernAlternative: '原生 JavaScript 方法', reason: '許多 Lodash 功能現在已有原生支援,可減少依賴', compatibility: 'ES2015+ 瀏覽器', impact: { performance: 10, bundle: 50, maintainability: 3 }, difficulty: 'simple', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 (Lodash) _.map(array, fn); _.filter(array, predicate); // 現代版 (原生) array.map(fn); array.filter(predicate);`, references: ['https://youmightnotneedlodash.com/'] }], // Request (已棄用) ['request', { name: 'Request', modernAlternative: 'node-fetch / axios / 原生 fetch', reason: 'Request 已棄用,建議使用現代 HTTP 客戶端', compatibility: 'Node.js + 現代瀏覽器', impact: { performance: 20, bundle: 30, maintainability: 4 }, difficulty: 'simple', breaking: true, deprecated: true, severity: 'high', migrationExample: `// 舊版 (Request) request.get(url, callback); // 現代版 (fetch) const response = await fetch(url); const data = await response.json();`, references: ['https://github.com/request/request/issues/3142'] }], // Left-pad (安全性問題) ['left-pad', { name: 'left-pad', modernAlternative: 'String.prototype.padStart()', reason: '原生方法已支援,無需額外依賴', compatibility: 'ES2017+ 瀏覽器', impact: { performance: 5, bundle: 1, maintainability: 2 }, difficulty: 'trivial', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 const leftPad = require('left-pad'); leftPad('hello', 10, '0'); // 現代版 'hello'.padStart(10, '0');`, }], // Core-js polyfills ['core-js', { name: 'core-js', modernAlternative: '選擇性 polyfill 或原生支援', reason: '根據目標瀏覽器選擇必要的 polyfill,避免過度 polyfill', compatibility: '根據 browserslist 決定', impact: { performance: 30, bundle: 100, maintainability: 3 }, difficulty: 'moderate', breaking: false, deprecated: false, severity: 'medium', migrationExample: `// 分析:檢查 browserslist 設定 // 只載入必要的 polyfill import 'core-js/stable/array/includes'; // 僅在需要時載入`, }], // Underscore.js (類似 Lodash) ['underscore', { name: 'Underscore.js', modernAlternative: '原生 JavaScript 方法', reason: 'Underscore.js 的大部分功能現在已有原生支援', compatibility: 'ES5+ 瀏覽器', impact: { performance: 8, bundle: 25, maintainability: 3 }, difficulty: 'simple', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 (Underscore) _.each(array, fn); _.map(array, fn); // 現代版 array.forEach(fn); array.map(fn);`, }], // Bluebird Promise ['bluebird', { name: 'Bluebird', modernAlternative: '原生 Promise', reason: '原生 Promise 已支援大部分功能,Bluebird 在現代環境中已非必要', compatibility: '所有現代瀏覽器', impact: { performance: 5, bundle: 45, maintainability: 2 }, difficulty: 'simple', breaking: true, deprecated: false, severity: 'low', migrationExample: `// 舊版 (Bluebird) const Promise = require('bluebird'); Promise.map(items, fn); // 現代版 Promise.all(items.map(fn)); // 或使用 for await...of for await (const result of asyncIterator) { ... }`, }], // Async.js ['async', { name: 'Async.js', modernAlternative: 'async/await + Promise', reason: 'async/await 語法提供更簡潔的非同步控制流程', compatibility: 'ES2017+ 瀏覽器', impact: { performance: 0, bundle: 20, maintainability: 4 }, difficulty: 'moderate', breaking: true, deprecated: false, severity: 'medium', migrationExample: `// 舊版 (Async.js) async.waterfall([fn1, fn2, fn3], callback); async.parallel([task1, task2], callback); // 現代版 // waterfall const result1 = await fn1(); const result2 = await fn2(result1); const result3 = await fn3(result2); // parallel const [res1, res2] = await Promise.all([task1(), task2()]);`, }], // uuid ['uuid', { name: 'uuid', modernAlternative: 'crypto.randomUUID()', reason: '瀏覽器和 Node.js 現已支援原生 UUID 生成', compatibility: 'Chrome 92+, Firefox 95+, Safari 15.4+, Node.js 19+', impact: { performance: 2, bundle: 8, maintainability: 2 }, difficulty: 'trivial', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 (uuid) import { v4 as uuidv4 } from 'uuid'; const id = uuidv4(); // 現代版 const id = crypto.randomUUID();`, }], // is-number / is-array 等小型工具 ['is-number', { name: 'is-number', modernAlternative: 'typeof + Number.isFinite()', reason: '原生方法已可完成相同功能', compatibility: '所有現代瀏覽器', impact: { performance: 0, bundle: 1, maintainability: 1 }, difficulty: 'trivial', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 const isNumber = require('is-number'); isNumber(value); // 現代版 typeof value === 'number' && Number.isFinite(value);`, }], ['is-array', { name: 'is-array', modernAlternative: 'Array.isArray()', reason: '原生 Array.isArray() 方法已存在多年', compatibility: '所有瀏覽器 (IE9+)', impact: { performance: 0, bundle: 1, maintainability: 1 }, difficulty: 'trivial', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 const isArray = require('is-array'); isArray(value); // 現代版 Array.isArray(value);`, }], // object-assign ['object-assign', { name: 'object-assign', modernAlternative: 'Object.assign() 或展開運算子', reason: '原生 Object.assign() 和展開運算子已廣泛支援', compatibility: 'ES2015+ 瀏覽器', impact: { performance: 0, bundle: 2, maintainability: 2 }, difficulty: 'trivial', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 const assign = require('object-assign'); assign({}, obj1, obj2); // 現代版 Object.assign({}, obj1, obj2); // 或 { ...obj1, ...obj2 };`, }], // array-flatten ['array-flatten', { name: 'array-flatten', modernAlternative: 'Array.prototype.flat()', reason: '原生 flat() 方法已廣泛支援', compatibility: 'ES2019+ 瀏覽器', impact: { performance: 0, bundle: 2, maintainability: 2 }, difficulty: 'trivial', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 const flatten = require('array-flatten'); flatten([1, [2, [3]]]); // 現代版 [1, [2, [3]]].flat(Infinity); // 完全展平 [1, [2, [3]]].flat(1); // 展平一層`, }], // classnames / clsx ['classnames', { name: 'classnames', modernAlternative: '模板字串或原生陣列方法', reason: '簡單場景可用模板字串處理,但 classnames 在複雜場景仍很有用', compatibility: '所有瀏覽器', impact: { performance: 0, bundle: 2, maintainability: 1 }, difficulty: 'simple', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 import classNames from 'classnames'; classNames('foo', { bar: true, baz: false }); // 現代版 (簡單場景) const classes = ['foo', isBar && 'bar', isBaz && 'baz'].filter(Boolean).join(' '); // 或使用模板字串 \`foo \${isBar ? 'bar' : ''} \${isBaz ? 'baz' : ''}\`.trim();`, }], // querystring ['querystring', { name: 'querystring', modernAlternative: 'URLSearchParams', reason: 'URLSearchParams 是瀏覽器原生 API,Node.js 也支援', compatibility: '所有現代瀏覽器', impact: { performance: 2, bundle: 5, maintainability: 3 }, difficulty: 'simple', breaking: false, deprecated: true, severity: 'medium', migrationExample: `// 舊版 (querystring) const qs = require('querystring'); qs.parse('foo=bar&baz=qux'); qs.stringify({ foo: 'bar' }); // 現代版 const params = new URLSearchParams('foo=bar&baz=qux'); params.get('foo'); // 'bar' const search = new URLSearchParams({ foo: 'bar' }); search.toString(); // 'foo=bar'`, }], // node-fetch (在 Node.js 18+) ['node-fetch', { name: 'node-fetch', modernAlternative: '原生 fetch (Node.js 18+)', reason: 'Node.js 18+ 已內建 fetch API', compatibility: 'Node.js 18+', impact: { performance: 5, bundle: 15, maintainability: 2 }, difficulty: 'trivial', breaking: false, deprecated: false, severity: 'low', migrationExample: `// 舊版 const fetch = require('node-fetch'); const response = await fetch(url); // 現代版 (Node.js 18+) // 直接使用,無需 import const response = await fetch(url);`, references: ['https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#fetch'] }] ]; for (const [key, rule] of rules) { this.libraryRules.set(key, rule); } } /** * 初始化 API 規則 */ private initializeApiRules() { const rules: Array<[string, ModernizationRule]> = [ // XMLHttpRequest → fetch ['XMLHttpRequest', { name: 'XMLHttpRequest', modernAlternative: 'fetch API', reason: 'fetch API 提供更現代、Promise 化的 HTTP 介面', compatibility: '現代瀏覽器 (IE 需要 polyfill)', impact: { performance: 10, bundle: 0, maintainability: 4 }, difficulty: 'simple', breaking: true, deprecated: false, migrationExample: `// 舊版 const xhr = new XMLHttpRequest(); xhr.open('GET', '/api/data'); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { callback(JSON.parse(xhr.responseText)); } }; xhr.send(); // 現代版 const response = await fetch('/api/data'); const data = await response.json();`, }], // setTimeout callback → Promise ['setTimeout', { name: 'setTimeout (callback pattern)', modernAlternative: 'Promise-based timer', reason: '避免回調地獄,提供更好的錯誤處理', compatibility: '所有現代瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 3 }, difficulty: 'simple', breaking: false, deprecated: false, migrationExample: `// 舊版 (回調模式) function delay(ms, callback) { setTimeout(callback, ms); } // 現代版 (Promise) function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 使用 await delay(1000);`, }], // document.getElementById → querySelector ['document.getElementById', { name: 'document.getElementById', modernAlternative: 'document.querySelector', reason: 'querySelector 提供更一致的 API 和更強大的選擇能力', compatibility: '所有現代瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 2 }, difficulty: 'trivial', breaking: false, deprecated: false, migrationExample: `// 舊版 const element = document.getElementById('myId'); // 現代版 (可選) const element = document.querySelector('#myId');`, }], // addEventListener → modern event handling ['attachEvent', { name: 'attachEvent', modernAlternative: 'addEventListener', reason: 'attachEvent 是 IE 特有的過時 API', compatibility: 'IE 已不再支援', impact: { performance: 0, bundle: -2, maintainability: 3 }, difficulty: 'simple', breaking: true, deprecated: true, severity: 'high', migrationExample: `// 舊版 (IE only) element.attachEvent('onclick', handler); // 現代版 element.addEventListener('click', handler);`, }], // var → let/const ['var', { name: 'var declarations', modernAlternative: 'let/const', reason: 'let/const 提供更好的作用域控制,避免 hoisting 問題', compatibility: 'ES2015+ 瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 3 }, difficulty: 'trivial', breaking: false, deprecated: false, migrationExample: `// 舊版 var name = 'John'; var age = 30; // 現代版 const name = 'John'; // 不會改變 let age = 30; // 可能改變`, }], // for loop → array methods ['for', { name: 'traditional for loops', modernAlternative: 'Array methods (map, filter, forEach)', reason: '陣列方法更具表達性,減少錯誤機會', compatibility: 'ES5+ 瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 4 }, difficulty: 'simple', breaking: false, deprecated: false, migrationExample: `// 舊版 const result = []; for (let i = 0; i < items.length; i++) { if (items[i].active) { result.push(items[i].name); } } // 現代版 const result = items .filter(item => item.active) .map(item => item.name);`, }], // document.write - 危險的 API ['document.write', { name: 'document.write', modernAlternative: 'DOM API (innerHTML, appendChild)', reason: 'document.write 會覆蓋整個頁面,在異步情況下特別危險', compatibility: '所有瀏覽器', impact: { performance: 10, bundle: 0, maintainability: 5 }, difficulty: 'simple', breaking: true, deprecated: true, severity: 'high', migrationExample: `// 舊版 (危險) document.write('<h1>Hello</h1>'); // 現代版 document.body.innerHTML = '<h1>Hello</h1>'; // 或 const h1 = document.createElement('h1'); h1.textContent = 'Hello'; document.body.appendChild(h1);`, }], // eval - 安全風險 ['eval', { name: 'eval', modernAlternative: 'Function 構造函數或其他安全替代方案', reason: 'eval 有嚴重的安全風險 (XSS),且影響效能優化', compatibility: '所有瀏覽器', impact: { performance: 20, bundle: 0, maintainability: 5 }, difficulty: 'moderate', breaking: true, deprecated: false, severity: 'high', migrationExample: `// 舊版 (危險) const result = eval('2 + 2'); const fn = eval('(function() { return x + y; })'); // 現代版 // 對於數學計算,直接使用 JavaScript const result = 2 + 2; // 對於動態函式,使用 Function 構造函數 (仍需謹慎) const fn = new Function('x', 'y', 'return x + y'); // 對於 JSON,使用 JSON.parse const data = JSON.parse(jsonString);`, }], // with - 已棄用 ['with', { name: 'with statement', modernAlternative: '解構賦值或直接存取', reason: 'with 語句在 strict mode 中被禁止,且會造成作用域混淆', compatibility: '所有瀏覽器 (但 strict mode 禁止)', impact: { performance: 5, bundle: 0, maintainability: 4 }, difficulty: 'simple', breaking: true, deprecated: true, severity: 'high', migrationExample: `// 舊版 (已棄用) with (obj) { console.log(a, b, c); } // 現代版 - 解構賦值 const { a, b, c } = obj; console.log(a, b, c);`, }], // arguments - 建議使用 rest parameters ['arguments', { name: 'arguments object', modernAlternative: 'Rest parameters (...args)', reason: 'Rest parameters 是真正的陣列,語法更清晰', compatibility: 'ES2015+ 瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 3 }, difficulty: 'simple', breaking: false, deprecated: false, migrationExample: `// 舊版 function sum() { let total = 0; for (let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total; } // 現代版 function sum(...numbers) { return numbers.reduce((a, b) => a + b, 0); }`, }], // innerHTML 安全警告 ['innerHTML', { name: 'innerHTML', modernAlternative: 'textContent 或 DOM API', reason: '使用 innerHTML 插入使用者輸入可能導致 XSS 攻擊', compatibility: '所有瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 2 }, difficulty: 'simple', breaking: false, deprecated: false, severity: 'medium', migrationExample: `// 舊版 (有 XSS 風險) element.innerHTML = userInput; // 現代版 - 純文字 element.textContent = userInput; // 現代版 - 需要 HTML 時使用 DOM API const p = document.createElement('p'); p.textContent = userInput; element.appendChild(p); // 或使用 DOMPurify 清理 HTML import DOMPurify from 'dompurify'; element.innerHTML = DOMPurify.sanitize(htmlContent);`, }], // new Array() → [] ['new Array', { name: 'new Array()', modernAlternative: '陣列字面量 []', reason: '陣列字面量更簡潔,且避免 new Array(n) 的歧義', compatibility: '所有瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 1 }, difficulty: 'trivial', breaking: false, deprecated: false, migrationExample: `// 舊版 const arr = new Array(1, 2, 3); const empty = new Array(); // 現代版 const arr = [1, 2, 3]; const empty = []; // 注意:new Array(5) 會建立長度為 5 的稀疏陣列 // 如需建立填充陣列,使用: const filled = Array.from({ length: 5 }, (_, i) => i);`, }], // new Object() → {} ['new Object', { name: 'new Object()', modernAlternative: '物件字面量 {}', reason: '物件字面量更簡潔明瞭', compatibility: '所有瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 1 }, difficulty: 'trivial', breaking: false, deprecated: false, migrationExample: `// 舊版 const obj = new Object(); obj.name = 'John'; // 現代版 const obj = { name: 'John' };`, }], // String.prototype.substr → substring/slice ['substr', { name: 'String.prototype.substr()', modernAlternative: 'substring() 或 slice()', reason: 'substr() 已被標記為遺留功能,建議使用 substring() 或 slice()', compatibility: '所有瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 2 }, difficulty: 'trivial', breaking: false, deprecated: true, severity: 'low', migrationExample: `// 舊版 (遺留) str.substr(start, length); // 現代版 str.substring(start, start + length); // 或 str.slice(start, start + length);`, }], // Date 建構函數字串解析 ['Date.parse', { name: 'Date 字串解析', modernAlternative: '明確的日期解析或使用 Temporal API', reason: 'Date 字串解析在不同瀏覽器中行為不一致', compatibility: '所有瀏覽器', impact: { performance: 0, bundle: 0, maintainability: 3 }, difficulty: 'simple', breaking: false, deprecated: false, severity: 'medium', migrationExample: `// 舊版 (行為不一致) new Date('2024-01-15'); Date.parse('Jan 15, 2024'); // 現代版 - 明確指定 new Date(2024, 0, 15); // 月份從 0 開始 // 或使用 ISO 8601 格式 (最可靠) new Date('2024-01-15T00:00:00.000Z'); // 未來:使用 Temporal API // Temporal.PlainDate.from('2024-01-15');`, }] ]; for (const [key, rule] of rules) { this.apiRules.set(key, rule); } } /** * 取得函式庫規則 */ getLibraryRule(libraryName: string): ModernizationRule | undefined { return this.libraryRules.get(libraryName); } /** * 取得 API 規則 */ getApiRule(apiName: string): ModernizationRule | undefined { return this.apiRules.get(apiName); } /** * 取得所有函式庫規則 */ getAllLibraryRules(): Map<string, ModernizationRule> { return new Map(this.libraryRules); } /** * 取得所有 API 規則 */ getAllApiRules(): Map<string, ModernizationRule> { return new Map(this.apiRules); } /** * 搜尋相關規則 */ searchRules(query: string): ModernizationRule[] { const results: ModernizationRule[] = []; const lowerQuery = query.toLowerCase(); // 搜尋函式庫規則 for (const [key, rule] of this.libraryRules) { if (key.toLowerCase().includes(lowerQuery) || rule.name.toLowerCase().includes(lowerQuery) || rule.modernAlternative.toLowerCase().includes(lowerQuery)) { results.push(rule); } } // 搜尋 API 規則 for (const [key, rule] of this.apiRules) { if (key.toLowerCase().includes(lowerQuery) || rule.name.toLowerCase().includes(lowerQuery) || rule.modernAlternative.toLowerCase().includes(lowerQuery)) { results.push(rule); } } return results; } /** * 新增自定義規則 */ addLibraryRule(name: string, rule: ModernizationRule) { this.libraryRules.set(name, rule); } /** * 新增 API 規則 */ addApiRule(name: string, rule: ModernizationRule) { this.apiRules.set(name, rule); } /** * 取得統計資訊 */ getStatistics() { const libraryCount = this.libraryRules.size; const apiCount = this.apiRules.size; let deprecatedCount = 0; let highImpactCount = 0; for (const rule of [...this.libraryRules.values(), ...this.apiRules.values()]) { if (rule.deprecated) deprecatedCount++; if (rule.impact.performance > 20 || rule.impact.bundle > 50) highImpactCount++; } return { totalRules: libraryCount + apiCount, libraryRules: libraryCount, apiRules: apiCount, deprecatedRules: deprecatedCount, highImpactRules: highImpactCount }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mukiwu/dev-advisor-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server