feat: add builder configuration file

feat: add cocos-service configuration file
feat: add device configuration file
feat: add engine configuration file
feat: add information configuration file
feat: add program configuration file
feat: add project configuration file
feat: add TypeScript configuration file
This commit is contained in:
ZhouXiao
2025-12-22 11:42:51 +08:00
parent 66cfa73345
commit 487c68994d
202 changed files with 57615 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 McvCar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,2 @@
# quickCompressImage
这是cocos creator 快速压缩图片插件

View File

@@ -0,0 +1,9 @@
module.exports = {
/**
* menu
*/
'name': 'x',
'compressPicture': 'Compress Picture',
'menu': 'Compress Picture',
'setting': 'Setting',
};

View File

@@ -0,0 +1,9 @@
module.exports = {
/**
* 菜单
*/
'name': 'x',
'compressPicture': '压缩图片',
'menu': '快闪·压缩图片',
'setting': '设置',
};

View File

@@ -0,0 +1,50 @@
{
"name": "mozjpeg",
"version": "8.0.0",
"description": "mozjpeg wrapper that makes it seamlessly available as a local dependency",
"license": "MIT",
"repository": "imagemin/mozjpeg-bin",
"type": "module",
"exports": "./index.js",
"bin": "cli.js",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"postinstall": "node lib/install.js",
"test": "xo && ava --timeout=120s",
"build-linux": "docker build --tag imagemin/mozjpeg docker && docker run --rm --volume $(pwd)/vendor/linux:/src/out imagemin/mozjpeg cp cjpeg /src/out"
},
"files": [
"index.js",
"cli.js",
"lib",
"vendor/source"
],
"keywords": [
"imagemin",
"jpeg",
"jpg",
"img",
"image",
"compress",
"minify",
"mozjpeg",
"optimize"
],
"dependencies": {
"bin-build": "^3.0.0",
"bin-wrapper": "^4.0.0"
},
"devDependencies": {
"ava": "^3.8.0",
"bin-check": "^4.1.0",
"compare-size": "^3.0.0",
"execa": "^5.1.1",
"tempy": "^2.0.0",
"xo": "^0.45.0"
},
"ava": {
"serial": true
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
/*!
* fill-range <https://github.com/jonschlinkert/fill-range>
*
* Copyright (c) 2014-present, Jon Schlinkert.
* Licensed under the MIT License.
*/
/*!
* is-extglob <https://github.com/jonschlinkert/is-extglob>
*
* Copyright (c) 2014-2016, Jon Schlinkert.
* Licensed under the MIT License.
*/
/*!
* is-glob <https://github.com/jonschlinkert/is-glob>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/
/*!
* is-number <https://github.com/jonschlinkert/is-number>
*
* Copyright (c) 2014-present, Jon Schlinkert.
* Released under the MIT License.
*/
/*!
* to-regex-range <https://github.com/micromatch/to-regex-range>
*
* Copyright (c) 2015-present, Jon Schlinkert.
* Released under the MIT License.
*/
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */

View File

@@ -0,0 +1,77 @@
let Path = require('path')
let Fs = require('fs');
let imageminApi = require('../lib/imagemin.min')
let packageCfg = require('../package.json')
module.exports = {
async getZipRate(){
let rate = parseInt(await Editor.Profile.getConfig(packageCfg.name,'zipRate')) || 30;
if(rate<0){
rate = 1;
}else if(rate>100){
rate = 100
}
return rate;
},
/**
* 调用压缩工具api
* @param {Array<{file:string,uuid:string}>} fileInfo
*/
async compressPicture(arrList,imageFileList){
let rate = await this.getZipRate();
let pngRate = rate*0.01;
console.log("压缩值:",rate+"%");
imageminApi.imagemin(arrList, {
plugins: [
imageminApi.imageminMozjpeg({ quality: rate }), //压缩质量0,1
imageminApi.imageminPngquant({
quality: [pngRate, Math.min(pngRate+0.25,1)] //压缩质量0,1
})
]
}).then((arrRes) => {
console.log("压缩成功,详情:\n")
for (let i = 0; i < arrRes.length; i++) {
const res = arrRes[i];
this.onCompressedSucceed(imageFileList,res)
}
}).catch(err => {
console.log("压缩失败:",err)
});
},
/**
* 压缩成功
* @param {Array<{file:string,uuid:string,size:number}>} imageFileList
* @param {Object<{data:Buffer,sourcePath:string}>} res
*/
onCompressedSucceed(imageFileList,res){
let desc = ""
for (let i = 0; i < imageFileList.length; i++) {
const fileInfo = imageFileList[i];
if(fileInfo.file.replace(/\\/g,'/') == res.sourcePath){
const fileName = Path.basename(fileInfo.file);
const newSize = res.data.byteLength;
const rate = (fileInfo.size-newSize)/fileInfo.size;
const oldMb = (fileInfo.size / 1024).toFixed(1) + " KB";
const newMb = (newSize / 1024).toFixed(1) + " KB";
if(newSize < fileInfo.size){
Fs.writeFileSync(res.sourcePath, res.data)
desc += `${fileName}、压缩率:${parseInt(rate*100)}%、压缩前后大小:${newMb} / ${oldMb}`
}else{
desc += `${fileName}、无法继续压缩`
}
break;
}
}
console.log(desc);
},
}

View File

@@ -0,0 +1,89 @@
const fs = require("fs");
const path = require("path");
const https = require("https");
const URL = require("url").URL;
const EventEmitter = require("events");
const err = (msg) => new EventEmitter().emit("error", msg);
/**
* TinyPng 远程压缩 HTTPS 请求的配置生成方法
*/
function getAjaxOptions() {
return {
method: "POST",
hostname: "tinypng.com",
path: "/web/shrink",
headers: {
rejectUnauthorized: false,
"X-Forwarded-For": Array(4)
.fill(1)
.map(() => parseInt(Math.random() * 254 + 1))
.join("."),
"Postman-Token": Date.now(),
"Cache-Control": "no-cache",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent":
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
}
};
}
/**
* TinyPng 远程压缩 HTTPS 请求
* @param {string} img 待处理的文件
* @success {
* "input": { "size": 887, "type": "image/png" },
* "output": { "size": 785, "type": "image/png", "width": 81, "height": 81, "ratio": 0.885, "url": "https://tinypng.com/web/output/7aztz90nq5p9545zch8gjzqg5ubdatd6" }
* }
* @error {"error": "Bad request", "message" : "Request is invalid"}
*/
function fileUpload(imgPath) {
let req = https.request(getAjaxOptions(), (res) => {
res.on("data", (buf) => {
let obj = JSON.parse(buf.toString());
if (obj.error)
console.log(`压缩失败!\n 当前文件:${imgPath} \n ${obj.message}`);
else fileUpdate(imgPath, obj);
});
});
req.write(fs.readFileSync(imgPath), "binary");
req.on("error", (e) =>
console.log(`请求错误! 当前文件:${path.basename(imgPath)} \n`, e)
);
req.end();
}
// 该方法被循环调用,请求图片数据
function fileUpdate(entryImgPath, obj) {
let options = new URL(obj.output.url);
let req = https.request(options, (res) => {
let body = "";
res.setEncoding("binary");
res.on("data", (data) => (body += data));
res.on("end", () => {
fs.writeFile(entryImgPath, body, "binary", (err) => {
if (err) return console.error(err);
let log = `压缩成功:`;
log += `${path.basename(entryImgPath)}、压缩率:${ ((1 - obj.output.ratio) * 100).toFixed(2) }%、压缩前后大小:${(obj.output.size / 1024).toFixed(2)} / ${(obj.input.size / 1024).toFixed(2)}`
console.log(log);
});
});
});
req.on("error", (e) => console.warn('压缩失败:',path.basename(entryImgPath) ,e));
req.end();
}
module.exports = {
/**
* 调用压缩工具api
* @param {Array<{file:string,uuid:string}>} fileInfo
*/
async compressPicture(arrList,imageFileList){
for (let i = 0; i < arrList.length; i++) {
const imgPath = arrList[i];
fileUpload(imgPath);
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
{
"name": "quick-compress-image",
"package_version": 2,
"version": "1.0.1",
"description": "Compress a picture",
"author": "嘉年华",
"main": "./src/browser.js",
"contributions": {
"menu": [{
"path": "i18n:menu.extension/i18n:quick-compress-image.menu",
"label": "i18n:quick-compress-image.setting",
"message": "setting"
}],
"messages": {
"setting": {
"methods": ["setting"]
}
},
"assets": {
"menu": {
"methods": "./src/assets-menu.js",
"createMenu": "onCreateMenu",
"assetMenu": "onAssetMenu"
}
},
"profile": {
"editor": {
"zipRate": {
"default": 70,
"label": "压缩值(0-100%)"
},
"zipMode":{
"default": 0,
"label": "压缩模式"
}
}
},
"preferences": {
"label" : "图片压缩",
"properties": {
"zipRate": {
"ui": "ui-num-input"
},
"zipMode": {
"ui": "ui-select",
"items": [
{
"value": 0,
"label": "Imagemin"
},
{
"value": 1,
"label": "Tinypng"
}
]
}
}
}
},
"panels": {
"default": {
"title": "快闪·压缩图片",
"type": "dockable",
"main": "src/setting-panel",
"size": {
"width": 280,
"height": 260
}
}
},
"dependencies": {
},
"devDependencies": {
}
}

View File

@@ -0,0 +1,113 @@
let Path = require('path')
let Fs = require('fs');
let imageminApi = require('../lib/imageminApi')
let tinypngApi = require('../lib/tinypngApi')
let statistical = require('./tools/statistical')
let packageCfg = require('../package.json');
const tools = require('./tools/tools');
let AssetsMenu = {
onAssetMenu(assetInfo) {
if(assetInfo.importer != 'image'){
return [];
}
return [
{
label: 'i18n:quick-compress-image.compressPicture',
enabled: true,
click() {
if(confirm('确定压缩图片?')){
AssetsMenu.onStartCompressPicture(assetInfo)
}
},
},
];
},
onCreateMenu(assetInfo) {
statistical.countStartupTimes();
return [];
},
isImageFile(filePath){
let extname = Path.extname(filePath).toLocaleLowerCase()
if(extname == '.png' || extname == '.jpg' || extname == '.jpeg'){
return true;
}
return false;
},
getFileSize(fsPath){
try {
return Fs.statSync(fsPath).size
} catch (error) {
return -1
}
},
/**
* 返回选中的图片
* @param {*} assetInfo
* @returns {Promise<Array<{file:string,uuid:string,size:number}>>}
*/
async getImageFileList(assetInfo){
let fileUuidList = Editor.Selection.getSelected('asset');
let imageFileList = [];
if(fileUuidList.includes(assetInfo.uuid)){
for (let i = 0; i < fileUuidList.length; i++) {
const uuid = fileUuidList[i];
const fsPath = await Editor.Message.request("asset-db",'query-path',uuid);
if(fsPath && this.isImageFile(fsPath)){
imageFileList.push({
file: fsPath,
uuid: uuid,
size: this.getFileSize(fsPath)
})
}
}
}else{
if(assetInfo.file && this.isImageFile(assetInfo.file)){
imageFileList.push({
file: assetInfo.file,
uuid: assetInfo.uuid,
})
}
}
return imageFileList;
},
async getMode(){
let mode = tools.isX64() ? await Editor.Profile.getConfig(packageCfg.name,'zipMode') || 0 : 1;
return mode;
},
async onStartCompressPicture(assetInfo){
let imageFileList = await this.getImageFileList(assetInfo);
if(imageFileList.length == 0){
return console.log("不支持该图片格式的压缩")
}
let arrList = [];
for (let i = 0; i < imageFileList.length; i++) {
const fileInfo = imageFileList[i];
arrList.push(fileInfo.file);
}
let mode = await this.getMode();
if(mode == 0){
console.log("---------------------压缩模式:Imagemin---------------------------");
imageminApi.compressPicture(arrList,imageFileList);
}else{
console.log("---------------------压缩模式:TinyPng---------------------------");
tinypngApi.compressPicture(arrList,imageFileList);
}
},
}
module.exports = AssetsMenu;

View File

@@ -0,0 +1,15 @@
"use strict";
exports.methods={
'setting'(){
Editor.Panel.open('quick-compress-image')
}
}
exports.load=function(){
}
exports.unload=function(){
};

View File

@@ -0,0 +1,58 @@
let fs = require('fs')
let path = require('path')
let packageCfg = require('../package.json')
const tools = require('./tools/tools')
Editor.Panel.define = Editor.Panel.define || ((args)=>{return args})
function saveConfig(doms){
Editor.Profile.setConfig(packageCfg.name,'zipRate',doms.zipRateSlider.value);
Editor.Profile.setConfig(packageCfg.name,'zipMode',doms.zipModeTab.value);
}
async function getMode(){
let mode = tools.isX64() ? await Editor.Profile.getConfig(packageCfg.name,'zipMode') || 0 : 1;
return mode;
}
module.exports = Editor.Panel.define({
template: fs.readFileSync(path.join(__dirname, '../template/setting.html'), 'utf-8'),
style: fs.readFileSync(path.join(__dirname, '../template/setting.css'), 'utf-8'),
$: {
zipRateSlider: '#zipRateSlider',
saveBtn: '#saveBtn',
zipModeTab: '#zipModeTab',
},
async ready() {
this.$.zipRateSlider.value = parseInt(await Editor.Profile.getConfig(packageCfg.name,'zipRate')) || 30;
this.$.zipModeTab.value = await getMode();
this.$.zipModeTab.value == 1 ? this.$.zipRateSlider.disabled = true : this.$.zipRateSlider.removeAttribute('disabled');
this.$.zipModeTab.addEventListener('click',()=>{
let mode = this.$.zipModeTab.value;
if(!tools.isX64() && mode == 0){
this.$.zipModeTab.value = 1;
this.$.zipRateSlider.disabled = true
alert('CPU不支持该模式');
}else{
this.$.zipModeTab.value == 1 ? this.$.zipRateSlider.disabled = true : this.$.zipRateSlider.removeAttribute('disabled');
saveConfig(this.$);
}
},0)
this.$.saveBtn.addEventListener('click',()=>{
saveConfig(this.$);
},0)
},
listeners: {
},
methods: {
},
beforeClose() { },
close() {
saveConfig(this.$);
},
});

View File

@@ -0,0 +1,20 @@
const tools = require("./tools")
let isStatistical = false;
module.exports = {
// 用户使用次数统计
countStartupTimes(){
if(!isStatistical && Editor.User && Editor.User.getData){
Editor.User.getData().then((post_data)=>{
if(!post_data) {
return
}
post_data.version = Editor.App ? Editor.App.version : "?";
tools.httpPost('120.77.174.207','/compressImageLogincount',8081,post_data);
});
isStatistical = true;
}
},
}

View File

@@ -0,0 +1,560 @@
let fs = require("fs");
let path = require("path");
let packageCfg = require("../../package.json")
var http = require('http');
var querystring = require('querystring');
var os = require('os');
const inputType = { "text": 1, "password": 1, "number": 1, "date": 1, "color": 1, "range": 1, "month": 1, "week": 1, "time": 1, "email": 1, "search": 1, "url": 1, "textarea": 1 }
let checkFsPath = new RegExp("\\.\\./", "g");
let readFileQueue = []
let readFileMaxCount = 50
let readFileCount = 0
let translateMap = {}
module.exports = {
isX64(){
return os.arch() == 'x64'
},
// 不是输入状态是时
inputTypeChk(e) {
if (e.path[0]) {
let type = e.path[0].type;
if (inputType[type]) {
return true
}
}
},
getLanguage(){
return window.navigator && window.navigator.language && window.navigator.language.split('-')[0];
},
// 更新i18翻译文本解决creator不重启不会刷新修改问题
initI18t(){
let locale = this.getLanguage() || 'zh';
let filePath = Editor2D.url('packages://simple-code/i18n/'+locale+'.js');
if(!this.isFileExit(filePath)){
return
}
let mapList = require(filePath);
let converList = {}
for (const key in mapList) {
const converText = mapList[key];
converList[packageCfg.name+'.'+key] = converText
}
translateMap = converList;
// Editor.i18n.extend(converList)
},
translate(key){
let name = packageCfg.name+'.'+key
return translateMap[name] || Editor2D.T(name) || name
},
translateZhAndEn(zeText,enText){
return this.getLanguage() == 'zh' ? zeText : enText;
},
// 翻译中英文
T(zeText,enText){
return this.translateZhAndEn(zeText,enText);
},
isEmptyObject(obj){
if(obj){
for (const key in obj) {
return false
}
}
return true;
},
// 拷贝本对象方法到目标对象
// newObj 子类
// baseObj 父类
// mergeFuncs = ["init"]; 新旧类的同名函数合并一起
extendTo(newObj, baseObj, mergeFuncs = []) {
if (!baseObj || !newObj) return;
for (let k in baseObj) {
let v = baseObj[k]
if (newObj[k] == null) {
newObj[k] = v
}
// 函数继承使用 "this._super()" 调用父类
else if (typeof v == "function" && typeof newObj[k] == "function" && !newObj[k]._isExend) {
let newFunc = newObj[k];
newObj[k] = function () {
this._super = v;
let ret = newFunc.apply(this, arguments);// 执行函数并传入传参
delete this._super;
return ret;
};
newObj[k]._isExend = true
}
}
},
copyToClipboard(str) {
var input = str;
const el = document.createElement('textarea');
el.value = input;
el.setAttribute('readonly', '');
el.style.contain = 'strict';
el.style.position = 'absolute';
el.style.left = '-9999px';
el.style.fontSize = '12pt'; // Prevent zooming on iOS
const selection = getSelection();
var originalRange = false;
if (selection.rangeCount > 0) {
originalRange = selection.getRangeAt(0);
}
document.body.appendChild(el);
el.select();
el.selectionStart = 0;
el.selectionEnd = input.length;
var success = false;
try {
success = document.execCommand('copy');
} catch (err) { }
document.body.removeChild(el);
if (originalRange) {
selection.removeAllRanges();
selection.addRange(originalRange);
}
return success;
},
parseJson(text){
try {
return JSON.parse(text)
} catch (error) {
return undefined;
}
},
objectCount(obj){
let len = 0
for (const key in obj) {
len++
}
return len;
},
// 获得import路径
getImportStringPaths(codeText) {
var regEx = /(require\(|import |reference path=)(.{0,}['"])(.+)['"]/g;
var match = regEx.exec(codeText);
var imports = []
while (match) {
let start = match.index + match[1].length + match[2].length;
imports.push({
path: match[3],
start: start,
length: match[3].length,
})
match = regEx.exec(codeText);
}
return imports
},
//将相对路径转为绝对路径
relativePathTofsPath(absolutePath, relativePath) {
var uplayCount = 0; // 相对路径中返回上层的次数。
var m = relativePath.match(checkFsPath);
if (m) uplayCount = m.length;
var lastIndex = absolutePath.length - 1;
var subString = absolutePath
for (var i = 0; i <= uplayCount; i++) {
lastIndex = subString.lastIndexOf("/", lastIndex);
subString = subString.substr(0, lastIndex)
}
return this.normPath( subString + "/" + relativePath.substr(relativePath.lastIndexOf('./') + 2));
},
//将绝对路径转为相对路径
fsPathToRelativePath(currPath, importPath) {
let s_i = currPath.lastIndexOf('/')
if (s_i != -1) currPath = currPath.substr(0, s_i);
let relativePath = path.relative(currPath, importPath);
if (relativePath[0] != '.') {
relativePath = './' + relativePath;
}
return this.normPath(relativePath);
},
//转换相对路径
converRelative(relativePath, oldFilePath, newFilePath) {
let s_i = oldFilePath.lastIndexOf('/')
if (s_i != -1) oldFilePath = oldFilePath.substr(0, s_i);
s_i = newFilePath.lastIndexOf('/')
if (s_i != -1) newFilePath = newFilePath.substr(0, s_i);
let rve_to_abs = this.normPath(path.resolve(oldFilePath, relativePath));
relativePath = this.normPath(path.relative(newFilePath, rve_to_abs));
if (relativePath[0] != '.') {
relativePath = './' + relativePath;
}
return relativePath;
},
normPath(filePath) {
return filePath.replace(/\\/g, '/');
},
// 异步读取文件
readFileAsyn(filePath,callback)
{
let args = {filePath,callback};
readFileQueue.push(args)
// 最多同时读取50个文件
readFileCount++;
if(readFileCount >= readFileMaxCount){
// console.log("readFileAsyn:读取超出最大文件数量",readFileCount);
return;
}
this._handleReadFileQueue()
},
// 处理 readFileAsyn 队列
_handleReadFileQueue(){
// 1 == Math.min(50,1)
let len = Math.min( readFileMaxCount , readFileQueue.length );
for (let i = 0; i < len; i++) {
// 处理队列
let args = readFileQueue.splice(0,1)[0];
fs.readFile(args.filePath,(err,data)=>
{
readFileCount--
if(readFileCount > 500){
setTimeout(this._handleReadFileQueue.bind(this),100)
}else{
this._handleReadFileQueue()
}
try {
args.callback(err,data);
} catch (error) {
console.log(error)
}
})
}
},
copyFile(sourcePath, toPath) {
fs.writeFileSync(toPath, fs.readFileSync(sourcePath))
},
// copyFile(sourcePath,toPath){
// fs.readFile(sourcePath,function(err,data){
// if(err) throw new Error('复制失败:'+sourcePath+" TO "+data);
// fs.writeFile(toPath,data,function(err){
// if(err) throw new Error('复制写入失败'+sourcePath+" TO "+data);
// })
// })
// },
moveDir(sourcePath, toPath) {
if (!fs.existsSync(sourcePath)) {
console.log("不存在目录:", sourcePath);
return;
}
if (sourcePath[sourcePath.length - 1] != path.sep) {
sourcePath += path.sep;// 加猴嘴
}
if (toPath[toPath.length - 1] != path.sep) {
toPath += path.sep;// 加猴嘴
}
let list = this.getDirAllFiles(sourcePath, []);
list.forEach((fileName, i) => {
let toFilePath = fileName.replace(sourcePath, toPath);
console.log("执行:", fileName, toFilePath);
let dirName = path.dirname(toFilePath);
this.createDir(dirName);
// 移动文件
fs.renameSync(fileName, toFilePath);
})
},
createDir(dirPath) {
if (fs.existsSync(dirPath)) return;
let paths = dirPath.split(path.sep);//分割路径
let path_ = "";
// c:\
let n = 0
let max = paths.length
if (paths[0].indexOf(":") != -1) {
path_ = paths[0];
n++;
}
if (paths[max - 1].indexOf(".") != -1) {
max--;
}
for (n; n < max; n++) {
path_ += path.sep + paths[n];
if (!fs.existsSync(path_)) {
fs.mkdirSync(path_);
}
}
},
// 获得文件夹列表
getDirList(dirPath, result) {
let files = fs.readdirSync(dirPath);
files.forEach((val, index) => {
let fPath = path.join(dirPath, val);
if (fs.existsSync(fPath) && fs.statSync(fPath).isDirectory()) {
result.push(fPath);
}
});
return result;
},
// 获得文件列表
getFileList(dirPath, result = []) {
let files = fs.readdirSync(dirPath);
files.forEach((val, index) => {
let fPath = path.join(dirPath, val);
if (fs.existsSync(fPath) && fs.statSync(fPath).isFile()) {
result.push(fPath);
}
});
return result;
},
isDirectory(fPath) {
return fs.existsSync(fPath) && fs.statSync(fPath).isDirectory()
},
getDirAllFiles(dirPath, result = []) {
let files = fs.readdirSync(dirPath);
files.forEach((val, index) => {
let fPath = path.join(dirPath, val);
if (fs.existsSync(fPath) && fs.statSync(fPath).isDirectory()) {
this.getDirAllFiles(fPath, result);
} else if (fs.statSync(fPath).isFile()) {
result.push(fPath);
}
});
return result;
},
getFileString(fileList, options) {
let curIndex = 0;
let totalIndex = fileList.length;
let str = {};
for (let key in fileList) {
let filePath = fileList[key];
let b = this._isFileExit(filePath);
if (b) {
fs.readFile(filePath, 'utf-8', function (err, data) {
if (!err) {
self._collectString(data, str);
} else {
console.log("error: " + filePath);
}
self._onCollectStep(filePath, ++curIndex, totalIndex, str, options);
})
} else {
self._onCollectStep(filePath, ++curIndex, totalIndex, str, options);
}
}
},
_onCollectStep(filePath, cur, total, str, data) {
if (data && data.stepCb) {
data.stepCb(filePath, cur, total);
}
if (cur >= total) {
self._onCollectOver(str, data);
}
},
_onCollectOver(collectObjArr, data) {
let strArr = [];
let str = "";
for (let k in collectObjArr) {
str += k;
strArr.push(k);
}
// console.log("一共有" + strArr.length + "个字符, " + strArr);
console.log("一共有" + strArr.length + "个字符");
if (data && data.compCb) {
data.compCb(str);
}
},
mkDir(path) {
try {
fs.mkdirSync(path);
} catch (e) {
if (e.code !== 'EEXIST') throw e;
}
},
isFileExit(file) {
try {
fs.accessSync(file, fs.F_OK);
} catch (e) {
return false;
}
return true;
},
async isFileExitAsync(file) {
return new Promise((resolev)=>{
fs.access(file,(err)=>{
resolev(err == null);
});
});
},
_collectString(data, collectObject) {
for (let i in data) {
let char = data.charAt(i);
if (collectObject[char]) {
collectObject[char]++;
} else {
collectObject[char] = 1;
}
}
},
emptyDir(rootFile) {
//删除所有的文件(将所有文件夹置空)
let emptyDir = function (fileUrl) {
let files = fs.readdirSync(fileUrl);//读取该文件夹
for (let k in files) {
let filePath = path.join(fileUrl, files[k]);
let stats = fs.statSync(filePath);
if (stats.isDirectory()) {
emptyDir(filePath);
} else {
fs.unlinkSync(filePath);
console.log("删除文件:" + filePath);
}
}
};
//删除所有的空文件夹
let rmEmptyDir = function (fileUrl) {
let files = fs.readdirSync(fileUrl);
if (files.length > 0) {
for (let k in files) {
let rmDir = path.join(fileUrl, files[k]);
rmEmptyDir(rmDir);
}
if (fileUrl !== rootFile) {// 不删除根目录
fs.rmdirSync(fileUrl);
console.log('删除空文件夹' + fileUrl);
}
} else {
if (fileUrl !== rootFile) {// 不删除根目录
fs.rmdirSync(fileUrl);
console.log('删除空文件夹' + fileUrl);
}
}
};
emptyDir(rootFile);
rmEmptyDir(rootFile);
},
/*
is_fileType($('#uploadfile').val(), 'doc,pdf,txt,wps,odf,md,png,gif,jpg')
* */
is_fileType(filename, types) {
types = types.split(',');
let pattern = '\.(';
for (let i = 0; i < types.length; i++) {
if (0 !== i) {
pattern += '|';
}
pattern += types[i].trim();
}
pattern += ')$';
return new RegExp(pattern, 'i').test(filename);
},
getFileName(filePath) {
let s_i = filePath.lastIndexOf('/');
if (s_i == -1) s_i = filePath.lastIndexOf('\\');
let name = filePath
if (s_i != -1) name = name.substr(s_i + 1)
s_i = name.lastIndexOf('.');
if (s_i != -1) {
name = name.substr(0, s_i)
}
return name;
},
getFileExtname(filePath) {
let s_i = filePath.lastIndexOf('.');
let extname = ""
if (s_i != -1) {
extname = filePath.substr(s_i).toLowerCase()
}
return extname;
},
getUrlInfo(url) {
let s_i = url.lastIndexOf('/');
if (s_i == -1) s_i = url.lastIndexOf('\\');
let name = ""
if (s_i != -1) name = url.substr(s_i + 1)
s_i = name.lastIndexOf('.');
let extname = ""
if (s_i != -1) {
extname = name.substr(s_i).toLowerCase()
}
return { name, extname, url }
},
httpPost(ip,path,port,args,callback){
var options = {
hostname: ip,
port: port,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
};
var req = http.request(options, function (res) {
// console.log('STATUS: ' + res.statusCode);
// console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
if(callback) callback(chunk);
});
});
req.on('error', function (e) {
if(callback) callback();
});
// write data to request body
var content = querystring.stringify(args);
req.write(content);
req.end();
},
}

View File

@@ -0,0 +1,136 @@
const fetch = require('./node-fetch');
/**
* 更新器
*/
const Updater = {
/**
* 远端地址
* @type {string}
*/
remoteUrl: 'https://gitee.com/mcv/simple-code-describe',
/**
* 获取远端的 package.json
* @returns {Promise<object>}
*/
async getRemotePackageJson() {
const packageJsonUrl = `${this.remoteUrl}/raw/master/package3.json`;
// 发起网络请求
const response = await fetch(packageJsonUrl, {
method: 'GET',
cache: 'no-cache',
mode: 'no-cors',
});
// 请求结果
if (response.status !== 200) {
return null;
}
// 读取 json
const json = response.json();
return json;
},
async getRemoteDesc() {
const descUrl = `${this.remoteUrl}/raw/master/README3.md`;
// 发起网络请求
const response = await fetch(descUrl, {
method: 'GET',
cache: 'no-cache',
mode: 'no-cors',
});
// 请求结果
if (response.status !== 200) {
return '';
}
const text = response.text();
return text;
},
/**
* 获取远端版本号
* @returns {Promise<string>}
*/
async getRemoteVersion() {
const package = await this.getRemotePackageJson();
if (!package) {
return null;
}
const version = package.version || null;
return version;
},
/**
* 获取本地版本号
* @returns {string}
*/
getLocalVersion() {
return require('../package.json').version;
},
/**
* 拆分版本号
* @param {string} version 版本号文本
* @returns {number[]}
* @example
* splitVersionString('1.2.0'); // [1, 2, 0]
*/
splitVersionString(version) {
return (
version.replace(/-/g, '.')
.split('.')
.map(v => (parseInt(v) || 0))
);
},
/**
* 对比版本号
* @param {string} a 版本 a
* @param {string} b 版本 b
* @returns {-1 | 0 | 1}
* @example
* compareVersion('1.0.0', '1.0.1'); // -1
* compareVersion('1.1.0', '1.1.0'); // 0
* compareVersion('1.2.1', '1.2.0'); // 1
* compareVersion('1.2.0.1', '1.2.0'); // 1
*/
compareVersion(a, b) {
const acs = this.splitVersionString(a),
bcs = this.splitVersionString(b);
const count = Math.max(acs.length, bcs.length);
for (let i = 0; i < count; i++) {
const ac = acs[i],
bc = bcs[i];
// 前者缺少分量或前者小于后者
if (ac == null || ac < bc) {
return -1;
}
// 后者缺少分量或前者大于后者
if (bc == null || ac > bc) {
return 1;
}
}
return 0;
},
/**
* 检查远端是否有新版本
* @returns {Promise<boolean>}
*/
async check() {
// 远端版本号
const remoteVersion = await this.getRemoteVersion();
if (!remoteVersion) {
return '';
}
// 本地版本号
const localVersion = this.getLocalVersion();
// 对比版本号
const result = this.compareVersion(localVersion, remoteVersion);
const remoteDesc = await this.getRemoteDesc() || '';
return (result < 0) ? remoteDesc : '';
},
};
module.exports = Updater;

View File

@@ -0,0 +1,214 @@
/**
* 1.监听文件变动
*/
const fs = require("fs");
const path = require("path");
const tools = require("./tools");
/**
* 事件回调
*
* @callback WatchEventCallback
* @param {string} eventName - 事件名 create | delete | change | init
* @param {Array<string>} files - 改变的文件
*/
/**
* 监听事件
*/
class WatchFile {
/**
* @param {WatchFile} watchObj
* @param {string} pathName
* @param {WatchEventCallback} eventCallback
*/
constructor(watchObj,pathName,eventCallback){
this.pathName = pathName;
this.eventCallback = eventCallback;
this._watchObj = watchObj;
/** @type Object<string,fs.Stats> */
this._files = {}
this._isChecking = false;
this._isInit = false;
this._isExistPath = false;
this.check();
}
stop(){
this._watchObj.removeWatch(this.eventCallback);
}
/**
* 更新文件状态
*/
async check(){
if(this._isChecking){
return;
}
let pathStat = fs.existsSync(this.pathName) ? fs.statSync(this.pathName) : undefined;
if(!pathStat){
// 监听的目录被删除
if(this._isExistPath) setTimeout(this._removeAllFile.bind(this),1);
this._isExistPath = false;
return ;
}
this._isExistPath = true;
this._isChecking = true;
let newFiles = {}
if(pathStat && pathStat.isDirectory())
{
newFiles = await getDirAllFiles(this.pathName,newFiles)
this._update(newFiles)
}else if(pathStat.isFile())
{
newFiles[this.pathName] = pathStat;
// 延迟执行防止循环调用
setTimeout(()=>this._update(newFiles),1)
}
}
/**
* 更新状态
* @param {Object<string,fs.Stats>} newFiles
*/
_update(newFiles){
let deleteFiles = [];
let changeFiles = [];
let createFiles = [];
for (const filePath in this._files) {
const oldFileStats = this._files[filePath];
const newFileStats = newFiles[filePath]
if(newFileStats == null){
// 文件被删
deleteFiles.push(filePath);
}else if(newFileStats.mtimeMs != oldFileStats.mtimeMs){
// 文件被修改
changeFiles.push(filePath);
}
}
for (const filePath in newFiles) {
/** @type fs.Stats */
const oldFileStats = this._files[filePath];
if(oldFileStats == null){
// 新创文件
createFiles.push(filePath);
}
}
let isInit = this._isInit;
this._files = newFiles;
this._isChecking = false;
this._isInit = true;
// 调用事件
if(this.eventCallback){
if(!isInit){
this.eventCallback('init',createFiles);
}else{
if(deleteFiles.length) this.eventCallback('delete',deleteFiles);
if(changeFiles.length) this.eventCallback('change',changeFiles);
if(createFiles.length) this.eventCallback('create',createFiles);
}
}
}
_removeAllFile(){
let deleteFiles = [];
for (const filePath in this._files) {
deleteFiles.push(filePath);
}
this._files = {};
if(deleteFiles.length) this.eventCallback('delete',deleteFiles);
}
}
/**
* 监听文件类
*/
class WatchMgr{
constructor(){
/** @type [WatchFile] */
this.eventListens = []
this.watchFileBuffs = {}
}
/**
*
* @param {string} pathName
* @param {WatchEventCallback} eventCallback
* @returns {WatchFile}
*/
addWatchPath(pathName,eventCallback) {
let watchFile = new WatchFile(this,pathName,eventCallback);
this.eventListens.push(watchFile);
return watchFile;
}
checkAll() {
for (let i = 0; i < this.eventListens.length; i++) {
const watchFile = this.eventListens[i];
watchFile.check();
}
}
check(pathName) {
for (let i = 0; i < this.eventListens.length; i++) {
const watchFile = this.eventListens[i];
if(watchFile.pathName == pathName){
watchFile.check();
break
}
}
}
removeWatch(pathName) {
for (let i = 0; i < this.eventListens.length; i++) {
const watchFile = this.eventListens[i];
if(watchFile.pathName == pathName){
this.eventListens.splice(i,1);
break
}
}
}
}
async function getDirAllFiles(dirPath ,result = {}) {
return new Promise((resolve, reject )=>
{
fs.readdir(dirPath,(err,files)=>
{
if(err) return reject(err);
let len = files.length;
if(len == 0){
resolve(result); // 没有文件
return;
}
let cur_ind = 0;
files.forEach((val) => {
let fPath = path.join(dirPath, val);
fs.stat(fPath,async (err,stat)=>
{
if(err) return reject(err);
if (stat.isDirectory()) {
result = await getDirAllFiles(fPath,result);
} else if (stat.isFile()) {
result[fPath] = stat ;
}
cur_ind ++;
if(cur_ind == len) {
resolve(result)
}
})
});
});
})
}
exports.WatchMgr = WatchMgr;
exports.WatchFile = WatchFile;

View File

@@ -0,0 +1,21 @@
#box {
display: flex;
flex-wrap: nowrap;
flex-direction: column;
align-content: flex-start;
align-items: stretch;
justify-content: space-between;
height: -webkit-fill-available;
margin-left: 22px;
margin-right: 22px;
margin-top: 22px;
margin-bottom: 50px;
}
.layoutItem {
flex: 0.5;
display: flex;
flex-direction: column;
flex-grow: 0;
}

View File

@@ -0,0 +1,15 @@
<div id="box">
<div class="layoutItem">
压缩模式 :<br/>
<ui-tab id = 'zipModeTab' value="0">
<ui-button>Imagemin(离线)</ui-button>
<ui-button>TinyPng(在线)</ui-button>
</ui-tab>
</div>
<br/>
<div class="layoutItem">
压缩值 (越小压缩率越大):
<ui-slider id = 'zipRateSlider' step="1" value="70" min="1" max="100"></ui-slider>
</div>
<ui-button class="layoutItem" id = 'saveBtn' class="green">保存</ui-button>
</div>

File diff suppressed because it is too large Load Diff