refactor: remove weex from codebase

This commit is contained in:
Evan You 2022-05-20 12:17:13 +08:00
parent 2d019e4e25
commit d8c3bbfa44
139 changed files with 39 additions and 19061 deletions

View File

@ -1,131 +0,0 @@
version: 2
defaults: &defaults
working_directory: ~/project/vue
docker:
- image: node:lts
jobs:
install:
<<: *defaults
steps:
- checkout
- restore_cache:
keys:
- v1-vue-{{ .Branch }}-{{ checksum "yarn.lock" }}
- v1-vue-{{ .Branch }}-
- v1-vue-
- run: npm install
- save_cache:
key: v1-vue-{{ .Branch }}-{{ checksum "yarn.lock" }}
paths:
- node_modules/
- persist_to_workspace:
root: ~/project
paths:
- vue
lint-ts-types:
<<: *defaults
steps:
- attach_workspace:
at: ~/project
- run: npm run lint
- run: npm run ts-check
- run: npm run test:types
test-cover:
<<: *defaults
steps:
- attach_workspace:
at: ~/project
- run: npm run test:cover
- run:
name: report coverage stats for non-PRs
command: |
if [[ -z $CI_PULL_REQUEST ]]; then
./node_modules/.bin/codecov
fi
test-e2e:
<<: *defaults
steps:
- attach_workspace:
at: ~/project
- run: npm run test:e2e -- --env phantomjs
test-ssr-weex:
<<: *defaults
steps:
- attach_workspace:
at: ~/project
- run: npm run test:ssr
- run: npm run test:weex
trigger-regression-test:
<<: *defaults
steps:
- run:
command: |
curl --user ${CIRCLE_TOKEN}: \
--data build_parameters[CIRCLE_JOB]=update \
--data build_parameters[VUE_REVISION]=${CIRCLE_SHA1} \
https://circleci.com/api/v1.1/project/github/vuejs/regression-testing/tree/master
workflows:
version: 2
install-and-parallel-test:
jobs:
- install
- test-cover:
requires:
- install
- lint-ts-types:
requires:
- install
- test-e2e:
requires:
- install
- test-ssr-weex:
requires:
- install
- trigger-regression-test:
filters:
branches:
only:
- "2.6"
- regression-test
requires:
- test-cover
- lint-ts-types
- test-e2e
- test-ssr-weex
weekly_regression_test:
triggers:
- schedule:
# At 13:00 UTC (9:00 EDT) on every Monday
cron: "0 13 * * 1"
filters:
branches:
only: dev
jobs:
- install
- test-cover:
requires:
- install
- lint-ts-types:
requires:
- install
- test-e2e:
requires:
- install
- test-ssr-weex:
requires:
- install
- trigger-regression-test:
requires:
- test-cover
- lint-ts-types
- test-e2e
- test-ssr-weex

View File

@ -1,23 +0,0 @@
[ignore]
.*/node_modules/.*
.*/test/.*
.*/scripts/.*
.*/examples/.*
.*/benchmarks/.*
[include]
[libs]
flow
[options]
# unsafe.enable_getters_and_setters=true
module.name_mapper='^compiler/\(.*\)$' -> '<PROJECT_ROOT>/src/compiler/\1'
module.name_mapper='^core/\(.*\)$' -> '<PROJECT_ROOT>/src/core/\1'
module.name_mapper='^shared/\(.*\)$' -> '<PROJECT_ROOT>/src/shared/\1'
module.name_mapper='^web/\(.*\)$' -> '<PROJECT_ROOT>/src/platforms/web/\1'
module.name_mapper='^weex/\(.*\)$' -> '<PROJECT_ROOT>/src/platforms/weex/\1'
module.name_mapper='^server/\(.*\)$' -> '<PROJECT_ROOT>/src/server/\1'
module.name_mapper='^entries/\(.*\)$' -> '<PROJECT_ROOT>/src/entries/\1'
module.name_mapper='^sfc/\(.*\)$' -> '<PROJECT_ROOT>/src/sfc/\1'
# suppress_comment= \\(.\\|\n\\)*\\$flow-disable-line

View File

@ -20,27 +20,16 @@
"dev:test": "karma start test/unit/karma.dev.config.ts",
"dev:ssr": "rollup -w -c scripts/config.js --environment TARGET:web-server-renderer",
"dev:compiler": "rollup -w -c scripts/config.js --environment TARGET:web-compiler ",
"dev:weex": "rollup -w -c scripts/config.js --environment TARGET:weex-framework",
"dev:weex:factory": "rollup -w -c scripts/config.js --environment TARGET:weex-factory",
"dev:weex:compiler": "rollup -w -c scripts/config.js --environment TARGET:weex-compiler ",
"build": "node scripts/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex": "npm run build -- weex",
"test": "npm run lint && npm run ts-check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr && npm run test:weex",
"test:dtw": "npm run lint && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr && npm run test:weex",
"test:unit": "karma start test/unit/karma.unit.config.ts",
"test:cover": "karma start test/unit/karma.cover.config.ts",
"test": "npm run lint && npm run ts-check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr",
"test:unit": "vitest run",
"test:e2e": "npm run build -- web-full-prod,web-server-basic-renderer && node test/e2e/runner.ts",
"test:weex": "npm run build:weex && jasmine-ts JASMINE_CONFIG_PATH=test/weex/jasmine.ts",
"test:ssr": "npm run build:ssr && jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.ts",
"test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2",
"test:types": "tsc -p ./types/tsconfig.json",
"lint": "eslint src scripts test",
"ts-check": "tsc --noEmit",
"sauce": "karma start test/unit/karma.sauce.config.ts",
"bench:ssr": "npm run build:ssr && node benchmarks/ssr/renderToString.js && node benchmarks/ssr/renderToStream.js",
"release": "bash scripts/release.sh",
"release:weex": "bash scripts/release-weex.sh",
"release:note": "node scripts/gen-release-note.js",
"commit": "git-cz"
},
@ -110,8 +99,6 @@
"typescript": "^4.6.4",
"vitest": "^0.12.6",
"webpack": "^5.72.1",
"weex-js-runtime": "^0.23.6",
"weex-styler": "^0.3.0",
"yorkie": "^2.0.0"
},
"config": {

View File

@ -160,9 +160,6 @@ export interface ASTElement {
// 2.4 ssr optimization
ssrOptimizability?: SSROptimizability;
// weex specific
appendAsTree?: boolean;
}
export interface ASTExpression {

View File

@ -1,3 +0,0 @@
# weex-template-compiler
> This package is auto-generated. For pull requests please see [src/platforms/weex/entry-compiler.js](https://github.com/vuejs/vue/tree/dev/src/platforms/weex/entry-compiler.js).

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
try {
var vueVersion = require('weex-vue-framework').version
} catch (e) {}
var packageName = require('./package.json').name
var packageVersion = require('./package.json').version
if (vueVersion && vueVersion !== packageVersion) {
throw new Error(
'\n\nVue packages version mismatch:\n\n' +
'- vue@' + vueVersion + '\n' +
'- ' + packageName + '@' + packageVersion + '\n\n' +
'This may cause things to work incorrectly. Make sure to use the same version for both.\n' +
'If you are using weex-vue-loader, re-installing them should bump ' + packageName + ' to the latest.\n'
)
}
module.exports = require('./build')

View File

@ -1,26 +0,0 @@
{
"name": "weex-template-compiler",
"version": "2.4.2-weex.1",
"description": "Weex template compiler for Vue 2.0",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vue.git"
},
"keywords": [
"vue",
"compiler"
],
"author": "Evan You",
"license": "MIT",
"bugs": {
"url": "https://github.com/vuejs/vue/issues"
},
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/weex-template-compiler#readme",
"dependencies": {
"acorn": "^8.1.0",
"acorn-walk": "^8.0.2",
"escodegen": "^1.8.1",
"he": "^1.1.0"
}
}

View File

@ -1,3 +0,0 @@
# weex-vue-framework
> This package is auto-generated. For pull requests please see [src/platforms/weex/entry-framework.js](https://github.com/vuejs/vue/blob/dev/src/platforms/weex/entry-framework.js).

File diff suppressed because it is too large Load Diff

View File

@ -1,203 +0,0 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
/* */
// this will be preserved during build
// $flow-disable-line
var VueFactory = require('./factory');
var instanceOptions = {};
/**
* Create instance context.
*/
function createInstanceContext (
instanceId,
runtimeContext,
data
) {
if ( data === void 0 ) data = {};
var weex = runtimeContext.weex;
var instance = instanceOptions[instanceId] = {
instanceId: instanceId,
config: weex.config,
document: weex.document,
data: data
};
// Each instance has an independent `Vue` module instance
var Vue = instance.Vue = createVueModuleInstance(instanceId, weex);
// DEPRECATED
var timerAPIs = getInstanceTimer(instanceId, weex.requireModule);
var instanceContext = Object.assign({ Vue: Vue }, timerAPIs);
Object.freeze(instanceContext);
return instanceContext
}
/**
* Destroy an instance with id. It will make sure all memory of
* this instance released and no more leaks.
*/
function destroyInstance (instanceId) {
var instance = instanceOptions[instanceId];
if (instance && instance.app instanceof instance.Vue) {
try {
instance.app.$destroy();
instance.document.destroy();
} catch (e) {}
delete instance.document;
delete instance.app;
}
delete instanceOptions[instanceId];
}
/**
* Refresh an instance with id and new top-level component data.
* It will use `Vue.set` on all keys of the new data. So it's better
* define all possible meaningful keys when instance created.
*/
function refreshInstance (
instanceId,
data
) {
var instance = instanceOptions[instanceId];
if (!instance || !(instance.app instanceof instance.Vue)) {
return new Error(("refreshInstance: instance " + instanceId + " not found!"))
}
if (instance.Vue && instance.Vue.set) {
for (var key in data) {
instance.Vue.set(instance.app, key, data[key]);
}
}
// Finally `refreshFinish` signal needed.
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, []);
}
/**
* Create a fresh instance of Vue for each Weex instance.
*/
function createVueModuleInstance (
instanceId,
weex
) {
var exports = {};
VueFactory(exports, weex.document);
var Vue = exports.Vue;
var instance = instanceOptions[instanceId];
// patch reserved tag detection to account for dynamically registered
// components
var weexRegex = /^weex:/i;
var isReservedTag = Vue.config.isReservedTag || (function () { return false; });
var isRuntimeComponent = Vue.config.isRuntimeComponent || (function () { return false; });
Vue.config.isReservedTag = function (name) {
return (!isRuntimeComponent(name) && weex.supports(("@component/" + name))) ||
isReservedTag(name) ||
weexRegex.test(name)
};
Vue.config.parsePlatformTagName = function (name) { return name.replace(weexRegex, ''); };
// expose weex-specific info
Vue.prototype.$instanceId = instanceId;
Vue.prototype.$document = instance.document;
// expose weex native module getter on subVue prototype so that
// vdom runtime modules can access native modules via vnode.context
Vue.prototype.$requireWeexModule = weex.requireModule;
// Hack `Vue` behavior to handle instance information and data
// before root component created.
Vue.mixin({
beforeCreate: function beforeCreate () {
var options = this.$options;
// root component (vm)
if (options.el) {
// set external data of instance
var dataOption = options.data;
var internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {};
options.data = Object.assign(internalData, instance.data);
// record instance by id
instance.app = this;
}
},
mounted: function mounted () {
var options = this.$options;
// root component (vm)
if (options.el && weex.document && instance.app === this) {
try {
// Send "createFinish" signal to native.
weex.document.taskCenter.send('dom', { action: 'createFinish' }, []);
} catch (e) {}
}
}
});
/**
* @deprecated Just instance variable `weex.config`
* Get instance config.
* @return {object}
*/
Vue.prototype.$getConfig = function () {
if (instance.app instanceof Vue) {
return instance.config
}
};
return Vue
}
/**
* DEPRECATED
* Generate HTML5 Timer APIs. An important point is that the callback
* will be converted into callback id when sent to native. So the
* framework can make sure no side effect of the callback happened after
* an instance destroyed.
*/
function getInstanceTimer (
instanceId,
moduleGetter
) {
var instance = instanceOptions[instanceId];
var timer = moduleGetter('timer');
var timerAPIs = {
setTimeout: function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
var handler = function () {
args[0].apply(args, args.slice(2));
};
timer.setTimeout(handler, args[1]);
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
setInterval: function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
var handler = function () {
args[0].apply(args, args.slice(2));
};
timer.setInterval(handler, args[1]);
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
clearTimeout: function (n) {
timer.clearTimeout(n);
},
clearInterval: function (n) {
timer.clearInterval(n);
}
};
return timerAPIs
}
exports.createInstanceContext = createInstanceContext;
exports.destroyInstance = destroyInstance;
exports.refreshInstance = refreshInstance;

View File

@ -1,20 +0,0 @@
{
"name": "weex-vue-framework",
"version": "2.4.2-weex.1",
"description": "Vue 2.0 Framework for Weex",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vue.git"
},
"keywords": [
"vue",
"compiler"
],
"author": "Evan You",
"license": "MIT",
"bugs": {
"url": "https://github.com/vuejs/vue/issues"
},
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/weex-vue-framework#readme"
}

View File

@ -44,8 +44,6 @@ specifiers:
typescript: ^4.6.4
vitest: ^0.12.6
webpack: ^5.72.1
weex-js-runtime: ^0.23.6
weex-styler: ^0.3.0
yorkie: ^2.0.0
devDependencies:
@ -92,8 +90,6 @@ devDependencies:
typescript: 4.6.4
vitest: 0.12.6_jsdom@19.0.0
webpack: 5.72.1
weex-js-runtime: 0.23.7
weex-styler: 0.3.1
yorkie: 2.0.0
packages:
@ -837,12 +833,6 @@ packages:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: true
/atob/2.1.2:
resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
engines: {node: '>= 4.5.0'}
hasBin: true
dev: true
/balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
@ -1315,15 +1305,6 @@ packages:
which: 2.0.2
dev: true
/css/2.2.4:
resolution: {integrity: sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==}
dependencies:
inherits: 2.0.4
source-map: 0.6.1
source-map-resolve: 0.5.3
urix: 0.1.0
dev: true
/cssom/0.3.8:
resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
dev: true
@ -1448,11 +1429,6 @@ packages:
resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
dev: true
/decode-uri-component/0.2.0:
resolution: {integrity: sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=}
engines: {node: '>=0.10'}
dev: true
/dedent/0.7.0:
resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=}
dev: true
@ -3629,11 +3605,6 @@ packages:
dev: true
optional: true
/resolve-url/0.2.1:
resolution: {integrity: sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=}
deprecated: https://github.com/lydell/resolve-url#deprecated
dev: true
/resolve/1.22.0:
resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==}
hasBin: true
@ -3861,17 +3832,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/source-map-resolve/0.5.3:
resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==}
deprecated: See https://github.com/lydell/source-map-resolve#deprecated
dependencies:
atob: 2.1.2
decode-uri-component: 0.2.0
resolve-url: 0.2.1
source-map-url: 0.4.1
urix: 0.1.0
dev: true
/source-map-support/0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
@ -3879,11 +3839,6 @@ packages:
source-map: 0.6.1
dev: true
/source-map-url/0.4.1:
resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==}
deprecated: See https://github.com/lydell/source-map-url#deprecated
dev: true
/source-map/0.5.6:
resolution: {integrity: sha1-dc449SvwczxafwwRjYEzSiu19BI=}
engines: {node: '>=0.10.0'}
@ -4350,11 +4305,6 @@ packages:
punycode: 2.1.1
dev: true
/urix/0.1.0:
resolution: {integrity: sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=}
deprecated: Please see https://github.com/lydell/urix#deprecated
dev: true
/url-join/4.0.1:
resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
dev: true
@ -4510,17 +4460,6 @@ packages:
- uglify-js
dev: true
/weex-js-runtime/0.23.7:
resolution: {integrity: sha512-3BFd5GXTo0X/GWh0KjzXDpIcPJuSwYuc9fE9llgez35IfVHs/nUmfkFBjifzxOJS2YLhtKf0Cy8eTQ00CJDWZA==}
engines: {node: '>=4'}
dev: true
/weex-styler/0.3.1:
resolution: {integrity: sha512-xkX5/wS/QLiJXKwbdpeytbLN0kHviQwj9CLdvBxqu+RRZABZpTniKZr1oxjh9Q0+n/aRC+smwFpQpUKvXh9V1g==}
dependencies:
css: 2.2.4
dev: true
/whatwg-encoding/2.0.0:
resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
engines: {node: '>=12'}

