Repository: jhipster/generator-jhipster (ts)

Issue:
Invalid JAVA syntax due to double quotes in JDL JavaDoc 

##### Double quotes in JDL JavaDoc don't get escaped in the Swagger @ApiModel annotation


##### **Motivation for or Use Case**
The affected JAVA files have invalid syntax and the Build fails.


##### **Reproduce the error**

Create a JDL file containing a JavaDoc comment for an entity containing double quotes. e.g.
```
/**
* Entity "Foo bar"
*/
entity Foobar {}
```
The annotation will look like this:
```
@ApiModel(description = "Entity "Foo bar"")
```

##### **Related issues**
Haven't found any.

##### **Suggest a Fix**
Escape the double quotes with backslash (as it's done when filling this annotation.



##### **JHipster Version(s)**
```
requirement@0.0.0 /home/vagrant/securityratv2/requirement
└── generator-jhipster@4.13.1 
```


##### **JHipster configuration, a `.yo-rc.json` file generated in the root folder**

<details>
<summary>.yo-rc.json file</summary>
<pre>
{
  "generator-jhipster": {
    "promptValues": {
      "packageName": "org.securityrat.requirementms"
    },
    "jhipsterVersion": "4.13.1",
    "baseName": "requirement",
    "packageName": "org.securityrat.requirementms",
    "packageFolder": "org/securityrat/requirementms",
    "serverPort": "8081",
    "authenticationType": "oauth2",
    "cacheProvider": "no",
    "clusteredHttpSession": false,
    "websocket": false,
    "databaseType": "sql",
    "devDatabaseType": "h2Disk",
    "prodDatabaseType": "mariadb",
    "searchEngine": false,
    "messageBroker": false,
    "serviceDiscoveryType": "consul",
    "buildTool": "maven",
    "enableSocialSignIn": false,
    "enableSwaggerCodegen": false,
    "jwtSecretKey": "replaced-by-jhipster-info",
    "enableTranslation": false,
    "applicationType": "microservice",
    "testFrameworks": [
      "gatling",
      "cucumber"
    ],
    "jhiPrefix": "jhi",
    "clientPackageManager": "yarn",
    "skipClient": true,
    "skipUserManagement": true
  }
}
</pre>
</details>


##### **JDL for the Entity configuration(s) `entityName.json` files generated in the `.jhipster` directory**

<details>
<summary>JDL entity definitions</summary>

<pre>
/**
 * Requirements are organized in different sets.
 * These define also the structure of contained requirements.
 * Selecting a suitable requirement set is the initial step when creating a "case".
 */
entity RequirementSet (requirement_set) {
  name String required,
  description TextBlob,
  showOrder Integer,
  active Boolean required
}
/**
 * The "core" part of a particular requirement.
 */
entity Skeleton (skeleton) {
  name String required,
  description TextBlob,
  showOrder Integer,
  active Boolean required
}
/**
 * Describes one group/collection of requirement attributes.
 * E.g. "Criticality" for Low, Medium, High.
 */
entity AttributeGroup (attribute_group) {
  name String required,
  description TextBlob,
  type AttributeType required,
  showOrder Integer,
  active Boolean required
}
/**
 * Every requirement can be classified in many ways
 * according to different attributes.
 */
entity Attribute (attribute) {
  name String required,
  description TextBlob,
  showOrder Integer,
  active Boolean required
}
/**
 * Describes properties of one type of a requirement extension.
 */
entity ExtensionDefinition (extension_definition) {
  name String required,
  description TextBlob,
  section ExtensionSection required,
  type ExtensionType,
  showOrder Integer,
  active Boolean required
}
/**
 * Requirement extension (extending the requirement skeleton).
 */
entity Extension (extension) {
  content TextBlob required,
  description TextBlob,
  showOrder Integer,
  active Boolean required
}
/**
 * Implements ternary relation of req. skeleton, attribute an extension.
 * Requirement extension can be added to a skeleton if a particular attribute is set.
 */
entity SkAtEx (sk_at_ex)

enum AttributeType {
  FE_TAG,
  PARAMETER,
  CATEGORY
}

enum ExtensionSection {
  STATUS,
  ENHANCEMENT
}

enum ExtensionType {
  ENUM,
  FREETEXT
}

relationship OneToMany {
  RequirementSet{skeleton} to Skeleton{requirementSet(name)},
  RequirementSet{attributeGroup} to AttributeGroup{requirementSet(name)},
  AttributeGroup{attribute} to Attribute{attributeGroup(name)},
  RequirementSet{extensionDefinition} to ExtensionDefinition{requirementSet(name)},
  ExtensionDefinition{extension} to Extension{extensionDefinition(name)},
  Skeleton{skAtEx} to SkAtEx{skeleton(name)},
  Attribute{skAtEx} to SkAtEx{attribute(name)},
  Extension{skAtEx} to SkAtEx{extension(content)}
}
relationship ManyToOne {
  Attribute{parent} to Attribute
}

paginate RequirementSet, Skeleton, AttributeGroup, Attribute, ExtensionDefinition, Extension, SkAtEx with infinite-scroll
service RequirementSet, Skeleton, AttributeGroup, Attribute, ExtensionDefinition, Extension, SkAtEx with serviceClass
microservice RequirementSet, Skeleton, AttributeGroup, Attribute, ExtensionDefinition, Extension, SkAtEx with requirement
filter RequirementSet, Skeleton, AttributeGroup, Attribute, ExtensionDefinition, Extension, SkAtEx

</pre>
</details>


##### **Environment and Tools**

openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.17.04.2-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)

