panel_ex.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. 面板扩展
  3. 功能: 扩展移动脚本文件时检测 import from 'xxx' 路径并修改
  4. */
  5. 'use strict';
  6. var path = require('path');
  7. var fs = require('fs');
  8. const tools = require('../../tools/tools');
  9. module.exports = {
  10. /** @type import('../../panel/vs-panel/vs-panel-base') */
  11. parent : null,
  12. //
  13. ready(parent){
  14. // index.js 对象
  15. this.parent = parent;
  16. },
  17. // 编辑器启动完成
  18. onLoad(parent){
  19. this.move_files = []
  20. },
  21. // 文件被移动
  22. onAssetsMovedEvent(files){
  23. if(!this.parent.cfg.renameConverImportPath){
  24. return;
  25. }
  26. files.forEach((v, i) =>
  27. {
  28. let extname = path.extname(v.url)
  29. // 重命名后检测引用路径
  30. if(extname == '.js' || extname == '.ts')
  31. {
  32. this.move_files.push(v); // 200毫秒内记录下被移动的文件
  33. }
  34. });
  35. // 多次调用200毫秒内只执行一次
  36. if(this.move_files.length){
  37. this.parent.setTimeoutById(this.tryLoadRenameFile.bind(this),200,'renameCheck');
  38. }
  39. },
  40. // 开始修改import路径
  41. tryLoadRenameFile()
  42. {
  43. if(!this.move_files.length){
  44. return
  45. }
  46. // 1.加载所有被移动的文件
  47. // 2.加载所有import引用被移动文件的脚本
  48. let usedPaths = {}
  49. let usedList = {}
  50. let moduleCheckReg = ''
  51. for (let i = 0; i < this.move_files.length; i++)
  52. {
  53. const file = this.move_files[i];
  54. let moduleName = '/'+tools.getFileName(file.srcPath);
  55. if(!usedList[moduleName]) moduleCheckReg += moduleName + "[\"\']|"
  56. let list = usedList[file.destPath] = usedList[moduleName] = usedList[file.srcPath] = {}; // 新路径、模块、旧路径,映射关系
  57. list.old_path = file.srcPath;
  58. list.new_path = file.destPath;
  59. let model = this.parent.fileMgr.getModelByFsPath(file.destPath)
  60. if(model == null){
  61. // 加载路径的代码文件到缓存
  62. model = this.parent.loadVsModel(file.url,path.extname(file.url),true);
  63. }
  64. usedPaths[file.destPath] = model;
  65. }
  66. moduleCheckReg = RegExp(moduleCheckReg.substr(0,moduleCheckReg.length-1).replace(/\./g,'\\.'),'g');
  67. // 尝试找出files被那些脚本内部import了,并加载
  68. for (const fsPath in this.parent.file_list_map)
  69. {
  70. let item = this.parent.file_list_map[fsPath];
  71. // 该文件引用的模块列表
  72. let importList = !usedList[fsPath] || usedList[fsPath].old_path != fsPath && usedList[fsPath].new_path != fsPath ? item.data && item.data.match(moduleCheckReg) : undefined;
  73. if(importList)// js,ts文件数据
  74. {
  75. // 2,import被移动路径的文件
  76. let model = this.parent.fileMgr.getModelByFsPath(fsPath);
  77. if(!model){
  78. // 加载旧路径的代码文件到缓存
  79. model = this.parent.loadVsModel(item.meta,item.extname,true,false);
  80. model.setValue(item.data);
  81. }
  82. usedPaths[fsPath] = model;
  83. let list = usedList[fsPath] = usedList[fsPath] || {}; // 模块、旧路径、新路径,映射关系
  84. list.new_path = fsPath;
  85. }
  86. }
  87. this.move_files = []
  88. setTimeout(()=>{
  89. // console.log("rename列表:",usedPaths)
  90. this.updatedImports(usedPaths,usedList);
  91. },10)
  92. },
  93. // 应用修改import路径
  94. updatedImports(usedPaths,usedList)
  95. {
  96. let saveList = []
  97. let hintText = '是否同步以下脚本文件的 import、require路径:\n';
  98. for (const m_path in usedPaths)
  99. {
  100. const model = usedPaths[m_path];
  101. const info = usedList[m_path];
  102. let text = model.getValue()
  103. let imports = tools.getImportStringPaths(text); // 代码内import列表
  104. let hasUpdate = false
  105. for (let i = imports.length-1; i >= 0 ; i--)
  106. {
  107. let importItem = imports[i];
  108. if(importItem.path.indexOf('/') == -1){
  109. continue;
  110. }
  111. // 转换相对路径
  112. let importFspath = tools.relativePathTofsPath(info.old_path || info.new_path,importItem.path);
  113. let extname = path.extname(importFspath);
  114. let importPathInfo = extname == '' ? usedList[importFspath+'.js'] || usedList[importFspath+'.ts'] : usedList[importFspath];
  115. let newImportPath = importItem.path;
  116. if(importPathInfo){
  117. newImportPath = tools.fsPathToRelativePath(info.new_path,importPathInfo.new_path);
  118. let s_i = path.extname(newImportPath) != '' ? newImportPath.lastIndexOf('.') : -1;
  119. if(extname == '' && importFspath.lastIndexOf('.') == -1 && s_i != -1) newImportPath = newImportPath.substr(0,s_i);
  120. }else{
  121. newImportPath = tools.fsPathToRelativePath(info.new_path,importFspath);
  122. }
  123. if(importItem.path != newImportPath){
  124. hasUpdate = true;
  125. // console.log('转换import:',info.new_path,importItem.path,'to',newImportPath)
  126. text = text.substr(0,importItem.start) + newImportPath + text.substr(importItem.start+importItem.length)
  127. }
  128. }
  129. if(hasUpdate){
  130. saveList.push({model,text})
  131. hintText+=model.dbUrl+"\n";
  132. }
  133. }
  134. // 应用提示
  135. let isApply = saveList.length>0 && confirm(hintText);
  136. if(isApply){
  137. for (let i = 0; i < saveList.length; i++)
  138. {
  139. let info = saveList[i];
  140. info.model.setValue(info.text);
  141. let id = this.parent.getTabIdByModel(info.model);
  142. if(id == null)
  143. {
  144. // 没有打开的文件则自动保存
  145. this.parent.saveFileByUrl(info.model.dbUrl,info.text);
  146. }else{
  147. // 已经打开的文件等用户手动保存
  148. this.parent.onVsDidChangeContent({},info.model)
  149. }
  150. }
  151. }
  152. },
  153. // 面板销毁
  154. onDestroy(){
  155. },
  156. /************* 事件 *************/
  157. messages:{
  158. // 快捷键打开当前选中文件/节点进入编辑
  159. 'custom-cmd' (event,info) {
  160. },
  161. 'scene:saved'(){
  162. // Editor.log("事件 save")
  163. }
  164. },
  165. };