no message

This commit is contained in:
gem
2025-02-18 15:21:31 +08:00
commit 2d133e56d7
1980 changed files with 465595 additions and 0 deletions

392
cmake/predefine.cmake Normal file
View File

@@ -0,0 +1,392 @@
set(CC_PLATFORM_IOS 1)
set(CC_PLATFORM_WINDOWS 2)
set(CC_PLATFORM_ANDROID 3)
set(CC_PLATFORM_MACOS 4)
set(CC_PLATFORM_OHOS 5)
set(CC_PLATFORM_LINUX 6)
set(CC_PLATFORM_QNX 7)
set(CC_PLATFORM_NX 8)
set(CC_PLATFORM_EMSCRIPTEN 9)
set(CC_PLATFORM_OPENHARMONY 10)
set(CC_PLATFORM 1)
if(NX)
if(NOT DEFINED ENV{NINTENDO_SDK_ROOT})
message(FATAL_ERROR "Nintendo SDK not found")
return()
endif()
if(NOT IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../platform-nx)
message(FATAL_ERROR "platform adaptation package not found")
return()
endif()
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows")
message(FATAL_ERROR "Only windows environment is supported")
return()
endif()
if (CC_NX_WINDOWS) # windows reference
set(WINDOWS TRUE)
set(CC_PLATFORM ${CC_PLATFORM_WINDOWS})
else()
set(CC_PLATFORM ${CC_PLATFORM_NX})
endif()
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(WINDOWS TRUE)
set(PLATFORM_FOLDER windows)
set(CC_PLATFORM ${CC_PLATFORM_WINDOWS})
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android")
set(PLATFORM_FOLDER android)
set(ANDROID TRUE)
set(CC_PLATFORM ${CC_PLATFORM_ANDROID})
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(APPLE TRUE)
set(MACOSX TRUE)
set(PLATFORM_FOLDER mac)
set(CC_PLATFORM ${CC_PLATFORM_MACOS})
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(LINUX TRUE)
set(PLATFORM_FOLDER linux)
set(CC_PLATFORM ${CC_PLATFORM_LINUX})
add_definitions(-D__LINUX__=1)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "iOS")
set(APPLE TRUE)
set(IOS TRUE)
set(PLATFORM_FOLDER ios)
set(CC_PLATFORM ${CC_PLATFORM_IOS})
elseif(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
if(NOT IS_DIRECTORY ${QNX_PATH})
message(FATAL_ERROR "platform adaptation package not found")
return()
endif()
set(QNX TRUE)
set(PLATFORM_FOLDER qnx)
set(CC_PLATFORM ${CC_PLATFORM_QNX})
add_definitions(-D__QNX__=1)
elseif(OPENHARMONY)
set(OPENHARMONY TRUE)
set(CC_PLATFORM ${CC_PLATFORM_OPENHARMONY})
add_definitions(-D__OPENHARMONY__=1)
set(PLATFORM_FOLDER openharmony)
set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden ${CMAKE_CXX_FLAGS}")
if("${OHOS_ARCH}" STREQUAL "armeabi-v7a")
set(CMAKE_CXX_FLAGS "-march=armv7a ${CMAKE_CXX_FLAGS}")
endif()
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
set(CC_WGPU_WASM TRUE)
set(CC_PLATFORM ${CC_PLATFORM_EMSCRIPTEN})
set(EMSCRIPTEN TRUE)
add_definitions(-DCC_WGPU_WASM=1)
elseif(OHOS)
set(OHOS TRUE)
set(CC_PLATFORM ${CC_PLATFORM_OHOS})
add_definitions(-D__OHOS__=1)
set(PLATFORM_FOLDER ohos)
else()
message(FATAL_ERROR "Unsupported platform '${CMAKE_SYSTEM_NAME}', CMake will exit!")
return()
endif()
MESSAGE(STATUS "platform: ${CMAKE_SYSTEM_NAME}")
# platform macros
add_definitions(-DCC_PLATFORM_WINDOWS=${CC_PLATFORM_WINDOWS})
add_definitions(-DCC_PLATFORM_MACOS=${CC_PLATFORM_MACOS})
add_definitions(-DCC_PLATFORM_IOS=${CC_PLATFORM_IOS})
add_definitions(-DCC_PLATFORM_MAC_OSX=${CC_PLATFORM_MACOS}) # keep compatible
add_definitions(-DCC_PLATFORM_MAC_IOS=${CC_PLATFORM_IOS}) # keep compatible
add_definitions(-DCC_PLATFORM_ANDROID=${CC_PLATFORM_ANDROID})
add_definitions(-DCC_PLATFORM_OHOS=${CC_PLATFORM_OHOS})
add_definitions(-DCC_PLATFORM_LINUX=${CC_PLATFORM_LINUX})
add_definitions(-DCC_PLATFORM_QNX=${CC_PLATFORM_QNX})
add_definitions(-DCC_PLATFORM_NX=${CC_PLATFORM_NX})
add_definitions(-DCC_PLATFORM_OPENHARMONY=${CC_PLATFORM_OPENHARMONY})
add_definitions(-DCC_PLATFORM_EMSCRIPTEN=${CC_PLATFORM_EMSCRIPTEN})
add_definitions(-DCC_PLATFORM=${CC_PLATFORM})
# simplify generator condition, please use them everywhere
if(CMAKE_GENERATOR STREQUAL Xcode)
set(XCODE TRUE)
elseif(CMAKE_GENERATOR MATCHES Visual)
set(VS TRUE)
endif()
# generators that are capable of organizing into a hierarchy of folders
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# set c++ standard
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if("$ENV{COCOS_ENGINE_DEV}" EQUAL "1")
set(WERROR_FLAGS "-Werror -Werror=return-type") # -Wshorten-64-to-32 -Werror=return-type
if(APPLE)
set(WERROR_FLAGS " ${WERROR_FLAGS} -Wno-deprecated-declarations")
elseif(LINUX)
set(WERROR_FLAGS " ${WERROR_FLAGS} -Wno-nullability-completeness -Wno-deprecated-declarations")
elseif(ANDROID)
set(WERROR_FLAGS " ${WERROR_FLAGS} -Wno-deprecated-declarations -Wno-unknown-warning-option -Wno-deprecated-builtins")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(WERROR_FLAGS " ${WERROR_FLAGS} -Wno-invalid-offsetof")
endif()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(WERROR_FLAGS "/WX")
endif()
message(STATUS "Enable NO_WERROR")
else()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
set(WERROR_FLAGS "")
else()
set(WERROR_FLAGS "-Werror=return-type")
endif()
message(STATUS "Ignore NO_WERROR")
endif()
if(ANDROID)
if("${ANDROID_ABI}" STREQUAL "armeabi-v7a")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon-fp16")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-fp16")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsigned-char -ffunction-sections -fdata-sections -fstrict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsigned-char -ffunction-sections -fdata-sections -fstrict-aliasing -frtti -fexceptions")
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=default -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -fno-omit-frame-pointer")
else()
if(NOT DEFINED HIDE_SYMBOLS OR HIDE_SYMBOLS) # hidden by default
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
endif()
endif()
endif()
function(cc_enable_werror source_list)
foreach(src IN LISTS source_list)
if("${src}" MATCHES "\\.(cpp|mm|c|m)\$")
set_source_files_properties("${src}" PROPERTIES
COMPILE_FLAGS "${WERROR_FLAGS}"
)
endif()
endforeach()
endfunction()
################################# cc_set_if_undefined ###################################
macro(cc_set_if_undefined varname value)
if(NOT DEFINED ${varname})
set(${varname} ${value})
endif()
endmacro()
################################# cocos_source_files ###################################
macro(cocos_source_files)
set(list_var "${ARGN}")
set(TWAE ON)
set(ACCEPT_MN OFF)
set(MODULE_NAME "COCOS")
set(NO_UBUILD OFF)
foreach(src IN LISTS list_var)
if(ACCEPT_MN)
set(MODULE_NAME "${src}")
set(ACCEPT_MN OFF)
elseif("NO_WERROR" STREQUAL "${src}")
set(TWAE OFF)
elseif("MODULE" STREQUAL "${src}")
set(ACCEPT_MN ON)
elseif("NO_UBUILD" STREQUAL "${src}")
set(NO_UBUILD ON)
else()
if(IS_ABSOLUTE "${src}")
set(fp "${src}")
else()
set(fp "${CWD}/${src}")
endif()
get_source_file_property(IS_GENERATED ${fp} GENERATED)
if(EXISTS ${fp} OR ${IS_GENERATED})
if("${fp}" MATCHES "\\.(cpp|mm|c|m)\$" AND TWAE)
set_source_files_properties("${fp}" PROPERTIES
COMPILE_FLAGS "${WERROR_FLAGS}"
)
endif()
if("${fp}" MATCHES "\\.(cpp|mm|c|m)\$" AND NO_UBUILD)
set_source_files_properties("${fp}" PROPERTIES
SKIP_UNITY_BUILD_INCLUSION ON
)
endif()
list(APPEND ${MODULE_NAME}_SOURCE_LIST "${fp}")
else()
message(FATAL_ERROR "Cocos souce file not exists: \"${src}\", is generated ${IS_GENERATED}")
endif()
set(TWAE ON)
set(NO_UBUILD OFF)
endif()
endforeach()
endmacro()
################################# inspect_values ###################################
function(cc_inspect_values)
set(list_var "${ARGN}")
foreach(src IN LISTS list_var)
set(opv ${${src}})
message(STATUS "OPTION ${src}:\t${opv}")
endforeach()
endfunction()
function(cc_parse_cfg_include_files cfg_file output_var)
file(STRINGS ${cfg_file} my_lines)
set(include_pattern "^%include *\"([^\"]*)\" *$")
set(include_files "")
foreach(line ${my_lines})
if(line MATCHES ${include_pattern})
# keep syncing with SWIG_ARGS
set(include_file ${CMAKE_CURRENT_LIST_DIR}/cocos/${CMAKE_MATCH_1})
set(include_file2 ${CMAKE_CURRENT_LIST_DIR}/${CMAKE_MATCH_1})
if(EXISTS ${include_file})
list(APPEND include_files ${include_file})
elseif(EXISTS ${include_file2})
list(APPEND include_files ${include_file2})
else()
message(FATAL_ERROR "%include ${include_file}: file not found")
endif()
endif()
endforeach()
set(${output_var} ${include_files} PARENT_SCOPE)
endfunction()
function(cc_gen_swig_files cfg_directory output_dir)
file(MAKE_DIRECTORY "${output_dir}")
if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Windows")
set(SWIG_DIR ${EXTERNAL_ROOT}/win64/bin/swig)
set(SWIG_EXEC ${SWIG_DIR}/bin/swig.exe)
elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin")
set(SWIG_DIR ${EXTERNAL_ROOT}/mac/bin/swig)
set(SWIG_EXEC ${SWIG_DIR}/bin/swig)
elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
set(SWIG_DIR ${EXTERNAL_ROOT}/linux/bin/swig)
set(SWIG_EXEC ${SWIG_DIR}/bin/swig)
else()
message(FATAL_ERROR "swig is not supported on current platform!")
endif()
set(SWIG_ARGS
-c++
-cocos
-fvirtual
-noexcept
-cpperraswarn
-D__clang__
-Dfinal=
-DCC_PLATFORM=3
-Dconstexpr=const
-DCC_PLATFORM_ANDROID=3
-I${SWIG_DIR}/share/swig/4.1.0/javascript/cocos
-I${SWIG_DIR}/share/swig/4.1.0
-I${CMAKE_CURRENT_LIST_DIR}/
-I${CMAKE_CURRENT_LIST_DIR}/cocos
-o
)
file(GLOB cfg_files ${cfg_directory}/*.i)
list(FILTER cfg_files EXCLUDE REGEX ".*template.*")
foreach(cfg ${cfg_files})
set(dep_files)
get_filename_component(mod_name ${cfg} NAME_WE)
set(output_file_tmp ${output_dir}/temp/jsb_${mod_name}_auto.cpp)
set(output_file ${output_dir}/jsb_${mod_name}_auto.cpp)
set(output_hfile_tmp ${output_dir}/temp/jsb_${mod_name}_auto.h)
set(output_hfile ${output_dir}/jsb_${mod_name}_auto.h)
cc_parse_cfg_include_files(${cfg} dep_files)
add_custom_command(
OUTPUT
${output_hfile}
${output_file}
COMMAND ${CMAKE_COMMAND} -E echo "Running swig with config file ${cfg} ..."
COMMAND ${CMAKE_COMMAND} -E make_directory ${output_dir}/temp
COMMAND ${SWIG_EXEC} ${SWIG_ARGS}
${output_file_tmp}
${cfg}
COMMAND
${CMAKE_COMMAND} -E copy_if_different ${output_file_tmp} ${output_file}
COMMAND
${CMAKE_COMMAND} -E copy_if_different ${output_hfile_tmp} ${output_hfile}
DEPENDS ${cfg} ${dep_files}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/..
)
set_source_files_properties(${output_file}
PROPERTIES
GENERATED TRUE
LOCATION ${output_file}
)
get_source_file_property(IS_GENERATED ${output_file} GENERATED)
endforeach()
endfunction(cc_gen_swig_files)
function(cc_set_target_property target_name property value)
set_target_properties(${target_name} PROPERTIES CC_${property} ${value})
endfunction()
function(cc_get_target_property output target_name property)
get_target_property(output ${target_name} ${property})
endfunction()
function(cc_redirect_property target from_property to_property)
cc_get_target_property(output ${target} ${from_property})
if(output)
set_target_properties(${target_name} PROPERTIES
${to_property} ${output}
)
endif()
endfunction()
if(NOT DEFINED NODE_EXECUTABLE)
if(DEFINED EDITOR_NODEJS)
set(NODE_EXECUTABLE ${EDITOR_NODEJS})
elseif(DEFINED ENV{NODE_EXECUTABLE})
set(NODE_EXECUTABLE $ENV{NODE_EXECUTABLE})
message(STATUS "set NODE_EXECUTABLE by env")
else()
find_program(NODE_EXECUTABLE NAMES node)
endif()
endif()
if(NOT DEFINED TSC_EXECUTABLE)
find_program(TSC_EXECUTABLE NAMES tsc)
endif()
if(NOT DEFINED CCACHE_EXECUTABLE)
find_program(CCACHE_EXECUTABLE NAMES ccache)
endif()
## predefined configurations for game applications
include(${CMAKE_CURRENT_LIST_DIR}/../templates/cmake/common.cmake)
if(APPLE)
include(${CMAKE_CURRENT_LIST_DIR}/../templates/cmake/apple.cmake)
elseif(WINDOWS)
include(${CMAKE_CURRENT_LIST_DIR}/../emplates/cmake/windows.cmake)
elseif(LINUX)
include(${CMAKE_CURRENT_LIST_DIR}/../templates/cmake/linux.cmake)
elseif(ANDROID)
include(${CMAKE_CURRENT_LIST_DIR}/../templates/cmake/android.cmake)
elseif(OPENHARMONY)
include(${CMAKE_CURRENT_LIST_DIR}/../templates/cmake/openharmony.cmake)
elseif(OHOS)
include(${CMAKE_CURRENT_LIST_DIR}/../templates/cmake/ohos.cmake)
elseif(QNX)
elseif(EMSCRIPTEN)
else()
message(FATAL_ERROR "Unhandled platform specified cmake utils!")
endif()

View File

@@ -0,0 +1,96 @@
const fs = require('fs');
const path = require('path');
const pkgCfg = path.join(__dirname, '../../../package.json');
if (!fs.existsSync(pkgCfg)) {
console.error(`Can not find package.json: ${pkgCfg}`);
process.exit(1);
}
let pkgJson = {};
try {
pkgJson = JSON.parse(fs.readFileSync(pkgCfg, 'utf8'));
} catch (err) {
console.error(`Error parsing ${pkgCfg}`);
console.error(err);
process.exit(1);
}
if (!pkgJson.version) {
console.error(`Can not find field 'version' in file ${pkgCfg}`);
process.exit(1);
}
const version_regex = /(\d+)\.(\d+)(\.(\d+))?(-(\w+))?/;
const version_str = pkgJson.version;
const version_result = version_str.match(version_regex);
if (!version_result) {
console.error(`Failed to parse version string: '${version_str}'`);
process.exit(1);
}
const majorVersion = parseInt(version_result[1]);
const minorVersion = parseInt(version_result[2]);
const patchVersion = version_result[4] ? parseInt(version_result[4]) : 0;
const preRelease = version_result[6] ? version_result[6] : 'release';
const versionIntValue = majorVersion * 10000 + minorVersion * 100 + patchVersion;
const fullYear = (new Date).getFullYear();
const version_header = `/****************************************************************************
Copyright (c) ${fullYear <= 2022 ? "2022" : "2022-"+fullYear} Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#define COCOS_MAJOR_VERSION ${majorVersion}
#define COCOS_MINJOR_VERSION ${minorVersion}
#define COCOS_PATCH_VERSION ${patchVersion}
#define COCOS_VERSION_STRING "${majorVersion}.${minorVersion}.${patchVersion}"
#define COCOS_VERSION_DEFINED 1
#define COCOS_VERSION ${versionIntValue}
// #define COCOS_PRE_RELEASE "${preRelease}"
`;
const outputVersionFile = path.join(__dirname, '../../cocos/cocos-version.h');
if(!fs.existsSync(outputVersionFile) || !compareFileContent(outputVersionFile, version_header)) {
console.log(`Update cocos-version.h to ${version_str}`);
fs.writeFileSync(outputVersionFile, version_header);
} else {
console.log(`cocos-version.h is up to date`);
}
function compareFileContent(file, content) {
const srcLines = fs.readFileSync(file, 'utf8').split('\n').map(x=>x.trim());
const dstLines = content.split('\n').map(x => x.trim());
if(srcLines.length !== dstLines.length) {
return false;
}
for(let i = 0, l = srcLines.length; i < l; i++) {
if(srcLines[i] != dstLines[i]) {
return false;
}
}
return true;
}

View File

@@ -0,0 +1,47 @@
const Fs = require('fs');
const process = require('process');
const writeIfDifferent = require('./utils').writeIfDifferent;
if (process.argv.length !== 5) {
console.error('bad argument');
console.error(' - input file');
console.error(' - template file');
console.error(' - output file');
process.exit(-1);
}
const inputFile = process.argv[2];
const template = process.argv[3];
const outputFile = process.argv[4];
let buildDebugInfos = function() {
let readContent = Fs.readFileSync(inputFile, 'utf-8');
let titleRegExp = /### \d+/g;
let debugInfos = "";
let result1 = titleRegExp.exec(readContent);
while (result1) {
let result2 = titleRegExp.exec(readContent);
let errInfoHead = result1.index + result1[0].length;
let errInfoTail = result2? result2.index: readContent.length;
let errCode = /\d+/.exec(result1[0])[0];
let errInfo = readContent.slice(errInfoHead, errInfoTail);
errInfo = errInfo.replace(/```/g, ' ');
errInfo = errInfo.trim();
errInfo = errInfo.replace(/\r\n/g, '\n');
if (!errInfo.includes('<!-- DEPRECATED -->')) {
errInfo = errInfo.replace(/\n/g, "\\n").replace(/\"/g, "'").replace(/\\`/g, "`");
debugInfos = debugInfos.concat("{ ", errCode, ", \"", errInfo, "\" },\n");
}
result1 = result2;
}
let replaceData = Fs.readFileSync(template).toString('utf-8').replace("${PLACE_HOLDER}", debugInfos);
writeIfDifferent(outputFile, replaceData, { encoding: 'utf-8' });
};
buildDebugInfos();
process.exit(0);

View File

@@ -0,0 +1,846 @@
/*
* Generated by PEG.js 0.10.0.
*
* http://pegjs.org/
*/
"use strict";
function peg$subclass(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
}
function peg$SyntaxError(message, expected, found, location) {
this.message = message;
this.expected = expected;
this.found = found;
this.location = location;
this.name = "SyntaxError";
if (typeof Error.captureStackTrace === "function") {
Error.captureStackTrace(this, peg$SyntaxError);
}
}
peg$subclass(peg$SyntaxError, Error);
peg$SyntaxError.buildMessage = function(expected, found) {
var DESCRIBE_EXPECTATION_FNS = {
literal: function(expectation) {
return "\"" + literalEscape(expectation.text) + "\"";
},
"class": function(expectation) {
var escapedParts = "",
i;
for (i = 0; i < expectation.parts.length; i++) {
escapedParts += expectation.parts[i] instanceof Array
? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1])
: classEscape(expectation.parts[i]);
}
return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
},
any: function(expectation) {
return "any character";
},
end: function(expectation) {
return "end of input";
},
other: function(expectation) {
return expectation.description;
}
};
function hex(ch) {
return ch.charCodeAt(0).toString(16).toUpperCase();
}
function literalEscape(s) {
return s
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\0/g, '\\0')
.replace(/\t/g, '\\t')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); });
}
function classEscape(s) {
return s
.replace(/\\/g, '\\\\')
.replace(/\]/g, '\\]')
.replace(/\^/g, '\\^')
.replace(/-/g, '\\-')
.replace(/\0/g, '\\0')
.replace(/\t/g, '\\t')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); });
}
function describeExpectation(expectation) {
return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
}
function describeExpected(expected) {
var descriptions = new Array(expected.length),
i, j;
for (i = 0; i < expected.length; i++) {
descriptions[i] = describeExpectation(expected[i]);
}
descriptions.sort();
if (descriptions.length > 0) {
for (i = 1, j = 1; i < descriptions.length; i++) {
if (descriptions[i - 1] !== descriptions[i]) {
descriptions[j] = descriptions[i];
j++;
}
}
descriptions.length = j;
}
switch (descriptions.length) {
case 1:
return descriptions[0];
case 2:
return descriptions[0] + " or " + descriptions[1];
default:
return descriptions.slice(0, -1).join(", ")
+ ", or "
+ descriptions[descriptions.length - 1];
}
}
function describeFound(found) {
return found ? "\"" + literalEscape(found) + "\"" : "end of input";
}
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
};
function peg$parse(input, options) {
options = options !== void 0 ? options : {};
var peg$FAILED = {},
peg$startRuleIndices = { Expression: 0 },
peg$startRuleIndex = 0,
peg$consts = [
"||",
peg$literalExpectation("||", false),
function(head, tail) {
let s = [head];
s = s.concat(tail.map(x=>x[1]));
return new VersionSet(s);
},
peg$otherExpectation("Condition Items"),
function(head, tail) {
let s = [head];
s = s.concat(tail.map(x=> x[1]));
return s;
},
function(head) {
return [head];
},
">=",
peg$literalExpectation(">=", false),
function(v) {
v.op = OP_GE;
return v;
},
"<=",
peg$literalExpectation("<=", false),
function(v) {
v.op = OP_LE;
return v;
},
"!=",
peg$literalExpectation("!=", false),
function(v) {
v.op = OP_NOT;
return v;
},
"!",
peg$literalExpectation("!", false),
"=",
peg$literalExpectation("=", false),
function(v) {
v.op = OP_EQ;
return v;
},
"<",
peg$literalExpectation("<", false),
function(v) {
v.op = OP_LT;
return v;
},
">",
peg$literalExpectation(">", false),
function(v) {
v.op = OP_GT;
return v;
},
function(head) {
head.op = OP_IS;
return head;
},
peg$otherExpectation("version"),
peg$otherExpectation("major.minor.patch"),
".",
peg$literalExpectation(".", false),
function(v, n) { v.patch = n; return v},
peg$otherExpectation("major.minor"),
function(v, n) {v.minor = n; return v},
peg$otherExpectation("major"),
function(n) {let v = new Version; v.major = n; return v},
"*",
peg$literalExpectation("*", false),
"x",
peg$literalExpectation("x", false),
"X",
peg$literalExpectation("X", false),
function() {return '*';},
peg$otherExpectation("integer"),
/^[0-9]/,
peg$classExpectation([["0", "9"]], false, false),
function() { return parseInt(text(), 10); },
peg$otherExpectation("whitespace"),
/^[ \t\n\r]/,
peg$classExpectation([" ", "\t", "\n", "\r"], false, false)
],
peg$bytecode = [
peg$decode("%;!/k#$%2 \"\"6 7!/,#;!/#$+\")(\"'#&'#0<*%2 \"\"6 7!/,#;!/#$+\")(\"'#&'#&/)$8\":\"\"\"! )(\"'#&'#"),
peg$decode("<%;*/w#;\"/n$$%;)/,#;\"/#$+\")(\"'#&'#/9#06*%;)/,#;\"/#$+\")(\"'#&'#&&&#/2$;*/)$8$:$$\"\"!)($'#(#'#(\"'#&'#.D &%;*/:#;\"/1$;*/($8#:%#!!)(#'#(\"'#&'#=.\" 7#"),
peg$decode("%2&\"\"6&7'/:#;*/1$;#/($8#:(#! )(#'#(\"'#&'#.\u013D &%2)\"\"6)7*/:#;*/1$;#/($8#:+#! )(#'#(\"'#&'#.\u0110 &%2,\"\"6,7-/:#;*/1$;#/($8#:.#! )(#'#(\"'#&'#.\xE3 &%2/\"\"6/70/:#;*/1$;#/($8#:.#! )(#'#(\"'#&'#.\xB6 &%21\"\"6172/:#;*/1$;#/($8#:3#! )(#'#(\"'#&'#.\x89 &%24\"\"6475/:#;*/1$;#/($8#:6#! )(#'#(\"'#&'#.\\ &%27\"\"6778/:#;*/1$;#/($8#:9#! )(#'#(\"'#&'#./ &%;#/' 8!::!! )"),
peg$decode("<;$.) &;%.# &;&=.\" 7;"),
peg$decode("<%;%/A#2=\"\"6=7>/2$;'/)$8#:?#\"\" )(#'#(\"'#&'#=.\" 7<"),
peg$decode("<%;&/A#2=\"\"6=7>/2$;'/)$8#:A#\"\" )(#'#(\"'#&'#=.\" 7@"),
peg$decode("<%;'/' 8!:C!! )=.\" 7B"),
peg$decode("%2D\"\"6D7E.5 &2F\"\"6F7G.) &2H\"\"6H7I/& 8!:J! ).# &;("),
peg$decode("<%$4L\"\"5!7M/,#0)*4L\"\"5!7M&&&#/& 8!:N! )=.\" 7K"),
peg$decode("<$4P\"\"5!7Q/,#0)*4P\"\"5!7Q&&&#=.\" 7O"),
peg$decode("<$4P\"\"5!7Q0)*4P\"\"5!7Q&=.\" 7O")
],
peg$currPos = 0,
peg$savedPos = 0,
peg$posDetailsCache = [{ line: 1, column: 1 }],
peg$maxFailPos = 0,
peg$maxFailExpected = [],
peg$silentFails = 0,
peg$result;
if ("startRule" in options) {
if (!(options.startRule in peg$startRuleIndices)) {
throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
}
peg$startRuleIndex = peg$startRuleIndices[options.startRule];
}
function text() {
return input.substring(peg$savedPos, peg$currPos);
}
function location() {
return peg$computeLocation(peg$savedPos, peg$currPos);
}
function expected(description, location) {
location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)
throw peg$buildStructuredError(
[peg$otherExpectation(description)],
input.substring(peg$savedPos, peg$currPos),
location
);
}
function error(message, location) {
location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)
throw peg$buildSimpleError(message, location);
}
function peg$literalExpectation(text, ignoreCase) {
return { type: "literal", text: text, ignoreCase: ignoreCase };
}
function peg$classExpectation(parts, inverted, ignoreCase) {
return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
}
function peg$anyExpectation() {
return { type: "any" };
}
function peg$endExpectation() {
return { type: "end" };
}
function peg$otherExpectation(description) {
return { type: "other", description: description };
}
function peg$computePosDetails(pos) {
var details = peg$posDetailsCache[pos], p;
if (details) {
return details;
} else {
p = pos - 1;
while (!peg$posDetailsCache[p]) {
p--;
}
details = peg$posDetailsCache[p];
details = {
line: details.line,
column: details.column
};
while (p < pos) {
if (input.charCodeAt(p) === 10) {
details.line++;
details.column = 1;
} else {
details.column++;
}
p++;
}
peg$posDetailsCache[pos] = details;
return details;
}
}
function peg$computeLocation(startPos, endPos) {
var startPosDetails = peg$computePosDetails(startPos),
endPosDetails = peg$computePosDetails(endPos);
return {
start: {
offset: startPos,
line: startPosDetails.line,
column: startPosDetails.column
},
end: {
offset: endPos,
line: endPosDetails.line,
column: endPosDetails.column
}
};
}
function peg$fail(expected) {
if (peg$currPos < peg$maxFailPos) { return; }
if (peg$currPos > peg$maxFailPos) {
peg$maxFailPos = peg$currPos;
peg$maxFailExpected = [];
}
peg$maxFailExpected.push(expected);
}
function peg$buildSimpleError(message, location) {
return new peg$SyntaxError(message, null, null, location);
}
function peg$buildStructuredError(expected, found, location) {
return new peg$SyntaxError(
peg$SyntaxError.buildMessage(expected, found),
expected,
found,
location
);
}
function peg$decode(s) {
var bc = new Array(s.length), i;
for (i = 0; i < s.length; i++) {
bc[i] = s.charCodeAt(i) - 32;
}
return bc;
}
function peg$parseRule(index) {
var bc = peg$bytecode[index],
ip = 0,
ips = [],
end = bc.length,
ends = [],
stack = [],
params, i;
while (true) {
while (ip < end) {
switch (bc[ip]) {
case 0:
stack.push(peg$consts[bc[ip + 1]]);
ip += 2;
break;
case 1:
stack.push(void 0);
ip++;
break;
case 2:
stack.push(null);
ip++;
break;
case 3:
stack.push(peg$FAILED);
ip++;
break;
case 4:
stack.push([]);
ip++;
break;
case 5:
stack.push(peg$currPos);
ip++;
break;
case 6:
stack.pop();
ip++;
break;
case 7:
peg$currPos = stack.pop();
ip++;
break;
case 8:
stack.length -= bc[ip + 1];
ip += 2;
break;
case 9:
stack.splice(-2, 1);
ip++;
break;
case 10:
stack[stack.length - 2].push(stack.pop());
ip++;
break;
case 11:
stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));
ip += 2;
break;
case 12:
stack.push(input.substring(stack.pop(), peg$currPos));
ip++;
break;
case 13:
ends.push(end);
ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
if (stack[stack.length - 1]) {
end = ip + 3 + bc[ip + 1];
ip += 3;
} else {
end = ip + 3 + bc[ip + 1] + bc[ip + 2];
ip += 3 + bc[ip + 1];
}
break;
case 14:
ends.push(end);
ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
if (stack[stack.length - 1] === peg$FAILED) {
end = ip + 3 + bc[ip + 1];
ip += 3;
} else {
end = ip + 3 + bc[ip + 1] + bc[ip + 2];
ip += 3 + bc[ip + 1];
}
break;
case 15:
ends.push(end);
ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
if (stack[stack.length - 1] !== peg$FAILED) {
end = ip + 3 + bc[ip + 1];
ip += 3;
} else {
end = ip + 3 + bc[ip + 1] + bc[ip + 2];
ip += 3 + bc[ip + 1];
}
break;
case 16:
if (stack[stack.length - 1] !== peg$FAILED) {
ends.push(end);
ips.push(ip);
end = ip + 2 + bc[ip + 1];
ip += 2;
} else {
ip += 2 + bc[ip + 1];
}
break;
case 17:
ends.push(end);
ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
if (input.length > peg$currPos) {
end = ip + 3 + bc[ip + 1];
ip += 3;
} else {
end = ip + 3 + bc[ip + 1] + bc[ip + 2];
ip += 3 + bc[ip + 1];
}
break;
case 18:
ends.push(end);
ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);
if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]) {
end = ip + 4 + bc[ip + 2];
ip += 4;
} else {
end = ip + 4 + bc[ip + 2] + bc[ip + 3];
ip += 4 + bc[ip + 2];
}
break;
case 19:
ends.push(end);
ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);
if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]) {
end = ip + 4 + bc[ip + 2];
ip += 4;
} else {
end = ip + 4 + bc[ip + 2] + bc[ip + 3];
ip += 4 + bc[ip + 2];
}
break;
case 20:
ends.push(end);
ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);
if (peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))) {
end = ip + 4 + bc[ip + 2];
ip += 4;
} else {
end = ip + 4 + bc[ip + 2] + bc[ip + 3];
ip += 4 + bc[ip + 2];
}
break;
case 21:
stack.push(input.substr(peg$currPos, bc[ip + 1]));
peg$currPos += bc[ip + 1];
ip += 2;
break;
case 22:
stack.push(peg$consts[bc[ip + 1]]);
peg$currPos += peg$consts[bc[ip + 1]].length;
ip += 2;
break;
case 23:
stack.push(peg$FAILED);
if (peg$silentFails === 0) {
peg$fail(peg$consts[bc[ip + 1]]);
}
ip += 2;
break;
case 24:
peg$savedPos = stack[stack.length - 1 - bc[ip + 1]];
ip += 2;
break;
case 25:
peg$savedPos = peg$currPos;
ip++;
break;
case 26:
params = bc.slice(ip + 4, ip + 4 + bc[ip + 3]);
for (i = 0; i < bc[ip + 3]; i++) {
params[i] = stack[stack.length - 1 - params[i]];
}
stack.splice(
stack.length - bc[ip + 2],
bc[ip + 2],
peg$consts[bc[ip + 1]].apply(null, params)
);
ip += 4 + bc[ip + 3];
break;
case 27:
stack.push(peg$parseRule(bc[ip + 1]));
ip += 2;
break;
case 28:
peg$silentFails++;
ip++;
break;
case 29:
peg$silentFails--;
ip++;
break;
default:
throw new Error("Invalid opcode: " + bc[ip] + ".");
}
}
if (ends.length > 0) {
end = ends.pop();
ip = ips.pop();
} else {
break;
}
}
return stack[0];
}
const OP_EQ = "equal";
const OP_IS = OP_EQ;
const OP_GT = "greater";
const OP_GE= "greaterequal";
const OP_LT= "less";
const OP_LE= "lessequal";
const OP_NOT = "not";
const VERBOSE = false;
function Version(){
this.major = null;
this.minor = null;
this.patch = null;
this.op = null;
}
const P = Version.prototype;
P.toString = function() {
return `[${this.op ? this.op : "?"}]/v${this.major}.${this.minor}.${this.patch}`;
}
Object.defineProperty(Version.prototype, 'wildcard', {
get: function() {
return this.major === '*' || this.minor === '*' || this.patch === '*';
}
});
Object.defineProperty(Version.prototype, 'anyMajor', {
get: function() { return this.major === '*';}
});
Object.defineProperty(Version.prototype, 'anyMinor', {
get: function() { return this.minor === '*';}
});
Object.defineProperty(Version.prototype, 'anyPatch', {
get: function() { return this.patch === '*';}
});
P.toArray = function() {
const r = [];
if(this.major !== null) {
r.push(this.major);
}
if(this.minor !== null) {
r.push(this.minor);
}
if(this.patch !== null) {
r.push(this.patch);
}
return r;
};
P.assertNotWildcard = function() {
if(this.wildcard) {
throw new Error("Source version should not be wildcard: "+this.toString());
}
}
P.compareTo = function(o) {
this.assertNotWildcard();
if(o.wildcard) {
throw new Error("Reference version should not be wildcard when comparing!");
}
const va = this.toArray();
const vb = o.toArray();
const l = Math.min(va.length, vb.length);
let fillZeros = (a, l, ml) =>{ for(let i = l; i < ml; i++) a[i] = 0;}
fillZeros(va, l, 3);
fillZeros(vb, l, 3);
let toFactor = (v) => {return (v[0] << 20) + (v[1] << 10) + (v[2]);}
return toFactor(va) - toFactor(vb);
};
P.match = function(o) {
if(VERBOSE) {
console.log(`try match ${o}`);
}
this.assertNotWildcard();
if(!o.wildcard) {
throw new Error("Reference version should be wildcard when matching!");
}
if(VERBOSE) {
console.log(` match major ${o.major}, any ${o.anyMajor}, ${this.major} <> ${o.major}`);
}
if(o.anyMajor) return true;
if(this.major !== o.major) return false;
if(VERBOSE) {
console.log(` match minor ${o.minor}, any ${o.anyMinor}, ${this.minor} <> ${o.minor}`);
}
if(o.anyMinor) return true;
if(this.minor !== o.minor) return false;
if(VERBOSE) {
console.log(` match patch ${o.patch}, any ${o.anyPatch}`);
}
if(o.anyPatch) return true;
return this.patch == o.patch;
};
P.test = function(o) {
let op = o.op;
if(op === OP_EQ) {
return o.wildcard ? this.match(o) : this.compareTo(o) === 0;
}
if(op === OP_NOT) {
return o.wildcard ? !this.match(o) : this.compareTo(o) !== 0;
}
if(o.wildcard){
throw new Error("Can not compare to wildcard version");
}
const R = this.compareTo(o);
if(op === OP_GE) {
return R >= 0;
}
if(op === OP_LE) {
return R <= 0;
}
if(op === OP_GT) {
return R > 0;
}
if(op === OP_LT) {
return R < 0;
}
throw new Error("invalidate operation " + op);
};
function VersionSet(data) {
this.conds = data;
}
function allMatch(v, versions) {
let t;
let r = true;
for(let c of versions) {
t = v.test(c);
if(VERBOSE) {
console.log(`test ${v} with ${c} => ${t}`);
}
if(!t){
r = false;
if(!VERBOSE) {
return false;
}
}
}
return r;
}
function arrElmOr(arr, idx, dft){
if(arr[idx] === undefined) return dft;
return arr[idx];
}
VersionSet.prototype.match = function(o) {
let ps = o.split('.');
let v = new Version;
v.major = parseInt(arrElmOr(ps, 0, 0), 10);
v.minor = parseInt(arrElmOr(ps, 1, 0), 10);
v.patch = parseInt(arrElmOr(ps, 2, 0), 10);
if(VERBOSE) {
console.log(`match version ${v}`);
}
for(let c of this.conds){
if(allMatch(v, c)) {
return true;
}
}
return false;
};
peg$result = peg$parseRule(peg$startRuleIndex);
if (peg$result !== peg$FAILED && peg$currPos === input.length) {
return peg$result;
} else {
if (peg$result !== peg$FAILED && peg$currPos < input.length) {
peg$fail(peg$endExpectation());
}
throw peg$buildStructuredError(
peg$maxFailExpected,
peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
peg$maxFailPos < input.length
? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
: peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
);
}
}
module.exports = {
SyntaxError: peg$SyntaxError,
parse: peg$parse
};

