@ldgerrits/rogen 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +7 -0
- package/README.md +33 -0
- package/dist/build.js +228 -0
- package/dist/bundle.cjs +10544 -0
- package/dist/cli.js +111 -0
- package/dist/config.js +349 -0
- package/dist/constants.js +86 -0
- package/dist/execute.js +109 -0
- package/dist/index.js +110 -0
- package/dist/logger.js +104 -0
- package/dist/route.js +345 -0
- package/dist/tree.js +182 -0
- package/dist/types.js +1 -0
- package/package.json +56 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import chokidar from "chokidar";
|
|
4
|
+
import { printHelp, parseCliArgs } from "./cli.js";
|
|
5
|
+
import { resolveConfigPath, loadConfig, getEnvironment, resolveActiveModes, createFallbackConfig, } from "./config.js";
|
|
6
|
+
import { execute } from "./execute.js";
|
|
7
|
+
import { version } from "./constants.js";
|
|
8
|
+
import { ConsoleLogger } from "./logger.js";
|
|
9
|
+
async function main() {
|
|
10
|
+
const logger = new ConsoleLogger();
|
|
11
|
+
const cliArgs = parseCliArgs(process.argv.slice(2), logger);
|
|
12
|
+
if (cliArgs.help) {
|
|
13
|
+
printHelp(logger);
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
if (cliArgs.version) {
|
|
17
|
+
logger.info(`rogen ${version}`);
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
if (cliArgs.init) {
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
const targetPath = path.resolve(cwd, ".rogen.json");
|
|
23
|
+
if (fs.existsSync(targetPath)) {
|
|
24
|
+
logger.error(`a .rogen.json file already exists in this directory.`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const config = createFallbackConfig(cwd);
|
|
28
|
+
const isTs = fs.existsSync(path.join(cwd, "tsconfig.json"));
|
|
29
|
+
const isDarklua = fs.existsSync(path.join(cwd, ".darklua.json")) ||
|
|
30
|
+
fs.existsSync(path.join(cwd, ".darklua.json5"));
|
|
31
|
+
if (isTs) {
|
|
32
|
+
delete config.luau;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
delete config.ts;
|
|
36
|
+
}
|
|
37
|
+
if (!isDarklua) {
|
|
38
|
+
delete config.darklua;
|
|
39
|
+
}
|
|
40
|
+
for (const mode of ["luau", "ts", "darklua"]) {
|
|
41
|
+
if (config[mode]) {
|
|
42
|
+
delete config[mode].tags;
|
|
43
|
+
delete config[mode].globIgnorePaths;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
delete config.globIgnorePaths;
|
|
47
|
+
delete config.tags;
|
|
48
|
+
delete config.aliases;
|
|
49
|
+
delete config.verbatim;
|
|
50
|
+
delete config.casing;
|
|
51
|
+
delete config.unwrap;
|
|
52
|
+
fs.writeFileSync(targetPath, JSON.stringify(config, null, "\t"));
|
|
53
|
+
logger.success(`Created .rogen.json in the current directory.`);
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
const configPath = resolveConfigPath(cliArgs.config, logger);
|
|
57
|
+
const { config, anchor } = loadConfig(configPath, cliArgs.project);
|
|
58
|
+
const rawSources = cliArgs.source || config.source;
|
|
59
|
+
const sourceDirs = Array.isArray(rawSources) ? rawSources : [rawSources];
|
|
60
|
+
const resolveBase = cliArgs.source ? process.cwd() : anchor;
|
|
61
|
+
const sourcePaths = sourceDirs.map((s) => {
|
|
62
|
+
const sourcePath = path.resolve(resolveBase, s);
|
|
63
|
+
if (!fs.existsSync(sourcePath)) {
|
|
64
|
+
throw new Error(`Source directory not found: ${sourcePath}`);
|
|
65
|
+
}
|
|
66
|
+
return sourcePath;
|
|
67
|
+
});
|
|
68
|
+
const env = getEnvironment(anchor, cliArgs.mode);
|
|
69
|
+
const activeModes = resolveActiveModes(config, cliArgs.mode, env);
|
|
70
|
+
const success = await execute(sourcePaths, env, activeModes, config.project, config, cliArgs, anchor, logger);
|
|
71
|
+
if (!success) {
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
if (cliArgs.watch) {
|
|
75
|
+
logger.info(`Watching for file changes in: "${sourceDirs.join(", ")}" (Ctrl+C to stop)`);
|
|
76
|
+
const watcher = chokidar.watch(sourcePaths, {
|
|
77
|
+
persistent: true,
|
|
78
|
+
ignoreInitial: true,
|
|
79
|
+
});
|
|
80
|
+
let debounceTimeout;
|
|
81
|
+
let isBuilding = false;
|
|
82
|
+
watcher.on("all", (event, filePath) => {
|
|
83
|
+
logger.trace(`File change detected (${event}): ${filePath}`);
|
|
84
|
+
clearTimeout(debounceTimeout);
|
|
85
|
+
debounceTimeout = setTimeout(() => {
|
|
86
|
+
if (isBuilding)
|
|
87
|
+
return;
|
|
88
|
+
isBuilding = true;
|
|
89
|
+
try {
|
|
90
|
+
execute(sourcePaths, env, activeModes, config.project, config, cliArgs, anchor, logger);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
logger.error(err instanceof Error ? err : String(err));
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
isBuilding = false;
|
|
97
|
+
}
|
|
98
|
+
}, 100);
|
|
99
|
+
});
|
|
100
|
+
watcher.on("error", (error) => logger.error(`${error}`));
|
|
101
|
+
await new Promise(() => { }); // Keep alive
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export default function run() {
|
|
105
|
+
const logger = new ConsoleLogger();
|
|
106
|
+
main().catch((error) => {
|
|
107
|
+
logger.error(`${error.message}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
});
|
|
110
|
+
}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export var LogLevel;
|
|
2
|
+
(function (LogLevel) {
|
|
3
|
+
LogLevel[LogLevel["Off"] = 0] = "Off";
|
|
4
|
+
LogLevel[LogLevel["Error"] = 1] = "Error";
|
|
5
|
+
LogLevel[LogLevel["Warn"] = 2] = "Warn";
|
|
6
|
+
LogLevel[LogLevel["Success"] = 3] = "Success";
|
|
7
|
+
LogLevel[LogLevel["Info"] = 4] = "Info";
|
|
8
|
+
LogLevel[LogLevel["Debug"] = 5] = "Debug";
|
|
9
|
+
LogLevel[LogLevel["Trace"] = 6] = "Trace";
|
|
10
|
+
})(LogLevel || (LogLevel = {}));
|
|
11
|
+
export class AbstractLogger {
|
|
12
|
+
level = LogLevel.Info;
|
|
13
|
+
setLevel(level) {
|
|
14
|
+
this.level = level;
|
|
15
|
+
}
|
|
16
|
+
getLevel() {
|
|
17
|
+
return this.level;
|
|
18
|
+
}
|
|
19
|
+
canLog(level) {
|
|
20
|
+
return this.level !== LogLevel.Off && this.level >= level;
|
|
21
|
+
}
|
|
22
|
+
format(message, args) {
|
|
23
|
+
let result = message instanceof Error
|
|
24
|
+
? message.stack || message.message
|
|
25
|
+
: message;
|
|
26
|
+
for (const arg of args) {
|
|
27
|
+
if (arg instanceof Error) {
|
|
28
|
+
result += " " + (arg.stack || arg.message);
|
|
29
|
+
}
|
|
30
|
+
else if (typeof arg === "object") {
|
|
31
|
+
try {
|
|
32
|
+
result += " " + JSON.stringify(arg);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
result += " [Unserializable Object]";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
result += " " + arg;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function getTimeStamp(wrapInBrackets = true) {
|
|
46
|
+
const now = new Date();
|
|
47
|
+
const h = String(now.getHours()).padStart(2, "0");
|
|
48
|
+
const m = String(now.getMinutes()).padStart(2, "0");
|
|
49
|
+
const s = String(now.getSeconds()).padStart(2, "0");
|
|
50
|
+
const timeStamp = `${h}:${m}:${s}`;
|
|
51
|
+
return wrapInBrackets ? `[${timeStamp}]` : timeStamp;
|
|
52
|
+
}
|
|
53
|
+
export class ConsoleLogger extends AbstractLogger {
|
|
54
|
+
colors = {
|
|
55
|
+
reset: "\x1b[0m",
|
|
56
|
+
red: "\x1b[31m",
|
|
57
|
+
green: "\x1b[32m",
|
|
58
|
+
yellow: "\x1b[33m",
|
|
59
|
+
gray: "\x1b[90m",
|
|
60
|
+
cyan: "\x1b[36m",
|
|
61
|
+
};
|
|
62
|
+
error(message, ...args) {
|
|
63
|
+
if (this.canLog(LogLevel.Error)) {
|
|
64
|
+
console.error(`${this.colors.red}error:${this.colors.reset} ${this.format(message, args)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
warn(message, ...args) {
|
|
68
|
+
if (this.canLog(LogLevel.Warn)) {
|
|
69
|
+
console.warn(`${this.colors.yellow}warning:${this.colors.reset} ${this.format(message, args)}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
success(message, ...args) {
|
|
73
|
+
if (this.canLog(LogLevel.Info)) {
|
|
74
|
+
console.info(`${getTimeStamp()} ${this.colors.green}success:${this.colors.reset} ${this.format(message, args)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
info(message, ...args) {
|
|
78
|
+
if (this.canLog(LogLevel.Info)) {
|
|
79
|
+
console.info(this.format(message, args));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
debug(message, ...args) {
|
|
83
|
+
if (this.canLog(LogLevel.Debug)) {
|
|
84
|
+
console.debug(`${this.colors.gray}[debug] ${this.format(message, args)}${this.colors.reset}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
trace(message, ...args) {
|
|
88
|
+
if (this.canLog(LogLevel.Trace)) {
|
|
89
|
+
console.debug(`${this.colors.cyan}[trace] ${this.format(message, args)}${this.colors.reset}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class NullLogger {
|
|
94
|
+
setLevel(_level) { }
|
|
95
|
+
getLevel() {
|
|
96
|
+
return LogLevel.Off;
|
|
97
|
+
}
|
|
98
|
+
error(_message, ..._args) { }
|
|
99
|
+
warn(_message, ..._args) { }
|
|
100
|
+
success(_message, ..._args) { }
|
|
101
|
+
info(_message, ..._args) { }
|
|
102
|
+
debug(_message, ..._args) { }
|
|
103
|
+
trace(_message, ..._args) { }
|
|
104
|
+
}
|
package/dist/route.js
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { serviceAliases, serverContainers, clientContainers, } from "./constants.js";
|
|
3
|
+
import { toPosix } from "./tree.js";
|
|
4
|
+
function resolveFolderRouting(parts, context) {
|
|
5
|
+
const { routingMaps, directoryMarkers, activeTags } = context;
|
|
6
|
+
const { lowerCaseMap } = routingMaps;
|
|
7
|
+
const virtualParts = [];
|
|
8
|
+
let targetService = "ReplicatedStorage";
|
|
9
|
+
let lastRouteKeyword = null;
|
|
10
|
+
let tagKeyword = null;
|
|
11
|
+
const flags = {
|
|
12
|
+
structure: false,
|
|
13
|
+
verbatim: false,
|
|
14
|
+
unwrap: false,
|
|
15
|
+
};
|
|
16
|
+
// Marker routing
|
|
17
|
+
const rootMarkers = directoryMarkers[""];
|
|
18
|
+
if (rootMarkers) {
|
|
19
|
+
if (rootMarkers.includes("structure")) {
|
|
20
|
+
flags.structure = true;
|
|
21
|
+
}
|
|
22
|
+
if (rootMarkers.includes("verbatim")) {
|
|
23
|
+
flags.verbatim = true;
|
|
24
|
+
}
|
|
25
|
+
if (rootMarkers.includes("unwrap")) {
|
|
26
|
+
flags.unwrap = true;
|
|
27
|
+
}
|
|
28
|
+
if (!flags.structure) {
|
|
29
|
+
const routingMarker = rootMarkers.find((m) => lowerCaseMap[m]);
|
|
30
|
+
if (routingMarker) {
|
|
31
|
+
targetService = lowerCaseMap[routingMarker];
|
|
32
|
+
lastRouteKeyword = routingMarker;
|
|
33
|
+
if (serviceAliases.has(routingMarker))
|
|
34
|
+
tagKeyword = routingMarker;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Folder path routing
|
|
39
|
+
let currentPath = "";
|
|
40
|
+
for (const part of parts) {
|
|
41
|
+
currentPath = currentPath ? `${currentPath}/${part}` : part;
|
|
42
|
+
let lowerPart = part.toLowerCase();
|
|
43
|
+
let isInvisible = false;
|
|
44
|
+
if (lowerPart.startsWith("(") && lowerPart.endsWith(")")) {
|
|
45
|
+
isInvisible = true;
|
|
46
|
+
lowerPart = lowerPart.slice(1, -1);
|
|
47
|
+
}
|
|
48
|
+
const markers = directoryMarkers
|
|
49
|
+
? directoryMarkers[currentPath]
|
|
50
|
+
: undefined;
|
|
51
|
+
if (markers) {
|
|
52
|
+
if (markers.includes("structure")) {
|
|
53
|
+
flags.structure = true;
|
|
54
|
+
}
|
|
55
|
+
if (markers.includes("verbatim")) {
|
|
56
|
+
flags.verbatim = true;
|
|
57
|
+
}
|
|
58
|
+
if (markers.includes("unwrap")) {
|
|
59
|
+
flags.unwrap = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (flags.structure) {
|
|
63
|
+
if (!activeTags.has(lowerPart)) {
|
|
64
|
+
virtualParts.push(part);
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const matchedService = lowerCaseMap[lowerPart];
|
|
69
|
+
if (markers) {
|
|
70
|
+
const routingMarker = markers.find((m) => lowerCaseMap[m]);
|
|
71
|
+
if (routingMarker) {
|
|
72
|
+
targetService = lowerCaseMap[routingMarker];
|
|
73
|
+
lastRouteKeyword = routingMarker;
|
|
74
|
+
if (serviceAliases.has(routingMarker))
|
|
75
|
+
tagKeyword = routingMarker;
|
|
76
|
+
if (!matchedService &&
|
|
77
|
+
!activeTags.has(lowerPart) &&
|
|
78
|
+
!isInvisible) {
|
|
79
|
+
virtualParts.push(part);
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (matchedService) {
|
|
85
|
+
targetService = matchedService;
|
|
86
|
+
lastRouteKeyword = lowerPart;
|
|
87
|
+
if (serviceAliases.has(lowerPart)) {
|
|
88
|
+
tagKeyword = lowerPart;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
if (!activeTags.has(lowerPart) && !isInvisible) {
|
|
93
|
+
virtualParts.push(part);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
targetService,
|
|
99
|
+
virtualParts,
|
|
100
|
+
lastRouteKeyword,
|
|
101
|
+
tagKeyword,
|
|
102
|
+
flags,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function resolveAffixes(basename, isInit, routingMaps) {
|
|
106
|
+
const { lowerCaseMap, mergedServices, separatorSuffixRegex, pascalCaseSuffixRegex, separatorPrefixRegex, camelCasePrefixRegex, } = routingMaps;
|
|
107
|
+
let match = basename.match(separatorSuffixRegex);
|
|
108
|
+
if (match && match[0].length < basename.length) {
|
|
109
|
+
const suffix = match[1].toLowerCase();
|
|
110
|
+
return {
|
|
111
|
+
mappedService: lowerCaseMap[suffix],
|
|
112
|
+
matchedLength: match[0].length,
|
|
113
|
+
exactMatch: match[0],
|
|
114
|
+
tagKeyword: !isInit && serviceAliases.has(suffix) ? suffix : undefined,
|
|
115
|
+
isPrefix: false,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
match = basename.match(pascalCaseSuffixRegex);
|
|
119
|
+
if (match && match[0].length < basename.length) {
|
|
120
|
+
const suffix = match[1].toLowerCase();
|
|
121
|
+
return {
|
|
122
|
+
mappedService: mergedServices[match[1]],
|
|
123
|
+
matchedLength: match[0].length,
|
|
124
|
+
exactMatch: match[0],
|
|
125
|
+
tagKeyword: !isInit && serviceAliases.has(suffix) ? suffix : undefined,
|
|
126
|
+
isPrefix: false,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
match = basename.match(separatorPrefixRegex);
|
|
130
|
+
if (match && match[0].length < basename.length) {
|
|
131
|
+
const prefix = match[1].toLowerCase();
|
|
132
|
+
return {
|
|
133
|
+
mappedService: lowerCaseMap[prefix],
|
|
134
|
+
matchedLength: match[0].length,
|
|
135
|
+
exactMatch: match[0],
|
|
136
|
+
tagKeyword: !isInit && serviceAliases.has(prefix) ? prefix : undefined,
|
|
137
|
+
isPrefix: true,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
match = basename.match(camelCasePrefixRegex);
|
|
141
|
+
if (match && match[0].length < basename.length) {
|
|
142
|
+
const prefix = match[1].toLowerCase();
|
|
143
|
+
return {
|
|
144
|
+
mappedService: lowerCaseMap[prefix],
|
|
145
|
+
matchedLength: match[1].length,
|
|
146
|
+
exactMatch: match[0],
|
|
147
|
+
tagKeyword: !isInit && serviceAliases.has(prefix) ? prefix : undefined,
|
|
148
|
+
isPrefix: true,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
function getWrapperFolder(targetService, tagKeyword) {
|
|
154
|
+
if (serverContainers.has(targetService))
|
|
155
|
+
return "server";
|
|
156
|
+
if (clientContainers.has(targetService))
|
|
157
|
+
return "client";
|
|
158
|
+
if (tagKeyword)
|
|
159
|
+
return tagKeyword;
|
|
160
|
+
return "shared";
|
|
161
|
+
}
|
|
162
|
+
export function resolveRoute(relativePath, isInit, context, isSync = false) {
|
|
163
|
+
const { emitLegacyScripts, isTsProject, build, routingMaps, verbatim, knownTags, activeTags, tagRegexes, directoryMarkers, } = context;
|
|
164
|
+
const parts = relativePath ? relativePath.split(/[\\/]/) : [];
|
|
165
|
+
let filename;
|
|
166
|
+
let rawBasename;
|
|
167
|
+
if (isSync) {
|
|
168
|
+
filename = parts.length > 0 ? parts[parts.length - 1] : "";
|
|
169
|
+
rawBasename = filename;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
filename = parts.length > 0 ? parts.pop() : "";
|
|
173
|
+
rawBasename = filename
|
|
174
|
+
? path.basename(filename, path.extname(filename))
|
|
175
|
+
: "";
|
|
176
|
+
}
|
|
177
|
+
// Detect and strip the hoisting prefix
|
|
178
|
+
let isHoisted = false;
|
|
179
|
+
let cleanBasename = rawBasename;
|
|
180
|
+
if (cleanBasename.startsWith("^")) {
|
|
181
|
+
isHoisted = true;
|
|
182
|
+
cleanBasename = cleanBasename.slice(1);
|
|
183
|
+
}
|
|
184
|
+
let dropped = false;
|
|
185
|
+
// Check folder paths and folder marker files
|
|
186
|
+
let currentRel = "";
|
|
187
|
+
for (const part of parts) {
|
|
188
|
+
currentRel = currentRel ? `${currentRel}/${part}` : part;
|
|
189
|
+
let lowerPart = part.toLowerCase();
|
|
190
|
+
// Strip invisible folder syntax for drop checks
|
|
191
|
+
if (lowerPart.startsWith("(") && lowerPart.endsWith(")")) {
|
|
192
|
+
lowerPart = lowerPart.slice(1, -1);
|
|
193
|
+
}
|
|
194
|
+
// Drop if folder name is an inactive env
|
|
195
|
+
if (knownTags.has(lowerPart) && !activeTags.has(lowerPart)) {
|
|
196
|
+
dropped = true;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
// Drop if folder contains an inactive env marker file
|
|
200
|
+
const markers = directoryMarkers?.[currentRel];
|
|
201
|
+
if (markers) {
|
|
202
|
+
for (const m of markers) {
|
|
203
|
+
if (knownTags.has(m) && !activeTags.has(m)) {
|
|
204
|
+
dropped = true;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (dropped)
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
// Check root directory markers for drops
|
|
213
|
+
const rootMarkers = directoryMarkers?.[""];
|
|
214
|
+
if (!dropped && rootMarkers) {
|
|
215
|
+
for (const m of rootMarkers) {
|
|
216
|
+
if (knownTags.has(m) && !activeTags.has(m)) {
|
|
217
|
+
dropped = true;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Check file affixes
|
|
223
|
+
if (!dropped && !isSync && cleanBasename) {
|
|
224
|
+
const delimiterSplit = cleanBasename.split(/[.\-_+]/);
|
|
225
|
+
for (const part of delimiterSplit) {
|
|
226
|
+
const lowerPart = part.toLowerCase();
|
|
227
|
+
if (knownTags.has(lowerPart) && !activeTags.has(lowerPart)) {
|
|
228
|
+
dropped = true;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Stop processing and flag for removal
|
|
234
|
+
if (dropped) {
|
|
235
|
+
return {
|
|
236
|
+
targetService: "",
|
|
237
|
+
wrapperFolder: "",
|
|
238
|
+
virtualParts: [],
|
|
239
|
+
nodeName: "",
|
|
240
|
+
projectPath: "",
|
|
241
|
+
dropped: true,
|
|
242
|
+
unwrap: false,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// Strip active environment affixes
|
|
246
|
+
let basename = cleanBasename;
|
|
247
|
+
if (!isSync) {
|
|
248
|
+
for (const regexSet of tagRegexes) {
|
|
249
|
+
while (regexSet.suffix.test(basename)) {
|
|
250
|
+
basename = basename.replace(regexSet.suffix, "");
|
|
251
|
+
}
|
|
252
|
+
while (regexSet.prefix.test(basename)) {
|
|
253
|
+
basename = basename.replace(regexSet.prefix, "");
|
|
254
|
+
}
|
|
255
|
+
while (regexSet.middle.test(basename)) {
|
|
256
|
+
basename = basename.replace(regexSet.middle, "");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Folder and marker routing
|
|
261
|
+
const { targetService: folderTarget, virtualParts, lastRouteKeyword, tagKeyword: folderFlag, flags, } = resolveFolderRouting(parts, context);
|
|
262
|
+
// Apply hoisting
|
|
263
|
+
if (isHoisted) {
|
|
264
|
+
virtualParts.length = 0;
|
|
265
|
+
}
|
|
266
|
+
// Affix routing
|
|
267
|
+
const affix = flags.structure || isSync
|
|
268
|
+
? null
|
|
269
|
+
: resolveAffixes(basename, isInit, routingMaps);
|
|
270
|
+
// Resolve overrides
|
|
271
|
+
let targetService = affix?.mappedService ?? folderTarget;
|
|
272
|
+
const tagKeyword = affix?.tagKeyword ?? folderFlag;
|
|
273
|
+
// Resolve namespace wrapper folder
|
|
274
|
+
const wrapperFolder = getWrapperFolder(targetService, tagKeyword);
|
|
275
|
+
// Determine if the wrapper folder should be skipped
|
|
276
|
+
const unwrap = context.unwrap || flags.unwrap;
|
|
277
|
+
// Edge case: Scripts with non-legacy RunContext run incorrectly in StarterPlayer container,
|
|
278
|
+
// hence they need to be put in ReplicatedStorage.
|
|
279
|
+
const isStarterPlayerContainer = targetService === "StarterPlayerScripts" ||
|
|
280
|
+
targetService === "StarterCharacterScripts";
|
|
281
|
+
if (emitLegacyScripts === false && isStarterPlayerContainer) {
|
|
282
|
+
targetService = "ReplicatedStorage";
|
|
283
|
+
}
|
|
284
|
+
// Node naming and path formatting
|
|
285
|
+
let nodeName = basename;
|
|
286
|
+
let projectPath;
|
|
287
|
+
if (isSync) {
|
|
288
|
+
projectPath = toPosix(path.join(build, relativePath));
|
|
289
|
+
if (virtualParts.length > 0) {
|
|
290
|
+
nodeName = virtualParts.pop();
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
nodeName = lastRouteKeyword
|
|
294
|
+
? lastRouteKeyword
|
|
295
|
+
: filename || "source";
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
else if (isInit) {
|
|
299
|
+
const folderRelativePath = path.dirname(relativePath);
|
|
300
|
+
projectPath = toPosix(path.join(build, folderRelativePath));
|
|
301
|
+
if (virtualParts.length > 0) {
|
|
302
|
+
nodeName = virtualParts.pop();
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
nodeName = lastRouteKeyword ? lastRouteKeyword : "source";
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
let compiledRelativePath = relativePath;
|
|
310
|
+
if (isTsProject) {
|
|
311
|
+
const compiledFilename = filename.replace(/\.tsx?$/i, ".luau");
|
|
312
|
+
compiledRelativePath = path.join(path.dirname(relativePath), compiledFilename);
|
|
313
|
+
}
|
|
314
|
+
projectPath = toPosix(path.join(build, compiledRelativePath));
|
|
315
|
+
if (affix) {
|
|
316
|
+
const keepFullNames = verbatim || flags.verbatim;
|
|
317
|
+
let shouldStrip = !keepFullNames;
|
|
318
|
+
// Rojo relies on '.server' and '.client' explicitly for script types.
|
|
319
|
+
// Even if verbatim is true, we must strip these exact dot-prefixes.
|
|
320
|
+
if (keepFullNames) {
|
|
321
|
+
const exactMatch = affix.exactMatch.toLowerCase();
|
|
322
|
+
if (exactMatch === ".server" || exactMatch === ".client") {
|
|
323
|
+
shouldStrip = true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (shouldStrip) {
|
|
327
|
+
if (affix.isPrefix) {
|
|
328
|
+
nodeName = basename.slice(affix.matchedLength);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
nodeName = basename.slice(0, -affix.matchedLength);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
targetService,
|
|
338
|
+
wrapperFolder,
|
|
339
|
+
virtualParts,
|
|
340
|
+
nodeName,
|
|
341
|
+
projectPath,
|
|
342
|
+
dropped: false,
|
|
343
|
+
unwrap,
|
|
344
|
+
};
|
|
345
|
+
}
|