generator-begcode
Version:
Spring Boot + Angular/React/Vue in one handy generator
292 lines (291 loc) • 12 kB
JavaScript
import { set, get } from 'lodash-es';
import sortKeys from 'sort-keys';
import XmlStorage from '../internal/xml-store.js';
const rootOrder = [
'modelVersion',
'groupId',
'artifactId',
'version',
'packaging',
'name',
'description',
'parent',
'repositories',
'pluginRepositories',
'distributionManagement',
'properties',
'dependencyManagement',
'dependencies',
'build',
'profiles',
];
const propertiesOrder = [
'maven.version',
'java.version',
'node.version',
'npm.version',
'project.build.sourceEncoding',
'project.reporting.outputEncoding',
'maven.build.timestamp.format',
'maven.compiler.source',
'maven.compiler.target',
'start-class',
'argLine',
'm2e.apt.activation',
'run.addResources',
'jhipster-dependencies.version',
'spring-boot.version',
];
const formatFirstXmlLevel = content => content.replace(/(\n {4}<(?:groupId|distributionManagement|repositories|pluginRepositories|properties|dependencyManagement|dependencies|build|profiles)>)/g, '\n$1');
const sortSection = section => {
return Object.fromEntries(Object.entries(section).sort(([key1, value1], [key2, value2]) => {
if (typeof value1 === typeof value2)
key1.localeCompare(key2);
if (typeof value1 === 'string')
return -1;
if (typeof value2 === 'string')
return 1;
return 0;
}));
};
const isComment = name => name.startsWith('#');
const toMaxInt = nr => (nr === -1 ? Number.MAX_SAFE_INTEGER : nr);
const sortWithTemplate = (template, a, b) => {
if (isComment(a))
return -1;
if (isComment(b))
return 1;
const indexOfA = toMaxInt(template.findIndex(item => item === a));
const indexOfB = toMaxInt(template.findIndex(item => item === b));
if (indexOfA === indexOfB) {
return a.localeCompare(b);
}
return indexOfA - indexOfB;
};
const comparator = (order) => (a, b) => sortWithTemplate(order, a, b);
const sortProperties = properties => sortKeys(properties, { compare: comparator(propertiesOrder) });
const artifactEquals = (a, b) => {
return a.groupId === b.groupId && a.artifactId === b.artifactId;
};
const dependencyEquals = (a, b) => {
return artifactEquals(a, b) && a.scope === b.scope && a.type === b.type;
};
const idEquals = (a, b) => {
return a.id === b.id;
};
const ensureChildIsArray = (node, childPath) => {
let dependencyArray = get(node, childPath);
if (!dependencyArray) {
dependencyArray = [];
set(node, childPath, dependencyArray);
}
else if (!Array.isArray(dependencyArray)) {
dependencyArray = [dependencyArray];
set(node, childPath, dependencyArray);
}
return dependencyArray;
};
function appendOrReplace(array, item, equals) {
const dependencyIndex = array.findIndex(existing => equals(existing, item));
if (dependencyIndex === -1) {
array.push(item);
}
else {
array[dependencyIndex] = item;
}
}
function appendOrGet(array, item, equals) {
const child = array.find(existing => equals(existing, item));
if (child) {
return child;
}
array.push(item);
return item;
}
const ensureProfile = (project, profileId) => {
const profileArray = ensureChildIsArray(project, 'profiles.profile');
return appendOrGet(profileArray, { id: profileId }, idEquals);
};
const groupIdOrder = ['tech.jhipster', 'org.springframework.boot', 'org.springframework.security', 'org.springdoc'];
const sortArtifacts = (artifacts) => artifacts.sort((a, b) => {
if (a.groupId !== b.groupId) {
if (a.groupId === undefined) {
return -1;
}
if (b.groupId === undefined) {
return 1;
}
const groupIdCompared = sortWithTemplate(groupIdOrder, a.groupId, b.groupId);
if (groupIdCompared)
return groupIdCompared;
}
return a.artifactId.localeCompare(b.artifactId);
});
const sortProfiles = (profiles) => profiles.sort((a, b) => a.id?.localeCompare(b.id) ?? 1);
const ensureChildPath = (node, childPath) => {
let child = get(node, childPath);
if (child)
return child;
child = {};
set(node, childPath, child);
return child;
};
const ensureChild = (current, ...childPath) => {
for (const node of childPath) {
if (typeof node === 'string') {
current = ensureChildPath(current, node);
}
else if (typeof node === 'function') {
current = node(current);
}
else {
throw new Error(`Path section not supported ${node}`);
}
if (!current) {
return undefined;
}
}
return current;
};
const reorderArtifact = ({ groupId, artifactId, inProfile, version, ...rest }) => ({ inProfile, groupId, artifactId, version, ...rest });
const reorderDependency = ({ groupId, artifactId, inProfile, version, type, scope, classifier, ...rest }) => ({ inProfile, groupId, artifactId, version, type, scope, classifier, ...rest });
export default class PomStorage extends XmlStorage {
constructor({ saveFile, loadFile, sortFile }) {
super({ saveFile, loadFile, sortFile });
}
addProperty({ inProfile, property, value = null }) {
const node = this.getNode({ nodePath: 'properties', profile: inProfile });
node[property] = value;
this.persist();
}
addDependency({ inProfile, ...dependency }) {
this.addDependencyAt(this.getNode({ profile: inProfile }), reorderDependency(dependency));
this.persist();
}
addDependencyManagement({ inProfile, ...dependency }) {
this.addDependencyAt(this.getNode({ profile: inProfile, nodePath: 'dependencyManagement' }), reorderDependency(dependency));
this.persist();
}
addDistributionManagement({ inProfile, snapshotsId, snapshotsUrl, releasesId, releasesUrl }) {
const store = this.getNode({ profile: inProfile });
store.distributionManagement = {
snapshotRepository: {
id: snapshotsId,
url: snapshotsUrl,
},
repository: {
id: releasesId,
url: releasesUrl,
},
};
this.persist();
}
addProfile({ content, ...profile }) {
const profileArray = ensureChildIsArray(this.getNode(), 'profiles.profile');
appendOrReplace(profileArray, this.mergeContent(profile, content), idEquals);
this.persist();
}
addPlugin({ inProfile, ...plugin }) {
this.addPluginAt(this.getNode({ profile: inProfile, nodePath: 'build' }), plugin);
this.persist();
}
addPluginManagement({ inProfile, ...plugin }) {
this.addPluginAt(this.getNode({ profile: inProfile, nodePath: 'build.pluginManagement' }), plugin);
this.persist();
}
addRepository({ inProfile, ...repository }) {
this.addRepositoryAt(this.getNode({ profile: inProfile }), repository);
this.persist();
}
addPluginRepository({ inProfile, ...repository }) {
this.addPluginRepositoryAt(this.getNode({ profile: inProfile }), repository);
this.persist();
}
addAnnotationProcessor({ inProfile, ...artifact }) {
const node = this.getNode({ profile: inProfile });
const plugins = ensureChildIsArray(node, 'build.pluginManagement.plugins.plugin');
const annotationProcessorPaths = ensureChild(plugins, pluginArray => {
return appendOrGet(pluginArray, {
groupId: 'org.apache.maven.plugins',
artifactId: 'maven-compiler-plugin',
}, artifactEquals);
}, 'configuration.annotationProcessorPaths');
const paths = ensureChildIsArray(annotationProcessorPaths, 'path');
appendOrReplace(paths, reorderArtifact(artifact), artifactEquals);
this.persist();
}
getNode({ profile, nodePath } = {}) {
const node = profile ? ensureProfile(this.store.project, profile) : this.store.project;
if (nodePath) {
return ensureChild(node, nodePath);
}
return node;
}
addDependencyAt(node, { additionalContent, ...dependency }) {
const dependencyArray = ensureChildIsArray(node, 'dependencies.dependency');
appendOrReplace(dependencyArray, this.mergeContent(reorderDependency(dependency), additionalContent), dependencyEquals);
}
addPluginAt(node, { additionalContent, ...artifact }) {
const artifactArray = ensureChildIsArray(node, 'plugins.plugin');
appendOrReplace(artifactArray, this.mergeContent(reorderArtifact(artifact), additionalContent), artifactEquals);
}
addRepositoryAt(node, { releasesEnabled, snapshotsEnabled, ...repository }) {
const releases = releasesEnabled === undefined ? undefined : { enabled: releasesEnabled };
const snapshots = snapshotsEnabled === undefined ? undefined : { enabled: snapshotsEnabled };
const repositoryArray = ensureChildIsArray(node, 'repositories.repository');
appendOrReplace(repositoryArray, { ...repository, releases, snapshots }, idEquals);
}
addPluginRepositoryAt(node, { releasesEnabled, snapshotsEnabled, ...repository }) {
const releases = releasesEnabled === undefined ? undefined : { enabled: releasesEnabled };
const snapshots = snapshotsEnabled === undefined ? undefined : { enabled: snapshotsEnabled };
const repositoryArray = ensureChildIsArray(node, 'pluginRepositories.pluginRepository');
appendOrReplace(repositoryArray, { ...repository, releases, snapshots }, idEquals);
}
sort() {
if (this.store.project) {
const project = sortKeys(this.store.project, { compare: comparator(rootOrder) });
this.store.project = project;
if (project.properties) {
project.properties = sortProperties(project.properties);
}
if (Array.isArray(project.dependencies?.dependency)) {
project.dependencies.dependency = sortArtifacts(project.dependencies.dependency);
}
if (Array.isArray(project.dependencyManagement?.dependencies?.dependency)) {
project.dependencyManagement.dependencies.dependency = sortArtifacts(project.dependencyManagement.dependencies.dependency);
}
if (project.build) {
project.build = sortSection(project.build);
if (Array.isArray(project.build.plugins?.plugin)) {
project.build.plugins.plugin = sortArtifacts(project.build.plugins.plugin);
}
if (Array.isArray(project.build.pluginManagement?.plugins?.plugin)) {
project.build.pluginManagement.plugins.plugin = sortArtifacts(project.build.pluginManagement.plugins.plugin);
}
}
if (Array.isArray(project.profiles?.profile)) {
project.profiles.profile = sortProfiles(project.profiles.profile);
}
}
}
}
const emptyPomFile = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
</project>
`;
export const createPomStorage = (generator, { sortFile } = {}) => {
const loadFile = () => generator.readDestination('pom.xml', { defaults: emptyPomFile })?.toString() ?? '';
const pomStorage = new PomStorage({
loadFile,
saveFile: content => generator.writeDestination('pom.xml', formatFirstXmlLevel(content)),
sortFile,
});
generator.fs.store.on('change', filename => {
if (filename === generator.destinationPath('pom.xml')) {
pomStorage.clearCache();
}
});
return pomStorage;
};