View File

@@ -0,0 +1,251 @@
// Simple Version Grammar
{
const OP_EQ = "equal";
const OP_IS = OP_EQ;
const OP_GT = "greater";
const OP_GE= "greaterequal";
const OP_LT= "less";
const OP_LE= "lessequal";
const OP_NOT = "not";
const VERBOSE = false;
function Version(){
this.major = null;
this.minor = null;
this.patch = null;
this.op = null;
}
const P = Version.prototype;
P.toString = function() {
return `[${this.op ? this.op : "?"}]/v${this.major}.${this.minor}.${this.patch}`;
}
Object.defineProperty(Version.prototype, 'wildcard', {
get: function() {
return this.major === '*' || this.minor === '*' || this.patch === '*';
}
});
Object.defineProperty(Version.prototype, 'anyMajor', {
get: function() { return this.major === '*';}
});
Object.defineProperty(Version.prototype, 'anyMinor', {
get: function() { return this.minor === '*';}
});
Object.defineProperty(Version.prototype, 'anyPatch', {
get: function() { return this.patch === '*';}
});
P.toArray = function() {
const r = [];
if(this.major !== null) {
r.push(this.major);
}
if(this.minor !== null) {
r.push(this.minor);
}
if(this.patch !== null) {
r.push(this.patch);
}
return r;
};
P.assertNotWildcard = function() {
if(this.wildcard) {
throw new Error("Source version should not be wildcard: "+this.toString());
}
}
P.compareTo = function(o) {
this.assertNotWildcard();
if(o.wildcard) {
throw new Error("Reference version should not be wildcard when comparing!");
}
const va = this.toArray();
const vb = o.toArray();
const l = Math.min(va.length, vb.length);
let fillZeros = (a, l, ml) =>{ for(let i = l; i < ml; i++) a[i] = 0;}
fillZeros(va, l, 3);
fillZeros(vb, l, 3);
let toFactor = (v) => {return (v[0] << 20) + (v[1] << 10) + (v[2]);}
return toFactor(va) - toFactor(vb);
};
P.match = function(o) {
if(VERBOSE) {
console.log(`try match ${o}`);
}
this.assertNotWildcard();
if(!o.wildcard) {
throw new Error("Reference version should be wildcard when matching!");
}
if(VERBOSE) {
console.log(` match major ${o.major}, any ${o.anyMajor}, ${this.major} <> ${o.major}`);
}
if(o.anyMajor) return true;
if(this.major !== o.major) return false;
if(VERBOSE) {
console.log(` match minor ${o.minor}, any ${o.anyMinor}, ${this.minor} <> ${o.minor}`);
}
if(o.anyMinor) return true;
if(this.minor !== o.minor) return false;
if(VERBOSE) {
console.log(` match patch ${o.patch}, any ${o.anyPatch}`);
}
if(o.anyPatch) return true;
return this.patch == o.patch;
};
P.test = function(o) {
let op = o.op;
if(op === OP_EQ) {
return o.wildcard ? this.match(o) : this.compareTo(o) === 0;
}
if(op === OP_NOT) {
return o.wildcard ? !this.match(o) : this.compareTo(o) !== 0;
}
if(o.wildcard){
throw new Error("Can not compare to wildcard version");
}
const R = this.compareTo(o);
if(op === OP_GE) {
return R >= 0;
}
if(op === OP_LE) {
return R <= 0;
}
if(op === OP_GT) {
return R > 0;
}
if(op === OP_LT) {
return R < 0;
}
throw new Error("invalidate operation " + op);
};
function VersionSet(data) {
this.conds = data;
}
function allMatch(v, versions) {
let t;
let r = true;
for(let c of versions) {
t = v.test(c);
if(VERBOSE) {
console.log(`test ${v} with ${c} => ${t}`);
}
if(!t){
r = false;
if(!VERBOSE) {
return false;
}
}
}
return r;
}
function arrElmOr(arr, idx, dft){
if(arr[idx] === undefined) return dft;
return arr[idx];
}
VersionSet.prototype.match = function(o) {
let ps = o.split('.');
let v = new Version;
v.major = parseInt(arrElmOr(ps, 0, 0), 10);
v.minor = parseInt(arrElmOr(ps, 1, 0), 10);
v.patch = parseInt(arrElmOr(ps, 2, 0), 10);
if(VERBOSE) {
console.log(`match version ${v}`);
}
for(let c of this.conds){
if(allMatch(v, c)) {
return true;
}
}
return false;
};
}
Expression
= head:Conds tail:('||' Conds)* {
let s = [head];
s = s.concat(tail.map(x=>x[1]));
return new VersionSet(s);
}
Conds "Condition Items"
= _ head:Cond tail:(S Cond)+ _ {
let s = [head];
s = s.concat(tail.map(x=> x[1]));
return s;
}
/ _ head: Cond _ {
return [head];
}
Cond
= '>=' _ v:Version {
v.op = OP_GE;
return v;
}
/ '<=' _ v:Version {
v.op = OP_LE;
return v;
}
/ '!=' _ v:Version {
v.op = OP_NOT;
return v;
}
/ '!' _ v:Version {
v.op = OP_NOT;
return v;
}
/ '=' _ v:Version {
v.op = OP_EQ;
return v;
}
/ '<' _ v:Version {
v.op = OP_LT;
return v;
}
/ '>'_ v:Version {
v.op = OP_GT;
return v;
}
/ head:Version {
head.op = OP_IS;
return head;
}
Version "version"
= V3 / V2 / V1
V3 "major.minor.patch"
= v:V2 '.' n:Factor { v.patch = n; return v}
V2 "major.minor"
= v:V1 '.' n:Factor {v.minor = n; return v}
V1 "major"
= n:Factor {let v = new Version; v.major = n; return v}
Factor
= ('*' / 'x' / 'X') {return '*';}
/ Integer
Integer "integer"
= [0-9]+ { return parseInt(text(), 10); }
S "whitespace"
= [ \t\n\r]+
_ "whitespace"
= [ \t\n\r]*

