
ãããžã§ã¯ãã®ãªãã¡ã¯ã¿ãªã³ã°ã¯ããã¹ãŠã®éçºè
ã«è¿ããããã¯ã ãšæããŸãã å€ãã®å ŽåãIDEãšæ£èŠè¡šçŸã§ååã§ãªããªããšåé¡ãçºçãããã®æçš¿ã§èª¬æãããŠãããããªè³éãå©ãã«ãªããŸãã Codemodã¹ã¯ãªããã¯éåžžã«åŒ·åãªããŒã«ã§ãã ããããã¹ã¿ãŒããåŸããªãã¡ã¯ã¿ãªã³ã°ãåãã«ãªãããšã¯æ±ºããŠãªãããšãæããã«ãªããŸãã ãããã£ãŠãç§ã¯ãã®æçš¿ãç§ãã¡ã®ãããã°ã«ç¿»èš³ããŸããã æ¥œããèªæžããç¥ãããŸãã
ã³ãŒãããŒã¹ã®ç¶æã¯ãç¹ã«JavaScriptã«é¢ããŠã¯ãéçºè
ã«ãšã£ãŠé çã®çš®ã«ãªããŸãã ãµãŒãããŒãã£ã®ããã±ãŒãžã®çµ¶ããå€åããæšæºãæ§æãããã³é倧ãªå€æŽãèãããšããã®ãããªã³ãŒãã®ç¶æã¯éåžžã«å°é£ã§ãã
JavaScriptã¯è¿å¹Žãèªèãè¶
ããŠå€åããŠããŸãã ãã®èšèªã®éçºã¯ã倿°ã宣èšããæãåçŽãªã¿ã¹ã¯ã§ãã倿Žããããšããäºå®ã«ã€ãªãããŸããã ES6ã¯let
ããã³const
ãarrow颿°ãããã³ä»ã®å€ãã®é©æ°ãå°å
¥let
ããããããéçºè
ã«å©çããããããŸãã
æã®è©Šç·Žã«èããããšãã§ããã³ãŒããäœæããã³ä¿å®ãããšããéçºè
ã®è² æ
ã¯å¢å€§ããŠããŸãã ãã®æçš¿ã§ã¯ã jscodeshift
ã¹ã¯ãªãããšjscodeshift
ããŒã«ã䜿çšããŠå€§èŠæš¡ãªã³ãŒããªãã¡ã¯ã¿ãªã³ã°ã®ã¿ã¹ã¯ãèªååããæ¹æ³ãåŠç¿ããŸããããã«ãããããšãã°ãèšèªã®æ°ããæ©èœã䜿çšããããã«ã³ãŒããç°¡åã«æŽæ°ã§ããŸãã
Codemod
Codemodã¯ãå€§èŠæš¡ãªã³ãŒãããŒã¹ããªãã¡ã¯ã¿ãªã³ã°ããããã«FacebookãéçºããããŒã«ã§ãã éçºè
ã¯çæéã§å€§éã®ã³ãŒããåç·šæã§ããŸãã ã¯ã©ã¹ã倿°ã®åå倿Žãªã©ã®å°ããªãªãã¡ã¯ã¿ãªã³ã°ã¿ã¹ã¯ã®å Žåãéçºè
ã¯IDEã䜿çšããŸãããã®ãããªå€æŽã¯éåžž1ã€ã®ãã¡ã€ã«ã«ã®ã¿åœ±é¿ããŸãã æ¬¡ã®ãªãã¡ã¯ã¿ãªã³ã°ããŒã«ã¯ãã°ããŒãã«æ€çŽ¢ãšçœ®æã§ãã å€ãã®å Žåãè€éãªæ£èŠè¡šçŸã䜿çšããŠæ©èœããŸãã ãããããã®æ¹æ³ã¯ãã¹ãŠã®å Žåã«é©ããŠããããã§ã¯ãããŸããã
Codemodã¯Pythonã§èšè¿°ãããŠãããæ€çŽ¢ã眮æã®ããã®åŒãå«ãå€ãã®ãã©ã¡ãŒã¿ãŒãåãå
¥ããŸãã
codemod -m -d /code/myAwesomeSite/pages --extensions php,html \ '<font *color="?(.*?)"?>(.*?)</font>' \ '<span style="color: \1;">\2</span>'
äžèšã®äŸã§ã¯ãã€ã³ã©ã€ã³ã¹ã¿ã€ã«ã䜿çšããŠè²ã瀺ã<font>
ã<span>
眮ãæããŠããŸãã æåã®2ã€ã®ãã©ã¡ãŒã¿ãŒã¯ãè€æ°ã®äžèŽãæ€çŽ¢ããå¿
èŠãããããšã瀺ããã©ã°ïŒ-mïŒãšãåŠçãéå§ãããã£ã¬ã¯ããªïŒ -d /code/myAwesomeSite/pages
ïŒã§ãã åŠçãããæ¡åŒµæ©èœãå¶éããããšãã§ããŸãïŒ -extensions php
ã html
ïŒã 次ã«ãæ€çŽ¢ãšçœ®æã®åŒãæäŸããŸãã 眮æåŒãæå®ãããŠããªãå Žåãå®è¡æã«å
¥åããããæ±ããããŸãã ãã®ããŒã«ã¯æ£åžžã«æ©èœããŸãããæ£èŠè¡šçŸã䜿çšããŠæ€çŽ¢ããã³çœ®æãè¡ãæ¢åã®ããŒã«ã«éåžžã«äŒŒãŠããŸãã
jscodeshift
jscodeshiftã¯ãªãã¡ã¯ã¿ãªã³ã°ããŒã«ããã¯ã¹ã®æ¬¡ã§ãã ãŸããFacebookã«ãã£ãŠéçºãããCodemodã¹ã¯ãªããã䜿çšããŠè€æ°ã®ãã¡ã€ã«ãåŠçããããã«èšèšãããŠããŸãã Node.jsã¢ãžã¥ãŒã«ãšããŠãjscodeshiftã¯ã·ã³ãã«ã§äŸ¿å©ãªAPIãæäŸããã å
éš ãã§ã¯ASTããASTïŒ æœè±¡æ§æããªãŒ ïŒå€æããŒã«ã§ããRecastã䜿çšããŸãã
ãªãã£ã¹ã
Recastã¯ãJavaScriptã³ãŒããè§£æããã³åçæããããã®ã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããNode.jsã¢ãžã¥ãŒã«ã§ãã ã³ãŒããæååãšããŠè§£æããASTæ§é ã«äžèŽãããªããžã§ã¯ããçæã§ããŸãã ããã«ãããéçºè
ã¯ãããšãã°é¢æ°å®£èšãªã©ã®ãã³ãã¬ãŒãã®ã³ãŒãã確èªã§ããŸãã
var recast = require("recast"); var code = [ "function add(a, b) {", " return a + b", "}" ].join("\n"); var ast = recast.parse(code); console.log(ast); //output { "program": { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add", "loc": { "start": { "line": 1, "column": 9 }, "end": { "line": 1, "column": 12 }, "lines": {}, "indent": 0 } }, ...........
äŸãããããããã«ã2ã€ã®æ°å€ã远å ãã颿°ãå«ãã³ãŒãè¡ãæž¡ããŸãã æååãè§£æããŠçµæã®ãªããžã§ã¯ããåºåãããšãASTã衚瀺ãããŸããFunctionDeclarationã颿°åãªã©ã衚瀺ãããŸããããã¯åãªãJavaScriptãªããžã§ã¯ãã§ãããããå¿
èŠã«å¿ããŠå€æŽã§ããŸãã ãã®åŸãprint颿°ãåŒã³åºããŠãæŽæ°ãããã³ãŒãè¡ãè¿ãããšãã§ããŸãã
ASTïŒæœè±¡æ§æããªãŒïŒ
åè¿°ã®ãšãããRecastã¯ã³ãŒãè¡ããASTãæ§ç¯ããŸãã ASTã¯ãæœè±¡ãœãŒã¹ã³ãŒãæ§æã®ããªãŒãã¥ãŒã§ãã åããªãŒããŒãã¯ããœãŒã¹ã³ãŒãå
ã®æ§é ã衚ããŸãã ASTExplorerã¯ãã³ãŒãããªãŒã®è§£æãšçè§£ã«åœ¹ç«ã€ãªã³ã©ã€ã³ããŒã«ã§ãã
ASTExplorerã䜿çšãããšãç°¡åãªã³ãŒãäŸã®ASTã衚瀺ã§ããŸãã fooãšããååã®å®æ°ã宣èšããæååå€'bar'
å²ãåœãŠãŸãã
const foo = 'bar';
ããã¯ãã®ãããªASTã«å¯Ÿå¿ããŸãïŒ

