[[JHIPSTER一覧]]

*** 目次 [#s90f7b0e]
#contents


* はじめに [#a6f92448]
jhipsterでなにが、うれしいかというと、
クラス図をJDLという簡易な設定さえ書けば、

一応動作する画面が、できるということだと思う。

リレーションとかも、考慮済みのテンプレートが、いい感じに、頑張ってくれる。


でも、すでに、自分のプロジェクトのひな型ができている場合がある。

成果物として、望まれているのは、自分のプロジェクトの形式に沿ったコード

だったりする。

そうなるとひな形のほうを修正したい。

* もし、ページを追加したい場合 [#xd2fe6b8]

例として、おみくじページの追加例がある。モジュールと呼んでいるらしい。

https://www.jhipster.tech/modules/creating-a-module/

** モジュール作成のジェネレータもある [#xacd1c6d]

https://github.com/jhipster/generator-jhipster-module

*** ためしに使ってみる [#wce535e0]

自分がデザインとかしたページのテンプレがつくれたらいいな。

インストールする

 npm install -g generator-jhipster-module

自分用のモジュールのディレクトリ作る

 mkdir generator-jhipster-mymod
 cd generator-jhipster-mymod

git使うので、gitのリポジトリとするための初期化
 git init

yoコマンドで、作るための質問に答える。(Windowsの場合、実行は、PowerShell)
 yo jhipster-module

質問はこんな感じでした。


 ? What is the base name of your module? (helloworld)

そのまま、エンター、モジュール名だろうか。

 ? Give a description of your module

モジュールの説明だろうか

 description-hello

と、回答

 ? Do you want to enable hooks for your module from JHipster generator? (Use arrow keys)
 > No, This is a stand alone module
   Yes, Enable post entity hook

とりあえずNoが、えらばれていたので、そのままEnter

 ? What is your GitHub username?

GitHub使うこと前提?とりあえず、入力

 ? Who are you? Firstname Lastname (Firstname Lastname)

氏名を入力
 ? Your email?

メアドを入力

 ? Your home page url?
ホームページを入力

 > No license
   Apache License 2.0
   GNU General Public License v3.0
   MIT License

そのまま、NoLicenseにした

*** 結果 [#s7a66243]

    create package.json
    create .editorconfig
    create .eslintignore
    create .eslintrc.json
    create .gitattributes
    create .gitignore
    create .travis.yml
    create README.md
    create test\test-app.js
    create generators\app\index.js
    create generators\app\templates\dummy.txt
 
 ##### USAGE #####
 To begin to work:
 - launch: npm install or yarn install
 - link: npm link or yarn link
 - test your module in a JHipster project:
     - go into your JHipster project
     - link to your module: npm link generator-jhipster-helloworld or yarn link 
 generator-jhipster-helloworld
     - launch your module: yo jhipster-helloworld
 - then, come back here, and begin to code!


と表示された。

これで、自分のJHIPSTERで作成したプロジェクトに、ディレクトリを移動して、

 npm link generator-jhipster-helloworld
 
 yo jhipster-helloworld

で、確認できるみたい。

実際に、やってみると、

 You don't seem to have a generator with the name “jhipster:modules” installed.
 But help is on the way:

と、エラーがでた。

わからん。


* もし、修正したいひな形が下記のいずれかの場合 [#je94886e]
JHIPSTERのサブモジュール拡張機能の通称:ブループリント

を使ったほうがいいかもしれない。

https://www.jhipster.tech/modules/creating-a-blueprint/

** ブループリントで拡張可能な、箇所 [#xdb73b75]
- common
- client
- server
- entity
- entity-client
- entity-server
- entity-i18n
- languages
- spring-controller
- spring-service

*** ブループリントのジェネレータ [#b2d425ae]

ジェネレータもある、質問に答えていけば、ブループリントのジェネレータが生成されるとある。

https://github.com/jhipster/generator-jhipster-blueprint


* JDLからのパラメータ [#y48f88a2]
以下は、JHIPSTERのソースコードを読んで、直接改造、するための解析

JDLからのパラメータは、どのように拾えるのか。


** テンプレートファイル [#scf5c772]

テンプレートは、yoというツールを使っていると思う。
JDLをyoで使える形式に変換するのが、JHIPSTERだとすると、テンプレートから、変数を引っ張ってくればいいんじゃなかろうか。

generator-jhipster-vuejs
は、node_modulesフォルダに、格納されている
さらにその配下の、generatorフォルダを、今回解析してみようと思う。

node_moduleフォルダにある、generatorフォルダが怪しいと思っておこう。

どうやら、jhipsterのコマンドは、

アプリフォルダ/node_moduless/generator-jhipster/cli
の

 commands.js

ファイルに記載があった。

ただし、ここから、どこかに行くというわけでは、ない。

モジュール側が、リスナーしているようだ。

例えば、import-jdl

というコマンドの場合、次のファイルが、このコマンドを待ち構えるモジュールとして作られている。

 import-jdl.js

たぶん、次の文が、リスナーの実装っぽい。確認してないけど。。。GREPしたらここしか、import-jdlの文言含んでなかった。

 const statistics = require('../generators/statistics');
 
 statistics.sendSubGenEvent('generator', 'import-jdl');



* テンプレートのソースコードを読んで、テンプレートの書き方を逆引きにしてみる [#s8b46879]

yoのテンプレートの書き方だけでは、役不足だ。JDL言語で簡易に書いた、

クラス図の情報が、どのように、テンプレートの引数にわたってくるのかが、知りたいよね?

だから、テンプレートファイルをみて、解析してみるとする。

とりあえず、エンティティまわりをみてみたいので、下記のファイルを観察してみるとする。

EntityRepository.java.ejs

** コメントの書き方 [#w45c20e8]
 <%#
 
 -%>

** パッケージ名 [#v8c39201]
 package <%=packageName%>.repository;

** エンティティクラス名 [#u1109869]
テーブル名とかに使用
 <%=asEntity(entityClass)%>
 
または
 
 <%=entityClass%>
 

** 多対多の場合 [#vf1b04ac]
 <%_ if (fieldsContainOwnerManyToMany) { _%>
 
 <%_ } _%>




** データベースの種類がsqlの場合 [#m61c4897]
 <%_ if (databaseType === 'mongodb') { _%>
 
 <%_ } _%>


** SQLのselect句 [#a296506c]
 select <%= entityInstance %> 

** リレーションしてる文だけ必要なループ [#l1799878]
 <% for (idx in relationships) {
    if (relationships[idx].relationshipType === 'many-to-many' && relationships[idx].ownerSide === true) { %>
    left join fetch <%=entityInstance%>.<%=relationships[idx].relationshipFieldNamePlural%><%} }%>",

** リレーションのjavadocが定義されているかどうかチェック [#ra656797]
 for (idx in relationships) {
     if (typeof relationships[idx].javadoc != 'undefined') {
         
     }
 }



** フィールドでループ [#d9159b14]
  <% for (idx in fields) {
 
    } _%>

** フィールドのjavadocが定義されているかどうかチェック [#yfb1dc1d]
   for (idx in fields) {
       if (typeof fields[idx].javadoc != 'undefined') {
           
       }
   }


** 未確認の引数 [#v805dd3d]
 fieldsContainBlob
 
 importJsonIgnoreProperties
 
 importApiModelProperty
 
 importJsonIgnore
 
 fieldsContainUUID
 
 prodDatabaseType
 
 hasTextBlob
 
 validation
 
 searchEngine
 
 fieldsContainBigDecimal



* jhipster entityとしたときのメッセージの場所 [#z81bf26d]
たまたま、みつけたから、メモしておこう。

node_modules\generator-jhipster\generators\entity\prompts.js

にある。


* JDLのパーサー [#n21d66b4]
jhiCore.JDLImporter

のimportメソッド

でパースされているようです。

JDLで、認識できる文法を、自分のプロジェクトに合わせれたら、いいんじゃないだろうか?

たとえば、案件ごとに、定義書は、大体似ては、いるが、若干、違う。

それをJDLに、まとめさせて、テンプレートに流すことができたら、すごくよさそうだ。

** JDLImporter [#zc4db629]
node_modules\jhipster-core\lib\jdl\jdl_importer.jsにて

  import() {
    const parsedJDLContent = parseFiles(this.files);

って書いてありました。

 function parseFiles(files) {
   return JDLReader.parseFromFiles(files);
 }

JDLReaderを調べる必要がありそうです。

 const JDLReader = require('../reader/jdl_reader');

とあるので、

アプリのフォルダ/node_modules/jhipster-core/lib/reader/jdl_reader を調べる必要がありそうです。

ちょと、ここで、発見したのですが、removeInternalJDLComments というメソッドで、

JavaDocコメントをパース前に、削除して、台無しにしてしまっているようにみえます。

だれか、修正してくれないかぁ。まあ、いいや、解析を進めよう。


 const parser = require('../dsl/api');

とあるので、

 /node_modules/jhipster-core/jhipster-core/lib/dsl/api.js

を見てみると、


まず、JDL言語の字句解析は、
 const lexResult = JDLLexer.tokenize(input);

でおこなっており、

パーサーは、
 const parserSingleton = JDLParser.getParser();

でパーサーの配列で取得できるようになっており、

デフォルトでは、progが使われているのが分かった。

で、パースをうごかしているのは、
 buildAst(cst);

で、行っているようだ。汎用的につくってあるので、buildAstは、解析しないことにする。

** lexer.js [#u609c145]

自分用にコマンドを追加するには、

 アプリフォルダ/node_modules/jhipster-core\lib/dsl/lexer.js

に、下記のような感じで、認識させる単語を登録させる、必要があるだろう。

たとえば、認識させたい単語が 
 required

ならば、それをパーサーに伝える際には、

 'REQUIRED'
として、伝えたいならば、

 createToken({ name: 'REQUIRED', pattern: 'required' });

と書かなくてはならない。


この 'REQUIRED'としたものは、node_modules\jhipster-core\lib\dsl\jdl_parser.jsにて

 const LexerTokens = require('./lexer').tokens;

としており、次のように文法のルール定義に記載されている。

 { ALT: () => this.CONSUME(LexerTokens.REQUIRED) },

*** 実務でありそうな要件を考えてみる。 [#i39ea552]

項目の定義がエクセルで、設計済みで、JDLでは、不足しているカラムがあるんだよなー。ってのが、一番ありそうなんじゃ、ないだろうか?

となると、やりたいことは、

カラムと、その中身の定義を、字句解析と、構文解析に追加する、方法が分かりたいということだ。

近そうな記述は、最大値の認識させ方かなと思って、解析を進めてみる。

** maxlengthに着目して、解析をする [#a59174a3]
*** lexer.jsでのmaxlength [#h19f6f0f]
 createToken({
   name: 'MAXLENGTH',
   pattern: 'maxlength',
   categories: [tokens.MIN_MAX_KEYWORD]
 });

*** jdl_parser.jsでの、MIN_MAX_KEYWORD [#j620febe]
   minMaxValidation() {
     this.RULE('minMaxValidation', () => {
       // Note that "MIN_MAX_KEYWORD" is an abstract token and could match 6 different concrete token types
       this.CONSUME(LexerTokens.MIN_MAX_KEYWORD);
       this.CONSUME(LexerTokens.LPAREN);
       this.OR([{ ALT: () => this.CONSUME(LexerTokens.INTEGER) }, { ALT: () => this.CONSUME(LexerTokens.NAME) }]);
       this.CONSUME(LexerTokens.RPAREN);
     });
   }

***  jdl_parser.jsでの、minMaxValidation [#nc8cd3d4]

  validation() {
    this.RULE('validation', () => {
      this.OR([
        { ALT: () => this.CONSUME(LexerTokens.REQUIRED) },
        { ALT: () => this.CONSUME(LexerTokens.UNIQUE) },
        { ALT: () => this.SUBRULE(this.minMaxValidation) },
        { ALT: () => this.SUBRULE(this.pattern) }
      ]);
    });
  }
 
以下、同様に解析していくと、呼び出しているメソッドが、次のようになっていました。

↑

fieldDeclaration

↑

entityBody

*** テンプレートfield_validators.ejsでのmaxlengthの使われ方 [#nfc071c7]
    if (rules.includes('maxlength') && !rules.includes('minlength')) {
        validators.push('@Size(max = ' + field.fieldValidateRulesMaxlength + ')');
    }

どこで、fieldValidateRulesMaxlength 入れてるの?

自動かなぁ

どうも、テンプレートを見る限りでは、

 field.fieldValidateRules, 'maxlength'

が定義されているなら、

 field.fieldValidateRulesMaxlength

は、あたかも定義済みだよね~という記述だ。

* テンプレートは、どのように管理されているのか? [#k9582859]

JHIPSTERは、yoを使っているので、yoでは、どのように、ファイルが生成されているのか、

知りたいところである。


** yo での一番基本的な、プロンプト入力 からの、テンプレートを使った生成の書き方。 [#w26b2772]


 class extends Generator {
   async prompting() {
     this.answers = await this.prompt([{
       type    : 'input',
       name    : 'title',
       message : 'Your project title',
     }]);
   } 
 
   writing() {
     this.fs.copyTpl(
       this.templatePath('index.html'),
       this.destinationPath('public/index.html'),
       { title: this.answers.title } // user answer `title` used
     );
   }
 }


templatePathに、着目してソースファイルをみると、writeFilesToDiskというメソッドで、ファイル生成していることがわかった。

** 例えば自作のjavaのテンプレート追加するにはどうするか [#o18c7453]

javaのコードのテンプレートと、リネームの設定は、次のフォルダに格納されているみたいだ。
 generator-jhipster\generators\entity-server

このフォルダのindex.jsが、files.jsを参照するような形になっていて、このフォルダのtemplateフォルダに、パラメータを渡すように、設定していることがわかったので、

もし、自分でテンプレートを追加したいのであれば、

- templateフォルダに、テンプレートを入れる。
- files.jsを修正する

で、いけそうだ。



*** 参考ページ [#q3e169f5]

https://github.com/SAP/chevrotain/blob/master/examples/lexer/keywords_vs_identifiers/keywords_vs_identifiers.js

** パーサー作成ツールキット chevrotain [#a4164c2b]

で、パーサどう書けばいいの?ってなるが、JDLで使っているパーサは、chevrotain

を使っているようだ。


*** chevrotain のソース [#h48a278b]
https://github.com/SAP/chevrotain

*** chevrotain のチュートリアル [#f220fc2b]
https://sap.github.io/chevrotain/docs/tutorial/step0_introduction.html

*** 参考:いろいろなパーサ生成ライブラリの紹介ドキュメント [#a4506e5c]
https://tomassetti.me/parsing-in-javascript/#chevrotain
トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS