JHIPSTER一覧

目次

はじめに

jhipsterでなにが、うれしいかというと、 クラス図をJDLという簡易な設定さえ書けば、

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

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

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

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

だったりする。

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

JDLからのパラメータ

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

テンプレートファイル

テンプレートは、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');

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

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

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

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

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

EntityRepository?.java.ejs

コメントの書き方

<%#

-%>

パッケージ名

package <%=packageName%>.repository;

エンティティクラス名

テーブル名とかに使用

<%=asEntity(entityClass)%>

または

<%=entityClass%>

多対多の場合

<%_ if (fieldsContainOwnerManyToMany) { _%>

<%_ } _%>

データベースの種類がsqlの場合

<%_ if (databaseType === 'mongodb') { _%>

<%_ } _%>

SQLのselect句

select <%= entityInstance %> 

リレーションしてる文だけ必要なループ

<% for (idx in relationships) {
   if (relationships[idx].relationshipType === 'many-to-many' && relationships[idx].ownerSide === true) { %>
   left join fetch <%=entityInstance%>.<%=relationships[idx].relationshipFieldNamePlural%><%} }%>",

リレーションのjavadocが定義されているかどうかチェック

for (idx in relationships) {
    if (typeof relationships[idx].javadoc != 'undefined') {
        
    }
}

フィールドでループ

 <% for (idx in fields) {

   } _%>

フィールドのjavadocが定義されているかどうかチェック

  for (idx in fields) {
      if (typeof fields[idx].javadoc != 'undefined') {
          
      }
  }

未確認の引数

fieldsContainBlob

importJsonIgnoreProperties

importApiModelProperty

importJsonIgnore

fieldsContainUUID

prodDatabaseType

hasTextBlob

validation

searchEngine

fieldsContainBigDecimal

jhipster entityとしたときのメッセージの場所

たまたま、みつけたから、メモしておこう。

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

にある。

JDLのパーサー

jhiCore.JDLImporter

のimportメソッド

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

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

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

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

JDLImporter

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

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

アプリフォルダ/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) },

実務でありそうな要件を考えてみる。

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

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

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

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

maxlengthに着目して、解析をする

lexer.jsでのmaxlength

createToken({
  name: 'MAXLENGTH',
  pattern: 'maxlength',
  categories: [tokens.MIN_MAX_KEYWORD]
});

jdl_parser.jsでの、MIN_MAX_KEYWORD

  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?

 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の使われ方

   if (rules.includes('maxlength') && !rules.includes('minlength')) {
       validators.push('@Size(max = ' + field.fieldValidateRulesMaxlength + ')');
   }

どこで、fieldValidateRulesMaxlength? 入れてるの?

自動かなぁ

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

field.fieldValidateRules, 'maxlength'

が定義されているなら、

field.fieldValidateRulesMaxlength

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

参考ページ

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

パーサー作成ツールキット chevrotain

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

を使っているようだ。

chevrotain のソース

https://github.com/SAP/chevrotain

chevrotain のチュートリアル

https://sap.github.io/chevrotain/docs/tutorial/step0_introduction.html

参考:いろいろなパーサ生成ライブラリの紹介ドキュメント

https://tomassetti.me/parsing-in-javascript/#chevrotain

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS