@if (0)==(0) echo off
@rem http://computer-technology.hateblo.jp/entry/20131025/p1
setlocal
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set "PATH=%PATH%;%cd%\graphviz\release\bin"
set PLANTUML_LIMIT_SIZE=8192
@rem 説明:
@rem PlantUMLのシーケンス図定義をクラス図定義に変換します。
@rem Convert PlantUML sequence diagram definition into class diagram definition.
@rem Usage:
@rem sdcd.bat [path]
@rem ####################
@rem Batch.
@rem ####################
@rem ====================
@rem Batch main.
@rem ====================
set "pusin=%~1"
set "DebugPrint=false"
set rv=1
if "!DebugPrint!"=="true" call ::L_BAT_printInfo %*
call :L_BAT_plantuml_main
@rem ====================
@rem Exit.
@rem ====================
@rem echo.
@rem pause
@rem echo 終了するには何かキーを押してください . . .
@rem pause>nul
exit /b !rv!
goto :eof
@rem ====================
@rem printInfo.
@rem ====================
:L_BAT_printInfo
if not "!DebugPrint!"=="true" goto :eof
@rem 変数 拡張子 ダイアグラム オプション 型
@rem pusin .txt シーケンス図 定義
@rem pusdd .pusdd.txt シーケンス図 定義
@rem puspp .pusdd.preproc シーケンス図 -preproc 定義
@rem pusim .pusim.png シーケンス図 -tpng 図
@rem pusid .pusid.txt シーケンス図 -metadata 定義
@rem pusat .pusat.atxt シーケンス図 -ttxt 図
@rem pusue .pusue.txt シーケンス図 -encodeurl 他
@rem pusud .pusud.txt シーケンス図 -decodeurl 定義
@rem pucdd .pucdd.txt クラス図 定義
@rem pucpp .pucdd.preproc クラス図 -preproc 定義
@rem pucim .pucim.png クラス図 -tpng 図
@rem pucid .pucid.txt クラス図 -metadata 定義
@rem pucat .pucat.atxt クラス図 -ttxt 図
@rem pucue .pucue.txt クラス図 -encodeurl 他
@rem pucud .pucud.txt クラス図 -decodeurl 定義
echo pusin
echo +-^> pusdd
echo +-^> puspp
echo ^| +-^> pucdd
echo ^| +-^> pucpp
echo ^| +-^> pucim
echo ^| ^| +-^> pucid
echo ^| +-^> pucat
echo ^| +-^> pucue
echo ^| +-^> pucud
echo +-^> pusim
echo ^| +-^> pusid
echo +-^> pusat
echo +-^> pusue
echo +-^> pusud
echo.
echo pusin=!pusin!
set /a rv=0
goto :eof
@rem ====================
@rem plantuml_main.
@rem ====================
:L_BAT_plantuml_main
if "!DebugPrint!"=="true" (
echo # !pusin!
)
if not exist "!pusin!" (
set /a rv=1
goto :eof
)
if "!DebugPrint!"=="true" (
echo ## Seaquense diagram.
)
set "pusdd=!pusin!"
set "pusdd=!pusdd:.txt=.pusdd.txt!"
set "pusdd=!pusdd:.pusdd.pusdd.txt=.pusdd.txt!"
set "puspp=!pusdd:.pusdd.txt=.pusdd.preproc!"
if "!DebugPrint!"=="true" (
echo # !pusdd!
)
if not "!pusin!"=="!pusdd!" (
copy "!pusin!" "!pusdd!"
)
call :Lc_PlantUML "!pusdd!"
if "!DebugPrint!"=="true" (
echo ## Class diagram.
)
set "pucdd=!pusdd!"
set "pucdd=!pucdd:.pusdd.txt=.pucdd.txt!"
set "pucdd=!pucdd:.txt=.pucdd.txt!"
set "pucdd=!pucdd:.pucdd.pucdd.txt=.pucdd.txt!"
if "!DebugPrint!"=="true" (
echo # !pucdd!
)
call :Lc_JS "!puspp!" > "!pucdd!"
call :Lc_PlantUML "!pucdd!"
set /a rv=0
goto :eof
@rem ====================
@rem Echo ErrorLevel.
@rem ====================
:L_echoErrorLevel
@rem echo BAT L_echoErrorLevel ....................
echo BAT %0 errorlevel=!errorlevel!
@rem echo.
goto :eof
@rem ====================
@rem Call PlantUML.
@rem ====================
:Lc_PlantUML
@rem echo BAT Lc_PlantUML ....................
set "puxdd=%~1"
set "puxdd=!puxdd:dd.txt=dd.txt!"
set "puxpp=!puxdd:dd.txt=dd.preproc!"
set "puxim=!puxdd:dd.txt=dd.png!"
set "puxid=!puxdd:dd.txt=id.txt!"
set "puxat=!puxdd:dd.txt=at.atxt!"
set "puxue=!puxdd:dd.txt=ue.txt!"
set "puxud=!puxdd:dd.txt=ud.txt!"
if "!DebugPrint!"=="true" (
echo puxdd=!puxdd!
echo puxpp=!puxpp!
echo puxim=!puxim!
echo puxid=!puxid!
echo puxat=!puxat!
echo puxue=!puxue!
echo puxud=!puxud!
)
if "!DebugPrint!"=="true" (
echo # !puxpp!
)
java -jar plantuml.jar -preproc "!puxdd!"
if "!DebugPrint!"=="true" (
echo # !puxim!
)
java -jar plantuml.jar "!puxdd!"
if "!DebugPrint!"=="true" (
echo # !puxid!
)
java -jar plantuml.jar -metadata "!puxim!" > "!puxid!"
if "!DebugPrint!"=="true" (
echo # !puxat!
)
java -jar plantuml.jar -ttxt "!puxdd!"
if "!DebugPrint!"=="true" (
echo # !puxue!
)
for /f "usebackq" %%z in (
`java -jar plantuml.jar -encodeurl "!puxdd!"`
) do (
echo %%z>"!puxue!"
if "!DebugPrint!"=="true" (
echo # !puxud!!
)
java -jar plantuml.jar -decodeurl "%%z" > "!puxud!"
)
goto :eof
@rem ====================
@rem Call JScript.
@rem ====================
:Lc_JS
@rem if "!DebugPrint!"=="true" echo BAT %0 %# ....................j
set "jsargs=%*"
if "!jsargs!"=="" (
cscript.exe //nologo //e:JScript "%~f0"
) else (
cscript.exe //nologo //e:JScript "%~f0" !jsargs!
)
@rem if "!DebugPrint!"=="true" call :L_echoErrorLevel
goto :eof
@end
// ####################
// JScript.
// ####################
var wsh = new ActiveXObject("WScript.Shell");
var env = wsh.Environment("PROCESS");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var DebugPrint = false;
if (env.item("DebugPrint") == "true") {
DebugPrint = true;
}
// ====================
// Output Args.
// ====================
function Output_Args(jsargs) {
// WScript.StdErr.WriteLine("JS Output_Args ....................");
WScript.StdErr.WriteLine("JS [" + jsargs.length + "]" + jsargs + ".");
for (var argIdx = 0; argIdx < jsargs.length; ++argIdx) {
WScript.StdErr.WriteLine("JS Args[" + argIdx + "]=" + jsargs[argIdx] + ".");
}
return 0;
}
// ====================
// Unknown arg.
// ====================
function UnknownArg(jsargs) {
WScript.StdErr.WriteLine("JS UnknownArg ....................");
Output_Args(jsargs);
return 1;
}
function runCommand(cmd_str) {
var shell = new ActiveXObject("WScript.Shell");
// コマンドを実行
var oe = shell.Exec(cmd_str);
var r = oe.StdOut.ReadAll();
return r;
}
if (! Object.keys){
Object.keys = function (obj){
var keys = [];
for (var i in obj){
if (obj.hasOwnProperty(i)){
keys.push(i);
}
}
return keys;
};
}
// ********************
// PuClassNameMap
// クラス集合を表します。
// クラス名をキーにした連想配列で複数のクラスを管理します。
// ********************
PuClassNameMap = function () {
this.puClassNameMap = {};
};
// ====================
// PuClassNameMap.setPuClass
// ====================
PuClassNameMap.prototype.setPuClass = function (className) {
if (! this.puClassNameMap[className]) {
this.puClassNameMap[className] = new PuClass(className);
}
return this.puClassNameMap[className];
};
// ====================
// PuClassNameMap.getNameList
// 管理しているクラスのクラス名の一覧を取得します。
// クラス名の一覧はクラス名の昇順です。
// 但しクラス名「Python」は常に先頭とします。
// これはクラス図上でクラス名「Python」を上部に配置されやすくするためです。
// ====================
PuClassNameMap.prototype.getNameList = function () {
function _sortClassName(str1, str2) {
if (str1 == "Python") { return -1; }
if (str2 == "Python") { return 1; }
if (str1 == str2) { return 0; }
if (str1 < str2) { return -1; }
if (str1 > str2) { return 1; }
}
return Object.keys(this.puClassNameMap).sort(_sortClassName);
};
// ====================
// PuClassNameMap.getPuClass
// ====================
PuClassNameMap.prototype.getPuClass = function (name) {
return this.puClassNameMap[name];
};
// ********************
// PuClass
// クラスを表します。
// ********************
PuClass = function (name) {
this.name = name;
this.methodNameMap = {};
var color = (Math.random() * 0xFFFFFF | 0).toString(16);
var randomColor = "#" + ("000000" + color).slice(-6);
this.color = randomColor;
};
// ====================
// PuClass.getName
// ====================
PuClass.prototype.getName = function () {
return this.name;
};
// ====================
// PuClass.setMethodName
// クラスのメソッドを登録します。
// ====================
PuClass.prototype.setMethodName = function (methodName) {
this.methodNameMap[methodName] = {};
return this;
};
// ====================
// PuClass.getMethodNameList
// クラスのメソッド名一覧を取得します。
// ====================
PuClass.prototype.getMethodNameList = function () {
return Object.keys(this.methodNameMap).sort();
};
// ====================
// PuClass.getPuClassDefLineList
// クラス定義を取得する。
// ====================
PuClass.prototype.getPuClassDefLineList = function () {
var puClassDefLineList = [];
puClassDefLineList.push("class " + this.name + " {");
var methodNameList = this.getMethodNameList();
for (var methodNameListIdx in methodNameList) {
puClassDefLineList.push(" " + methodNameList[methodNameListIdx]);
}
puClassDefLineList.push("}");
return puClassDefLineList;
};
// ********************
// PuMessageMap
// メッセージ集合を表します。
// ********************
PuMessageMap = function (puClassNameMap) {
this.larmMap = {};
this.ftamMap = {};
this.puClassNameMap = puClassNameMap;
};
// ====================
// PuMessageMap.setMessage
// ====================
PuMessageMap.prototype.setMessage = function (from, arrow, to, message) {
var fat = null;
var fta = null;
if (arrow == "<->") {
fat = [from, "<->", to].join(" ");
fta = [from, to, "<->"].join(" ");
} else {
fat = [from, "->", to].join(" ");
fta = [from, to, "->"].join(" ");
}
if (! this.larmMap[fat]) {
this.larmMap[fat] = {};
}
this.larmMap[fat][message] = {};
if (! this.ftamMap[fta]) {
this.ftamMap[fta] = {};
}
this.ftamMap[fta] = fat;
};
// ====================
// PuMessageMap.getPuRelationDefList
// 関連定義一覧を取得します。
// ====================
PuMessageMap.prototype.getPuRelationDefList = function () {
var puRelationDefList = [];
var fatList = Object.keys(this.larmMap).sort();
var ftaList = Object.keys(this.ftamMap).sort();
for (var ftaListIdx in ftaList) {
var fatListKey = this.ftamMap[ftaList[ftaListIdx]];
var fatListKeyDsp = fatListKey
fatListKeyDsp = fatListKeyDsp
.replace(/ -> /g, " --> ")
.replace(/ <- /g, " <-- ")
.replace(/ <-> /g, " <--> ");
// 関連定義をfrom[1]=クラス名(元)、arrow[2]=矢印、to[3]=クラス名(先)に分ける。
var fatListKeyDspSplit = fatListKeyDsp.split(/ +/);
// 矢印が一方向の場合、クラス名(先)の色を求める。
var color = "#000000";
if (fatListKeyDspSplit[1] == "-->") {
color = this.puClassNameMap.puClassNameMap[fatListKeyDspSplit[2]].color;
}
if (fatListKeyDspSplit[1] == "<--") {
color = this.puClassNameMap.puClassNameMap[fatListKeyDspSplit[1]].color;
}
// 矢印に色指定を付与し、関連定義を組み立てる。
var arrow = fatListKeyDspSplit[1].substring(0, 2) + "[" + color + "]" + fatListKeyDspSplit[1].substring(2);
fatListKeyDsp = [fatListKeyDspSplit[0], arrow, fatListKeyDspSplit[2]].join(" ");
puRelationDefList.push(
[
fatListKeyDsp,
"\"" + Object.keys(this.larmMap[fatListKey]).sort().join("\\n") + "\""
].join(" : ")
);
}
return puRelationDefList;
};
// ********************
// ********************
// ====================
// SdCd : PlantUMLのシーケンス図定義をクラス図定義に変換します。
// ====================
function SdCd(jsargs) {
if (DebugPrint == true) {
WScript.StdErr.WriteLine("JS SdCd ....................");
Output_Args(jsargs);
}
// シーケンス図定義の矢印の種類を統一するための連想配列。矢印の向きは維持する。
// 矢印の種類には「->」、「-//」、「-\\」がある。これらを「->」に統一する。
// シーケンス図の「メッセージ」をクラスのメソッドとし、クラス図では「関連」とする。
var arrowMap = {
"->" : "->",
"<-" : "<-",
"<->" : "<->",
"->>" : "->",
"<<-" : "<-",
"<<->>" : "<->",
"-/" : "->",
"/-" : "<-",
"/-/" : "<->",
"-//" : "->",
"//-" : "<-",
"//-//" : "<->",
"-\\" : "->",
"\\-" : "<-",
"\\-\\" : "<->",
"-\\\\" : "->",
"\\\\-" : "<-",
"\\\\-\\\\" : "<->"
};
var arrowList = new Array();
for (var allow in arrowMap) {
arrowList.push(allow);
}
// 「メッセージ」を降順で取得する。
function _desc(str1, str2) {
if (str1 == str2) { return 0; }
if (str1 < str2) { return 1; }
if (str1 > str2) { return -1; }
}
var arrowsRegexp = new RegExp(arrowList.sort(_desc).join("|"));
var strmSdd = WScript.StdIn;
var strmCdd = WScript.StdOut;
var FORREADING = 1;
var TRISTATE_FALSE = 0;
if (jsargs.length != 0) {
strmSdd = fso.OpenTextFile(jsargs[0], FORREADING, false, TRISTATE_FALSE);
}
// メッセージ定義を取得する。
var titleLine = null;
var messageDefLineList = [];
while (! strmSdd.AtEndOfStream) {
var lineSdd = strmSdd.ReadLine().replace(/(^\s+|\s+$)/g, "");
// 図題を取得する。
if (/^title /.test(lineSdd)) {
titleLine = lineSdd;
// 不要行を除外する。おそらく不十分。
} else if (/^==/.test(lineSdd)) {
;
// メッセージ定義を取得する。
} else if (arrowsRegexp.test(lineSdd)) {
messageDefLineList.push(lineSdd);
}
}
// メッセージ定義を解析する。
// メッセージの両端のクラスをクラス集合に登録する。
// メッセージをメッセージ集合に登録する。
var puClassNameMap = new PuClassNameMap();
var puMessageMap = new PuMessageMap(puClassNameMap);
for (var messageDefLineListIdx = 0; messageDefLineListIdx < messageDefLineList.length; ++messageDefLineListIdx) {
// larm[0]=メッセージ定義全体、larm[1]=クラス名(左)、larm[2]=矢印、larm[3]=クラス名(右)、larm[4]=メッセージを取得する。
var larm = messageDefLineList[messageDefLineListIdx].match(new RegExp("^([^ :]+) +([^ ]+) +([^ :]*) +: +(.*)$"));
var larmLeft = 1;
var larmArrow = 2;
var larmRight = 3;
var larmMessage = 4;
// クラス名(左)をクラス集合に登録する。
var leftClass = puClassNameMap.setPuClass(larm[larmLeft]);
// クラス名(右)をクラス集合に登録する。
var rightClass = puClassNameMap.setPuClass(larm[larmRight]);
// 矢印に付加されているo、xを削除する。
larm[larmArrow] = larm[larmArrow].replace(/[ox]/g, "");
// 矢印の種類を統一する。
larm[larmArrow] = arrowMap[larm[larmArrow]];
// メッセージを矢印の先のクラスのメソッドとして登録する。
var larmFrom = 1;
var larmTo = 3;
if (larm[larmArrow].slice(-2) == "->") {
rightClass.setMethodName(larm[larmMessage]);
}
// メッセージを矢印の先のクラスのメソッドとして登録する。
if (larm[larmArrow].slice(0, 2) == "<-") {
leftClass.setMethodName(larm[larmMessage]);
larmFrom = 3;
larmTo = 1;
}
// クラス間の関連をメッセージ集合に登録する。
puMessageMap.setMessage(larm[larmFrom], larm[larmArrow], larm[larmTo], larm[larmMessage]);
}
// クラス図定義の開始を出力する。
strmCdd.WriteLine("@startuml");
// 図題を出力する。
if (titleLine != null) {
strmCdd.WriteLine(titleLine);
strmCdd.WriteLine();
}
// クラス名一覧を取得する。
puClassNameList = puClassNameMap.getNameList();
// クラス定義を出力する。
strmCdd.WriteLine("' Classes.");
for (var puClassNameListIdx in puClassNameList) {
var puClassName = puClassNameList[puClassNameListIdx];
var puClass = puClassNameMap.getPuClass(puClassName);
var puClassDefLineList = puClass.getPuClassDefLineList();
for (var puClassDefLineListIdx in puClassDefLineList) {
strmCdd.WriteLine(puClassDefLineList[puClassDefLineListIdx]);
}
strmCdd.WriteLine("");
}
// 関連一覧を取得する。
puRelationDefList = puMessageMap.getPuRelationDefList();
// 関連定義を出力する。
strmCdd.WriteLine("' Relations.");
for (var puRelationDefListIdx in puRelationDefList) {
var puRelationDef = puRelationDefList[puRelationDefListIdx];
strmCdd.WriteLine(puRelationDef);
}
strmCdd.WriteLine("");
// クラス図定義の終了を出力する。
strmCdd.WriteLine("'");
strmCdd.WriteLine("@enduml");
return 0;
}
// ====================
// JScript main.
// ====================
var rv = 0;
var jsargs = new Array();
for (var argIdx = 0; argIdx < WScript.Arguments.length; ++argIdx) {
jsargs[argIdx] = WScript.Arguments(argIdx);
}
var ary = new Array();
ary = jsargs.slice(0, jsargs.length);
if (0 == 1) {
rv = rv + 1;
} else if ((WScript.Arguments.length >= 1) && (WScript.Arguments.length <= 1)) {
rv = rv + SdCd(ary);
} else {
rv = rv + UnknownArg(ary);
}
WScript.quit(rv);
0 件のコメント:
コメントを投稿