View File

@ -8,7 +8,6 @@ module.exports = {
core: resolve('src/core'),
shared: resolve('src/shared'),
web: resolve('src/platforms/web'),
weex: resolve('src/platforms/weex'),
server: resolve('src/server'),
sfc: resolve('src/sfc')
}

View File

@ -16,11 +16,6 @@ if (process.argv[2]) {
builds = builds.filter(b => {
return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
})
} else {
// filter out weex builds by default
builds = builds.filter(b => {
return b.output.file.indexOf('weex') === -1
})
}
build(builds)

View File

@ -6,9 +6,6 @@ const node = require('@rollup/plugin-node-resolve').nodeResolve
const ts = require('rollup-plugin-typescript2')
const version = process.env.VERSION || require('../package.json').version
const weexVersion =
process.env.WEEX_VERSION ||
require('../packages/weex-vue-framework/package.json').version
const featureFlags = require('./feature-flags')
const banner =
@ -18,15 +15,6 @@ const banner =
' * Released under the MIT License.\n' +
' */'
const weexFactoryPlugin = {
intro() {
return 'module.exports = function weexFactory (exports, document) {'
},
outro() {
return '}'
}
}
const aliases = require('./alias')
const resolve = (p) => {
const base = p.split('/')[0]
@ -199,31 +187,6 @@ const builds = {
external: Object.keys(
require('../packages/vue-server-renderer/package.json').dependencies
)
},
// Weex runtime factory
'weex-factory': {
weex: true,
entry: resolve('weex/entry-runtime-factory.ts'),
dest: resolve('packages/weex-vue-framework/factory.js'),
format: 'cjs',
plugins: [weexFactoryPlugin]
},
// Weex runtime framework (CommonJS).
'weex-framework': {
weex: true,
entry: resolve('weex/entry-framework.ts'),
dest: resolve('packages/weex-vue-framework/index.js'),
format: 'cjs'
},
// Weex compiler (CommonJS). Used by Weex's Webpack loader.
'weex-compiler': {
weex: true,
entry: resolve('weex/entry-compiler.ts'),
dest: resolve('packages/weex-template-compiler/build.js'),
format: 'cjs',
external: Object.keys(
require('../packages/weex-template-compiler/package.json').dependencies
)
}
}
@ -267,8 +230,6 @@ function genConfig(name) {
// built-in vars
const vars = {
__WEEX__: !!opts.weex,
__WEEX_VERSION__: weexVersion,
__VERSION__: version,
__SSR_TEST__: false
}

View File

@ -1,24 +0,0 @@
const coreVersion = require('../package.json').version
const weexVersion = require('../packages/weex-vue-framework/package.json').version
let weexBaseVersion = weexVersion.match(/^[\d.]+/)[0]
let weexSubVersion = Number(weexVersion.match(/-weex\.(\d+)$/)[1])
if (weexBaseVersion === coreVersion) {
// same core version, increment sub version
weexSubVersion++
} else {
// new core version, reset sub version
weexBaseVersion = coreVersion
weexSubVersion = 1
}
if (process.argv[2] === '-c') {
console.log(weexVersion)
} else {
console.log(weexBaseVersion + '-weex.' + weexSubVersion)
}
module.exports = {
base: weexBaseVersion,
sub: weexSubVersion
}

View File

@ -1,38 +0,0 @@
#!/bin/bash
set -e
CUR_VERSION=$(node build/get-weex-version.js -c)
NEXT_VERSION=$(node build/get-weex-version.js)
echo "Current: $CUR_VERSION"
read -p "Enter new version ($NEXT_VERSION): " -n 1 -r
if ! [[ -z $REPLY ]]; then
NEXT_VERSION=$REPLY
fi
read -p "Releasing weex-vue-framework@$NEXT_VERSION - are you sure? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Releasing weex-vue-framework@$NEXT_VERSION ..."
npm run lint
npm run flow
npm run test:weex
# build
WEEX_VERSION=$NEXT_VERSION npm run build:weex
# update package
# using subshells to avoid having to cd back
( cd packages/weex-vue-framework
npm version "$NEXT_VERSION"
npm publish
)
( cd packages/weex-template-compiler
npm version "$NEXT_VERSION"
npm publish
)
# commit
git add packages/weex*
git commit -m "[release] weex-vue-framework@$NEXT_VERSION"
fi

View File

@ -1,7 +1,7 @@
const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/
const fnInvokeRE = /\([^)]*?\);*$/
const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/
const simplePathRE =
/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/
// KeyboardEvent.keyCode aliases
const keyCodes: { [key: string]: number | Array<number> } = {
@ -13,7 +13,7 @@ const keyCodes: { [key: string]: number | Array<number> } = {
left: 37,
right: 39,
down: 40,
delete: [8, 46],
delete: [8, 46]
}
// KeyboardEvent.key aliases
@ -30,7 +30,7 @@ const keyNames: { [key: string]: string | Array<string> } = {
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
// #9112: IE11 uses `Del` for Delete key name.
delete: ['Backspace', 'Delete', 'Del'],
delete: ['Backspace', 'Delete', 'Del']
}
// #4868: modifiers that prevent the execution of the listener
@ -48,7 +48,7 @@ const modifierCode: { [key: string]: string } = {
meta: genGuard(`!$event.metaKey`),
left: genGuard(`'button' in $event && $event.button !== 0`),
middle: genGuard(`'button' in $event && $event.button !== 1`),
right: genGuard(`'button' in $event && $event.button !== 2`),
right: genGuard(`'button' in $event && $event.button !== 2`)
}
export function genHandlers(
@ -75,28 +75,6 @@ export function genHandlers(
}
}
// Generate handler code with binding params on Weex
/* istanbul ignore next */
function genWeexHandler(params: Array<any>, handlerCode: string) {
let innerHandlerCode = handlerCode
const exps = params.filter(
(exp) => simplePathRE.test(exp) && exp !== '$event'
)
const bindings = exps.map((exp) => ({ '@binding': exp }))
const args = exps.map((exp, i) => {
const key = `$_${i + 1}`
innerHandlerCode = innerHandlerCode.replace(exp, key)
return key
})
args.push('$event')
return (
'{\n' +
`handler:function(${args.join(',')}){${innerHandlerCode}},\n` +
`params:${JSON.stringify(bindings)}\n` +
'}'
)
}
function genHandler(
handler: ASTElementHandler | Array<ASTElementHandler>
): string {
@ -118,10 +96,6 @@ function genHandler(
if (isMethodPath || isFunctionExpression) {
return handler.value
}
/* istanbul ignore if */
if (__WEEX__ && handler.params) {
return genWeexHandler(handler.params, handler.value)
}
return `function($event){${
isFunctionInvocation ? `return ${handler.value}` : handler.value
}}` // inline statement
@ -162,10 +136,6 @@ function genHandler(
: isFunctionInvocation
? `return ${handler.value}`
: handler.value
/* istanbul ignore if */
if (__WEEX__ && handler.params) {
return genWeexHandler(handler.params, code + handlerCode)
}
return `function($event){${code}${handlerCode}}`
}
}

View File

@ -1,4 +1,3 @@
import { genHandlers } from './events'
import baseDirectives from '../directives/index'
import { camelize, no, extend } from 'shared/util'
@ -58,7 +57,7 @@ export function generate(
: '_c("div")'
return {
render: `with(this){return ${code}}`,
staticRenderFns: state.staticRenderFns,
staticRenderFns: state.staticRenderFns
}
}
@ -561,14 +560,17 @@ function genSlot(el: ASTElement, state: CodegenState): string {
const slotName = el.slotName || '"default"'
const children = genChildren(el, state)
let res = `_t(${slotName}${children ? `,function(){return ${children}}` : ''}`
const attrs = el.attrs || el.dynamicAttrs
? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(attr => ({
// slot props are camelized
name: camelize(attr.name),
value: attr.value,
dynamic: attr.dynamic
})))
: null
const attrs =
el.attrs || el.dynamicAttrs
? genProps(
(el.attrs || []).concat(el.dynamicAttrs || []).map((attr) => ({
// slot props are camelized
name: camelize(attr.name),
value: attr.value,
dynamic: attr.dynamic
}))
)
: null
const bind = el.attrsMap['v-bind']
if ((attrs || bind) && !children) {
res += `,null`
@ -599,9 +601,7 @@ function genProps(props: Array<ASTAttr>): string {
let dynamicProps = ``
for (let i = 0; i < props.length; i++) {
const prop = props[i]
const value = __WEEX__
? generateValue(prop.value)
: transformSpecialNewlines(prop.value)
const value = transformSpecialNewlines(prop.value)
if (prop.dynamic) {
dynamicProps += `${prop.name},${value},`
} else {
@ -616,14 +616,6 @@ function genProps(props: Array<ASTAttr>): string {
}
}
/* istanbul ignore next */
function generateValue(value) {
if (typeof value === 'string') {
return transformSpecialNewlines(value)
}
return JSON.stringify(value)
}
// #3895, #4268
function transformSpecialNewlines(text: string): string {
return text.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029')

View File

@ -1,19 +1,14 @@
// can we use __proto__?
export const hasProto = '__proto__' in {}
// Browser environment sniffing
export const inBrowser = typeof window !== 'undefined'
export const inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform
export const weexPlatform = inWeex && WXEnvironment.platform.toLowerCase()
export const UA = inBrowser && window.navigator.userAgent.toLowerCase()
export const isIE = UA && /msie|trident/.test(UA)
export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
export const isEdge = UA && UA.indexOf('edge/') > 0
export const isAndroid =
(UA && UA.indexOf('android') > 0) || weexPlatform === 'android'
export const isIOS =
(UA && /iphone|ipad|ipod|ios/.test(UA)) || weexPlatform === 'ios'
export const isAndroid = UA && UA.indexOf('android') > 0
export const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA)
export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge
export const isPhantomJS = UA && /phantomjs/.test(UA)
export const isFF = UA && UA.match(/firefox\/(\d+)/)
@ -30,7 +25,7 @@ if (inBrowser) {
get() {
/* istanbul ignore next */
supportsPassive = true
},
}
} as object) // https://github.com/facebook/flow/issues/285
window.addEventListener('test-passive', null as any, opts)
} catch (e: any) {}
@ -42,7 +37,7 @@ let _isServer
export const isServerRendering = () => {
if (_isServer === undefined) {
/* istanbul ignore if */
if (!inBrowser && !inWeex && typeof global !== 'undefined') {
if (!inBrowser && typeof global !== 'undefined') {
// detect presence of vue-server-renderer and avoid
// Webpack shimming the process
_isServer =

View File

@ -1,4 +1,3 @@
import { warn } from './debug'
import { observe, toggleObserving, shouldObserve } from '../observer/index'
import {
@ -7,7 +6,7 @@ import {
toRawType,
hyphenate,
capitalize,
isPlainObject,
isPlainObject
} from 'shared/util'
import type { Component } from 'typescript/component'
@ -51,11 +50,7 @@ export function validateProp(
observe(value)
toggleObserving(prevShouldObserve)
}
if (
process.env.NODE_ENV !== 'production' &&
// skip validation for weex recycle-list child component props
!(__WEEX__ && isObject(value) && '@binding' in value)
) {
if (process.env.NODE_ENV !== 'production') {
assertProp(prop, key, value, vm, absent)
}
return value
@ -182,7 +177,7 @@ function assertType(
}
return {
valid,
expectedType,
expectedType
}
}

View File

@ -20,10 +20,6 @@ import {
deactivateChildComponent,
} from '../instance/lifecycle'
import {
isRecyclableComponent,
renderRecyclableComponentTemplate,
} from 'weex/runtime/recycle-list/render-component-template'
import type {
MountedComponentVNode,
VNodeData,
@ -206,14 +202,6 @@ export function createComponent(
asyncFactory
)
// Weex specific: invoke recycle-list optimized @render function for
// extracting cell-slot template.
// https://github.com/Hanks10100/weex-native-directive/tree/master/component
/* istanbul ignore if */
if (__WEEX__ && isRecyclableComponent(vnode)) {
return renderRecyclableComponentTemplate(vnode)
}
return vnode
}

View File

@ -1,4 +1,3 @@
import config from '../config'
import VNode, { createEmptyVNode } from './vnode'
import { createComponent } from './create-component'
@ -11,7 +10,7 @@ import {
isTrue,
isObject,
isPrimitive,
resolveAsset,
resolveAsset
} from '../util/index'
import { normalizeChildren, simpleNormalizeChildren } from './helpers/index'
@ -74,14 +73,11 @@ export function _createElement(
isDef(data.key) &&
!isPrimitive(data.key)
) {
// @ts-expect-error
if (!__WEEX__ || !('@binding' in data.key)) {
warn(
'Avoid using non-primitive value as key, ' +
'use string/number value instead.',
context
)
}
warn(
'Avoid using non-primitive value as key, ' +
'use string/number value instead.',
context
)
}
// support single function children as default scoped slot
if (Array.isArray(children) && typeof children[0] === 'function') {

View File

@ -1,5 +1,5 @@
import { warn, invokeWithErrorHandling } from 'core/util/index'
import { cached, isUndef, isTrue, isPlainObject } from 'shared/util'
import { cached, isUndef, isTrue } from 'shared/util'
import type { Component } from 'typescript/component'
const normalizeEvent = cached((name: string): {
@ -69,11 +69,6 @@ export function updateListeners(
def = cur = on[name]
old = oldOn[name]
event = normalizeEvent(name)
/* istanbul ignore if */
if (__WEEX__ && isPlainObject(def)) {
cur = def.handler
event.params = def.params
}
if (isUndef(cur)) {
process.env.NODE_ENV !== 'production' &&
warn(

View File

@ -170,32 +170,11 @@ export function createPatchFunction(backend) {
: nodeOps.createElement(tag, vnode)
setScope(vnode)
/* istanbul ignore if */
if (__WEEX__) {
// in Weex, the default insertion order is parent-first.
// List items can be optimized to use children-first insertion
// with append="tree".
const appendAsTree = isDef(data) && isTrue(data.appendAsTree)
if (!appendAsTree) {
if (isDef(data)) {
invokeCreateHooks(vnode, insertedVnodeQueue)
}
insert(parentElm, vnode.elm, refElm)
}
createChildren(vnode, children, insertedVnodeQueue)
if (appendAsTree) {
if (isDef(data)) {
invokeCreateHooks(vnode, insertedVnodeQueue)
}
insert(parentElm, vnode.elm, refElm)
}
} else {
createChildren(vnode, children, insertedVnodeQueue)
if (isDef(data)) {
invokeCreateHooks(vnode, insertedVnodeQueue)
}
insert(parentElm, vnode.elm, refElm)
createChildren(vnode, children, insertedVnodeQueue)
if (isDef(data)) {
invokeCreateHooks(vnode, insertedVnodeQueue)
}
insert(parentElm, vnode.elm, refElm)
if (process.env.NODE_ENV !== 'production' && data && data.pre) {
creatingElmInVPre--

23
src/global.d.ts vendored
View File

@ -1,32 +1,9 @@
declare const __WEEX__: boolean;
declare const __SSR_TEST__: boolean;
declare type WeexEnvironment = {
platform: string; // could be "Web", "iOS", "Android"
weexVersion: string; // the version of WeexSDK
osName: string; // could be "iOS", "Android" or others
osVersion: string;
appName: string; // mobile app name or browser name
appVersion: string;
// information about current running device
deviceModel: string; // phone device model
deviceWidth: number;
deviceHeight: number;
scale: number;
// only available on the web
userAgent?: string;
dpr?: number;
rem?: number;
};
declare let WXEnvironment: WeexEnvironment;
interface Window {
__VUE_DEVTOOLS_GLOBAL_HOOK__: DevtoolsHook;
}
// from https://github.com/vuejs/vue-devtools/blob/bc719c95a744614f5c3693460b64dc21dfa339a8/packages/app-backend-api/src/global-hook.ts#L3
interface DevtoolsHook {
emit: (event: string, ...payload: any[]) => void

View File

@ -1,5 +0,0 @@
import model from './model'
export default {
model,
}

View File

@ -1,29 +0,0 @@
import { addHandler, addAttr } from 'compiler/helpers'
import { genComponentModel, genAssignmentCode } from 'compiler/directives/model'
export default function model(el: ASTElement, dir: ASTDirective): void {
if (el.tag === 'input' || el.tag === 'textarea') {
genDefaultModel(el, dir.value, dir.modifiers)
} else {
genComponentModel(el, dir.value, dir.modifiers)
}
}
function genDefaultModel(
el: ASTElement,
value: string,
modifiers: ASTModifiers | null
) {
const { lazy, trim, number } = modifiers || {}
const event = lazy ? 'change' : 'input'
let valueExpression = `$event.target.attr.value${trim ? '.trim()' : ''}`
if (number) {
valueExpression = `_n(${valueExpression})`
}
const code = genAssignmentCode(value, valueExpression)
addAttr(el, 'value', `(${value})`)
addHandler(el, event, code, null, true)
}

View File

@ -1,52 +0,0 @@
import { genStaticKeys } from 'shared/util'
import { createCompiler } from 'compiler/index'
import modules from './modules/index'
import directives from './directives/index'
import {
isUnaryTag,
mustUseProp,
isReservedTag,
canBeLeftOpenTag,
getTagNamespace,
} from '../util/element'
import type { WeexCompiledResult, WeexCompilerOptions } from 'typescript/weex'
export const baseOptions: WeexCompilerOptions = {
modules,
directives,
isUnaryTag,
mustUseProp,
canBeLeftOpenTag,
isReservedTag,
getTagNamespace,
preserveWhitespace: false,
recyclable: false,
staticKeys: genStaticKeys(modules),
}
const compiler = createCompiler(baseOptions)
export function compile(
template: string,
options?: WeexCompilerOptions
): WeexCompiledResult {
let generateAltRender = false
if (options && options.recyclable === true) {
generateAltRender = true
options.recyclable = false
}
const result = compiler.compile(template, options)
// generate @render function for <recycle-list>
if (options && generateAltRender) {
options.recyclable = true
// disable static optimizations
options.optimize = false
const { render } = compiler.compile(template, options)
result['@render'] = render
}
return result
}

View File

@ -1,29 +0,0 @@
import { makeMap } from 'shared/util'
// The "unitary tag" means that the tag node and its children
// must be sent to the native together.
const isUnitaryTag = makeMap('cell,header,cell-slot,recycle-list', true)
function preTransformNode(el: ASTElement) {
if (
isUnitaryTag(el.tag) &&
!el.attrsList.some((item) => item.name === 'append')
) {
el.attrsMap.append = 'tree'
el.attrsList.push({ name: 'append', value: 'tree' })
}
if (el.attrsMap.append === 'tree') {
el.appendAsTree = true
}
}
function genData(el: ASTElement): string {
return el.appendAsTree ? `appendAsTree:true,` : ''
}
export default {
staticKeys: ['appendAsTree'],
preTransformNode,
genData,
} as ModuleOptions

View File

@ -1,75 +0,0 @@
import { parseText } from 'compiler/parser/text-parser'
import { getAndRemoveAttr, getBindingAttr, baseWarn } from 'compiler/helpers'
type StaticClassResult = {
dynamic: boolean
classResult: string
}
function transformNode(el: ASTElement, options: CompilerOptions) {
const warn = options.warn || baseWarn
const staticClass = getAndRemoveAttr(el, 'class')
const { dynamic, classResult } = parseStaticClass(staticClass, options)
if (process.env.NODE_ENV !== 'production' && dynamic && staticClass) {
warn(
`class="${staticClass}": ` +
'Interpolation inside attributes has been deprecated. ' +
'Use v-bind or the colon shorthand instead.',
el.rawAttrsMap['class']
)
}
if (!dynamic && classResult) {
el.staticClass = classResult
}
const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
if (classBinding) {
el.classBinding = classBinding
} else if (dynamic) {
el.classBinding = classResult
}
}
function genData(el: ASTElement): string {
let data = ''
if (el.staticClass) {
data += `staticClass:${el.staticClass},`
}
if (el.classBinding) {
data += `class:${el.classBinding},`
}
return data
}
function parseStaticClass(
staticClass: string | null | undefined,
options: CompilerOptions
): StaticClassResult {
// "a b c" -> ["a", "b", "c"] => staticClass: ["a", "b", "c"]
// "a {{x}} c" -> ["a", x, "c"] => classBinding: '["a", x, "c"]'
let dynamic = false
let classResult = ''
if (staticClass) {
const classList = staticClass
.trim()
.split(' ')
.map((name) => {
const result = parseText(name, options.delimiters)
if (result) {
dynamic = true
return result.expression
}
return JSON.stringify(name)
})
if (classList.length) {
classResult = '[' + classList.join(',') + ']'
}
}
return { dynamic, classResult }
}
export default {
staticKeys: ['staticClass'],
transformNode,
genData,
} as ModuleOptions

View File

@ -1,7 +0,0 @@
import klass from './class'
import style from './style'
import props from './props'
import append from './append'
import recycleList from './recycle-list/index'
export default [recycleList, klass, style, props, append]

View File

@ -1,36 +0,0 @@
import { cached, camelize } from 'shared/util'
const normalize = cached(camelize)
function normalizeKeyName(str: string): string {
if (str.match(/^v\-/)) {
return str.replace(/(v-[a-z\-]+\:)([a-z\-]+)$/i, ($, directive, prop) => {
return directive + normalize(prop)
})
}
return normalize(str)
}
function transformNode(el: ASTElement) {
if (Array.isArray(el.attrsList)) {
el.attrsList.forEach((attr) => {
if (attr.name && attr.name.match(/\-/)) {
const realName = normalizeKeyName(attr.name)
if (el.attrsMap) {
el.attrsMap[realName] = el.attrsMap[attr.name]
delete el.attrsMap[attr.name]
}
if (el.rawAttrsMap && el.rawAttrsMap[attr.name]) {
el.rawAttrsMap[realName] = el.rawAttrsMap[attr.name]
// $flow-disable-line
delete el.rawAttrsMap[attr.name]
}
attr.name = realName
}
})
}
}
export default {
transformNode,
} as ModuleOptions

View File

@ -1,12 +0,0 @@
import { addAttr } from 'compiler/helpers'
// mark component root nodes as
export function postTransformComponentRoot(el: ASTElement) {
if (!el.parent) {
// component root
addAttr(el, '@isComponentRoot', 'true')
addAttr(el, '@templateId', '_uid')
addAttr(el, '@componentProps', '$props || {}')
}
}

View File

@ -1,16 +0,0 @@
import { addAttr } from 'compiler/helpers'
import type { WeexCompilerOptions } from 'typescript/weex'
import { RECYCLE_LIST_MARKER } from 'weex/util/index'
// mark components as inside recycle-list so that we know we need to invoke
// their special @render function instead of render in create-component.js
export function postTransformComponent(
el: ASTElement,
options: WeexCompilerOptions
) {
// $flow-disable-line (we know isReservedTag is there)
if (!options.isReservedTag!(el.tag) && el.tag !== 'cell-slot') {
addAttr(el, RECYCLE_LIST_MARKER, 'true')
}
}

View File

@ -1,59 +0,0 @@
import { preTransformRecycleList } from './recycle-list'
import { postTransformComponent } from './component'
import { postTransformComponentRoot } from './component-root'
import { postTransformText } from './text'
import { preTransformVBind } from './v-bind'
import { preTransformVIf } from './v-if'
import { preTransformVFor } from './v-for'
import { postTransformVOn } from './v-on'
import { preTransformVOnce } from './v-once'
import type { WeexCompilerOptions } from 'typescript/weex'
let currentRecycleList: null | ASTElement = null
function shouldCompile(el: ASTElement, options: WeexCompilerOptions) {
return options.recyclable || (currentRecycleList && el !== currentRecycleList)
}
function preTransformNode(el: ASTElement, options: WeexCompilerOptions) {
if (el.tag === 'recycle-list') {
preTransformRecycleList(el, options)
currentRecycleList = el
}
if (shouldCompile(el, options)) {
preTransformVBind(el)
preTransformVIf(el, options) // also v-else-if and v-else
preTransformVFor(el, options)
preTransformVOnce(el)
}
}
function transformNode(el: ASTElement, options: WeexCompilerOptions) {
if (shouldCompile(el, options)) {
// do nothing yet
}
}
function postTransformNode(el: ASTElement, options: WeexCompilerOptions) {
if (shouldCompile(el, options)) {
// mark child component in parent template
postTransformComponent(el, options)
// mark root in child component template
postTransformComponentRoot(el)
// <text>: transform children text into value attr
if (el.tag === 'text') {
postTransformText(el)
}
postTransformVOn(el)
}
if (el === currentRecycleList) {
currentRecycleList = null
}
}
export default {
preTransformNode,
transformNode,
postTransformNode,
} as ModuleOptions

View File

@ -1,50 +0,0 @@
import { parseFor } from 'compiler/parser/index'
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
import type { WeexCompilerOptions } from 'typescript/weex'
/**
* Map the following syntax to corresponding attrs:
*
* <recycle-list for="(item, i) in longList" switch="cellType">
* <cell-slot case="A"> ... </cell-slot>
* <cell-slot case="B"> ... </cell-slot>
* </recycle-list>
*/
export function preTransformRecycleList(
el: ASTElement,
options: WeexCompilerOptions
) {
const exp = getAndRemoveAttr(el, 'for')
if (!exp) {
if (options.warn) {
options.warn(`Invalid <recycle-list> syntax: missing "for" expression.`)
}
return
}
const res = parseFor(exp)
if (!res) {
if (options.warn) {
options.warn(`Invalid <recycle-list> syntax: ${exp}.`)
}
return
}
addRawAttr(el, ':list-data', res.for)
addRawAttr(el, 'binding-expression', res.for)
addRawAttr(el, 'alias', res.alias)
if (res.iterator2) {
// (item, key, index) for object iteration
// is this even supported?
addRawAttr(el, 'index', res.iterator2)
} else if (res.iterator1) {
addRawAttr(el, 'index', res.iterator1)
}
const switchKey = getAndRemoveAttr(el, 'switch')
if (switchKey) {
addRawAttr(el, 'switch', switchKey)
}
}

View File

@ -1,23 +0,0 @@
import { addAttr } from 'compiler/helpers'
function genText(node: ASTNode) {
const value =
node.type === 3
? node.text
: node.type === 2
? node.tokens.length === 1
? node.tokens[0]
: node.tokens
: ''
return JSON.stringify(value)
}
export function postTransformText(el: ASTElement) {
// weex <text> can only contain text, so the parser
// always generates a single child.
if (el.children.length) {
addAttr(el, 'value', genText(el.children[0]))
el.children = []
}
}

View File

@ -1,20 +0,0 @@
import { camelize } from 'shared/util'
import { generateBinding } from 'weex/util/parser'
import { bindRE } from 'compiler/parser/index'
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
function parseAttrName(name: string): string {
return camelize(name.replace(bindRE, ''))
}
export function preTransformVBind(el: ASTElement) {
for (const attr in el.attrsMap) {
if (bindRE.test(attr)) {
const name: string = parseAttrName(attr)
const value = generateBinding(getAndRemoveAttr(el, attr))
delete el.attrsMap[attr]
addRawAttr(el, name, value)
}
}
}

View File

@ -1,33 +0,0 @@
import { parseFor } from 'compiler/parser/index'
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
import type { WeexCompilerOptions } from 'typescript/weex'
export function preTransformVFor(el: ASTElement, options: WeexCompilerOptions) {
const exp = getAndRemoveAttr(el, 'v-for')
if (!exp) {
return
}
const res = parseFor(exp)
if (!res) {
if (process.env.NODE_ENV !== 'production' && options.warn) {
options.warn(`Invalid v-for expression: ${exp}`)
}
return
}
const desc: Object = {
'@expression': res.for,
'@alias': res.alias,
}
if (res.iterator2) {
desc['@key'] = res.iterator1
desc['@index'] = res.iterator2
} else {
desc['@index'] = res.iterator1
}
delete el.attrsMap['v-for']
addRawAttr(el, '[[repeat]]', desc)
}

View File

@ -1,61 +0,0 @@
import { addIfCondition } from "compiler/parser/index";
import { getAndRemoveAttr, addRawAttr } from "compiler/helpers";
import type { WeexCompilerOptions } from "typescript/weex";
function hasConditionDirective(el: ASTElement): boolean {
for (const attr in el.attrsMap) {
if (/^v\-if|v\-else|v\-else\-if$/.test(attr)) {
return true;
}
}
return false;
}
function getPreviousConditions(el: ASTElement): Array<string> {
const conditions: any[] = [];
if (el.parent && el.parent.children) {
for (let c = 0, n = el.parent.children.length; c < n; ++c) {
const ifConditions = (el.parent.children[c] as ASTElement).ifConditions;
if (ifConditions) {
for (let i = 0, l = ifConditions.length; i < l; ++i) {
const condition = ifConditions[i];
if (condition && condition.exp) {
conditions.push(condition.exp);
}
}
}
}
}
return conditions;
}
export function preTransformVIf(el: ASTElement, options: WeexCompilerOptions) {
if (hasConditionDirective(el)) {
let exp;
const ifExp = getAndRemoveAttr(el, "v-if", true /* remove from attrsMap */);
const elseifExp = getAndRemoveAttr(el, "v-else-if", true);
// don't need the value, but remove it to avoid being generated as a
// custom directive
getAndRemoveAttr(el, "v-else", true);
if (ifExp) {
exp = ifExp;
addIfCondition(el, { exp: ifExp, block: el });
} else {
elseifExp && addIfCondition(el, { exp: elseifExp, block: el });
const prevConditions = getPreviousConditions(el);
if (prevConditions.length) {
const prevMatch = prevConditions.join(" || ");
exp = elseifExp
? `!(${prevMatch}) && (${elseifExp})` // v-else-if
: `!(${prevMatch})`; // v-else
} else if (process.env.NODE_ENV !== "production" && options.warn) {
options.warn(
`v-${elseifExp ? 'else-if="' + elseifExp + '"' : "else"} ` +
`used on element <${el.tag}> without corresponding v-if.`
);
return;
}
}
addRawAttr(el, "[[match]]", exp);
}
}

View File

@ -1,24 +0,0 @@
const inlineStatementRE = /^\s*([A-Za-z_$0-9\['\."\]]+)*\s*\(\s*(([A-Za-z_$0-9\['\."\]]+)?(\s*,\s*([A-Za-z_$0-9\['\."\]]+))*)\s*\)$/
function parseHandlerParams(handler: ASTElementHandler) {
const res = inlineStatementRE.exec(handler.value)
if (res && res[2]) {
handler.params = res[2].split(/\s*,\s*/)
}
}
export function postTransformVOn(el: ASTElement) {
const events: ASTElementHandlers | void = el.events
if (!events) {
return
}
for (const name in events) {
const handler: ASTElementHandler | Array<ASTElementHandler> = events[name]
if (Array.isArray(handler)) {
handler.map((fn) => parseHandlerParams(fn))
} else {
parseHandlerParams(handler)
}
}
}

View File

@ -1,18 +0,0 @@
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
function containVOnce(el: ASTElement): boolean {
for (const attr in el.attrsMap) {
if (/^v\-once$/i.test(attr)) {
return true
}
}
return false
}
export function preTransformVOnce(el: ASTElement) {
if (containVOnce(el)) {
getAndRemoveAttr(el, 'v-once', true)
addRawAttr(el, '[[once]]', true)
}
}

View File

@ -1,87 +0,0 @@
import { cached, camelize, isPlainObject } from 'shared/util'
import { parseText } from 'compiler/parser/text-parser'
import { getAndRemoveAttr, getBindingAttr, baseWarn } from 'compiler/helpers'
type StaticStyleResult = {
dynamic: boolean
styleResult: string
}
const normalize = cached(camelize)
function transformNode(el: ASTElement, options: CompilerOptions) {
const warn = options.warn || baseWarn
const staticStyle = getAndRemoveAttr(el, 'style')
const { dynamic, styleResult } = parseStaticStyle(staticStyle!, options)
if (process.env.NODE_ENV !== 'production' && dynamic) {
warn(
`style="${String(staticStyle)}": ` +
'Interpolation inside attributes has been deprecated. ' +
'Use v-bind or the colon shorthand instead.',
el.rawAttrsMap['style']
)
}
if (!dynamic && styleResult) {
el.staticStyle = styleResult
}
const styleBinding = getBindingAttr(el, 'style', false /* getStatic */)
if (styleBinding) {
el.styleBinding = styleBinding
} else if (dynamic) {
el.styleBinding = styleResult
}
}
function genData(el: ASTElement): string {
let data = ''
if (el.staticStyle) {
data += `staticStyle:${el.staticStyle},`
}
if (el.styleBinding) {
data += `style:${el.styleBinding},`
}
return data
}
function parseStaticStyle(
staticStyle: string | null,
options: CompilerOptions
): StaticStyleResult {
// "width: 200px; height: 200px;" -> {width: 200, height: 200}
// "width: 200px; height: {{y}}" -> {width: 200, height: y}
let dynamic = false
let styleResult = ''
if (typeof staticStyle === 'string') {
const styleList = staticStyle
.trim()
.split(';')
.map((style) => {
const result = style.trim().split(':')
if (result.length !== 2) {
return
}
const key = normalize(result[0].trim())
const value = result[1].trim()
const dynamicValue = parseText(value, options.delimiters)
if (dynamicValue) {
dynamic = true
return key + ':' + dynamicValue.expression
}
return key + ':' + JSON.stringify(value)
})
.filter((result) => result)
if (styleList.length) {
styleResult = '{' + styleList.join(',') + '}'
}
} else if (isPlainObject(staticStyle)) {
styleResult = JSON.stringify(staticStyle) || ''
}
return { dynamic, styleResult }
}
export default {
staticKeys: ['staticStyle'],
transformNode,
genData,
} as ModuleOptions

View File

@ -1,2 +0,0 @@
export { compile } from 'weex/compiler/index'
export { generateCodeFrame } from 'compiler/codeframe'

View File

@ -1,196 +0,0 @@
import type { GlobalAPI } from 'typescript/global-api'
import type {
Weex,
WeexInstanceContext,
WeexInstanceOption,
WeexRuntimeContext,
} from 'typescript/weex'
// this will be preserved during build
const VueFactory = require('./factory')
const instanceOptions: { [key: string]: WeexInstanceOption } = {}
/**
* Create instance context.
*/
export function createInstanceContext(
instanceId: string,
runtimeContext: WeexRuntimeContext,
data: any = {}
): WeexInstanceContext {
const weex: Weex = runtimeContext.weex
const instance: WeexInstanceOption = (instanceOptions[instanceId] = {
instanceId,
config: weex.config,
document: weex.document,
data
})
// Each instance has an independent `Vue` module instance
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
// DEPRECATED
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)
const instanceContext = Object.assign({ Vue }, timerAPIs)
Object.freeze(instanceContext)
return instanceContext
}
/**
* Destroy an instance with id. It will make sure all memory of
* this instance released and no more leaks.
*/
export function destroyInstance(instanceId: string): void {
const instance = instanceOptions[instanceId]
//@ts-expect-error
if (instance && instance.app instanceof instance.Vue) {
try {
instance.app!.$destroy()
instance.document.destroy()
} catch (e: any) {}
//@ts-expect-error
delete instance.document
delete instance.app
}
delete instanceOptions[instanceId]
}
/**
* Refresh an instance with id and new top-level component data.
* It will use `Vue.set` on all keys of the new data. So it's better
* define all possible meaningful keys when instance created.
*/
export function refreshInstance(
instanceId: string,
data: Object
): Error | void {
const instance = instanceOptions[instanceId]
//@ts-expect-error
if (!instance || !(instance.app instanceof instance.Vue)) {
return new Error(`refreshInstance: instance ${instanceId} not found!`)
}
if (instance.Vue && instance.Vue.set) {
for (const key in data) {
instance.Vue.set(instance.app!, key, data[key])
}
}
// Finally `refreshFinish` signal needed.
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, [])
}
/**
* Create a fresh instance of Vue for each Weex instance.
*/
function createVueModuleInstance(instanceId: string, weex: Weex): GlobalAPI {
const exports = {}
VueFactory(exports, weex.document)
//@ts-expect-error
const Vue = exports.Vue
const instance = instanceOptions[instanceId]
// patch reserved tag detection to account for dynamically registered
// components
const weexRegex = /^weex:/i
const isReservedTag = Vue.config.isReservedTag || (() => false)
const isRuntimeComponent = Vue.config.isRuntimeComponent || (() => false)
Vue.config.isReservedTag = (name) => {
return (
(!isRuntimeComponent(name) && weex.supports(`@component/${name}`)) ||
isReservedTag(name) ||
weexRegex.test(name)
)
}
Vue.config.parsePlatformTagName = (name) => name.replace(weexRegex, '')
// expose weex-specific info
Vue.prototype.$instanceId = instanceId
Vue.prototype.$document = instance.document
// expose weex native module getter on subVue prototype so that
// vdom runtime modules can access native modules via vnode.context
Vue.prototype.$requireWeexModule = weex.requireModule
// Hack `Vue` behavior to handle instance information and data
// before root component created.
Vue.mixin({
beforeCreate() {
const options = this.$options
// root component (vm)
if (options.el) {
// set external data of instance
const dataOption = options.data
const internalData =
(typeof dataOption === 'function' ? dataOption() : dataOption) || {}
options.data = Object.assign(internalData, instance.data)
// record instance by id
instance.app = this
}
},
mounted() {
const options = this.$options
// root component (vm)
if (options.el && weex.document && instance.app === this) {
try {
// Send "createFinish" signal to native.
weex.document.taskCenter.send('dom', { action: 'createFinish' }, [])
} catch (e: any) {}
}
},
})
/**
* @deprecated Just instance variable `weex.config`
* Get instance config.
* @return {object}
*/
Vue.prototype.$getConfig = function () {
if (instance.app instanceof Vue) {
return instance.config
}
}
return Vue
}
/**
* DEPRECATED
* Generate HTML5 Timer APIs. An important point is that the callback
* will be converted into callback id when sent to native. So the
* framework can make sure no side effect of the callback happened after
* an instance destroyed.
*/
function getInstanceTimer(instanceId: string, moduleGetter: Function): Object {
const instance = instanceOptions[instanceId]
const timer = moduleGetter('timer')
const timerAPIs = {
setTimeout: (...args) => {
const handler = function () {
args[0](...args.slice(2))
}
timer.setTimeout(handler, args[1])
//@ts-expect-error
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
setInterval: (...args) => {
const handler = function () {
args[0](...args.slice(2))
}
timer.setInterval(handler, args[1])
//@ts-expect-error
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
},
clearTimeout: (n) => {
timer.clearTimeout(n)
},
clearInterval: (n) => {
timer.clearInterval(n)
},
}
return timerAPIs
}

View File

@ -1,6 +0,0 @@
// this entry is built and wrapped with a factory function
// used to generate a fresh copy of Vue for every Weex instance.
import Vue from './runtime/index'
exports.Vue = Vue

View File

@ -1,9 +0,0 @@
import Richtext from './richtext'
import Transition from './transition'
import TransitionGroup from './transition-group'
export default {
Richtext,
Transition,
TransitionGroup,
}

View File

@ -1,89 +0,0 @@
import VNode from 'core/vdom/vnode'
function getVNodeType(vnode: VNode): string {
if (!vnode.tag) {
return ''
}
return vnode.tag.replace(/vue\-component\-(\d+\-)?/, '')
}
function isSimpleSpan(vnode: VNode): boolean {
return (vnode.children &&
vnode.children.length === 1 &&
!vnode.children[0].tag) as any
}
function parseStyle(vnode: VNode): Object | void {
if (!vnode || !vnode.data) {
return
}
const { staticStyle, staticClass } = vnode.data
if (vnode.data.style || vnode.data.class || staticStyle || staticClass) {
const styles = Object.assign({}, staticStyle, vnode.data.style)
// @ts-expect-error
const cssMap = vnode.context!.$options.style || {}
const classList = ([] as string[]).concat(staticClass!, vnode.data.class)
classList.forEach((name) => {
if (name && cssMap[name]) {
Object.assign(styles, cssMap[name])
}
})
return styles
}
}
function convertVNodeChildren(
children: Array<VNode>
): Array<VNode> | undefined {
if (!children.length) {
return
}
return children.map(
(vnode): VNode => {
const type: string = getVNodeType(vnode)
const props: any = { type }
// convert raw text node
if (!type) {
props.type = 'span'
props.attr = {
value: (vnode.text || '').trim(),
}
} else {
props.style = parseStyle(vnode)
if (vnode.data) {
props.attr = vnode.data.attrs
if (vnode.data.on) {
props.events = vnode.data.on
}
}
if (type === 'span' && isSimpleSpan(vnode)) {
props.attr = props.attr || {}
//@ts-expect-error
props.attr.value = vnode.children[0].text.trim()
return props
}
}
if (vnode.children && vnode.children.length) {
props.children = convertVNodeChildren(vnode.children)
}
return props
}
)
}
export default {
name: 'richtext',
render(h: Function) {
return h('weex:richtext', {
on: this._events,
attrs: {
value: convertVNodeChildren(this.$options._renderChildren || []),
},
})
},
}

View File

@ -1,152 +0,0 @@
import { warn, extend } from 'core/util/index'
import { transitionProps, extractTransitionData } from './transition'
const props = extend(
{
tag: String,
moveClass: String,
},
transitionProps
)
delete props.mode
export default {
props,
created() {
const dom = this.$requireWeexModule('dom')
this.getPosition = (el) =>
new Promise((resolve, reject) => {
dom.getComponentRect(el.ref, (res) => {
if (!res.result) {
reject(new Error(`failed to get rect for element: ${el.tag}`))
} else {
resolve(res.size)
}
})
})
const animation = this.$requireWeexModule('animation')
this.animate = (el, options) =>
new Promise((resolve) => {
animation.transition(el.ref, options, resolve)
})
},
render(h) {
const tag = this.tag || this.$vnode.data.tag || 'span'
const map = Object.create(null)
const prevChildren = (this.prevChildren = this.children)
const rawChildren = this.$slots.default || []
const children: any[] = (this.children = [])
const transitionData = extractTransitionData(this)
for (let i = 0; i < rawChildren.length; i++) {
const c = rawChildren[i]
if (c.tag) {
if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
children.push(c)
map[c.key] = c
;(c.data || (c.data = {})).transition = transitionData
} else if (process.env.NODE_ENV !== 'production') {
const opts = c.componentOptions
const name = opts ? opts.Ctor.options.name || opts.tag : c.tag
warn(`<transition-group> children must be keyed: <${name}>`)
}
}
}
if (prevChildren) {
const kept: any[] = []
const removed: any[] = []
prevChildren.forEach((c) => {
c.data.transition = transitionData
// TODO: record before patch positions
if (map[c.key]) {
kept.push(c)
} else {
removed.push(c)
}
})
this.kept = h(tag, null, kept)
this.removed = removed
}
return h(tag, null, children)
},
beforeUpdate() {
// force removing pass
this.__patch__(
this._vnode,
this.kept,
false, // hydrating
true // removeOnly (!important, avoids unnecessary moves)
)
this._vnode = this.kept
},
updated() {
const children = this.prevChildren
const moveClass = this.moveClass || (this.name || 'v') + '-move'
const moveData =
children.length && this.getMoveData(children[0].context, moveClass)
if (!moveData) {
return
}
// TODO: finish implementing move animations once
// we have access to sync getComponentRect()
// children.forEach(callPendingCbs)
// Promise.all(children.map(c => {
// const oldPos = c.data.pos
// const newPos = c.data.newPos
// const dx = oldPos.left - newPos.left
// const dy = oldPos.top - newPos.top
// if (dx || dy) {
// c.data.moved = true
// return this.animate(c.elm, {
// styles: {
// transform: `translate(${dx}px,${dy}px)`
// }
// })
// }
// })).then(() => {
// children.forEach(c => {
// if (c.data.moved) {
// this.animate(c.elm, {
// styles: {
// transform: ''
// },
// duration: moveData.duration || 0,
// delay: moveData.delay || 0,
// timingFunction: moveData.timingFunction || 'linear'
// })
// }
// })
// })
},
methods: {
getMoveData(context, moveClass) {
const stylesheet = context.$options.style || {}
return stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][moveClass]
},
},
}
// function callPendingCbs (c) {
// /* istanbul ignore if */
// if (c.elm._moveCb) {
// c.elm._moveCb()
// }
// /* istanbul ignore if */
// if (c.elm._enterCb) {
// c.elm._enterCb()
// }
// }

View File

@ -1,9 +0,0 @@
// reuse same transition component logic from web
export {
transitionProps,
extractTransitionData,
} from 'web/runtime/components/transition'
import Transition from 'web/runtime/components/transition'
export default Transition

View File

@ -1 +0,0 @@
export default {}

View File

@ -1,35 +0,0 @@
import Vue from 'core/index'
import { patch } from 'weex/runtime/patch'
import { mountComponent } from 'core/instance/lifecycle'
import platformDirectives from 'weex/runtime/directives/index'
import platformComponents from 'weex/runtime/components/index'
import {
query,
mustUseProp,
isReservedTag,
isRuntimeComponent,
isUnknownElement,
} from 'weex/util/element'
import { Component} from 'typescript/component'
// install platform specific utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isRuntimeComponent = isRuntimeComponent
Vue.config.isUnknownElement = isUnknownElement
// install platform runtime directives and components
Vue.options.directives = platformDirectives
Vue.options.components = platformComponents
// install platform patch function
Vue.prototype.__patch__ = patch
// wrap mount
Vue.prototype.$mount = function (el?: any, hydrating?: boolean): Component {
return mountComponent(this, el && query(el, this.$document), hydrating)
}
export default Vue

View File

@ -1,40 +0,0 @@
import { extend } from 'shared/util'
import type { VNodeWithData } from 'typescript/vnode'
function updateAttrs(oldVnode: VNodeWithData, vnode: VNodeWithData) {
if (!oldVnode.data.attrs && !vnode.data.attrs) {
return
}
let key, cur, old
const elm = vnode.elm
const oldAttrs = oldVnode.data.attrs || {}
let attrs = vnode.data.attrs || {}
// clone observed objects, as the user probably wants to mutate it
if (attrs.__ob__) {
attrs = vnode.data.attrs = extend({}, attrs)
}
const supportBatchUpdate = typeof elm.setAttrs === 'function'
const batchedAttrs = {}
for (key in attrs) {
cur = attrs[key]
old = oldAttrs[key]
if (old !== cur) {
supportBatchUpdate ? (batchedAttrs[key] = cur) : elm.setAttr(key, cur)
}
}
for (key in oldAttrs) {
if (attrs[key] == null) {
supportBatchUpdate ? (batchedAttrs[key] = undefined) : elm.setAttr(key)
}
}
if (supportBatchUpdate) {
elm.setAttrs(batchedAttrs)
}
}
export default {
create: updateAttrs,
update: updateAttrs,
}

View File

@ -1,86 +0,0 @@
import { extend, isObject } from 'shared/util'
import type { Component } from 'typescript/component'
import type { VNodeData, VNodeWithData } from 'typescript/vnode'
function updateClass(oldVnode: VNodeWithData, vnode: VNodeWithData) {
const el = vnode.elm
const ctx = vnode.context
const data: VNodeData = vnode.data
const oldData: VNodeData = oldVnode.data
if (
!data.staticClass &&
!data.class &&
(!oldData || (!oldData.staticClass && !oldData.class))
) {
return
}
const oldClassList = makeClassList(oldData)
const classList = makeClassList(data)
if (typeof el.setClassList === 'function') {
el.setClassList(classList)
} else {
const style = getStyle(oldClassList, classList, ctx)
if (typeof el.setStyles === 'function') {
el.setStyles(style)
} else {
for (const key in style) {
el.setStyle(key, style[key])
}
}
}
}
function makeClassList(data: VNodeData): Array<string> {
const classList: any[] = []
// unlike web, weex vnode staticClass is an Array
const staticClass: any = data.staticClass
const dataClass = data.class
if (staticClass) {
classList.push.apply(classList, staticClass)
}
if (Array.isArray(dataClass)) {
classList.push.apply(classList, dataClass)
} else if (isObject(dataClass)) {
classList.push.apply(
classList,
Object.keys(dataClass).filter((className) => dataClass[className])
)
} else if (typeof dataClass === 'string') {
classList.push.apply(classList, dataClass.trim().split(/\s+/))
}
return classList
}
function getStyle(
oldClassList: Array<string>,
classList: Array<string>,
ctx: Component
): Object {
// style is a weex-only injected object
// compiled from <style> tags in weex files
//@ts-expect-error
const stylesheet: any = ctx.$options.style || {}
const result = {}
classList.forEach((name) => {
const style = stylesheet[name]
extend(result, style)
})
oldClassList.forEach((name) => {
const style = stylesheet[name]
for (const key in style) {
if (!result.hasOwnProperty(key)) {
result[key] = ''
}
}
})
return result
}
export default {
create: updateClass,
update: updateClass,
}

View File

@ -1,49 +0,0 @@
import { updateListeners } from 'core/vdom/helpers/update-listeners'
import type { VNodeWithData } from 'typescript/vnode'
let target: any
function createOnceHandler(event, handler, capture) {
const _target = target // save current target element in closure
return function onceHandler() {
const res = handler.apply(null, arguments)
if (res !== null) {
remove(event, onceHandler, capture, _target)
}
}
}
function add(
event: string,
handler: Function,
capture: boolean,
passive?: boolean,
params?: Array<any>
) {
if (capture) {
console.log('Weex do not support event in bubble phase.')
return
}
target.addEvent(event, handler, params)
}
function remove(event: string, handler: any, capture: any, _target?: any) {
(_target || target).removeEvent(event)
}
function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
if (!oldVnode.data.on && !vnode.data.on) {
return
}
const on = vnode.data.on || {}
const oldOn = oldVnode.data.on || {}
target = vnode.elm
updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)
target = undefined
}
export default {
create: updateDOMListeners,
update: updateDOMListeners,
}

View File

@ -1,7 +0,0 @@
import attrs from './attrs'
import klass from './class'
import events from './events'
import style from './style'
import transition from './transition'
export default [attrs, klass, events, style, transition]

View File

@ -1,84 +0,0 @@
import { extend, cached, camelize } from 'shared/util'
import type { VNodeWithData } from 'typescript/vnode'
const normalize = cached(camelize)
function createStyle(oldVnode: VNodeWithData, vnode: VNodeWithData) {
if (!vnode.data.staticStyle) {
updateStyle(oldVnode, vnode)
return
}
const elm = vnode.elm
const staticStyle = vnode.data.staticStyle
const supportBatchUpdate = typeof elm.setStyles === 'function'
const batchedStyles = {}
for (const name in staticStyle) {
if (staticStyle[name]) {
supportBatchUpdate
? (batchedStyles[normalize(name)] = staticStyle[name])
: elm.setStyle(normalize(name), staticStyle[name])
}
}
if (supportBatchUpdate) {
elm.setStyles(batchedStyles)
}
updateStyle(oldVnode, vnode)
}
function updateStyle(oldVnode: VNodeWithData, vnode: VNodeWithData) {
if (!oldVnode.data.style && !vnode.data.style) {
return
}
let cur, name
const elm = vnode.elm
const oldStyle: any = oldVnode.data.style || {}
let style: any = vnode.data.style || {}
const needClone = style.__ob__
// handle array syntax
if (Array.isArray(style)) {
style = vnode.data.style = toObject(style)
}
// clone the style for future updates,
// in case the user mutates the style object in-place.
if (needClone) {
style = vnode.data.style = extend({}, style)
}
const supportBatchUpdate = typeof elm.setStyles === 'function'
const batchedStyles = {}
for (name in oldStyle) {
if (!style[name]) {
supportBatchUpdate
? (batchedStyles[normalize(name)] = '')
: elm.setStyle(normalize(name), '')
}
}
for (name in style) {
cur = style[name]
supportBatchUpdate
? (batchedStyles[normalize(name)] = cur)
: elm.setStyle(normalize(name), cur)
}
if (supportBatchUpdate) {
elm.setStyles(batchedStyles)
}
}
function toObject(arr) {
const res = {}
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i])
}
}
return res
}
export default {
create: createStyle,
update: updateStyle,
}

View File

@ -1,310 +0,0 @@
import { warn } from 'core/util/debug'
import { extend, once, noop } from 'shared/util'
import { activeInstance } from 'core/instance/lifecycle'
import { resolveTransition } from 'web/runtime/transition-util'
export default {
create: enter,
activate: enter,
remove: leave,
}
function enter(_, vnode) {
const el = vnode.elm
// call leave callback now
if (el._leaveCb) {
el._leaveCb.cancelled = true
el._leaveCb()
}
const data = resolveTransition(vnode.data.transition)
if (!data) {
return
}
/* istanbul ignore if */
if (el._enterCb) {
return
}
const {
enterClass,
enterToClass,
enterActiveClass,
appearClass,
appearToClass,
appearActiveClass,
beforeEnter,
enter,
afterEnter,
enterCancelled,
beforeAppear,
appear,
afterAppear,
appearCancelled,
} = data
let context = activeInstance
let transitionNode = activeInstance.$vnode
while (transitionNode && transitionNode.parent) {
transitionNode = transitionNode.parent
context = transitionNode.context
}
const isAppear = !context._isMounted || !vnode.isRootInsert
if (isAppear && !appear && appear !== '') {
return
}
const startClass = isAppear ? appearClass : enterClass
const toClass = isAppear ? appearToClass : enterToClass
const activeClass = isAppear ? appearActiveClass : enterActiveClass
const beforeEnterHook = isAppear ? beforeAppear || beforeEnter : beforeEnter
const enterHook = isAppear
? typeof appear === 'function'
? appear
: enter
: enter
const afterEnterHook = isAppear ? afterAppear || afterEnter : afterEnter
const enterCancelledHook = isAppear
? appearCancelled || enterCancelled
: enterCancelled
const userWantsControl =
enterHook &&
// enterHook may be a bound method which exposes
// the length of original fn as _length
(enterHook._length || enterHook.length) > 1
const stylesheet = vnode.context.$options.style || {}
const startState = stylesheet[startClass]
const transitionProperties =
(stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][activeClass]) || {}
const endState = getEnterTargetState(
el,
stylesheet,
startClass,
toClass,
activeClass
)
const needAnimation = Object.keys(endState).length > 0
const cb = (el._enterCb = once(() => {
//@ts-expect-error
if (cb.cancelled) {
enterCancelledHook && enterCancelledHook(el)
} else {
afterEnterHook && afterEnterHook(el)
}
el._enterCb = null
}))
// We need to wait until the native element has been inserted, but currently
// there's no API to do that. So we have to wait "one frame" - not entirely
// sure if this is guaranteed to be enough (e.g. on slow devices?)
setTimeout(() => {
const parent = el.parentNode
const pendingNode = parent && parent._pending && parent._pending[vnode.key]
if (
pendingNode &&
pendingNode.context === vnode.context &&
pendingNode.tag === vnode.tag &&
pendingNode.elm._leaveCb
) {
pendingNode.elm._leaveCb()
}
enterHook && enterHook(el, cb)
if (needAnimation) {
const animation = vnode.context.$requireWeexModule('animation')
animation.transition(
el.ref,
{
styles: endState,
duration: transitionProperties.duration || 0,
delay: transitionProperties.delay || 0,
timingFunction: transitionProperties.timingFunction || 'linear',
},
userWantsControl ? noop : cb
)
} else if (!userWantsControl) {
cb()
}
}, 16)
// start enter transition
beforeEnterHook && beforeEnterHook(el)
if (startState) {
if (typeof el.setStyles === 'function') {
el.setStyles(startState)
} else {
for (const key in startState) {
el.setStyle(key, startState[key])
}
}
}
if (!needAnimation && !userWantsControl) {
cb()
}
}
function leave(vnode, rm) {
const el = vnode.elm
// call enter callback now
if (el._enterCb) {
el._enterCb.cancelled = true
el._enterCb()
}
const data = resolveTransition(vnode.data.transition)
if (!data) {
return rm()
}
if (el._leaveCb) {
return
}
const {
leaveClass,
leaveToClass,
leaveActiveClass,
beforeLeave,
leave,
afterLeave,
leaveCancelled,
delayLeave,
} = data
const userWantsControl =
leave &&
// leave hook may be a bound method which exposes
// the length of original fn as _length
(leave._length || leave.length) > 1
const stylesheet = vnode.context.$options.style || {}
const startState = stylesheet[leaveClass]
const endState = stylesheet[leaveToClass] || stylesheet[leaveActiveClass]
const transitionProperties =
(stylesheet['@TRANSITION'] &&
stylesheet['@TRANSITION'][leaveActiveClass]) ||
{}
const cb = (el._leaveCb = once(() => {
if (el.parentNode && el.parentNode._pending) {
el.parentNode._pending[vnode.key] = null
}
//@ts-expect-error
if (cb.cancelled) {
leaveCancelled && leaveCancelled(el)
} else {
rm()
afterLeave && afterLeave(el)
}
el._leaveCb = null
}))
if (delayLeave) {
delayLeave(performLeave)
} else {
performLeave()
}
function performLeave() {
const animation = vnode.context.$requireWeexModule('animation')
// the delayed leave may have already been cancelled
//@ts-expect-error
if (cb.cancelled) {
return
}
// record leaving element
if (!vnode.data.show) {
(el.parentNode._pending || (el.parentNode._pending = {}))[
vnode.key
] = vnode
}
beforeLeave && beforeLeave(el)
if (startState) {
animation.transition(
el.ref,
{
styles: startState,
},
next
)
} else {
next()
}
function next() {
animation.transition(
el.ref,
{
styles: endState,
duration: transitionProperties.duration || 0,
delay: transitionProperties.delay || 0,
timingFunction: transitionProperties.timingFunction || 'linear',
},
userWantsControl ? noop : cb
)
}
leave && leave(el, cb)
if (!endState && !userWantsControl) {
cb()
}
}
}
// determine the target animation style for an entering transition.
function getEnterTargetState(
el,
stylesheet,
startClass,
endClass,
activeClass
) {
const targetState = {}
const startState = stylesheet[startClass]
const endState = stylesheet[endClass]
const activeState = stylesheet[activeClass]
// 1. fallback to element's default styling
if (startState) {
for (const key in startState) {
targetState[key] = el.style[key]
if (
process.env.NODE_ENV !== 'production' &&
targetState[key] == null &&
(!activeState || activeState[key] == null) &&
(!endState || endState[key] == null)
) {
warn(
`transition property "${key}" is declared in enter starting class (.${startClass}), ` +
`but not declared anywhere in enter ending class (.${endClass}), ` +
`enter active cass (.${activeClass}) or the element's default styling. ` +
`Note in Weex, CSS properties need explicit values to be transitionable.`
)
}
}
}
// 2. if state is mixed in active state, extract them while excluding
// transition properties
if (activeState) {
for (const key in activeState) {
if (key.indexOf('transition') !== 0) {
targetState[key] = activeState[key]
}
}
}
// 3. explicit endState has highest priority
if (endState) {
extend(targetState, endState)
}
return targetState
}

View File

@ -1,94 +0,0 @@
declare let document: WeexDocument
import type { WeexDocument, WeexElement } from 'typescript/weex'
import TextNode from 'weex/runtime/text-node'
export const namespaceMap = {}
export function createElement(tagName: string): WeexElement {
return document.createElement(tagName)
}
export function createElementNS(
namespace: string,
tagName: string
): WeexElement {
return document.createElement(namespace + ':' + tagName)
}
export function createTextNode(text: string) {
return new TextNode(text)
}
export function createComment(text: string) {
return document.createComment(text)
}
export function insertBefore(
node: WeexElement,
target: WeexElement,
before: WeexElement
) {
if (target.nodeType === 3) {
if (node.type === 'text') {
node.setAttr('value', target.text)
target.parentNode = node
} else {
const text = createElement('text')
text.setAttr('value', target.text)
node.insertBefore(text, before)
}
return
}
node.insertBefore(target, before)
}
export function removeChild(node: WeexElement, child: WeexElement) {
if (child.nodeType === 3) {
node.setAttr('value', '')
return
}
node.removeChild(child)
}
export function appendChild(node: WeexElement, child: WeexElement) {
if (child.nodeType === 3) {
if (node.type === 'text') {
node.setAttr('value', child.text)
child.parentNode = node
} else {
const text = createElement('text')
text.setAttr('value', child.text)
node.appendChild(text)
}
return
}
node.appendChild(child)
}
export function parentNode(node: WeexElement): WeexElement | void {
return node.parentNode
}
export function nextSibling(node: WeexElement): WeexElement | void {
return node.nextSibling
}
export function tagName(node: WeexElement): string {
return node.type
}
export function setTextContent(node: WeexElement, text: string) {
if (node.parentNode) {
node.parentNode.setAttr('value', text)
}
}
export function setAttribute(node: WeexElement, key: string, val: any) {
node.setAttr(key, val)
}
export function setStyleScope(node: WeexElement, scopeId: string) {
node.setAttr('@styleScope', scopeId)
}

View File

@ -1,15 +0,0 @@
import * as nodeOps from 'weex/runtime/node-ops'
import { createPatchFunction } from 'core/vdom/patch'
import baseModules from 'core/vdom/modules/index'
import platformModules from 'weex/runtime/modules/index'
// the directive module should be applied last, after all
// built-in modules have been applied.
const modules = platformModules.concat(baseModules)
export const patch: Function = createPatchFunction({
nodeOps,
modules,
LONG_LIST_THRESHOLD: 10,
})

View File

@ -1,35 +0,0 @@
import { warn } from 'core/util/debug'
import { handleError } from 'core/util/error'
import { RECYCLE_LIST_MARKER } from 'weex/util/index'
import { createComponentInstanceForVnode } from 'core/vdom/create-component'
import { resolveVirtualComponent } from './virtual-component'
import type { MountedComponentVNode, VNodeWithData } from 'typescript/vnode'
import VNode from 'core/vdom/vnode'
export function isRecyclableComponent(vnode: VNodeWithData | VNode): boolean {
return vnode.data!.attrs ? RECYCLE_LIST_MARKER in vnode.data!.attrs : false
}
export function renderRecyclableComponentTemplate(
vnode: MountedComponentVNode | VNode
): VNode | undefined {
//@ts-expect-error
delete vnode.data.attrs[RECYCLE_LIST_MARKER]
resolveVirtualComponent(vnode)
const vm = createComponentInstanceForVnode(vnode)
const render = (vm.$options as any)['@render']
if (render) {
try {
return render.call(vm)
} catch (err:any) {
handleError(err, vm, `@render`)
}
} else {
warn(
`@render function not defined on component used in <recycle-list>. ` +
`Make sure to declare \`recyclable="true"\` on the component's template.`,
vm
)
}
}

View File

@ -1,142 +0,0 @@
// https://github.com/Hanks10100/weex-native-directive/tree/master/component
import { mergeOptions, isPlainObject, noop } from 'core/util/index'
import Watcher from 'core/observer/watcher'
import { initProxy } from 'core/instance/proxy'
import { initState, getData } from 'core/instance/state'
import { initRender } from 'core/instance/render'
import { initEvents } from 'core/instance/events'
import { initProvide, initInjections } from 'core/instance/inject'
import { initLifecycle, callHook } from 'core/instance/lifecycle'
import {
initInternalComponent,
resolveConstructorOptions,
} from 'core/instance/init'
import { registerComponentHook, updateComponentData } from '../../util/index'
import type { Component } from 'typescript/component'
import VNode from 'core/vdom/vnode'
import type { MountedComponentVNode } from 'typescript/vnode'
let uid = 0
// override Vue.prototype._init
function initVirtualComponent(options: Record<string, any> = {}) {
const vm: Component = this
const componentId = options.componentId
// virtual component uid
vm._uid = `virtual-component-${uid++}`
// a flag to avoid this being observed
vm._isVue = true
// merge options
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
//@ts-expect-error
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
//@ts-expect-error
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
initProxy(vm)
} else {
vm._renderProxy = vm
}
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
// send initial data to native
const data = vm.$options.data
const params = typeof data === 'function' ? getData(data, vm) : data || {}
if (isPlainObject(params)) {
updateComponentData(componentId, params)
}
registerComponentHook(componentId, 'lifecycle', 'attach', () => {
callHook(vm, 'beforeMount')
const updateComponent = () => {
vm._update(vm._vnode!, false)
}
new Watcher(vm, updateComponent, noop, null, true)
vm._isMounted = true
callHook(vm, 'mounted')
})
registerComponentHook(componentId, 'lifecycle', 'detach', () => {
vm.$destroy()
})
}
// override Vue.prototype._update
function updateVirtualComponent(vnode?: VNode) {
const vm: Component = this
const componentId = vm.$options.componentId
if (vm._isMounted) {
callHook(vm, 'beforeUpdate')
}
vm._vnode = vnode
if (vm._isMounted && componentId) {
// TODO: data should be filtered and without bindings
const data = Object.assign({}, vm._data)
updateComponentData(componentId, data, () => {
callHook(vm, 'updated')
})
}
}
// listening on native callback
export function resolveVirtualComponent(
vnode: MountedComponentVNode | VNode
): void {
const BaseCtor = vnode.componentOptions!.Ctor
const VirtualComponent = BaseCtor.extend({})
const cid = VirtualComponent.cid
VirtualComponent.prototype._init = initVirtualComponent
VirtualComponent.prototype._update = updateVirtualComponent
vnode.componentOptions!.Ctor = BaseCtor.extend({
beforeCreate() {
// const vm: Component = this
// TODO: listen on all events and dispatch them to the
// corresponding virtual components according to the componentId.
// vm._virtualComponents = {}
const createVirtualComponent = (componentId, propsData) => {
// create virtual component
// const subVm =
new VirtualComponent({
componentId,
propsData,
})
// if (vm._virtualComponents) {
// vm._virtualComponents[componentId] = subVm
// }
}
registerComponentHook(cid, 'lifecycle', 'create', createVirtualComponent)
},
beforeDestroy() {
delete this._virtualComponents
},
})
}

View File

@ -1,9 +0,0 @@
let latestNodeId = 1
export default function TextNode(text) {
this.instanceId = ''
this.nodeId = latestNodeId++
this.parentNode = null
this.nodeType = 3
this.text = text
}

View File

@ -1,7 +0,0 @@
import "core/config";
declare module "core/config" {
interface Config {
isRuntimeComponent: (key: string) => true | undefined;
}
}

View File

@ -1,48 +0,0 @@
// These util functions are split into its own file because Rollup cannot drop
// makeMap() due to potential side effects, so these variables end up
// bloating the web builds.
import { makeMap, noop } from "shared/util";
export const isReservedTag = makeMap(
"template,script,style,element,content,slot,link,meta,svg,view," +
"a,div,img,image,text,span,input,switch,textarea,spinner,select," +
"slider,slider-neighbor,indicator,canvas," +
"list,cell,header,loading,loading-indicator,refresh,scrollable,scroller," +
"video,web,embed,tabbar,tabheader,datepicker,timepicker,marquee,countdown",
true
);
// Elements that you can, intentionally, leave open (and which close themselves)
// more flexible than web
export const canBeLeftOpenTag = makeMap(
"web,spinner,switch,video,textarea,canvas," + "indicator,marquee,countdown",
true
);
export const isRuntimeComponent = makeMap(
"richtext,transition,transition-group",
true
);
export const isUnaryTag = makeMap("embed,img,image,input,link,meta", true);
export function mustUseProp(): boolean {
return false;
}
export function getTagNamespace() {
return undefined;
}
export function isUnknownElement(): boolean {
return false;
}
export function query(el: string | Element, document: any) {
// document is injected by weex factory wrapper
const placeholder = document.createComment("root");
placeholder.hasAttribute = placeholder.removeAttribute = noop; // hack for patch
document.documentElement.appendChild(placeholder);
return placeholder;
}

View File

@ -1,40 +0,0 @@
declare let document: WeexDocument
import { warn } from 'core/util/index'
import type { WeexDocument } from 'typescript/weex'
export const RECYCLE_LIST_MARKER = '@inRecycleList'
// Register the component hook to weex native render engine.
// The hook will be triggered by native, not javascript.
export function registerComponentHook(
componentId: string,
type: string, // hook type, could be "lifecycle" or "instance"
hook: string, // hook name
fn: Function
) {
if (!document || !document.taskCenter) {
warn(`Can't find available "document" or "taskCenter".`)
return
}
if (typeof document.taskCenter.registerHook === 'function') {
return document.taskCenter.registerHook(componentId, type, hook, fn)
}
warn(`Failed to register component hook "${type}@${hook}#${componentId}".`)
}
// Updates the state of the component to weex native render engine.
export function updateComponentData(
componentId: string,
newData: Object | void,
callback?: Function
) {
if (!document || !document.taskCenter) {
warn(`Can't find available "document" or "taskCenter".`)
return
}
if (typeof document.taskCenter.updateData === 'function') {
return document.taskCenter.updateData(componentId, newData, callback)
}
warn(`Failed to update component data (${componentId}).`)
}

View File

@ -1,60 +0,0 @@
// import { warn } from 'core/util/index'
import acorn from 'acorn'
import walk from "acorn-walk";
const escodegen = require("escodegen");
export function nodeToBinding(node: any): any {
switch (node.type) {
case "Literal":
return node.value;
case "Identifier":
case "UnaryExpression":
case "BinaryExpression":
case "LogicalExpression":
case "ConditionalExpression":
case "MemberExpression":
return { "@binding": escodegen.generate(node) };
case "ArrayExpression":
return node.elements.map((_) => nodeToBinding(_));
case "ObjectExpression": {
const object = {};
node.properties.forEach((prop) => {
if (!prop.key || prop.key.type !== "Identifier") {
return;
}
const key = escodegen.generate(prop.key);
const value = nodeToBinding(prop.value);
if (key && value) {
object[key] = value;
}
});
return object;
}
default: {
// warn(`Not support ${node.type}: "${escodegen.generate(node)}"`)
return "";
}
}
}
export function generateBinding(exp?: string): any {
if (exp && typeof exp === "string") {
let ast: acorn.Node| null = null;
try {
ast = acorn.parse(`(${exp})`, {ecmaVersion: 5});
} catch (e: any) {
// warn(`Failed to parse the expression: "${exp}"`)
return "";
}
let output = "";
walk.simple(ast, {
Expression(node) {
output = nodeToBinding(node);
},
});
return output;
}
}

View File

@ -1,5 +1,5 @@
;(global as any).__WEEX__ = false
;(global as any).__SSR_TEST__ = false
process.env.NEW_SLOT_SYNTAX = 'true'
import './helpers/shim-done'

View File

@ -1,238 +0,0 @@
import {
readFile,
readObject,
compileVue,
compileWithDeps,
createInstance,
addTaskHook,
resetTaskHook,
getRoot,
getEvents,
fireEvent
} from '../helpers'
// Create one-off render test case
function createRenderTestCase (name) {
const source = readFile(`${name}.vue`)
const target = readObject(`${name}.vdom.js`)
return done => {
compileVue(source).then(code => {
const id = String(Date.now() * Math.random())
const instance = createInstance(id, code)
setTimeout(() => {
expect(getRoot(instance)).toEqual(target)
instance.$destroy()
done()
}, 50)
}).catch(done.fail)
}
}
// Create event test case, will trigger the first bind event
function createEventTestCase (name) {
const source = readFile(`${name}.vue`)
const before = readObject(`${name}.before.vdom.js`)
const after = readObject(`${name}.after.vdom.js`)
return done => {
compileVue(source).then(code => {
const id = String(Date.now() * Math.random())
const instance = createInstance(id, code)
setTimeout(() => {
expect(getRoot(instance)).toEqual(before)
const event = getEvents(instance)[0]
fireEvent(instance, event.ref, event.type, {})
setTimeout(() => {
expect(getRoot(instance)).toEqual(after)
instance.$destroy()
done()
}, 50)
}, 50)
}).catch(done.fail)
}
}
describe('Usage', () => {
describe('render', () => {
it('sample', createRenderTestCase('render/sample'))
it('class', createRenderTestCase('render/class'))
})
describe('event', () => {
it('click', createEventTestCase('event/click'))
})
describe('recycle-list', () => {
it('text node', createRenderTestCase('recycle-list/text-node'))
it('attributes', createRenderTestCase('recycle-list/attrs'))
// it('class name', createRenderTestCase('recycle-list/classname'))
it('inline style', createRenderTestCase('recycle-list/inline-style'))
it('v-if', createRenderTestCase('recycle-list/v-if'))
it('v-else', createRenderTestCase('recycle-list/v-else'))
it('v-else-if', createRenderTestCase('recycle-list/v-else-if'))
it('v-for', createRenderTestCase('recycle-list/v-for'))
it('v-for-iterator', createRenderTestCase('recycle-list/v-for-iterator'))
it('v-on', createRenderTestCase('recycle-list/v-on'))
it('v-on-inline', createRenderTestCase('recycle-list/v-on-inline'))
it('v-once', createRenderTestCase('recycle-list/v-once'))
it('stateless component', done => {
compileWithDeps('recycle-list/components/stateless.vue', [{
name: 'banner',
path: 'recycle-list/components/banner.vue'
}]).then(code => {
const id = String(Date.now() * Math.random())
const instance = createInstance(id, code)
setTimeout(() => {
const target = readObject('recycle-list/components/stateless.vdom.js')
expect(getRoot(instance)).toEqual(target)
instance.$destroy()
done()
}, 50)
}).catch(done.fail)
})
it('stateless component with props', done => {
compileWithDeps('recycle-list/components/stateless-with-props.vue', [{
name: 'poster',
path: 'recycle-list/components/poster.vue'
}]).then(code => {
const id = String(Date.now() * Math.random())
const instance = createInstance(id, code)
setTimeout(() => {
const target = readObject('recycle-list/components/stateless-with-props.vdom.js')
expect(getRoot(instance)).toEqual(target)
instance.$destroy()
done()
}, 50)
}).catch(done.fail)
})
it('multi stateless components', done => {
compileWithDeps('recycle-list/components/stateless-multi-components.vue', [{
name: 'banner',
path: 'recycle-list/components/banner.vue'
}, {
name: 'poster',
path: 'recycle-list/components/poster.vue'
}, {
name: 'footer',
path: 'recycle-list/components/footer.vue'
}]).then(code => {
const id = String(Date.now() * Math.random())
const instance = createInstance(id, code)
setTimeout(() => {
const target = readObject('recycle-list/components/stateless-multi-components.vdom.js')
expect(getRoot(instance)).toEqual(target)
instance.$destroy()
done()
}, 50)
}).catch(done.fail)
})
it('stateful component', done => {
const tasks: any[] = []
addTaskHook((_, task) => tasks.push(task))
compileWithDeps('recycle-list/components/stateful.vue', [{
name: 'counter',
path: 'recycle-list/components/counter.vue'
}]).then(code => {
const id = String(Date.now() * Math.random())
const instance = createInstance(id, code)
// expect(tasks.length).toEqual(3)
setTimeout(() => {
// check the render results
const target = readObject('recycle-list/components/stateful.vdom.js')
expect(getRoot(instance)).toEqual(target)
tasks.length = 0
// // trigger component hooks
// instance.$triggerHook(
// 2, // cid of the virtual component template
// 'create', // lifecycle hook name
// // arguments for the callback
// [
// 'x-1', // componentId of the virtual component
// { start: 3 } // propsData of the virtual component
// ]
// )
// instance.$triggerHook(2, 'create', ['x-2', { start: 11 }])
// // the state (_data) of the virtual component should be sent to native
// expect(tasks.length).toEqual(2)
// expect(tasks[0].method).toEqual('updateComponentData')
// expect(tasks[0].args).toEqual(['x-1', { count: 6 }, ''])
// expect(tasks[1].method).toEqual('updateComponentData')
// expect(tasks[1].args).toEqual(['x-2', { count: 22 }, ''])
// instance.$triggerHook('x-1', 'attach')
// instance.$triggerHook('x-2', 'attach')
// tasks.length = 0
// // simulate a click event
// // the event will be caught by the virtual component template and
// // should be dispatched to virtual component according to the componentId
// const event = getEvents(instance)[0]
// fireEvent(instance, event.ref, 'click', { componentId: 'x-1' })
setTimeout(() => {
// expect(tasks.length).toEqual(1)
// expect(tasks[0].method).toEqual('updateComponentData')
// expect(tasks[0].args).toEqual([{ count: 7 }])
instance.$destroy()
resetTaskHook()
done()
})
}, 50)
}).catch(done.fail)
})
// it('component lifecycle', done => {
// global.__lifecycles = []
// compileWithDeps('recycle-list/components/stateful-lifecycle.vue', [{
// name: 'lifecycle',
// path: 'recycle-list/components/lifecycle.vue'
// }]).then(code => {
// const id = String(Date.now() * Math.random())
// const instance = createInstance(id, code)
// setTimeout(() => {
// const target = readObject('recycle-list/components/stateful-lifecycle.vdom.js')
// expect(getRoot(instance)).toEqual(target)
// instance.$triggerHook(2, 'create', ['y-1'])
// instance.$triggerHook('y-1', 'attach')
// instance.$triggerHook('y-1', 'detach')
// expect(global.__lifecycles).toEqual([
// 'beforeCreate undefined',
// 'created 0',
// 'beforeMount 1',
// 'mounted 1',
// 'beforeUpdate 2',
// 'updated 2',
// 'beforeDestroy 2',
// 'destroyed 2'
// ])
// delete global.__lifecycles
// instance.$destroy()
// done()
// }, 50)
// }).catch(done.fail)
// })
it('stateful component with v-model', done => {
compileWithDeps('recycle-list/components/stateful-v-model.vue', [{
name: 'editor',
path: 'recycle-list/components/editor.vue'
}]).then(code => {
const id = String(Date.now() * Math.random())
const instance = createInstance(id, code)
setTimeout(() => {
const target = readObject('recycle-list/components/stateful-v-model.vdom.js')
expect(getRoot(instance)).toEqual(target)
instance.$destroy()
done()
}, 50)
}).catch(done.fail)
})
})
})

View File

@ -1,10 +0,0 @@
({
type: 'div',
event: ['click'],
children: [{
type: 'text',
attr: {
value: '43'
}
}]
})

View File

@ -1,10 +0,0 @@
({
type: 'div',
event: ['click'],
children: [{
type: 'text',
attr: {
value: '42'
}
}]
})

View File

@ -1,20 +0,0 @@
<template>
<div @click="inc">
<text>{{count}}</text>
</div>
</template>
<script>
module.exports = {
data () {
return {
count: 42
}
},
methods: {
inc () {
this.count++
}
}
}
</script>

View File

@ -1,34 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A', count: 1, source: 'http://whatever.com/x.png' },
{ type: 'A', count: 2, source: 'http://whatever.com/y.png' },
{ type: 'A', count: 3, source: 'http://whatever.com/z.png' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
children: [{
type: 'image',
attr: {
resize: 'cover',
src: {
'@binding': 'item.source'
}
}
}, {
type: 'text',
attr: {
lines: '3',
count: {
'@binding': 'item.count'
}
}
}]
}]
})

