luaut-parser 1.2.0 → 2.0.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 +70 -28
- package/dist/index.cjs +414 -31
- package/dist/index.d.cts +92 -23
- package/dist/index.d.ts +92 -23
- package/dist/index.js +406 -21
- package/package.json +4 -2
- package/dist/luau.d.luaut +0 -245
- package/dist/roblox.d.luaut +0 -503
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
BinaryOperators: () => BinaryOperators,
|
|
24
|
+
CONFIG_FILE_NAMES: () => CONFIG_FILE_NAMES,
|
|
24
25
|
Keywords: () => Keywords,
|
|
25
26
|
LexError: () => LexError,
|
|
26
27
|
Operators: () => Operators,
|
|
@@ -35,10 +36,10 @@ __export(index_exports, {
|
|
|
35
36
|
bufferType: () => bufferType,
|
|
36
37
|
containsTypeParam: () => containsTypeParam,
|
|
37
38
|
default: () => index_default,
|
|
38
|
-
defaultLibs: () => defaultLibs,
|
|
39
39
|
difference: () => difference,
|
|
40
40
|
equalTypes: () => equalTypes,
|
|
41
41
|
falsyType: () => falsyType,
|
|
42
|
+
findConfig: () => findConfig,
|
|
42
43
|
fn: () => fn,
|
|
43
44
|
formatType: () => formatType,
|
|
44
45
|
getBinding: () => getBinding,
|
|
@@ -49,11 +50,10 @@ __export(index_exports, {
|
|
|
49
50
|
isPossiblyTruthy: () => isPossiblyTruthy,
|
|
50
51
|
isUnassignedGlobal: () => isUnassignedGlobal,
|
|
51
52
|
literal: () => literal,
|
|
52
|
-
|
|
53
|
-
luauDefsPath: () => luauDefsPath,
|
|
54
|
-
luauLib: () => luauLib,
|
|
53
|
+
loadConfig: () => loadConfig,
|
|
55
54
|
luautparser: () => luautparser,
|
|
56
55
|
matchInfer: () => matchInfer,
|
|
56
|
+
moduleCandidates: () => moduleCandidates,
|
|
57
57
|
moduleExports: () => moduleExports,
|
|
58
58
|
narrowExclude: () => narrowExclude,
|
|
59
59
|
narrowFalsy: () => narrowFalsy,
|
|
@@ -61,6 +61,7 @@ __export(index_exports, {
|
|
|
61
61
|
narrowTruthy: () => narrowTruthy,
|
|
62
62
|
neverType: () => neverType,
|
|
63
63
|
nilType: () => nilType,
|
|
64
|
+
nodeHost: () => nodeHost,
|
|
64
65
|
numberType: () => numberType,
|
|
65
66
|
objectType: () => objectType,
|
|
66
67
|
optional: () => optional,
|
|
@@ -70,11 +71,12 @@ __export(index_exports, {
|
|
|
70
71
|
parseTokens: () => parseTokens,
|
|
71
72
|
parseWithRecovery: () => parseWithRecovery,
|
|
72
73
|
primitive: () => primitive,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
robloxLib: () => robloxLib,
|
|
74
|
+
resolveModulePath: () => resolveModulePath,
|
|
75
|
+
resolveTypeLibraries: () => resolveTypeLibraries,
|
|
76
76
|
setAliasExpander: () => setAliasExpander,
|
|
77
|
+
sourceMapTypes: () => sourceMapTypes,
|
|
77
78
|
stringType: () => stringType,
|
|
79
|
+
stripJsonComments: () => stripJsonComments,
|
|
78
80
|
substitute: () => substitute,
|
|
79
81
|
templateMatches: () => templateMatches,
|
|
80
82
|
threadType: () => threadType,
|
|
@@ -88,10 +90,6 @@ __export(index_exports, {
|
|
|
88
90
|
});
|
|
89
91
|
module.exports = __toCommonJS(index_exports);
|
|
90
92
|
|
|
91
|
-
// node_modules/tsup/assets/cjs_shims.js
|
|
92
|
-
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
93
|
-
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
94
|
-
|
|
95
93
|
// src/lexer/lexer.ts
|
|
96
94
|
var Keywords = [
|
|
97
95
|
"and",
|
|
@@ -3270,7 +3268,11 @@ function isAssignableInner(a, b) {
|
|
|
3270
3268
|
if (a.kind === "union") return a.types.every((t) => isAssignable(t, b));
|
|
3271
3269
|
if (b.kind === "union") return b.types.some((t) => isAssignable(a, t));
|
|
3272
3270
|
if (b.kind === "intersection") return b.types.every((t) => isAssignable(a, t));
|
|
3273
|
-
if (a.kind === "intersection")
|
|
3271
|
+
if (a.kind === "intersection") {
|
|
3272
|
+
if (a.types.some((t) => isAssignable(t, b))) return true;
|
|
3273
|
+
const merged = mergeObjectMembers(a.types);
|
|
3274
|
+
return merged !== void 0 && isAssignable(merged, b);
|
|
3275
|
+
}
|
|
3274
3276
|
if (a.kind === "literal") {
|
|
3275
3277
|
if (b.kind === "literal") return a.value === b.value;
|
|
3276
3278
|
if (b.kind === "primitive") return b.name === a.base;
|
|
@@ -3625,6 +3627,39 @@ var IDENT_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
|
3625
3627
|
function formatKey(k) {
|
|
3626
3628
|
return IDENT_KEY.test(k) ? k : JSON.stringify(k);
|
|
3627
3629
|
}
|
|
3630
|
+
function mergeObjectMembers(types) {
|
|
3631
|
+
const objects = [];
|
|
3632
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3633
|
+
const collect = (t) => {
|
|
3634
|
+
if (seen.has(t)) return true;
|
|
3635
|
+
seen.add(t);
|
|
3636
|
+
if (t.kind === "genericRef") {
|
|
3637
|
+
const expanded = expandAlias?.(t);
|
|
3638
|
+
return expanded !== void 0 && expanded !== t && collect(expanded);
|
|
3639
|
+
}
|
|
3640
|
+
if (t.kind === "intersection") return t.types.every(collect);
|
|
3641
|
+
if (t.kind === "object") {
|
|
3642
|
+
objects.push(t);
|
|
3643
|
+
return true;
|
|
3644
|
+
}
|
|
3645
|
+
return false;
|
|
3646
|
+
};
|
|
3647
|
+
if (!types.every(collect) || objects.length < 2) return void 0;
|
|
3648
|
+
const properties = /* @__PURE__ */ new Map();
|
|
3649
|
+
let indexer;
|
|
3650
|
+
for (const object of objects) {
|
|
3651
|
+
indexer ??= object.indexer;
|
|
3652
|
+
for (const [name, property] of object.properties) {
|
|
3653
|
+
const existing = properties.get(name);
|
|
3654
|
+
properties.set(name, existing ? {
|
|
3655
|
+
type: intersection([existing.type, property.type]),
|
|
3656
|
+
optional: existing.optional && property.optional,
|
|
3657
|
+
readonly: existing.readonly || property.readonly
|
|
3658
|
+
} : property);
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
return objectType([...properties], indexer);
|
|
3662
|
+
}
|
|
3628
3663
|
|
|
3629
3664
|
// src/ast/analyzeTypes.ts
|
|
3630
3665
|
function analyzeTypes(program, scopes, options = {}) {
|
|
@@ -5917,22 +5952,368 @@ function briefType(t) {
|
|
|
5917
5952
|
return formatType(t);
|
|
5918
5953
|
}
|
|
5919
5954
|
|
|
5920
|
-
// src/
|
|
5955
|
+
// src/project/host.ts
|
|
5921
5956
|
var import_node_fs = require("fs");
|
|
5922
|
-
var
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5957
|
+
var nodeHost = {
|
|
5958
|
+
readFile(path) {
|
|
5959
|
+
try {
|
|
5960
|
+
return (0, import_node_fs.statSync)(path).isFile() ? (0, import_node_fs.readFileSync)(path, "utf8") : void 0;
|
|
5961
|
+
} catch {
|
|
5962
|
+
return void 0;
|
|
5963
|
+
}
|
|
5964
|
+
}
|
|
5965
|
+
};
|
|
5966
|
+
|
|
5967
|
+
// src/project/config.ts
|
|
5968
|
+
var import_node_path = require("path");
|
|
5969
|
+
var CONFIG_FILE_NAMES = ["luaut.config.json", "luaut.config.jsonc"];
|
|
5970
|
+
function findConfig(file, host = nodeHost) {
|
|
5971
|
+
const searched = [];
|
|
5972
|
+
let directory = (0, import_node_path.dirname)((0, import_node_path.resolve)(file));
|
|
5973
|
+
for (; ; ) {
|
|
5974
|
+
const found = [];
|
|
5975
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
5976
|
+
const path = (0, import_node_path.join)(directory, name);
|
|
5977
|
+
searched.push(path);
|
|
5978
|
+
if (host.readFile(path) !== void 0) found.push(path);
|
|
5979
|
+
}
|
|
5980
|
+
if (found.length > 1) {
|
|
5981
|
+
const message = `Only one luaut config may be in a folder, but both ${CONFIG_FILE_NAMES.join(" and ")} are in ${directory}`;
|
|
5982
|
+
return { searched, problems: found.map((path) => ({ file: path, message, line: 1, column: 1 })) };
|
|
5983
|
+
}
|
|
5984
|
+
if (found.length === 1) {
|
|
5985
|
+
const { config, problems } = loadConfig(found[0], host);
|
|
5986
|
+
return { config, problems, searched };
|
|
5987
|
+
}
|
|
5988
|
+
const parent = (0, import_node_path.dirname)(directory);
|
|
5989
|
+
if (parent === directory) return { searched, problems: [] };
|
|
5990
|
+
directory = parent;
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5993
|
+
var OPTIONS = ["types", "paths", "baseUrl", "sourceMap"];
|
|
5994
|
+
function loadConfig(path, host = nodeHost) {
|
|
5995
|
+
const file = (0, import_node_path.resolve)(path);
|
|
5996
|
+
const source = host.readFile(file);
|
|
5997
|
+
if (source === void 0) return { problems: [{ file, message: "Cannot read the config file" }] };
|
|
5998
|
+
let raw;
|
|
5999
|
+
try {
|
|
6000
|
+
raw = JSON.parse(stripJsonComments(source));
|
|
6001
|
+
} catch (error) {
|
|
6002
|
+
const message = error.message;
|
|
6003
|
+
return { problems: [{ file, message: `Invalid JSON: ${message}`, ...jsonErrorPosition(source, message) }] };
|
|
6004
|
+
}
|
|
6005
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
6006
|
+
return { problems: [{ file, message: "The config must be a JSON object", line: 1, column: 1 }] };
|
|
6007
|
+
}
|
|
6008
|
+
const directory = (0, import_node_path.dirname)(file);
|
|
6009
|
+
const options = raw;
|
|
6010
|
+
const problems = [];
|
|
6011
|
+
const at = (key) => keyPosition(source, key);
|
|
6012
|
+
const problem = (key, message) => {
|
|
6013
|
+
problems.push({ file, message, ...at(key) });
|
|
6014
|
+
};
|
|
6015
|
+
for (const key of Object.keys(options)) {
|
|
6016
|
+
if (!OPTIONS.includes(key)) {
|
|
6017
|
+
problem(key, `Unknown option '${key}'. Options are: ${OPTIONS.join(", ")}`);
|
|
6018
|
+
}
|
|
6019
|
+
}
|
|
6020
|
+
let types = [];
|
|
6021
|
+
if (options.types !== void 0) {
|
|
6022
|
+
if (Array.isArray(options.types) && options.types.every((t) => typeof t === "string")) types = options.types;
|
|
6023
|
+
else problem("types", `'types' must be an array of strings, such as ["luau"]`);
|
|
6024
|
+
}
|
|
6025
|
+
const paths = {};
|
|
6026
|
+
if (options.paths !== void 0) {
|
|
6027
|
+
const value = options.paths;
|
|
6028
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
6029
|
+
for (const [pattern, targets] of Object.entries(value)) {
|
|
6030
|
+
if (Array.isArray(targets) && targets.every((t) => typeof t === "string")) paths[pattern] = targets;
|
|
6031
|
+
else problem(pattern, `'paths' entry '${pattern}' must be an array of strings`);
|
|
6032
|
+
if (pattern.split("*").length > 2) problem(pattern, `'paths' pattern '${pattern}' may contain at most one '*'`);
|
|
6033
|
+
}
|
|
6034
|
+
} else {
|
|
6035
|
+
problem("paths", `'paths' must be an object, such as { "@shared/*": ["src/shared/*"] }`);
|
|
6036
|
+
}
|
|
6037
|
+
}
|
|
6038
|
+
let baseUrl = directory;
|
|
6039
|
+
if (options.baseUrl !== void 0) {
|
|
6040
|
+
if (typeof options.baseUrl === "string") baseUrl = (0, import_node_path.resolve)(directory, options.baseUrl);
|
|
6041
|
+
else problem("baseUrl", "'baseUrl' must be a string");
|
|
6042
|
+
}
|
|
6043
|
+
let sourceMap = null;
|
|
6044
|
+
if (options.sourceMap !== void 0 && options.sourceMap !== null) {
|
|
6045
|
+
if (typeof options.sourceMap === "string") sourceMap = (0, import_node_path.resolve)(directory, options.sourceMap);
|
|
6046
|
+
else problem("sourceMap", "'sourceMap' must be a path string, or null for none");
|
|
6047
|
+
}
|
|
6048
|
+
return { config: { path: file, directory, source, types, paths, baseUrl, sourceMap }, problems };
|
|
6049
|
+
}
|
|
6050
|
+
function stripJsonComments(text) {
|
|
6051
|
+
const out = text.split("");
|
|
6052
|
+
let i = 0;
|
|
6053
|
+
let inString = false;
|
|
6054
|
+
while (i < text.length) {
|
|
6055
|
+
const ch = text[i];
|
|
6056
|
+
if (inString) {
|
|
6057
|
+
if (ch === "\\") i += 2;
|
|
6058
|
+
else {
|
|
6059
|
+
if (ch === '"') inString = false;
|
|
6060
|
+
i++;
|
|
6061
|
+
}
|
|
6062
|
+
continue;
|
|
6063
|
+
}
|
|
6064
|
+
if (ch === '"') {
|
|
6065
|
+
inString = true;
|
|
6066
|
+
i++;
|
|
6067
|
+
} else if (ch === "/" && text[i + 1] === "/") {
|
|
6068
|
+
while (i < text.length && text[i] !== "\n") out[i++] = " ";
|
|
6069
|
+
} else if (ch === "/" && text[i + 1] === "*") {
|
|
6070
|
+
out[i++] = " ";
|
|
6071
|
+
out[i++] = " ";
|
|
6072
|
+
while (i < text.length && !(text[i] === "*" && text[i + 1] === "/")) {
|
|
6073
|
+
if (text[i] !== "\n") out[i] = " ";
|
|
6074
|
+
i++;
|
|
6075
|
+
}
|
|
6076
|
+
if (i < text.length) {
|
|
6077
|
+
out[i++] = " ";
|
|
6078
|
+
out[i++] = " ";
|
|
6079
|
+
}
|
|
6080
|
+
} else if (ch === ",") {
|
|
6081
|
+
let j = i + 1;
|
|
6082
|
+
while (j < text.length && /\s/.test(text[j])) j++;
|
|
6083
|
+
if (text[j] === "}" || text[j] === "]") out[i] = " ";
|
|
6084
|
+
i++;
|
|
6085
|
+
} else {
|
|
6086
|
+
i++;
|
|
6087
|
+
}
|
|
6088
|
+
}
|
|
6089
|
+
return out.join("");
|
|
6090
|
+
}
|
|
6091
|
+
function jsonErrorPosition(source, message) {
|
|
6092
|
+
const lineColumn = /line (\d+) column (\d+)/.exec(message);
|
|
6093
|
+
if (lineColumn) return { line: Number(lineColumn[1]), column: Number(lineColumn[2]) };
|
|
6094
|
+
const position = /position (\d+)/.exec(message);
|
|
6095
|
+
return position ? offsetPosition(source, Number(position[1])) : { line: 1, column: 1 };
|
|
6096
|
+
}
|
|
6097
|
+
function keyPosition(source, key) {
|
|
6098
|
+
const offset = source.indexOf(JSON.stringify(key));
|
|
6099
|
+
return offset < 0 ? { line: 1, column: 1 } : offsetPosition(source, offset);
|
|
6100
|
+
}
|
|
6101
|
+
function offsetPosition(source, offset) {
|
|
6102
|
+
const before = source.slice(0, offset);
|
|
6103
|
+
const line = before.split("\n").length;
|
|
6104
|
+
return { line, column: offset - before.lastIndexOf("\n") };
|
|
6105
|
+
}
|
|
6106
|
+
|
|
6107
|
+
// src/project/libraries.ts
|
|
6108
|
+
var import_node_path2 = require("path");
|
|
6109
|
+
function resolveTypeLibraries(config, host = nodeHost) {
|
|
6110
|
+
const files = [];
|
|
6111
|
+
const problems = [];
|
|
6112
|
+
const loaded = /* @__PURE__ */ new Set();
|
|
6113
|
+
const addFile = (file) => {
|
|
6114
|
+
const key = pathKey(file);
|
|
6115
|
+
if (loaded.has(key)) return;
|
|
6116
|
+
loaded.add(key);
|
|
6117
|
+
files.push(file);
|
|
6118
|
+
};
|
|
6119
|
+
const addPackage = (directory, entryFile, visiting) => {
|
|
6120
|
+
const key = pathKey(directory);
|
|
6121
|
+
if (visiting.has(key)) return;
|
|
6122
|
+
visiting.add(key);
|
|
6123
|
+
for (const dependency of dependencyNames(directory, host)) {
|
|
6124
|
+
const found = findPackage(dependency, directory, host);
|
|
6125
|
+
if (found) addPackage(found.directory, found.file, visiting);
|
|
6126
|
+
}
|
|
6127
|
+
addFile(entryFile);
|
|
6128
|
+
};
|
|
6129
|
+
for (const entry of config.types) {
|
|
6130
|
+
const relative = entry.startsWith("./") || entry.startsWith("../") || entry.startsWith("/") || /^[A-Za-z]:[\\/]/.test(entry);
|
|
6131
|
+
if (relative) {
|
|
6132
|
+
const target = (0, import_node_path2.resolve)(config.directory, entry);
|
|
6133
|
+
if (entry.endsWith(".luaut")) {
|
|
6134
|
+
if (host.readFile(target) !== void 0) addFile(target);
|
|
6135
|
+
else problems.push({ file: config.path, message: `Cannot find type library file '${entry}'`, ...entryPosition(config, entry) });
|
|
6136
|
+
continue;
|
|
6137
|
+
}
|
|
6138
|
+
const file = packageEntry(target, host);
|
|
6139
|
+
if (file) addPackage(target, file, /* @__PURE__ */ new Set());
|
|
6140
|
+
else problems.push({ file: config.path, message: `'${entry}' has no ${ENTRY_FILE} (or 'luaut.types' in its package.json)`, ...entryPosition(config, entry) });
|
|
6141
|
+
continue;
|
|
6142
|
+
}
|
|
6143
|
+
const names = entry.startsWith("@") || entry.includes("/") ? [entry] : [`@luaut/${entry}`, entry];
|
|
6144
|
+
const found = names.map((name) => findPackage(name, config.directory, host)).find(Boolean);
|
|
6145
|
+
if (found) addPackage(found.directory, found.file, /* @__PURE__ */ new Set());
|
|
6146
|
+
else {
|
|
6147
|
+
problems.push({
|
|
6148
|
+
file: config.path,
|
|
6149
|
+
message: `Cannot find type library '${entry}'. Install it with: npm i -D ${names[0]}`,
|
|
6150
|
+
...entryPosition(config, entry)
|
|
6151
|
+
});
|
|
6152
|
+
}
|
|
6153
|
+
}
|
|
6154
|
+
return { files, problems };
|
|
6155
|
+
}
|
|
6156
|
+
var ENTRY_FILE = "index.d.luaut";
|
|
6157
|
+
function packageEntry(directory, host) {
|
|
6158
|
+
const manifest = readJson((0, import_node_path2.join)(directory, "package.json"), host);
|
|
6159
|
+
const declared = manifest?.luaut?.types;
|
|
6160
|
+
const file = (0, import_node_path2.resolve)(directory, typeof declared === "string" ? declared : ENTRY_FILE);
|
|
6161
|
+
return host.readFile(file) !== void 0 ? file : void 0;
|
|
6162
|
+
}
|
|
6163
|
+
function findPackage(name, from, host) {
|
|
6164
|
+
let directory = (0, import_node_path2.resolve)(from);
|
|
6165
|
+
for (; ; ) {
|
|
6166
|
+
const candidate = (0, import_node_path2.join)(directory, "node_modules", ...name.split("/"));
|
|
6167
|
+
const file = packageEntry(candidate, host);
|
|
6168
|
+
if (file) return { directory: candidate, file };
|
|
6169
|
+
const parent = (0, import_node_path2.dirname)(directory);
|
|
6170
|
+
if (parent === directory) return void 0;
|
|
6171
|
+
directory = parent;
|
|
6172
|
+
}
|
|
6173
|
+
}
|
|
6174
|
+
function dependencyNames(directory, host) {
|
|
6175
|
+
const manifest = readJson((0, import_node_path2.join)(directory, "package.json"), host);
|
|
6176
|
+
const names = /* @__PURE__ */ new Set();
|
|
6177
|
+
for (const field of ["dependencies", "peerDependencies"]) {
|
|
6178
|
+
const deps = manifest?.[field];
|
|
6179
|
+
if (deps && typeof deps === "object") for (const name of Object.keys(deps)) names.add(name);
|
|
6180
|
+
}
|
|
6181
|
+
return [...names];
|
|
6182
|
+
}
|
|
6183
|
+
function readJson(path, host) {
|
|
6184
|
+
const text = host.readFile(path);
|
|
6185
|
+
if (text === void 0) return void 0;
|
|
6186
|
+
try {
|
|
6187
|
+
const value = JSON.parse(text);
|
|
6188
|
+
return value && typeof value === "object" ? value : void 0;
|
|
6189
|
+
} catch {
|
|
6190
|
+
return void 0;
|
|
6191
|
+
}
|
|
6192
|
+
}
|
|
6193
|
+
function entryPosition(config, entry) {
|
|
6194
|
+
return keyPosition(config.source, entry);
|
|
6195
|
+
}
|
|
6196
|
+
function pathKey(path) {
|
|
6197
|
+
const normalized = (0, import_node_path2.resolve)(path);
|
|
6198
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
6199
|
+
}
|
|
6200
|
+
|
|
6201
|
+
// src/project/modules.ts
|
|
6202
|
+
var import_node_path3 = require("path");
|
|
6203
|
+
function moduleCandidates(fromFile, specifier, config) {
|
|
6204
|
+
const bases = specifier.startsWith("./") || specifier.startsWith("../") ? [(0, import_node_path3.resolve)((0, import_node_path3.dirname)(fromFile), specifier)] : config ? aliasTargets(config, specifier) : [];
|
|
6205
|
+
return bases.flatMap((base) => base.endsWith(".luaut") ? [base] : [`${base}.luaut`, `${base}.d.luaut`, (0, import_node_path3.join)(base, "index.luaut")]);
|
|
6206
|
+
}
|
|
6207
|
+
function resolveModulePath(fromFile, specifier, config, host = nodeHost) {
|
|
6208
|
+
return moduleCandidates(fromFile, specifier, config).find((path) => host.readFile(path) !== void 0);
|
|
6209
|
+
}
|
|
6210
|
+
function aliasTargets(config, specifier) {
|
|
6211
|
+
let match;
|
|
6212
|
+
let prefixLength = -1;
|
|
6213
|
+
for (const pattern2 of Object.keys(config.paths)) {
|
|
6214
|
+
const star = pattern2.indexOf("*");
|
|
6215
|
+
if (star < 0) {
|
|
6216
|
+
if (pattern2 === specifier) {
|
|
6217
|
+
match = { pattern: pattern2, wildcard: "" };
|
|
6218
|
+
break;
|
|
6219
|
+
}
|
|
6220
|
+
continue;
|
|
6221
|
+
}
|
|
6222
|
+
const prefix = pattern2.slice(0, star);
|
|
6223
|
+
const suffix = pattern2.slice(star + 1);
|
|
6224
|
+
const fits = specifier.length >= prefix.length + suffix.length && specifier.startsWith(prefix) && specifier.endsWith(suffix);
|
|
6225
|
+
if (fits && prefix.length > prefixLength) {
|
|
6226
|
+
prefixLength = prefix.length;
|
|
6227
|
+
match = { pattern: pattern2, wildcard: specifier.slice(prefix.length, specifier.length - suffix.length) };
|
|
6228
|
+
}
|
|
6229
|
+
}
|
|
6230
|
+
if (!match) return [];
|
|
6231
|
+
const { pattern, wildcard } = match;
|
|
6232
|
+
return config.paths[pattern].map((target) => (0, import_node_path3.resolve)(config.baseUrl, target.replace("*", wildcard)));
|
|
6233
|
+
}
|
|
5926
6234
|
|
|
5927
|
-
// src/
|
|
5928
|
-
var
|
|
5929
|
-
var
|
|
5930
|
-
var
|
|
5931
|
-
var
|
|
5932
|
-
|
|
6235
|
+
// src/project/sourcemap.ts
|
|
6236
|
+
var import_node_path4 = require("path");
|
|
6237
|
+
var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
6238
|
+
var INSTANCE_MEMBERS = /* @__PURE__ */ new Set(["Name", "ClassName", "Parent", "Archivable"]);
|
|
6239
|
+
var SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".luaut", ".luau", ".lua"]);
|
|
6240
|
+
function sourceMapTypes(text, path, options) {
|
|
6241
|
+
let root;
|
|
6242
|
+
try {
|
|
6243
|
+
root = JSON.parse(text);
|
|
6244
|
+
} catch (error) {
|
|
6245
|
+
return { problem: `Invalid sourcemap: ${error.message}` };
|
|
6246
|
+
}
|
|
6247
|
+
if (!isNode(root)) return { problem: "Invalid sourcemap: the root must be an object with 'name' and 'className'" };
|
|
6248
|
+
const directory = (0, import_node_path4.dirname)((0, import_node_path4.resolve)(path));
|
|
6249
|
+
const lines = [];
|
|
6250
|
+
const aliasOfFile = /* @__PURE__ */ new Map();
|
|
6251
|
+
const used = /* @__PURE__ */ new Set();
|
|
6252
|
+
const canOmit = options.classes.has("Omit");
|
|
6253
|
+
const aliasOfNode = /* @__PURE__ */ new Map();
|
|
6254
|
+
const aliasFor = (segments) => {
|
|
6255
|
+
const base = `SourceMap_${segments.map((s) => s.replace(/[^A-Za-z0-9_]/g, "_")).join("_")}`;
|
|
6256
|
+
let alias = base;
|
|
6257
|
+
for (let n = 2; used.has(alias); n++) alias = `${base}_${n}`;
|
|
6258
|
+
used.add(alias);
|
|
6259
|
+
return alias;
|
|
6260
|
+
};
|
|
6261
|
+
const visit = (node, segments, parent) => {
|
|
6262
|
+
const alias = aliasFor(segments);
|
|
6263
|
+
aliasOfNode.set(node, alias);
|
|
6264
|
+
for (const filePath of node.filePaths ?? []) aliasOfFile.set(fileKey((0, import_node_path4.resolve)(directory, filePath)), alias);
|
|
6265
|
+
const className = IDENTIFIER.test(node.className) && options.classes.has(node.className) ? node.className : "Instance";
|
|
6266
|
+
const taken = options.membersOf?.(className) ?? INSTANCE_MEMBERS;
|
|
6267
|
+
const members = [];
|
|
6268
|
+
if (parent && canOmit) members.push(`Parent: ${parent}`);
|
|
6269
|
+
const named = /* @__PURE__ */ new Set();
|
|
6270
|
+
for (const child of node.children ?? []) {
|
|
6271
|
+
if (!isNode(child)) continue;
|
|
6272
|
+
const childAlias = visit(child, [...segments, child.name], alias);
|
|
6273
|
+
if (!IDENTIFIER.test(child.name) || taken.has(child.name) || named.has(child.name)) continue;
|
|
6274
|
+
named.add(child.name);
|
|
6275
|
+
members.push(`${child.name}: ${childAlias}`);
|
|
6276
|
+
}
|
|
6277
|
+
const base = parent && canOmit ? `Omit<${className}, "Parent">` : className;
|
|
6278
|
+
lines.push(`type ${alias} = ${members.length ? `${base} & { ${members.join(", ")} }` : base}`);
|
|
6279
|
+
return alias;
|
|
6280
|
+
};
|
|
6281
|
+
const rootAlias = visit(root, [root.name], void 0);
|
|
6282
|
+
if (root.className === "DataModel") {
|
|
6283
|
+
lines.push(`declare game: ${rootAlias}`);
|
|
6284
|
+
const workspace = (root.children ?? []).find((child) => isNode(child) && child.className === "Workspace");
|
|
6285
|
+
const workspaceAlias = workspace && aliasOfNode.get(workspace);
|
|
6286
|
+
if (workspaceAlias) lines.push(`declare workspace: ${workspaceAlias}`);
|
|
6287
|
+
}
|
|
6288
|
+
let program;
|
|
6289
|
+
try {
|
|
6290
|
+
program = parse(lines.join("\n"));
|
|
6291
|
+
} catch (error) {
|
|
6292
|
+
return { problem: `Could not turn the sourcemap into types: ${error.message}` };
|
|
6293
|
+
}
|
|
6294
|
+
return {
|
|
6295
|
+
types: {
|
|
6296
|
+
program,
|
|
6297
|
+
scriptFor(file) {
|
|
6298
|
+
const alias = aliasOfFile.get(fileKey(file));
|
|
6299
|
+
return alias ? parse(`declare script: ${alias}`) : void 0;
|
|
6300
|
+
}
|
|
6301
|
+
}
|
|
6302
|
+
};
|
|
6303
|
+
}
|
|
6304
|
+
function isNode(value) {
|
|
6305
|
+
if (!value || typeof value !== "object") return false;
|
|
6306
|
+
const node = value;
|
|
6307
|
+
return typeof node.name === "string" && typeof node.className === "string";
|
|
6308
|
+
}
|
|
6309
|
+
function fileKey(path) {
|
|
6310
|
+
const extension = (0, import_node_path4.extname)(path);
|
|
6311
|
+
const bare = SCRIPT_EXTENSIONS.has(extension) ? path.slice(0, -extension.length) : path;
|
|
6312
|
+
const normalized = (0, import_node_path4.resolve)(bare);
|
|
6313
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
6314
|
+
}
|
|
5933
6315
|
|
|
5934
6316
|
// src/index.ts
|
|
5935
|
-
var defaultLibs = [luauLib, robloxLib];
|
|
5936
6317
|
var luautparser = {
|
|
5937
6318
|
tokenize,
|
|
5938
6319
|
parseTokens,
|
|
@@ -5949,6 +6330,7 @@ var index_default = luautparser;
|
|
|
5949
6330
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5950
6331
|
0 && (module.exports = {
|
|
5951
6332
|
BinaryOperators,
|
|
6333
|
+
CONFIG_FILE_NAMES,
|
|
5952
6334
|
Keywords,
|
|
5953
6335
|
LexError,
|
|
5954
6336
|
Operators,
|
|
@@ -5962,10 +6344,10 @@ var index_default = luautparser;
|
|
|
5962
6344
|
booleanType,
|
|
5963
6345
|
bufferType,
|
|
5964
6346
|
containsTypeParam,
|
|
5965
|
-
defaultLibs,
|
|
5966
6347
|
difference,
|
|
5967
6348
|
equalTypes,
|
|
5968
6349
|
falsyType,
|
|
6350
|
+
findConfig,
|
|
5969
6351
|
fn,
|
|
5970
6352
|
formatType,
|
|
5971
6353
|
getBinding,
|
|
@@ -5976,11 +6358,10 @@ var index_default = luautparser;
|
|
|
5976
6358
|
isPossiblyTruthy,
|
|
5977
6359
|
isUnassignedGlobal,
|
|
5978
6360
|
literal,
|
|
5979
|
-
|
|
5980
|
-
luauDefsPath,
|
|
5981
|
-
luauLib,
|
|
6361
|
+
loadConfig,
|
|
5982
6362
|
luautparser,
|
|
5983
6363
|
matchInfer,
|
|
6364
|
+
moduleCandidates,
|
|
5984
6365
|
moduleExports,
|
|
5985
6366
|
narrowExclude,
|
|
5986
6367
|
narrowFalsy,
|
|
@@ -5988,6 +6369,7 @@ var index_default = luautparser;
|
|
|
5988
6369
|
narrowTruthy,
|
|
5989
6370
|
neverType,
|
|
5990
6371
|
nilType,
|
|
6372
|
+
nodeHost,
|
|
5991
6373
|
numberType,
|
|
5992
6374
|
objectType,
|
|
5993
6375
|
optional,
|
|
@@ -5997,11 +6379,12 @@ var index_default = luautparser;
|
|
|
5997
6379
|
parseTokens,
|
|
5998
6380
|
parseWithRecovery,
|
|
5999
6381
|
primitive,
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
robloxLib,
|
|
6382
|
+
resolveModulePath,
|
|
6383
|
+
resolveTypeLibraries,
|
|
6003
6384
|
setAliasExpander,
|
|
6385
|
+
sourceMapTypes,
|
|
6004
6386
|
stringType,
|
|
6387
|
+
stripJsonComments,
|
|
6005
6388
|
substitute,
|
|
6006
6389
|
templateMatches,
|
|
6007
6390
|
threadType,
|