View File

@@ -0,0 +1,133 @@
const parser = require('./plugin_cfg.js');
const input_text = `3.4.x 3.5 3 3.* * 6.2.* || > 3.5 <= 3.2 > 2.4 <= 33.2 >=133.222.2 !333 != 22 || 4`;
// let r = parser.parse(input_text);
function assert(label, blk) {
console.log(`run ${label}`);
let r = blk();
if (!r) {
console.error(` failed!`);
}
}
// r.match("3.2");
// r.match("3.4");
{
let vs = ["3.4", "3.4.*", "3.4.x", "3.4.X"];
for (let v of vs) {
let s = parser.parse(v);
let label = `Simple match ${v}`;
assert(`${label} 1`, () => {
return s.match("3.4");
});
assert(`${label} 2`, () => {
return !s.match("3.2");
});
assert(`${label} 2`, () => {
return s.match("3.4.3");
});
assert(`${label} 3`, () => {
return s.match("3.4.6");
});
assert(`${label} 4`, () => {
return !s.match("3.444");
});
assert("dont match", () => {
let cases = [
"2.4",
"2.4.2",
"6.4",
"3"
]
return !cases.reduce((p, cs) => p || s.match(cs), false);
});
}
}
{
let s = parser.parse("*");
assert("match all", () => {
let cases = [
"2.4",
"2.4.2",
"6.4",
"3"
]
return cases.reduce((p, cs) => p && s.match(cs), true);
});
}
{
function assert_match(target, versions, bad_versions) {
let s = parser.parse(target);
for (let v of versions) {
assert(`test ${v}`, () => {
return s.match(v);
});
}
for (let v of bad_versions) {
assert(`test not match ${v}`, () => {
return !s.match(v);
});
}
}
assert_match(">3.3 <3.6", [
'3.4',
'3.4.1',
'3.4.2',
'3.5',
'3.5.0',
'3.5.1',
'3.5.2',
],
[
'3.3',
'3.3.2',
'2.3',
'3.6.0',
'3.6',
]
);
assert_match(">=3.3 <= 3.6.0", [
'3.3.0',
'3.3.1',
'3.4',
'3.4.1',
'3.4.2',
'3.5',
'3.5.0',
'3.5.1',
'3.5.2',
'3.6.0'
],
[
'3.2.9',
'2.3',
'3.6.1',
]
);
assert_match(">=3.3 <= 3.6.0 !3.5.2|| 4.x", [
'3.3.0',
'3.3.1',
'3.4',
'3.4.1',
'3.4.2',
'3.5',
'3.5.0',
'4.0',
'4.1',
'4.2',
'3.5.1',
'3.6.0'
],
[
'3.2.9',
'2.3',
'3.6.1',
'3.5.2'
]
);
}