View File

@ -1,23 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A">
<image resize="cover" :src="item.source">
<text lines="3" v-bind:count="item.count"></text>
</cell-slot>
</recycle-list>
</template>
<script>
module.exports = {
data () {
return {
longList: [
{ type: 'A', count: 1, source: 'http://whatever.com/x.png' },
{ type: 'A', count: 2, source: 'http://whatever.com/y.png' },
{ type: 'A', count: 3, source: 'http://whatever.com/z.png' }
]
}
}
}
</script>

View File

@ -1,27 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A', color: 'red' },
{ type: 'A', color: 'blue' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
style: {
backgroundColor: '#FF6600'
},
children: [{
type: 'text',
attr: {
// not supported yet
// classList: ['text', { '@binding': 'item.color' }],
value: 'content'
}
}]
}]
})

View File

@ -1,37 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A" class="cell">
<text :class="['text', item.color]">content</text>
</cell-slot>
</recycle-list>
</template>
<style scoped>
.cell {
background-color: #FF6600;
}
.text {
font-size: 100px;
text-align: center;
}
.red {
color: #FF0000;
}
.blue {
color: #0000FF;
}
</style>
<script>
module.exports = {
data () {
return {
longList: [
{ type: 'A', color: 'red' },
{ type: 'A', color: 'blue' }
]
}
}
}
</script>

