简单分割 Creator 生成的代码
在这篇文章中,我们将详细解析一段用于解析 Cocos Creator 生成代码的 JavaScript 代码。我们会逐步讲解这段代码的每个部分,帮助大家理解其背后的逻辑。
初始化函数与变量
const functionPattern = ':[function(';
const codeBlockStart = '{';
const metadataPattern = 'cc._RF.push(';
这段代码初始化了三个变量,用于在代码字符串中查找特定的标记:
- functionPattern:表示函数定义的起始位置。
- codeBlockStart:表示代码块的开始标记。
- metadataPattern:用于查找元数据的标记。
定位函数定义
const functionIndex = code.indexOf(functionPattern);
if (functionIndex === -1) {
console.log('代码解析结束');
return null;
}
通过 indexOf
方法查找 functionPattern
在代码中的位置,functionIndex
表示模块函数定义的起始位置。如果没有找到,解析过程将终止。
提取模块名
const splitIndex = code.lastIndexOf(',', functionIndex);
if (splitIndex === -1) {
console.log('未找到起始的 ","');
return null;
}
let moduleName = code.substring(splitIndex + 1, functionIndex);
moduleName = moduleName.replace(/"/g, '');
console.log("模块名称 = ", moduleName);
在找到函数定义位置后,代码通过 lastIndexOf
方法查找最靠近的逗号,并提取其中的字符串作为模块名。随后,去掉模块名中的引号,以便后续使用。
处理严格模式
const strictModeIndex = code.indexOf(codeBlockStart);
if (strictModeIndex === -1) {
console.log('未找到起始的严格模式代码');
return null;
}
通过查找代码块开始标记 codeBlockStart
,定位严格模式代码块的位置。如果没有找到该标记,说明代码结构不符合预期,解析过程将结束。
解析函数参数
let functionArgs = code.substring(functionIndex + functionPattern.length, code.indexOf(")"));
let argArray = functionArgs.split(",");
this.classes[moduleName] = "";
if (argArray.length >= 3) {
this.classes[moduleName] = `let ${argArray[0]} = require;\nlet ${argArray[1]} = module;\nlet ${argArray[2]} = exports;\n`;
} else if (argArray.length >= 2) {
this.classes[moduleName] = `let ${argArray[0]} = require;\nlet ${argArray[1]} = module;\n`;
} else if (argArray.length >= 1 && argArray[0].length > 0) {
this.classes[moduleName] = `let ${argArray[0]} = require;\n`;
}
这部分代码解析模块的函数参数,并根据参数的数量生成相应的 require
、module
和 exports
代码。这样做的目的是为了在解析后的代码中保留模块依赖的引用。
查找下一个函数定义
code = code.substring(strictModeIndex + 1);
let nextFunctionIndex = code.indexOf(functionPattern);
if (nextFunctionIndex === -1) {
nextFunctionIndex = code.length;
} else {
nextFunctionIndex = code.lastIndexOf(',', nextFunctionIndex);
if (nextFunctionIndex === -1) {
console.log('未找到下一个 ","');
return null;
}
}
在处理完当前模块后,代码会继续查找下一个函数定义的起始位置。如果找到了下一个函数定义,则继续分割代码块;如果没有找到,说明代码解析已经完成。
提取当前代码块
let currentCodeBlock = code.substring(0, nextFunctionIndex);
const codeSeparator = "},{";
const codeEndIndex = currentCodeBlock.lastIndexOf(codeSeparator);
if (codeEndIndex === -1) {
console.log('代码分割失败 "},{"');
return null;
}
this.classes[moduleName] += currentCodeBlock.substring(0, codeEndIndex);
这段代码负责提取当前代码块的内容,并使用分隔符 },{
将代码块进行分割,确保只提取有用的代码部分。
元数据解析
let metaIndex = this.classes[moduleName].indexOf(metadataPattern);
if (metaIndex != -1) {
let metaString = this.classes[moduleName].substring(metaIndex + metadataPattern.length);
let metaEndIndex = metaString.indexOf(")");
metaString = metaString.substring(0, metaEndIndex);
let metaArray = metaString.split(",");
this.metaMap[moduleName] = UuidUtils.decompressUuid(metaArray[1].replace(/"/g, ''));
}
通过查找 metadataPattern
,代码可以提取并解析元数据。元数据通常包含 UUID 信息,代码会解压并存储这些 UUID 信息,方便后续使用。
递归解析剩余代码
code = code.substring(nextFunctionIndex);
this.parseCreatorCode(code);
代码递归调用自身,继续解析剩余的代码块,直到所有代码都被解析完成。
导入项目并运行
最后,将导出的代码与meta文件导入creator工程,运行项目调试。
2 学习与交流
- 欢迎加 qq 985251414,一起学习与交流!