@flamework-experimental/transformer 2.0.0-alpha.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/README.md +66 -0
- package/flamework-schema.json +76 -0
- package/flamework.config.schema.json +197 -0
- package/out/classes/buildInfo.js +467 -0
- package/out/classes/diagnostics.js +110 -0
- package/out/classes/logger.js +201 -0
- package/out/classes/nodeMetadata.js +232 -0
- package/out/classes/transformState.js +623 -0
- package/out/index.js +75 -0
- package/out/transformations/expressions/transformAccessExpression.js +35 -0
- package/out/transformations/expressions/transformBinaryExpression.js +57 -0
- package/out/transformations/expressions/transformCallExpression.js +33 -0
- package/out/transformations/expressions/transformDeleteExpression.js +22 -0
- package/out/transformations/expressions/transformNewExpression.js +17 -0
- package/out/transformations/expressions/transformUnaryExpression.js +63 -0
- package/out/transformations/macros/intrinsics/components.js +64 -0
- package/out/transformations/macros/intrinsics/env.js +31 -0
- package/out/transformations/macros/intrinsics/guards.js +43 -0
- package/out/transformations/macros/intrinsics/inlining.js +22 -0
- package/out/transformations/macros/intrinsics/networking.js +131 -0
- package/out/transformations/macros/intrinsics/parameters.js +81 -0
- package/out/transformations/macros/intrinsics/paths.js +42 -0
- package/out/transformations/macros/updateComponentConfig.js +409 -0
- package/out/transformations/plugins/nodeFactory.js +159 -0
- package/out/transformations/plugins/pluginHost.js +235 -0
- package/out/transformations/plugins/typeFacade.js +242 -0
- package/out/transformations/statements/transformClassDeclaration.js +282 -0
- package/out/transformations/transformExpression.js +34 -0
- package/out/transformations/transformFile.js +78 -0
- package/out/transformations/transformNetworkingCall.js +566 -0
- package/out/transformations/transformNode.js +27 -0
- package/out/transformations/transformStatement.js +57 -0
- package/out/transformations/transformStatementList.js +64 -0
- package/out/transformations/transformUserMacro.js +698 -0
- package/out/transformer.js +52 -0
- package/out/util/cache.js +10 -0
- package/out/util/constants.js +5 -0
- package/out/util/diagnosticsUtils.js +112 -0
- package/out/util/env.js +267 -0
- package/out/util/factory.js +583 -0
- package/out/util/functions/addLeadingComment.js +13 -0
- package/out/util/functions/arePathsEqual.js +14 -0
- package/out/util/functions/assert.js +17 -0
- package/out/util/functions/buildGuardFromType.js +713 -0
- package/out/util/functions/buildInstanceShape.js +156 -0
- package/out/util/functions/buildSerializerFromType.js +2309 -0
- package/out/util/functions/createPathTranslator.js +54 -0
- package/out/util/functions/emitTypescriptMismatch.js +80 -0
- package/out/util/functions/getDeclarationName.js +23 -0
- package/out/util/functions/getDeclarationOfType.js +7 -0
- package/out/util/functions/getIndexExpression.js +16 -0
- package/out/util/functions/getInstanceTypeFromType.js +75 -0
- package/out/util/functions/getNodeList.js +6 -0
- package/out/util/functions/getPackageJson.js +44 -0
- package/out/util/functions/getSuperClasses.js +51 -0
- package/out/util/functions/isAttributesAccess.js +23 -0
- package/out/util/functions/isCleanBuildDirectory.js +13 -0
- package/out/util/functions/isDefinedType.js +16 -0
- package/out/util/functions/isPathDescendantOf.js +25 -0
- package/out/util/functions/isTupleType.js +10 -0
- package/out/util/functions/parseCommandLine.js +31 -0
- package/out/util/functions/shuffle.js +39 -0
- package/out/util/functions/tryResolve.js +15 -0
- package/out/util/functions/validateConstraintMetadata.js +60 -0
- package/out/util/packages.js +12 -0
- package/out/util/projectConfig.js +221 -0
- package/out/util/schema.js +80 -0
- package/out/util/tsInternals.js +16 -0
- package/out/util/uid.js +227 -0
- package/package.json +45 -0
- package/rojo-schema.json +34 -0
- package/types.d.ts +4 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __values = (this && this.__values) || function(o) {
|
|
14
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
15
|
+
if (m) return m.call(o);
|
|
16
|
+
if (o && typeof o.length === "number") return {
|
|
17
|
+
next: function () {
|
|
18
|
+
if (o && i >= o.length) o = void 0;
|
|
19
|
+
return { value: o && o[i++], done: !o };
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
23
|
+
};
|
|
24
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
25
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
26
|
+
if (!m) return o;
|
|
27
|
+
var i = m.call(o), r, ar = [], e;
|
|
28
|
+
try {
|
|
29
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
30
|
+
}
|
|
31
|
+
catch (error) { e = { error: error }; }
|
|
32
|
+
finally {
|
|
33
|
+
try {
|
|
34
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
35
|
+
}
|
|
36
|
+
finally { if (e) throw e.error; }
|
|
37
|
+
}
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.RUNTIME_SECTIONS = exports.PROJECT_CONFIG_NAME = void 0;
|
|
45
|
+
exports.findProjectConfig = findProjectConfig;
|
|
46
|
+
exports.readProjectConfig = readProjectConfig;
|
|
47
|
+
exports.mergeTransformerConfig = mergeTransformerConfig;
|
|
48
|
+
exports.getRuntimeConfig = getRuntimeConfig;
|
|
49
|
+
exports.fingerprintProjectConfig = fingerprintProjectConfig;
|
|
50
|
+
exports.loadProjectConfig = loadProjectConfig;
|
|
51
|
+
var crypto_1 = __importDefault(require("crypto"));
|
|
52
|
+
var fs_1 = __importDefault(require("fs"));
|
|
53
|
+
var path_1 = __importDefault(require("path"));
|
|
54
|
+
var typescript_1 = __importDefault(require("typescript"));
|
|
55
|
+
var logger_1 = require("../classes/logger");
|
|
56
|
+
var env_1 = require("./env");
|
|
57
|
+
var schema_1 = require("./schema");
|
|
58
|
+
/** The file every Flamework package reads its options from, found from the tsconfig's directory up to the package root. */
|
|
59
|
+
exports.PROJECT_CONFIG_NAME = "flamework.config.json";
|
|
60
|
+
exports.RUNTIME_SECTIONS = ["core", "networking", "components", "scopes", "testing"];
|
|
61
|
+
/**
|
|
62
|
+
* Locates `flamework.config.json`.
|
|
63
|
+
*
|
|
64
|
+
* With `configFile` set on the tsconfig entry, that path (relative to the tsconfig's directory) is
|
|
65
|
+
* used and must exist. Otherwise the tsconfig's directory is searched first, then each parent up to
|
|
66
|
+
* and including the package root, so a multi-place repository can keep one file at the root and
|
|
67
|
+
* still override it per place.
|
|
68
|
+
*/
|
|
69
|
+
function findProjectConfig(projectDirectory, rootDirectory, explicitPath) {
|
|
70
|
+
if (explicitPath !== undefined) {
|
|
71
|
+
var resolved = path_1.default.resolve(projectDirectory, explicitPath);
|
|
72
|
+
if (!fs_1.default.existsSync(resolved)) {
|
|
73
|
+
throw new Error("The Flamework config file '".concat(explicitPath, "' does not exist (looked at '").concat(resolved, "')."));
|
|
74
|
+
}
|
|
75
|
+
return resolved;
|
|
76
|
+
}
|
|
77
|
+
var root = path_1.default.resolve(rootDirectory);
|
|
78
|
+
var current = path_1.default.resolve(projectDirectory);
|
|
79
|
+
while (true) {
|
|
80
|
+
var candidate = path_1.default.join(current, exports.PROJECT_CONFIG_NAME);
|
|
81
|
+
if (fs_1.default.existsSync(candidate)) {
|
|
82
|
+
return candidate;
|
|
83
|
+
}
|
|
84
|
+
if (path_1.default.relative(current, root) === "") {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
var parent_1 = path_1.default.dirname(current);
|
|
88
|
+
if (parent_1 === current) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
current = parent_1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Reads and validates a `flamework.config.json`. Comments and trailing commas are allowed, as in tsconfig.
|
|
96
|
+
*
|
|
97
|
+
* Every string in the file can reference the environment as `${NAME}` or `${NAME:-fallback}`
|
|
98
|
+
* (`$$` for a literal dollar). The environment is `.env` and `.env.local` next to the file with the
|
|
99
|
+
* process environment on top, unless one is given. A string sitting where the schema expects a
|
|
100
|
+
* boolean, a number or a list of strings is converted before validation, since a variable is
|
|
101
|
+
* always a string.
|
|
102
|
+
*/
|
|
103
|
+
function readProjectConfig(configPath, env) {
|
|
104
|
+
if (env === void 0) { env = (0, env_1.loadEnv)(path_1.default.dirname(configPath)); }
|
|
105
|
+
var text = fs_1.default.readFileSync(configPath, "utf8");
|
|
106
|
+
// TypeScript asserts a forward-slash path when it attaches a diagnostic to the JSON source file.
|
|
107
|
+
var _a = typescript_1.default.parseConfigFileTextToJson(configPath.replace(/\\/g, "/"), text), parsed = _a.config, error = _a.error;
|
|
108
|
+
if (error) {
|
|
109
|
+
throw new Error("Failed to parse ".concat(configPath, ": ").concat(typescript_1.default.flattenDiagnosticMessageText(error.messageText, "\n")));
|
|
110
|
+
}
|
|
111
|
+
var describe = function (pointer) { return "".concat(configPath, ": '").concat(pointer === "" ? "/" : pointer, "'"); };
|
|
112
|
+
var config = (0, env_1.coerceBySchema)((0, env_1.substituteEnv)(parsed, env, describe).value, (0, schema_1.getSchema)("projectConfig"), describe);
|
|
113
|
+
if (!(0, schema_1.validateSchema)("projectConfig", config)) {
|
|
114
|
+
var details = (0, schema_1.getSchemaErrors)().map(function (v) {
|
|
115
|
+
var location = v.instancePath === "" ? "/" : v.instancePath;
|
|
116
|
+
var extra = v.params && "additionalProperty" in v.params ? " '".concat(v.params.additionalProperty, "'") : "";
|
|
117
|
+
return "".concat(location, " ").concat(v.message).concat(extra);
|
|
118
|
+
});
|
|
119
|
+
throw new Error("Invalid ".concat(configPath, ":\n ").concat(details.join("\n ")));
|
|
120
|
+
}
|
|
121
|
+
var projectConfig = __assign({}, config);
|
|
122
|
+
delete projectConfig.$schema;
|
|
123
|
+
return projectConfig;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Combines the file's transformer section with the options set inline on the tsconfig entry.
|
|
127
|
+
*
|
|
128
|
+
* Inline options win: they are the more specific place to have written something. `optimizations`
|
|
129
|
+
* merges one level deep so that an inline override of one optimisation keeps the file's others.
|
|
130
|
+
*/
|
|
131
|
+
function mergeTransformerConfig(fileOptions, inlineConfig) {
|
|
132
|
+
var e_1, _a;
|
|
133
|
+
var merged = __assign({}, (fileOptions !== null && fileOptions !== void 0 ? fileOptions : {}));
|
|
134
|
+
try {
|
|
135
|
+
for (var _b = __values(Object.entries(inlineConfig)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
136
|
+
var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
|
|
137
|
+
if (value !== undefined) {
|
|
138
|
+
merged[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
143
|
+
finally {
|
|
144
|
+
try {
|
|
145
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
146
|
+
}
|
|
147
|
+
finally { if (e_1) throw e_1.error; }
|
|
148
|
+
}
|
|
149
|
+
if ((fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.optimizations) && inlineConfig.optimizations) {
|
|
150
|
+
merged.optimizations = __assign(__assign({}, fileOptions.optimizations), inlineConfig.optimizations);
|
|
151
|
+
}
|
|
152
|
+
return merged;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The runtime sections of a project config, or `undefined` when it has none, so that a project
|
|
156
|
+
* without any gets no `config.json` artifact.
|
|
157
|
+
*/
|
|
158
|
+
function getRuntimeConfig(project) {
|
|
159
|
+
var e_2, _a;
|
|
160
|
+
var runtime = {};
|
|
161
|
+
var any = false;
|
|
162
|
+
try {
|
|
163
|
+
for (var RUNTIME_SECTIONS_1 = __values(exports.RUNTIME_SECTIONS), RUNTIME_SECTIONS_1_1 = RUNTIME_SECTIONS_1.next(); !RUNTIME_SECTIONS_1_1.done; RUNTIME_SECTIONS_1_1 = RUNTIME_SECTIONS_1.next()) {
|
|
164
|
+
var section = RUNTIME_SECTIONS_1_1.value;
|
|
165
|
+
var value = project[section];
|
|
166
|
+
if (value !== undefined) {
|
|
167
|
+
runtime[section] = value;
|
|
168
|
+
any = true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
173
|
+
finally {
|
|
174
|
+
try {
|
|
175
|
+
if (RUNTIME_SECTIONS_1_1 && !RUNTIME_SECTIONS_1_1.done && (_a = RUNTIME_SECTIONS_1.return)) _a.call(RUNTIME_SECTIONS_1);
|
|
176
|
+
}
|
|
177
|
+
finally { if (e_2) throw e_2.error; }
|
|
178
|
+
}
|
|
179
|
+
return any ? runtime : undefined;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* A fingerprint of everything a compilation takes from the config file and the environment: the
|
|
183
|
+
* effective options, the whole file after substitution, and the environment itself, since
|
|
184
|
+
* `Flamework.env` reads variables the file never mentions.
|
|
185
|
+
*
|
|
186
|
+
* A watcher reads all of this once, when it starts, and compares later reads against the first:
|
|
187
|
+
* a change means files that do not recompile would disagree with files that do, so the first read
|
|
188
|
+
* stays in force and the watcher says to restart.
|
|
189
|
+
*/
|
|
190
|
+
function fingerprintProjectConfig(loaded) {
|
|
191
|
+
var stable = function (value) {
|
|
192
|
+
if (Array.isArray(value)) {
|
|
193
|
+
return value.map(stable);
|
|
194
|
+
}
|
|
195
|
+
if (value !== null && typeof value === "object") {
|
|
196
|
+
return Object.fromEntries(Object.keys(value)
|
|
197
|
+
.sort()
|
|
198
|
+
.map(function (key) { return [key, stable(value[key])]; }));
|
|
199
|
+
}
|
|
200
|
+
return value;
|
|
201
|
+
};
|
|
202
|
+
var snapshot = { config: loaded.config, project: loaded.project, configPath: loaded.configPath, env: loaded.env };
|
|
203
|
+
return crypto_1.default
|
|
204
|
+
.createHash("sha1")
|
|
205
|
+
.update(JSON.stringify(stable(snapshot)))
|
|
206
|
+
.digest("hex");
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Resolves the project config, the effective transformer options and the environment for a
|
|
210
|
+
* compilation.
|
|
211
|
+
*/
|
|
212
|
+
function loadProjectConfig(projectDirectory, rootDirectory, inlineConfig, processEnv) {
|
|
213
|
+
var configPath = findProjectConfig(projectDirectory, rootDirectory, inlineConfig.configFile);
|
|
214
|
+
var env = (0, env_1.loadEnv)(configPath !== undefined ? path_1.default.dirname(configPath) : projectDirectory, processEnv);
|
|
215
|
+
if (configPath === undefined) {
|
|
216
|
+
return { config: mergeTransformerConfig(undefined, inlineConfig), project: {}, env: env };
|
|
217
|
+
}
|
|
218
|
+
var project = readProjectConfig(configPath, env);
|
|
219
|
+
logger_1.Logger.infoIfVerbose("Loaded project config from ".concat(path_1.default.relative(projectDirectory, configPath) || configPath));
|
|
220
|
+
return { config: mergeTransformerConfig(project.transformer, inlineConfig), project: project, configPath: configPath, env: env };
|
|
221
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __values = (this && this.__values) || function(o) {
|
|
3
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
4
|
+
if (m) return m.call(o);
|
|
5
|
+
if (o && typeof o.length === "number") return {
|
|
6
|
+
next: function () {
|
|
7
|
+
if (o && i >= o.length) o = void 0;
|
|
8
|
+
return { value: o && o[i++], done: !o };
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
12
|
+
};
|
|
13
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
14
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
15
|
+
if (!m) return o;
|
|
16
|
+
var i = m.call(o), r, ar = [], e;
|
|
17
|
+
try {
|
|
18
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
19
|
+
}
|
|
20
|
+
catch (error) { e = { error: error }; }
|
|
21
|
+
finally {
|
|
22
|
+
try {
|
|
23
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
24
|
+
}
|
|
25
|
+
finally { if (e) throw e.error; }
|
|
26
|
+
}
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
30
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
|
+
};
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.getSchemaErrors = getSchemaErrors;
|
|
34
|
+
exports.getSchema = getSchema;
|
|
35
|
+
exports.validateSchema = validateSchema;
|
|
36
|
+
var ajv_1 = __importDefault(require("ajv"));
|
|
37
|
+
var path_1 = __importDefault(require("path"));
|
|
38
|
+
var fs_1 = __importDefault(require("fs"));
|
|
39
|
+
/** Schemas that live in their own file, so editors can reference them directly. */
|
|
40
|
+
var STANDALONE_SCHEMAS = {
|
|
41
|
+
projectConfig: "flamework.config.schema.json",
|
|
42
|
+
};
|
|
43
|
+
var SCHEMA = createSchema();
|
|
44
|
+
function createSchema() {
|
|
45
|
+
var e_1, _a;
|
|
46
|
+
var schema = new ajv_1.default();
|
|
47
|
+
schema.addSchema(readSchema("flamework-schema.json"), "root");
|
|
48
|
+
try {
|
|
49
|
+
for (var _b = __values(Object.entries(STANDALONE_SCHEMAS)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
50
|
+
var _d = __read(_c.value, 2), key = _d[0], file = _d[1];
|
|
51
|
+
schema.addSchema(readSchema(file), key);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
55
|
+
finally {
|
|
56
|
+
try {
|
|
57
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
58
|
+
}
|
|
59
|
+
finally { if (e_1) throw e_1.error; }
|
|
60
|
+
}
|
|
61
|
+
return schema;
|
|
62
|
+
}
|
|
63
|
+
function readSchema(file) {
|
|
64
|
+
return JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, "../..", file), { encoding: "utf8" }));
|
|
65
|
+
}
|
|
66
|
+
function getSchemaErrors() {
|
|
67
|
+
var _a;
|
|
68
|
+
return (_a = SCHEMA.errors) !== null && _a !== void 0 ? _a : [];
|
|
69
|
+
}
|
|
70
|
+
/** The parsed schema itself, for code that walks it alongside a value. */
|
|
71
|
+
function getSchema(key) {
|
|
72
|
+
var validate = SCHEMA.getSchema(key in STANDALONE_SCHEMAS ? key : "root#/properties/".concat(key));
|
|
73
|
+
if (!validate || typeof validate.schema !== "object") {
|
|
74
|
+
throw new Error("No schema registered for '".concat(key, "'"));
|
|
75
|
+
}
|
|
76
|
+
return validate.schema;
|
|
77
|
+
}
|
|
78
|
+
function validateSchema(key, value) {
|
|
79
|
+
return SCHEMA.validate(key in STANDALONE_SCHEMAS ? key : "root#/properties/".concat(key), value);
|
|
80
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TYPE_FLAG_DISJOINT_DOMAINS = exports.TYPE_FLAG_INTRINSIC = void 0;
|
|
7
|
+
var typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
/**
|
|
9
|
+
* TypeScript does not export these `TypeFlags` members, and enum declaration merging would require
|
|
10
|
+
* hardcoding their numeric values -- which are computed from other flags and drift between
|
|
11
|
+
* releases. Reading them off the real enum keeps them correct for whatever TypeScript the project
|
|
12
|
+
* happens to be compiling with.
|
|
13
|
+
*/
|
|
14
|
+
var internalTypeFlags = typescript_1.default.TypeFlags;
|
|
15
|
+
exports.TYPE_FLAG_INTRINSIC = internalTypeFlags.Intrinsic;
|
|
16
|
+
exports.TYPE_FLAG_DISJOINT_DOMAINS = internalTypeFlags.DisjointDomains;
|
package/out/util/uid.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
3
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
|
+
if (!m) return o;
|
|
5
|
+
var i = m.call(o), r, ar = [], e;
|
|
6
|
+
try {
|
|
7
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
8
|
+
}
|
|
9
|
+
catch (error) { e = { error: error }; }
|
|
10
|
+
finally {
|
|
11
|
+
try {
|
|
12
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
13
|
+
}
|
|
14
|
+
finally { if (e) throw e.error; }
|
|
15
|
+
}
|
|
16
|
+
return ar;
|
|
17
|
+
};
|
|
18
|
+
var __values = (this && this.__values) || function(o) {
|
|
19
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
20
|
+
if (m) return m.call(o);
|
|
21
|
+
if (o && typeof o.length === "number") return {
|
|
22
|
+
next: function () {
|
|
23
|
+
if (o && i >= o.length) o = void 0;
|
|
24
|
+
return { value: o && o[i++], done: !o };
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
28
|
+
};
|
|
29
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
30
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
|
+
};
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.getTypeUid = getTypeUid;
|
|
34
|
+
exports.getNodeTypeUid = getNodeTypeUid;
|
|
35
|
+
var path_1 = __importDefault(require("path"));
|
|
36
|
+
var typescript_1 = __importDefault(require("typescript"));
|
|
37
|
+
var diagnostics_1 = require("../classes/diagnostics");
|
|
38
|
+
var getDeclarationName_1 = require("./functions/getDeclarationName");
|
|
39
|
+
var tsInternals_1 = require("./tsInternals");
|
|
40
|
+
var getPackageJson_1 = require("./functions/getPackageJson");
|
|
41
|
+
var isDefinedType_1 = require("./functions/isDefinedType");
|
|
42
|
+
var isPathDescendantOf_1 = require("./functions/isPathDescendantOf");
|
|
43
|
+
var assert_1 = require("./functions/assert");
|
|
44
|
+
/**
|
|
45
|
+
* Format the internal id to be shorter, remove `out` part of path, and use hashPrefix.
|
|
46
|
+
*/
|
|
47
|
+
function formatInternalid(state, internalId, hashPrefix) {
|
|
48
|
+
if (hashPrefix === void 0) { hashPrefix = state.config.hashPrefix; }
|
|
49
|
+
var match = new RegExp("^.*:(.*)@(.+)$").exec(internalId);
|
|
50
|
+
if (!match)
|
|
51
|
+
return internalId;
|
|
52
|
+
var _a = __read(match, 3), path = _a[1], name = _a[2];
|
|
53
|
+
var revisedPath = path.replace(/^(.*?)[\/\\]/, "");
|
|
54
|
+
return hashPrefix ? "".concat(hashPrefix, ":").concat(revisedPath, "@").concat(name) : "".concat(revisedPath, "@").concat(name);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Gets the short ID for a node and includes the hash for uniqueness.
|
|
58
|
+
*/
|
|
59
|
+
function getShortId(state, node, hashPrefix) {
|
|
60
|
+
if (hashPrefix === void 0) { hashPrefix = state.config.hashPrefix; }
|
|
61
|
+
var hash = state.hash(state.buildInfo.getLatestId(), true);
|
|
62
|
+
var fullName = (0, getDeclarationName_1.getDeclarationName)(node);
|
|
63
|
+
var fileName = path_1.default.parse(node.getSourceFile().fileName).name;
|
|
64
|
+
var luaFileName = fileName === "index" ? "init" : fileName;
|
|
65
|
+
var isShort = state.config.idGenerationMode === "short";
|
|
66
|
+
var shortId = "".concat(isShort ? luaFileName + "@" : "").concat(fullName, "{").concat(hash, "}");
|
|
67
|
+
return hashPrefix ? "".concat(state.config.hashPrefix, ":").concat(shortId) : shortId;
|
|
68
|
+
}
|
|
69
|
+
function getInternalId(state, node) {
|
|
70
|
+
var filePath = state.getSourceFile(node).fileName;
|
|
71
|
+
var fullName = (0, getDeclarationName_1.getDeclarationName)(node);
|
|
72
|
+
var _a = (0, getPackageJson_1.getPackageJson)(path_1.default.dirname(filePath)), directory = _a.directory, result = _a.result;
|
|
73
|
+
if ((0, isPathDescendantOf_1.isPathDescendantOfAny)(filePath, state.rootDirs)) {
|
|
74
|
+
var outputPath = state.pathTranslator.getOutputPath(filePath).replace(/(\.lua)$/, "");
|
|
75
|
+
var relativePath_1 = path_1.default.relative(state.currentDirectory, outputPath);
|
|
76
|
+
var internalId_1 = "".concat(result.name, ":").concat(relativePath_1.replace(/\\/g, "/"), "@").concat(fullName);
|
|
77
|
+
return {
|
|
78
|
+
isPackage: false,
|
|
79
|
+
internalId: internalId_1,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
var relativePath = path_1.default.relative(directory, filePath.replace(/(\.d)?.ts$/, "").replace(/index$/, "init"));
|
|
83
|
+
var internalId = "".concat(result.name, ":").concat(relativePath.replace(/\\/g, "/"), "@").concat(fullName);
|
|
84
|
+
return {
|
|
85
|
+
isPackage: true,
|
|
86
|
+
internalId: internalId,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function getDeclarationUid(state, node) {
|
|
90
|
+
var _a = getInternalId(state, node), isPackage = _a.isPackage, internalId = _a.internalId;
|
|
91
|
+
var id = state.buildInfo.getIdentifierFromInternal(internalId);
|
|
92
|
+
if (id)
|
|
93
|
+
return id;
|
|
94
|
+
// this is a package, and the package itself did not generate an id
|
|
95
|
+
// use the internal ID to prevent breakage between packages and games.
|
|
96
|
+
if (isPackage) {
|
|
97
|
+
var buildInfo = state.buildInfo.getBuildInfoFromFile(state.getSourceFile(node).fileName);
|
|
98
|
+
if (buildInfo) {
|
|
99
|
+
var prefix = buildInfo.getIdentifierPrefix();
|
|
100
|
+
if (prefix) {
|
|
101
|
+
return formatInternalid(state, internalId, prefix);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return internalId;
|
|
105
|
+
}
|
|
106
|
+
var newId;
|
|
107
|
+
if (state.config.idGenerationMode === "obfuscated") {
|
|
108
|
+
newId = state.hash(state.buildInfo.getLatestId());
|
|
109
|
+
}
|
|
110
|
+
else if (state.config.idGenerationMode === "short" || state.config.idGenerationMode === "tiny") {
|
|
111
|
+
newId = getShortId(state, node);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
newId = formatInternalid(state, internalId);
|
|
115
|
+
}
|
|
116
|
+
state.buildInfo.addIdentifier(internalId, newId);
|
|
117
|
+
return newId;
|
|
118
|
+
}
|
|
119
|
+
function findValidDeclaration(symbol, trace) {
|
|
120
|
+
var e_1, _a, e_2, _b;
|
|
121
|
+
var _c, _d;
|
|
122
|
+
var usableDeclarations = new Array();
|
|
123
|
+
try {
|
|
124
|
+
for (var _e = __values((_c = symbol.declarations) !== null && _c !== void 0 ? _c : []), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
125
|
+
var declaration = _f.value;
|
|
126
|
+
if (typescript_1.default.isTypeLiteralNode(declaration) || typescript_1.default.isTypeAliasDeclaration(declaration)) {
|
|
127
|
+
var typeAlias = typescript_1.default.findAncestor(declaration, typescript_1.default.isTypeAliasDeclaration);
|
|
128
|
+
if (typeAlias) {
|
|
129
|
+
usableDeclarations.push(typeAlias);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (typescript_1.default.isInterfaceDeclaration(declaration)) {
|
|
134
|
+
usableDeclarations.push(declaration);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (typescript_1.default.isClassDeclaration(declaration)) {
|
|
138
|
+
usableDeclarations.push(declaration);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (typescript_1.default.isFunctionDeclaration(declaration)) {
|
|
142
|
+
usableDeclarations.push(declaration);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
148
|
+
finally {
|
|
149
|
+
try {
|
|
150
|
+
if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
|
|
151
|
+
}
|
|
152
|
+
finally { if (e_1) throw e_1.error; }
|
|
153
|
+
}
|
|
154
|
+
if (usableDeclarations.length <= 1) {
|
|
155
|
+
return usableDeclarations[0];
|
|
156
|
+
}
|
|
157
|
+
var classesOnly = usableDeclarations.filter(typescript_1.default.isClassDeclaration);
|
|
158
|
+
if (classesOnly.length === 1) {
|
|
159
|
+
return classesOnly[0];
|
|
160
|
+
}
|
|
161
|
+
if (trace) {
|
|
162
|
+
var diagnostic = diagnostics_1.Diagnostics.createDiagnostic(trace, typescript_1.default.DiagnosticCategory.Error, "There are multiple possible IDs for this symbol: ".concat(symbol.name));
|
|
163
|
+
try {
|
|
164
|
+
for (var usableDeclarations_1 = __values(usableDeclarations), usableDeclarations_1_1 = usableDeclarations_1.next(); !usableDeclarations_1_1.done; usableDeclarations_1_1 = usableDeclarations_1.next()) {
|
|
165
|
+
var declaration = usableDeclarations_1_1.value;
|
|
166
|
+
typescript_1.default.addRelatedInfo(diagnostic, diagnostics_1.Diagnostics.createDiagnostic((_d = declaration.name) !== null && _d !== void 0 ? _d : declaration, typescript_1.default.DiagnosticCategory.Message, "This is a valid declaration with a unique ID."));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
170
|
+
finally {
|
|
171
|
+
try {
|
|
172
|
+
if (usableDeclarations_1_1 && !usableDeclarations_1_1.done && (_b = usableDeclarations_1.return)) _b.call(usableDeclarations_1);
|
|
173
|
+
}
|
|
174
|
+
finally { if (e_2) throw e_2.error; }
|
|
175
|
+
}
|
|
176
|
+
throw new diagnostics_1.DiagnosticError(diagnostic);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function getSymbolUid(state, symbol, trace) {
|
|
180
|
+
if (!symbol.declarations) {
|
|
181
|
+
if (trace) {
|
|
182
|
+
diagnostics_1.Diagnostics.error(trace, "This symbol does not have any ID: \"".concat(symbol.name, "\""));
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
var validDeclaration = findValidDeclaration(symbol, trace);
|
|
187
|
+
if (validDeclaration) {
|
|
188
|
+
return getDeclarationUid(state, validDeclaration);
|
|
189
|
+
}
|
|
190
|
+
if (trace) {
|
|
191
|
+
diagnostics_1.Diagnostics.error(trace, "Could not find a declaration with a unique ID for '".concat(symbol.name, "'."), "Only classes, interfaces, type aliases and functions have IDs; a type parameter or an anonymous type cannot be used here.");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function getTypeUid(state, type, trace) {
|
|
195
|
+
var injectableConfig = state.typeChecker.getTypeOfPropertyOfType(type, "_flamework_injectable");
|
|
196
|
+
if (injectableConfig) {
|
|
197
|
+
var idOverride = state.typeChecker.getTypeOfPropertyOfType(injectableConfig, "id");
|
|
198
|
+
if (idOverride) {
|
|
199
|
+
return getTypeUid(state, idOverride, trace);
|
|
200
|
+
}
|
|
201
|
+
var originalType = state.typeChecker.getTypeOfPropertyOfType(injectableConfig, "type");
|
|
202
|
+
(0, assert_1.assert)(originalType !== undefined && originalType !== type, "malformed injectable type");
|
|
203
|
+
return getTypeUid(state, originalType, trace);
|
|
204
|
+
}
|
|
205
|
+
// A type parameter cannot be resolved here; a generic class's own constructor is the usual source,
|
|
206
|
+
// and only its subclasses -- where the argument is concrete -- are ever constructed. The placeholder
|
|
207
|
+
// keeps the parameter count intact and fails at resolution time with the parameter's name.
|
|
208
|
+
if (type.flags & typescript_1.default.TypeFlags.TypeParameter) {
|
|
209
|
+
return "$tp:".concat(type.checker.typeToString(type));
|
|
210
|
+
}
|
|
211
|
+
if (type.symbol) {
|
|
212
|
+
return getSymbolUid(state, type.symbol, trace);
|
|
213
|
+
}
|
|
214
|
+
else if ((0, isDefinedType_1.isDefinedType)(type)) {
|
|
215
|
+
return "$p:defined";
|
|
216
|
+
}
|
|
217
|
+
else if (type.flags & tsInternals_1.TYPE_FLAG_INTRINSIC) {
|
|
218
|
+
return "$p:".concat(type.intrinsicName);
|
|
219
|
+
}
|
|
220
|
+
else if (trace) {
|
|
221
|
+
diagnostics_1.Diagnostics.error(trace, "Could not find UID for type \"".concat(type.checker.typeToString(type), "\""));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function getNodeTypeUid(state, node) {
|
|
225
|
+
var type = state.typeChecker.getTypeAtLocation(node);
|
|
226
|
+
return getTypeUid(state, type, node);
|
|
227
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flamework-experimental/transformer",
|
|
3
|
+
"version": "2.0.0-alpha.0",
|
|
4
|
+
"description": "An opinionated game framework for Roblox.",
|
|
5
|
+
"main": "out/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"watch": "tsc -w"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/rbxts-flamework/transformer.git"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"out",
|
|
16
|
+
"index.d.ts",
|
|
17
|
+
"rojo-schema.json",
|
|
18
|
+
"flamework-schema.json",
|
|
19
|
+
"flamework.config.schema.json",
|
|
20
|
+
"types.d.ts"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@roblox-ts/path-translator": "^1.1.0",
|
|
24
|
+
"@roblox-ts/rojo-resolver": "^1.1.0",
|
|
25
|
+
"ajv": "^8.6.3",
|
|
26
|
+
"chalk": "^4.1.2",
|
|
27
|
+
"fs-extra": "^10.0.0",
|
|
28
|
+
"glob": "9.3",
|
|
29
|
+
"hashids": "^2.2.8",
|
|
30
|
+
"normalize-package-data": "^3.0.3",
|
|
31
|
+
"uuid": "^8.3.2"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/fs-extra": "^9.0.13",
|
|
35
|
+
"@types/node": "^16.11.1",
|
|
36
|
+
"@types/normalize-package-data": "^2.4.1",
|
|
37
|
+
"@types/uuid": "^8.3.1",
|
|
38
|
+
"@flamework-experimental/transformer-plugin": "2.0.0-alpha.0",
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"typescript": "*"
|
|
43
|
+
},
|
|
44
|
+
"types": "types.d.ts"
|
|
45
|
+
}
|
package/rojo-schema.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"required": ["name", "tree"],
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"name": {
|
|
7
|
+
"type": "string"
|
|
8
|
+
},
|
|
9
|
+
"servePort": {
|
|
10
|
+
"type": "integer"
|
|
11
|
+
},
|
|
12
|
+
"tree": {
|
|
13
|
+
"$id": "tree",
|
|
14
|
+
"type": "object",
|
|
15
|
+
"properties": {
|
|
16
|
+
"$className": {
|
|
17
|
+
"type": "string"
|
|
18
|
+
},
|
|
19
|
+
"$ignoreUnknownInstances": {
|
|
20
|
+
"type": "boolean"
|
|
21
|
+
},
|
|
22
|
+
"$path": {
|
|
23
|
+
"type": "string"
|
|
24
|
+
},
|
|
25
|
+
"$properties": {
|
|
26
|
+
"type": "object"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"patternProperties": {
|
|
30
|
+
"^[^\\$].*$": { "$ref": "tree" }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Deliberately empty. A game lists the scope in its typeRoots, and TypeScript then treats every
|
|
2
|
+
// package in that directory as a type library to include: this file is what it finds here, so
|
|
3
|
+
// the transformer's own declarations (typescript and all) never enter a place's program.
|
|
4
|
+
export {};
|