View File

@ -1,19 +0,0 @@
<template recyclable="true">
<div class="banner">
<text class="title">BANNER</text>
</div>
</template>
<style scoped>
.banner {
height: 120px;
justify-content: center;
align-items: center;
background-color: rgb(162, 217, 192);
}
.title {
font-weight: bold;
color: #41B883;
font-size: 60px;
}
</style>

View File

@ -1,36 +0,0 @@
<template recyclable="true">
<div>
<text class="output">{{count}}</text>
<text class="button" @click="inc">+</text>
</div>
</template>
<script>
module.exports = {
props: ['start'],
data () {
return {
count: parseInt(this.start, 10) * 2 || 42
}
},
methods: {
inc () {
this.count++
}
}
}
</script>
<style scoped>
.output {
font-size: 150px;
text-align: center;
}
.button {
font-size: 100px;
text-align: center;
border-width: 2px;
border-color: #DDD;
background-color: #F5F5F5;
}
</style>

View File

@ -1,31 +0,0 @@
<template recyclable="true">
<div>
<text class="output">{{output}}</text>
<input class="input" type="text" v-model="output" />
</div>
</template>
<script>
module.exports = {
props: ['message'],
data () {
return {
output: this.message || ''
}
}
}
</script>
<style scoped>
.output {
height: 80px;
font-size: 60px;
color: #41B883;
}
.input {
font-size: 50px;
color: #666666;
border-width: 2px;
border-color: #41B883;
}
</style>

