Skip to content

Commit

Permalink
Merge pull request #1701 from Bolo89/add-angular-common-service
Browse files Browse the repository at this point in the history
Add oauth 2 Angular
  • Loading branch information
pascalgrimaud authored May 18, 2022
2 parents 1b9708c + 8ed3d2c commit 6706f44
Show file tree
Hide file tree
Showing 53 changed files with 3,073 additions and 10 deletions.
1 change: 1 addition & 0 deletions .github/workflows/github-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ jobs:
- svelteapp
- kafkaapp
- reactiveapp
- angularoauth2app
steps:
- name: 'Setup: checkout project'
uses: actions/checkout@v3
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/tech/jhipster/lite/common/domain/WordUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ public class WordUtils {
public static final String OB = "\\{";
public static final String CB = "\\}";

public static final String COMA = ",";
public static final String O_BRACKET = "[";
public static final String C_BRACKET = "]";

private static final String VALUE_FIELD = "value";

private WordUtils() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Angular

## Description

This context is used to manipulate existing angular files :

- Add imports in .ts
- Add constants in .ts
- Add declarations, providers in decorated classes
- Add new config in environment.ts files
- ...

## Maintainers

- [Bolo](https://github.com/Bolo89)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package tech.jhipster.lite.generator.client.angular.common.application;

import org.springframework.stereotype.Service;
import tech.jhipster.lite.generator.client.angular.common.domain.AngularCommonService;
import tech.jhipster.lite.generator.project.domain.Project;

@Service
public class AngularCommonApplicationService {

private final AngularCommonService angularCommonService;

public AngularCommonApplicationService(AngularCommonService angularCommonService) {
this.angularCommonService = angularCommonService;
}

public void addImports(Project project, String filePath, String imports) {
angularCommonService.addImports(project, filePath, imports);
}

public void addInExistingImport(Project project, String filePath, String imports, String existingImportName) {
angularCommonService.addInExistingImport(project, filePath, imports, existingImportName);
}

public void addConstants(Project project, String filePath, String constants) {
angularCommonService.addConstants(project, filePath, constants);
}

public void addDeclarations(Project project, String filePath, String declarations) {
angularCommonService.addDeclarations(project, filePath, declarations);
}

public void addProviders(Project project, String filePath, String providers) {
angularCommonService.addProviders(project, filePath, providers);
}

public void addEnvVariables(Project project, String envFilePath, String values) {
angularCommonService.addEnvVariables(project, envFilePath, values);
}

public void addHtml(Project project, String htmlFilePath, String htmlToAdd, String htmlTagRegexToReplace) {
angularCommonService.addHtml(project, htmlFilePath, htmlToAdd, htmlTagRegexToReplace);
}

public void addTest(Project project, String specTsFilePath, String testToAdd, String afterTestName) {
angularCommonService.addTest(project, specTsFilePath, testToAdd, afterTestName);
}

public void addAllowedCommonJsDependenciesAngularJson(Project project, String libToAdd) {
angularCommonService.addAllowedCommonJsDependenciesAngularJson(project, libToAdd);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package tech.jhipster.lite.generator.client.angular.common.domain;

import java.util.List;

public class AngularCommon {

protected static final String ANGULAR_JSON_FILE_NAME = "angular.json";

protected static final String IMPORT_REGEX = "(^import[\\s]+[^;]+;)";
protected static final String EXISTING_IMPORT_PATTERN = "^(import[\\s]+\\{[^\\}]+)\\} from '[%s]+';";

protected static final List<String> DECORATOR_REGEX_LIST = List.of("(^@[A-Z]{1}[\\w]+\\(\\{)");

protected static final String DECLARATIONS_REGEX = "^([\\s]+declarations:[\\s]+\\[[^\\]]+\\][\\s,]*)";

protected static final List<String> DECLARATIONS_WITH_ARRAY_VALUES_REGEX_LIST = List.of(
"^([\\s]+declarations:[\\s]+\\[[^\\]]+)\\]",
"^([\\s]+declarations:[\\s]+\\[)\\]"
);

protected static final List<String> PROVIDERS_WITH_ARRAY_VALUES_REGEX_LIST = List.of(
"^([\\s]+providers:[\\s]+\\[[^\\]]+)\\]",
"^([\\s]+providers:[\\s]+\\[)\\]"
);

protected static final List<String> ENV_VARIABLES_WITH_VALUES_REGEX_LIST = List.of(
"(export const environment = [^(\\};)]+[\\}]?[\\s,]*)\\};"
);

protected static final String TEST_REGEX_FORMAT = "([\\s]+it\\('%s',[^}]+}\\);)";

protected static final List<String> ALLOWED_COMMON_JS_DEPENDENCIES_REGEX_LIST = List.of(
"^([\\s]+\"allowedCommonJsDependencies\": [^\\]]+)\\]"
);

private AngularCommon() {
// Cannot be instantiated
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package tech.jhipster.lite.generator.client.angular.common.domain;

import static tech.jhipster.lite.common.domain.WordUtils.COMA;
import static tech.jhipster.lite.common.domain.WordUtils.C_BRACKET;
import static tech.jhipster.lite.common.domain.WordUtils.O_BRACKET;
import static tech.jhipster.lite.common.domain.WordUtils.indent;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.ALLOWED_COMMON_JS_DEPENDENCIES_REGEX_LIST;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.ANGULAR_JSON_FILE_NAME;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.DECLARATIONS_REGEX;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.DECLARATIONS_WITH_ARRAY_VALUES_REGEX_LIST;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.DECORATOR_REGEX_LIST;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.ENV_VARIABLES_WITH_VALUES_REGEX_LIST;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.EXISTING_IMPORT_PATTERN;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.PROVIDERS_WITH_ARRAY_VALUES_REGEX_LIST;
import static tech.jhipster.lite.generator.client.angular.common.domain.AngularCommon.TEST_REGEX_FORMAT;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import tech.jhipster.lite.common.domain.FileUtils;
import tech.jhipster.lite.error.domain.GeneratorException;
import tech.jhipster.lite.generator.project.domain.Project;

public class AngularCommonDomainService implements AngularCommonService {

@Override
public void addImports(Project project, String tsFilePath, String imports) {
String fullFilePath = FileUtils.getPath(project.getFolder(), tsFilePath);
String fileContent = getFileContent(fullFilePath);

String newFileContent = getLastImportInFile(fileContent)
.map(lastImport -> fileContent.replace(lastImport, lastImport + project.getEndOfLine() + imports))
.orElse(imports + project.getEndOfLine() + fileContent);

writeInFile(fullFilePath, newFileContent, project);
}

@Override
public void addInExistingImport(Project project, String tsFilePath, String importToAdd, String existingImportName) {
String fullFilePath = FileUtils.getPath(project.getFolder(), tsFilePath);
String fileContent = getFileContent(fullFilePath);

String newFileContent = getFirstMatchInFile(List.of(String.format(EXISTING_IMPORT_PATTERN, existingImportName)), fileContent)
.map(importPrefix -> appendValuesInList(fileContent, importPrefix, importToAdd, ""))
.orElseThrow(() -> new GeneratorException("Cannot find declarations array in file " + fullFilePath));

writeInFile(fullFilePath, newFileContent, project);
}

@Override
public void addConstants(Project project, String tsFilePath, String constants) {
String fullFilePath = FileUtils.getPath(project.getFolder(), tsFilePath);
String fileContent = getFileContent(fullFilePath);
String newFileContent = getFirstMatchInFile(DECORATOR_REGEX_LIST, fileContent)
.map(decoratorPrefix -> fileContent.replace(decoratorPrefix, constants + project.getEndOfLine() + decoratorPrefix))
.orElse(fileContent + project.getEndOfLine() + constants);

writeInFile(fullFilePath, newFileContent, project);
}

@Override
public void addDeclarations(Project project, String tsFilePath, String declarations) {
String fullFilePath = FileUtils.getPath(project.getFolder(), tsFilePath);
String fileContent = getFileContent(fullFilePath);
String newFileContent = getFirstMatchInFile(DECLARATIONS_WITH_ARRAY_VALUES_REGEX_LIST, fileContent)
.map(declarationsPrefix -> appendValuesInList(fileContent, declarationsPrefix, declarations, project.getEndOfLine()))
.orElseThrow(() -> new GeneratorException("Cannot find declarations array in file " + fullFilePath));

writeInFile(fullFilePath, newFileContent, project);
}

@Override
public void addProviders(Project project, String tsFilePath, String providers) {
String fullFilePath = FileUtils.getPath(project.getFolder(), tsFilePath);
String fileContent = getFileContent(fullFilePath);

String newFileContent = getFirstMatchInFile(PROVIDERS_WITH_ARRAY_VALUES_REGEX_LIST, fileContent)
.map(providersPrefix -> appendValuesInList(fileContent, providersPrefix, providers, project.getEndOfLine()))
.orElseGet(() -> appendProvidersAfterDeclarations(fileContent, fullFilePath, providers, project));

writeInFile(fullFilePath, newFileContent, project);
}

@Override
public void addEnvVariables(Project project, String envFilePath, String values) {
String fullFilePath = FileUtils.getPath(project.getFolder(), envFilePath);
String fileContent = getFileContent(fullFilePath);
String newFileContent = getFirstMatchInFile(ENV_VARIABLES_WITH_VALUES_REGEX_LIST, fileContent)
.map(prefixEnvVariables -> {
String updatedEnvVariablesStr = prefixEnvVariables.stripTrailing();
if (!updatedEnvVariablesStr.endsWith(COMA)) {
updatedEnvVariablesStr += COMA;
}
updatedEnvVariablesStr += project.getEndOfLine() + values.stripTrailing() + project.getEndOfLine();
return fileContent.replace(prefixEnvVariables, updatedEnvVariablesStr);
})
.orElseThrow(() -> new GeneratorException("Cannot find environnement const in " + fullFilePath));
writeInFile(fullFilePath, newFileContent, project);
}

@Override
public void addHtml(Project project, String htmlFilePath, String htmlToAdd, String htmlTagRegexToReplace) {
replaceTextByRegex(project, htmlFilePath, htmlToAdd, htmlTagRegexToReplace);
}

@Override
public void addTest(Project project, String specTsFilePath, String testToAdd, String afterTestName) {
String testRegex = String.format(TEST_REGEX_FORMAT, afterTestName.replaceAll("\\s", "[\\\\s]+"));
replaceTextByRegex(project, specTsFilePath, testToAdd, testRegex);
}

@Override
public void addAllowedCommonJsDependenciesAngularJson(Project project, String libToAdd) {
String fullFilePath = FileUtils.getPath(project.getFolder(), ANGULAR_JSON_FILE_NAME);
String fileContent = getFileContent(fullFilePath);
String newFileContent = getFirstMatchInFile(ALLOWED_COMMON_JS_DEPENDENCIES_REGEX_LIST, fileContent)
.map(dependenciesPrefix -> appendValuesInList(fileContent, dependenciesPrefix, libToAdd, project.getEndOfLine()))
.orElseThrow(() -> new GeneratorException("Cannot find allowed common js dependencies array in file " + fullFilePath));

writeInFile(fullFilePath, newFileContent, project);
}

private String getFileContent(String fullFilePath) {
String fileContent;
try {
fileContent = FileUtils.read(fullFilePath);
} catch (IOException e) {
throw new GeneratorException("Cannot read file " + fullFilePath + ": " + e.getMessage());
}
return fileContent;
}

private void writeInFile(String fullFilePath, String newFileContent, Project project) {
try {
FileUtils.write(fullFilePath, newFileContent, project.getEndOfLine());
} catch (IOException e) {
throw new GeneratorException("Cannot write content in file " + fullFilePath + ": " + e.getMessage());
}
}

private Optional<String> getLastImportInFile(String fileContent) {
Pattern pattern = Pattern.compile(AngularCommon.IMPORT_REGEX, Pattern.MULTILINE);
Matcher matcher = pattern.matcher(fileContent);
String lastMatchFound = null;
while (matcher.find()) {
lastMatchFound = matcher.group(1);
}
return Optional.ofNullable(lastMatchFound);
}

private Optional<String> getFirstMatchInFile(List<String> regexList, String fileContent) {
return regexList
.stream()
.map(regex -> {
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
return pattern.matcher(fileContent);
})
.filter(Matcher::find)
.findFirst()
.map(matcher -> matcher.group(1));
}

private String appendValuesInList(String fileContent, String prefixWithArrayValuesStr, String arrayValuesToAdd, String endOfLine) {
StringBuilder updatedArrayValuesStr = new StringBuilder(prefixWithArrayValuesStr.stripTrailing());
if (!prefixWithArrayValuesStr.trim().endsWith(O_BRACKET) && !updatedArrayValuesStr.toString().endsWith(COMA)) {
updatedArrayValuesStr.append(COMA);
}
int prefixIdx = prefixWithArrayValuesStr.indexOf(prefixWithArrayValuesStr.trim());
String spaceBeforePrefix = prefixWithArrayValuesStr.substring(0, prefixIdx);
updatedArrayValuesStr.append(endOfLine).append(arrayValuesToAdd.stripTrailing()).append(endOfLine).append(spaceBeforePrefix);
return fileContent.replace(prefixWithArrayValuesStr, updatedArrayValuesStr.toString());
}

private String appendProvidersAfterDeclarations(String fileContent, String fullFilePath, String providers, Project project) {
String declarationsStr = getFirstMatchInFile(List.of(DECLARATIONS_REGEX), fileContent)
.map(String::stripTrailing)
.orElseThrow(() -> new GeneratorException("Missing declarations in file: " + fullFilePath));
String newProvidersArrayStr =
indent(1) +
"providers: " +
O_BRACKET +
project.getEndOfLine() +
providers.stripTrailing() +
project.getEndOfLine() +
indent(1) +
C_BRACKET +
COMA;
String declarationsAndProvidersStr = declarationsStr.trim().endsWith(COMA) ? declarationsStr : declarationsStr + COMA;
declarationsAndProvidersStr += project.getEndOfLine() + newProvidersArrayStr;
return fileContent.replace(declarationsStr, declarationsAndProvidersStr);
}

private void replaceTextByRegex(Project project, String filePath, String textToAdd, String textToReplaceRegex) {
String fullFilePath = FileUtils.getPath(project.getFolder(), filePath);
String fileContent = getFileContent(fullFilePath);
Pattern pattern = Pattern.compile(textToReplaceRegex, Pattern.MULTILINE);
Matcher matcher = pattern.matcher(fileContent);
if (!matcher.find()) {
throw new GeneratorException("Cannot find " + textToReplaceRegex + " in file " + fullFilePath);
}
String textFound = matcher.group(1);
String newFileContent = fileContent.replace(textFound, textFound.stripTrailing() + project.getEndOfLine() + textToAdd);
writeInFile(fullFilePath, newFileContent, project);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tech.jhipster.lite.generator.client.angular.common.domain;

import tech.jhipster.lite.generator.project.domain.Project;

public interface AngularCommonService {
void addImports(Project project, String tsFilePath, String imports);

void addInExistingImport(Project project, String tsFilePath, String importToAdd, String existingImportName);

void addConstants(Project project, String tsFilePath, String constants);

void addDeclarations(Project project, String tsFilePath, String declarations);

void addProviders(Project project, String tsFilePath, String providers);

void addEnvVariables(Project project, String envFilePath, String values);

void addHtml(Project project, String htmlFilePath, String htmlToAdd, String htmlTagRegexToReplace);

void addTest(Project project, String specTsFilePath, String testToAdd, String afterTestName);

void addAllowedCommonJsDependenciesAngularJson(Project project, String libToAdd);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tech.jhipster.lite.generator.client.angular.common.infrastructure;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tech.jhipster.lite.generator.client.angular.common.domain.AngularCommonDomainService;
import tech.jhipster.lite.generator.client.angular.common.domain.AngularCommonService;

@Configuration
public class AngularCommonBeanConfiguration {

@Bean
public AngularCommonService angularCommonService() {
return new AngularCommonDomainService();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@tech.jhipster.lite.SharedKernel
package tech.jhipster.lite.generator.client.angular.common;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Angular

## Description

This context is used to add oauth2 (with keycloak) in angular project.

## Maintainers

- [Bolo](https://github.com/Bolo89)
Loading

0 comments on commit 6706f44

Please sign in to comment.