update ets2bundle

Signed-off-by: lihong <lihong67@huawei.com>
Change-Id: Ia9c0229b1adac41d31004da97764063b680f9274
This commit is contained in:
lihong
2021-09-13 16:10:05 +08:00
parent 4c8e2e7196
commit 76a6f96442
19 changed files with 3693 additions and 3617 deletions
+1
View File
@@ -54,6 +54,7 @@ function initProjectConfig(projectConfig) {
function loadEntryObj(projectConfig) {
initProjectConfig(projectConfig);
setEntryFile(projectConfig);
if(staticPreviewPage) {
projectConfig.entryObj['./' + staticPreviewPage] = projectConfig.projectPath + path.sep +
staticPreviewPage + '.ets?entry';
+6 -3
View File
@@ -28,7 +28,8 @@ import {
import { transformLog } from './process_ui_syntax';
import {
dollarCollection,
componentCollection
componentCollection,
moduleCollection
} from './validate_ui_syntax';
import { decoratorParamSet } from './process_component_member';
import { appComponentCollection } from './process_component_build';
@@ -78,10 +79,12 @@ export class ResultStates {
});
if (!projectConfig.isPreview) {
compiler.hooks.compilation.tap('Collect Components', compilation => {
compilation.hooks.additionalAssets.tapAsync('Collect Components', callback => {
compiler.hooks.compilation.tap('Collect Components And Modules', compilation => {
compilation.hooks.additionalAssets.tapAsync('Collect Components And Modules', callback => {
compilation.assets['./component_collection.txt'] =
new RawSource(Array.from(appComponentCollection).join(","));
compilation.assets['./module_collection.txt'] =
new RawSource(moduleCollection.size === 0 ? 'NULL' : Array.from(moduleCollection).join(","));
callback();
});
})
+419 -360
View File
@@ -1,360 +1,419 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const COMPONENT_MAP: any = {
FormComponent: {
atomic: true,
attrs: [
'size', 'moduleName', 'dimension', 'allowUpdate', 'visibility',
'onAcquired', 'onError', 'onRouter'
]
},
Image: {
atomic: true,
attrs: [
'alt', 'objectFit', 'matchTextDirection', 'fitOriginalSize', 'objectRepeat', 'renderMode', 'interpolation',
'onComplete', 'onError', 'onFinish', 'sourceSize', 'fillColor', 'autoResize'
]
},
ImageAnimator: {
atomic: true,
attrs: [
'images', 'state', 'duration', 'reverse', 'fixedSize', 'preDecode', 'fillMode', 'iterations', 'onStart',
'onPause', 'onRepeat', 'onCancel', 'onFinish'
]
},
Animator: {
atomic: true,
attrs: [
'state', 'duration', 'curve', 'delay', 'fillMode', 'iterations', 'playMode', 'motion', 'onStart',
'onPause', 'onRepeat', 'onCancel', 'onFinish', 'onFrame'
]
},
SpringProp: {
atomic: true
},
SpringMotion: {
atomic: true
},
FrictionMotion: {
atomic: true
},
ScrollMotion: {
atomic: true
},
Text: {
children: ['Span'],
attrs: [
'fontColor', 'fontSize', 'fontStyle', 'fontWeight', 'textAlign', 'lineHeight', 'textOverflow', 'maxLines',
'decoration', 'letterSpacing', 'textCase', 'baselineOffset', 'minFontSize', 'maxFontSize'
]
},
TextPicker: {
atomic: true,
attrs: [
'defaultPickerItemHeight', 'onAccept', 'onCancel', 'onChange']
},
Span: {
atomic: true,
attrs: [
'fontColor', 'fontSize', 'fontStyle', 'fontFamily', 'fontWeight', 'decoration', 'letterSpacing', 'textCase'
]
},
Button: {
attrs: ['type', 'stateEffect', 'fontColor', 'fontSize', 'fontWeight']
},
Divider: {
atomic: true,
attrs: ['color', 'vertical', 'strokeWidth', 'lineCap']
},
Piece: {
atomic: true,
attrs: ['iconPosition']
},
Slider: {
atomic: true,
attrs: ['blockColor', 'trackColor', 'selectedColor', 'minLabel', 'maxLabel', 'showSteps', 'showTips', 'onChange']
},
Counter: {
attrs: [
'onStateChange', 'onInc',
'onDec', 'height', 'width'
]
},
Row: {
attrs: ['alignItems']
},
Column: {
attrs: ['alignItems']
},
Stack: {
attrs: ['alignContent']
},
List: {
children: ['ListItem', 'Section'],
attrs: [
'listDirection', 'scrollBar', 'edgeEffect', 'divider', 'editMode', 'cachedCount', 'chainAnimation',
'onScroll', 'onReachStart', 'onReachEnd', 'onScrollStop', 'onItemDelete', 'onItemMove'
]
},
ListItem: {
parents: ['List'],
single: true,
attrs: ['sticky', 'editable']
},
Grid: {
children: ['GridItem'],
attrs: ['columnsTemplate', 'rowsTemplate', 'columnsGap', 'rowsGap', 'scrollBar', 'scrollBarWidth', 'scrollBarColor']
},
GridItem: {
parents: ['Grid'],
single: true,
attrs: ['rowStart', 'rowEnd', 'columnStart', 'columnEnd', 'forceRebuild']
},
GridContainer: {
attrs: ['columns', 'sizeType', 'gutter', 'margin']
},
Swiper: {
attrs: [
'index', 'autoPlay', 'interval', 'indicator',
'loop', 'duration', 'vertical', 'itemSpace', 'onChange'
]
},
Rating: {
attrs: ['stars', 'stepSize', 'starStyle', 'onChange']
},
Calendar: {
attrs: [
'date', 'showLunar', 'startOfWeek', 'offDays', 'onSelectChange', 'onRequestData',
'currentData', 'preData', 'nextData', 'needSlide', 'showHoliday', 'direction',
'currentDayStyle', 'nonCurrentDayStyle', 'todayStyle', 'weekStyle', 'workStateStyle'
]
},
Panel: {
attrs: [
'type', 'mode', 'dragBar', 'fullHeight',
'halfHeight', 'miniHeight', 'show', 'onChange'
]
},
Navigator: {
single: true,
attrs: ['target', 'type', 'params', 'active']
},
Sheet: {
children: ['Section'],
attrs: []
},
Section: {
attrs: []
},
QRCode: {
attrs: ['color', 'backgroundColor']
},
Flex: {
attrs: []
},
LoadingProgress: {
atomic: true,
attrs: ['color']
},
NavigationView: {
attrs: []
},
Scroll: {
attrs: [
'scrollable', 'onScroll', 'onScrollEdge', 'onScrollEnd', 'scrollBar', 'scrollBarColor',
'scrollBarWidth', 'edgeEffect'
]
},
Shape: {
children: ['Rect', 'Path', 'Circle', 'Ellipse', 'Shape', 'Polyline', 'Polygon', 'Image', 'Text'],
attrs: [
'stroke', 'fill', 'strokeDashOffset', 'strokeLineCap',
'strokeLineJoin', 'strokeMiterLimit', 'strokeOpacity',
'fillOpacity', 'strokeWidth', 'antiAlias', 'strokeDashArray',
'viewPort'
]
},
Rect: {
atomic: true,
attrs: [
'radiusWidth', 'radiusHeight', 'radius'
]
},
Path: {
atomic: true,
attrs: [
'commands'
]
},
Circle: {
atomic: true
},
Ellipse: {
atomic: true
},
Camera: {
atomic: true,
attrs: ['devicePosition']
},
Tabs: {
children: ['TabContent'],
attrs: [
'initialIndex', 'vertical', 'scrollable', 'barMode', 'barWidth', 'barHeight', 'animationDuration',
'onChange'
]
},
TabContent: {
parents: ['Tabs'],
attrs: ['tabBar']
},
PageTransitionEnter: {
atomic: true,
attrs: ['onEnter']
},
PageTransitionExit: {
atomic: true,
attrs: ['onExit']
},
Blank: {
parents: ['Row', 'Column'],
automic: true,
attrs: ['color']
},
RowSplit: {
attrs: ['resizeable']
},
ColumnSplit: {
attrs: ['resizeable']
},
Toggle: {
attrs: ['onChange', 'selectedColor', 'swithPointStyle']
},
AlertDialog: {
attrs: ['show']
},
Video: {
atomic: true,
attrs: [
'muted', 'autoPlay', 'controls', 'loop', 'objectFit', 'onSeeking', 'onFullscreenChange',
'onStart', 'onPause', 'onPrepared', 'onFinish', 'onSeeked', 'onUpdate', 'onError'
]
},
AbilityComponent: {
attrs: ['onReady', 'onDestroy', 'onAbilityCreated', 'onAbilityMoveToFront', 'onAbilityWillRemove']
},
AlphabetIndexer: {
attrs: [
'onSelected', 'selectedColor', 'popupColor', 'selectedBackgroundColor', 'popupBackground', 'usingPopup',
'selectedFont', 'popupFont', 'iteamSize', 'font', 'color', 'alignStyle'
]
},
Radio: {
atomic: true,
attrs: ['checked', 'onChange']
},
GeometryView: {
atomic: true
},
DataPanel: {
atomic: false,
attrs: ['closeEffect']
},
Badge: {
atomics: true,
attrs: []
},
Line: {
atomic: true,
attrs: [
'startPoint','endPoint'
]
},
Polygon: {
atomic: true,
attrs: ['points']
},
Polyline: {
atomic: true,
attrs: ['points']
},
};
const COMMON_ATTRS: Set<string> = new Set([
'width', 'height', 'size', 'constraintSize', 'layoutPriority', 'layoutWeight',
'padding', 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom',
'margin', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom',
'border', 'borderStyle', 'borderWidth', 'borderColor', 'borderRadius',
'backgroundColor', 'backgroundImage', 'backgroundImageSize', 'backgroundImagePosition', 'opacity', 'animation',
'transition', 'navigationTitle', 'navigationSubTitle', 'hideNavigationBar', 'hideNavigationBackButton',
'toolBar', 'hideToolBar', 'onClick', 'onTouch', 'onKeyEvent',
'blur', 'backdropBlur', 'windowBlur', 'translate', 'rotate', 'scale', 'transform',
'onAppear', 'onDisAppear', 'visibility', 'flexBasis', 'flexShrink', 'flexGrow', 'alignSelf',
'useAlign', 'zIndex', 'sharedTransition', 'direction', 'align', 'position', 'markAnchor', 'offset',
'enabled', 'aspectRatio', 'displayPriority', 'onDrag', 'onDragEnter', 'onDragMove', 'onDragLeave', 'onDrop',
'overlay', 'linearGradient', 'sweepGradient', 'radialGradient', 'gridOffset', 'gridSpan', 'useSizeType',
'motionPath', 'clip', 'shadow', 'mask', 'accessibilityGroup', 'accessibilityText', 'accessibilityDescription',
'accessibilityImportance', 'onAccessibility'
]);
const TRANSITION_COMMON_ATTRS: Set<string> = new Set([
'slide', 'translate', 'scale', 'opacity'
]);
export const GESTURE_ATTRS: Set<string> = new Set([
'gesture', 'parallelGesture', 'priorityGesture'
]);
export const forbiddenUseStateType: Set<string> = new Set(['Scroller', 'SwiperScroller']);
export const INNER_COMPONENT_NAMES: Set<string> = new Set();
export const BUILDIN_CONTAINER_COMPONENT: Set<string> = new Set();
export const BUILDIN_STYLE_NAMES: Set<string> = new Set([
...COMMON_ATTRS, ...GESTURE_ATTRS, ...TRANSITION_COMMON_ATTRS
]);
export const AUTOMIC_COMPONENT: Set<string> = new Set();
export const SINGLE_CHILD_COMPONENT: Set<string> = new Set();
export const SPECIFIC_CHILD_COMPONENT: Map<string, Set<string>> = new Map();
export const GESTURE_TYPE_NAMES: Set<string> = new Set([
'TapGesture', 'LongPressGesture', 'PanGesture', 'PinchGesture', 'RotationGesture', 'GestureGroup'
]);
export const CUSTOM_BUILDER_METHOD: Set<string> = new Set();
export interface ExtendParamterInterfance {
attribute: string,
parameterCount: number
}
export const EXTEND_ATTRIBUTE: Map<string, Set<ExtendParamterInterfance>> = new Map();
(function initComponent() {
Object.keys(COMPONENT_MAP).forEach((componentName) => {
INNER_COMPONENT_NAMES.add(componentName);
if (!COMPONENT_MAP[componentName].atomic) {
BUILDIN_CONTAINER_COMPONENT.add(componentName);
} else {
AUTOMIC_COMPONENT.add(componentName);
}
if (COMPONENT_MAP[componentName].single) {
SINGLE_CHILD_COMPONENT.add(componentName);
}
if (COMPONENT_MAP[componentName].children) {
SPECIFIC_CHILD_COMPONENT.set(componentName,
new Set([...COMPONENT_MAP[componentName].children]));
}
if (COMPONENT_MAP[componentName].attrs && COMPONENT_MAP[componentName].attrs.length) {
COMPONENT_MAP[componentName].attrs.forEach((item) => {
BUILDIN_STYLE_NAMES.add(item);
});
}
});
})();
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const COMPONENT_MAP: any = {
FormComponent: {
atomic: true,
attrs: [
'size', 'moduleName', 'dimension', 'allowUpdate', 'visibility',
'onAcquired', 'onError', 'onRouter'
]
},
Image: {
atomic: true,
attrs: [
'alt', 'objectFit', 'matchTextDirection', 'fitOriginalSize', 'objectRepeat', 'renderMode', 'interpolation',
'onComplete', 'onError', 'onFinish', 'sourceSize', 'fillColor', 'autoResize'
]
},
ImageAnimator: {
atomic: true,
attrs: [
'images', 'state', 'duration', 'reverse', 'fixedSize', 'preDecode', 'fillMode', 'iterations', 'onStart',
'onPause', 'onRepeat', 'onCancel', 'onFinish'
]
},
Animator: {
atomic: true,
attrs: [
'state', 'duration', 'curve', 'delay', 'fillMode', 'iterations', 'playMode', 'motion', 'onStart',
'onPause', 'onRepeat', 'onCancel', 'onFinish', 'onFrame'
]
},
Refresh: {
atomic: true,
attrs: [
'refreshing', 'offset', 'friction',
'onStateChange', 'onRefreshing'
]
},
SpringProp: {
atomic: true
},
SpringMotion: {
atomic: true
},
FrictionMotion: {
atomic: true
},
ScrollMotion: {
atomic: true
},
Text: {
children: ['Span'],
attrs: [
'fontColor', 'fontSize', 'fontStyle', 'fontWeight', 'textAlign', 'lineHeight', 'textOverflow', 'maxLines',
'decoration', 'letterSpacing', 'textCase', 'baselineOffset', 'minFontSize', 'maxFontSize'
]
},
TextPicker: {
atomic: true,
attrs: ['defaultPickerItemHeight', 'onAccept', 'onCancel', 'onChange']
},
DatePicker: {
atomic: true,
attrs: ['lunar', 'onChange', 'useMilitaryTime']
},
Span: {
atomic: true,
attrs: [
'fontColor', 'fontSize', 'fontStyle', 'fontFamily', 'fontWeight', 'decoration', 'letterSpacing', 'textCase'
]
},
Button: {
attrs: ['type', 'stateEffect', 'fontColor', 'fontSize', 'fontWeight']
},
Divider: {
atomic: true,
attrs: ['color', 'vertical', 'strokeWidth', 'lineCap']
},
Piece: {
atomic: true,
attrs: ['iconPosition']
},
Slider: {
atomic: true,
attrs: ['blockColor', 'trackColor', 'selectedColor', 'minLabel','maxLabel', 'showSteps', 'showTips', 'onChange']
},
Counter: {
attrs: [
'onStateChange', 'onInc',
'onDec', 'height', 'width'
]
},
Row: {
attrs: ['alignItems']
},
Column: {
attrs: ['alignItems']
},
Stack: {
attrs: ['alignContent']
},
List: {
children: ['ListItem', 'Section'],
attrs: [
'listDirection', 'scrollBar', 'edgeEffect', 'divider', 'editMode', 'cachedCount', 'chainAnimation',
'onScroll', 'onReachStart', 'onReachEnd', 'onScrollStop', 'onItemDelete', 'onItemMove'
]
},
ListItem: {
parents: ['List'],
single: true,
attrs: ['sticky', 'editable']
},
Grid: {
children: ['GridItem'],
attrs: ['columnsTemplate', 'rowsTemplate', 'columnsGap', 'rowsGap', 'scrollBar', 'scrollBarWidth', 'scrollBarColor']
},
GridItem: {
parents: ['Grid'],
single: true,
attrs: ['rowStart', 'rowEnd', 'columnStart', 'columnEnd', 'forceRebuild']
},
GridContainer: {
attrs: ['columns', 'sizeType', 'gutter', 'margin']
},
Hyperlink: {
attrs: ['color']
},
Swiper: {
attrs: [
'index', 'autoPlay', 'interval', 'indicator',
'loop', 'duration', 'vertical', 'itemSpace', 'displayMode', 'onChange'
]
},
Rating: {
attrs: ['stars', 'stepSize', 'starStyle', 'onChange']
},
Calendar: {
attrs: [
'date', 'showLunar', 'startOfWeek', 'offDays', 'onSelectChange', 'onRequestData',
'currentData', 'preData', 'nextData', 'needSlide', 'showHoliday', 'direction',
'currentDayStyle', 'nonCurrentDayStyle', 'todayStyle', 'weekStyle', 'workStateStyle'
]
},
Panel: {
attrs: [
'type', 'mode', 'dragBar', 'fullHeight',
'halfHeight', 'miniHeight', 'show', 'onChange'
]
},
Navigator: {
single: true,
attrs: ['target', 'type', 'params', 'active']
},
Sheet: {
children: ['Section'],
attrs: []
},
Section: {
attrs: []
},
QRCode: {
attrs: ['color', 'backgroundColor']
},
Flex: {
attrs: []
},
LoadingProgress: {
atomic: true,
attrs: ['color']
},
NavigationView: {
attrs: []
},
Scroll: {
attrs: [
'scrollable', 'onScroll', 'onScrollEdge', 'onScrollEnd', 'scrollBar', 'scrollBarColor',
'scrollBarWidth', 'edgeEffect'
]
},
Shape: {
children: ['Rect', 'Path', 'Circle', 'Ellipse', 'Shape', 'Polyline', 'Polygon', 'Image', 'Text'],
attrs: [
'stroke', 'fill', 'strokeDashOffset', 'strokeLineCap',
'strokeLineJoin', 'strokeMiterLimit', 'strokeOpacity',
'fillOpacity', 'strokeWidth', 'antiAlias', 'strokeDashArray',
'viewPort'
]
},
Progress: {
atomic: true,
attrs: [
'value', 'color', 'cricularStyle'
]
},
Rect: {
atomic: true,
attrs: [
'radiusWidth', 'radiusHeight', 'radius'
]
},
Path: {
atomic: true,
attrs: [
'commands'
]
},
Circle: {
atomic: true
},
Ellipse: {
atomic: true
},
Camera: {
atomic: true,
attrs: ['devicePosition']
},
Tabs: {
children: ['TabContent'],
attrs: [
'vertical', 'scrollable', 'barMode', 'barWidth', 'barHeight', 'animationDuration',
'onChange'
]
},
TabContent: {
parents: ['Tabs'],
attrs: ['tabBar']
},
PageTransitionEnter: {
atomic: true,
attrs: ['onEnter']
},
PageTransitionExit: {
atomic: true,
attrs: ['onExit']
},
Blank: {
parents: ['Row', 'Column'],
automic: true,
attrs: ['color']
},
RowSplit: {
attrs: ['resizeable']
},
ColumnSplit: {
attrs: ['resizeable']
},
Toggle: {
attrs: ['onChange', 'selectedColor', 'swithPointStyle']
},
AlertDialog: {
attrs: ['show']
},
ActionSheet: {
attrs: ['show']
},
Video: {
atomic: true,
attrs: [
'muted', 'autoPlay', 'controls', 'loop', 'objectFit', 'onSeeking', 'onFullscreenChange',
'onStart', 'onPause', 'onPrepared', 'onFinish', 'onSeeked', 'onUpdate', 'onError'
]
},
AbilityComponent: {
attrs: ['onReady', 'onDestroy', 'onAbilityCreated', 'onAbilityMoveToFront', 'onAbilityWillRemove']
},
AlphabetIndexer: {
attrs: [
'onSelected', 'selectedColor', 'popupColor', 'selectedBackgroundColor', 'popupBackground', 'usingPopup',
'selectedFont', 'popupFont', 'itemSize', 'font', 'color', 'alignStyle'
]
},
Radio: {
atomic: true,
attrs: ['checked', 'onChange']
},
GeometryView: {
atomic: true
},
DataPanel: {
atomic: false,
attrs: ['closeEffect']
},
Badge: {
atomics: true,
attrs: []
},
Line: {
atomic: true,
attrs: [
'startPoint','endPoint'
]
},
Polygon: {
atomic: true,
attrs: ['points']
},
Polyline: {
atomic: true,
attrs: ['points']
},
Gauge: {
atomic: true,
attrs: ['value', 'startAngle', 'endAngle', 'colors', 'strokeWidth', 'labelTextConfig', 'labelColorConfig']
},
TextArea: {
atomic: true,
attrs: [
'placeholderColor', 'placeholderFont', 'textAlign', 'caretColor', 'correction', 'onChange'
]
},
TextInput: {
atomic: true,
attrs: [
'textInputType', 'placeholderColor', 'placeholderFont', 'textInputAction', 'inputFilter', 'caretColor',
'correction', 'onEditChanged', 'onSubmit', 'onChange'
]
},
Marquee: {
atomic: true,
attrs: ['onStart', 'onBounce', 'onFinish']
},
Menu: {
children: ['Option'],
attrs: ['show', 'showPosition'],
},
Option: {
parents: ['Menu'],
attrs: [],
},
};
const COMMON_ATTRS: Set<string> = new Set([
'width', 'height', 'size', 'constraintSize', 'layoutPriority', 'layoutWeight',
'padding', 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom',
'margin', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom',
'border', 'borderStyle', 'borderWidth', 'borderColor', 'borderRadius',
'backgroundColor', 'backgroundImage', 'backgroundImageSize', 'backgroundImagePosition', 'opacity', 'animation', 'transition',
'navigationTitle', 'navigationSubTitle', 'hideNavigationBar', 'hideNavigationBackButton',
'toolBar', 'hideToolBar', 'onClick', 'onTouch', 'onKeyEvent', 'onHover',
'blur', 'backdropBlur', 'windowBlur', 'translate', 'rotate', 'scale', 'transform',
'onAppear', 'onDisAppear', 'visibility', 'flexBasis', 'flexShrink', 'flexGrow', 'alignSelf',
'useAlign', 'zIndex', 'sharedTransition', 'direction', 'align', 'position', 'markAnchor', 'offset',
'enabled', 'aspectRatio', 'displayPriority', 'onDrag', 'onDragEnter', 'onDragMove', 'onDragLeave', 'onDrop',
'overlay', 'linearGradient', 'sweepGradient', 'radialGradient', 'gridOffset', 'gridSpan', 'useSizeType',
'motionPath', 'clip', 'shadow', 'mask', 'accessibilityGroup', 'accessibilityText', 'accessibilityDescription',
'accessibilityImportance', 'onAccessibility', 'grayscale', 'brightness', 'contrast', 'saturate', 'geometryTransition',
'bindPopup', 'colorBlend', 'invert', 'sepia', 'hueRotate'
]);
const TRANSITION_COMMON_ATTRS: Set<string> = new Set([
'slide', 'translate', 'scale', 'opacity'
]);
export const GESTURE_ATTRS: Set<string> = new Set([
'gesture', 'parallelGesture', 'priorityGesture'
]);
export const forbiddenUseStateType: Set<string> = new Set(['Scroller', 'SwiperScroller']);
export const INNER_COMPONENT_NAMES: Set<string> = new Set();
export const BUILDIN_CONTAINER_COMPONENT: Set<string> = new Set();
export const BUILDIN_STYLE_NAMES: Set<string> = new Set([
...COMMON_ATTRS, ...GESTURE_ATTRS, ...TRANSITION_COMMON_ATTRS
]);
export const AUTOMIC_COMPONENT: Set<string> = new Set();
export const SINGLE_CHILD_COMPONENT: Set<string> = new Set();
export const SPECIFIC_CHILD_COMPONENT: Map<string, Set<string>> = new Map();
export const GESTURE_TYPE_NAMES: Set<string> = new Set([
'TapGesture', 'LongPressGesture', 'PanGesture', 'PinchGesture', 'RotationGesture', 'GestureGroup'
]);
export const CUSTOM_BUILDER_METHOD: Set<string> = new Set();
export interface ExtendParamterInterfance {
attribute: string,
parameterCount: number
}
export const EXTEND_ATTRIBUTE: Map<string, Set<ExtendParamterInterfance>> = new Map();
export const JS_BIND_COMPONENTS: Set<string> = new Set([
...GESTURE_TYPE_NAMES, 'Gesture',
'PanGestureOption', 'CustomDialogController', 'Storage', 'Scroller', 'SwiperController',
'TabsController', 'CalendarController', 'AbilityController', 'VideoController'
]);
(function initComponent() {
Object.keys(COMPONENT_MAP).forEach((componentName) => {
INNER_COMPONENT_NAMES.add(componentName);
JS_BIND_COMPONENTS.add(componentName);
if (!COMPONENT_MAP[componentName].atomic) {
BUILDIN_CONTAINER_COMPONENT.add(componentName);
} else {
AUTOMIC_COMPONENT.add(componentName);
}
if (COMPONENT_MAP[componentName].single) {
SINGLE_CHILD_COMPONENT.add(componentName);
}
if (COMPONENT_MAP[componentName].children) {
SPECIFIC_CHILD_COMPONENT.set(componentName,
new Set([...COMPONENT_MAP[componentName].children]));
}
if (COMPONENT_MAP[componentName].attrs && COMPONENT_MAP[componentName].attrs.length) {
COMPONENT_MAP[componentName].attrs.forEach((item) => {
BUILDIN_STYLE_NAMES.add(item);
});
}
});
})();
+109 -109
View File
@@ -1,109 +1,109 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const program = require('commander');
program.parse(process.argv);
let name:string = 'HelloAce';
let appID:string = 'ace.helloworld';
let appName:string = 'HelloAce';
if (program.args && program.args[0]) {
name = program.args[0];
appID = program.args[0];
appName = program.args[0];
}
const regPath: RegExp = /[`~!@#$%^&*()_+<>?:"{},./;'[\]]/im;
/*
* Create sample project and files.
* @param dist {String}
*/
function createProject(dist: string) {
const dist_ = dist.trim().split('/');
if (dist_.length > 1 || regPath.test(dist)) {
return console.error(
'ERROR: The project name cannot be a path nor contain any special symbol.\n' +
"NOTE: To create the template project, run 'npm run create' in the root directory.\n" +
"NOTE: To customize the project name, run 'npm run create <projectName>'.");
}
const appPath:string = dist + '/app.ets';
const manifestPath:string = dist + '/manifest.json';
const indexPath:string = dist + '/pages/index.ets';
const app:string = `export default {
onCreate() {
console.info('Application onCreate')
},
onDestroy() {
console.info('Application onDestroy')
},
}`;
const manifest:string = `{
"appID": "com.huawei.` + appID + `",
"appName": "` + appName + `",
"versionName": "1.0.0",
"versionCode": 1,
"minPlatformVersion": "1.0.1",
"pages": [
"pages/index"
],
"window": {
"designWidth": 750,
"autoDesignWidth": false
}
}`;
const index:string = `@Entry
@Component
struct MyComponent {
private value1: string = "hello world 1";
private value2: string = "hello world 2";
private value3: string = "hello world 3";
build() {
Column() {
Text(this.value1);
Text(this.value2);
Text(this.value3);
}
}
}`;
fs.mkdir(dist + '/pages', { recursive: true }, (err) => {
if (err) {
return console.error('ERROR: Failed to create project directory.');
}
fs.writeFile(appPath, app, (err) => {
if (err) {
return console.error('ERROR: Failed to write app.ets.');
}
});
fs.writeFile(manifestPath, manifest, (err) => {
if (err) {
return console.error('ERROR: Failed to write manifest.json.');
}
});
fs.writeFile(indexPath, index, (err) => {
if (err) {
return console.error('ERROR: Failed to write index.ets.');
}
});
});
}
createProject(name);
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const program = require('commander');
program.parse(process.argv);
let name:string = 'HelloAce';
let appID:string = 'ace.helloworld';
let appName:string = 'HelloAce';
if (program.args && program.args[0]) {
name = program.args[0];
appID = program.args[0];
appName = program.args[0];
}
const regPath: RegExp = /[`~!@#$%^&*()_+<>?:"{},./;'[\]]/im;
/*
* Create sample project and files.
* @param dist {String}
*/
function createProject(dist: string) {
const dist_ = dist.trim().split('/');
if (dist_.length > 1 || regPath.test(dist)) {
return console.error(
'ERROR: The project name cannot be a path nor contain any special symbol.\n' +
"NOTE: To create the template project, run 'npm run create' in the root directory.\n" +
"NOTE: To customize the project name, run 'npm run create <projectName>'.");
}
const appPath:string = dist + '/app.ets';
const manifestPath:string = dist + '/manifest.json';
const indexPath:string = dist + '/pages/index.ets';
const app:string = `export default {
onCreate() {
console.info('Application onCreate')
},
onDestroy() {
console.info('Application onDestroy')
},
}`;
const manifest:string = `{
"appID": "com.huawei.` + appID + `",
"appName": "` + appName + `",
"versionName": "1.0.0",
"versionCode": 1,
"minPlatformVersion": "1.0.1",
"pages": [
"pages/index"
],
"window": {
"designWidth": 750,
"autoDesignWidth": false
}
}`;
const index:string = `@Entry
@Component
struct MyComponent {
private value1: string = "hello world 1";
private value2: string = "hello world 2";
private value3: string = "hello world 3";
build() {
Column() {
Text(this.value1);
Text(this.value2);
Text(this.value3);
}
}
}`;
fs.mkdir(dist + '/pages', { recursive: true }, (err) => {
if (err) {
return console.error('ERROR: Failed to create project directory.');
}
fs.writeFile(appPath, app, (err) => {
if (err) {
return console.error('ERROR: Failed to write app.ets.');
}
});
fs.writeFile(manifestPath, manifest, (err) => {
if (err) {
return console.error('ERROR: Failed to write manifest.json.');
}
});
fs.writeFile(indexPath, index, (err) => {
if (err) {
return console.error('ERROR: Failed to write index.ets.');
}
});
});
}
createProject(name);
+13 -2
View File
@@ -13,7 +13,8 @@
* limitations under the License.
*/
export const NATIVE_MODULE: Set<string> = new Set(['app', 'router', 'curves', 'matrix4']);
export const NATIVE_MODULE: Set<string> = new Set(
['system.app', 'ohos.app', 'system.router', 'system.curves', 'ohos.curves', 'system.matrix4', 'ohos.matrix4']);
export const SYSTEM_PLUGIN: string = 'system';
export const OHOS_PLUGIN: string = 'ohos';
@@ -137,12 +138,22 @@ export const GESTURE_ENUM_VALUE_LOW: string = 'Low';
export const GESTURE_ENUM_VALUE_PARALLEL: string = 'Parallel';
export const RESOURCE: string = '$r';
export const RESOURCE_RAWFILE: string = '$rawfile';
export const RESOURCE_NAME_ID: string = 'id';
export const RESOURCE_NAME_TYPE: string = 'type';
export const RESOURCE_NAME_PARAMS: string = 'params';
export const RESOURCE_TYPE = {
color: 10001,
float: 10002,
string: 10003,
plural: 10004,
media: 20000
boolean: 10005,
intarray: 10006,
integer: 10007,
pattern: 10008,
strarray: 10009,
media: 20000,
rawfile: 30000
};
export const WORKERS_DIR: string = 'workers';
+42 -38
View File
@@ -1,38 +1,42 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
sourceReplace,
validateUISyntax
} from './validate_ui_syntax';
import {
LogInfo,
emitLogInfo
} from './utils';
import { BUILD_ON } from './pre_define';
function preProcess(source: string): string {
process.env.compiler = BUILD_ON;
const newContent: string = sourceReplace(source);
const log: LogInfo[] =
validateUISyntax(source, newContent, this.resourcePath, this.resourceQuery);
if (log.length) {
emitLogInfo(this, log);
}
return newContent;
}
module.exports = preProcess;
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
sourceReplace,
validateUISyntax,
processSystemApi
} from './validate_ui_syntax';
import {
LogInfo,
emitLogInfo
} from './utils';
import { BUILD_ON } from './pre_define';
function preProcess(source: string): string {
process.env.compiler = BUILD_ON;
if (/\.ets$/.test(this.resourcePath)) {
const newContent: string = sourceReplace(source);
const log: LogInfo[] =
validateUISyntax(source, newContent, this.resourcePath, this.resourceQuery);
if (log.length) {
emitLogInfo(this, log);
}
return newContent;
} else {
return processSystemApi(source);
}
}
module.exports = preProcess;
@@ -1,25 +0,0 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import { abilityConfig } from '../main';
module.exports = function processAbilityEntryFile(source: string): string {
if (path.basename(this.resourcePath) === abilityConfig.abilityEntryFile) {
source = source.replace(/exports\.default/, 'globalThis.exports.default');
}
return source;
}
File diff suppressed because it is too large Load Diff
+400 -400
View File
@@ -1,400 +1,400 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import {
COMPONENT_BUILD_FUNCTION,
BASE_COMPONENT_NAME,
ATTRIBUTE_ANIMATETO,
GLOBAL_CONTEXT,
CREATE_CONSTRUCTOR_PARAMS,
COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
COMPONENT_CONSTRUCTOR_DELETE_PARAMS,
CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER,
ABOUT_TO_BE_DELETE_FUNCTION_ID,
CREATE_CONSTRUCTOR_GET_FUNCTION,
CREATE_CONSTRUCTOR_DELETE_FUNCTION,
FOREACH_OBSERVED_OBJECT,
FOREACH_GET_RAW_OBJECT,
COMPONENT_BUILDER_DECORATOR,
COMPONENT_TRANSITION_FUNCTION,
COMPONENT_CREATE_FUNCTION,
GEOMETRY_VIEW
} from './pre_define';
import {
BUILDIN_STYLE_NAMES,
CUSTOM_BUILDER_METHOD
} from './component_map';
import {
componentCollection,
linkCollection
} from './validate_ui_syntax';
import {
addConstructor,
getInitConstructor
} from './process_component_constructor';
import {
ControllerType,
processMemberVariableDecorators,
UpdateResult,
stateObjectCollection,
curPropMap
} from './process_component_member';
import {
processComponentBuild,
processComponentBlock
} from './process_component_build';
import {
LogType,
LogInfo,
hasDecorator
} from './utils';
export function processComponentClass(node: ts.ClassDeclaration, context: ts.TransformationContext,
log: LogInfo[], program: ts.Program): ts.ClassDeclaration {
validateInheritClass(node, log);
const memberNode: ts.ClassElement[] =
processMembers(node.members, node.name, context, log, program);
return ts.factory.updateClassDeclaration(node, undefined, node.modifiers, node.name,
node.typeParameters, updateHeritageClauses(node), memberNode);
}
type BuildCount = {
count: number;
}
function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier,
context: ts.TransformationContext, log: LogInfo[], program: ts.Program): ts.ClassElement[] {
const buildCount: BuildCount = { count: 0 };
let ctorNode: any = getInitConstructor(members);
const newMembers: ts.ClassElement[] = [];
const watchMap: Map<string, ts.Node> = new Map();
const updateParamsStatements: ts.Statement[] = [];
const deleteParamsStatements: ts.PropertyDeclaration[] = [];
const checkController: ControllerType =
{ hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) };
members.forEach((item: ts.ClassElement) => {
let updateItem: ts.ClassElement;
if (ts.isPropertyDeclaration(item)) {
const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item,
ctorNode, watchMap, checkController, log, program);
if (result.isItemUpdate()) {
updateItem = result.getProperity();
} else {
updateItem = item;
}
if (result.getVariableGet()) {
newMembers.push(result.getVariableGet());
}
if (result.getVariableSet()) {
newMembers.push(result.getVariableSet());
}
if (result.isCtorUpdate()) {
ctorNode = result.getCtor();
}
if (result.getUpdateParams()) {
updateParamsStatements.push(result.getUpdateParams());
}
if (result.isDeleteParams()) {
deleteParamsStatements.push(item);
}
if (result.getControllerSet()) {
newMembers.push(result.getControllerSet());
}
}
if (ts.isMethodDeclaration(item) && item.name) {
updateItem =
processComponentMethod(item, parentComponentName, context, log, buildCount);
}
if (updateItem) {
newMembers.push(updateItem);
}
});
validateBuildMethodCount(buildCount, parentComponentName, log);
validateHasController(parentComponentName, checkController, log);
newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements));
newMembers.unshift(addUpdateParamsFunc(updateParamsStatements));
newMembers.unshift(addConstructor(ctorNode, watchMap));
return newMembers;
}
function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: ts.Identifier,
context: ts.TransformationContext, log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration {
let updateItem: ts.MethodDeclaration = node;
const name: string = node.name.getText();
if (name === COMPONENT_BUILD_FUNCTION) {
buildCount.count = buildCount.count + 1;
updateItem = processBuildMember(node, context, log);
curPropMap.clear();
} else if (node.body && ts.isBlock(node.body)) {
if (name === COMPONENT_TRANSITION_FUNCTION) {
updateItem = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers,
node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
node.type, processComponentBlock(node.body, false, log, true));
} else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
CUSTOM_BUILDER_METHOD.add(name);
updateItem = ts.factory.updateMethodDeclaration(node, undefined, node.modifiers,
node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
node.type, processComponentBlock(node.body, false, log));
}
}
return ts.visitNode(updateItem, visitMethod);
function visitMethod(node: ts.Node): ts.Node {
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
const name: string = node.expression.escapedText.toString();
if (name === ATTRIBUTE_ANIMATETO) {
node = processAnimateTo(node);
}
}
return ts.visitEachChild(node, visitMethod, context);
}
}
function processBuildMember(node: ts.MethodDeclaration, context: ts.TransformationContext,
log: LogInfo[]): ts.MethodDeclaration {
if (node.parameters.length) {
log.push({
type: LogType.ERROR,
message: `The 'build' method can not have arguments.`,
pos: node.getStart()
});
}
const buildNode: ts.MethodDeclaration = processComponentBuild(node, log);
return ts.visitNode(buildNode, visitBuild);
function visitBuild(node: ts.Node): ts.Node {
if (isGeometryView(node)) {
node = processGeometryView(node as ts.ExpressionStatement, log);
}
if (isProperty(node)) {
node = createReference(node as ts.PropertyAssignment);
}
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) &&
stateObjectCollection.has(node.name.escapedText.toString()) && node.parent &&
ts.isCallExpression(node.parent) && ts.isPropertyAccessExpression(node.parent.expression) &&
node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT) {
return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]);
}
return ts.visitEachChild(node, visitBuild, context);
}
}
function isGeometryView(node: ts.Node): boolean {
if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) {
const call: ts.CallExpression = node.expression;
const exp: ts.Expression = call.expression;
const args: ts.NodeArray<ts.Expression> = call.arguments;
if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) &&
exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) &&
exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 &&
(ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) {
return true;
}
}
return false;
}
function processGeometryView(node: ts.ExpressionStatement,
log: LogInfo[]): ts.ExpressionStatement {
const exp: ts.CallExpression = node.expression as ts.CallExpression;
const arg: ts.ArrowFunction | ts.FunctionExpression =
exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression;
return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp,
exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters,
undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
getGeometryReaderFunctionBlock(arg, log))]));
}
function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression,
log: LogInfo[]): ts.Block {
let blockNode: ts.Block;
if (ts.isBlock(node.body)) {
blockNode = node.body;
} else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) {
blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]);
}
return processComponentBlock(blockNode, false, log);
}
function updateHeritageClauses(node: ts.ClassDeclaration): ts.NodeArray<ts.HeritageClause> {
const result:ts.HeritageClause[] = [];
const heritageClause:ts.HeritageClause = ts.factory.createHeritageClause(
ts.SyntaxKind.ExtendsKeyword,
[ts.factory.createExpressionWithTypeArguments(
ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])]);
if (node.heritageClauses) {
result.push(...node.heritageClauses);
}
result.push(heritageClause);
return ts.factory.createNodeArray(result);
}
function isProperty(node: ts.Node): Boolean {
if (node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent &&
ts.isCallExpression(node.parent.parent) && ts.isPropertyAssignment(node) &&
ts.isIdentifier(node.name)) {
if (ts.isIdentifier(node.parent.parent.expression) &&
!BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) &&
componentCollection.customComponents.has(
node.parent.parent.expression.escapedText.toString())) {
return true;
} else if (ts.isPropertyAccessExpression(node.parent.parent.expression) &&
ts.isIdentifier(node.parent.parent.expression.expression) &&
componentCollection.customComponents.has(
node.parent.parent.expression.name.escapedText.toString())) {
return true;
}
}
return false;
}
function createReference(node: ts.PropertyAssignment): ts.PropertyAssignment {
const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1);
const propertyName: ts.Identifier = node.name as ts.Identifier;
let initText: string;
if (linkParentComponent && ts.isPropertyAssignment(node) && ts.isIdentifier(propertyName) &&
linkParentComponent.includes(propertyName.escapedText.toString())) {
const LINK_REG: RegExp = /^\$/g;
const initExpression: ts.Expression = node.initializer;
if (ts.isIdentifier(initExpression) &&
initExpression.escapedText.toString().match(LINK_REG)) {
if (linkParentComponent.includes(propertyName.escapedText.toString())) {
initText = initExpression.escapedText.toString().replace(LINK_REG, '');
}
} else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
ts.isIdentifier(initExpression.name) &&
initExpression.name.escapedText.toString().match(LINK_REG)) {
if (linkParentComponent.includes(propertyName.escapedText.toString())) {
initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
}
}
if (initText) {
node = addDoubleUnderline(node, propertyName, initText);
}
}
return node;
}
function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier,
initText: string): ts.PropertyAssignment {
return ts.factory.updatePropertyAssignment(node, propertyName,
ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(`__${initText}`)));
}
function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] {
const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression;
const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression =
grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression;
let parentComponent: Set<string> = new Set();
let grandparentName: string;
if (ts.isIdentifier(grandparentExpression)) {
grandparentName = grandparentExpression.escapedText.toString();
parentComponent = collection.get(grandparentName);
} else if (ts.isPropertyAccessExpression(grandparentExpression)) {
grandparentName = grandparentExpression.name.escapedText.toString();
parentComponent = collection.get(grandparentName);
} else {
// ignore
}
if (!parentComponent) {
parentComponent = new Set();
}
return [grandparentName, ...parentComponent];
}
function processAnimateTo(node: ts.CallExpression): ts.CallExpression {
return ts.factory.updateCallExpression(node, ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier(GLOBAL_CONTEXT), ts.factory.createIdentifier(ATTRIBUTE_ANIMATETO)),
node.typeArguments, node.arguments);
}
function addUpdateParamsFunc(statements: ts.Statement[]): ts.MethodDeclaration {
return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements);
}
function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDeclaration {
const deleteStatements: ts.ExpressionStatement[] = [];
statements.forEach((statement: ts.PropertyDeclaration) => {
const name: ts.Identifier = statement.name as ts.Identifier;
const paramsStatement: ts.ExpressionStatement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, []));
deleteStatements.push(paramsStatement);
});
const defaultStatement: ts.ExpressionStatement =
ts.factory.createExpressionStatement(ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER),
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []),
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)),
undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createThis(), ts.factory.createIdentifier(ABOUT_TO_BE_DELETE_FUNCTION_ID)),
undefined, [])]));
deleteStatements.push(defaultStatement);
const deleteParamsMethod: ts.MethodDeclaration =
createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements);
return deleteParamsMethod;
}
function createParamsInitBlock(express: string, statements: ts.Statement[]): ts.MethodDeclaration {
const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined,
undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined,
[ts.factory.createParameterDeclaration(undefined, undefined, undefined,
express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined, undefined, undefined)],
undefined, ts.factory.createBlock(statements, true));
return methodDeclaration;
}
function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier,
log: LogInfo[]): void {
if (buildCount.count !== 1) {
log.push({
type: LogType.ERROR,
message: `struct '${parentComponentName.getText()}' must be at least or at most one 'build' method.`,
pos: parentComponentName.getStart()
});
}
}
function validateInheritClass(node: ts.ClassDeclaration, log: LogInfo[]): void {
if (node.heritageClauses) {
log.push({
type: LogType.ERROR,
message: '@Component should not be inherit other Classes.',
pos: node.heritageClauses.pos
});
}
}
function validateHasController(componentName: ts.Identifier, checkController: ControllerType,
log: LogInfo[]): void {
if (!checkController.hasController) {
log.push({
type: LogType.ERROR,
message: '@CustomDialog component should have a property of the CustomDialogController type.',
pos: componentName.pos
});
}
}
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import {
COMPONENT_BUILD_FUNCTION,
BASE_COMPONENT_NAME,
ATTRIBUTE_ANIMATETO,
GLOBAL_CONTEXT,
CREATE_CONSTRUCTOR_PARAMS,
COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
COMPONENT_CONSTRUCTOR_DELETE_PARAMS,
CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER,
ABOUT_TO_BE_DELETE_FUNCTION_ID,
CREATE_CONSTRUCTOR_GET_FUNCTION,
CREATE_CONSTRUCTOR_DELETE_FUNCTION,
FOREACH_OBSERVED_OBJECT,
FOREACH_GET_RAW_OBJECT,
COMPONENT_BUILDER_DECORATOR,
COMPONENT_TRANSITION_FUNCTION,
COMPONENT_CREATE_FUNCTION,
GEOMETRY_VIEW
} from './pre_define';
import {
BUILDIN_STYLE_NAMES,
CUSTOM_BUILDER_METHOD
} from './component_map';
import {
componentCollection,
linkCollection
} from './validate_ui_syntax';
import {
addConstructor,
getInitConstructor
} from './process_component_constructor';
import {
ControllerType,
processMemberVariableDecorators,
UpdateResult,
stateObjectCollection,
curPropMap
} from './process_component_member';
import {
processComponentBuild,
processComponentBlock
} from './process_component_build';
import {
LogType,
LogInfo,
hasDecorator
} from './utils';
export function processComponentClass(node: ts.ClassDeclaration, context: ts.TransformationContext,
log: LogInfo[], program: ts.Program): ts.ClassDeclaration {
validateInheritClass(node, log);
const memberNode: ts.ClassElement[] =
processMembers(node.members, node.name, context, log, program);
return ts.factory.updateClassDeclaration(node, undefined, node.modifiers, node.name,
node.typeParameters, updateHeritageClauses(node), memberNode);
}
type BuildCount = {
count: number;
}
function processMembers(members: ts.NodeArray<ts.ClassElement>, parentComponentName: ts.Identifier,
context: ts.TransformationContext, log: LogInfo[], program: ts.Program): ts.ClassElement[] {
const buildCount: BuildCount = { count: 0 };
let ctorNode: any = getInitConstructor(members);
const newMembers: ts.ClassElement[] = [];
const watchMap: Map<string, ts.Node> = new Map();
const updateParamsStatements: ts.Statement[] = [];
const deleteParamsStatements: ts.PropertyDeclaration[] = [];
const checkController: ControllerType =
{ hasController: !componentCollection.customDialogs.has(parentComponentName.getText()) };
members.forEach((item: ts.ClassElement) => {
let updateItem: ts.ClassElement;
if (ts.isPropertyDeclaration(item)) {
const result: UpdateResult = processMemberVariableDecorators(parentComponentName, item,
ctorNode, watchMap, checkController, log, program);
if (result.isItemUpdate()) {
updateItem = result.getProperity();
} else {
updateItem = item;
}
if (result.getVariableGet()) {
newMembers.push(result.getVariableGet());
}
if (result.getVariableSet()) {
newMembers.push(result.getVariableSet());
}
if (result.isCtorUpdate()) {
ctorNode = result.getCtor();
}
if (result.getUpdateParams()) {
updateParamsStatements.push(result.getUpdateParams());
}
if (result.isDeleteParams()) {
deleteParamsStatements.push(item);
}
if (result.getControllerSet()) {
newMembers.push(result.getControllerSet());
}
}
if (ts.isMethodDeclaration(item) && item.name) {
updateItem =
processComponentMethod(item, parentComponentName, context, log, buildCount);
}
if (updateItem) {
newMembers.push(updateItem);
}
});
validateBuildMethodCount(buildCount, parentComponentName, log);
validateHasController(parentComponentName, checkController, log);
newMembers.unshift(addDeleteParamsFunc(deleteParamsStatements));
newMembers.unshift(addUpdateParamsFunc(updateParamsStatements));
newMembers.unshift(addConstructor(ctorNode, watchMap));
return newMembers;
}
function processComponentMethod(node: ts.MethodDeclaration, parentComponentName: ts.Identifier,
context: ts.TransformationContext, log: LogInfo[], buildCount: BuildCount): ts.MethodDeclaration {
let updateItem: ts.MethodDeclaration = node;
const name: string = node.name.getText();
if (name === COMPONENT_BUILD_FUNCTION) {
buildCount.count = buildCount.count + 1;
updateItem = processBuildMember(node, context, log);
curPropMap.clear();
} else if (node.body && ts.isBlock(node.body)) {
if (name === COMPONENT_TRANSITION_FUNCTION) {
updateItem = ts.factory.updateMethodDeclaration(node, node.decorators, node.modifiers,
node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
node.type, processComponentBlock(node.body, false, log, true));
} else if (hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
CUSTOM_BUILDER_METHOD.add(name);
updateItem = ts.factory.updateMethodDeclaration(node, undefined, node.modifiers,
node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters,
node.type, processComponentBlock(node.body, false, log));
}
}
return ts.visitNode(updateItem, visitMethod);
function visitMethod(node: ts.Node): ts.Node {
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
const name: string = node.expression.escapedText.toString();
if (name === ATTRIBUTE_ANIMATETO) {
node = processAnimateTo(node);
}
}
return ts.visitEachChild(node, visitMethod, context);
}
}
function processBuildMember(node: ts.MethodDeclaration, context: ts.TransformationContext,
log: LogInfo[]): ts.MethodDeclaration {
if (node.parameters.length) {
log.push({
type: LogType.ERROR,
message: `The 'build' method can not have arguments.`,
pos: node.getStart()
});
}
const buildNode: ts.MethodDeclaration = processComponentBuild(node, log);
return ts.visitNode(buildNode, visitBuild);
function visitBuild(node: ts.Node): ts.Node {
if (isGeometryView(node)) {
node = processGeometryView(node as ts.ExpressionStatement, log);
}
if (isProperty(node)) {
node = createReference(node as ts.PropertyAssignment);
}
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) &&
stateObjectCollection.has(node.name.escapedText.toString()) && node.parent &&
ts.isCallExpression(node.parent) && ts.isPropertyAccessExpression(node.parent.expression) &&
node.parent.expression.name.escapedText.toString() !== FOREACH_GET_RAW_OBJECT) {
return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier(FOREACH_OBSERVED_OBJECT),
ts.factory.createIdentifier(FOREACH_GET_RAW_OBJECT)), undefined, [node]);
}
return ts.visitEachChild(node, visitBuild, context);
}
}
function isGeometryView(node: ts.Node): boolean {
if (ts.isExpressionStatement(node) && ts.isCallExpression(node.expression)) {
const call: ts.CallExpression = node.expression;
const exp: ts.Expression = call.expression;
const args: ts.NodeArray<ts.Expression> = call.arguments;
if (ts.isPropertyAccessExpression(exp) && ts.isIdentifier(exp.expression) &&
exp.expression.escapedText.toString() === GEOMETRY_VIEW && ts.isIdentifier(exp.name) &&
exp.name.escapedText.toString() === COMPONENT_CREATE_FUNCTION && args && args.length === 1 &&
(ts.isArrowFunction(args[0]) || ts.isFunctionExpression(args[0]))) {
return true;
}
}
return false;
}
function processGeometryView(node: ts.ExpressionStatement,
log: LogInfo[]): ts.ExpressionStatement {
const exp: ts.CallExpression = node.expression as ts.CallExpression;
const arg: ts.ArrowFunction | ts.FunctionExpression =
exp.arguments[0] as ts.ArrowFunction | ts.FunctionExpression;
return ts.factory.updateExpressionStatement(node, ts.factory.updateCallExpression(exp,
exp.expression, undefined, [ts.factory.createArrowFunction(undefined, undefined, arg.parameters,
undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
getGeometryReaderFunctionBlock(arg, log))]));
}
function getGeometryReaderFunctionBlock(node: ts.ArrowFunction | ts.FunctionExpression,
log: LogInfo[]): ts.Block {
let blockNode: ts.Block;
if (ts.isBlock(node.body)) {
blockNode = node.body;
} else if (ts.isArrowFunction(node) && ts.isCallExpression(node.body)) {
blockNode = ts.factory.createBlock([ts.factory.createExpressionStatement(node.body)]);
}
return processComponentBlock(blockNode, false, log);
}
function updateHeritageClauses(node: ts.ClassDeclaration): ts.NodeArray<ts.HeritageClause> {
const result:ts.HeritageClause[] = [];
const heritageClause:ts.HeritageClause = ts.factory.createHeritageClause(
ts.SyntaxKind.ExtendsKeyword,
[ts.factory.createExpressionWithTypeArguments(
ts.factory.createIdentifier(BASE_COMPONENT_NAME), [])]);
if (node.heritageClauses) {
result.push(...node.heritageClauses);
}
result.push(heritageClause);
return ts.factory.createNodeArray(result);
}
function isProperty(node: ts.Node): Boolean {
if (node.parent && ts.isObjectLiteralExpression(node.parent) && node.parent.parent &&
ts.isCallExpression(node.parent.parent) && ts.isPropertyAssignment(node) &&
ts.isIdentifier(node.name)) {
if (ts.isIdentifier(node.parent.parent.expression) &&
!BUILDIN_STYLE_NAMES.has(node.parent.parent.expression.escapedText.toString()) &&
componentCollection.customComponents.has(
node.parent.parent.expression.escapedText.toString())) {
return true;
} else if (ts.isPropertyAccessExpression(node.parent.parent.expression) &&
ts.isIdentifier(node.parent.parent.expression.expression) &&
componentCollection.customComponents.has(
node.parent.parent.expression.name.escapedText.toString())) {
return true;
}
}
return false;
}
function createReference(node: ts.PropertyAssignment): ts.PropertyAssignment {
const linkParentComponent: string[] = getParentNode(node, linkCollection).slice(1);
const propertyName: ts.Identifier = node.name as ts.Identifier;
let initText: string;
if (linkParentComponent && ts.isPropertyAssignment(node) && ts.isIdentifier(propertyName) &&
linkParentComponent.includes(propertyName.escapedText.toString())) {
const LINK_REG: RegExp = /^\$/g;
const initExpression: ts.Expression = node.initializer;
if (ts.isIdentifier(initExpression) &&
initExpression.escapedText.toString().match(LINK_REG)) {
if (linkParentComponent.includes(propertyName.escapedText.toString())) {
initText = initExpression.escapedText.toString().replace(LINK_REG, '');
}
} else if (ts.isPropertyAccessExpression(initExpression) && initExpression.expression &&
initExpression.expression.kind === ts.SyntaxKind.ThisKeyword &&
ts.isIdentifier(initExpression.name) &&
initExpression.name.escapedText.toString().match(LINK_REG)) {
if (linkParentComponent.includes(propertyName.escapedText.toString())) {
initText = initExpression.name.escapedText.toString().replace(LINK_REG, '');
}
}
if (initText) {
node = addDoubleUnderline(node, propertyName, initText);
}
}
return node;
}
function addDoubleUnderline(node: ts.PropertyAssignment, propertyName: ts.Identifier,
initText: string): ts.PropertyAssignment {
return ts.factory.updatePropertyAssignment(node, propertyName,
ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(`__${initText}`)));
}
function getParentNode(node: ts.PropertyAssignment, collection: Map<string, Set<string>>): string[] {
const grandparentNode: ts.NewExpression = node.parent.parent as ts.NewExpression;
const grandparentExpression: ts.Identifier | ts.PropertyAccessExpression =
grandparentNode.expression as ts.Identifier | ts.PropertyAccessExpression;
let parentComponent: Set<string> = new Set();
let grandparentName: string;
if (ts.isIdentifier(grandparentExpression)) {
grandparentName = grandparentExpression.escapedText.toString();
parentComponent = collection.get(grandparentName);
} else if (ts.isPropertyAccessExpression(grandparentExpression)) {
grandparentName = grandparentExpression.name.escapedText.toString();
parentComponent = collection.get(grandparentName);
} else {
// ignore
}
if (!parentComponent) {
parentComponent = new Set();
}
return [grandparentName, ...parentComponent];
}
function processAnimateTo(node: ts.CallExpression): ts.CallExpression {
return ts.factory.updateCallExpression(node, ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier(GLOBAL_CONTEXT), ts.factory.createIdentifier(ATTRIBUTE_ANIMATETO)),
node.typeArguments, node.arguments);
}
function addUpdateParamsFunc(statements: ts.Statement[]): ts.MethodDeclaration {
return createParamsInitBlock(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS, statements);
}
function addDeleteParamsFunc(statements: ts.PropertyDeclaration[]): ts.MethodDeclaration {
const deleteStatements: ts.ExpressionStatement[] = [];
statements.forEach((statement: ts.PropertyDeclaration) => {
const name: ts.Identifier = statement.name as ts.Identifier;
const paramsStatement: ts.ExpressionStatement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(`__${name.escapedText.toString()}`)),
ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_DELETE_PARAMS)), undefined, []));
deleteStatements.push(paramsStatement);
});
const defaultStatement: ts.ExpressionStatement =
ts.factory.createExpressionStatement(ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_SUBSCRIBER_MANAGER),
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_GET_FUNCTION)), undefined, []),
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_DELETE_FUNCTION)),
undefined, [ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createThis(), ts.factory.createIdentifier(ABOUT_TO_BE_DELETE_FUNCTION_ID)),
undefined, [])]));
deleteStatements.push(defaultStatement);
const deleteParamsMethod: ts.MethodDeclaration =
createParamsInitBlock(COMPONENT_CONSTRUCTOR_DELETE_PARAMS, deleteStatements);
return deleteParamsMethod;
}
function createParamsInitBlock(express: string, statements: ts.Statement[]): ts.MethodDeclaration {
const methodDeclaration: ts.MethodDeclaration = ts.factory.createMethodDeclaration(undefined,
undefined, undefined, ts.factory.createIdentifier(express), undefined, undefined,
[ts.factory.createParameterDeclaration(undefined, undefined, undefined,
express === COMPONENT_CONSTRUCTOR_DELETE_PARAMS ? undefined :
ts.factory.createIdentifier(CREATE_CONSTRUCTOR_PARAMS), undefined, undefined, undefined)],
undefined, ts.factory.createBlock(statements, true));
return methodDeclaration;
}
function validateBuildMethodCount(buildCount: BuildCount, parentComponentName: ts.Identifier,
log: LogInfo[]): void {
if (buildCount.count !== 1) {
log.push({
type: LogType.ERROR,
message: `struct '${parentComponentName.getText()}' must be at least or at most one 'build' method.`,
pos: parentComponentName.getStart()
});
}
}
function validateInheritClass(node: ts.ClassDeclaration, log: LogInfo[]): void {
if (node.heritageClauses) {
log.push({
type: LogType.ERROR,
message: '@Component should not be inherit other Classes.',
pos: node.heritageClauses.pos
});
}
}
function validateHasController(componentName: ts.Identifier, checkController: ControllerType,
log: LogInfo[]): void {
if (!checkController.hasController) {
log.push({
type: LogType.ERROR,
message: '@CustomDialog component should have a property of the CustomDialogController type.',
pos: componentName.pos
});
}
}
+95 -95
View File
@@ -1,95 +1,95 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import {
COMPONENT_CONSTRUCTOR_ID,
COMPONENT_CONSTRUCTOR_PARENT,
COMPONENT_CONSTRUCTOR_PARAMS,
COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
COMPONENT_WATCH_FUNCTION
} from './pre_define';
export function getInitConstructor(members: ts.NodeArray<ts.Node>): ts.ConstructorDeclaration {
let ctorNode: any = members.find(item => {
return ts.isConstructorDeclaration(item);
});
if (ctorNode) {
ctorNode = updateConstructor(ctorNode, [], [], true);
}
return ctorNode;
}
export function updateConstructor(ctorNode: ts.ConstructorDeclaration,
para: ts.ParameterDeclaration[], addStatements: ts.Statement[],
isSuper: boolean = false): ts.ConstructorDeclaration {
let modifyPara: ts.ParameterDeclaration[];
if (para && para.length) {
modifyPara = Array.from(ctorNode.parameters);
if (modifyPara) {
modifyPara.push(...para);
}
}
let modifyBody: ts.Statement[];
if (addStatements && addStatements.length && ctorNode) {
modifyBody = Array.from(ctorNode.body.statements);
if (modifyBody) {
if (isSuper) {
modifyBody.unshift(...addStatements);
} else {
modifyBody.push(...addStatements);
}
}
}
if (ctorNode) {
ctorNode = ts.factory.updateConstructorDeclaration(ctorNode, ctorNode.decorators,
ctorNode.modifiers, modifyPara || ctorNode.parameters,
ts.factory.createBlock(modifyBody || ctorNode.body.statements, true));
}
return ctorNode;
}
export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>)
: ts.ConstructorDeclaration {
const watchStatements: ts.ExpressionStatement[] = [];
watchMap.forEach((value, key) => {
const watchNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createThis(),
ts.factory.createIdentifier(COMPONENT_WATCH_FUNCTION)
),
undefined,
[
ts.factory.createStringLiteral(key),
ts.isStringLiteral(value) ?
ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(value.text)) : value as ts.PropertyAccessExpression
]
));
watchStatements.push(watchNode);
});
const callSuperStatement: ts.Statement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(ts.factory.createSuper(), undefined,
[ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID),
ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)]));
const updateWithValueParamsStatement: ts.Statement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createThis(), ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS)),
undefined, [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)]));
return updateConstructor(updateConstructor(ctorNode, [], [callSuperStatement], true), [],
[updateWithValueParamsStatement, ...watchStatements], false);
}
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import {
COMPONENT_CONSTRUCTOR_ID,
COMPONENT_CONSTRUCTOR_PARENT,
COMPONENT_CONSTRUCTOR_PARAMS,
COMPONENT_CONSTRUCTOR_UPDATE_PARAMS,
COMPONENT_WATCH_FUNCTION
} from './pre_define';
export function getInitConstructor(members: ts.NodeArray<ts.Node>): ts.ConstructorDeclaration {
let ctorNode: any = members.find(item => {
return ts.isConstructorDeclaration(item);
});
if (ctorNode) {
ctorNode = updateConstructor(ctorNode, [], [], true);
}
return ctorNode;
}
export function updateConstructor(ctorNode: ts.ConstructorDeclaration,
para: ts.ParameterDeclaration[], addStatements: ts.Statement[],
isSuper: boolean = false): ts.ConstructorDeclaration {
let modifyPara: ts.ParameterDeclaration[];
if (para && para.length) {
modifyPara = Array.from(ctorNode.parameters);
if (modifyPara) {
modifyPara.push(...para);
}
}
let modifyBody: ts.Statement[];
if (addStatements && addStatements.length && ctorNode) {
modifyBody = Array.from(ctorNode.body.statements);
if (modifyBody) {
if (isSuper) {
modifyBody.unshift(...addStatements);
} else {
modifyBody.push(...addStatements);
}
}
}
if (ctorNode) {
ctorNode = ts.factory.updateConstructorDeclaration(ctorNode, ctorNode.decorators,
ctorNode.modifiers, modifyPara || ctorNode.parameters,
ts.factory.createBlock(modifyBody || ctorNode.body.statements, true));
}
return ctorNode;
}
export function addConstructor(ctorNode: any, watchMap: Map<string, ts.Node>)
: ts.ConstructorDeclaration {
const watchStatements: ts.ExpressionStatement[] = [];
watchMap.forEach((value, key) => {
const watchNode: ts.ExpressionStatement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createThis(),
ts.factory.createIdentifier(COMPONENT_WATCH_FUNCTION)
),
undefined,
[
ts.factory.createStringLiteral(key),
ts.isStringLiteral(value) ?
ts.factory.createPropertyAccessExpression(ts.factory.createThis(),
ts.factory.createIdentifier(value.text)) : value as ts.PropertyAccessExpression
]
));
watchStatements.push(watchNode);
});
const callSuperStatement: ts.Statement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(ts.factory.createSuper(), undefined,
[ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_ID),
ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARENT)]));
const updateWithValueParamsStatement: ts.Statement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createThis(), ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_UPDATE_PARAMS)),
undefined, [ts.factory.createIdentifier(COMPONENT_CONSTRUCTOR_PARAMS)]));
return updateConstructor(updateConstructor(ctorNode, [], [callSuperStatement], true), [],
[updateWithValueParamsStatement, ...watchStatements], false);
}
File diff suppressed because it is too large Load Diff
@@ -15,6 +15,6 @@
import { processSystemApi } from './validate_ui_syntax';
module.exports = function processWorker(source: string): string {
module.exports = function processSystemModule(source: string): string {
return processSystemApi(source);
};
+47 -15
View File
@@ -28,7 +28,11 @@ import {
COMPONENT_EXTEND_DECORATOR,
RESOURCE,
RESOURCE_TYPE,
WORKER_OBJECT
WORKER_OBJECT,
RESOURCE_NAME_ID,
RESOURCE_NAME_TYPE,
RESOURCE_NAME_PARAMS,
RESOURCE_RAWFILE
} from './pre_define';
import {
componentInfo,
@@ -48,19 +52,19 @@ import {
BUILDIN_CONTAINER_COMPONENT,
CUSTOM_BUILDER_METHOD,
EXTEND_ATTRIBUTE,
INNER_COMPONENT_NAMES
JS_BIND_COMPONENTS
} from './component_map';
import { resources } from '../main';
export const transformLog: FileLog = new FileLog();
export function processUISyntax(program: ts.Program): Function {
export function processUISyntax(program: ts.Program, ut = false): Function {
return (context: ts.TransformationContext) => {
let pagesDir: string;
return (node: ts.SourceFile) => {
pagesDir = path.resolve(path.dirname(node.fileName));
if (process.env.compiler === BUILD_ON) {
if (path.basename(node.fileName) === 'app.ets.ts') {
if (!ut && (path.basename(node.fileName) === 'app.ets.ts' || !/\.ets\.ts$/.test(node.fileName))) {
return node;
}
collectComponents(node);
@@ -120,7 +124,7 @@ function collectComponents(node: ts.SourceFile): void {
if (node.identifiers && node.identifiers.size) {
// @ts-ignore
for (let key of node.identifiers.keys()) {
if (INNER_COMPONENT_NAMES.has(key)) {
if (JS_BIND_COMPONENTS.has(key)) {
appComponentCollection.add(key);
}
}
@@ -129,25 +133,53 @@ function collectComponents(node: ts.SourceFile): void {
function isResource(node: ts.Node): boolean {
return ts.isCallExpression(node) && ts.isIdentifier(node.expression) &&
node.expression.escapedText.toString() === RESOURCE && node.arguments.length > 0;
(node.expression.escapedText.toString() === RESOURCE ||
node.expression.escapedText.toString() === RESOURCE_RAWFILE) && node.arguments.length > 0;
}
function processResourceData(node: ts.CallExpression): ts.Node {
if (ts.isStringLiteral(node.arguments[0])) {
// @ts-ignore
const resourceData: string[] = node.arguments[0].text.split('.');
if (validateResourceData(resourceData, resources, node.arguments[0].getStart())) {
const resourceType: number = RESOURCE_TYPE[resourceData[1]];
const resourceValue: number = resources[resourceData[0]][resourceData[1]][resourceData[2]];
const argsArr: ts.Expression[] = Array.from(node.arguments);
argsArr.splice(0, 1, ts.factory.createNumericLiteral(resourceValue),
ts.factory.createNumericLiteral(resourceType));
return ts.factory.updateCallExpression(node, node.expression, node.typeArguments, argsArr);
if (node.expression.getText() === RESOURCE_RAWFILE) {
return createResourceParam(0, RESOURCE_TYPE.rawfile, [node.arguments[0]]);
} else {
// @ts-ignore
const resourceData: string[] = node.arguments[0].text.trim().split('.');
if (validateResourceData(resourceData, resources, node.arguments[0].getStart())) {
const resourceType: number = RESOURCE_TYPE[resourceData[1]];
const resourceValue: number = resources[resourceData[0]][resourceData[1]][resourceData[2]];
return createResourceParam(resourceValue, resourceType,
Array.from(node.arguments).slice(1));
}
}
}
return node;
}
function createResourceParam(resourceValue: number, resourceType: number,argsArr: ts.Expression[]):
ts.ObjectLiteralExpression {
const resourceParams: ts.ObjectLiteralExpression = ts.factory.createObjectLiteralExpression(
[
ts.factory.createPropertyAssignment(
ts.factory.createStringLiteral(RESOURCE_NAME_ID),
ts.factory.createNumericLiteral(resourceValue)
),
ts.factory.createPropertyAssignment(
ts.factory.createStringLiteral(RESOURCE_NAME_TYPE),
ts.factory.createNumericLiteral(resourceType)
),
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(RESOURCE_NAME_PARAMS),
ts.factory.createArrayLiteralExpression(
argsArr,
false
)
)
],
false
);
return resourceParams;
}
function validateResourceData(resourceData: string[], resources: object, pos: number): boolean {
if (resourceData.length !== 3) {
transformLog.errors.push({
+68 -65
View File
@@ -1,65 +1,68 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import path from 'path';
import { BUILD_OFF } from './pre_define';
import {
resetLog,
transformLog
} from './process_ui_syntax';
import {
propertyCollection,
linkCollection
} from './validate_ui_syntax';
import {
LogInfo,
emitLogInfo,
componentInfo
} from './utils';
import { resetComponentCollection } from './validate_ui_syntax';
module.exports = function resultProcess(source: string, map: any): string {
process.env.compiler = BUILD_OFF;
componentInfo.id = 0;
propertyCollection.clear();
linkCollection.clear();
resetComponentCollection();
if (transformLog && transformLog.errors.length) {
const sourceFile: ts.SourceFile = transformLog.sourceFile;
const logInfos: LogInfo[] = transformLog.errors.map((item) => {
if (item.pos) {
const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(item.pos);
item.line = posOfNode.line + 1;
item.column = posOfNode.character + 1;
} else {
item.line = undefined;
item.column = undefined;
}
item.fileName = sourceFile.fileName.replace(/.ts$/, '');
return item;
});
emitLogInfo(this, logInfos);
resetLog();
}
if (path.basename(this.resourcePath) === 'app.ets') {
source = source.replace(/exports\.default/, 'globalThis.exports.default');
}
this.callback(null, source, map);
return;
};
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import path from 'path';
import { BUILD_OFF } from './pre_define';
import {
resetLog,
transformLog
} from './process_ui_syntax';
import {
propertyCollection,
linkCollection
} from './validate_ui_syntax';
import {
LogInfo,
emitLogInfo,
componentInfo
} from './utils';
import { resetComponentCollection } from './validate_ui_syntax';
import { abilityConfig } from '../main';
module.exports = function resultProcess(source: string, map: any): string {
process.env.compiler = BUILD_OFF;
if (/\.ets$/.test(this.resourcePath)) {
componentInfo.id = 0;
propertyCollection.clear();
linkCollection.clear();
resetComponentCollection();
if (transformLog && transformLog.errors.length) {
const sourceFile: ts.SourceFile = transformLog.sourceFile;
const logInfos: LogInfo[] = transformLog.errors.map((item) => {
if (item.pos) {
const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(item.pos);
item.line = posOfNode.line + 1;
item.column = posOfNode.character + 1;
} else {
item.line = undefined;
item.column = undefined;
}
item.fileName = sourceFile.fileName.replace(/.ts$/, '');
return item;
});
emitLogInfo(this, logInfos);
resetLog();
}
}
const resourcePath: string = path.basename(this.resourcePath);
if (['app.ets', abilityConfig.abilityEntryFile].includes(resourcePath)) {
source = source.replace(/exports\.default/, 'globalThis.exports.default');
}
this.callback(null, source, map);
return;
};
+158 -158
View File
@@ -1,158 +1,158 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import path from 'path';
import fs from 'fs';
export enum LogType {
ERROR = 'ERROR',
WARN = 'WARN',
NOTE = 'NOTE'
}
export interface LogInfo {
type: LogType,
message: string,
pos?: number,
line?: number,
column?: number,
fileName?: string
}
export class FileLog {
private _sourceFile: ts.SourceFile;
private _errors: LogInfo[] = [];
public get sourceFile() {
return this._sourceFile;
}
public set sourceFile(newValue: ts.SourceFile) {
this._sourceFile = newValue;
}
public get errors() {
return this._errors;
}
public set errors(newValue: LogInfo[]) {
this._errors = newValue;
}
}
export function emitLogInfo(loader: any, infos: LogInfo[]) {
if (infos && infos.length) {
infos.forEach((item) => {
switch (item.type) {
case LogType.ERROR:
loader.emitError(getMessage(loader.resourcePath, item));
break;
case LogType.WARN:
loader.emitWarning(getMessage(loader.resourcePath, item));
break;
case LogType.NOTE:
loader.emitWarning(getMessage(loader.resourcePath, item));
break;
}
});
}
}
export function addLog(type: LogType, message: string, pos: number, log: LogInfo[],
sourceFile: ts.SourceFile) {
const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(pos);
log.push({
type: type,
message: message,
line: posOfNode.line + 1,
column: posOfNode.character + 1,
fileName: sourceFile.fileName
});
}
export function getMessage(fileName: string, info: LogInfo): string {
let messsage: string;
if (info.line && info.column) {
messsage = `BUILD${info.type} File: ${fileName}:${info.line}:${info.column}\n ${info.message}`;
} else {
messsage = `BUILD${info.type} File: ${fileName}\n ${info.message}`;
}
return messsage;
}
class ComponentInfo {
private _id: number = 0;
private _componentNames: Set<string> = new Set(['ForEach']);
public set id(id: number) {
this._id = id;
}
public get id() {
return this._id;
}
public set componentNames(componentNames: Set<string>) {
this._componentNames = componentNames;
}
public get componentNames() {
return this._componentNames;
}
}
export const componentInfo: ComponentInfo = new ComponentInfo();
export function hasDecorator(node: ts.MethodDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration,
decortorName: string): boolean {
if (node.decorators && node.decorators.length) {
for (let i = 0; i < node.decorators.length; i++) {
if (node.decorators[i].getText() === decortorName) {
return true;
}
}
}
return false;
}
const STATEMENT_EXPECT: number = 1128;
const SEMICOLON_EXPECT: number = 1005;
export const IGNORE_ERROR_CODE: number[] = [STATEMENT_EXPECT, SEMICOLON_EXPECT];
export function readFile(dir: string, utFiles: string[]) {
try {
const files: string[] = fs.readdirSync(dir);
files.forEach((element) => {
const filePath: string = path.join(dir, element);
const status: fs.Stats = fs.statSync(filePath);
if (status.isDirectory()) {
readFile(filePath, utFiles);
} else {
utFiles.push(filePath);
}
});
} catch (e) {
console.error('ETS ERROR: ' + e);
}
}
export function createFunction(node: ts.Identifier, attrNode: ts.Identifier,
argumentsArr: ts.NodeArray<ts.Expression>): ts.CallExpression {
return ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
node,
attrNode
),
undefined,
argumentsArr && argumentsArr.length ? argumentsArr : []
);
}
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import path from 'path';
import fs from 'fs';
export enum LogType {
ERROR = 'ERROR',
WARN = 'WARN',
NOTE = 'NOTE'
}
export interface LogInfo {
type: LogType,
message: string,
pos?: number,
line?: number,
column?: number,
fileName?: string
}
export class FileLog {
private _sourceFile: ts.SourceFile;
private _errors: LogInfo[] = [];
public get sourceFile() {
return this._sourceFile;
}
public set sourceFile(newValue: ts.SourceFile) {
this._sourceFile = newValue;
}
public get errors() {
return this._errors;
}
public set errors(newValue: LogInfo[]) {
this._errors = newValue;
}
}
export function emitLogInfo(loader: any, infos: LogInfo[]) {
if (infos && infos.length) {
infos.forEach((item) => {
switch (item.type) {
case LogType.ERROR:
loader.emitError(getMessage(loader.resourcePath, item));
break;
case LogType.WARN:
loader.emitWarning(getMessage(loader.resourcePath, item));
break;
case LogType.NOTE:
loader.emitWarning(getMessage(loader.resourcePath, item));
break;
}
});
}
}
export function addLog(type: LogType, message: string, pos: number, log: LogInfo[],
sourceFile: ts.SourceFile) {
const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(pos);
log.push({
type: type,
message: message,
line: posOfNode.line + 1,
column: posOfNode.character + 1,
fileName: sourceFile.fileName
});
}
export function getMessage(fileName: string, info: LogInfo): string {
let messsage: string;
if (info.line && info.column) {
messsage = `BUILD${info.type} File: ${fileName}:${info.line}:${info.column}\n ${info.message}`;
} else {
messsage = `BUILD${info.type} File: ${fileName}\n ${info.message}`;
}
return messsage;
}
class ComponentInfo {
private _id: number = 0;
private _componentNames: Set<string> = new Set(['ForEach']);
public set id(id: number) {
this._id = id;
}
public get id() {
return this._id;
}
public set componentNames(componentNames: Set<string>) {
this._componentNames = componentNames;
}
public get componentNames() {
return this._componentNames;
}
}
export const componentInfo: ComponentInfo = new ComponentInfo();
export function hasDecorator(node: ts.MethodDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration,
decortorName: string): boolean {
if (node.decorators && node.decorators.length) {
for (let i = 0; i < node.decorators.length; i++) {
if (node.decorators[i].getText() === decortorName) {
return true;
}
}
}
return false;
}
const STATEMENT_EXPECT: number = 1128;
const SEMICOLON_EXPECT: number = 1005;
export const IGNORE_ERROR_CODE: number[] = [STATEMENT_EXPECT, SEMICOLON_EXPECT];
export function readFile(dir: string, utFiles: string[]) {
try {
const files: string[] = fs.readdirSync(dir);
files.forEach((element) => {
const filePath: string = path.join(dir, element);
const status: fs.Stats = fs.statSync(filePath);
if (status.isDirectory()) {
readFile(filePath, utFiles);
} else {
utFiles.push(filePath);
}
});
} catch (e) {
console.error('ETS ERROR: ' + e);
}
}
export function createFunction(node: ts.Identifier, attrNode: ts.Identifier,
argumentsArr: ts.NodeArray<ts.Expression>): ts.CallExpression {
return ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
node,
attrNode
),
undefined,
argumentsArr && argumentsArr.length ? argumentsArr : []
);
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -46,7 +46,7 @@ function expectActual(name: string, filePath: string) {
"target": ts.ScriptTarget.ES2017
},
fileName: `${name}.ts`,
transformers: { before: [processUISyntax(null)] }
transformers: { before: [processUISyntax(null, true)] }
});
componentInfo.id = 0;
componentCollection.customComponents.clear();
@@ -91,7 +91,8 @@ export const expectResult: string =
if (earlierCreatedChild_2 == undefined) {
View.create(new Child("2", this, { stateProperty: this.regularToState,
propProperty: this.stateToProp,
regularProperty: this.regularToRegular, linkProperty: this.__stateToLink
regularProperty: this.regularToRegular,
linkProperty: this.__stateToLink
}));
}
else {
+4 -20
View File
@@ -53,7 +53,7 @@ function initConfig(config) {
module: {
rules: [
{
test: /\.ets$/,
test: /\.(ets|ts)$/,
use: [
{ loader: path.resolve(__dirname, 'lib/result_process.js') },
{
@@ -64,7 +64,7 @@ function initConfig(config) {
configFile: path.resolve(__dirname, 'tsconfig.json'),
getCustomTransformers(program) {
return {
before: [processUISyntax(program, path.join(projectPath, 'pages'))],
before: [processUISyntax(program)],
after: []
};
},
@@ -74,26 +74,10 @@ function initConfig(config) {
{ loader: path.resolve(__dirname, 'lib/pre_process.js') }
]
},
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{ loader: path.resolve(__dirname, 'lib/process_ability_entry_file.js') },
{
loader: 'ts-loader',
options: {
onlyCompileBundledFiles: true,
configFile: path.resolve(__dirname, 'tsconfig.json'),
}
},
{ loader: path.resolve(__dirname, 'lib/process_worker.js') }
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{ loader: path.resolve(__dirname, 'lib/process_worker.js') }
{ loader: path.resolve(__dirname, 'lib/process_system_module.js') }
]
}
]
@@ -102,7 +86,7 @@ function initConfig(config) {
global: false
},
resolve: {
extensions:['.ts', '.ets', '.js'],
extensions:['.js', '.ets', '.ts'],
modules: [
projectPath,
path.join(projectPath, '../../../../../'),