View File

@ -1,18 +0,0 @@
<template recyclable="true">
<div class="footer">
<text class="copyright">All rights reserved.</text>
</div>
</template>
<style scoped>
.footer {
height: 80px;
justify-content: center;
background-color: #EEEEEE;
}
.copyright {
color: #AAAAAA;
font-size: 32px;
text-align: center;
}
</style>

View File

@ -1,39 +0,0 @@
<template recyclable="true">
<div>
<text>{{number}}</text>
</div>
</template>
<script>
module.exports = {
data () {
return { number: 0 }
},
beforeCreate () {
try { __lifecycles.push('beforeCreate ' + this.number) } catch (e) {}
},
created () {
try { __lifecycles.push('created ' + this.number) } catch (e) {}
this.number++
},
beforeMount () {
try { __lifecycles.push('beforeMount ' + this.number) } catch (e) {}
},
mounted () {
try { __lifecycles.push('mounted ' + this.number) } catch (e) {}
this.number++
},
beforeUpdate () {
try { __lifecycles.push('beforeUpdate ' + this.number) } catch (e) {}
},
updated () {
try { __lifecycles.push('updated ' + this.number) } catch (e) {}
},
beforeDestroy () {
try { __lifecycles.push('beforeDestroy ' + this.number) } catch (e) {}
},
destroyed () {
try { __lifecycles.push('destroyed ' + this.number) } catch (e) {}
}
}
</script>

