1157 lines
28 KiB
JavaScript
1157 lines
28 KiB
JavaScript
//
|
|
//#region Imports ...
|
|
const XValueTools = require('../tools/x-value.tools');
|
|
const XTypeDectorTools = require('../tools/x-type-detector.tools');
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constants ...
|
|
/**
|
|
* base usefull Expression keys ...
|
|
*/
|
|
const ExpressionKeys = {
|
|
From: 'from',
|
|
Enum: 'enum',
|
|
Type: 'type',
|
|
Class: 'class',
|
|
Const: 'const',
|
|
Export: 'export',
|
|
Import: 'import',
|
|
Public: 'public',
|
|
Exports: 'exports',
|
|
Private: 'private',
|
|
Extends: 'extends',
|
|
Abstract: 'abstract',
|
|
Interface: 'interface',
|
|
Implements: 'implements',
|
|
IGNORED_KEY: '|$IGNORED_KEY$|',
|
|
}
|
|
|
|
/**
|
|
* all available content types for raw contents ...
|
|
*/
|
|
const ContentTypes = {
|
|
Array: 'array',
|
|
Object: 'object',
|
|
String: 'string',
|
|
Unknown: 'unknown',
|
|
NonString: 'non_string',
|
|
NonStringSelf: 'non_string_self',
|
|
NonStringHasClosure: 'non_string_has_closure',
|
|
NonStringHasProperty: 'non_string_has_property',
|
|
}
|
|
|
|
/**
|
|
* ng files decorator types ...
|
|
*/
|
|
const DecoratorTypes = {
|
|
Module: 'module',
|
|
Unknown: 'unknown',
|
|
Component: 'component',
|
|
Directive: 'directive',
|
|
Injectable: 'injectable'
|
|
}
|
|
|
|
/**
|
|
* all available decorator parts ...
|
|
*/
|
|
const DecoratorParts = {
|
|
Styles: 'styles',
|
|
Imports: 'imports',
|
|
Exports: 'exports',
|
|
Selector: 'selector',
|
|
Template: 'template',
|
|
Providers: 'providers',
|
|
StyleUrls: 'styleUrls',
|
|
Bootstrap: 'bootstrap',
|
|
ProvidedIn: 'providedIn',
|
|
TemplateUrl: 'templateUrl',
|
|
Declarations: 'declarations',
|
|
EntryComponents: 'entryComponents',
|
|
ChangeDetection: 'changeDetection',
|
|
}
|
|
|
|
const ModuleDecoratorValidParts = [
|
|
DecoratorParts.Imports,
|
|
DecoratorParts.Exports,
|
|
DecoratorParts.Bootstrap,
|
|
DecoratorParts.Providers,
|
|
DecoratorParts.Declarations,
|
|
DecoratorParts.EntryComponents,
|
|
];
|
|
|
|
const ComponentDecoratorValidParts = [
|
|
DecoratorParts.Selector,
|
|
DecoratorParts.Template,
|
|
DecoratorParts.TemplateUrl,
|
|
DecoratorParts.Styles,
|
|
DecoratorParts.StyleUrls,
|
|
DecoratorParts.ChangeDetection,
|
|
];
|
|
|
|
const DirectiveDecoratorValidParts = [
|
|
DecoratorParts.Selector
|
|
];
|
|
|
|
const InjectableDecoratorValidParts = [
|
|
DecoratorParts.ProvidedIn
|
|
];
|
|
|
|
/**
|
|
* all available types for decorator parts ...
|
|
*/
|
|
const DecoratorPartTypes = {
|
|
Array: 'array',
|
|
String: 'string'
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Content Type ...
|
|
/**
|
|
* check a proposed type is valid content type or not ...
|
|
*
|
|
* @param {string} type the proposed type to check ...
|
|
* @returns
|
|
*/
|
|
function isValidContentType(type = '') {
|
|
//
|
|
// Validate Args ...
|
|
if (!XValueTools.isValidArg(type)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Normalize Arg ...
|
|
type = type.trim();
|
|
|
|
//
|
|
let result = Object.values(ContentTypes).includes(type);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* retrieve a content type ...
|
|
*
|
|
* @param {string} content a content which going to check ...
|
|
* @returns a member of ContentTypes const ...
|
|
*/
|
|
function getContentType(content = '') {
|
|
//
|
|
// Validate Args ...
|
|
if (!XValueTools.isValidArg(content)) {
|
|
return ContentTypes.Unknown;
|
|
}
|
|
|
|
//
|
|
if (XValueTools.isSurroundedObject(content)) {
|
|
return ContentTypes.Object;
|
|
} else if (XValueTools.isSurroundedArray(content)) {
|
|
return ContentTypes.Array;
|
|
} else if (XValueTools.isSurroundedString(content)) {
|
|
return ContentTypes.String;
|
|
} else if (
|
|
content.includes(':') ||
|
|
content.includes('=')
|
|
) {
|
|
//
|
|
if (
|
|
content.includes('{') &&
|
|
content.includes('}')
|
|
) {
|
|
return ContentTypes.NonStringHasClosure;
|
|
} else if (
|
|
content.includes('[') &&
|
|
content.includes(']')
|
|
) {
|
|
return ContentTypes.NonStringHasClosure;
|
|
} else {
|
|
//
|
|
const colons = XValueTools.findAllIndexes(':', content);
|
|
if (
|
|
!XValueTools.hasChildArray(colons) ||
|
|
colons.length === 1
|
|
) {
|
|
return ContentTypes.NonStringSelf
|
|
}
|
|
|
|
//
|
|
return ContentTypes.NonStringHasProperty;
|
|
}
|
|
} else {
|
|
return ContentTypes.NonString;
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Decorator ...
|
|
/**
|
|
* determines a property name is valid in Decorator Object or not ...
|
|
*
|
|
* @param {string} part decorator object property name ...
|
|
* @returns is it valid or not ...
|
|
*/
|
|
function isValidDecoratorPart(part = DecoratorParts.Imports) {
|
|
//
|
|
// Validate Args ...
|
|
if (!XValueTools.isValidArg(part)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
result = Object.values(DecoratorParts).includes(part);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* determines a proposed value is valid decorator types or not ...
|
|
*
|
|
* @param {string} type a child of DecoratorTypes ...
|
|
* @returns proposed value is valid type or not ...
|
|
*/
|
|
function isValidDecoratorType(type = DecoratorTypes.Unknown) {
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!XValueTools.isValidArg(type) ||
|
|
type === DecoratorTypes.Unknown
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
result = Object.values(DecoratorTypes).includes(type);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* determines a part of decorator is valid for specified decorator type or not ...
|
|
*
|
|
* @param {string} part specified proposed part of DecoratorDescriptor ...
|
|
* @param {string} type specified proposed DecoratorType ...
|
|
* @returns part is valid for type or not ...
|
|
*/
|
|
function isValidDecoratorPartForType(
|
|
part = DecoratorParts.Imports,
|
|
type = DecoratorTypes.Unknown
|
|
) {
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!isValidDecoratorType(type) ||
|
|
!isValidDecoratorPart(part) ||
|
|
!XValueTools.isValidArg(part) ||
|
|
!XValueTools.isValidArg(type)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
let result = false;
|
|
switch (type) {
|
|
//
|
|
case DecoratorTypes.Module:
|
|
result = ModuleDecoratorValidParts
|
|
.includes(part);
|
|
break;
|
|
|
|
//
|
|
case DecoratorTypes.Component:
|
|
result = ComponentDecoratorValidParts
|
|
.includes(part);
|
|
break;
|
|
|
|
//
|
|
case DecoratorTypes.Directive:
|
|
result = DirectiveDecoratorValidParts
|
|
.includes(part);
|
|
break;
|
|
|
|
//
|
|
case DecoratorTypes.Injectable:
|
|
result = InjectableDecoratorValidParts
|
|
.includes(part);
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* retrieve decorator specific part type ...
|
|
*
|
|
* @param {string} part Decorator Object property name ...
|
|
* @returns decorator part type ...
|
|
*/
|
|
function getDecoratorPartType(part) {
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!isValidDecoratorPart(part) &&
|
|
!XValueTools.isValidArg(part)
|
|
) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
let result = '';
|
|
|
|
//
|
|
switch (part) {
|
|
//
|
|
// Array Parts ...
|
|
case DecoratorParts.Styles:
|
|
case DecoratorParts.Imports:
|
|
case DecoratorParts.Exports:
|
|
case DecoratorParts.Providers:
|
|
case DecoratorParts.StyleUrls:
|
|
case DecoratorParts.Bootstrap:
|
|
case DecoratorParts.Declarations:
|
|
case DecoratorParts.EntryComponents:
|
|
result = DecoratorPartTypes.Array;
|
|
break;
|
|
|
|
//
|
|
// String Parts ...
|
|
case DecoratorParts.Selector:
|
|
case DecoratorParts.Template:
|
|
case DecoratorParts.ProvidedIn:
|
|
case DecoratorParts.TemplateUrl:
|
|
case DecoratorParts.ChangeDetection:
|
|
result = DecoratorPartTypes.String;
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (!XValueTools.isValidArg(result)) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* determines an specific part of decorator is in array type or not ...
|
|
*
|
|
* @param {string} part Decorator Object property name ...
|
|
* @returns
|
|
*/
|
|
function isDecoratorPartArray(part) {
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!isValidDecoratorPart(part) ||
|
|
!XValueTools.isValidArg(part)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Retrieve Decorator Part Type ...
|
|
const type = getDecoratorPartType(part);
|
|
if (!XValueTools.isValidArg(type)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const result = type === DecoratorPartTypes.Array;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* determines an specific part of decorator is in string type or not ...
|
|
*
|
|
* @param {string} part Decorator Object property name ...
|
|
* @returns
|
|
*/
|
|
function isDecoratorPartString(part) {
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!isValidDecoratorPart(part) ||
|
|
!XValueTools.isValidArg(part)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Retrieve Decorator Part Type ...
|
|
const type = getDecoratorPartType(part);
|
|
if (!XValueTools.isValidArg(type)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const result = type === DecoratorPartTypes.String;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* extract specified decorator part values from given content ...
|
|
*
|
|
* @param {string} part the part which reuire to extract from given text, which usually must be DecoratorParts value ...
|
|
* @param {string} content given content to tokenize ...
|
|
* @param {boolean} isArray determines the given token value is array or not ...
|
|
* @returns parsed token's value(s) ...
|
|
*/
|
|
function extractDecoratorPart(
|
|
part = '',
|
|
content = '',
|
|
) {
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!isValidDecoratorPart(part) ||
|
|
!XValueTools.isValidArg(part) ||
|
|
!XValueTools.isValidArg(content)
|
|
) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
const partType = getDecoratorPartType(part);
|
|
const isArray = isDecoratorPartArray(part);
|
|
|
|
//
|
|
let listSeparator = ',';
|
|
let end = isArray ? ']' : '\'';
|
|
let start = isArray ? '[' : '\'';
|
|
|
|
//
|
|
// find token index ...
|
|
let partIndex = content.indexOf(part);
|
|
if (partIndex === -1) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
content = content.substring(partIndex);
|
|
partIndex = content.indexOf(part);
|
|
if (part === DecoratorParts.Template) {
|
|
//
|
|
const tIndex = content.indexOf(DecoratorParts.TemplateUrl);
|
|
if (partIndex === tIndex) {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
//
|
|
// find start and end index ...
|
|
let startIndex = content.indexOf(start, partIndex) + 1;
|
|
let endIndex = content.indexOf(end, startIndex) - 1;
|
|
|
|
//
|
|
// Try to fix string interpolation ...
|
|
if (!isArray && (startIndex < 0 || endIndex < 0)) {
|
|
startIndex = content.indexOf('`', partIndex + part.length);
|
|
endIndex = content.indexOf('`', startIndex + 1);
|
|
}
|
|
|
|
//
|
|
// Try to fix Object ...
|
|
if (!isArray && (startIndex < 0 || endIndex < 0)) {
|
|
startIndex = part.length;
|
|
endIndex = content.indexOf('`', startIndex + 1) > 0 ?
|
|
content.indexOf('`', startIndex + 1) :
|
|
content.indexOf(',', startIndex + 1) > 0 ?
|
|
content.indexOf(',', startIndex + 1) :
|
|
content.indexOf('}', startIndex + 1) > 0 ?
|
|
content.indexOf('}', startIndex + 1) :
|
|
-1;
|
|
}
|
|
|
|
if (startIndex === -1 || endIndex === -1) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
// define regExps for clearing content ...
|
|
const regExp = new RegExp(
|
|
' |\n|',
|
|
'g'
|
|
);
|
|
|
|
//
|
|
// Extract required content and remove all non required contents from it ...
|
|
let resultContent = content
|
|
.substr(startIndex, (endIndex - startIndex) + 1);
|
|
if (isArray) {
|
|
resultContent = resultContent.replace(regExp, '').trim();
|
|
} else {
|
|
resultContent = resultContent
|
|
.replace(',', '')
|
|
.replace('}', '')
|
|
.replace(':', '').trim();
|
|
}
|
|
if (!XValueTools.isValidArg(resultContent)) {
|
|
return isArray ? [] : '';
|
|
}
|
|
|
|
//
|
|
// check content is a list or not ...
|
|
const isMultipleDeclaration = resultContent.includes(listSeparator);
|
|
|
|
//
|
|
// prepare result ...
|
|
const outOfClosedIndexes = XValueTools.findAllIndexesOutOfCloseds(listSeparator, resultContent);
|
|
const outOfClosedParts = XValueTools.sliceContent(outOfClosedIndexes, resultContent);
|
|
let result = isMultipleDeclaration ?
|
|
isArray ?
|
|
[...outOfClosedParts] :
|
|
resultContent :
|
|
isArray ?
|
|
[resultContent] :
|
|
resultContent;
|
|
result = isArray ?
|
|
result.filter(r => r.length > 0) :
|
|
result.trim();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Parsers ...
|
|
/**
|
|
* parse given content and extracts it's XKeyValueDescriptor childs ...
|
|
*
|
|
* @param {string} content a proposed content to parse ...
|
|
* @param {boolean} isInterface force parser to parse object content as an interface content, default is false ...
|
|
* @returns parsed collection of XKeyValueDescriptor object instance ...
|
|
*/
|
|
function parseContent(
|
|
content = '',
|
|
isInterface = false
|
|
) {
|
|
//
|
|
// Validate Args ...
|
|
if (!XValueTools.isValidArg(content)) {
|
|
return undefined;
|
|
}
|
|
|
|
//
|
|
// Define Result Structure ...
|
|
let result = [{
|
|
key: '',
|
|
value: undefined,
|
|
type: ContentTypes.Unknown,
|
|
}];
|
|
result.pop();
|
|
|
|
//
|
|
const contentType = getContentType(content);
|
|
if (isValidContentType(contentType)) {
|
|
result.type = contentType;
|
|
}
|
|
|
|
//
|
|
switch (contentType) {
|
|
//
|
|
// parse array contents ...
|
|
case ContentTypes.Array:
|
|
result = parseProperties(
|
|
content,
|
|
isInterface
|
|
);
|
|
break;
|
|
|
|
//
|
|
//parse object content ...
|
|
case ContentTypes.Object:
|
|
result = parseProperties(
|
|
content,
|
|
isInterface
|
|
);
|
|
break;
|
|
|
|
//
|
|
// add content it self ...
|
|
case ContentTypes.String:
|
|
result.push({
|
|
type: contentType,
|
|
value: parseString(content),
|
|
key: ExpressionKeys.IGNORED_KEY,
|
|
});
|
|
break;
|
|
|
|
//
|
|
// add content it self without anything ...
|
|
case ContentTypes.NonString:
|
|
result.push({
|
|
value: content,
|
|
type: contentType,
|
|
key: ExpressionKeys.IGNORED_KEY,
|
|
});
|
|
break;
|
|
|
|
//
|
|
// parse just one property ...
|
|
case ContentTypes.NonStringSelf:
|
|
break;
|
|
|
|
//
|
|
// parse properties more than one ...
|
|
case ContentTypes.NonStringHasProperty:
|
|
break;
|
|
|
|
//
|
|
// parse key and values ...
|
|
case ContentTypes.NonStringHasClosure:
|
|
break;
|
|
|
|
//
|
|
case ContentTypes.Unknown:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* parse properties of given content and extract it's values ...
|
|
*
|
|
* @param {string} content the content which going to parse ...
|
|
* @param {boolean} isInterface determines the props is for interface or not ...
|
|
* @returns parse props as a collection of key/value/type array ...
|
|
*/
|
|
function parseProperties(
|
|
content = '',
|
|
isInterface = false
|
|
) {
|
|
//
|
|
let result = [{
|
|
key: '',
|
|
value: undefined,
|
|
type: ContentTypes.Unknown,
|
|
}];
|
|
result.pop();
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (!XValueTools.isValidArg(content)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Clear Surrounded Chars ...
|
|
if (XValueTools.isSurroundedArray(content)) {
|
|
content = XValueTools.clearArraySurround(content);
|
|
} else if (XValueTools.isSurroundedObject(content)) {
|
|
content = XValueTools.clearObjectSurround(content);
|
|
}
|
|
|
|
//
|
|
let individualColonIndexes = [];
|
|
if (!!isInterface) {
|
|
individualColonIndexes = XValueTools.findAllIndexesOutOfCloseds(';', content);
|
|
} else {
|
|
individualColonIndexes = XValueTools.findAllIndexesOutOfCloseds(',', content);
|
|
}
|
|
|
|
//
|
|
let parts = [];
|
|
if (XValueTools.hasChildArray(individualColonIndexes)) {
|
|
parts = XValueTools
|
|
.sliceContent(individualColonIndexes, content)
|
|
.filter(r => XValueTools.isValidArg(r));
|
|
} else {
|
|
parts.push(content);
|
|
}
|
|
|
|
//
|
|
for (const part of parts) {
|
|
//
|
|
const partType = getContentType(part);
|
|
|
|
//
|
|
const individualSemicolonIndexes = XValueTools
|
|
.findAllIndexesOutOfCloseds(
|
|
[':', '='],
|
|
part
|
|
);
|
|
|
|
//
|
|
if (!XValueTools.hasChildArray(individualSemicolonIndexes)) {
|
|
//
|
|
const parsedContent = parseContent(
|
|
part,
|
|
isInterface
|
|
) || [];
|
|
if (partType === ContentTypes.Object) {
|
|
result.push({
|
|
type: partType,
|
|
value: parsedContent,
|
|
key: ExpressionKeys.IGNORED_KEY,
|
|
});
|
|
} else {
|
|
result.push(...parsedContent);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
const sepIndex = individualSemicolonIndexes[0];
|
|
const keyVal = XValueTools.sliceContent([sepIndex], part);
|
|
if (
|
|
keyVal.length !== 2 ||
|
|
!XValueTools.hasChildArray(keyVal)
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
let parsedValue = parseContent(
|
|
keyVal[1],
|
|
isInterface
|
|
);
|
|
let type = parsedValue.type || getContentType(keyVal[1]);
|
|
if (
|
|
parsedValue.length === 1 &&
|
|
XValueTools.hasChildArray(parsedValue) &&
|
|
parsedValue[0].key === ExpressionKeys.IGNORED_KEY &&
|
|
!Object.values([ContentTypes.Array, ContentTypes.Object]).includes(parsedValue[0].type)
|
|
) {
|
|
parsedValue = parsedValue[0].value;
|
|
}
|
|
|
|
//
|
|
result.push({
|
|
type,
|
|
key: keyVal[0],
|
|
value: parsedValue
|
|
});
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* parse a content as string ...
|
|
*
|
|
* @param {string} content the content which going to parsed ...
|
|
* @returns parsed string content ...
|
|
*/
|
|
function parseString(content = '') {
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!XValueTools.isValidArg(content) ||
|
|
!XValueTools.isSurroundedString(content)
|
|
) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
if (
|
|
content.startsWith('\'') &&
|
|
(
|
|
XValueTools.endsWidth('\'', content) ||
|
|
XValueTools.endsWidth('\',', content) ||
|
|
XValueTools.endsWidth('\';', content) ||
|
|
XValueTools.endsWidth('\'\n', content)
|
|
)
|
|
) {
|
|
//
|
|
const removeFromLastLength = XValueTools.endsWidth('\'', content) ?
|
|
1 :
|
|
XValueTools.endsWidth('\',', content) ||
|
|
XValueTools.endsWidth('\';', content) ||
|
|
XValueTools.endsWidth('\'\n', content) ?
|
|
2 :
|
|
0;
|
|
|
|
//
|
|
content = content.substring(1, content.length - removeFromLastLength);
|
|
content = XValueTools.surroundBy('\"', content);
|
|
} else if (
|
|
content.startsWith('`') &&
|
|
(
|
|
XValueTools.endsWidth('\`', content) ||
|
|
XValueTools.endsWidth('\`,', content) ||
|
|
XValueTools.endsWidth('\`;', content) ||
|
|
XValueTools.endsWidth('\`\n', content)
|
|
)
|
|
) {
|
|
content = XValueTools.surroundBy('\"', content);
|
|
}
|
|
|
|
//
|
|
return content;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Expressions ...
|
|
function toExpression(content) {
|
|
//
|
|
let result = '';
|
|
const isKeyValueType = XValueTools.isKeyValueType(content);
|
|
if (!isKeyValueType) {
|
|
//
|
|
const isContentArray = XTypeDectorTools.isArray(content);
|
|
if (isContentArray) {
|
|
//
|
|
const contentResults = [''];
|
|
contentResults.pop();
|
|
|
|
//
|
|
for (const contentChild of content) {
|
|
//
|
|
const contentResult = toExpression(contentChild);
|
|
contentResults.push(contentResult);
|
|
}
|
|
|
|
//
|
|
result += '[\n' + contentResults.join(',\n') + '\n]';
|
|
} else {
|
|
result += content;
|
|
}
|
|
} else {
|
|
//
|
|
// Retrieve Type ...
|
|
const keyValType = content.type || ContentTypes.Unknown;
|
|
|
|
//
|
|
let contentResult = '';
|
|
switch (keyValType) {
|
|
//
|
|
// String ...
|
|
case ContentTypes.String:
|
|
//
|
|
let surroundSymbol = content.value.charAt(0);
|
|
contentResult = XValueTools.clearSurround(surroundSymbol, content.value);
|
|
|
|
//
|
|
surroundSymbol = contentResult.charAt(0) || '';
|
|
if (surroundSymbol !== '\'' && surroundSymbol !== '`') {
|
|
contentResult = XValueTools.surroundBy('\'', contentResult);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// NonString ...
|
|
case ContentTypes.NonString:
|
|
contentResult = content.value;
|
|
break;
|
|
|
|
//
|
|
// Array ...
|
|
case ContentTypes.Array:
|
|
//
|
|
const arrayResult = [''];
|
|
arrayResult.pop();
|
|
|
|
//
|
|
if (XTypeDectorTools.isString(content.value)) {
|
|
//
|
|
const normalContentValue = XValueTools.toNormalArray(content.value);
|
|
content.value = [
|
|
...normalContentValue
|
|
]
|
|
}
|
|
for (const arrayChild of content.value) {
|
|
//
|
|
const arrayChildExp = toExpression(arrayChild);
|
|
arrayResult.push(arrayChildExp);
|
|
}
|
|
|
|
//
|
|
// TODO: create a way to handle array or objects childs for join ...
|
|
let arrayResultContent = '';
|
|
for (let i = 0; i < arrayResult.length; i++) {
|
|
//
|
|
const nextResult = arrayResult[i + 1];
|
|
arrayResultContent += arrayResult[i] + (
|
|
i < arrayResult.length - 1 ?
|
|
(XValueTools.isSurroundedArray(nextResult) ||
|
|
XValueTools.isSurroundedObject(nextResult)) ?
|
|
',\n' :
|
|
', ' :
|
|
''
|
|
);
|
|
}
|
|
|
|
//
|
|
contentResult = '[\n' + arrayResultContent + '\n]';
|
|
break;
|
|
|
|
//
|
|
// Object ...
|
|
case ContentTypes.Object:
|
|
//
|
|
let objectResult = '{\n';
|
|
|
|
//
|
|
for (let i = 0; i < content.value.length; i++) {
|
|
//
|
|
const arrayChild = content.value[i];
|
|
const arrayChildExp = toExpression(arrayChild);
|
|
objectResult += (
|
|
arrayChild.key !== ExpressionKeys.IGNORED_KEY ?
|
|
arrayChild.key +
|
|
': ' :
|
|
''
|
|
) +
|
|
arrayChildExp +
|
|
(
|
|
i === content.value.length - 1 ?
|
|
'' :
|
|
',\n'
|
|
);
|
|
}
|
|
|
|
//
|
|
objectResult += '\n}';
|
|
|
|
//
|
|
contentResult = objectResult;
|
|
break;
|
|
}
|
|
|
|
//
|
|
result += contentResult;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Extractors ...
|
|
/**
|
|
* extract all occurance indexes of an identifier inside a content ...
|
|
*
|
|
* @param {string} identifier the value which going to search ...
|
|
* @param {string} content the content is going to searched for value ...
|
|
* @returns a collection of occurance indexes ...
|
|
*/
|
|
function extractIdentifierIndexes(
|
|
identifier = '',
|
|
content = '') {
|
|
//
|
|
// Prepare Result ...
|
|
let result = [0];
|
|
result.pop();
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!XValueTools.isValidArg(content) ||
|
|
!XValueTools.isValidArg(identifier)
|
|
) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Identifiers ...
|
|
result = XValueTools.
|
|
findAllIndexes(
|
|
identifier,
|
|
content
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* check an index of an identifier inside a content is same as identifier or not ...
|
|
*
|
|
* @param {string} identifier the value which going to search ...
|
|
* @param {number} index the item proposed index on content ...
|
|
* @param {string} content the content is going to searched for value ...
|
|
* @returns is it match identifier or not ...
|
|
*/
|
|
function validateIdentifierInContent(
|
|
identifier = '',
|
|
index = -1,
|
|
content = ''
|
|
) {
|
|
//
|
|
// Prepare Result ...
|
|
let result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!XValueTools.isValidArg(content) ||
|
|
!XValueTools.isValidArg(identifier)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Normalize Index ...
|
|
index = index < 0 ? 0 : index > content.length ? content.length : index;
|
|
|
|
//
|
|
//
|
|
// Check Type after befre content ...
|
|
let startIndex = index - 1;
|
|
let endIndex = index + identifier.length + 1;
|
|
const tIdentifier = content.substring(startIndex, endIndex).trim();
|
|
result = tIdentifier === identifier;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* extract all occurance indexes of an identifier inside a content and Validate them ...
|
|
*
|
|
* @param {string} identifier the value which going to search ...
|
|
* @param {string} content the content is going to searched for value ...
|
|
* @returns a collection of occurance indexes ...
|
|
*/
|
|
function extractValidIdentifierIndexes(
|
|
identifier = '',
|
|
content = ''
|
|
) {
|
|
//
|
|
// Prepare Result ...
|
|
let result = [0];
|
|
result.pop();
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
!XValueTools.isValidArg(content) ||
|
|
!XValueTools.isValidArg(identifier)
|
|
) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Identifier Indexes ...
|
|
result = extractIdentifierIndexes(
|
|
identifier,
|
|
content
|
|
);
|
|
|
|
//
|
|
// Filter result to get Valid Identifiers ...
|
|
result = result.filter(i => validateIdentifierInContent
|
|
(
|
|
identifier,
|
|
i,
|
|
content
|
|
)
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* determines a content expression starter is exported or not ...
|
|
*
|
|
* @param {number} index start index for checking export ...
|
|
* @param {string} content the content which reuired to check ...
|
|
* @returns is exported or not ...
|
|
*/
|
|
function checkIsExported(
|
|
index = 0,
|
|
content = ''
|
|
) {
|
|
//
|
|
// Prepare Result ...
|
|
let result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (!XValueTools.isValidArg(content)) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalize Index ...
|
|
index = index < 0 ? 0 : index > content.length ? content.length : index;
|
|
|
|
//
|
|
const startIndex = index - ExpressionKeys.Export.length - 1;
|
|
const endIndex = startIndex + ExpressionKeys.Export.length;
|
|
const identifier = content.substring(startIndex, endIndex).trim();
|
|
result = identifier === ExpressionKeys.Export;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Content Cleaners ...
|
|
/**
|
|
* clear all comments, regions symbols and non required signs from a content ...
|
|
*
|
|
* @param {string} content the content which used ...
|
|
* @returns cleared content ...
|
|
*/
|
|
function clearContent(content = '') {
|
|
//
|
|
// Validate Args ...
|
|
if (!XValueTools.isValidArg(content)) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
// Check Content contains Line Return or not ...
|
|
if (content.includes('\n')) {
|
|
content = content.split('\n')
|
|
.map(cc => cc.trim())
|
|
.filter(cc => XValueTools.isValidArg(cc) &&
|
|
!cc.startsWith('//') &&
|
|
!cc.startsWith('#'))
|
|
.join('\n');
|
|
}
|
|
|
|
//
|
|
return content;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
// Module Exports ...
|
|
module.exports = {
|
|
//
|
|
ContentTypes,
|
|
ExpressionKeys,
|
|
DecoratorTypes,
|
|
DecoratorParts,
|
|
DecoratorPartTypes,
|
|
ModuleDecoratorValidParts,
|
|
ComponentDecoratorValidParts,
|
|
DirectiveDecoratorValidParts,
|
|
InjectableDecoratorValidParts,
|
|
|
|
//
|
|
getContentType,
|
|
isValidContentType,
|
|
|
|
//
|
|
extractDecoratorPart,
|
|
isValidDecoratorPart,
|
|
isValidDecoratorType,
|
|
getDecoratorPartType,
|
|
isDecoratorPartArray,
|
|
isDecoratorPartString,
|
|
isValidDecoratorPartForType,
|
|
|
|
//
|
|
parseContent,
|
|
clearContent,
|
|
checkIsExported,
|
|
extractIdentifierIndexes,
|
|
validateIdentifierInContent,
|
|
extractValidIdentifierIndexes,
|
|
|
|
//
|
|
toExpression,
|
|
} |