-
Notifications
You must be signed in to change notification settings - Fork 95
/
Copy pathhelpers.js
141 lines (130 loc) · 4.66 KB
/
helpers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
const path = require("path");
const fs = require("fs");
const LOG = require("@sap/cds").log("dev-approuter") || console;
/**
* Parses the approuter configuration from an `xs-dev.json` file.
* If that file doesn't exist, it looks for an `xs-app.json` file.
* Also scans the routes of the config file and checks for the `dependency` property
* and stores those in `config.dependencyRoutes`, which is where the dev approuter will do its magic.
* @returns {Object} the approuter configuration including all `dependencyRoutes`.
*/
const parseConfig = () => {
let config;
let configFile;
let configFiles = ["xs-dev.json", "xs-app.json"];
for (const file of configFiles) {
if (fs.existsSync(path.join(process.cwd(), file))) {
config = JSON.parse(fs.readFileSync(path.join(process.cwd(), file), { encoding: "utf8" }));
configFile = file;
LOG.info(`Using configuration from ${path.join(process.cwd(), configFile)}`);
break;
}
}
config.dependencyRoutes = {};
config.routes?.forEach((route) => {
if (route.dependency) {
if (config.dependencyRoutes[`${route.dependency}`]) {
throw new Error(`Duplicate dependency "${route.dependency}" found in file ${path.join(process.cwd(), configFile)}.`);
} else {
config.dependencyRoutes[`${route.dependency}`] = {};
Object.assign(config.dependencyRoutes[`${route.dependency}`], route);
}
}
});
return config;
};
/**
* Applies the `config.dependencyRoutes` to the `config.routes` and removes them.
* @param {Object} config - the approuter configuration including all `dependencyRoutes`.
* @returns {Object} config - the approuter configuration that can be used to start the approuter.
*/
const applyDependencyConfig = (config) => {
config.routes?.forEach((route) => {
if (route.dependency) {
Object.assign(route, config.dependencyRoutes[route.dependency]);
delete route.dependency;
delete route.options;
}
});
delete config.dependencyRoutes;
LOG.info("running these routes:", config.routes);
return config;
};
/**
* Adds a destination to `process.env.destinations` for a given module.
* If a destination with this `name === moduleId` already exists, no new destination will be created.
* @param {String} moduleId - the id of the module that a destination is created for.
* @param {Number} port - the port of the localhost that the destination should point to.
* @param {String} mountPath - the path the module was mounted to and the destination should point to.
*/
const addDestination = (moduleId, port, mountPath) => {
let destinations = [];
if (process.env.destinations) {
destinations = JSON.parse(process.env.destinations);
}
let url = `http://localhost${port ? `:${port}` : ""}${mountPath || ""}`;
// only add new destination if it's not already provided
const destinationAlreadyExists = destinations.some((destination) => {
const lowerCaseDestination = {};
Object.keys(destination).forEach((key) => {
lowerCaseDestination[key.toLowerCase()] = destination[key];
});
return lowerCaseDestination.name === moduleId;
});
if (!destinationAlreadyExists) {
destinations.push({
Name: moduleId,
Authentication: "NoAuthentication",
ProxyType: "Internet",
Type: "HTTP",
URL: url,
});
process.env.destinations = JSON.stringify(destinations);
}
LOG.info("running these destinations:", JSON.parse(process.env.destinations));
};
/**
* Configures the route for a given CDS module.
* @param {String} moduleId - the id of the module that the route should be configured for.
* @param {String[]} servicesPaths - an array of service paths that the CDS module serves.
* @param {Object} route - the route that is to be configured.
* @returns {Object} the configured route.
*/
const configureCDSRoute = (moduleId, servicesPaths, route) => {
if (!route.source) {
route.source = servicesPaths
.map((path) => {
return `${path}(/.*)`;
})
.join("|");
}
route.destination = moduleId;
delete route.dependency;
return route;
};
/**
* Configures the route for a given UI5 module.
* @param {String} moduleId - the id of the module that the route should be configured for.
* @param {String} sourcePath - the path the approuter should handle the module at.
* @param {Object} route - the route that is to be configured.
* @returns {Object} the configured route.
*/
const configureUI5Route = (moduleId, sourcePath, route) => {
if (sourcePath === "/") {
// special regex to avoid endless loop
route.source = `^(?!.*(/_${sourcePath}))`;
} else {
route.source = `^${sourcePath}(/.*)$`;
route.target = "$1";
}
route.destination = moduleId;
delete route.dependency;
return route;
};
module.exports = {
parseConfig,
applyDependencyConfig,
addDestination,
configureCDSRoute,
configureUI5Route,
};