git version 2.11.0

node: v8.9.3

npm: 5.6.0

bower: 1.8.2

gulp:
[17:27:40] CLI version 3.9.1

yeoman: 2.0.0

yarn: 1.3.2

Docker version 17.11.0-ce, build 1caf76c


##### **Browsers and Operating System**

JHipster DevBox 4.13.1

- [X] Checking this box is mandatory (this is just to show you read everything)



Pull request:
Updated the #formatAsApiDescription method to deal with special cases
- Please make sure the below checklist is followed for Pull Requests.

- [ ] [Travis tests](https://travis-ci.org/jhipster/generator-jhipster/pull_requests) are green
- [X] Tests are added where necessary
- [X] Documentation is added/updated where necessary
- [X] Coding Rules & Commit Guidelines as per our [CONTRIBUTING.md document](https://github.com/jhipster/generator-jhipster/blob/master/CONTRIBUTING.md) are followed

The special cases are:
  - Nil and empty strings
  - Double-quotes (replaced by `\"`)
  - Empty-when-trimmed lines

Also added tests

Fixes #6918
  

Patch:
diff --git a/generators/generator-base-private.js b/generators/generator-base-private.js
index 05a411dc46..7877f0b3d8 100644
--- a/generators/generator-base-private.js
+++ b/generators/generator-base-private.js
@@ -339,21 +339,31 @@ module.exports = class extends Generator {
      * @returns formatted api description
      */
     formatAsApiDescription(text) {
+        if (!text) {
+            return text;
+        }
         const rows = text.split('\n');
         let description = rows[0];
         for (let i = 1; i < rows.length; i++) {
             // discard empty rows
-            if (rows[i] !== '') {
+            if (rows[i].trim() !== '') {
                 // if simple text then put space between row strings
                 if (!description.endsWith('>') && !rows[i].startsWith('<')) {
                     description += ' ';
                 }
-                description += rows[i];
+                description += this.formatLineForJavaStringUse(rows[i]);
             }
         }
         return description;
     }
 
+    formatLineForJavaStringUse(text) {
+        if (!text) {
+            return text;
+        }
+        return text.replace(/"/g, '\\"');
+    }
+
     /**
      * @param {any} input input
      * @returns {boolean} true if input is number; false otherwise


Test patch:
diff --git a/test/generator-base-private.spec.js b/test/generator-base-private.spec.js
index 26dccdd7d8..a7b2aadecc 100644
--- a/test/generator-base-private.spec.js
+++ b/test/generator-base-private.spec.js
@@ -111,4 +111,40 @@ export * from './entityFolderName/entityFileName.state';`;
             });
         });
     });
+
+    describe('formatAsApiDescription', () => {
+        describe('when formatting a nil text', () => {
+            it('returns it', () => {
+                expect(BaseGenerator.formatAsApiDescription()).to.equal(undefined);
+            });
+        });
+        describe('when formatting an empty text', () => {
+            it('returns it', () => {
+                expect(BaseGenerator.formatAsApiDescription('')).to.equal('');
+            });
+        });
+        describe('when formatting normal texts', () => {
+            describe('when having empty lines', () => {
+                it('discards them', () => {
+                    expect(BaseGenerator.formatAsApiDescription('First line\n \nSecond line\n\nThird line')).to.equal('First line Second line Third line');
+                });
+            });
+            describe('when having HTML tags', () => {
+                it('keeps them', () => {
+                    expect(BaseGenerator.formatAsApiDescription('Not boldy\n<b>boldy</b>')).to.equal('Not boldy<b>boldy</b>');
+                });
+            });
+            describe('when having a plain text', () => {
+                it('puts a space before each line', () => {
+                    expect(BaseGenerator.formatAsApiDescription('JHipster is\na great generator')).to.equal('JHipster is a great generator');
+                });
+            });
+            describe('when having quotes', () => {
+                it('formats the text to make the string valid', () => {
+                    // eslint-disable-next-line quotes
+                    expect(BaseGenerator.formatAsApiDescription("JHipster is \"the\" best")).to.equal("JHipster is \"the\" best");
+                });
+            });
+        });
+    });
 });