bc-minecraft-bedrock-project
Version:
The typescript library responsible for reading/parsing minecraft bedrock data
298 lines • 10.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.process = process;
exports.parseCustomCommands = parseCustomCommands;
const bc_minecraft_bedrock_command_1 = require("bc-minecraft-bedrock-command");
const ts = __importStar(require("typescript"));
const custom_command_1 = require("./custom-command");
/**
* Parses script files and returns script-defined custom commands.
*/
function process(doc) {
const data = parseCustomCommands(doc);
const out = [];
Object.keys(data).forEach((key) => out.push(custom_command_1.CustomCommand.create(key, doc.uri, data[key])));
return out;
}
function parseCustomCommands(doc) {
const text = doc.getText();
const language = doc.uri.endsWith('.ts') ? 'typescript' : 'javascript';
const scriptKind = doc.uri.endsWith('.ts') ? ts.ScriptKind.TS : ts.ScriptKind.JS;
const source = ts.createSourceFile(doc.uri, text, ts.ScriptTarget.Latest, true, scriptKind);
const variables = new Map();
const output = {};
visit(source);
return output;
function visit(node) {
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
variables.set(node.name.text, node.initializer);
}
if (ts.isCallExpression(node)) {
const call = node;
if (isCustomCommandRegisterCall(call)) {
const info = parseRegisterCall(call, source, variables, doc.uri, language);
if (info) {
const list = output[info.name] ?? [];
list.push(info);
output[info.name] = list;
}
}
}
ts.forEachChild(node, visit);
}
}
function isCustomCommandRegisterCall(node) {
if (!ts.isPropertyAccessExpression(node.expression))
return false;
if (node.expression.name.text !== 'registerCommand')
return false;
const object = node.expression.expression;
if (ts.isIdentifier(object) && object.text === 'CustomCommandRegistry') {
return true;
}
if (ts.isPropertyAccessExpression(object) && ts.isIdentifier(object.name)) {
return object.name.text === 'CustomCommandRegistry';
}
return false;
}
function parseRegisterCall(call, source, variables, uri, language) {
const args = call.arguments;
if (args.length <= 0)
return undefined;
const first = resolveValue(args[0], variables);
const second = args.length > 1 ? resolveValue(args[1], variables) : undefined;
const object = getDefinitionObject(first, second);
if (!object)
return undefined;
const nameRaw = getString(object['name']) ?? getString(first);
if (!nameRaw)
return undefined;
const name = nameRaw.replace(/^\//, '');
const description = getString(object['description']) ?? 'Script-defined custom command.';
const permission = getPermissionLevel(object['permission']);
const parameters = getParameters(name, object);
const line = ts.getLineAndCharacterOfPosition(source, call.getStart(source)).line + 1;
return {
name,
documentation: description,
permission_level: permission,
parameters,
source: {
uri,
line,
language,
},
};
}
function getDefinitionObject(first, second) {
if (isObject(first))
return first;
if (isObject(second))
return second;
return undefined;
}
function getParameters(commandName, object) {
const out = [{ text: commandName, type: bc_minecraft_bedrock_command_1.ParameterType.keyword, required: true }];
const mandatory = getArray(object['mandatoryParameters']);
const optional = getArray(object['optionalParameters']);
const mixed = getArray(object['parameters']);
addParameterArray(out, mandatory, true);
addParameterArray(out, optional, false);
addParameterArray(out, mixed, undefined);
return out;
}
function addParameterArray(receiver, input, required) {
if (!input)
return;
for (let i = 0; i < input.length; i++) {
const item = input[i];
if (!isObject(item))
continue;
const name = getString(item['name']) ?? getString(item['id']) ?? `parameter_${i + 1}`;
const typeValue = getString(item['type']);
const optional = item['optional'] === true;
const parameterRequired = typeof required === 'boolean' ? required : !optional;
const type = toParameterType(typeValue);
const parameter = { text: name, type, required: parameterRequired };
const acceptedValues = getStringArray(item['enum']) ?? getStringArray(item['acceptedValues']) ?? getStringArray(item['values']);
if (acceptedValues && acceptedValues.length > 0) {
parameter.options = { acceptedValues };
if (type === bc_minecraft_bedrock_command_1.ParameterType.unknown) {
parameter.type = bc_minecraft_bedrock_command_1.ParameterType.keyword;
}
}
receiver.push(parameter);
}
}
function toParameterType(type) {
if (!type)
return bc_minecraft_bedrock_command_1.ParameterType.unknown;
switch (type.toLowerCase()) {
case 'bool':
case 'boolean':
return bc_minecraft_bedrock_command_1.ParameterType.boolean;
case 'int':
case 'integer':
case 'long':
return bc_minecraft_bedrock_command_1.ParameterType.integer;
case 'float':
case 'number':
case 'double':
return bc_minecraft_bedrock_command_1.ParameterType.float;
case 'coordinate':
case 'coordinates':
case 'position':
case 'vector3':
case 'location':
return bc_minecraft_bedrock_command_1.ParameterType.coordinate;
case 'target':
case 'entity':
case 'selector':
case 'entityselector':
case 'playerselector':
return bc_minecraft_bedrock_command_1.ParameterType.selector;
case 'message':
return bc_minecraft_bedrock_command_1.ParameterType.message;
case 'string':
case 'text':
return bc_minecraft_bedrock_command_1.ParameterType.string;
case 'json':
return bc_minecraft_bedrock_command_1.ParameterType.jsonRawText;
default:
return bc_minecraft_bedrock_command_1.ParameterType.unknown;
}
}
function getPermissionLevel(value) {
if (typeof value === 'number')
return value;
const text = getString(value);
if (!text)
return 0;
switch (text.toLowerCase()) {
case 'any':
return 0;
case 'host':
case 'gamedirectors':
return 1;
case 'admin':
return 2;
}
return 0;
}
function resolveValue(value, variables, depth = 0) {
if (depth > 20)
return undefined;
if (ts.isParenthesizedExpression(value)) {
return resolveValue(value.expression, variables, depth + 1);
}
if (ts.isAsExpression(value) || ts.isTypeAssertionExpression(value)) {
return resolveValue(value.expression, variables, depth + 1);
}
if (ts.isIdentifier(value)) {
const resolved = variables.get(value.text);
if (resolved)
return resolveValue(resolved, variables, depth + 1);
return value.text;
}
if (ts.isPropertyAccessExpression(value)) {
return value.name.text;
}
if (ts.isStringLiteral(value) || ts.isNoSubstitutionTemplateLiteral(value)) {
return value.text;
}
if (ts.isNumericLiteral(value)) {
return Number(value.text);
}
if (value.kind === ts.SyntaxKind.TrueKeyword)
return true;
if (value.kind === ts.SyntaxKind.FalseKeyword)
return false;
if (ts.isArrayLiteralExpression(value)) {
return value.elements.map((element) => resolveValue(element, variables, depth + 1));
}
if (ts.isObjectLiteralExpression(value)) {
const out = {};
for (let i = 0; i < value.properties.length; i++) {
const property = value.properties[i];
if (ts.isPropertyAssignment(property)) {
const key = getPropertyName(property.name);
if (!key)
continue;
out[key] = resolveValue(property.initializer, variables, depth + 1);
}
else if (ts.isShorthandPropertyAssignment(property)) {
const name = property.name.text;
out[name] = resolveValue(property.name, variables, depth + 1);
}
}
return out;
}
return undefined;
}
function getPropertyName(name) {
if (ts.isIdentifier(name))
return name.text;
if (ts.isStringLiteral(name))
return name.text;
if (ts.isNumericLiteral(name))
return name.text;
return undefined;
}
function isObject(value) {
return !!value && typeof value === 'object' && !Array.isArray(value);
}
function getArray(value) {
if (Array.isArray(value))
return value;
return undefined;
}
function getString(value) {
if (typeof value === 'string')
return value;
return undefined;
}
function getStringArray(value) {
if (!Array.isArray(value))
return undefined;
const out = [];
for (let i = 0; i < value.length; i++) {
const item = value[i];
if (typeof item === 'string')
out.push(item);
}
return out;
}
//# sourceMappingURL=process.js.map