Under the cut- HolyJS 2018 Piterã«ã³ãã¡ã¬ã³ã¹ããã®Kirill CherkashinïŒ z6Dabrata ïŒã«ããã¬ããŒãã®ãããªããã³ããã¹ãã®ãã©ã³ã¹ã¯ãªããã
èè ã«ã€ããŠ
ã·ãªã«ã¯ã¢ã¹ã¯ã¯ã§çãŸããçŸåšã¯ãã¥ãŒãšãŒã¯ã«äœãã§ãããFirebaseã§åããŠããŸãã Googleã ãã§ãªãäžçäžã§AngularãæããŠããŸãã äžçæ倧ã®Angular mitapã®ãªãŒã¬ãã€ã¶ãŒã¯AngularNYCïŒããã³VueNYCãšReactNYCïŒã§ãã ããã°ã©ãã³ã°ã®äœæã«ã¯ãã¿ã³ãŽãæ¬ã楜ããäŒè©±ã奜ãã§ãã
åŒã®ããŸãã¯æšïŒ
äŸããå§ããŸããããããã°ã©ã ããããã°ããgitã«å ããå€æŽãéä¿¡ããåŸãéãã«å¯ããšããŸãããã æãååãããªãã®å€æŽãããŠã³ããŒãããåæ¥ã³ã³ãœãŒã«ãžã®ãããã°æ å ±ã®åºåãåé€ããã®ãå¿ãããããããã衚瀺ããŠåºåãè©°ãŸãããããšãå€æããŸããã å€ãã®äººããã®åé¡ã«çŽé¢ããŸããã
EsLintãªã©ã®ç¶æ³ãä¿®æ£ããããŒã«ããããŸãããæè²ç®çã®ããã«ãèªåã§è§£æ±ºçãèŠã€ããŠã¿ãŸãããã
ã³ãŒããããã¹ãŠã®
console.log()
ãåé€ããã«ã¯ãã©ã®ããŒã«ã䜿çšããå¿ èŠããããŸããïŒ
æ£èŠè¡šçŸãšAbstract Sitax TreesïŒASDïŒã®äœ¿çšããéžæããŸãã
findConsoleLog
é¢æ°ãäœæããŠãæ£èŠè¡šçŸã§ããã解決ããŠã¿ãŸãããã å ¥åæã«ãããã°ã©ã ã³ãŒããåŒæ°ãšããŠåãåããããã°ã©ã ããã¹ãã®ã©ããã«console.logïŒïŒãèŠã€ãã£ãå Žåã«trueã衚瀺ããŸãã
function findConsoleLog(code) { return !!code.match(/console.log/); }
ç§ãã¡ã®æ©èœãå£ãããŸããŸãªæ¹æ³ãèããŠã17ã®ãã¹ããæžããŸããã ãã®ãªã¹ãã¯å®å šã«ã¯ã»ã©é ãã
æãåçŽãªãã¹ãã«åæ ŒããŸããã
ãŸããé¢æ°ã®ååã«æååãconsole.logããå«ãŸããŠããå Žåã¯ã©ããªããŸããïŒ
function findConsoleLog(code) { return !!code.match(/\bconsole.log/); }
console.log
ãåèªã®å é ã«ããããšã瀺ãæåãè¿œå ããŸããã
2ã€ã®ãã¹ãã®ã¿ãåæ ŒããŸãããã
console.log
ãã³ã¡ã³ãå ã«ãããåé€ããå¿ èŠããªãå Žåã¯ã©ããªããŸããïŒ
ããŒãµãŒãã³ã¡ã³ãã«è§Šããªãããã«æžãçŽããŸãã
function findConsoleLog(code) { return !!code .replace(/\/\/.*/) .match(/\bconsole.log/); }
è¡ãããconsole.logãã®åé€ãé€å€ããŸãã
function findConsoleLog(code) { return !!code .replace(/\/\/.*|'.*'/, '') .match(/\bconsole.log/); }
ããã€ãã®ãã¹ãã®åæ Œã劚ããå¯èœæ§ã®ããã¹ããŒã¹ããã®ä»ã®æåããŸã ããããšãå¿ããªãã§ãã ããïŒ
ã¢ã€ãã¢ã¯éåžžã«åçŽã§ã¯ãªãã£ããšããäºå®ã«ãããããããæ£èŠè¡šçŸã䜿çšãã17ã®ãã¹ããã¹ãŠã«åæ Œã§ããŸãã ãã®å Žåããœãªã¥ãŒã·ã§ã³ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
function findConsoleLog(code) { return code .replace(/\/\/.*|'.*?[^\\]'|".*?"|`[\s\S]*`|\/\*[\s\S]*\*\//) .match(/\bconsole\s*.log\(/); }
åé¡ã¯ããã®ã³ãŒãããã¹ãŠã®å¯èœãªã±ãŒã¹ãã«ããŒããŠããããã§ã¯ãªãããããç¶æããã®ãããªãé£ããããšã§ãã
ASDã䜿çšããŠãã®åé¡ã解決ããæ¹æ³ãæ€èšããŠãã ããã
æšã¯ã©ã®ããã«æé·ããŸããïŒ
ããŒãµãŒãã¢ããªã±ãŒã·ã§ã³ã®ã³ãŒããæäœããçµæãšããŠãæœè±¡æ§æããªãŒãååŸãããŸãã ããŒãµãŒ@ babel / parserããã¢ã³ã¹ãã¬ãŒã·ã§ã³ã«äœ¿çšãããŸããã
äŸãšããŠãæåå
console.log('holy')
ååŸããããŒãµãŒã«æž¡ããŸãã
import { parse } from 'babylon'; parse("console.log('holy')");
圌ã®ä»äºã®çµæãçŽ300è¡ã®JSONãã¡ã€ã«ãååŸãããŸãã ãµãŒãã¹æ å ±ã®ããçªå·è¡ããé€å€ããŸãã ããã£ã»ã¯ã·ã§ã³ã«èå³ããããŸãã ã¡ã¿æ å ±ãç§ãã¡ã«ã¯èå³ããããŸããã çµæã¯çŽ100è¡ã§ãã ãã©ãŠã¶ãŒã1ã€ã®æ¬äœå€æ°ïŒçŽ300è¡ïŒã«å¯ŸããŠçæããæ§é ãšæ¯èŒãããšãããã¯ããã»ã©å€ããããŸããã
æ§æããªãŒã®ã³ãŒãã§ããŸããŸãªãªãã©ã«ãã©ã®ããã«è¡šããããã®äŸãããã€ãèŠãŠã¿ãŸãããã
ããã¯ãæ°å€ãªãã©ã«ã§ããæ°å€ãªãã©ã«ãååšããåŒã§ãã
ãã§ã«éŠŽæã¿ã®ããconsole.logåŒã ããããã£ãæã€ãªããžã§ã¯ãããããŸãã
logãé¢æ°åŒã³åºãã®å Žåã説æã¯æ¬¡ã®ãšããã§ããåŒã³åºãåŒããããåŒæ°-æ°å€ãªãã©ã«ããããŸãã åæã«ãåŒã³åºãåŒã«ã¯åå-logããããŸãã
ãªãã©ã«ã¯ç°ãªãå ŽåããããŸãïŒæ°å€ãæååãæ£èŠè¡šçŸãããŒã«å€ãnullã
console.logåŒã³åºãã«æ»ã
ããã¯ãå éšã«ã¡ã³ããŒåŒãæã€åŒã³åºãåŒã§ãã ãã®ããšãããå éšã®ã³ã³ãœãŒã«ãªããžã§ã¯ãã«ã¯logãšããããããã£ãããããšãæããã§ãã
ASDãã€ãã¹
次ã«ãã³ãŒãå ã§ãã®æ§é ãæäœããŠã¿ãŸãããã babel-traverseã©ã€ãã©ãªãŒã¯ãtreeããã©ããŒã¹ããããã«äœ¿çšãããŸãã
åã17ã®ãã¹ããè¡ââãããŸãã ãã®ãããªã³ãŒãã¯ãããã°ã©ã ã®æ§æããªãŒãåæãããconsole.logãã®ãšã³ããªãæ€çŽ¢ããããšã§ååŸã§ããŸãã
function traverseConsoleLog(code, {babylon, babelTraverse, types, log}) { const ast = babylon.parse(code); let hasConsoleLog = false; babelTraverse(ast, { MemberExpression(path){ if ( path.node.property.type === 'Identifier' && path.node.property.name === 'log' && path.node.object.type === 'Identifier' && path.node.object.name === 'console' && path.parent.type === 'CallExpression' && path.Parentkey === 'callee' ) { hasConsoleLog = true; } } }) return hasConsoleLog; }
ããã«æžãããŠããããšãåæããŸãããã
const ast = babylon.parse(code);
astå€æ°ã«ã³ãŒãããæ§ææšã解æããŸãã 次ã«ããã®ããªãŒãåŠçã®ããã«babel-parseã©ã€ãã©ãªã«æž¡ããŸãã åŒã³åºãåŒå ã§äžèŽããååãæã€ããŒããšããããã£ãæ¢ããŠããŸãã ããŒããšãã®ååã®å¿ èŠãªçµã¿åãããèŠã€ãã£ãå ŽåãhasConsoleLogå€æ°ãtrueã«èšå®ããŸãã
ããªãŒå ã移åããããŒãã®èŠªãåå«ãååŸããããããæã£ãŠããåŒæ°ãšããããã£ãæ¢ãããããã®ããããã£ã®ååãèŠãŠãã¿ã€ãããããšãã§ããŸã-ããã¯éåžžã«äŸ¿å©ã§ãã
babel-typesã©ã€ãã©ãªã䜿çšããŠç°¡åã«ä¿®æ£ã§ããäžå¿«ãªãã¥ã¢ã³ã¹ããããŸãã ããšãã°ã
path.parent.type === 'CallExpression'
代ããã«èª€ã£ãååã®ããã«ããªãŒãæ€çŽ¢ããéã®ãšã©ãŒãåé¿ããããã«ã誀ã£ãŠ
path.parent.type === 'CallExpression'
ãäœæããŸããã ïŒ
// Before path.node.property.type === 'Identifier' path.node.property.name === 'log' // with babel types import {isIdentifier} from 'babel-types'; isIdentifier(path.node.property, {name: log}) // , , isIdentifier,
babel-typesã䜿çšããŠä»¥åã®ã³ãŒããæžãæããŸãã
function traverseConsoleLogSolved2(code, {babylon, babelTraverse, types}) { const ast = babylon.parse(code); let hasConsoleLog = false; babelTraverse(ast, { MemberExpression(path) { if ( types.isIdentifier(path.node.object, { name: 'console'}) && types.isIdentifier(path.node.property, { name: 'log'}) && types.isCallExpression(path.parent) && path.parentKey === 'callee' ) { hasConsoleLog = true; } } }); return hasConsoleLog; }
babel-traverseã䜿çšããŠASDãå€æãã
人件費ãåæžããããã«ã
console.log
ã³ãŒãããããã«åé€ããå¿ èŠããã
console.log
ã³ãŒãå ã«ãããšããä¿¡å·ã§ã¯ãªãïŒã
MemberExpressionèªäœã§ã¯ãªãããã®èŠªãåé€ããå¿ èŠãããããã代ããã«
hasConsoleLog = true;
path.parentPath.remove();
ã
removeConsoleLog
é¢æ°ããããŸã ããŒã«å€ãè¿ããŸãã 次ã®ããã«ããã®åºåãbabel-generatorãçæããã³ãŒãã«çœ®ãæããŸãã
hasConsoleLog
=>
babelGenerator(ast).code
Babel-generatorã¯ãä¿®æ£ãããæœè±¡æ§æããªãŒããã©ã¡ãŒã¿ãŒãšããŠåãåããcodeããããã£ãæã€ãªããžã§ã¯ããè¿ããŸãããã®ãªããžã§ã¯ãå ã§ã¯ã
console.log
ãªãã§ã³ãŒããåçæãããŸãã ãšããã§ãã³ãŒãããããååŸããå Žåã¯ããã®ãªããžã§ã¯ãã®sourceMapsããããã£ãåŒã³åºãããšãã§ããŸãã
ãããŠããããã¬ãèŠã€ããå¿ èŠãããå Žåã¯ïŒ
ä»åã¯ã ASTexplorerã䜿çšããŠã¿ã¹ã¯ãå®äºããŸãã ãããã¬ãŒã¯ããããã¬ãŒã¹ããŒãã¡ã³ãããŒãã®äžçš®ã§ãã ããã¯ç¹å¥ãªçš®é¡ã®ããŒãã§ãããããå šäœã®æ§é ãèŠãå¿ èŠã¯ãããŸããããããã¬ãŒã¹ããŒãã¡ã³ããèŠã€ããã ãã§ãã ESLintçšã®ãã©ã°ã€ã³ãäœæããŸãïŒASTexploreräžïŒã
ASTexplorerã¯ãå·ŠåŽã«ã³ãŒããèšè¿°ããå³åŽã«å®æããASDãååŸããããã«èšèšãããŠããŸãã åä¿¡ãã圢åŒãéžæã§ããŸãïŒJSONãŸãã¯ããªãŒåœ¢åŒã
ESLintã䜿çšããŠããããããã¡ã€ã«ãèŠã€ããããã®ãã¹ãŠã®äœæ¥ãè¡ãããç®çã®ãã¡ã€ã«ãæäŸãããããããã®äžã®ãããã¬ãŒè¡ãèŠã€ããããšãã§ããŸãã ãã®ããŒã«ã¯ãç°ãªãASDããŒãµãŒã䜿çšããŸãã ãã ããJavaScriptã«ã¯ããã€ãã®ã¿ã€ãã®ASDããããŸãã ããŸããŸãªãã©ãŠã¶ãããŸããŸãªæ¹æ³ã§ä»æ§ãå®è£ ããŠããéå»ãé£æ³ããããã®ã ãããã£ãŠããããã¬ãŒæ€çŽ¢ãå®è£ ããŸãã
export default function(context) { return { DebuggerStatement(node) { // , console.log path, - , path context.report(node, 'LOL Debugger!!!'); // ESLint , debugger, node , , debugger } } }
æžããããã©ã°ã€ã³ã®åäœã確èªããïŒ
åæ§ã«ããããã¬ãŒãã³ãŒãããåé€ã§ããŸãã
ä»ã«åœ¹ç«ã€ASD
ç§ã¯å人çã«ASDã䜿çšããŠãAngularããã®ä»ã®ããã³ããšã³ããã¬ãŒã ã¯ãŒã¯ã§ã®äœæ¥ãç°¡çŽ åããŸãã ãã¿ã³ãã¯ãªãã¯ããã ãã§ãã€ã³ã¿ãŒãã§ãŒã¹ãã¡ãœããããã³ã¬ãŒã¿ãŒãªã©ãã€ã³ããŒããæ¡åŒµãè¿œå ã§ããŸãã ãã®ã±ãŒã¹ã§ã¯Javascriptã«ã€ããŠèª¬æããŠããŸãããTypeScriptã«ã¯ç¬èªã®ASDããããŸãããå¯äžã®éãã¯ããŒãã¿ã€ããšæ§é ã®ååã®éãã§ãã åãASTExplorerã§èšèªTypeScriptãšããŠéžæã§ããŸãã
ã ããïŒ
- ã³ãŒãããã现ããå¶åŸ¡ãããªãã¡ã¯ã¿ãªã³ã°ã容æã«ããcodemodã䜿çšããŸãã ããšãã°ãã³ãããããåã«ã1ã€ã®ããŒãæŒãããšã«ãããã¬ã€ãã©ã€ã³ã«åŸã£ãŠã³ãŒãå
šäœããã©ãŒãããã§ããŸãã codemodsã¯ãå¿
èŠãªãã¬ãŒã ã¯ãŒã¯ã®ããŒãžã§ã³ã«å¿ããèªåã³ãŒããããã³ã°ãæå³ããŸãã
- ã³ãŒãèšèšã«é¢ããè«äºã®æžå°ã
- ã²ãŒã ãããžã§ã¯ããäœæã§ããŸãã ããšãã°ãããã°ã©ããæžããã³ãŒãã«é¢ãããã£ãŒãããã¯ãèªåçã«æäŸããŸãã
- JavaScriptã®ããè¯ãç解ã
Babelã®äŸ¿å©ãªãªã³ã¯
- ãã¹ãŠã®Babelå€æã¯ããã®APIã䜿çšããŸãïŒ ãã©ã°ã€ã³ãšããªã»ãã ã
- ECMAScriptã«æ°ããæ©èœãè¿œå ããããã»ã¹ã®äžéšã¯ãBabelã®ãã©ã°ã€ã³ãäœæããããšã§ãã ããã¯ã人ã
ãæ°ããæ©èœããã¹ãã§ããããã«ããããã«å¿
èŠã§ãã ãªã³ã¯ããã©ããšãåãæ¹æ³ã§ASDã®æ©èœã䜿çšãããŠããããšãããããŸãã ããšãã°ã logical-assignment-operator ã
- Babel Generatorã¯ãã³ãŒããçæãããšãã«ãã©ãŒãããã倱ããŸãã ãã®ããŒã«ãéçºããŒã ã§äœ¿çšãããå ŽåãASDããã³ãŒããçæããåŸããã¹ãŠã®äººã«åãããã«èŠãããããããã¯éšåçã«ã¯è¯ãããšã§ãã ãã ãããã©ãŒããããç¶æãããå Žåã¯ã次ã®ããããã®ããŒã«ã䜿çšã§ããŸãïŒ RecastãŸãã¯Babel CodeMod
- ãã®ãªã³ã¯ãããBabel Awesome Babelã«é¢ããè±å¯ãªæ
å ±ãèŠã€ããããšãã§ããŸãã
- Babelã¯ãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã§ããããã©ã³ãã£ã¢ããŒã ãããã«åãçµãã§ããŸãã ããªããå©ããããšãã§ããŸãã ãããè¡ãã«ã¯3ã€ã®æ¹æ³ããããŸãïŒè²¡æ¿æ¯æŽãããªãã¯pabelonãŠã§ããµã€ãããµããŒãã§ããŸãã
ããŒãã¹
ã³ãŒãã§
console.log
ãèŠã€ããæ¹æ³ã¯ä»ã«ãããŸããïŒ IDEã䜿çšããŠãã ããïŒ ã³ãŒãã®æ€çŽ¢å ŽæãéžæããåŸãæ€çŽ¢ãšçœ®æããŒã«ã䜿çšããŸãã
Intellij IDEAã«ã¯ãã³ãŒãå ã®é©åãªå ŽæãèŠã€ããã®ã«åœ¹ç«ã€ãæ§é æ€çŽ¢ãããŒã«ããããŸããã¡ãªã¿ã«ãASDã䜿çšããŠããŸãã
11æ24ã25æ¥ã«ã Kirillã¯ã ã¢ã¹ã¯ã¯ã®HolyJSã§JavaScript * LOVES *ãã€ããªããŒã¿ã«é¢ãããã¬ãŒã³ããŒã·ã§ã³ãè¡ããŸãããã€ããªããŒã¿ã¬ãã«ã«é²ã¿ã* .gifãã¡ã€ã«ã䜿çšããŠãã€ããªãã¡ã€ã«ãæããProtobufãThriftãªã©ã®ã·ãªã¢ã«åãã¬ãŒã ã¯ãŒã¯ãæ±ããŸãã å ±ååŸãCyrilãšè©±ãåããè°è«ã®åéã§é¢å¿ã®ãããã¹ãŠã®åé¡ã«ã€ããŠè°è«ããããšãå¯èœã«ãªããŸãã