bodyé
åã«ã¯ã宿°ãå«ãVariableDeclaration
ãã©ã³ãããããŸãã ãã¹ãŠã®VariableDeclarations
ã¯ãéèŠãªæ
å ±ïŒååãªã©ïŒãå«ãid
屿§ããããŸãã fooã®ãã¹ãŠã®ã€ã³ã¹ã¿ã³ã¹ã®ååã倿ŽããCodemodã¹ã¯ãªãããäœæããå Žåããã®å±æ§ã䜿çšãããã¹ãŠã®ã€ã³ã¹ã¿ã³ã¹ãå埩åŠçããŠååã倿ŽããŸãã
ã€ã³ã¹ããŒã«ãšäœ¿çš
äžèšã®ããŒã«ãšãã¯ããã¯ã䜿çšããŠãjscodeshiftãæå€§éã«æŽ»çšã§ããŸãã ç§ãã¡ãç¥ã£ãŠããããã«ãããã¯Node.jsã¢ãžã¥ãŒã«ã§ããããããããžã§ã¯ããŸãã¯ã°ããŒãã«ã«ã€ã³ã¹ããŒã«ã§ããŸãã
npm install -g jscodeshift
ã€ã³ã¹ããŒã«åŸãå©çšå¯èœãªCodemodã¹ã¯ãªãããjscodeshift
ãšçµã¿åãããŠäœ¿çšââã§ããŸãã jscodeshiftãéæãããããšãäŒãããã©ã¡ãŒã¿ãŒãæäŸããå¿
èŠããããŸãã åºæ¬çãªæ§æã¯ã倿ãããã¡ã€ã«ãžã®ãã¹ã䜿çšããjscodeshift
åŒã³åºãã§ãã éèŠãªãã©ã¡ãŒã¿ãŒã¯ã倿ã¹ã¯ãªããã®å Žæ(-t)
ã§ããããŒã«ã«ãã¡ã€ã«ãŸãã¯Codemodã¹ã¯ãªãããã¡ã€ã«ã®URLãæå®ã§ããŸãã ããã©ã«ãã§ã¯ã jscodeshift
ã¯çŸåšã®ãã£ã¬ã¯ããªã®transform.jsãã¡ã€ã«ã§å€æã¹ã¯ãªãããæ¢ããŸãã
ä»ã®äŸ¿å©ãªãªãã·ã§ã³ã¯ããã¹ãã®å®è¡ïŒ-dïŒã§ããããã¯ã倿ãé©çšããŸããããã¡ã€ã«ãæŽæ°ããŸããã-vãªãã·ã§ã³ã¯ã倿ããã»ã¹ã«é¢ãããã¹ãŠã®æ
å ±ã衚瀺ããŸãã 倿ã¹ã¯ãªããã¯ã颿°ããšã¯ã¹ããŒãããåçŽãªJavaScriptã¢ãžã¥ãŒã«ã§ããCodemodã¹ã¯ãªããã§ãã ãã®é¢æ°ã¯ã次ã®ãã©ã¡ãŒã¿ãŒãåãå
¥ããŸãã
- fileInfo
- api
- ãªãã·ã§ã³
fileInfoãã©ã¡ãŒã¿ãŒã«ã¯ããã¹ããœãŒã¹ãªã©ãçŸåšã®ãã¡ã€ã«ã«é¢ãããã¹ãŠã®æ
å ±ãæ ŒçŽãããŸãã apiãã©ã¡ãŒã¿ãŒã¯ã findVariableDeclarators
ãrenameTo
ãªã©ã®jscodeshift
ãã«ããŒé¢æ°ãžã®ã¢ã¯ã»ã¹ãæäŸãããªããžã§ã¯ãã§ãã æåŸã«ããã©ã¡ãŒã¿ãŒã¯ãã³ãã³ãã©ã€ã³ããCodemodã«ãã©ã¡ãŒã¿ãŒãæž¡ãããšãã§ãããªãã·ã§ã³ã§ãã ããšãã°ããã¹ãŠã®ãã¡ã€ã«ã«ã³ãŒãã®ããŒãžã§ã³ã远å ããå Žåãã³ãã³ãã©ã€ã³jscodeshift -t myTransforms fileA fileB --codeVersion = 1.2
ä»ããŠæž¡ãããšãã§ãjscodeshift -t myTransforms fileA fileB --codeVersion = 1.2
ã ãã®å Žåãoptionsãã©ã¡ãŒã¿ãŒã«ã¯{codeVersion: '1.2'}
ãå«ãŸããŸãã
ãšã¯ã¹ããŒããã颿°å
ã§ã倿ãããã³ãŒããæååãšããŠè¿ãå¿
èŠããããŸãã ããšãã°ã const foo = 'bar',
ã³ãŒãè¡ãããã const foo
ãconst bar
眮ãæããŠå€æããå Žåãã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
export default function transformer(file, api) { const j = api.jscodeshift; return j(file.source) .find(j.Identifier) .forEach(path => { j(path).replaceWith( j.identifier('bar') ); }) .toSource(); }
ããã§ã¯ãäžé£ã®åŒã³åºãã§é¢æ°ãçµã¿åãããæåŸã«toSource()
ãåŒã³åºããŠã倿ãããã³ãŒãè¡ãçæããŸãã
ã³ãŒããè¿ããšããããã€ãã®èŠåãé å®ããå¿
èŠããããŸãã çä¿¡æåå以å€ã®æååãè¿ãããšã¯ãæåãã倿ãšèŠãªãããŸãã æååãå
¥åãšåãå Žåã倿ã¯å€±æãããšèŠãªãããäœãè¿ãããªãå Žåã倿ã¯äžèŠã§ããã jscodeshift
ã¯ãããã®çµæã䜿çšããŠãå€æçµ±èšãåŠçããŸãã
æ¢åã®Codemodã¹ã¯ãªãã
ã»ãšãã©ã®å Žåãéçºè
ã¯ç¬èªã®ã³ãŒããèšè¿°ããå¿
èŠã¯ãããŸãããå€ãã®å
žåçãªãªãã¡ã¯ã¿ãªã³ã°ã¢ã¯ã·ã§ã³ã¯ãã§ã«Codemodã¹ã¯ãªããã«å€æãããŠããŸãã ããšãã°ã js-codemod no-vars
ã¯ã倿°ã®äœ¿çšã«å¿ããŠãã¹ãŠã®varã€ã³ã¹ã¿ã³ã¹ãletãŸãã¯constã«å€æããŸãïŒ js-codemod no-vars
倿°ãåŸã§å€æŽãããå Žåã js-codemod no-vars
倿°ã倿Žãããªãå ŽåïŒã
js-codemod template-literals
ãæååã®é£çµããã¿ãŒã³æååã«çœ®ãæããŸããæ¬¡ã«äŸã瀺ããŸãã
const sayHello = 'Hi my name is ' + name; //after transform const sayHello = `Hi my name is ${name}`;
codemodã¹ã¯ãªããã®äœææ¹æ³
äžèšã®no-vars
ã¹ã¯ãªããã䜿çšããŠã³ãŒããäžæããè€éãªCodemodã¹ã¯ãªãããã©ã®ããã«æ©èœãããã確èªã§ããŸãã
const updatedAnything = root.find(j.VariableDeclaration).filter( dec => dec.value.kind === 'var' ).filter(declaration => { return declaration.value.declarations.every(declarator => { return !isTruelyVar(declaration, declarator); }); }).forEach(declaration => { const forLoopWithoutInit = isForLoopDeclarationWithoutInit(declaration); if ( declaration.value.declarations.some(declarator => { return (!declarator.init && !forLoopWithoutInit) || isMutated(declaration, declarator); }) ) { declaration.value.kind = 'let'; } else { declaration.value.kind = 'const'; } }).size() !== 0; return updatedAnything ? root.toSource() : null;
ãã®ã³ãŒãã¯ãno-varsã¹ã¯ãªããã®äžæ žã§ãã æåã«ããã£ã«ã¿ãŒã¯var
ã let
ããã³const
ãå«ããã¹ãŠã®VariableDeclaration
倿°ã§å®è¡ããããŠãŒã¶ãŒå®çŸ©é¢æ°isTruelyVar
ãåŒã³åºã2çªç®ã®ãã£ã«ã¿ãŒã«æž¡ãããvar宣èšã®ã¿ãè¿ããŸãã varã®æ§è³ªïŒããšãã°ãvarãã¯ããŒãžã£å
ã«ãããã2å宣èšãããŠããããçºçå¯èœãªé¢æ°å®£èšïŒã決å®ãããã®varãå®å
šã«å€æã§ãããã©ããã瀺ããŸãã isTruelyVar
ãã£ã«ã¿ãŒã«ãã£ãŠè¿ãããåisTruelyVar
ã¯ãforeachã«ãŒãã§åŠçãããŸãã
ã«ãŒãå
ã§ãvarãã«ãŒãå
ã«ãããã©ããã確èªããŸããæ¬¡ã«äŸã瀺ããŸãã
for(var i = 0; i < 10; i++) { doSomething(); }
varãã«ãŒãå
ã«ãããã©ããã倿ããã«ã¯ã芪ã®åã確èªã§ããŸãã
const isForLoopDeclarationWithoutInit = declaration => { const parentType = declaration.parentPath.value.type; return parentType === 'ForOfStatement' || parentType === 'ForInStatement'; };
var
ãã«ãŒãå
ã«ãããå€åããªãå Žåã¯ã const
ã«çœ®ãæããããšãã§ããŸãã æ€èšŒã¯ã var AssignmentExpression
ããã³UpdateExpression. AssignmentExpression
ãã£ã«ã¿ãªã³ã°ããããšã§å®è¡ã§ããŸãUpdateExpression. AssignmentExpression
UpdateExpression. AssignmentExpression
ã¯ã var
ãåæåãããå Žæãšæéã衚瀺ããŸããäŸïŒ
var foo = 'bar'; UpdateExpression , var , : var foo = 'bar'; foo = 'Foo Bar';
var
ã倿Žã®ããã«ãŒãå
ã«ããå Žåã let
䜿çšãããŸããããã¯ãã€ã³ã¹ã¿ã³ã¹ã®äœæåŸã«å€æŽã§ããããã§ãã ã¹ã¯ãªããã®æåŸã®è¡ã¯ãäœãã倿Žããããã©ããã確èªããçãããã¯ããã®å Žåããã¡ã€ã«ã®æ°ãããœãŒã¹ã³ãŒããè¿ãããŸãã ãã以å€ã®å ŽåãããŒã¿åŠçãå®è¡ãããªãã£ãããšã瀺ãnull
è¿ãããŸãã ãã®Codemodã¹ã¯ãªããã®å®å
šãªã³ãŒãã¯ãã¡ãã«ãããŸã ã
FacebookããŒã ã¯ãReactæ§æãæŽæ°ããReact APIã®å€æŽãåŠçããããã«ãããã€ãã®Codemodã¹ã¯ãªããã远å ããŸããã ããšãã°ã react-codemod sort-comp
ã¯ãReactã©ã€ããµã€ã¯ã«ã¡ãœããããœãŒãããŠã ESlint sort-compã«ãŒã«ã«æºæ ããŸãã
Reactã®ææ°ã®äººæ°ã®ããCodemodã¹ã¯ãªããã¯React-PropTypes-to-prop-types
ãããã¯æè¿ã®Reactã®å€æŽã«å¯ŸåŠããã®ã«åœ¹ç«ã¡ãŸãã ã PropTypes
ã䜿çšããæ¹æ³PropTypes
ãäžå€ã§PropTypes
ãŸããã
以äžã®äŸã¯ãã¹ãŠçå®ã§ãã
Reactãã€ã³ããŒãããããã©ã«ãã®ã€ã³ããŒãããPropTypes
ã«ã¢ã¯ã»ã¹ããŸãïŒ
import React from 'react'; class HelloWorld extends React.Component { static propTypes = { name: React.PropTypes.string, } .....
Reactãã€ã³ããŒãããPropTypesã®ååä»ãã€ã³ããŒããäœæããŸãã
import React, { PropTypes, Component } from 'react'; class HelloWorld extends Component { static propTypes = { name: PropTypes.string, } .....
stateless
ã³ã³ããŒãã³ãã®å¥ã®ãªãã·ã§ã³ïŒ
import React, { PropTypes } from 'react'; const HelloWorld = ({name}) => { ..... } HelloWorld.propTypes = { name: PropTypes.string };
åããœãªã¥ãŒã·ã§ã³ãå®è£
ãã3ã€ã®æ¹æ³ãååšãããããæ€çŽ¢ãšçœ®æã«æ£èŠè¡šçŸã䜿çšããããšãé£ãããªããŸãã ã³ãŒãã«3ã€ã®ãªãã·ã§ã³ããã¹ãŠããå Žåãæ¬¡ã®æäœãè¡ãããšã§æ°ããPropTypesãã¿ãŒã³ã«ç°¡åã«åãæ¿ããããšãã§ããŸãã
jscodeshift src/ -t transforms/proptypes.js
ãã®äŸã§ã¯ã react-codemod
ããPropTypes Codemodã¹ã¯ãªãããreact-codemod
ãããããžã§ã¯ãã®transforms
ãã£ã¬ã¯ããªã«è¿œå ããŸããã ã¹ã¯ãªããã¯import PropTypes from 'prop-types
ã import PropTypes from 'prop-types
ã远å ããŸãã åãã¡ã€ã«ã«ã€ããŠããã¹ãŠã®React.PropTypes
ãPropTypes
眮ãæããŸãã
çµè«
Facebookã¯ã³ãŒããµããŒãã®å®è£
ãéå§ããéçºè
ã¯çµ¶ããå€åããAPIãšã³ãŒããæäœããããã®å®çšçãªã¢ãããŒãã«é©å¿ã§ããããã«ãªããŸããã Javascript Fatigue
ã¯å€§ããªåé¡ã«ãªã£ãŠããŸãããããŸã§èŠãŠããããã«ãæ¢åã®ã³ãŒããæŽæ°ããããã»ã¹ãæ¯æŽããããŒã«ã¯ããã®ãœãªã¥ãŒã·ã§ã³ã«å€§ããè²¢ç®ããŠããŸãã
ãµãŒããŒéçºã®äžçã§ã¯ãããã°ã©ããŒã¯å®æçã«ç§»è¡ã¹ã¯ãªãããäœæããŠããŒã¿ããŒã¹ãææ°ã®ç¶æ
ã«ä¿ã¡ããŠãŒã¶ãŒã«ææ°ããŒãžã§ã³ãéç¥ããŸãã JavaScriptã©ã€ãã©ãªã®äœæè
ã¯ãCodemodã¹ã¯ãªãããç§»è¡ã¹ã¯ãªãããšããŠæäŸããéèŠãªå€æŽãå ããããæ°ããããŒãžã§ã³ããªãªãŒã¹ããããšãã«ãæŽæ°ã®ããã«ã³ãŒããç°¡åã«åŠçã§ããŸãã
ã€ã³ã¹ããŒã«ãŸãã¯ã¢ããã°ã¬ãŒãæã«èªåçã«å®è¡ãããCodemodã¹ã¯ãªããã䜿çšãããšãããã»ã¹ãé«éåããæ¶è²»è
ã®ä¿¡é Œãé«ããããšãã§ããŸãã ããã«ããã®ãããªã¹ã¯ãªããããªãªãŒã¹ããã»ã¹ã«å«ããããšã¯ãæ¶è²»è
ã«ãšã£ãŠæçã§ããã ãã§ãªããæŽæ°ã«äŒŽãäŸããã¥ãŒããªã¢ã«ã®ã³ã¹ããåæžããŸãã
ãã®æçš¿ã§ã¯ãCdemodã¹ã¯ãªãããšjscodeshift
æ§è³ªãããã³ããããè€éãªã³ãŒããã©ãã ãè¿
éã«æŽæ°ã§ãããã調ã¹ãŸããã Codemodããå§ããŠASTExplorerãjscodeshiftãªã©ã®ããŒã«ã«ASTExplorer
ãšãããŒãºã«åãããŠCodemodã¹ã¯ãªãããäœæããæ¹æ³ãåŠã¶ããšãã§ããŸãã ãŸããåºç¯ãªæ¢è£œã¢ãžã¥ãŒã«ã®ååšã«ãããéçºè
ã¯ç©æ¥µçã«ãã¯ãããžãŒã倧è¡ã«å®£äŒã§ããŸãã
翻蚳è
泚ïŒJSConfEUã§ãã®ãããã¯ã«é¢ããè峿·±ããã¬ãŒã³ããŒã·ã§ã³ããããŸããã