View File

@ -1,33 +0,0 @@
<template recyclable="true">
<div>
<image class="image" :src="imageUrl"></image>
<text class="title">{{title}}</text>
</div>
</template>
<script>
module.exports = {
props: {
imageUrl: {
type: String,
default: 'https://gw.alicdn.com/tfs/TB1KF_ybRTH8KJjy0FiXXcRsXXa-890-1186.png'
},
title: {
type: String,
default: 'I WANT YOU!'
}
}
}
</script>
<style scoped>
.image {
width: 750px;
height: 1000px;
}
.title {
font-size: 80px;
text-align: center;
color: #E95659;
}
</style>

View File

@ -1,29 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'X' },
{ type: 'X' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'X' },
children: [{
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {}
},
children: [{
type: 'text',
attr: {
value: { '@binding': 'number' }
}
}]
}]
}]
})

View File

@ -1,21 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="X">
<lifecycle></lifecycle>
</cell-slot>
</recycle-list>
</template>
<script>
// require('./lifecycle.vue')
module.exports = {
data () {
return {
longList: [
{ type: 'X' },
{ type: 'X' }
]
}
}
}
</script>

View File

@ -1,40 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A' },
{ type: 'A' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
children: [{
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {
message: 'No binding'
}
},
children: [{
type: 'text',
classList: ['output'],
attr: {
value: { '@binding': 'output' }
}
}, {
type: 'input',
event: ['input'],
classList: ['input'],
attr: {
type: 'text',
value: 'No binding'
}
}]
}]
}]
})

