mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 02:54:11 +08:00

* chore: move tns-core-modules to nativescript-core * chore: preparing compat generate script * chore: add missing definitions * chore: no need for http-request to be private * chore: packages chore * test: generate tests for tns-core-modules * chore: add anroid module for consistency * chore: add .npmignore * chore: added privateModulesWhitelist * chore(webpack): added bundle-entry-points * chore: scripts * chore: tests changed to use @ns/core * test: add scoped-packages test project * test: fix types * test: update test project * chore: build scripts * chore: update build script * chore: npm scripts cleanup * chore: make the compat pgk work with old wp config * test: generate diff friendly tests * chore: create barrel exports * chore: move files after rebase * chore: typedoc config * chore: compat mode * chore: review of barrels * chore: remove tns-core-modules import after rebase * chore: dev workflow setup * chore: update developer-workflow * docs: experiment with API extractor * chore: api-extractor and barrel exports * chore: api-extractor configs * chore: generate d.ts rollup with api-extractor * refactor: move methods inside Frame * chore: fic tests to use Frame static methods * refactor: create Builder class * refactor: use Builder class in tests * refactor: include Style in ui barrel * chore: separate compat build script * chore: fix tslint errors * chore: update NATIVESCRIPT_CORE_ARGS * chore: fix compat pack * chore: fix ui-test-app build with linked modules * chore: Application, ApplicationSettings, Connectivity and Http * chore: export Trace, Profiling and Utils * refactor: Static create methods for ImageSource * chore: fix deprecated usages of ImageSource * chore: move Span and FormattedString to ui * chore: add events-args and ImageSource to index files * chore: check for CLI >= 6.2 when building for IOS * chore: update travis build * chore: copy Pod file to compat package * chore: update error msg ui-tests-app * refactor: Apply suggestions from code review Co-Authored-By: Martin Yankov <m.i.yankov@gmail.com> * chore: typings and refs * chore: add missing d.ts files for public API * chore: adress code review FB * chore: update api-report * chore: dev-workflow for other apps * chore: api update * chore: update api-report
215 lines
6.5 KiB
TypeScript
215 lines
6.5 KiB
TypeScript
// regex that contains all symbols applicable for expression used to AI detect an expression.
|
|
const expressionSymbolsRegex = /[\+\-\*\/%\?:<>=!\|&\(\)^~]/;
|
|
|
|
export module bindingConstants {
|
|
export const sourceProperty = "sourceProperty";
|
|
export const targetProperty = "targetProperty";
|
|
export const expression = "expression";
|
|
export const twoWay = "twoWay";
|
|
export const source = "source";
|
|
export const bindingValueKey = "$value";
|
|
export const parentValueKey = "$parent";
|
|
export const parentsValueKey = "$parents";
|
|
export const newPropertyValueKey = "$newPropertyValue";
|
|
}
|
|
|
|
const hasEqualSignRegex = /=+/;
|
|
const equalSignComparisionOperatorsRegex = /(==|===|>=|<=|!=|!==)/;
|
|
|
|
// this regex is used to search for all instaces of '$parents[]' within an expression
|
|
export const parentsRegex = /\$parents\s*\[\s*(['"]*)\w*\1\s*\]/g;
|
|
|
|
function isNamedParam(value) {
|
|
const equalSignIndex = value.search(hasEqualSignRegex);
|
|
if (equalSignIndex > -1) {
|
|
const equalSignSurround = value.substr(equalSignIndex > 0 ? equalSignIndex - 1 : 0, 3);
|
|
if (equalSignSurround.search(equalSignComparisionOperatorsRegex) === -1) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function areNamedParams(params: Array<any>) {
|
|
for (let i = 0; i < params.length; i++) {
|
|
if (isNamedParam(params[i])) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const namedParamConstants = {
|
|
propName: "propName",
|
|
propValue: "propValue"
|
|
};
|
|
|
|
function getPropertyNameValuePair(param, knownOptions, callback) {
|
|
let nameValuePair = {};
|
|
let propertyName = param.substr(0, param.indexOf("=")).trim();
|
|
const propertyValue = param.substr(param.indexOf("=") + 1).trim();
|
|
if (knownOptions) {
|
|
if (!propertyName) {
|
|
propertyName = knownOptions.defaultProperty;
|
|
}
|
|
else {
|
|
propertyName = propertyName in knownOptions ? propertyName : null;
|
|
}
|
|
}
|
|
|
|
if (propertyName) {
|
|
if (callback) {
|
|
nameValuePair = callback(propertyName, propertyValue);
|
|
}
|
|
else {
|
|
nameValuePair[namedParamConstants.propName] = propertyName;
|
|
nameValuePair[namedParamConstants.propValue] = propertyValue;
|
|
}
|
|
|
|
return nameValuePair;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function parseNamedProperties(parameterList, knownOptions, callback) {
|
|
const result = {};
|
|
let nameValuePair;
|
|
for (let i = 0; i < parameterList.length; i++) {
|
|
nameValuePair = getPropertyNameValuePair(parameterList[i], knownOptions, callback);
|
|
if (nameValuePair) {
|
|
result[nameValuePair[namedParamConstants.propName]] = nameValuePair[namedParamConstants.propValue];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function getParamsArray(value: string) {
|
|
const result = [];
|
|
let skipComma = 0;
|
|
let indexReached = 0;
|
|
let singleQuoteBlock = false;
|
|
let doubleQuoteBlock = false;
|
|
|
|
for (let i = 0; i < value.length; i++) {
|
|
if (value[i] === "\"") {
|
|
doubleQuoteBlock = !doubleQuoteBlock;
|
|
}
|
|
|
|
if (value[i] === "'") {
|
|
singleQuoteBlock = !singleQuoteBlock;
|
|
}
|
|
|
|
if (value[i] === "(" || value[i] === "[") {
|
|
skipComma++;
|
|
}
|
|
|
|
if (value[i] === ")" || value[i] === "]") {
|
|
skipComma--;
|
|
}
|
|
|
|
if (value[i] === "," && skipComma === 0 && !(singleQuoteBlock || doubleQuoteBlock)) {
|
|
result.push(value.substr(indexReached, i - indexReached));
|
|
indexReached = i + 1;
|
|
}
|
|
}
|
|
|
|
result.push(value.substr(indexReached));
|
|
|
|
return result;
|
|
}
|
|
|
|
function isExpression(expression: string): boolean {
|
|
if (expression.search(expressionSymbolsRegex) > -1) {
|
|
const parentsMatches = expression.match(parentsRegex);
|
|
if (parentsMatches) {
|
|
const restOfExpression = expression.substr(expression.indexOf(parentsMatches[0]) + parentsMatches[0].length);
|
|
// no more expression regognition symbols so it is safe for sourceProperty
|
|
if (!(restOfExpression.search(expressionSymbolsRegex) > -1)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export function getBindingOptions(name: string, value: string): any {
|
|
let namedParams = [];
|
|
const params = getParamsArray(value);
|
|
if (!areNamedParams(params)) {
|
|
if (params.length === 1) {
|
|
const trimmedValue = params[0].trim();
|
|
let sourceProp;
|
|
if (isExpression(trimmedValue)) {
|
|
sourceProp = bindingConstants.bindingValueKey;
|
|
namedParams.push(bindingConstants.expression + " = " + trimmedValue);
|
|
}
|
|
else {
|
|
sourceProp = trimmedValue;
|
|
}
|
|
namedParams.push(bindingConstants.sourceProperty + " = " + sourceProp);
|
|
|
|
namedParams.push(bindingConstants.twoWay + " = true");
|
|
}
|
|
else {
|
|
namedParams.push(bindingConstants.sourceProperty + " = " + params[0].trim());
|
|
namedParams.push(bindingConstants.expression + " = " + params[1].trim());
|
|
const twoWay = params[2] ? params[2].toLowerCase().trim() === "true" : true;
|
|
namedParams.push(bindingConstants.twoWay + " = " + twoWay);
|
|
}
|
|
}
|
|
else {
|
|
namedParams = params;
|
|
}
|
|
|
|
const bindingPropertyHandler = function (prop, value) {
|
|
const result = {};
|
|
result[namedParamConstants.propName] = prop;
|
|
if (prop === bindingConstants.twoWay) {
|
|
// create a real boolean value
|
|
if (value === "true") {
|
|
result[namedParamConstants.propValue] = true;
|
|
}
|
|
else {
|
|
result[namedParamConstants.propValue] = false;
|
|
}
|
|
}
|
|
else {
|
|
result[namedParamConstants.propValue] = value;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
const bindingOptionsParameters = parseNamedProperties(namedParams, xmlBindingProperties, bindingPropertyHandler);
|
|
const bindOptions = {
|
|
targetProperty: name
|
|
};
|
|
|
|
for (let prop in bindingOptionsParameters) {
|
|
if (bindingOptionsParameters.hasOwnProperty(prop)) {
|
|
bindOptions[prop] = bindingOptionsParameters[prop];
|
|
}
|
|
}
|
|
|
|
if (bindOptions[bindingConstants.twoWay] === undefined) {
|
|
bindOptions[bindingConstants.twoWay] = true;
|
|
}
|
|
|
|
return bindOptions;
|
|
}
|
|
|
|
const xmlBindingProperties = {
|
|
sourceProperty: true,
|
|
expression: true,
|
|
twoWay: true,
|
|
source: true,
|
|
defaultProperty: bindingConstants.sourceProperty
|
|
};
|