neo-cmp-cli 1.10.3 → 1.10.6
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/dist/neo/neoService.js +1 -1
- package/dist/package.json.js +1 -1
- package/package.json +2 -3
- package/template/antd-custom-cmp-template/package.json +1 -1
- package/template/antd-custom-cmp-template/src/components/dataDashboard__c/model.ts +1 -1
- package/template/antd-custom-cmp-template/src/components/searchWidget__c/model.ts +1 -1
- package/template/develop/neo-custom-cmp-template/src/components/neoEntityGrid/model.ts +2 -2
- package/template/echarts-custom-cmp-template/package.json +1 -1
- package/template/echarts-custom-cmp-template/src/components/chartWidget__c/model.ts +1 -1
- package/template/neo-custom-cmp-template/package.json +1 -1
- package/template/neo-custom-cmp-template/src/components/entityDetail__c/model.ts +1 -1
- package/template/neo-custom-cmp-template/src/components/entityForm__c/model.ts +1 -1
- package/template/neo-custom-cmp-template/src/components/entityTable__c/model.ts +1 -1
- package/template/react-custom-cmp-template/package.json +1 -1
- package/template/react-ts-custom-cmp-template/package.json +1 -1
- package/template/vue2-custom-cmp-template/package.json +1 -1
- package/test/demo.js +0 -20
- package/test/demo2.js +0 -3
- package/test/demo3.js +0 -3
- package/test/demo6.js +0 -95
- package/test/deprecate-versions.js +0 -30
- package/test/neo.config.js +0 -117
- package/test/package.json +0 -46
package/dist/neo/neoService.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("axios"),t=require("form-data"),s=require("node:fs"),o=require("node:path"),i=require("ora"),r=require("lodash"),n=require("akfun"),a=require("./neoLogin.js"),c=require("../utils/projectUtils/updatePublishLog.js"),l=require("../utils/common.js"),h=require("./neoEnvManager.js"),u=require("../utils/tableLog.js");var d,p;exports.__require=function(){if(p)return d;p=1;const m=e,f=t,y=s,g=o,w=i,k=r,{resolve:A}=n,$=a.__require(),C=c.__require(),{getFramework:x,errorLog:T,successLog:F}=l.__require(),L=h.__require(),{tableLog:P}=u.__require(),b=["cmpType","label","componentCategory","description","framework","icon","iconUrl","orderNo","version","propsSchema","defaultProps","previewProps","events","functions","asset","modelAsset","cssAsset","codeLib"];return d=class{constructor(){const e=L.getEnvConfig(),{assetsRoot:t,auth:s,authType:o}=e||{};this.authType=o||"oauth2",this.NeoCrmAPI=e,"password"!==this.authType||s||(T("密码授权模式时,neo.config.js / neoConfig / auth 配置不能为空"),process.exit(1)),"password"===this.authType?s.client_id&&s.client_secret&&s.username&&s.password||(T("neo.config.js / neoConfig / auth 配置不完整(password 模式),需要包含 client_id、client_secret、username、password"),process.exit(1)):"oauth2"!=this.authType&&(T(`不支持的授权类型: ${this.authType},可选值:oauth2、password`),process.exit(1)),this.assetsRoot=t||A("dist"),this.auth=s,this.cmpList=[],this.cmpInfoMap={},this.tokenCache={token:null,expiresAt:null}}buildFullUrl(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.NeoCrmAPI.neoBaseURL}${e}`}uploadAPI(){return this.buildFullUrl(this.NeoCrmAPI.uploadAPI)}saveAPI(){return this.buildFullUrl(this.NeoCrmAPI.saveAPI)}isTokenExpired(){return!this.tokenCache.token||!this.tokenCache.expiresAt||Date.now()>=this.tokenCache.expiresAt}async getToken(){return this.isTokenExpired()?"oauth2"===this.authType?await this.getTokenByOAuth2():await this.getTokenByPassword():this.tokenCache.token}async getTokenByPassword(){const e=w("获取 token(密码模式)...").start();if(!this.isTokenExpired())return F("使用缓存的 token。",e),this.tokenCache.token;const t=new URLSearchParams;t.append("grant_type","password"),t.append("client_id",this.auth.client_id),t.append("client_secret",this.auth.client_secret),t.append("username",this.auth.username),t.append("password",this.auth.password);const s=this.buildFullUrl(this.NeoCrmAPI.tokenURL);try{const o=await m.post(s,t.toString(),{headers:{"Content-Type":"application/x-www-form-urlencoded"}}),i=o.data||{},{access_token:r,expires_in:n}=i;r||(T("获取 token 失败(授权配置错误):响应中未包含 access_token,"+JSON.stringify(o.data),e),process.exit(1));const a=parseInt(n)||3600;return this.tokenCache={...i,token:r,expiresAt:Date.now()+1e3*(a-60)},e.clear(),e.stop(),r}catch(o){T("获取 token 失败",e),T(`\n获取 token 失败: ${o.message||o.msg}`),T(`\ntoken 授权地址: ${s}`),T(`\ntoken 请求参数: ${t}`),o.response&&T(`响应数据: ${JSON.stringify(o.response.data)}`),process.exit(1)}}async getTokenByOAuth2(){const e=w("获取 token(OAuth2 模式)...").start();try{const t={loginURL:this.NeoCrmAPI.loginURL,tokenURL:this.NeoCrmAPI.tokenURL},s=new $(t),o=await s.getAccessToken(),i=o.access_token;return this.tokenCache={...o,token:i,expiresAt:Date.now()+72e5},e.clear(),e.stop(),i}catch(t){T("获取 token 失败(OAuth2 模式)",e),T(`\n获取 token 失败: ${t.message||t.msg}`),t.response&&T(`响应数据: ${JSON.stringify(t.response.data)}`),process.exit(1)}}async refreshToken(){return this.tokenCache={token:null,expiresAt:null},await this.getToken()}async ensureValidToken(){if(!this.tokenCache.token)return await this.getToken();if(this.isTokenExpired()){const e=w("token 已过期,正在刷新...").start();try{const t=await this.refreshToken();return F("token 刷新成功。",e),t}catch(t){throw T("token 刷新失败。",e),t}}return this.tokenCache.token}async uploadFile(e,t={}){const s=await this.ensureValidToken();if(!e||"string"!=typeof e)throw new Error(`文件路径无效: ${e}`);if(!y.existsSync(e))throw new Error(`文件不存在: ${e}`);const o=y.statSync(e);if(!o.isFile())throw new Error(`路径不是文件: ${e}`);const i=t.maxSize||5242880;if(o.size>i){const e=(o.size/1024/1024).toFixed(2),t=(i/1024/1024).toFixed(2);throw new Error(`文件大小超过限制: ${e}MB > ${t}MB`)}if(0===o.size)throw new Error(`文件为空: ${e}`);const r=g.basename(e),n=(o.size/1024).toFixed(2),a=w(`正在上传文件: ${r} (${n}KB)...`).start();try{const o=new f,i=t.fieldName||"customComponentCode",n=y.createReadStream(e);o.append(i,n,r);const c=this.uploadAPI(),l=t.timeout||6e4,h={headers:{Authorization:`Bearer ${s}`,"xsy-inner-source":"bff",...o.getHeaders()},timeout:l,maxContentLength:1/0,maxBodyLength:1/0},u=await m.post(c,o,h);let d;const p=u.data;if(200!==u.status&&201!==u.status)throw new Error(`上传失败: HTTP ${u.status}`);if("string"==typeof p)d=p.trim();else{if(!p||"object"!=typeof p)throw new Error("响应数据格式不正确: "+typeof p);if(void 0!==p.code&&200!==p.code&&0!==p.code){const e=p.message||p.msg||"未知错误";throw new Error(`上传失败: ${e} (code: ${p.code})`)}d=void 0!==p.data?p.data:void 0!==p.url?p.url:void 0!==p.fileUrl?p.fileUrl:p}if(!d)throw new Error("返回的文件地址为空");let g;return"string"==typeof d?g=d:d&&"object"==typeof d&&d.url&&(g=d.url),F(`文件上传成功: ${r} -> ${g}`,a),g}catch(t){if(T(`上传文件失败: ${t.message||t.msg}, 文件路径: ${e}`,a),t.response){const e=t.response.status,s=t.response.statusText,o=t.response.data,i=t.config?.url||this.uploadAPI();if(T("\n========== 上传请求详情 =========="),T(`请求 URL: ${i}`),T(`HTTP 状态码: ${e} ${s}`),T(`响应数据: ${JSON.stringify(o)}`),T("==================================\n"),404===e)throw new Error(`上传 API 不存在 (404): ${i}\n请检查 neo.config.js 中的 neoBaseURL 配置是否正确,或者 API 路径是否存在。\n当前配置的 API 路径: ${this.NeoCrmAPI.uploadAPI}`)}else t.request&&T("请求已发送但未收到响应,请检查网络连接或代理配置。");throw t}}async publish2oss(e,t=[".js",".css",".zip"]){if(!e)return void T(`自定义组件名称不能为空: ${e}`);if(!y.existsSync(this.assetsRoot))return void T(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e},o=y.readdirSync(this.assetsRoot).map(async o=>{const i=g.join(this.assetsRoot,o),r=y.statSync(i),n=g.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=k.camelCase(e);if(o.indexOf(t)<0)return;try{const e=await this.uploadFile(i);o.indexOf("Model")>-1?s.modelAsset=e:o.endsWith(".css")?s.cssAsset=e:o.endsWith(".zip")?s.codeLib=e:s.asset=e}catch(e){T(`文件上传失败(${o}):\n`),process.exit(1)}}});return await Promise.all(o),s&&s.cmpType&&(console.info("上传至 OSS 的文件信息:\n",s),C(s)),s}async getCmpAssets(e,t=[".js",".css",".zip"]){if(!e)return void T(`自定义组件名称不能为空: ${e}`);if(!y.existsSync(this.assetsRoot))return void T(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e};return y.readdirSync(this.assetsRoot).forEach(o=>{const i=g.join(this.assetsRoot,o),r=y.statSync(i),n=g.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=k.camelCase(e);if(o.indexOf(t)<0)return;const n=5242880;if(r.size>n){const e=(r.size/1024/1024).toFixed(2),t=(n/1024/1024).toFixed(2);throw new Error(`${o} 文件大小超过限制: ${e}MB > ${t}MB`)}const a={fileContent:y.createReadStream(i),fileName:o,fileSize:r.size};o.indexOf("Model")>-1?s.modelAssetFile=a:o.endsWith(".css")?s.cssAssetFile=a:o.endsWith(".zip")?s.codeLibFile=a:s.assetFile=a}}),s}async updateCustomComponent(e){const t=await this.ensureValidToken();if(!e)throw new Error("componentData 不能为空");const s=w("正在保存自定义组件信息...").start();try{const o=this.saveAPI(),i=new f;e.assetFile&&i.append("assetFile",e.assetFile.fileContent,e.assetFile.fileName),e.modelAssetFile&&i.append("modelAssetFile",e.modelAssetFile.fileContent,e.modelAssetFile.fileName),e.cssAssetFile&&i.append("cssAssetFile",e.cssAssetFile.fileContent,e.cssAssetFile.fileName),e.codeLibFile&&i.append("codeLibFile",e.codeLibFile.fileContent,e.codeLibFile.fileName),i.append("component",JSON.stringify(k.omit(e,["assetFile","modelAssetFile","cssAssetFile","codeLibFile"])));const r=await m.post(o,i,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff",...i.getHeaders()},timeout:12e4,maxContentLength:1/0,maxBodyLength:1/0}),{code:n,message:a,msg:c}=r.data||{};n&&200!==n&&(T(`保存自定义组件信息失败: ${a||c||"未知错误"}`),process.exit(1)),s.clear(),s.stop()}catch(e){const t=e.message||e.msg;T(t?`保存自定义组件信息失败: ${t}`:`保存自定义组件信息失败: ${JSON.stringify(e)}`,s),process.exit(1)}}async getCustomCmpList(){const e=await this.ensureValidToken();try{let t=this.buildFullUrl(this.NeoCrmAPI.queryAll);t+=`&fields=${b.join(",")}`;const s=await m.get(t,{headers:{Authorization:`Bearer ${e}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:o,message:i,msg:r}=s.data||{};o&&200!==o&&(T(`获取自定义组件列表失败: ${i||r||"未知错误"}`),process.exit(1)),this.updateCustomCmpList(s.data.data||[])}catch(e){const t=e.message||e.msg;T(t?`获取自定义组件列表失败: ${t}`:`响应数据: ${JSON.stringify(e)}`),process.exit(1)}return this.cmpList||[]}getCodeLibByCmpType(e){return e?this.buildFullUrl(this.NeoCrmAPI.getCodeLibAPI(e)):null}async deleteCmp(e){const t=await this.ensureValidToken();e||(T("自定义组件名称不能为空。"),process.exit(1));let s=this.buildFullUrl(this.NeoCrmAPI.delete);s+=`/${e}`;const o=await m.delete(s,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:i,message:r,msg:n,errorInfo:a}=o.data||{};return i&&200!==i&&(a&&a.length>0?P(a,{title:"删除自定义组件失败",columns:["reason","instance"],headers:{reason:"原因",instance:"实例"},align:{reason:"center",instance:"center"},padding:2,showBorder:!0}):T(`删除自定义组件失败: ${r||n||"未知错误"}`),process.exit(1)),o.data}getCmpListByFramework(e){if(!e)return this.cmpList;const t=x(e);return this.cmpList.filter(e=>e.framework===t)}getCmpInfoByCmpType(e){return e&&this.cmpInfoMap[e]||null}updateCustomCmpList(e){e&&Array.isArray(e)&&(this.cmpList=e,e.forEach(e=>{this.cmpInfoMap[e.cmpType]=e}))}async request(e,t,s={}){const o=await this.ensureValidToken(),{data:i,headers:r={},params:n}=s,a=this.buildFullUrl(t);try{const t=await m({method:e,url:a,data:i,params:n,headers:{Authorization:`Bearer ${o}`,"xsy-inner-source":"bff",...r}});if(t.data&&t.data.code&&200!==t.data.code)throw new Error(`请求失败: ${t.data.message||t.data.msg||"未知错误"}`);return t.data}catch(s){throw T(`请求失败 [${e} ${t}]: ${s.message||s.msg}`),s.response&&T(`响应数据: ${JSON.stringify(s.response.data)}`),s}}async get(e,t={}){return await this.request("GET",e,t)}async post(e,t={}){return await this.request("POST",e,t)}async put(e,t={}){return await this.request("PUT",e,t)}async delete(e,t={}){return await this.request("DELETE",e,t)}}};
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("axios"),t=require("form-data"),s=require("node:fs"),o=require("node:path"),i=require("ora"),r=require("lodash"),n=require("akfun"),a=require("./neoLogin.js"),c=require("../utils/projectUtils/updatePublishLog.js"),l=require("../utils/common.js"),h=require("./neoEnvManager.js"),u=require("../utils/tableLog.js");var d,p;exports.__require=function(){if(p)return d;p=1;const m=e,f=t,y=s,g=o,w=i,k=r,{resolve:A}=n,C=a.__require(),$=c.__require(),{getFramework:x,errorLog:T,successLog:F}=l.__require(),L=h.__require(),{tableLog:P}=u.__require(),b=["cmpType","label","componentCategory","description","framework","icon","iconUrl","orderNo","version","propsSchema","defaultProps","previewProps","events","functions","asset","modelAsset","cssAsset","codeLib"];return d=class{constructor(){const e=L.getEnvConfig(),{assetsRoot:t,auth:s,authType:o}=e||{};this.authType=o||"oauth2",this.NeoCrmAPI=e,"password"!==this.authType||s||(T("密码授权模式时,neo.config.js / neoConfig / auth 配置不能为空"),process.exit(1)),"password"===this.authType?s.client_id&&s.client_secret&&s.username&&s.password||(T("neo.config.js / neoConfig / auth 配置不完整(password 模式),需要包含 client_id、client_secret、username、password"),process.exit(1)):"oauth2"!=this.authType&&(T(`不支持的授权类型: ${this.authType},可选值:oauth2、password`),process.exit(1)),this.assetsRoot=t||A("dist"),this.auth=s,this.cmpList=[],this.cmpInfoMap={},this.tokenCache={token:null,expiresAt:null}}buildFullUrl(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.NeoCrmAPI.neoBaseURL}${e}`}uploadAPI(){return this.buildFullUrl(this.NeoCrmAPI.uploadAPI)}saveAPI(){return this.buildFullUrl(this.NeoCrmAPI.saveAPI)}isTokenExpired(){return!this.tokenCache.token||!this.tokenCache.expiresAt||Date.now()>=this.tokenCache.expiresAt}async getToken(){return this.isTokenExpired()?"oauth2"===this.authType?await this.getTokenByOAuth2():await this.getTokenByPassword():this.tokenCache.token}async getTokenByPassword(){const e=w("获取 token(密码模式)...").start();if(!this.isTokenExpired())return F("使用缓存的 token。",e),this.tokenCache.token;const t=new URLSearchParams;t.append("grant_type","password"),t.append("client_id",this.auth.client_id),t.append("client_secret",this.auth.client_secret),t.append("username",this.auth.username),t.append("password",this.auth.password);const s=this.buildFullUrl(this.NeoCrmAPI.tokenURL);try{const o=await m.post(s,t.toString(),{headers:{"Content-Type":"application/x-www-form-urlencoded"}}),i=o.data||{},{access_token:r,expires_in:n}=i;r||(T("获取 token 失败(授权配置错误):响应中未包含 access_token,"+JSON.stringify(o.data),e),process.exit(1));const a=parseInt(n)||3600;return this.tokenCache={...i,token:r,expiresAt:Date.now()+1e3*(a-60)},e.clear(),e.stop(),r}catch(o){T("获取 token 失败",e),T(`\n获取 token 失败: ${o.message||o.msg}`),T(`\ntoken 授权地址: ${s}`),T(`\ntoken 请求参数: ${t}`),o.response&&T(`响应数据: ${JSON.stringify(o.response.data)}`),process.exit(1)}}async getTokenByOAuth2(){const e=w("获取 token(OAuth2 模式)...").start();try{const t={neoBaseURL:this.NeoCrmAPI.neoBaseURL,loginURL:this.NeoCrmAPI.loginURL,tokenURL:this.NeoCrmAPI.tokenURL},s=new C(t),o=await s.getAccessToken(),i=o.access_token;return this.tokenCache={...o,token:i,expiresAt:Date.now()+72e5},e.clear(),e.stop(),i}catch(t){T("获取 token 失败(OAuth2 模式)",e),T(`\n获取 token 失败: ${t.message||t.msg}`),t.response&&T(`响应数据: ${JSON.stringify(t.response.data)}`),process.exit(1)}}async refreshToken(){return this.tokenCache={token:null,expiresAt:null},await this.getToken()}async ensureValidToken(){if(!this.tokenCache.token)return await this.getToken();if(this.isTokenExpired()){const e=w("token 已过期,正在刷新...").start();try{const t=await this.refreshToken();return F("token 刷新成功。",e),t}catch(t){throw T("token 刷新失败。",e),t}}return this.tokenCache.token}async uploadFile(e,t={}){const s=await this.ensureValidToken();if(!e||"string"!=typeof e)throw new Error(`文件路径无效: ${e}`);if(!y.existsSync(e))throw new Error(`文件不存在: ${e}`);const o=y.statSync(e);if(!o.isFile())throw new Error(`路径不是文件: ${e}`);const i=t.maxSize||5242880;if(o.size>i){const e=(o.size/1024/1024).toFixed(2),t=(i/1024/1024).toFixed(2);throw new Error(`文件大小超过限制: ${e}MB > ${t}MB`)}if(0===o.size)throw new Error(`文件为空: ${e}`);const r=g.basename(e),n=(o.size/1024).toFixed(2),a=w(`正在上传文件: ${r} (${n}KB)...`).start();try{const o=new f,i=t.fieldName||"customComponentCode",n=y.createReadStream(e);o.append(i,n,r);const c=this.uploadAPI(),l=t.timeout||6e4,h={headers:{Authorization:`Bearer ${s}`,"xsy-inner-source":"bff",...o.getHeaders()},timeout:l,maxContentLength:1/0,maxBodyLength:1/0},u=await m.post(c,o,h);let d;const p=u.data;if(200!==u.status&&201!==u.status)throw new Error(`上传失败: HTTP ${u.status}`);if("string"==typeof p)d=p.trim();else{if(!p||"object"!=typeof p)throw new Error("响应数据格式不正确: "+typeof p);if(void 0!==p.code&&200!==p.code&&0!==p.code){const e=p.message||p.msg||"未知错误";throw new Error(`上传失败: ${e} (code: ${p.code})`)}d=void 0!==p.data?p.data:void 0!==p.url?p.url:void 0!==p.fileUrl?p.fileUrl:p}if(!d)throw new Error("返回的文件地址为空");let g;return"string"==typeof d?g=d:d&&"object"==typeof d&&d.url&&(g=d.url),F(`文件上传成功: ${r} -> ${g}`,a),g}catch(t){if(T(`上传文件失败: ${t.message||t.msg}, 文件路径: ${e}`,a),t.response){const e=t.response.status,s=t.response.statusText,o=t.response.data,i=t.config?.url||this.uploadAPI();if(T("\n========== 上传请求详情 =========="),T(`请求 URL: ${i}`),T(`HTTP 状态码: ${e} ${s}`),T(`响应数据: ${JSON.stringify(o)}`),T("==================================\n"),404===e)throw new Error(`上传 API 不存在 (404): ${i}\n请检查 neo.config.js 中的 neoBaseURL 配置是否正确,或者 API 路径是否存在。\n当前配置的 API 路径: ${this.NeoCrmAPI.uploadAPI}`)}else t.request&&T("请求已发送但未收到响应,请检查网络连接或代理配置。");throw t}}async publish2oss(e,t=[".js",".css",".zip"]){if(!e)return void T(`自定义组件名称不能为空: ${e}`);if(!y.existsSync(this.assetsRoot))return void T(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e},o=y.readdirSync(this.assetsRoot).map(async o=>{const i=g.join(this.assetsRoot,o),r=y.statSync(i),n=g.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=k.camelCase(e);if(o.indexOf(t)<0)return;try{const e=await this.uploadFile(i);o.indexOf("Model")>-1?s.modelAsset=e:o.endsWith(".css")?s.cssAsset=e:o.endsWith(".zip")?s.codeLib=e:s.asset=e}catch(e){T(`文件上传失败(${o}):\n`),process.exit(1)}}});return await Promise.all(o),s&&s.cmpType&&(console.info("上传至 OSS 的文件信息:\n",s),$(s)),s}async getCmpAssets(e,t=[".js",".css",".zip"]){if(!e)return void T(`自定义组件名称不能为空: ${e}`);if(!y.existsSync(this.assetsRoot))return void T(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e};return y.readdirSync(this.assetsRoot).forEach(o=>{const i=g.join(this.assetsRoot,o),r=y.statSync(i),n=g.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=k.camelCase(e);if(o.indexOf(t)<0)return;const n=5242880;if(r.size>n){const e=(r.size/1024/1024).toFixed(2),t=(n/1024/1024).toFixed(2);throw new Error(`${o} 文件大小超过限制: ${e}MB > ${t}MB`)}const a={fileContent:y.createReadStream(i),fileName:o,fileSize:r.size};o.indexOf("Model")>-1?s.modelAssetFile=a:o.endsWith(".css")?s.cssAssetFile=a:o.endsWith(".zip")?s.codeLibFile=a:s.assetFile=a}}),s}async updateCustomComponent(e){const t=await this.ensureValidToken();if(!e)throw new Error("componentData 不能为空");const s=w("正在保存自定义组件信息...").start();try{const o=this.saveAPI(),i=new f;e.assetFile&&i.append("assetFile",e.assetFile.fileContent,e.assetFile.fileName),e.modelAssetFile&&i.append("modelAssetFile",e.modelAssetFile.fileContent,e.modelAssetFile.fileName),e.cssAssetFile&&i.append("cssAssetFile",e.cssAssetFile.fileContent,e.cssAssetFile.fileName),e.codeLibFile&&i.append("codeLibFile",e.codeLibFile.fileContent,e.codeLibFile.fileName),i.append("component",JSON.stringify(k.omit(e,["assetFile","modelAssetFile","cssAssetFile","codeLibFile"])));const r=await m.post(o,i,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff",...i.getHeaders()},timeout:12e4,maxContentLength:1/0,maxBodyLength:1/0}),{code:n,message:a,msg:c}=r.data||{};n&&200!==n&&(T(`保存自定义组件信息失败: ${a||c||"未知错误"}`),process.exit(1)),s.clear(),s.stop()}catch(e){const t=e.message||e.msg;T(t?`保存自定义组件信息失败: ${t}`:`保存自定义组件信息失败: ${JSON.stringify(e)}`,s),process.exit(1)}}async getCustomCmpList(){const e=await this.ensureValidToken();try{let t=this.buildFullUrl(this.NeoCrmAPI.queryAll);t+=`&fields=${b.join(",")}`;const s=await m.get(t,{headers:{Authorization:`Bearer ${e}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:o,message:i,msg:r}=s.data||{};o&&200!==o&&(T(`获取自定义组件列表失败: ${i||r||"未知错误"}`),process.exit(1)),this.updateCustomCmpList(s.data.data||[])}catch(e){const t=e.message||e.msg;T(t?`获取自定义组件列表失败: ${t}`:`响应数据: ${JSON.stringify(e)}`),process.exit(1)}return this.cmpList||[]}getCodeLibByCmpType(e){return e?this.buildFullUrl(this.NeoCrmAPI.getCodeLibAPI(e)):null}async deleteCmp(e){const t=await this.ensureValidToken();e||(T("自定义组件名称不能为空。"),process.exit(1));let s=this.buildFullUrl(this.NeoCrmAPI.delete);s+=`/${e}`;const o=await m.delete(s,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:i,message:r,msg:n,errorInfo:a}=o.data||{};return i&&200!==i&&(a&&a.length>0?P(a,{title:"删除自定义组件失败",columns:["reason","instance"],headers:{reason:"原因",instance:"实例"},align:{reason:"center",instance:"center"},padding:2,showBorder:!0}):T(`删除自定义组件失败: ${r||n||"未知错误"}`),process.exit(1)),o.data}getCmpListByFramework(e){if(!e)return this.cmpList;const t=x(e);return this.cmpList.filter(e=>e.framework===t)}getCmpInfoByCmpType(e){return e&&this.cmpInfoMap[e]||null}updateCustomCmpList(e){e&&Array.isArray(e)&&(this.cmpList=e,e.forEach(e=>{this.cmpInfoMap[e.cmpType]=e}))}async request(e,t,s={}){const o=await this.ensureValidToken(),{data:i,headers:r={},params:n}=s,a=this.buildFullUrl(t);try{const t=await m({method:e,url:a,data:i,params:n,headers:{Authorization:`Bearer ${o}`,"xsy-inner-source":"bff",...r}});if(t.data&&t.data.code&&200!==t.data.code)throw new Error(`请求失败: ${t.data.message||t.data.msg||"未知错误"}`);return t.data}catch(s){throw T(`请求失败 [${e} ${t}]: ${s.message||s.msg}`),s.response&&T(`响应数据: ${JSON.stringify(s.response.data)}`),s}}async get(e,t={}){return await this.request("GET",e,t)}async post(e,t={}){return await this.request("POST",e,t)}async put(e,t={}){return await this.request("PUT",e,t)}async delete(e,t={}){return await this.request("DELETE",e,t)}}};
|
package/dist/package.json.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var e="1.10.
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var e="1.10.5";const o={version:e};exports.default=o,exports.version=e;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neo-cmp-cli",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.6",
|
|
4
4
|
"description": "Neo 自定义组件开发工具,支持react 和 vue2.0技术栈。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neo-cli",
|
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"bin/*",
|
|
21
21
|
"dist/*",
|
|
22
|
-
"template/*"
|
|
23
|
-
"test/*"
|
|
22
|
+
"template/*"
|
|
24
23
|
],
|
|
25
24
|
"husky": {
|
|
26
25
|
"hooks": {
|
|
@@ -43,7 +43,7 @@ export class NeoEntityGridModel {
|
|
|
43
43
|
*/
|
|
44
44
|
propsSchema = [
|
|
45
45
|
{
|
|
46
|
-
type: '
|
|
46
|
+
type: 'neo_select',
|
|
47
47
|
name: 'objectApiKey',
|
|
48
48
|
label: '实体API Key',
|
|
49
49
|
value: 'account',
|
|
@@ -58,7 +58,7 @@ export class NeoEntityGridModel {
|
|
|
58
58
|
],
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
|
-
type: '
|
|
61
|
+
type: 'neo_select',
|
|
62
62
|
name: 'selectionMode',
|
|
63
63
|
label: '选择模式',
|
|
64
64
|
value: 'multiple',
|
package/test/demo.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const {createCmpByTemplate, neoInitByCopy, previewCmp, linkDebug, pushCmp, deleteCmp } = require('../src/main');
|
|
2
|
-
// createCmpByTemplate('react_ts');
|
|
3
|
-
// neoInitByCopy('react-ts', 'test123');
|
|
4
|
-
|
|
5
|
-
// previewCmp('info-card');
|
|
6
|
-
|
|
7
|
-
// 本地调试
|
|
8
|
-
// linkDebug();
|
|
9
|
-
|
|
10
|
-
// 发布到 Neo 平台
|
|
11
|
-
pushCmp('entityForm__c')
|
|
12
|
-
|
|
13
|
-
// 删除自定义组件
|
|
14
|
-
// deleteCmp('entityForm__c')
|
|
15
|
-
|
|
16
|
-
// 拉取自定义组件
|
|
17
|
-
// pullCmp('entityForm__c')
|
|
18
|
-
|
|
19
|
-
// const entries = getEntriesWithAutoRegister('linkDebug');
|
|
20
|
-
// console.log(entries);
|
package/test/demo2.js
DELETED
package/test/demo3.js
DELETED
package/test/demo6.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 基于XMLHttpRequest的通用请求方法
|
|
3
|
-
* @param {string} url - 请求地址
|
|
4
|
-
* @param {object} options - 请求配置
|
|
5
|
-
* @param {string} [options.method='GET'] - 请求方法
|
|
6
|
-
* @param {object} [options.params={}] - URL查询参数(GET/DELETE)
|
|
7
|
-
* @param {object} [options.data={}] - 请求体数据(POST/PUT)
|
|
8
|
-
* @param {object} [options.headers={}] - 请求头
|
|
9
|
-
* @param {number} [options.timeout=5000] - 超时时间(毫秒)
|
|
10
|
-
* @returns {Promise} - 返回Promise对象
|
|
11
|
-
*/
|
|
12
|
-
function requestXHR(url, options) {
|
|
13
|
-
options = options || {};
|
|
14
|
-
var method = options.method || 'GET';
|
|
15
|
-
var data = options.data || {};
|
|
16
|
-
var headers = options.headers || {};
|
|
17
|
-
var timeout = options.timeout || 5000;
|
|
18
|
-
|
|
19
|
-
return new Promise(function(resolve, reject) {
|
|
20
|
-
// 1. 创建XHR对象
|
|
21
|
-
var xhr = new XMLHttpRequest();
|
|
22
|
-
|
|
23
|
-
// 2. 处理GET参数,拼接到URL
|
|
24
|
-
var queryParts = [];
|
|
25
|
-
var queryString = queryParts.join('&');
|
|
26
|
-
var fullUrl = queryString ? url + '?' + queryString : url;
|
|
27
|
-
|
|
28
|
-
// 3. 初始化请求
|
|
29
|
-
xhr.open(method.toUpperCase(), fullUrl, true);
|
|
30
|
-
|
|
31
|
-
// 4. 设置请求头
|
|
32
|
-
// 默认JSON请求头(POST/PUT)
|
|
33
|
-
var methodUpper = method.toUpperCase();
|
|
34
|
-
if (methodUpper === 'POST' || methodUpper === 'PUT') {
|
|
35
|
-
xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
|
|
36
|
-
}
|
|
37
|
-
// 自定义请求头
|
|
38
|
-
var headerKeys = Object.keys(headers);
|
|
39
|
-
for (var j = 0; j < headerKeys.length; j++) {
|
|
40
|
-
var headerKey = headerKeys[j];
|
|
41
|
-
var headerValue = headers[headerKey];
|
|
42
|
-
xhr.setRequestHeader(headerKey, headerValue);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 5. 设置超时
|
|
46
|
-
xhr.timeout = timeout;
|
|
47
|
-
|
|
48
|
-
// 6. 处理响应
|
|
49
|
-
xhr.onload = function () {
|
|
50
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
51
|
-
// 解析响应数据(优先JSON,其次文本)
|
|
52
|
-
var responseData;
|
|
53
|
-
try {
|
|
54
|
-
responseData = JSON.parse(xhr.responseText);
|
|
55
|
-
} catch (e) {
|
|
56
|
-
responseData = xhr.responseText;
|
|
57
|
-
}
|
|
58
|
-
resolve({
|
|
59
|
-
data: responseData,
|
|
60
|
-
status: xhr.status,
|
|
61
|
-
statusText: xhr.statusText
|
|
62
|
-
});
|
|
63
|
-
} else {
|
|
64
|
-
reject(new Error('请求失败:' + xhr.status + ' ' + xhr.statusText));
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// 7. 处理网络错误、超时
|
|
69
|
-
xhr.onerror = function () {
|
|
70
|
-
reject(new Error('网络错误,请检查网络连接'));
|
|
71
|
-
};
|
|
72
|
-
xhr.ontimeout = function () {
|
|
73
|
-
reject(new Error('请求超时(' + timeout + 'ms)'));
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// 8. 发送请求(POST/PUT需传请求体)
|
|
77
|
-
var methodUpperSend = method.toUpperCase();
|
|
78
|
-
if (methodUpperSend === 'POST' || methodUpperSend === 'PUT') {
|
|
79
|
-
xhr.send(JSON.stringify(data));
|
|
80
|
-
} else {
|
|
81
|
-
xhr.send(null);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// GET请求
|
|
87
|
-
requestXHR('https://jsonplaceholder.typicode.com/posts', {
|
|
88
|
-
timeout: 10000
|
|
89
|
-
})
|
|
90
|
-
.then(function(res) {
|
|
91
|
-
|
|
92
|
-
})
|
|
93
|
-
.catch(function(err) {
|
|
94
|
-
|
|
95
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const { execSync } = require('child_process');
|
|
2
|
-
|
|
3
|
-
// 所有需要废弃的版本
|
|
4
|
-
const versionsToDeprecate = ["1.9.12", "1.9.13", "1.9.15", "1.9.16", "1.9.17", "1.9.18", "1.9.19", "1.9.20", "1.9.21", "1.9.22"];
|
|
5
|
-
|
|
6
|
-
const packageName = 'neo-cmp-cli';
|
|
7
|
-
const deprecateMessage = '此版本为开发中版本(存在 bug),请升级到最新版本。';
|
|
8
|
-
|
|
9
|
-
console.log(`开始标记 ${versionsToDeprecate.length} 个版本为废弃状态...\n`);
|
|
10
|
-
|
|
11
|
-
let successCount = 0;
|
|
12
|
-
let failCount = 0;
|
|
13
|
-
|
|
14
|
-
versionsToDeprecate.forEach((version, index) => {
|
|
15
|
-
try {
|
|
16
|
-
const command = `npm deprecate ${packageName}@${version} "${deprecateMessage}"`;
|
|
17
|
-
console.log(`[${index + 1}/${versionsToDeprecate.length}] 正在标记 ${version}...`);
|
|
18
|
-
execSync(command, { stdio: 'inherit' });
|
|
19
|
-
successCount++;
|
|
20
|
-
console.log(`✓ ${version} 已成功标记\n`);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
failCount++;
|
|
23
|
-
console.error(`✗ ${version} 标记失败: ${error.message}\n`);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
console.log('\n========================================');
|
|
28
|
-
console.log(`完成!成功: ${successCount}, 失败: ${failCount}`);
|
|
29
|
-
console.log('========================================');
|
|
30
|
-
|
package/test/neo.config.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
// 统一路径解析
|
|
5
|
-
function resolve(dir) {
|
|
6
|
-
return path.resolve(__dirname, dir);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// 包括生产和开发的环境配置信息
|
|
10
|
-
module.exports = {
|
|
11
|
-
settings: {
|
|
12
|
-
enableESLint: false, // 调试模式是否开启ESLint,默认开启ESLint检测代码格式
|
|
13
|
-
enableESLintFix: false, // 是否自动修正代码格式,默认不自动修正
|
|
14
|
-
enableStyleLint: false, // 是否开启StyleLint,默认开启ESLint检测代码格式
|
|
15
|
-
enableStyleLintFix: false, // 是否需要StyleLint自动修正代码格式
|
|
16
|
-
},
|
|
17
|
-
webpack: {
|
|
18
|
-
target: ['web', 'es5'], // 指定目标环境为 web 和 es5,确保兼容性
|
|
19
|
-
resolve: {
|
|
20
|
-
// webpack的resolve配置
|
|
21
|
-
extensions: ['.js', '.jsx', '.ts', '.tsx', '.umd.js', '.min.js', '.json'], // 用于配置webpack在尝试过程中用到的后缀列表
|
|
22
|
-
alias: {
|
|
23
|
-
'@': resolve('src'),
|
|
24
|
-
$assets: resolve('src/assets'),
|
|
25
|
-
$public: resolve('public'),
|
|
26
|
-
$utils: resolve('src/utils'),
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
// createDeclaration: true, // 打包时是否创建ts声明文件
|
|
30
|
-
ignoreNodeModules: false, // 打包时是否忽略 node_modules
|
|
31
|
-
// allowList: [], // ignoreNodeModules为true时生效
|
|
32
|
-
projectDir: ['../template/neo-custom-cmp-template/src'],
|
|
33
|
-
// template: resolve('./public/template.html'), // 自定义html模板
|
|
34
|
-
// plugins: [],
|
|
35
|
-
// babelPlugins: [],
|
|
36
|
-
},
|
|
37
|
-
// 用于添加 Neo 共享依赖模块的配置信息
|
|
38
|
-
/*
|
|
39
|
-
neoCommonModule: {
|
|
40
|
-
// exports: ['xxModule'], // 数组写法,用于导出当前自定义组件中的第三方依赖模块
|
|
41
|
-
exports: { // 对象写法,可用于导出自定义组件中的某个内容模块(需要使用绝对路径导出)
|
|
42
|
-
'xxModule': path.resolve('./src/components/xxModule'), // 导出 xx组件 或 xx模块
|
|
43
|
-
},
|
|
44
|
-
// remoteDeps: ['xxCmpType'], // 远程依赖组件,表示当前自定义组件会用到的依赖组件,需要和 externals 配合使用
|
|
45
|
-
// externals: ['xxModule'], // 自定义组件中需要剔除的模块,仅支持数组写法
|
|
46
|
-
},
|
|
47
|
-
*/
|
|
48
|
-
componentsDir: resolve('../template/neo-custom-cmp-template/src/components'), // 自定义组件根目录
|
|
49
|
-
preview: {
|
|
50
|
-
// 用于开启本地预览模式的相关配置信息
|
|
51
|
-
/*
|
|
52
|
-
【特别说明】以下配置项都自带默认值,非必填。如需自定义请自行配置。
|
|
53
|
-
entry: { // 根据 src/components 目录下的文件自动生成 entry 相关配置
|
|
54
|
-
// 本地预览自定义组件内容
|
|
55
|
-
index: './src/preview.jsx',
|
|
56
|
-
},
|
|
57
|
-
NODE_ENV: 'development',
|
|
58
|
-
port: 80, // 设置基础端口,如果被占用则自动寻找可用端口
|
|
59
|
-
assetsPublicPath: '/', // 设置静态资源的引用路径(根域名+路径)
|
|
60
|
-
assetsSubDirectory: '',
|
|
61
|
-
hostname: 'localhost',
|
|
62
|
-
proxyTable: {
|
|
63
|
-
'/apiTest': {
|
|
64
|
-
target: 'http://api-test.com.cn', // 不支持跨域的接口根地址
|
|
65
|
-
ws: true,
|
|
66
|
-
changeOrigin: true,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
*/
|
|
70
|
-
},
|
|
71
|
-
linkDebug: {
|
|
72
|
-
// 用于开启本地调试模式的相关配置信息
|
|
73
|
-
/*
|
|
74
|
-
【特别说明】以下配置项都自带默认值,非必填。如需自定义请自行配置。
|
|
75
|
-
entry: { // 根据 src/components 目录下的文件自动生成 entry 相关配置
|
|
76
|
-
// 外链调试(在线上页面设计器端预览自定义组件)
|
|
77
|
-
index: [
|
|
78
|
-
'./src/components/xxCmp/register.ts',
|
|
79
|
-
'./src/components/xxCmp/model.ts',
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
NODE_ENV: 'development',
|
|
83
|
-
port: 80, // 设置基础端口,如果被占用则自动寻找可用端口
|
|
84
|
-
closeHotReload: true, // 是否关闭热更新
|
|
85
|
-
assetsPublicPath: '/', // 设置静态资源的引用路径(根域名+路径)
|
|
86
|
-
assetsSubDirectory: '',
|
|
87
|
-
hostname: 'localhost',
|
|
88
|
-
proxyTable: {
|
|
89
|
-
'/apiTest': {
|
|
90
|
-
target: 'http://api-test.com.cn', // 不支持跨域的接口根地址
|
|
91
|
-
ws: true,
|
|
92
|
-
changeOrigin: true,
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
*/
|
|
96
|
-
},
|
|
97
|
-
// 选择「自定义环境」时需要添加 NeoCRM 平台配置,可自定义对接的任何环境
|
|
98
|
-
neoConfig: {
|
|
99
|
-
// authType: 'oauth2', // 默认授权模式:OAuth2 授权码模式
|
|
100
|
-
neoBaseURL: 'https://crm-test.xiaoshouyi.com', // 平台根地址(默认:https://crm.xiaoshouyi.com)
|
|
101
|
-
loginURL: 'https://login-test.xiaoshouyi.com/auc/oauth2/auth', // 登录授权 URL(默认:https://login.xiaoshouyi.com/auc/oauth2/auth)
|
|
102
|
-
tokenURL: 'https://login-test.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址(默认:https://login.xiaoshouyi.com/auc/oauth2/token)
|
|
103
|
-
},
|
|
104
|
-
pushCmp: {
|
|
105
|
-
// 用于构建并发布至 NeoCRM 的相关配置
|
|
106
|
-
/*
|
|
107
|
-
【特别说明】以下配置项都自带默认值,非必填。如需自定义请自行配置。
|
|
108
|
-
NODE_ENV: 'production',
|
|
109
|
-
entry: { // 根据 src/components 目录下的文件自动生成 entry 相关配置
|
|
110
|
-
InfoCardModel: './src/components/xxCmp/model.ts',
|
|
111
|
-
infoCard: './src/components/xxCmp/register.ts'
|
|
112
|
-
},
|
|
113
|
-
cssExtract: false, // 不额外提取css文件
|
|
114
|
-
assetsRoot: resolve('dist') // 上传指定目录下的脚本文件
|
|
115
|
-
*/
|
|
116
|
-
},
|
|
117
|
-
};
|
package/test/package.json
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "neo-custom-cmp-template",
|
|
3
|
-
"version": "1.1.10",
|
|
4
|
-
"description": "neo自定义组件模板(react&ts技术栈)",
|
|
5
|
-
"framework": "react-ts",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"自定义组件模板",
|
|
8
|
-
"react&ts技术栈",
|
|
9
|
-
"neo自定义组件"
|
|
10
|
-
],
|
|
11
|
-
"author": "wibetter",
|
|
12
|
-
"license": "MIT",
|
|
13
|
-
"scripts": {
|
|
14
|
-
"preview": "neo preview",
|
|
15
|
-
"linkDebug": "neo linkDebug",
|
|
16
|
-
"neoLogin": "neo login",
|
|
17
|
-
"pushCmp": "neo push cmp",
|
|
18
|
-
"pullCmp": "neo pull cmp",
|
|
19
|
-
"deleteCmp": "neo delete cmp",
|
|
20
|
-
"format": "prettier --write \"src/**/**/*.{js,jsx,ts,tsx,vue,scss,json}\""
|
|
21
|
-
},
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"neo-register": "^1.1.3",
|
|
24
|
-
"react": "^16.9.0",
|
|
25
|
-
"react-dom": "^16.9.0",
|
|
26
|
-
"axios": "^0.27.2",
|
|
27
|
-
"antd": "^4.9.4",
|
|
28
|
-
"lodash": "^4.17.21",
|
|
29
|
-
"neo-open-api": "^1.1.9"
|
|
30
|
-
},
|
|
31
|
-
"devDependencies": {
|
|
32
|
-
"@commitlint/cli": "^8.3.5",
|
|
33
|
-
"@commitlint/config-conventional": "^9.1.1",
|
|
34
|
-
"@types/react": "^16.9.11",
|
|
35
|
-
"@types/react-dom": "^16.9.15",
|
|
36
|
-
"@types/axios": "^0.14.0",
|
|
37
|
-
"neo-cmp-cli": "^1.9.28",
|
|
38
|
-
"husky": "^4.2.5",
|
|
39
|
-
"lint-staged": "^10.2.9",
|
|
40
|
-
"prettier": "^2.0.5"
|
|
41
|
-
},
|
|
42
|
-
"engines": {
|
|
43
|
-
"node": ">= 16.0.0",
|
|
44
|
-
"npm": ">= 8.0.0"
|
|
45
|
-
}
|
|
46
|
-
}
|