View File

@ -1,21 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A">
<editor message="No binding"></editor>
</cell-slot>
</recycle-list>
</template>
<script>
// require('./editor.vue')
module.exports = {
data () {
return {
longList: [
{ type: 'A' },
{ type: 'A' }
]
}
}
}
</script>

View File

@ -1,40 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A', number: 24 },
{ type: 'A', number: 42 }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
children: [{
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {
start: { '@binding': 'item.number' }
}
},
children: [{
type: 'text',
classList: ['output'],
attr: {
value: { '@binding': 'count' } // need confirm
}
}, {
type: 'text',
event: ['click'],
classList: ['button'],
attr: { value: '+' }
}]
}, {
type: 'text',
attr: { value: 'other' }
}]
}]
})

View File

@ -1,22 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A">
<counter :start="item.number"></counter>
<text>other</text>
</cell-slot>
</recycle-list>
</template>
<script>
// require('./counter.vue')
module.exports = {
data () {
return {
longList: [
{ type: 'A', number: 24 },
{ type: 'A', number: 42 }
]
}
}
}
</script>

View File

@ -1,83 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A' },
{ type: 'B', poster: 'yy', title: 'y' },
{ type: 'A' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
children: [{
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {}
},
classList: ['banner'],
children: [{
type: 'text',
classList: ['title'],
attr: { value: 'BANNER' }
}]
}, {
type: 'text',
attr: { value: '----' }
}, {
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {}
},
classList: ['footer'],
children: [{
type: 'text',
classList: ['copyright'],
attr: { value: 'All rights reserved.' }
}]
}]
}, {
type: 'cell-slot',
attr: { append: 'tree', case: 'B' },
children: [{
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {}
},
classList: ['banner'],
children: [{
type: 'text',
classList: ['title'],
attr: { value: 'BANNER' }
}]
}, {
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {
imageUrl: { '@binding': 'item.poster' },
title: { '@binding': 'item.title' }
}
},
children: [{
type: 'image',
classList: ['image'],
attr: {
src: { '@binding': 'imageUrl' }
}
}, {
type: 'text',
classList: ['title'],
attr: {
value: { '@binding': 'title' }
}
}]
}]
}]
})

View File

@ -1,30 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A">
<banner></banner>
<text>----</text>
<footer></footer>
</cell-slot>
<cell-slot case="B">
<banner></banner>
<poster :image-url="item.poster" :title="item.title"></poster>
</cell-slot>
</recycle-list>
</template>
<script>
// require('./banner.vue')
// require('./footer.vue')
// require('./poster.vue')
module.exports = {
data () {
return {
longList: [
{ type: 'A' },
{ type: 'B', poster: 'yy', title: 'y' },
{ type: 'A' }
]
}
}
}
</script>

View File

@ -1,44 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A', poster: 'xx', title: 'x' },
{ type: 'A', poster: 'yy', title: 'y' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
children: [{
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {
imageUrl: { '@binding': 'item.poster' },
title: { '@binding': 'item.title' }
}
},
children: [{
type: 'image',
classList: ['image'],
attr: {
src: { '@binding': 'imageUrl' }
}
}, {
type: 'text',
classList: ['title'],
attr: {
value: { '@binding': 'title' }
}
}]
}, {
type: 'text',
attr: {
value: 'content'
}
}]
}]
})

View File

@ -1,22 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A">
<poster :image-url="item.poster" :title="item.title"></poster>
<text>content</text>
</cell-slot>
</recycle-list>
</template>
<script>
// require('./poster.vue')
module.exports = {
data () {
return {
longList: [
{ type: 'A', poster: 'xx', title: 'x' },
{ type: 'A', poster: 'yy', title: 'y' }
]
}
}
}
</script>

View File

@ -1,36 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A' },
{ type: 'A' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
children: [{
type: 'div',
attr: {
'@isComponentRoot': true,
'@componentProps': {}
},
classList: ['banner'],
children: [{
type: 'text',
classList: ['title'],
attr: {
value: 'BANNER'
}
}]
}, {
type: 'text',
attr: {
value: 'content'
}
}]
}]
})

View File

@ -1,22 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A">
<banner></banner>
<text>content</text>
</cell-slot>
</recycle-list>
</template>
<script>
// require('./banner.vue')
module.exports = {
data () {
return {
longList: [
{ type: 'A' },
{ type: 'A' }
]
}
}
}
</script>

View File

@ -1,29 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A', color: '#606060' },
{ type: 'A', color: '#E5E5E5' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
style: {
backgroundColor: '#FF6600'
},
children: [{
type: 'text',
style: {
fontSize: '100px',
color: { '@binding': 'item.color' }
},
attr: {
value: 'content'
}
}]
}]
})

View File

@ -1,21 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A" style="background-color:#FF6600">
<text :style="{ fontSize: '100px', color: item.color }">content</text>
</cell-slot>
</recycle-list>
</template>
<script>
module.exports = {
data () {
return {
longList: [
{ type: 'A', color: '#606060' },
{ type: 'A', color: '#E5E5E5' }
]
}
}
}
</script>

View File

@ -1,38 +0,0 @@
({
type: 'recycle-list',
attr: {
append: 'tree',
listData: [
{ type: 'A', dynamic: 'decimal', two: '2', four: '4' },
{ type: 'A', dynamic: 'binary', two: '10', four: '100' }
],
switch: 'type',
alias: 'item'
},
children: [{
type: 'cell-slot',
attr: { append: 'tree', case: 'A' },
children: [{
type: 'text',
attr: {
value: 'static'
}
}, {
type: 'text',
attr: {
value: { '@binding': 'item.dynamic' }
}
}, {
type: 'text',
attr: {
value: [
'one ',
{ '@binding': 'item.two' },
' three ',
{ '@binding': 'item.four' },
' five'
]
}
}]
}]
})

View File

@ -1,23 +0,0 @@
<template>
<recycle-list for="item in longList" switch="type">
<cell-slot case="A">
<text>static</text>
<text>{{item.dynamic}}</text>
<text>one {{item.two}} three {{ item.four }} five</text>
</cell-slot>
</recycle-list>
</template>
<script>
module.exports = {
data () {
return {
longList: [
{ type: 'A', dynamic: 'decimal', two: '2', four: '4' },
{ type: 'A', dynamic: 'binary', two: '10', four: '100' }
]
}
}
}
</script>

Some files were not shown because too many files have changed in this diff Show More