View File

@@ -0,0 +1,271 @@
const fs = require('fs');
const path = require('path');
const version_parser = require('./plugin_support/plugin_cfg');
const MAX_SEARCH_LEVEL = 7;
const CC_PLUGIN_JSON_STR = 'cc_plugin.json';
const node_path = process.argv.shift();
const script_path = process.argv.shift();
const search_path_input_file = process.argv.shift();
const plugin_cmake_output_file = process.argv.shift();
const PLATFORM_NAME_FROM_CMAKE = process.argv.shift();
const PROJ_SEARCH_PATHS = fs.readFileSync(search_path_input_file, 'utf8').
split('\n').
map(x => x.trim()).
filter(x => x.length > 0 && !x.startsWith("#"));
const cc_config_json_list = [];
function search_cc_config_json_levels(dir, depth) {
// console.log(`[searching plugins] search dir ${dir}`);
if (depth > MAX_SEARCH_LEVEL) return;
const st = fs.statSync(dir);
if (!st.isDirectory()) return;
let subfiles = fs.readdirSync(dir);
let subdirs = [];
for (let item of subfiles) {
if (item === "." || item === "..") continue;
let fp = path.join(dir, item);
const subst = fs.statSync(fp);
if (subst.isFile() && item === CC_PLUGIN_JSON_STR) {
cc_config_json_list.push(dir);
return;
}
if (subst.isDirectory()) {
subdirs.push(fp);
}
}
for (let sd of subdirs) {
search_cc_config_json_levels(sd, depth + 1);
}
}
for (let searchPath of PROJ_SEARCH_PATHS) {
if (!fs.existsSync(searchPath)) {
console.log(`[searching plugins] directory ${searchPath} does not exist`);
continue;
}
search_cc_config_json_levels(searchPath, 1);
}
if (cc_config_json_list.length === 0) {
console.log("[searching plugins] no plugins found!");
process.exit(0)
}
for (let dir of cc_config_json_list) {
console.log(`[searching plugins] plugin dir found: ${dir}`)
}
function read_engine_version() {
const pkg = path.join(__dirname, '../../../package.json');
return require(pkg).version;
}
function parse_package_dependency(info) {
let pkgs = [];
for (let m of info.modules) {
if (m.platforms && m.platforms.indexOf(PLATFORM_NAME_FROM_CMAKE) < 0) {
continue;
}
pkgs.push({ target: m.target, depends: typeof m.depends === 'string' ? [m.depends] : (m.depends || []) });
}
return pkgs;
}
function get_property_variants(obj, ...names) {
for (let n of names) {
if (obj.hasOwnProperty(n)) {
return obj[n];
}
if (n.indexOf('_') >= 0) {
const k = n.replace(/_/g, '-');
if (obj.hasOwnProperty(k)) {
return obj[k];
}
}
if (n.indexOf('-') >= 0) {
const k = n.replace(/-/g, '_');
if (obj.hasOwnProperty(k)) {
return obj[k];
}
}
}
return undefined;
}
function test_enable_by_configurations(config) {
const support_platforms = get_property_variants(config, "platforms") || [];
const enabled_default = get_property_variants(config, "enable", "enabled");
const enable_all = enabled_default === undefined ? true : enabled_default;
const disable_all = (get_property_variants(config, "disable", "disabled") || false) || !enable_all;
const disabled_platforms = get_property_variants(config, "disable-by-platforms", "disabled-by-platforms") || [];
const engine_version_value = get_property_variants(config, "engine-version");
if (disable_all) {
// all disabled
console.log(` plugin is disabled.`);
return false;
}
if (support_platforms.length > 0 && support_platforms.indexOf(PLATFORM_NAME_FROM_CMAKE) < 0) {
// unsupported platform
console.log(` plugin is not supported by current platform ${PLATFORM_NAME_FROM_CMAKE}.`);
return false;
}
if (disabled_platforms.indexOf(PLATFORM_NAME_FROM_CMAKE) > -1) {
// disable by user settings
console.log(` plugin is disabled by setting.`);
return false;
}
const ENGINE_VERSION = read_engine_version().replace(/^(v|V)/, '');
try {
const version_filter = version_parser.parse(engine_version_value);
const version_valid = version_filter.match(ENGINE_VERSION);
if (!version_valid) {
console.warn(` Engine version '${ENGINE_VERSION}' mismatch '${engine_version_value}'`);
}
} catch (e) {
console.error(` Failed to parse 'engine-version', value: '${engine_version_value}'`);
console.error(e);
return false;
}
return true;
}
function validate_cc_plugin_json_format(tag, content) {
const field_required = (obj, field_name) => {
if (Object.hasOwnProperty(obj, field_name)) {
console.warn(`${tag} field '${field_name}' is not set`);
return false;
}
return true;
}
const required_fields = ["name", "version", "engine-version", "author", "description", "modules", "platforms"];
for (const f of required_fields) {
if (!field_required(content, f)) {
return false;
}
}
const modules = content["modules"];
if (modules.length == 0) {
console.warn(`${tag} modules field is empty`);
return false;
}
for (let m of modules) {
const mod_fields = ["target"];
for (const f of mod_fields) {
if (!field_required(m, f)) {
console.warn(`${tag} module field ${f} is not set`);
return false;
}
}
}
return true;
}
function add_search_path_suffix(dir, platform) {
if (platform.match(/^android/i)) {
return [`${dir}/android/\${ANDROID_ABI}`, `${dir}/android`];
} else if (platform.match(/^win/i)) {
return [`${dir}/windows/x86_64`, `${dir}/windows`];
} else if (platform.match(/^iphonesimulator/i)) {
return [`${dir}/iphonesimulator`, `${dir}/ios`];
} else if (platform.match(/^ios/i)) {
return [`${dir}/ios`];
} else if (platform.match(/^mac/i) || platform.match(/^darwin/i)) {
return [`${dir}/mac/\${CMAKE_SYSTEM_PROCESSOR}`, `${dir}/mac`];
} else {
console.warn(`Don't knowm suffix for '${platform}`)
return [];
}
}
console.log(`Engine version: ${read_engine_version()}`);
/// Generate Pre-AutoLoadPlugins.cmake
let output_lines = ["# plugins found & enabled in search path",
"# To disable automatic update of this file, set SKIP_SCAN_PLUGINS to ON.",
""];
for (let plugin_dir of cc_config_json_list) {
let load_plugins = [];
try {
let maybe_plugin_name = path.basename(plugin_dir);
console.log(`Parsing plugin directory ${maybe_plugin_name}`);
let cc_plugin_file = path.join(plugin_dir, CC_PLUGIN_JSON_STR);
let cc_plugin_content = fs.readFileSync(cc_plugin_file, { encoding: 'utf8' });
let cc_plugin_json = JSON.parse(cc_plugin_content);
if (!validate_cc_plugin_json_format(`Parsing module ${maybe_plugin_name}:`, cc_plugin_json)) {
continue;
}
if (!test_enable_by_configurations(cc_plugin_json)) {
console.log(` ${maybe_plugin_name} disabled by configuration`);
continue;
}
const plugin_name = cc_plugin_json.name;
const module_type = get_property_variants(cc_plugin_json, "module_type")
if (module_type !== undefined && module_type !== 'release') {
console.log(` plugin ${plugin_name} is not a release, should be include or add_subdirectory in dev env.`);
continue;
}
const packages = parse_package_dependency(cc_plugin_json);
const cc_project_dir = path.dirname(plugin_cmake_output_file);
let project_to_plugin_dir = path.relative(cc_project_dir, plugin_dir).replace(/\\/g, '/');
project_to_plugin_dir = `\${CC_PROJECT_DIR}/${project_to_plugin_dir}`;
const plugin_root_path_for_platform = add_search_path_suffix(project_to_plugin_dir, PLATFORM_NAME_FROM_CMAKE);
for (let pkg of packages) {
const [target_name, target_version] = pkg.target.split('@');
output_lines.push(`set(${target_name}_ROOT\n${plugin_root_path_for_platform.map(x => ` "${x}"`).join("\n")}\n)`, "");
output_lines.push(`list(APPEND CMAKE_FIND_ROOT_PATH \${${target_name}_ROOT})`)
load_plugins = load_plugins.concat([...pkg.depends, target_name + (target_version !== undefined ? '@' + target_version : '')]);
output_lines.push(`list(APPEND CC_REGISTERED_PLUGINS`);
output_lines = output_lines.concat(` ${target_name}`);
output_lines.push(`)`);
}
let plugin_names = load_plugins.map(x => x.split(/@/));
for (let plg of plugin_names) {
output_lines.push("");
if (plg[1] && plg.length > 0) {
output_lines.push(`find_package(${plg[0]} ${plg[1]}`);
} else {
output_lines.push(`find_package(${plg[0]}`);
}
output_lines.push(` REQUIRED`);
output_lines.push(` NAMES "${plg[0]}"`);
output_lines.push(`# NO_DEFAULT_PATH`);
output_lines.push(`)`);
}
if (packages.length > 0) {
console.log(` record plugin ${plugin_name}`);
} else {
console.log(` no sub module found`);
}
} catch (e) {
console.error(`Parsing plugin directory: ${plugin_dir}`)
console.error(e);
}
}
if (cc_config_json_list.length == 0) {
console.log(`Try unlink file ${out_file}`)
if (fs.existsSync(out_file)) {
fs.unlinkSync(out_file);
}
} else {
let old_content = null;
let new_content = output_lines.join("\n") + "\n";
if (fs.existsSync(plugin_cmake_output_file)) {
old_content = fs.readFileSync(plugin_cmake_output_file);
}
if (old_content !== new_content) {
fs.writeFileSync(plugin_cmake_output_file, output_lines.join("\n") + "\n", { encoding: 'utf8' });
}
}
process.exit(0);

38
cmake/scripts/utils.js Normal file
View File

@@ -0,0 +1,38 @@
const fs = require('fs');
function all_eql(a, b) {
if (a.length !== b.length) {
return false;
}
const l = a.length;
for (let i = 0; i < l; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
function equals_ignore_spaces(a, b) {
const lines_a = a.split('\n').map(x => x.trim());
const lines_b = b.split('\n').map(x => x.trim());
return all_eql(lines_a, lines_b);
}
function writeIfDifferent(file, data, args) {
if (fs.existsSync(file)) {
let content = fs.readFileSync(file, args).toString(args.encoding);
if (equals_ignore_spaces(content, data)) {
console.log(`Skip update ${file}`);
return;
}
}
fs.writeFileSync(file, data, args);
console.log(` write to file ${file}`);
}
exports.writeIfDifferent = writeIfDifferent;