How to use isComponentTag method in Playwright Internal

Best JavaScript code snippet using playwright-internal

metalJSXComponent-1.0.4.js

Source:metalJSXComponent-1.0.4.js Github

copy

Full Screen

...3151 * @return {boolean}3152 * @protected3153 */3154 IncrementalDomRenderer.prototype.handleChildRender_ = function handleChildRender_(node) {3155 if (node.tag && _IncrementalDomUtils2.default.isComponentTag(node.tag)) {3156 node.config.children = this.buildChildren_(node.config.children);3157 this.renderFromTag_(node.tag, node.config);3158 return true;3159 }3160 };3161 /**3162 * Handles the `stateKeyChanged` event. Overrides original method from3163 * `ComponentRenderer` to guarantee that `IncrementalDomRenderer`'s logic3164 * will run first.3165 * @param {!Object} data3166 * @override3167 * @protected3168 */3169 IncrementalDomRenderer.prototype.handleComponentRendererStateKeyChanged_ = function handleComponentRendererStateKeyChanged_(data) {3170 this.handleStateKeyChanged_(data);3171 _ComponentRenderer.prototype.handleComponentRendererStateKeyChanged_.call(this, data);3172 };3173 /**3174 * Handles an intercepted call to the `elementOpen` function from incremental3175 * dom.3176 * @param {!function()} originalFn The original function before interception.3177 * @param {string} tag3178 * @protected3179 */3180 IncrementalDomRenderer.prototype.handleInterceptedOpenCall_ = function handleInterceptedOpenCall_(originalFn, tag) {3181 if (_IncrementalDomUtils2.default.isComponentTag(tag)) {3182 return this.handleSubComponentCall_.apply(this, arguments);3183 } else {3184 return this.handleRegularCall_.apply(this, arguments);3185 }3186 };3187 /**3188 * Handles an intercepted call to the `elementOpen` function from incremental3189 * dom, done for a regular element. Adds any inline listeners found and makes3190 * sure that component root elements are always reused.3191 * @param {!function()} originalFn The original function before interception.3192 * @protected3193 */3194 IncrementalDomRenderer.prototype.handleRegularCall_ = function handleRegularCall_(originalFn) {3195 var currComp = IncrementalDomRenderer.getComponentBeingRendered();3196 var currRenderer = currComp.getRenderer();3197 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {3198 args[_key - 1] = arguments[_key];3199 }3200 if (!currRenderer.rootElementReached_ && currComp.config.key) {3201 args[1] = currComp.config.key;3202 }3203 var node = originalFn.apply(null, args);3204 this.attachDecoratedListeners_(node, args);3205 this.updateElementIfNotReached_(node);3206 return node;3207 };3208 /**3209 * Handles the `stateKeyChanged` event. Stores state properties that have3210 * changed since the last render.3211 * @param {!Object} data3212 * @protected3213 */3214 IncrementalDomRenderer.prototype.handleStateKeyChanged_ = function handleStateKeyChanged_(data) {3215 this.changes_[data.key] = data;3216 };3217 /**3218 * Handles an intercepted call to the `elementOpen` function from incremental3219 * dom, done for a sub component element. Creates and updates the appropriate3220 * sub component.3221 * @param {!function()} originalFn The original function before interception.3222 * @protected3223 */3224 IncrementalDomRenderer.prototype.handleSubComponentCall_ = function handleSubComponentCall_(originalFn) {3225 for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {3226 args[_key2 - 1] = arguments[_key2];3227 }3228 var config = _IncrementalDomUtils2.default.buildConfigFromCall(args);3229 config.ref = _metal.core.isDefAndNotNull(config.ref) ? config.ref : this.buildRef(args[0]);3230 this.componentToRender_ = {3231 config: config,3232 tag: args[0]3233 };3234 this.prevPrefix_ = this.currentPrefix_;3235 this.currentPrefix_ = config.ref;3236 this.generatedRefCount_[this.currentPrefix_] = 0;3237 _IncrementalDomChildren2.default.capture(this, this.handleChildrenCaptured_);3238 };3239 /**3240 * Intercepts incremental dom calls from this component.3241 * @protected3242 */3243 IncrementalDomRenderer.prototype.intercept_ = function intercept_() {3244 _IncrementalDomAop2.default.startInterception({3245 attributes: this.handleInterceptedAttributesCall_,3246 elementOpen: this.handleInterceptedOpenCall_3247 });3248 };3249 /**3250 * Checks if the given object is an incremental dom node.3251 * @param {!Object} node3252 * @return {boolean}3253 */3254 IncrementalDomRenderer.isIncDomNode = function isIncDomNode(node) {3255 return !!node[_IncrementalDomChildren2.default.CHILD_OWNER];3256 };3257 /**3258 * Returns the event name if the given attribute is a listener (of the form3259 * "on<EventName>"), or null if it isn't.3260 * @param {string} attr3261 * @return {?string}3262 * @protected3263 */3264 IncrementalDomRenderer.prototype.getEventFromListenerAttr_ = function getEventFromListenerAttr_(attr) {3265 var matches = IncrementalDomRenderer.LISTENER_REGEX.exec(attr);3266 var eventName = matches ? matches[1] ? matches[1] : matches[2] : null;3267 return eventName ? eventName.toLowerCase() : null;3268 };3269 /**3270 * Gets the component that is this component's parent (that is, the one that3271 * actually rendered it), or null if there's no parent.3272 * @return {Component}3273 */3274 IncrementalDomRenderer.prototype.getParent = function getParent() {3275 return this.parent_;3276 };3277 /**3278 * Gets the component that is this component's owner (that is, the one that3279 * passed its config properties and holds its ref), or null if there's none.3280 * @return {Component}3281 */3282 IncrementalDomRenderer.prototype.getOwner = function getOwner() {3283 return this.owner_;3284 };3285 /**3286 * Creates and renders the given function, which can either be a simple3287 * incremental dom function or a component constructor.3288 * @param {!function()} fnOrCtor Either be a simple incremental dom function3289 or a component constructor.3290 * @param {Object|Element=} opt_dataOrElement Optional config data for the3291 * function or parent for the rendered content.3292 * @param {Element=} opt_element Optional parent for the rendered content.3293 * @return {!Component} The rendered component's instance.3294 */3295 IncrementalDomRenderer.render = function render(fnOrCtor, opt_dataOrElement, opt_parent) {3296 if (!_metalComponent.Component.isComponentCtor(fnOrCtor)) {3297 var fn = fnOrCtor;3298 var TempComponent = function (_Component) {3299 _inherits(TempComponent, _Component);3300 function TempComponent() {3301 _classCallCheck(this, TempComponent);3302 return _possibleConstructorReturn(this, _Component.apply(this, arguments));3303 }3304 TempComponent.prototype.created = function created() {3305 if (IncrementalDomRenderer.getComponentBeingRendered()) {3306 this.getRenderer().updateContext_(this);3307 }3308 };3309 TempComponent.prototype.render = function render() {3310 fn(this.config);3311 };3312 return TempComponent;3313 }(_metalComponent.Component);3314 TempComponent.RENDERER = IncrementalDomRenderer;3315 fnOrCtor = TempComponent;3316 }3317 return _metalComponent.Component.render(fnOrCtor, opt_dataOrElement, opt_parent);3318 };3319 /**3320 * Renders the renderer's component for the first time, patching its element3321 * through the incremental dom function calls done by `renderIncDom`.3322 */3323 IncrementalDomRenderer.prototype.render = function render() {3324 this.patch();3325 };3326 /**3327 * Renders the given child node via its owner renderer.3328 * @param {!Object} child3329 */3330 IncrementalDomRenderer.renderChild = function renderChild(child) {3331 child[_IncrementalDomChildren2.default.CHILD_OWNER].renderChild(child);3332 };3333 /**3334 * Renders the given child node.3335 * @param {!Object} child3336 */3337 IncrementalDomRenderer.prototype.renderChild = function renderChild(child) {3338 this.intercept_();3339 _IncrementalDomChildren2.default.render(child, this.handleChildRender_);3340 _IncrementalDomAop2.default.stopInterception();3341 };3342 /**3343 * Renders the contents for the given tag.3344 * @param {!function()|string} tag3345 * @param {!Object} config3346 * @protected3347 */3348 IncrementalDomRenderer.prototype.renderFromTag_ = function renderFromTag_(tag, config) {3349 if (_metal.core.isString(tag) || tag.prototype.getRenderer) {3350 var comp = this.renderSubComponent_(tag, config);3351 this.updateElementIfNotReached_(comp.element);3352 return comp.element;3353 } else {3354 return tag(config);3355 }3356 };3357 /**3358 * Calls functions from `IncrementalDOM` to build the component element's3359 * content. Can be overriden by subclasses (for integration with template3360 * engines for example).3361 */3362 IncrementalDomRenderer.prototype.renderIncDom = function renderIncDom() {3363 if (this.component_.render) {3364 this.component_.render();3365 } else {3366 IncrementalDOM.elementVoid('div');3367 }3368 };3369 /**3370 * Runs the incremental dom functions for rendering this component, but3371 * doesn't call `patch` yet. Rather, this will be the function that should be3372 * called by `patch`.3373 */3374 IncrementalDomRenderer.prototype.renderInsidePatch = function renderInsidePatch() {3375 if (this.component_.wasRendered && !this.shouldUpdate(this.changes_) && IncrementalDOM.currentPointer() === this.component_.element) {3376 if (this.component_.element) {3377 IncrementalDOM.skipNode();3378 }3379 return;3380 }3381 this.renderInsidePatchDontSkip_();3382 };3383 /**3384 * The same as `renderInsidePatch`, but without the check that may skip the3385 * render action.3386 * @protected3387 */3388 IncrementalDomRenderer.prototype.renderInsidePatchDontSkip_ = function renderInsidePatchDontSkip_() {3389 IncrementalDomRenderer.startedRenderingComponent(this.component_);3390 this.changes_ = {};3391 this.rootElementReached_ = false;3392 _IncrementalDomUnusedComponents2.default.schedule(this.childComponents_ || []);3393 this.childComponents_ = [];3394 this.generatedRefCount_ = {};3395 this.listenersToAttach_ = [];3396 this.currentPrefix_ = '';3397 this.intercept_();3398 this.renderIncDom();3399 _IncrementalDomAop2.default.stopInterception();3400 if (!this.rootElementReached_) {3401 this.component_.element = null;3402 } else {3403 this.component_.addElementClasses();3404 }3405 this.emit('rendered', !this.isRendered_);3406 IncrementalDomRenderer.finishedRenderingComponent();3407 };3408 /**3409 * This updates the sub component that is represented by the given data.3410 * The sub component is created, added to its parent and rendered. If it3411 * had already been rendered before though, it will only have its state3412 * updated instead.3413 * @param {string|!function()} tagOrCtor The tag name or constructor function.3414 * @param {!Object} config The config object for the sub component.3415 * @return {!Component} The updated sub component.3416 * @protected3417 */3418 IncrementalDomRenderer.prototype.renderSubComponent_ = function renderSubComponent_(tagOrCtor, config) {3419 var comp = this.getSubComponent_(tagOrCtor, config);3420 this.updateContext_(comp);3421 var renderer = comp.getRenderer();3422 if (renderer instanceof IncrementalDomRenderer) {3423 var parentComp = IncrementalDomRenderer.getComponentBeingRendered();3424 parentComp.getRenderer().childComponents_.push(comp);3425 renderer.parent_ = parentComp;3426 renderer.owner_ = this.component_;3427 renderer.renderInsidePatch();3428 } else {3429 console.warn('IncrementalDomRenderer doesn\'t support rendering sub components ' + 'that don\'t use IncrementalDomRenderer as well, like:', comp);3430 }3431 if (!comp.wasRendered) {3432 comp.renderAsSubComponent();3433 }3434 return comp;3435 };3436 /**3437 * Sets the component's config object with its new value.3438 * @param {!Component} comp The component to set the config for.3439 * @param {!Object} config3440 * @protected3441 */3442 IncrementalDomRenderer.prototype.setConfig_ = function setConfig_(comp, config) {3443 var prevConfig = comp.config;3444 comp.config = config;3445 if (_metal.core.isFunction(comp.configChanged)) {3446 comp.configChanged(config, prevConfig || {});3447 }3448 comp.emit('configChanged', {3449 prevVal: prevConfig,3450 newVal: config3451 });3452 };3453 /**3454 * Checks if the component should be updated with the current state changes.3455 * Can be overridden by subclasses or implemented by components to provide3456 * customized behavior (only updating when a state property used by the3457 * template changes, for example).3458 * @param {!Object} changes3459 * @return {boolean}3460 */3461 IncrementalDomRenderer.prototype.shouldUpdate = function shouldUpdate(changes) {3462 if (this.component_.shouldUpdate) {3463 return this.component_.shouldUpdate(changes);3464 }3465 return true;3466 };3467 /**3468 * Stores the component that has just started being rendered.3469 * @param {!Component} comp3470 */3471 IncrementalDomRenderer.startedRenderingComponent = function startedRenderingComponent(comp) {3472 renderingComponents_.push(comp);3473 };3474 /**3475 * Patches the component's element with the incremental dom function calls3476 * done by `renderIncDom`.3477 */3478 IncrementalDomRenderer.prototype.patch = function patch() {3479 if (!this.component_.element && this.parent_) {3480 // If the component has no content but was rendered from another component,3481 // we'll need to patch this parent to make sure that any new content will3482 // be added in the right place.3483 this.parent_.getRenderer().patch();3484 return;3485 }3486 var tempParent = this.guaranteeParent_();3487 if (tempParent) {3488 IncrementalDOM.patch(tempParent, this.renderInsidePatchDontSkip_);3489 _metalDom2.default.exitDocument(this.component_.element);3490 if (this.component_.element && this.component_.inDocument) {3491 this.component_.renderElement_(this.attachData_.parent, this.attachData_.sibling);3492 }3493 } else {3494 var element = this.component_.element;3495 IncrementalDOM.patchOuter(element, this.renderInsidePatchDontSkip_);3496 if (!this.component_.element) {3497 _metalDom2.default.exitDocument(element);3498 }3499 }3500 };3501 /**3502 * Updates the renderer's component when state changes, patching its element3503 * through the incremental dom function calls done by `renderIncDom`. Makes3504 * sure that it won't cause a rerender if the only change was for the3505 * "element" property.3506 */3507 IncrementalDomRenderer.prototype.update = function update() {3508 if (this.hasChangedBesidesElement_(this.changes_) && this.shouldUpdate(this.changes_)) {3509 this.patch();3510 }3511 };3512 /**3513 * Updates this renderer's component's element with the given values, unless3514 * it has already been reached by an earlier call.3515 * @param {!Element} node3516 * @protected3517 */3518 IncrementalDomRenderer.prototype.updateElementIfNotReached_ = function updateElementIfNotReached_(node) {3519 var currComp = IncrementalDomRenderer.getComponentBeingRendered();3520 var currRenderer = currComp.getRenderer();3521 if (!currRenderer.rootElementReached_) {3522 currRenderer.rootElementReached_ = true;3523 if (currComp.element !== node) {3524 currComp.element = node;3525 }3526 }3527 };3528 /**3529 * Updates the given component's context according to the data from the3530 * component that is currently being rendered.3531 * @param {!Component} comp3532 * @protected3533 */3534 IncrementalDomRenderer.prototype.updateContext_ = function updateContext_(comp) {3535 var context = comp.context;3536 var parent = IncrementalDomRenderer.getComponentBeingRendered();3537 var childContext = parent.getChildContext ? parent.getChildContext() : {};3538 _metal.object.mixin(context, parent.context, childContext);3539 comp.context = context;3540 };3541 return IncrementalDomRenderer;3542}(_metalComponent.ComponentRenderer);3543var renderingComponents_ = [];3544var emptyChildren_ = [];3545IncrementalDomRenderer.LISTENER_REGEX = /^(?:on([A-Z]\w+))|(?:data-on(\w+))$/;3546exports.default = IncrementalDomRenderer;3547},{"./IncrementalDomAop":21,"./children/IncrementalDomChildren":23,"./cleanup/IncrementalDomUnusedComponents":24,"./incremental-dom":25,"./utils/IncrementalDomUtils":26,"metal":34,"metal-component":5,"metal-dom":9}],23:[function(require,module,exports){3548'use strict';3549Object.defineProperty(exports, "__esModule", {3550 value: true3551});3552var _metal = require('metal');3553var _metal2 = _interopRequireDefault(_metal);3554var _IncrementalDomAop = require('../IncrementalDomAop');3555var _IncrementalDomAop2 = _interopRequireDefault(_IncrementalDomAop);3556var _IncrementalDomUtils = require('../utils/IncrementalDomUtils');3557var _IncrementalDomUtils2 = _interopRequireDefault(_IncrementalDomUtils);3558function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }3559function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }3560function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }3561/**3562 * Provides helpers for capturing children elements from incremental dom calls,3563 * as well as actually rendering those captured children via incremental dom3564 * later.3565 */3566var IncrementalDomChildren = function () {3567 function IncrementalDomChildren() {3568 _classCallCheck(this, IncrementalDomChildren);3569 }3570 /**3571 * Captures all child elements from incremental dom calls.3572 * @param {!IncrementalDomRenderer} renderer The renderer that is capturing3573 * children.3574 * @param {!function} callback Function to be called when children have all3575 * been captured.3576 */3577 IncrementalDomChildren.capture = function capture(renderer, callback) {3578 renderer_ = renderer;3579 callback_ = callback;3580 tree_ = {3581 config: {3582 children: []3583 }3584 };3585 currentParent_ = tree_;3586 isCapturing_ = true;3587 _IncrementalDomAop2.default.startInterception({3588 elementClose: handleInterceptedCloseCall_,3589 elementOpen: handleInterceptedOpenCall_,3590 text: handleInterceptedTextCall_3591 });3592 };3593 /**3594 * Renders a children tree through incremental dom.3595 * @param {!{args: Array, !children: Array, isText: ?boolean}}3596 * @param {function()=} opt_skipNode Optional function that is called for3597 * each node to be rendered. If it returns true, the node will be skipped.3598 * @protected3599 */3600 IncrementalDomChildren.render = function render(tree, opt_skipNode) {3601 if (isCapturing_) {3602 // If capturing, just add the node directly to the captured tree.3603 addChildToTree(tree);3604 return;3605 }3606 if (opt_skipNode && opt_skipNode(tree)) {3607 return;3608 }3609 if (_metal2.default.isDef(tree.text)) {3610 var args = tree.args ? tree.args : [];3611 args[0] = tree.text;3612 IncrementalDOM.text.apply(null, args);3613 } else {3614 var _args = _IncrementalDomUtils2.default.buildCallFromConfig(tree.tag, tree.config);3615 IncrementalDOM.elementOpen.apply(null, _args);3616 if (tree.config.children) {3617 for (var i = 0; i < tree.config.children.length; i++) {3618 IncrementalDomChildren.render(tree.config.children[i], opt_skipNode);3619 }3620 }3621 IncrementalDOM.elementClose(tree.tag);3622 }3623 };3624 return IncrementalDomChildren;3625}();3626var callback_;3627var currentParent_;3628var isCapturing_ = false;3629var renderer_;3630var tree_;3631/**3632 * Adds a child element to the tree.3633 * @param {!Array} args The arguments passed to the incremental dom call.3634 * @param {boolean=} opt_isText Optional flag indicating if the child is a3635 * text element.3636 * @protected3637 */3638function addChildCallToTree_(args, opt_isText) {3639 var child = _defineProperty({3640 parent: currentParent_3641 }, IncrementalDomChildren.CHILD_OWNER, renderer_);3642 if (opt_isText) {3643 child.text = args[0];3644 if (args.length > 1) {3645 child.args = args;3646 }3647 } else {3648 child.tag = args[0];3649 child.config = _IncrementalDomUtils2.default.buildConfigFromCall(args);3650 if (_IncrementalDomUtils2.default.isComponentTag(child.tag)) {3651 child.config.ref = _metal2.default.isDefAndNotNull(child.config.ref) ? child.config.ref : renderer_.buildRef(args[0]);3652 }3653 child.config.children = [];3654 }3655 addChildToTree(child);3656 return child;3657}3658function addChildToTree(child) {3659 currentParent_.config.children.push(child);3660}3661/**3662 * Handles an intercepted call to the `elementClose` function from incremental3663 * dom.3664 * @protected3665 */3666function handleInterceptedCloseCall_() {3667 if (currentParent_ === tree_) {3668 _IncrementalDomAop2.default.stopInterception();3669 isCapturing_ = false;3670 callback_(tree_);3671 callback_ = null;3672 currentParent_ = null;3673 renderer_ = null;3674 tree_ = null;3675 } else {3676 currentParent_ = currentParent_.parent;3677 }3678}3679/**3680 * Handles an intercepted call to the `elementOpen` function from incremental3681 * dom.3682 * @param {!function()} originalFn The original function before interception.3683 * @protected3684 */3685function handleInterceptedOpenCall_(originalFn) {3686 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {3687 args[_key - 1] = arguments[_key];3688 }3689 currentParent_ = addChildCallToTree_(args);3690}3691/**3692 * Handles an intercepted call to the `text` function from incremental dom.3693 * @param {!function()} originalFn The original function before interception.3694 * @protected3695 */3696function handleInterceptedTextCall_(originalFn) {3697 for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {3698 args[_key2 - 1] = arguments[_key2];3699 }3700 addChildCallToTree_(args, true);3701}3702/**3703 * Property identifying a specific object as a Metal.js child node, and3704 * pointing to the renderer instance that created it.3705 * @type {string}3706 * @static3707 */3708IncrementalDomChildren.CHILD_OWNER = '__metalChildOwner';3709exports.default = IncrementalDomChildren;3710},{"../IncrementalDomAop":21,"../utils/IncrementalDomUtils":26,"metal":34}],24:[function(require,module,exports){3711'use strict';3712Object.defineProperty(exports, "__esModule", {3713 value: true3714});3715function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }3716var comps_ = [];3717var IncrementalDomUnusedComponents = function () {3718 function IncrementalDomUnusedComponents() {3719 _classCallCheck(this, IncrementalDomUnusedComponents);3720 }3721 /**3722 * Disposes all sub components that were not rerendered since the last3723 * time this function was scheduled.3724 */3725 IncrementalDomUnusedComponents.disposeUnused = function disposeUnused() {3726 for (var i = 0; i < comps_.length; i++) {3727 if (!comps_[i].isDisposed()) {3728 var renderer = comps_[i].getRenderer();3729 if (!renderer.getParent()) {3730 // Don't let disposing cause the element to be removed, since it may3731 // be currently being reused by another component.3732 comps_[i].element = null;3733 var ref = comps_[i].config.ref;3734 var owner = renderer.getOwner();3735 if (owner.components[ref] === comps_[i]) {3736 owner.disposeSubComponents([ref]);3737 } else {3738 comps_[i].dispose();3739 }3740 }3741 }3742 }3743 comps_ = [];3744 };3745 /**3746 * Schedules the given components to be checked and disposed if not used3747 * anymore, when `IncrementalDomUnusedComponents.disposeUnused` is called.3748 * @param {!Array<!Component} comps3749 */3750 IncrementalDomUnusedComponents.schedule = function schedule(comps) {3751 for (var i = 0; i < comps.length; i++) {3752 comps[i].getRenderer().parent_ = null;3753 comps_.push(comps[i]);3754 }3755 };3756 return IncrementalDomUnusedComponents;3757}();3758exports.default = IncrementalDomUnusedComponents;3759},{}],25:[function(require,module,exports){3760'use strict';3761var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };3762/* jshint ignore:start */3763/**3764 * @license3765 * Copyright 2015 The Incremental DOM Authors. All Rights Reserved.3766 *3767 * Licensed under the Apache License, Version 2.0 (the "License");3768 * you may not use this file except in compliance with the License.3769 * You may obtain a copy of the License at3770 *3771 * http://www.apache.org/licenses/LICENSE-2.03772 *3773 * Unless required by applicable law or agreed to in writing, software3774 * distributed under the License is distributed on an "AS-IS" BASIS,3775 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.3776 * See the License for the specific language governing permissions and3777 * limitations under the License.3778 */3779(function (global, factory) {3780 factory(global.IncrementalDOM = global.IncrementalDOM || {});3781})(window, function (exports) {3782 'use strict';3783 /**3784 * Copyright 2015 The Incremental DOM Authors. All Rights Reserved.3785 *3786 * Licensed under the Apache License, Version 2.0 (the "License");3787 * you may not use this file except in compliance with the License.3788 * You may obtain a copy of the License at3789 *3790 * http://www.apache.org/licenses/LICENSE-2.03791 *3792 * Unless required by applicable law or agreed to in writing, software3793 * distributed under the License is distributed on an "AS-IS" BASIS,3794 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.3795 * See the License for the specific language governing permissions and3796 * limitations under the License.3797 */3798 /**3799 * A cached reference to the hasOwnProperty function.3800 */3801 var hasOwnProperty = Object.prototype.hasOwnProperty;3802 /**3803 * A constructor function that will create blank objects.3804 * @constructor3805 */3806 function Blank() {}3807 Blank.prototype = Object.create(null);3808 /**3809 * Used to prevent property collisions between our "map" and its prototype.3810 * @param {!Object<string, *>} map The map to check.3811 * @param {string} property The property to check.3812 * @return {boolean} Whether map has property.3813 */3814 var has = function has(map, property) {3815 return hasOwnProperty.call(map, property);3816 };3817 /**3818 * Creates an map object without a prototype.3819 * @return {!Object}3820 */3821 var createMap = function createMap() {3822 return new Blank();3823 };3824 /**3825 * The property name where we store Incremental DOM data.3826 */3827 var DATA_PROP = '__incrementalDOMData';3828 /**3829 * Keeps track of information needed to perform diffs for a given DOM node.3830 * @param {!string} nodeName3831 * @param {?string=} key3832 * @constructor3833 */3834 function NodeData(nodeName, key) {3835 /**3836 * The attributes and their values.3837 * @const {!Object<string, *>}3838 */3839 this.attrs = createMap();3840 /**3841 * An array of attribute name/value pairs, used for quickly diffing the3842 * incomming attributes to see if the DOM node's attributes need to be3843 * updated.3844 * @const {Array<*>}3845 */3846 this.attrsArr = [];3847 /**3848 * The incoming attributes for this Node, before they are updated.3849 * @const {!Object<string, *>}3850 */3851 this.newAttrs = createMap();3852 /**3853 * Whether or not the statics have been applied for the node yet.3854 * {boolean}3855 */3856 this.staticsApplied = false;3857 /**3858 * The key used to identify this node, used to preserve DOM nodes when they3859 * move within their parent.3860 * @const3861 */3862 this.key = key;3863 /**3864 * Keeps track of children within this node by their key.3865 * {!Object<string, !Element>}3866 */3867 this.keyMap = createMap();3868 /**3869 * Whether or not the keyMap is currently valid.3870 * @type {boolean}3871 */3872 this.keyMapValid = true;3873 /**3874 * Whether or the associated node is, or contains, a focused Element.3875 * @type {boolean}3876 */3877 this.focused = false;3878 /**3879 * The node name for this node.3880 * @const {string}3881 */3882 this.nodeName = nodeName;3883 /**3884 * @type {?string}3885 */3886 this.text = null;3887 }3888 /**3889 * Initializes a NodeData object for a Node.3890 *3891 * @param {Node} node The node to initialize data for.3892 * @param {string} nodeName The node name of node.3893 * @param {?string=} key The key that identifies the node.3894 * @return {!NodeData} The newly initialized data object3895 */3896 var initData = function initData(node, nodeName, key) {3897 var data = new NodeData(nodeName, key);3898 node[DATA_PROP] = data;3899 return data;3900 };3901 /**3902 * Retrieves the NodeData object for a Node, creating it if necessary.3903 *3904 * @param {?Node} node The Node to retrieve the data for.3905 * @return {!NodeData} The NodeData for this Node.3906 */3907 var getData = function getData(node) {3908 importNode(node);3909 return node[DATA_PROP];3910 };3911 /**3912 * Imports node and its subtree, initializing caches.3913 *3914 * @param {?Node} node The Node to import.3915 */3916 var importNode = function importNode(node) {3917 if (node[DATA_PROP]) {3918 return;3919 }3920 var nodeName = node.nodeName.toLowerCase();3921 var isElement = node instanceof Element;3922 var key = isElement ? node.getAttribute('key') : null;3923 var data = initData(node, nodeName, key);3924 if (key) {3925 getData(node.parentNode).keyMap[key] = node;3926 }3927 if (isElement) {3928 var attributes = node.attributes;3929 var attrs = data.attrs;3930 var newAttrs = data.newAttrs;3931 var attrsArr = data.attrsArr;3932 for (var i = 0; i < attributes.length; i += 1) {3933 var attr = attributes[i];3934 var name = attr.name;3935 var value = attr.value;3936 attrs[name] = value;3937 newAttrs[name] = undefined;3938 attrsArr.push(name);3939 attrsArr.push(value);3940 }3941 }3942 for (var child = node.firstChild; child; child = child.nextSibling) {3943 importNode(child);3944 }3945 };3946 /**3947 * Gets the namespace to create an element (of a given tag) in.3948 * @param {string} tag The tag to get the namespace for.3949 * @param {?Node} parent3950 * @return {?string} The namespace to create the tag in.3951 */3952 var getNamespaceForTag = function getNamespaceForTag(tag, parent) {3953 if (tag === 'svg') {3954 return 'http://www.w3.org/2000/svg';3955 }3956 if (getData(parent).nodeName === 'foreignObject') {3957 return null;3958 }3959 return parent.namespaceURI;3960 };3961 /**3962 * Creates an Element.3963 * @param {Document} doc The document with which to create the Element.3964 * @param {?Node} parent3965 * @param {string} tag The tag for the Element.3966 * @param {?string=} key A key to identify the Element.3967 * @return {!Element}3968 */3969 var createElement = function createElement(doc, parent, tag, key) {3970 var namespace = getNamespaceForTag(tag, parent);3971 var el = undefined;3972 if (namespace) {3973 el = doc.createElementNS(namespace, tag);3974 } else {3975 el = doc.createElement(tag);3976 }3977 initData(el, tag, key);3978 return el;3979 };3980 /**3981 * Creates a Text Node.3982 * @param {Document} doc The document with which to create the Element.3983 * @return {!Text}3984 */3985 var createText = function createText(doc) {3986 var node = doc.createTextNode('');3987 initData(node, '#text', null);3988 return node;3989 };3990 /**3991 * Copyright 2015 The Incremental DOM Authors. All Rights Reserved.3992 *3993 * Licensed under the Apache License, Version 2.0 (the "License");3994 * you may not use this file except in compliance with the License.3995 * You may obtain a copy of the License at3996 *3997 * http://www.apache.org/licenses/LICENSE-2.03998 *3999 * Unless required by applicable law or agreed to in writing, software4000 * distributed under the License is distributed on an "AS-IS" BASIS,4001 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.4002 * See the License for the specific language governing permissions and4003 * limitations under the License.4004 */4005 /** @const */4006 var notifications = {4007 /**4008 * Called after patch has compleated with any Nodes that have been created4009 * and added to the DOM.4010 * @type {?function(Array<!Node>)}4011 */4012 nodesCreated: null,4013 /**4014 * Called after patch has compleated with any Nodes that have been removed4015 * from the DOM.4016 * Note it's an applications responsibility to handle any childNodes.4017 * @type {?function(Array<!Node>)}4018 */4019 nodesDeleted: null4020 };4021 /**4022 * Keeps track of the state of a patch.4023 * @constructor4024 */4025 function Context() {4026 /**4027 * @type {(Array<!Node>|undefined)}4028 */4029 this.created = notifications.nodesCreated && [];4030 /**4031 * @type {(Array<!Node>|undefined)}4032 */4033 this.deleted = notifications.nodesDeleted && [];4034 }4035 /**4036 * @param {!Node} node4037 */4038 Context.prototype.markCreated = function (node) {4039 if (this.created) {4040 this.created.push(node);4041 }4042 };4043 /**4044 * @param {!Node} node4045 */4046 Context.prototype.markDeleted = function (node) {4047 if (this.deleted) {4048 this.deleted.push(node);4049 }4050 };4051 /**4052 * Notifies about nodes that were created during the patch opearation.4053 */4054 Context.prototype.notifyChanges = function () {4055 if (this.created && this.created.length > 0) {4056 notifications.nodesCreated(this.created);4057 }4058 if (this.deleted && this.deleted.length > 0) {4059 notifications.nodesDeleted(this.deleted);4060 }4061 };4062 /**4063 * Copyright 2016 The Incremental DOM Authors. All Rights Reserved.4064 *4065 * Licensed under the Apache License, Version 2.0 (the "License");4066 * you may not use this file except in compliance with the License.4067 * You may obtain a copy of the License at4068 *4069 * http://www.apache.org/licenses/LICENSE-2.04070 *4071 * Unless required by applicable law or agreed to in writing, software4072 * distributed under the License is distributed on an "AS-IS" BASIS,4073 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.4074 * See the License for the specific language governing permissions and4075 * limitations under the License.4076 */4077 /**4078 * @param {!Node} node4079 * @return {boolean} True if the node the root of a document, false otherwise.4080 */4081 var isDocumentRoot = function isDocumentRoot(node) {4082 // For ShadowRoots, check if they are a DocumentFragment instead of if they4083 // are a ShadowRoot so that this can work in 'use strict' if ShadowRoots are4084 // not supported.4085 return node instanceof Document || node instanceof DocumentFragment;4086 };4087 /**4088 * @param {!Node} node The node to start at, inclusive.4089 * @param {?Node} root The root ancestor to get until, exclusive.4090 * @return {!Array<!Node>} The ancestry of DOM nodes.4091 */4092 var getAncestry = function getAncestry(node, root) {4093 var ancestry = [];4094 var cur = node;4095 while (cur !== root) {4096 ancestry.push(cur);4097 cur = cur.parentNode;4098 }4099 return ancestry;4100 };4101 /**4102 * @param {!Node} node4103 * @return {!Node} The root node of the DOM tree that contains node.4104 */4105 var getRoot = function getRoot(node) {4106 var cur = node;4107 var prev = cur;4108 while (cur) {4109 prev = cur;4110 cur = cur.parentNode;4111 }4112 return prev;4113 };4114 /**4115 * @param {!Node} node The node to get the activeElement for.4116 * @return {?Element} The activeElement in the Document or ShadowRoot4117 * corresponding to node, if present.4118 */4119 var getActiveElement = function getActiveElement(node) {4120 var root = getRoot(node);4121 return isDocumentRoot(root) ? root.activeElement : null;4122 };4123 /**4124 * Gets the path of nodes that contain the focused node in the same document as4125 * a reference node, up until the root.4126 * @param {!Node} node The reference node to get the activeElement for.4127 * @param {?Node} root The root to get the focused path until.4128 * @return {!Array<Node>}4129 */4130 var getFocusedPath = function getFocusedPath(node, root) {4131 var activeElement = getActiveElement(node);4132 if (!activeElement || !node.contains(activeElement)) {4133 return [];4134 }4135 return getAncestry(activeElement, root);4136 };4137 /**4138 * Like insertBefore, but instead instead of moving the desired node, instead4139 * moves all the other nodes after.4140 * @param {?Node} parentNode4141 * @param {!Node} node4142 * @param {?Node} referenceNode4143 */4144 var moveBefore = function moveBefore(parentNode, node, referenceNode) {4145 var insertReferenceNode = node.nextSibling;4146 var cur = referenceNode;4147 while (cur !== node) {4148 var next = cur.nextSibling;4149 parentNode.insertBefore(cur, insertReferenceNode);4150 cur = next;4151 }4152 };4153 /** @type {?Context} */4154 var context = null;4155 /** @type {?Node} */4156 var currentNode = null;4157 /** @type {?Node} */4158 var currentParent = null;4159 /** @type {?Document} */4160 var doc = null;4161 /**4162 * @param {!Array<Node>} focusPath The nodes to mark.4163 * @param {boolean} focused Whether or not they are focused.4164 */4165 var markFocused = function markFocused(focusPath, focused) {4166 for (var i = 0; i < focusPath.length; i += 1) {4167 getData(focusPath[i]).focused = focused;4168 }4169 };4170 /**4171 * Returns a patcher function that sets up and restores a patch context,4172 * running the run function with the provided data.4173 * @param {function((!Element|!DocumentFragment),!function(T),T=): ?Node} run4174 * @return {function((!Element|!DocumentFragment),!function(T),T=): ?Node}4175 * @template T4176 */4177 var patchFactory = function patchFactory(run) {4178 /**4179 * TODO(moz): These annotations won't be necessary once we switch to Closure4180 * Compiler's new type inference. Remove these once the switch is done.4181 *4182 * @param {(!Element|!DocumentFragment)} node4183 * @param {!function(T)} fn4184 * @param {T=} data4185 * @return {?Node} node4186 * @template T4187 */4188 var f = function f(node, fn, data) {4189 var prevContext = context;4190 var prevDoc = doc;4191 var prevCurrentNode = currentNode;4192 var prevCurrentParent = currentParent;4193 var previousInAttributes = false;4194 var previousInSkip = false;4195 context = new Context();4196 doc = node.ownerDocument;4197 currentParent = node.parentNode;4198 if ('production' !== 'production') {}4199 var focusPath = getFocusedPath(node, currentParent);4200 markFocused(focusPath, true);4201 var retVal = run(node, fn, data);4202 markFocused(focusPath, false);4203 if ('production' !== 'production') {}4204 context.notifyChanges();4205 context = prevContext;4206 doc = prevDoc;4207 currentNode = prevCurrentNode;4208 currentParent = prevCurrentParent;4209 return retVal;4210 };4211 return f;4212 };4213 /**4214 * Patches the document starting at node with the provided function. This4215 * function may be called during an existing patch operation.4216 * @param {!Element|!DocumentFragment} node The Element or Document4217 * to patch.4218 * @param {!function(T)} fn A function containing elementOpen/elementClose/etc.4219 * calls that describe the DOM.4220 * @param {T=} data An argument passed to fn to represent DOM state.4221 * @return {!Node} The patched node.4222 * @template T4223 */4224 var patchInner = patchFactory(function (node, fn, data) {4225 currentNode = node;4226 enterNode();4227 fn(data);4228 exitNode();4229 if ('production' !== 'production') {}4230 return node;4231 });4232 /**4233 * Patches an Element with the the provided function. Exactly one top level4234 * element call should be made corresponding to `node`.4235 * @param {!Element} node The Element where the patch should start.4236 * @param {!function(T)} fn A function containing elementOpen/elementClose/etc.4237 * calls that describe the DOM. This should have at most one top level4238 * element call.4239 * @param {T=} data An argument passed to fn to represent DOM state.4240 * @return {?Node} The node if it was updated, its replacedment or null if it4241 * was removed.4242 * @template T4243 */4244 var patchOuter = patchFactory(function (node, fn, data) {4245 var startNode = /** @type {!Element} */{ nextSibling: node };4246 var expectedNextNode = null;4247 var expectedPrevNode = null;4248 if ('production' !== 'production') {}4249 currentNode = startNode;4250 fn(data);4251 if ('production' !== 'production') {}4252 if (node !== currentNode) {4253 removeChild(currentParent, node, getData(currentParent).keyMap);4254 }4255 return startNode === currentNode ? null : currentNode;4256 });4257 /**4258 * Checks whether or not the current node matches the specified nodeName and4259 * key.4260 *4261 * @param {!Node} matchNode A node to match the data to.4262 * @param {?string} nodeName The nodeName for this node.4263 * @param {?string=} key An optional key that identifies a node.4264 * @return {boolean} True if the node matches, false otherwise.4265 */4266 var matches = function matches(matchNode, nodeName, key) {4267 var data = getData(matchNode);4268 // Key check is done using double equals as we want to treat a null key the4269 // same as undefined. This should be okay as the only values allowed are4270 // strings, null and undefined so the == semantics are not too weird.4271 return nodeName === data.nodeName && key == data.key;4272 };4273 /**4274 * Aligns the virtual Element definition with the actual DOM, moving the4275 * corresponding DOM node to the correct location or creating it if necessary.4276 * @param {string} nodeName For an Element, this should be a valid tag string.4277 * For a Text, this should be #text.4278 * @param {?string=} key The key used to identify this element.4279 */4280 var alignWithDOM = function alignWithDOM(nodeName, key) {4281 if (currentNode && matches(currentNode, nodeName, key)) {4282 return;4283 }4284 var parentData = getData(currentParent);4285 var currentNodeData = currentNode && getData(currentNode);4286 var keyMap = parentData.keyMap;4287 var node = undefined;4288 // Check to see if the node has moved within the parent.4289 if (key) {4290 var keyNode = keyMap[key];4291 if (keyNode) {4292 if (matches(keyNode, nodeName, key)) {4293 node = keyNode;4294 } else if (keyNode === currentNode) {4295 context.markDeleted(keyNode);4296 } else {4297 removeChild(currentParent, keyNode, keyMap);4298 }4299 }4300 }4301 // Create the node if it doesn't exist.4302 if (!node) {4303 if (nodeName === '#text') {4304 node = createText(doc);4305 } else {4306 node = createElement(doc, currentParent, nodeName, key);4307 }4308 if (key) {4309 keyMap[key] = node;4310 }4311 context.markCreated(node);4312 }4313 // Re-order the node into the right position, preserving focus if either4314 // node or currentNode are focused by making sure that they are not detached4315 // from the DOM.4316 if (getData(node).focused) {4317 // Move everything else before the node.4318 moveBefore(currentParent, node, currentNode);4319 } else if (currentNodeData && currentNodeData.key && !currentNodeData.focused) {4320 // Remove the currentNode, which can always be added back since we hold a4321 // reference through the keyMap. This prevents a large number of moves when4322 // a keyed item is removed or moved backwards in the DOM.4323 currentParent.replaceChild(node, currentNode);4324 parentData.keyMapValid = false;4325 } else {4326 currentParent.insertBefore(node, currentNode);4327 }4328 currentNode = node;4329 };4330 /**4331 * @param {?Node} node4332 * @param {?Node} child4333 * @param {?Object<string, !Element>} keyMap4334 */4335 var removeChild = function removeChild(node, child, keyMap) {4336 node.removeChild(child);4337 context.markDeleted( /** @type {!Node}*/child);4338 var key = getData(child).key;4339 if (key) {4340 delete keyMap[key];4341 }4342 };4343 /**4344 * Clears out any unvisited Nodes, as the corresponding virtual element4345 * functions were never called for them.4346 */4347 var clearUnvisitedDOM = function clearUnvisitedDOM() {4348 var node = currentParent;4349 var data = getData(node);4350 var keyMap = data.keyMap;4351 var keyMapValid = data.keyMapValid;4352 var child = node.lastChild;4353 var key = undefined;4354 if (child === currentNode && keyMapValid) {4355 return;4356 }4357 while (child !== currentNode) {4358 removeChild(node, child, keyMap);4359 child = node.lastChild;4360 }4361 // Clean the keyMap, removing any unusued keys.4362 if (!keyMapValid) {4363 for (key in keyMap) {4364 child = keyMap[key];4365 if (child.parentNode !== node) {4366 context.markDeleted(child);4367 delete keyMap[key];4368 }4369 }4370 data.keyMapValid = true;4371 }4372 };4373 /**4374 * Changes to the first child of the current node.4375 */4376 var enterNode = function enterNode() {4377 currentParent = currentNode;4378 currentNode = null;4379 };4380 /**4381 * @return {?Node} The next Node to be patched.4382 */4383 var getNextNode = function getNextNode() {4384 if (currentNode) {4385 return currentNode.nextSibling;4386 } else {4387 return currentParent.firstChild;4388 }4389 };4390 /**4391 * Changes to the next sibling of the current node.4392 */4393 var nextNode = function nextNode() {4394 currentNode = getNextNode();4395 };4396 /**4397 * Changes to the parent of the current node, removing any unvisited children.4398 */4399 var exitNode = function exitNode() {4400 clearUnvisitedDOM();4401 currentNode = currentParent;4402 currentParent = currentParent.parentNode;4403 };4404 /**4405 * Makes sure that the current node is an Element with a matching tagName and4406 * key.4407 *4408 * @param {string} tag The element's tag.4409 * @param {?string=} key The key used to identify this element. This can be an4410 * empty string, but performance may be better if a unique value is used4411 * when iterating over an array of items.4412 * @return {!Element} The corresponding Element.4413 */4414 var coreElementOpen = function coreElementOpen(tag, key) {4415 nextNode();4416 alignWithDOM(tag, key);4417 enterNode();4418 return (/** @type {!Element} */currentParent4419 );4420 };4421 /**4422 * Closes the currently open Element, removing any unvisited children if4423 * necessary.4424 *4425 * @return {!Element} The corresponding Element.4426 */4427 var coreElementClose = function coreElementClose() {4428 if ('production' !== 'production') {}4429 exitNode();4430 return (/** @type {!Element} */currentNode4431 );4432 };4433 /**4434 * Makes sure the current node is a Text node and creates a Text node if it is4435 * not.4436 *4437 * @return {!Text} The corresponding Text Node.4438 */4439 var coreText = function coreText() {4440 nextNode();4441 alignWithDOM('#text', null);4442 return (/** @type {!Text} */currentNode4443 );4444 };4445 /**4446 * Gets the current Element being patched.4447 * @return {!Element}4448 */4449 var currentElement = function currentElement() {4450 if ('production' !== 'production') {}4451 return (/** @type {!Element} */currentParent4452 );4453 };4454 /**4455 * @return {Node} The Node that will be evaluated for the next instruction.4456 */4457 var currentPointer = function currentPointer() {4458 if ('production' !== 'production') {}4459 return getNextNode();4460 };4461 /**4462 * Skips the children in a subtree, allowing an Element to be closed without4463 * clearing out the children.4464 */4465 var skip = function skip() {4466 if ('production' !== 'production') {}4467 currentNode = currentParent.lastChild;4468 };4469 /**4470 * Skips the next Node to be patched, moving the pointer forward to the next4471 * sibling of the current pointer.4472 */4473 var skipNode = nextNode;4474 /**4475 * Copyright 2015 The Incremental DOM Authors. All Rights Reserved.4476 *4477 * Licensed under the Apache License, Version 2.0 (the "License");4478 * you may not use this file except in compliance with the License.4479 * You may obtain a copy of the License at4480 *4481 * http://www.apache.org/licenses/LICENSE-2.04482 *4483 * Unless required by applicable law or agreed to in writing, software4484 * distributed under the License is distributed on an "AS-IS" BASIS,4485 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.4486 * See the License for the specific language governing permissions and4487 * limitations under the License.4488 */4489 /** @const */4490 var symbols = {4491 default: '__default'4492 };4493 /**4494 * @param {string} name4495 * @return {string|undefined} The namespace to use for the attribute.4496 */4497 var getNamespace = function getNamespace(name) {4498 if (name.lastIndexOf('xml:', 0) === 0) {4499 return 'http://www.w3.org/XML/1998/namespace';4500 }4501 if (name.lastIndexOf('xlink:', 0) === 0) {4502 return 'http://www.w3.org/1999/xlink';4503 }4504 };4505 /**4506 * Applies an attribute or property to a given Element. If the value is null4507 * or undefined, it is removed from the Element. Otherwise, the value is set4508 * as an attribute.4509 * @param {!Element} el4510 * @param {string} name The attribute's name.4511 * @param {?(boolean|number|string)=} value The attribute's value.4512 */4513 var applyAttr = function applyAttr(el, name, value) {4514 if (value == null) {4515 el.removeAttribute(name);4516 } else {4517 var attrNS = getNamespace(name);4518 if (attrNS) {4519 el.setAttributeNS(attrNS, name, value);4520 } else {4521 el.setAttribute(name, value);4522 }4523 }4524 };4525 /**4526 * Applies a property to a given Element.4527 * @param {!Element} el4528 * @param {string} name The property's name.4529 * @param {*} value The property's value.4530 */4531 var applyProp = function applyProp(el, name, value) {4532 el[name] = value;4533 };4534 /**4535 * Applies a value to a style declaration. Supports CSS custom properties by4536 * setting properties containing a dash using CSSStyleDeclaration.setProperty.4537 * @param {CSSStyleDeclaration} style4538 * @param {!string} prop4539 * @param {*} value4540 */4541 var setStyleValue = function setStyleValue(style, prop, value) {4542 if (prop.indexOf('-') >= 0) {4543 style.setProperty(prop, /** @type {string} */value);4544 } else {4545 style[prop] = value;4546 }4547 };4548 /**4549 * Applies a style to an Element. No vendor prefix expansion is done for4550 * property names/values.4551 * @param {!Element} el4552 * @param {string} name The attribute's name.4553 * @param {*} style The style to set. Either a string of css or an object4554 * containing property-value pairs.4555 */4556 var applyStyle = function applyStyle(el, name, style) {4557 if (typeof style === 'string') {4558 el.style.cssText = style;4559 } else {4560 el.style.cssText = '';4561 var elStyle = el.style;4562 var obj = /** @type {!Object<string,string>} */style;4563 for (var prop in obj) {4564 if (has(obj, prop)) {4565 setStyleValue(elStyle, prop, obj[prop]);4566 }4567 }4568 }4569 };4570 /**4571 * Updates a single attribute on an Element.4572 * @param {!Element} el4573 * @param {string} name The attribute's name.4574 * @param {*} value The attribute's value. If the value is an object or4575 * function it is set on the Element, otherwise, it is set as an HTML4576 * attribute.4577 */4578 var applyAttributeTyped = function applyAttributeTyped(el, name, value) {4579 var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);4580 if (type === 'object' || type === 'function') {4581 applyProp(el, name, value);4582 } else {4583 applyAttr(el, name, /** @type {?(boolean|number|string)} */value);4584 }4585 };4586 /**4587 * Calls the appropriate attribute mutator for this attribute.4588 * @param {!Element} el4589 * @param {string} name The attribute's name.4590 * @param {*} value The attribute's value.4591 */4592 var updateAttribute = function updateAttribute(el, name, value) {4593 var data = getData(el);4594 var attrs = data.attrs;4595 if (attrs[name] === value) {4596 return;4597 }4598 var mutator = attributes[name] || attributes[symbols.default];4599 mutator(el, name, value);4600 attrs[name] = value;4601 };4602 /**4603 * A publicly mutable object to provide custom mutators for attributes.4604 * @const {!Object<string, function(!Element, string, *)>}4605 */4606 var attributes = createMap();4607 // Special generic mutator that's called for any attribute that does not4608 // have a specific mutator.4609 attributes[symbols.default] = applyAttributeTyped;4610 attributes['style'] = applyStyle;4611 /**4612 * The offset in the virtual element declaration where the attributes are4613 * specified.4614 * @const4615 */4616 var ATTRIBUTES_OFFSET = 3;4617 /**4618 * Builds an array of arguments for use with elementOpenStart, attr and4619 * elementOpenEnd.4620 * @const {Array<*>}4621 */4622 var argsBuilder = [];4623 /**4624 * @param {string} tag The element's tag.4625 * @param {?string=} key The key used to identify this element. This can be an4626 * empty string, but performance may be better if a unique value is used4627 * when iterating over an array of items.4628 * @param {?Array<*>=} statics An array of attribute name/value pairs of the4629 * static attributes for the Element. These will only be set once when the4630 * Element is created.4631 * @param {...*} var_args, Attribute name/value pairs of the dynamic attributes4632 * for the Element.4633 * @return {!Element} The corresponding Element.4634 */4635 var elementOpen = function elementOpen(tag, key, statics, var_args) {4636 if ('production' !== 'production') {}4637 var node = coreElementOpen(tag, key);4638 var data = getData(node);4639 if (!data.staticsApplied) {4640 if (statics) {4641 for (var _i = 0; _i < statics.length; _i += 2) {4642 var name = /** @type {string} */statics[_i];4643 var value = statics[_i + 1];4644 updateAttribute(node, name, value);4645 }4646 }4647 // Down the road, we may want to keep track of the statics array to use it4648 // as an additional signal about whether a node matches or not. For now,4649 // just use a marker so that we do not reapply statics.4650 data.staticsApplied = true;4651 }4652 /*4653 * Checks to see if one or more attributes have changed for a given Element.4654 * When no attributes have changed, this is much faster than checking each4655 * individual argument. When attributes have changed, the overhead of this is4656 * minimal.4657 */4658 var attrsArr = data.attrsArr;4659 var newAttrs = data.newAttrs;4660 var isNew = !attrsArr.length;4661 var i = ATTRIBUTES_OFFSET;4662 var j = 0;4663 for (; i < arguments.length; i += 2, j += 2) {4664 var _attr = arguments[i];4665 if (isNew) {4666 attrsArr[j] = _attr;4667 newAttrs[_attr] = undefined;4668 } else if (attrsArr[j] !== _attr) {4669 break;4670 }4671 var value = arguments[i + 1];4672 if (isNew || attrsArr[j + 1] !== value) {4673 attrsArr[j + 1] = value;4674 updateAttribute(node, _attr, value);4675 }4676 }4677 if (i < arguments.length || j < attrsArr.length) {4678 for (; i < arguments.length; i += 1, j += 1) {4679 attrsArr[j] = arguments[i];4680 }4681 if (j < attrsArr.length) {4682 attrsArr.length = j;4683 }4684 /*4685 * Actually perform the attribute update.4686 */4687 for (i = 0; i < attrsArr.length; i += 2) {4688 var name = /** @type {string} */attrsArr[i];4689 var value = attrsArr[i + 1];4690 newAttrs[name] = value;4691 }4692 for (var _attr2 in newAttrs) {4693 updateAttribute(node, _attr2, newAttrs[_attr2]);4694 newAttrs[_attr2] = undefined;4695 }4696 }4697 return node;4698 };4699 /**4700 * Declares a virtual Element at the current location in the document. This4701 * corresponds to an opening tag and a elementClose tag is required. This is4702 * like elementOpen, but the attributes are defined using the attr function4703 * rather than being passed as arguments. Must be folllowed by 0 or more calls4704 * to attr, then a call to elementOpenEnd.4705 * @param {string} tag The element's tag.4706 * @param {?string=} key The key used to identify this element. This can be an4707 * empty string, but performance may be better if a unique value is used4708 * when iterating over an array of items.4709 * @param {?Array<*>=} statics An array of attribute name/value pairs of the4710 * static attributes for the Element. These will only be set once when the4711 * Element is created.4712 */4713 var elementOpenStart = function elementOpenStart(tag, key, statics) {4714 if ('production' !== 'production') {}4715 argsBuilder[0] = tag;4716 argsBuilder[1] = key;4717 argsBuilder[2] = statics;4718 };4719 /***4720 * Defines a virtual attribute at this point of the DOM. This is only valid4721 * when called between elementOpenStart and elementOpenEnd.4722 *4723 * @param {string} name4724 * @param {*} value4725 */4726 var attr = function attr(name, value) {4727 if ('production' !== 'production') {}4728 argsBuilder.push(name);4729 argsBuilder.push(value);4730 };4731 /**4732 * Closes an open tag started with elementOpenStart.4733 * @return {!Element} The corresponding Element.4734 */4735 var elementOpenEnd = function elementOpenEnd() {4736 if ('production' !== 'production') {}4737 var node = elementOpen.apply(null, argsBuilder);4738 argsBuilder.length = 0;4739 return node;4740 };4741 /**4742 * Closes an open virtual Element.4743 *4744 * @param {string} tag The element's tag.4745 * @return {!Element} The corresponding Element.4746 */4747 var elementClose = function elementClose(tag) {4748 if ('production' !== 'production') {}4749 var node = coreElementClose();4750 if ('production' !== 'production') {}4751 return node;4752 };4753 /**4754 * Declares a virtual Element at the current location in the document that has4755 * no children.4756 * @param {string} tag The element's tag.4757 * @param {?string=} key The key used to identify this element. This can be an4758 * empty string, but performance may be better if a unique value is used4759 * when iterating over an array of items.4760 * @param {?Array<*>=} statics An array of attribute name/value pairs of the4761 * static attributes for the Element. These will only be set once when the4762 * Element is created.4763 * @param {...*} var_args Attribute name/value pairs of the dynamic attributes4764 * for the Element.4765 * @return {!Element} The corresponding Element.4766 */4767 var elementVoid = function elementVoid(tag, key, statics, var_args) {4768 elementOpen.apply(null, arguments);4769 return elementClose(tag);4770 };4771 /**4772 * Declares a virtual Text at this point in the document.4773 *4774 * @param {string|number|boolean} value The value of the Text.4775 * @param {...(function((string|number|boolean)):string)} var_args4776 * Functions to format the value which are called only when the value has4777 * changed.4778 * @return {!Text} The corresponding text node.4779 */4780 var text = function text(value, var_args) {4781 if ('production' !== 'production') {}4782 var node = coreText();4783 var data = getData(node);4784 if (data.text !== value) {4785 data.text = /** @type {string} */value;4786 var formatted = value;4787 for (var i = 1; i < arguments.length; i += 1) {4788 /*4789 * Call the formatter function directly to prevent leaking arguments.4790 * https://github.com/google/incremental-dom/pull/204#issuecomment-1782235744791 */4792 var fn = arguments[i];4793 formatted = fn(formatted);4794 }4795 node.data = formatted;4796 }4797 return node;4798 };4799 exports.patch = patchInner;4800 exports.patchInner = patchInner;4801 exports.patchOuter = patchOuter;4802 exports.currentElement = currentElement;4803 exports.currentPointer = currentPointer;4804 exports.skip = skip;4805 exports.skipNode = skipNode;4806 exports.elementVoid = elementVoid;4807 exports.elementOpenStart = elementOpenStart;4808 exports.elementOpenEnd = elementOpenEnd;4809 exports.elementOpen = elementOpen;4810 exports.elementClose = elementClose;4811 exports.text = text;4812 exports.attr = attr;4813 exports.symbols = symbols;4814 exports.attributes = attributes;4815 exports.applyAttr = applyAttr;4816 exports.applyProp = applyProp;4817 exports.notifications = notifications;4818 exports.importNode = importNode;4819});4820/* jshint ignore:end */4821},{}],26:[function(require,module,exports){4822'use strict';4823Object.defineProperty(exports, "__esModule", {4824 value: true4825});4826var _metal = require('metal');4827var _metal2 = _interopRequireDefault(_metal);4828function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }4829function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }4830/**4831 * Utility functions used to handle incremental dom calls.4832 */4833var IncrementalDomUtils = function () {4834 function IncrementalDomUtils() {4835 _classCallCheck(this, IncrementalDomUtils);4836 }4837 /**4838 * Builds the component config object from its incremental dom call's4839 * arguments.4840 * @param {!Array} args4841 * @return {!Object}4842 */4843 IncrementalDomUtils.buildConfigFromCall = function buildConfigFromCall(args) {4844 var config = {};4845 if (args[1]) {4846 config.key = args[1];4847 }4848 var attrsArr = (args[2] || []).concat(args.slice(3));4849 for (var i = 0; i < attrsArr.length; i += 2) {4850 config[attrsArr[i]] = attrsArr[i + 1];4851 }4852 return config;4853 };4854 /**4855 * Builds an incremental dom call array from the given tag and config object.4856 * @param {string} tag4857 * @param {!Object} config4858 * @return {!Array}4859 */4860 IncrementalDomUtils.buildCallFromConfig = function buildCallFromConfig(tag, config) {4861 var call = [tag, config.key, []];4862 var keys = Object.keys(config);4863 for (var i = 0; i < keys.length; i++) {4864 if (keys[i] !== 'children') {4865 call.push(keys[i], config[keys[i]]);4866 }4867 }4868 return call;4869 };4870 /**4871 * Checks if the given tag represents a metal component.4872 * @param {string} tag4873 * @param {boolean}4874 */4875 IncrementalDomUtils.isComponentTag = function isComponentTag(tag) {4876 return !_metal2.default.isString(tag) || tag[0] === tag[0].toUpperCase();4877 };4878 return IncrementalDomUtils;4879}();4880exports.default = IncrementalDomUtils;4881},{"metal":34}],27:[function(require,module,exports){4882'use strict';4883Object.defineProperty(exports, "__esModule", {4884 value: true4885});4886require('./iDOMHelpers');4887var _metalComponent = require('metal-component');4888var _metalComponent2 = _interopRequireDefault(_metalComponent);4889var _metalIncrementalDom = require('metal-incremental-dom');...

Full Screen

Full Screen

compiler-core.cjs.js

Source:compiler-core.cjs.js Github

copy

Full Screen

...3726};3727function resolveComponentType(node, context, ssr = false) {3728 const { tag } = node;3729 // 1. dynamic component3730 const isProp = isComponentTag(tag)3731 ? findProp(node, 'is')3732 : findDir(node, 'is');3733 if (isProp) {3734 const exp = isProp.type === 6 /* ATTRIBUTE */3735 ? isProp.value && createSimpleExpression(isProp.value.content, true)3736 : isProp.exp;3737 if (exp) {3738 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3739 exp3740 ]);3741 }3742 }3743 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)3744 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);3745 if (builtIn) {3746 // built-ins are simply fallthroughs / have special handling during ssr3747 // so we don't need to import their runtime equivalents3748 if (!ssr)3749 context.helper(builtIn);3750 return builtIn;3751 }3752 // 3. user component (from setup bindings)3753 // this is skipped in browser build since browser builds do not perform3754 // binding analysis.3755 {3756 const fromSetup = resolveSetupReference(tag, context);3757 if (fromSetup) {3758 return fromSetup;3759 }3760 }3761 // 4. Self referencing component (inferred from filename)3762 if (context.selfName &&3763 shared.capitalize(shared.camelize(tag)) === context.selfName) {3764 context.helper(RESOLVE_COMPONENT);3765 // codegen.ts has special check for __self postfix when generating3766 // component imports, which will pass additional `maybeSelfReference` flag3767 // to `resolveComponent`.3768 context.components.add(tag + `__self`);3769 return toValidAssetId(tag, `component`);3770 }3771 // 5. user component (resolve)3772 context.helper(RESOLVE_COMPONENT);3773 context.components.add(tag);3774 return toValidAssetId(tag, `component`);3775}3776function resolveSetupReference(name, context) {3777 const bindings = context.bindingMetadata;3778 if (!bindings || bindings.__isScriptSetup === false) {3779 return;3780 }3781 const camelName = shared.camelize(name);3782 const PascalName = shared.capitalize(camelName);3783 const checkType = (type) => {3784 if (bindings[name] === type) {3785 return name;3786 }3787 if (bindings[camelName] === type) {3788 return camelName;3789 }3790 if (bindings[PascalName] === type) {3791 return PascalName;3792 }3793 };3794 const fromConst = checkType("setup-const" /* SETUP_CONST */);3795 if (fromConst) {3796 return context.inline3797 ? // in inline mode, const setup bindings (e.g. imports) can be used as-is3798 fromConst3799 : `$setup[${JSON.stringify(fromConst)}]`;3800 }3801 const fromMaybeRef = checkType("setup-let" /* SETUP_LET */) ||3802 checkType("setup-ref" /* SETUP_REF */) ||3803 checkType("setup-maybe-ref" /* SETUP_MAYBE_REF */);3804 if (fromMaybeRef) {3805 return context.inline3806 ? // setup scope bindings that may be refs need to be unrefed3807 `${context.helperString(UNREF)}(${fromMaybeRef})`3808 : `$setup[${JSON.stringify(fromMaybeRef)}]`;3809 }3810}3811function buildProps(node, context, props = node.props, ssr = false) {3812 const { tag, loc: elementLoc } = node;3813 const isComponent = node.tagType === 1 /* COMPONENT */;3814 let properties = [];3815 const mergeArgs = [];3816 const runtimeDirectives = [];3817 // patchFlag analysis3818 let patchFlag = 0;3819 let hasRef = false;3820 let hasClassBinding = false;3821 let hasStyleBinding = false;3822 let hasHydrationEventBinding = false;3823 let hasDynamicKeys = false;3824 let hasVnodeHook = false;3825 const dynamicPropNames = [];3826 const analyzePatchFlag = ({ key, value }) => {3827 if (isStaticExp(key)) {3828 const name = key.content;3829 const isEventHandler = shared.isOn(name);3830 if (!isComponent &&3831 isEventHandler &&3832 // omit the flag for click handlers because hydration gives click3833 // dedicated fast path.3834 name.toLowerCase() !== 'onclick' &&3835 // omit v-model handlers3836 name !== 'onUpdate:modelValue' &&3837 // omit onVnodeXXX hooks3838 !shared.isReservedProp(name)) {3839 hasHydrationEventBinding = true;3840 }3841 if (isEventHandler && shared.isReservedProp(name)) {3842 hasVnodeHook = true;3843 }3844 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3845 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3846 value.type === 8 /* COMPOUND_EXPRESSION */) &&3847 getConstantType(value, context) > 0)) {3848 // skip if the prop is a cached handler or has constant value3849 return;3850 }3851 if (name === 'ref') {3852 hasRef = true;3853 }3854 else if (name === 'class' && !isComponent) {3855 hasClassBinding = true;3856 }3857 else if (name === 'style' && !isComponent) {3858 hasStyleBinding = true;3859 }3860 else if (name !== 'key' && !dynamicPropNames.includes(name)) {3861 dynamicPropNames.push(name);3862 }3863 }3864 else {3865 hasDynamicKeys = true;3866 }3867 };3868 for (let i = 0; i < props.length; i++) {3869 // static attribute3870 const prop = props[i];3871 if (prop.type === 6 /* ATTRIBUTE */) {3872 const { loc, name, value } = prop;3873 let isStatic = true;3874 if (name === 'ref') {3875 hasRef = true;3876 // in inline mode there is no setupState object, so we can't use string3877 // keys to set the ref. Instead, we need to transform it to pass the3878 // acrtual ref instead.3879 if (context.inline) {3880 isStatic = false;3881 }3882 }3883 // skip :is on <component>3884 if (name === 'is' && isComponentTag(tag)) {3885 continue;3886 }3887 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));3888 }3889 else {3890 // directives3891 const { name, arg, exp, loc } = prop;3892 const isBind = name === 'bind';3893 const isOn = name === 'on';3894 // skip v-slot - it is handled by its dedicated transform.3895 if (name === 'slot') {3896 if (!isComponent) {3897 context.onError(createCompilerError(39 /* X_V_SLOT_MISPLACED */, loc));3898 }3899 continue;3900 }3901 // skip v-once - it is handled by its dedicated transform.3902 if (name === 'once') {3903 continue;3904 }3905 // skip v-is and :is on <component>3906 if (name === 'is' ||3907 (isBind && isComponentTag(tag) && isBindKey(arg, 'is'))) {3908 continue;3909 }3910 // skip v-on in SSR compilation3911 if (isOn && ssr) {3912 continue;3913 }3914 // special case for v-bind and v-on with no argument3915 if (!arg && (isBind || isOn)) {3916 hasDynamicKeys = true;3917 if (exp) {3918 if (properties.length) {3919 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3920 properties = [];3921 }3922 if (isBind) {3923 mergeArgs.push(exp);3924 }3925 else {3926 // v-on="obj" -> toHandlers(obj)3927 mergeArgs.push({3928 type: 14 /* JS_CALL_EXPRESSION */,3929 loc,3930 callee: context.helper(TO_HANDLERS),3931 arguments: [exp]3932 });3933 }3934 }3935 else {3936 context.onError(createCompilerError(isBind3937 ? 33 /* X_V_BIND_NO_EXPRESSION */3938 : 34 /* X_V_ON_NO_EXPRESSION */, loc));3939 }3940 continue;3941 }3942 const directiveTransform = context.directiveTransforms[name];3943 if (directiveTransform) {3944 // has built-in directive transform.3945 const { props, needRuntime } = directiveTransform(prop, node, context);3946 !ssr && props.forEach(analyzePatchFlag);3947 properties.push(...props);3948 if (needRuntime) {3949 runtimeDirectives.push(prop);3950 if (shared.isSymbol(needRuntime)) {3951 directiveImportMap.set(prop, needRuntime);3952 }3953 }3954 }3955 else {3956 // no built-in transform, this is a user custom directive.3957 runtimeDirectives.push(prop);3958 }3959 }3960 }3961 let propsExpression = undefined;3962 // has v-bind="object" or v-on="object", wrap with mergeProps3963 if (mergeArgs.length) {3964 if (properties.length) {3965 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3966 }3967 if (mergeArgs.length > 1) {3968 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);3969 }3970 else {3971 // single v-bind with nothing else - no need for a mergeProps call3972 propsExpression = mergeArgs[0];3973 }3974 }3975 else if (properties.length) {3976 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);3977 }3978 // patchFlag analysis3979 if (hasDynamicKeys) {3980 patchFlag |= 16 /* FULL_PROPS */;3981 }3982 else {3983 if (hasClassBinding) {3984 patchFlag |= 2 /* CLASS */;3985 }3986 if (hasStyleBinding) {3987 patchFlag |= 4 /* STYLE */;3988 }3989 if (dynamicPropNames.length) {3990 patchFlag |= 8 /* PROPS */;3991 }3992 if (hasHydrationEventBinding) {3993 patchFlag |= 32 /* HYDRATE_EVENTS */;3994 }3995 }3996 if ((patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&3997 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {3998 patchFlag |= 512 /* NEED_PATCH */;3999 }4000 return {4001 props: propsExpression,4002 directives: runtimeDirectives,4003 patchFlag,4004 dynamicPropNames4005 };4006}4007// Dedupe props in an object literal.4008// Literal duplicated attributes would have been warned during the parse phase,4009// however, it's possible to encounter duplicated `onXXX` handlers with different4010// modifiers. We also need to merge static and dynamic class / style attributes.4011// - onXXX handlers / style: merge into array4012// - class: merge into single expression with concatenation4013function dedupeProperties(properties) {4014 const knownProps = new Map();4015 const deduped = [];4016 for (let i = 0; i < properties.length; i++) {4017 const prop = properties[i];4018 // dynamic keys are always allowed4019 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {4020 deduped.push(prop);4021 continue;4022 }4023 const name = prop.key.content;4024 const existing = knownProps.get(name);4025 if (existing) {4026 if (name === 'style' || name === 'class' || name.startsWith('on')) {4027 mergeAsArray(existing, prop);4028 }4029 // unexpected duplicate, should have emitted error during parse4030 }4031 else {4032 knownProps.set(name, prop);4033 deduped.push(prop);4034 }4035 }4036 return deduped;4037}4038function mergeAsArray(existing, incoming) {4039 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {4040 existing.value.elements.push(incoming.value);4041 }4042 else {4043 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);4044 }4045}4046function buildDirectiveArgs(dir, context) {4047 const dirArgs = [];4048 const runtime = directiveImportMap.get(dir);4049 if (runtime) {4050 // built-in directive with runtime4051 dirArgs.push(context.helperString(runtime));4052 }4053 else {4054 // user directive.4055 // see if we have directives exposed via <script setup>4056 const fromSetup = resolveSetupReference(dir.name, context);4057 if (fromSetup) {4058 dirArgs.push(fromSetup);4059 }4060 else {4061 // inject statement for resolving directive4062 context.helper(RESOLVE_DIRECTIVE);4063 context.directives.add(dir.name);4064 dirArgs.push(toValidAssetId(dir.name, `directive`));4065 }4066 }4067 const { loc } = dir;4068 if (dir.exp)4069 dirArgs.push(dir.exp);4070 if (dir.arg) {4071 if (!dir.exp) {4072 dirArgs.push(`void 0`);4073 }4074 dirArgs.push(dir.arg);4075 }4076 if (Object.keys(dir.modifiers).length) {4077 if (!dir.arg) {4078 if (!dir.exp) {4079 dirArgs.push(`void 0`);4080 }4081 dirArgs.push(`void 0`);4082 }4083 const trueExpression = createSimpleExpression(`true`, false, loc);4084 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4085 }4086 return createArrayExpression(dirArgs, dir.loc);4087}4088function stringifyDynamicPropNames(props) {4089 let propsNamesString = `[`;4090 for (let i = 0, l = props.length; i < l; i++) {4091 propsNamesString += JSON.stringify(props[i]);4092 if (i < l - 1)4093 propsNamesString += ', ';4094 }4095 return propsNamesString + `]`;4096}4097function isComponentTag(tag) {4098 return tag[0].toLowerCase() + tag.slice(1) === 'component';4099}4100Object.freeze({})4101 ;4102Object.freeze([]) ;4103const cacheStringFunction = (fn) => {4104 const cache = Object.create(null);4105 return ((str) => {4106 const hit = cache[str];4107 return hit || (cache[str] = fn(str));4108 });4109};4110const camelizeRE = /-(\w)/g;4111/** ...

Full Screen

Full Screen

compiler-core.cjs.prod.js

Source:compiler-core.cjs.prod.js Github

copy

Full Screen

...3652};3653function resolveComponentType(node, context, ssr = false) {3654 const { tag } = node;3655 // 1. dynamic component3656 const isProp = isComponentTag(tag)3657 ? findProp(node, 'is')3658 : findDir(node, 'is');3659 if (isProp) {3660 const exp = isProp.type === 6 /* ATTRIBUTE */3661 ? isProp.value && createSimpleExpression(isProp.value.content, true)3662 : isProp.exp;3663 if (exp) {3664 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3665 exp3666 ]);3667 }3668 }3669 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)3670 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);3671 if (builtIn) {3672 // built-ins are simply fallthroughs / have special handling during ssr3673 // so we don't need to import their runtime equivalents3674 if (!ssr)3675 context.helper(builtIn);3676 return builtIn;3677 }3678 // 3. user component (from setup bindings)3679 // this is skipped in browser build since browser builds do not perform3680 // binding analysis.3681 {3682 const fromSetup = resolveSetupReference(tag, context);3683 if (fromSetup) {3684 return fromSetup;3685 }3686 }3687 // 4. Self referencing component (inferred from filename)3688 if (context.selfName &&3689 shared.capitalize(shared.camelize(tag)) === context.selfName) {3690 context.helper(RESOLVE_COMPONENT);3691 // codegen.ts has special check for __self postfix when generating3692 // component imports, which will pass additional `maybeSelfReference` flag3693 // to `resolveComponent`.3694 context.components.add(tag + `__self`);3695 return toValidAssetId(tag, `component`);3696 }3697 // 5. user component (resolve)3698 context.helper(RESOLVE_COMPONENT);3699 context.components.add(tag);3700 return toValidAssetId(tag, `component`);3701}3702function resolveSetupReference(name, context) {3703 const bindings = context.bindingMetadata;3704 if (!bindings || bindings.__isScriptSetup === false) {3705 return;3706 }3707 const camelName = shared.camelize(name);3708 const PascalName = shared.capitalize(camelName);3709 const checkType = (type) => {3710 if (bindings[name] === type) {3711 return name;3712 }3713 if (bindings[camelName] === type) {3714 return camelName;3715 }3716 if (bindings[PascalName] === type) {3717 return PascalName;3718 }3719 };3720 const fromConst = checkType("setup-const" /* SETUP_CONST */);3721 if (fromConst) {3722 return context.inline3723 ? // in inline mode, const setup bindings (e.g. imports) can be used as-is3724 fromConst3725 : `$setup[${JSON.stringify(fromConst)}]`;3726 }3727 const fromMaybeRef = checkType("setup-let" /* SETUP_LET */) ||3728 checkType("setup-ref" /* SETUP_REF */) ||3729 checkType("setup-maybe-ref" /* SETUP_MAYBE_REF */);3730 if (fromMaybeRef) {3731 return context.inline3732 ? // setup scope bindings that may be refs need to be unrefed3733 `${context.helperString(UNREF)}(${fromMaybeRef})`3734 : `$setup[${JSON.stringify(fromMaybeRef)}]`;3735 }3736}3737function buildProps(node, context, props = node.props, ssr = false) {3738 const { tag, loc: elementLoc } = node;3739 const isComponent = node.tagType === 1 /* COMPONENT */;3740 let properties = [];3741 const mergeArgs = [];3742 const runtimeDirectives = [];3743 // patchFlag analysis3744 let patchFlag = 0;3745 let hasRef = false;3746 let hasClassBinding = false;3747 let hasStyleBinding = false;3748 let hasHydrationEventBinding = false;3749 let hasDynamicKeys = false;3750 let hasVnodeHook = false;3751 const dynamicPropNames = [];3752 const analyzePatchFlag = ({ key, value }) => {3753 if (isStaticExp(key)) {3754 const name = key.content;3755 const isEventHandler = shared.isOn(name);3756 if (!isComponent &&3757 isEventHandler &&3758 // omit the flag for click handlers because hydration gives click3759 // dedicated fast path.3760 name.toLowerCase() !== 'onclick' &&3761 // omit v-model handlers3762 name !== 'onUpdate:modelValue' &&3763 // omit onVnodeXXX hooks3764 !shared.isReservedProp(name)) {3765 hasHydrationEventBinding = true;3766 }3767 if (isEventHandler && shared.isReservedProp(name)) {3768 hasVnodeHook = true;3769 }3770 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3771 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3772 value.type === 8 /* COMPOUND_EXPRESSION */) &&3773 getConstantType(value, context) > 0)) {3774 // skip if the prop is a cached handler or has constant value3775 return;3776 }3777 if (name === 'ref') {3778 hasRef = true;3779 }3780 else if (name === 'class' && !isComponent) {3781 hasClassBinding = true;3782 }3783 else if (name === 'style' && !isComponent) {3784 hasStyleBinding = true;3785 }3786 else if (name !== 'key' && !dynamicPropNames.includes(name)) {3787 dynamicPropNames.push(name);3788 }3789 }3790 else {3791 hasDynamicKeys = true;3792 }3793 };3794 for (let i = 0; i < props.length; i++) {3795 // static attribute3796 const prop = props[i];3797 if (prop.type === 6 /* ATTRIBUTE */) {3798 const { loc, name, value } = prop;3799 let isStatic = true;3800 if (name === 'ref') {3801 hasRef = true;3802 // in inline mode there is no setupState object, so we can't use string3803 // keys to set the ref. Instead, we need to transform it to pass the3804 // acrtual ref instead.3805 if (context.inline) {3806 isStatic = false;3807 }3808 }3809 // skip :is on <component>3810 if (name === 'is' && isComponentTag(tag)) {3811 continue;3812 }3813 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));3814 }3815 else {3816 // directives3817 const { name, arg, exp, loc } = prop;3818 const isBind = name === 'bind';3819 const isOn = name === 'on';3820 // skip v-slot - it is handled by its dedicated transform.3821 if (name === 'slot') {3822 if (!isComponent) {3823 context.onError(createCompilerError(39 /* X_V_SLOT_MISPLACED */, loc));3824 }3825 continue;3826 }3827 // skip v-once - it is handled by its dedicated transform.3828 if (name === 'once') {3829 continue;3830 }3831 // skip v-is and :is on <component>3832 if (name === 'is' ||3833 (isBind && isComponentTag(tag) && isBindKey(arg, 'is'))) {3834 continue;3835 }3836 // skip v-on in SSR compilation3837 if (isOn && ssr) {3838 continue;3839 }3840 // special case for v-bind and v-on with no argument3841 if (!arg && (isBind || isOn)) {3842 hasDynamicKeys = true;3843 if (exp) {3844 if (properties.length) {3845 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3846 properties = [];3847 }3848 if (isBind) {3849 mergeArgs.push(exp);3850 }3851 else {3852 // v-on="obj" -> toHandlers(obj)3853 mergeArgs.push({3854 type: 14 /* JS_CALL_EXPRESSION */,3855 loc,3856 callee: context.helper(TO_HANDLERS),3857 arguments: [exp]3858 });3859 }3860 }3861 else {3862 context.onError(createCompilerError(isBind3863 ? 33 /* X_V_BIND_NO_EXPRESSION */3864 : 34 /* X_V_ON_NO_EXPRESSION */, loc));3865 }3866 continue;3867 }3868 const directiveTransform = context.directiveTransforms[name];3869 if (directiveTransform) {3870 // has built-in directive transform.3871 const { props, needRuntime } = directiveTransform(prop, node, context);3872 !ssr && props.forEach(analyzePatchFlag);3873 properties.push(...props);3874 if (needRuntime) {3875 runtimeDirectives.push(prop);3876 if (shared.isSymbol(needRuntime)) {3877 directiveImportMap.set(prop, needRuntime);3878 }3879 }3880 }3881 else {3882 // no built-in transform, this is a user custom directive.3883 runtimeDirectives.push(prop);3884 }3885 }3886 }3887 let propsExpression = undefined;3888 // has v-bind="object" or v-on="object", wrap with mergeProps3889 if (mergeArgs.length) {3890 if (properties.length) {3891 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3892 }3893 if (mergeArgs.length > 1) {3894 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);3895 }3896 else {3897 // single v-bind with nothing else - no need for a mergeProps call3898 propsExpression = mergeArgs[0];3899 }3900 }3901 else if (properties.length) {3902 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);3903 }3904 // patchFlag analysis3905 if (hasDynamicKeys) {3906 patchFlag |= 16 /* FULL_PROPS */;3907 }3908 else {3909 if (hasClassBinding) {3910 patchFlag |= 2 /* CLASS */;3911 }3912 if (hasStyleBinding) {3913 patchFlag |= 4 /* STYLE */;3914 }3915 if (dynamicPropNames.length) {3916 patchFlag |= 8 /* PROPS */;3917 }3918 if (hasHydrationEventBinding) {3919 patchFlag |= 32 /* HYDRATE_EVENTS */;3920 }3921 }3922 if ((patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&3923 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {3924 patchFlag |= 512 /* NEED_PATCH */;3925 }3926 return {3927 props: propsExpression,3928 directives: runtimeDirectives,3929 patchFlag,3930 dynamicPropNames3931 };3932}3933// Dedupe props in an object literal.3934// Literal duplicated attributes would have been warned during the parse phase,3935// however, it's possible to encounter duplicated `onXXX` handlers with different3936// modifiers. We also need to merge static and dynamic class / style attributes.3937// - onXXX handlers / style: merge into array3938// - class: merge into single expression with concatenation3939function dedupeProperties(properties) {3940 const knownProps = new Map();3941 const deduped = [];3942 for (let i = 0; i < properties.length; i++) {3943 const prop = properties[i];3944 // dynamic keys are always allowed3945 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {3946 deduped.push(prop);3947 continue;3948 }3949 const name = prop.key.content;3950 const existing = knownProps.get(name);3951 if (existing) {3952 if (name === 'style' || name === 'class' || name.startsWith('on')) {3953 mergeAsArray(existing, prop);3954 }3955 // unexpected duplicate, should have emitted error during parse3956 }3957 else {3958 knownProps.set(name, prop);3959 deduped.push(prop);3960 }3961 }3962 return deduped;3963}3964function mergeAsArray(existing, incoming) {3965 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {3966 existing.value.elements.push(incoming.value);3967 }3968 else {3969 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);3970 }3971}3972function buildDirectiveArgs(dir, context) {3973 const dirArgs = [];3974 const runtime = directiveImportMap.get(dir);3975 if (runtime) {3976 // built-in directive with runtime3977 dirArgs.push(context.helperString(runtime));3978 }3979 else {3980 // user directive.3981 // see if we have directives exposed via <script setup>3982 const fromSetup = resolveSetupReference(dir.name, context);3983 if (fromSetup) {3984 dirArgs.push(fromSetup);3985 }3986 else {3987 // inject statement for resolving directive3988 context.helper(RESOLVE_DIRECTIVE);3989 context.directives.add(dir.name);3990 dirArgs.push(toValidAssetId(dir.name, `directive`));3991 }3992 }3993 const { loc } = dir;3994 if (dir.exp)3995 dirArgs.push(dir.exp);3996 if (dir.arg) {3997 if (!dir.exp) {3998 dirArgs.push(`void 0`);3999 }4000 dirArgs.push(dir.arg);4001 }4002 if (Object.keys(dir.modifiers).length) {4003 if (!dir.arg) {4004 if (!dir.exp) {4005 dirArgs.push(`void 0`);4006 }4007 dirArgs.push(`void 0`);4008 }4009 const trueExpression = createSimpleExpression(`true`, false, loc);4010 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4011 }4012 return createArrayExpression(dirArgs, dir.loc);4013}4014function stringifyDynamicPropNames(props) {4015 let propsNamesString = `[`;4016 for (let i = 0, l = props.length; i < l; i++) {4017 propsNamesString += JSON.stringify(props[i]);4018 if (i < l - 1)4019 propsNamesString += ', ';4020 }4021 return propsNamesString + `]`;4022}4023function isComponentTag(tag) {4024 return tag[0].toLowerCase() + tag.slice(1) === 'component';4025}4026const cacheStringFunction = (fn) => {4027 const cache = Object.create(null);4028 return ((str) => {4029 const hit = cache[str];4030 return hit || (cache[str] = fn(str));4031 });4032};4033const camelizeRE = /-(\w)/g;4034/**4035 * @private4036 */4037const camelize = cacheStringFunction((str) => { ...

Full Screen

Full Screen

compiler-core.esm-bundler.js

Source:compiler-core.esm-bundler.js Github

copy

Full Screen

...3217};3218function resolveComponentType(node, context, ssr = false) {3219 const { tag } = node;3220 // 1. dynamic component3221 const isProp = isComponentTag(tag)3222 ? findProp(node, 'is')3223 : findDir(node, 'is');3224 if (isProp) {3225 const exp = isProp.type === 6 /* ATTRIBUTE */3226 ? isProp.value && createSimpleExpression(isProp.value.content, true)3227 : isProp.exp;3228 if (exp) {3229 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3230 exp3231 ]);3232 }3233 }3234 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)3235 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);3236 if (builtIn) {3237 // built-ins are simply fallthroughs / have special handling during ssr3238 // so we don't need to import their runtime equivalents3239 if (!ssr)3240 context.helper(builtIn);3241 return builtIn;3242 }3243 // 5. user component (resolve)3244 context.helper(RESOLVE_COMPONENT);3245 context.components.add(tag);3246 return toValidAssetId(tag, `component`);3247}3248function buildProps(node, context, props = node.props, ssr = false) {3249 const { tag, loc: elementLoc } = node;3250 const isComponent = node.tagType === 1 /* COMPONENT */;3251 let properties = [];3252 const mergeArgs = [];3253 const runtimeDirectives = [];3254 // patchFlag analysis3255 let patchFlag = 0;3256 let hasRef = false;3257 let hasClassBinding = false;3258 let hasStyleBinding = false;3259 let hasHydrationEventBinding = false;3260 let hasDynamicKeys = false;3261 let hasVnodeHook = false;3262 const dynamicPropNames = [];3263 const analyzePatchFlag = ({ key, value }) => {3264 if (isStaticExp(key)) {3265 const name = key.content;3266 const isEventHandler = isOn(name);3267 if (!isComponent &&3268 isEventHandler &&3269 // omit the flag for click handlers because hydration gives click3270 // dedicated fast path.3271 name.toLowerCase() !== 'onclick' &&3272 // omit v-model handlers3273 name !== 'onUpdate:modelValue' &&3274 // omit onVnodeXXX hooks3275 !isReservedProp(name)) {3276 hasHydrationEventBinding = true;3277 }3278 if (isEventHandler && isReservedProp(name)) {3279 hasVnodeHook = true;3280 }3281 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3282 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3283 value.type === 8 /* COMPOUND_EXPRESSION */) &&3284 getConstantType(value, context) > 0)) {3285 // skip if the prop is a cached handler or has constant value3286 return;3287 }3288 if (name === 'ref') {3289 hasRef = true;3290 }3291 else if (name === 'class' && !isComponent) {3292 hasClassBinding = true;3293 }3294 else if (name === 'style' && !isComponent) {3295 hasStyleBinding = true;3296 }3297 else if (name !== 'key' && !dynamicPropNames.includes(name)) {3298 dynamicPropNames.push(name);3299 }3300 }3301 else {3302 hasDynamicKeys = true;3303 }3304 };3305 for (let i = 0; i < props.length; i++) {3306 // static attribute3307 const prop = props[i];3308 if (prop.type === 6 /* ATTRIBUTE */) {3309 const { loc, name, value } = prop;3310 let isStatic = true;3311 if (name === 'ref') {3312 hasRef = true;3313 }3314 // skip :is on <component>3315 if (name === 'is' && isComponentTag(tag)) {3316 continue;3317 }3318 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));3319 }3320 else {3321 // directives3322 const { name, arg, exp, loc } = prop;3323 const isBind = name === 'bind';3324 const isOn = name === 'on';3325 // skip v-slot - it is handled by its dedicated transform.3326 if (name === 'slot') {3327 if (!isComponent) {3328 context.onError(createCompilerError(39 /* X_V_SLOT_MISPLACED */, loc));3329 }3330 continue;3331 }3332 // skip v-once - it is handled by its dedicated transform.3333 if (name === 'once') {3334 continue;3335 }3336 // skip v-is and :is on <component>3337 if (name === 'is' ||3338 (isBind && isComponentTag(tag) && isBindKey(arg, 'is'))) {3339 continue;3340 }3341 // skip v-on in SSR compilation3342 if (isOn && ssr) {3343 continue;3344 }3345 // special case for v-bind and v-on with no argument3346 if (!arg && (isBind || isOn)) {3347 hasDynamicKeys = true;3348 if (exp) {3349 if (properties.length) {3350 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3351 properties = [];3352 }3353 if (isBind) {3354 mergeArgs.push(exp);3355 }3356 else {3357 // v-on="obj" -> toHandlers(obj)3358 mergeArgs.push({3359 type: 14 /* JS_CALL_EXPRESSION */,3360 loc,3361 callee: context.helper(TO_HANDLERS),3362 arguments: [exp]3363 });3364 }3365 }3366 else {3367 context.onError(createCompilerError(isBind3368 ? 33 /* X_V_BIND_NO_EXPRESSION */3369 : 34 /* X_V_ON_NO_EXPRESSION */, loc));3370 }3371 continue;3372 }3373 const directiveTransform = context.directiveTransforms[name];3374 if (directiveTransform) {3375 // has built-in directive transform.3376 const { props, needRuntime } = directiveTransform(prop, node, context);3377 !ssr && props.forEach(analyzePatchFlag);3378 properties.push(...props);3379 if (needRuntime) {3380 runtimeDirectives.push(prop);3381 if (isSymbol(needRuntime)) {3382 directiveImportMap.set(prop, needRuntime);3383 }3384 }3385 }3386 else {3387 // no built-in transform, this is a user custom directive.3388 runtimeDirectives.push(prop);3389 }3390 }3391 }3392 let propsExpression = undefined;3393 // has v-bind="object" or v-on="object", wrap with mergeProps3394 if (mergeArgs.length) {3395 if (properties.length) {3396 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3397 }3398 if (mergeArgs.length > 1) {3399 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);3400 }3401 else {3402 // single v-bind with nothing else - no need for a mergeProps call3403 propsExpression = mergeArgs[0];3404 }3405 }3406 else if (properties.length) {3407 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);3408 }3409 // patchFlag analysis3410 if (hasDynamicKeys) {3411 patchFlag |= 16 /* FULL_PROPS */;3412 }3413 else {3414 if (hasClassBinding) {3415 patchFlag |= 2 /* CLASS */;3416 }3417 if (hasStyleBinding) {3418 patchFlag |= 4 /* STYLE */;3419 }3420 if (dynamicPropNames.length) {3421 patchFlag |= 8 /* PROPS */;3422 }3423 if (hasHydrationEventBinding) {3424 patchFlag |= 32 /* HYDRATE_EVENTS */;3425 }3426 }3427 if ((patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&3428 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {3429 patchFlag |= 512 /* NEED_PATCH */;3430 }3431 return {3432 props: propsExpression,3433 directives: runtimeDirectives,3434 patchFlag,3435 dynamicPropNames3436 };3437}3438// Dedupe props in an object literal.3439// Literal duplicated attributes would have been warned during the parse phase,3440// however, it's possible to encounter duplicated `onXXX` handlers with different3441// modifiers. We also need to merge static and dynamic class / style attributes.3442// - onXXX handlers / style: merge into array3443// - class: merge into single expression with concatenation3444function dedupeProperties(properties) {3445 const knownProps = new Map();3446 const deduped = [];3447 for (let i = 0; i < properties.length; i++) {3448 const prop = properties[i];3449 // dynamic keys are always allowed3450 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {3451 deduped.push(prop);3452 continue;3453 }3454 const name = prop.key.content;3455 const existing = knownProps.get(name);3456 if (existing) {3457 if (name === 'style' || name === 'class' || name.startsWith('on')) {3458 mergeAsArray(existing, prop);3459 }3460 // unexpected duplicate, should have emitted error during parse3461 }3462 else {3463 knownProps.set(name, prop);3464 deduped.push(prop);3465 }3466 }3467 return deduped;3468}3469function mergeAsArray(existing, incoming) {3470 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {3471 existing.value.elements.push(incoming.value);3472 }3473 else {3474 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);3475 }3476}3477function buildDirectiveArgs(dir, context) {3478 const dirArgs = [];3479 const runtime = directiveImportMap.get(dir);3480 if (runtime) {3481 // built-in directive with runtime3482 dirArgs.push(context.helperString(runtime));3483 }3484 else {3485 {3486 // inject statement for resolving directive3487 context.helper(RESOLVE_DIRECTIVE);3488 context.directives.add(dir.name);3489 dirArgs.push(toValidAssetId(dir.name, `directive`));3490 }3491 }3492 const { loc } = dir;3493 if (dir.exp)3494 dirArgs.push(dir.exp);3495 if (dir.arg) {3496 if (!dir.exp) {3497 dirArgs.push(`void 0`);3498 }3499 dirArgs.push(dir.arg);3500 }3501 if (Object.keys(dir.modifiers).length) {3502 if (!dir.arg) {3503 if (!dir.exp) {3504 dirArgs.push(`void 0`);3505 }3506 dirArgs.push(`void 0`);3507 }3508 const trueExpression = createSimpleExpression(`true`, false, loc);3509 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));3510 }3511 return createArrayExpression(dirArgs, dir.loc);3512}3513function stringifyDynamicPropNames(props) {3514 let propsNamesString = `[`;3515 for (let i = 0, l = props.length; i < l; i++) {3516 propsNamesString += JSON.stringify(props[i]);3517 if (i < l - 1)3518 propsNamesString += ', ';3519 }3520 return propsNamesString + `]`;3521}3522function isComponentTag(tag) {3523 return tag[0].toLowerCase() + tag.slice(1) === 'component';3524}35253526(process.env.NODE_ENV !== 'production')3527 ? Object.freeze({})3528 : {};3529(process.env.NODE_ENV !== 'production') ? Object.freeze([]) : [];3530const cacheStringFunction = (fn) => {3531 const cache = Object.create(null);3532 return ((str) => {3533 const hit = cache[str];3534 return hit || (cache[str] = fn(str));3535 });3536}; ...

Full Screen

Full Screen

compiler.js

Source:compiler.js Github

copy

Full Screen

...251const componentEvaluator = (code) => {252 let results = "";253 parser.HTMLParser(code, {254 start: (tag, attrs, unary) => {255 if (isComponentTag(tag)) {256 attrs.push({257 name: "__trex_module",258 value: true,259 }, {260 name: constants.trexComponentAttributeKey,261 value: tag262 });263 results += `<${constants.trexModuleName}`;264 }265 else {266 results += `<${tag}`;267 }268 results += attrs269 .reduce((t, { name, value }, _, arr) => {270 return `${t} ${name}="${value}"`;271 }, "");272 results += (unary ? "/" : "") + ">";273 },274 end: tag => {275 if (isComponentTag(tag)) {276 results += `</${constants.trexModuleName}>`;277 }278 else {279 results += `</${tag}>`;280 }281 },282 chars: text => {283 results += text284 .replace(/\{\{/g, "<trex-interpolation><textarea hidden>")285 .replace(/\}\}/g, "</textarea></trex-interpolation>");286 },287 comment: text => {288 results += `<!--${text}-->`;289 },...

Full Screen

Full Screen

compiler.mjs

Source:compiler.mjs Github

copy

Full Screen

...133 const [tag, rawTag, isDynamicTag] = parseValue(vnode.tag);134 if (vnode.ref === "this") {135 generateProperties(vnode, $);136 generateChildren(vnode, $);137 } else if (!isDynamicTag && !isComponentTag(rawTag)) {138 $.html += `<${rawTag}`;139 generateProperties(vnode, $);140 $.html += ">";141 if (vnode.void) return;142 generateChildren(vnode, $);143 $.html += `</${rawTag}>`;144 } else if (isComponentTag(rawTag)) {145 const [splats, attrs, kvs] = Object.entries(vnode.properties).reduce(([splats, attrs, kvs], [k, v]) => {146 if (splatRegexp.test(k)) return [splats.concat(k.match(splatRegexp)[1]), attrs, kvs];147 else if (k === "id" || k === "class") return [splats, attrs.concat(`${k}="${v}"`), kvs];148 return [splats, attrs, kvs.concat(`[${parseValue(k)[0]}]: ${parseValue(v)[0]}`)];149 }, [[], [], []]);150 $.html += `<${rawTag}${attrs.length ? " " + attrs.join(" ") : ""}>`;151 generateChildren(vnode, $);152 $.html += `</${rawTag}>`;153 const props = splats.length ? `Object.assign({}, ${splats.join(", ")}, {${kvs.join(", ")}})` : `{${kvs.join(", ")}}`;154 $.create += `${vnode.ref}.init($.app, $, ${props});\n`;155 $.update += `${vnode.ref}.update(${props});\n`;156 } else {157 throw new Error("dynamic tags are currently not supported");158 }159}160function generateProperties(vnode, $) {161 const dynamicProperties = [];162 for (const k in vnode.properties) {163 const [key, rawKey, isDynamicKey] = parseValue(k),164 [value, rawValue, isDynamicValue] = parseValue(vnode.properties[k]);165 if (splatRegexp.test(k)) throw new Error(`splat properties are only allowed on component tags, not <${vnode.tag}>`);166 else if (!isDynamicKey && !isDynamicValue && vnode.ref === "this") $.create += `xm.setTemplateProperty(${vnode.ref}, ${key}, ${value});\n`;167 else if (!isDynamicKey && !isDynamicValue) $.html += ` ${rawKey}=${value}`;168 else dynamicProperties.push({key, value, isDynamicKey, isDynamicValue});169 }170 if (!dynamicProperties.length) return;171 const node = generateLocalNodeRef($, vnode, "properties");172 for (let {key, value, isDynamicKey, isDynamicValue} of dynamicProperties) {173 if (!isDynamicKey) {174 $.create += `xm.setProperty(${node}, ${key}, ${value});\n`;175 $.update += `xm.setProperty(${node}, ${key}, ${value});\n`;176 } else {177 const _ = prefix("properties");178 $.create += `let ${_}key = ${key}; xm.setProperty(${node}, ${_}key, ${value});\n`;179 $.update += `${_}key = xm.setDynamicKeyProperty(${node}, ${_}key, ${key}, ${value});\n`;180 }181 }182}183function generateChildren(vnode, $) {184 let node = vnode.ref + ".firstChild", dynamicChildren = [];185 for (const vchild of vnode.children) {186 node = generateNodeRef($, {ref: node}, "children");187 if (vchild.tag) {188 vchild.ref = node;189 generateVnode(vchild, $);190 node = vchild.ref;191 node = node + ".nextSibling";192 } else {193 for (let [value, rawValue, isDynamic] of parseValueParts(vchild)[0]) {194 $.html += isDynamic ? "<!---->" : rawValue;195 if (isDynamic) dynamicChildren.push([node, value]);196 node = node + ".nextSibling";197 }198 }199 }200 if (dynamicChildren.length) {201 const _ = prefix("children"), values = dynamicChildren.map(([_, v]) => v), nodes = dynamicChildren.map(([n]) => n),202 node = generateLocalNodeRef($, vnode, "children");203 $.create += `const ${_}nodes = [${nodes}], ${_}values = [];204 xm.updateChildNodes(${node}, null, ${_}nodes, ${_}values, [${values}], $, xm.createChildNode);\n`;205 $.update += `xm.updateChildNodes(${node}, null, ${_}nodes, ${_}values, [${values}], $, xm.createChildNode);\n`;206 }207}208function isComponentTag(tag) {209 return tag && tag.startsWith("x-");210}211function generateNodeRef($, vnode, key = "") {212 if (vnode.ref.indexOf(".") === -1) return vnode.ref;213 return vnode.ref = generateLocalNodeRef($, vnode, key);214}215function generateLocalNodeRef($, vnode, key = "") {216 const _ = prefix(key);217 $.create += `let ${_}node = ${vnode.ref};\n`;218 return `${_}node`;219}220let prefixId = 0;221export const resetPrefixId = () => prefixId = 0;222const prefix = (key) => `_${key}_${prefixId++}_`;

Full Screen

Full Screen

layout-element-parser.js

Source:layout-element-parser.js Github

copy

Full Screen

...19 */20const isProp = element => !!element && typeof element === 'object' && !Array.isArray(element);21const isComponentTag = layoutElement => Array.isArray(layoutElement) && typeof layoutElement[0] === 'string' && layoutElement[0].startsWith('@') && isProp(layoutElement[1]);22const hasOnlyStringsProperties = function (layoutElement) {23 return Array.isArray(layoutElement) && layoutElement.length > 0 && !isComponentTag(layoutElement) && !layoutElement.find(el => typeof el !== 'string');24};25const hasArrayOfLayoutElements = function (layoutElement) {26 return Array.isArray(layoutElement) && layoutElement.length > 0 && !layoutElement.find(element => !Array.isArray(element));27};28const hasFirstStringProperty = function (layoutElement) {29 return Array.isArray(layoutElement) && typeof layoutElement[0] === 'string' && !isComponentTag(layoutElement);30};31const getPropertyNames = layoutElement => {32 if (typeof layoutElement === 'string') {33 return [layoutElement];34 }35 if (hasOnlyStringsProperties(layoutElement)) {36 return layoutElement;37 }38 if (hasFirstStringProperty(layoutElement)) {39 return [layoutElement[0]];40 }41 return [];42};43const getInnerLayoutElements = layoutElement => {44 // only cases like [{}, layoutElement] (whatever follows props)45 if (Array.isArray(layoutElement) && isProp(layoutElement[0])) {46 return layoutElement[1];47 }48 if (hasArrayOfLayoutElements(layoutElement)) {49 return layoutElement;50 }51 return [];52};53const getComponent = layoutElement => {54 if (isComponentTag(layoutElement)) {55 return layoutElement[0].slice(1);56 }57 return 'Box';58};59const getProps = layoutElement => {60 if (Array.isArray(layoutElement) && layoutElement.length) {61 const boxProps = layoutElement.find(isProp);62 return boxProps || {};63 }64 return {};65};66const layoutElementParser = layoutElement => {67 const props = getProps(layoutElement);68 const innerLayoutElements = getInnerLayoutElements(layoutElement);...

Full Screen

Full Screen

props.js

Source:props.js Github

copy

Full Screen

1const path = require('path')2const fs = require('fs-extra')3const Config = require('../config.js')4module.exports = function(ast, fileInfo, renderAxml) {5 let isComponentTag = false6 const { type, props } = ast7 if (props) {8 Object.keys(props).forEach((key) => {9 if (key && !props[key].value[0]) {10 props[key] = { type: 'double', value: [' '] }11 }12 })13 }14 15 /**16 * 自定义组件预处理 - 事件17 */18 isComponentTag = processCustomComponent(ast, fileInfo)19 return isComponentTag20}21function checkoutCustomComponent(fileInfo, tagName) {22 let bool = false; let json; let23 appJson24 if (fileInfo.extname === '.axml') {25 json = fileInfo.path.replace('.axml', '.json')26 if (!fs.pathExistsSync(json)) { return false }27 if (!fileInfo.jsonUsingComponents) {28 json = JSON.parse(fs.readFileSync(json, 'utf8')) || {}29 } else {30 json = fileInfo.jsonUsingComponents31 }32 if (json.usingComponents && json.usingComponents[tagName]) {33 bool = true34 }35 36 if (!tagName) {37 fileInfo.jsonUsingComponents = fileInfo.jsonUsingComponents || json.usingComponents38 return {39 component: json.usingComponents,40 }41 }42 }43 return bool44}45function processCustomComponent(ast, fileInfo) {46 let isComponentTag = false47 /**48 * 自定义组件事件处理49 */50 51 if (!fileInfo.jsonUsingComponents) {52 const customComponents = checkoutCustomComponent(fileInfo) || {}53 fileInfo.jsonUsingComponents = customComponents.component || {}54 }55 if (fileInfo.jsonUsingComponents[ast.type]) {56 isComponentTag = true57 if (ast.props && !Config.component2) {58 ast.props._parent_ref = { type: 'double', value: ['{{isMounted}}'] }59 }60 }61 return isComponentTag...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const { isComponentTag } = require('@playwright/test/lib/api/test/page');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const selector = 'text=Get Started';8 const isComponent = await isComponentTag(page, selector);9 console.log(isComponent);10 await browser.close();11})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { isComponentTag } = require('@playwright/test/lib/internal/locators');2const { test } = require('@playwright/test');3test('test', async ({ page }) => {4 await page.click(isComponentTag('a'));5 await page.click(isComponentTag('button'));6});7isComponentTag(tagName)8const { isComponentTag } = require('@playwright/test/lib/internal/locators');9const { test } = require('@playwright/test');10test('test', async ({ page }) => {11 await page.click(isComponentTag('a'));12 await page.click(isComponentTag('button'));13});14isComponentText(text)15const { isComponentText } = require('@playwright/test/lib/internal/locators');16const { test } = require('@playwright/test');17test('test', async ({ page }) => {18 await page.click(isComponentText('Docs'));19 await page.click(isComponentText('Blog'));20});21isComponentAttribute(name, value)22const { isComponentAttribute } = require('@playwright/test/lib/internal/locators');23const { test } = require('@playwright/test');24test('test', async ({ page }) => {25 await page.click(isComponentAttribute('href', '/docs'));26 await page.click(isComponentAttribute('href', '/blog'));27});28isComponentDataTest(name)29const { isComponentDataTest } = require('@playwright/test/lib/internal/locators');30const { test } = require('@playwright/test');31test('test', async ({ page }) => {32 await page.click(isComponentDataTest('docs-link'));33 await page.click(isComponentDataTest('blog-link'));34});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { isComponentTag } = require('playwright/lib/server/supplements/utils/componentUtils');2const { Page } = require('playwright/lib/server/page');3const { ElementHandle } = require('playwright/lib/server/dom');4const { PageBinding } = require('playwright/lib/server/pageBinding');5const { JSHandle } = require('playwright/lib/server/jsHandle');6const { test } = require('@playwright/test');7test('test', async ({ page }) => {8 await page.setContent('<div></div>');9 const div = await page.$('div');10 const component = await page.evaluateHandle((div) => {11 return div.attachShadow({ mode: 'open' });12 }, div);13 await component.evaluate(() => {14 const div = document.createElement('div');15 div.innerHTML = 'Hello';16 document.body.appendChild(div);17 });18 const divHandle = await component.$('div');19 const isComponent = await isComponentTag(divHandle);20 console.log(isComponent);21});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { isComponentTag } = require('@playwright/test');2const { isComponentTag } = require('@playwright/test');3const { isComponentTag } = require('@playwright/test');4const { isComponentTag } = require('@playwright/test');5const { isComponentTag } = require('@playwright/test');6const { isComponentTag } = require('@playwright/test');

Full Screen

Using AI Code Generation

copy

Full Screen

1const { isComponentTag } = require('@playwright/test/lib/server/frames');2const { test } = require('@playwright/test');3test('is component tag', async ({ page }) => {4 await page.setContent('<div></div>');5 const div = await page.$('div');6 const divHandle = await div.asElement();7 const isComponent = await page.evaluate((handle) => {8 return isComponentTag(handle);9 }, divHandle);10 console.log(isComponent);11});12const { isComponentTag } = require('@playwright/test/lib/server/frames');13const { test } = require('@playwright/test');14test('is component tag', async ({ page }) => {15 await page.setContent('<div></div>');16 const div = await page.$('div');17 const divHandle = await div.asElement();18 const isComponent = await page.evaluate((handle) => {19 return isComponentTag(handle);20 }, divHandle);21 expect(isComponent).toBe(true);22});23 FAIL test.spec.js (6.746 s)24 14 | const divHandle = await div.asElement();25 15 | const isComponent = await page.evaluate((handle) => {26 > 16 | return isComponentTag(handle);27 17 | }, divHandle);28 18 | console.log(isComponent);29 19 | });30 at ExecutionContext._evaluateInternal (node_modules/playwright

Full Screen

Using AI Code Generation

copy

Full Screen

1const { isComponentTag } = require('@playwright/test');2const { test, expect } = require('@playwright/test');3test('Check if the given tag is a component tag or not', async ({ page }) => {4 expect(isComponentTag('input')).toBe(true);5 expect(isComponentTag('div')).toBe(false);6});7const { test, expect } = require('@playwright/test');8test('Check if the given tag is a component tag or not', async ({ page }) => {9 expect(isComponentTag('input')).toBe(true);10 expect(isComponentTag('div')).toBe(false);11});12Types of Test Cases in Software Testing | Set 1 (Functional and Non-Functional)

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful