├── .eslintrc
├── .gitignore
├── demo
├── .browserslistrc
├── public
│ ├── robots.txt
│ ├── favicon.ico
│ ├── img
│ │ └── icons
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── mstile-150x150.png
│ │ │ ├── apple-touch-icon.png
│ │ │ ├── android-chrome-192x192.png
│ │ │ ├── android-chrome-512x512.png
│ │ │ ├── apple-touch-icon-120x120.png
│ │ │ ├── apple-touch-icon-152x152.png
│ │ │ ├── apple-touch-icon-180x180.png
│ │ │ ├── apple-touch-icon-60x60.png
│ │ │ ├── apple-touch-icon-76x76.png
│ │ │ ├── msapplication-icon-144x144.png
│ │ │ └── safari-pinned-tab.svg
│ ├── manifest.json
│ └── index.html
├── babel.config.js
├── postcss.config.js
├── src
│ ├── shims-vue.d.ts
│ ├── assets
│ │ └── demo-print.png
│ ├── store.ts
│ ├── router.ts
│ ├── main.ts
│ ├── shims-tsx.d.ts
│ ├── components
│ │ ├── Editor.vue
│ │ └── Presets.vue
│ ├── App.vue
│ ├── registerServiceWorker.ts
│ ├── utils
│ │ └── presets.ts
│ └── views
│ │ └── Home.vue
├── vue.config.js
├── .editorconfig
├── .gitignore
├── .eslintrc.js
├── README.md
├── tsconfig.json
└── package.json
├── src
├── index.ts
├── SvelteComponent.ts
├── Compiler.ts
└── TemplateCompiler.ts
├── test
├── output
│ ├── static.svelte
│ └── simple.svelte
└── index.spec.ts
├── jest.config.js
├── tsconfig.json
├── tslint.json
├── release-it.json
├── webpack.config.js
├── LICENSE
├── .circleci
└── config.yml
├── package.json
└── README.md
/.eslintrc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist/*
3 |
--------------------------------------------------------------------------------
/demo/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/demo/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { ComponentCompiler as default } from './Compiler'
2 |
--------------------------------------------------------------------------------
/test/output/static.svelte:
--------------------------------------------------------------------------------
1 | I am just
2 | STATIC
--------------------------------------------------------------------------------
/demo/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'ts-jest',
3 | testEnvironment: 'node',
4 | };
--------------------------------------------------------------------------------
/demo/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/demo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/favicon.ico
--------------------------------------------------------------------------------
/demo/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
5 |
--------------------------------------------------------------------------------
/demo/src/assets/demo-print.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/src/assets/demo-print.png
--------------------------------------------------------------------------------
/demo/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | configureWebpack: {
3 | node: {
4 | module: 'empty'
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/demo/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/demo/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/demo/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/demo/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/demo/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/demo/public/img/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/demo/public/img/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/demo/public/img/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/demo/public/img/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/demo/public/img/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/demo/public/img/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/demo/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/demo/public/img/icons/msapplication-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trickstival/vue2svelte/HEAD/demo/public/img/icons/msapplication-icon-144x144.png
--------------------------------------------------------------------------------
/test/output/simple.svelte:
--------------------------------------------------------------------------------
1 |
{#if heyProp==='ai'}sup {heyProp} {/if} plp {heyProp} {hey}
--------------------------------------------------------------------------------
/demo/src/store.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | export default new Vuex.Store({
7 | state: {
8 |
9 | },
10 | mutations: {
11 |
12 | },
13 | actions: {
14 |
15 | }
16 | })
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "./dist/",
4 | "noImplicitAny": true,
5 | "module": "es6",
6 | "moduleResolution": "node",
7 | "target": "es5",
8 | "sourceMap": true,
9 | "declaration": true
10 | }
11 | }
--------------------------------------------------------------------------------
/demo/src/router.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Home from './views/Home.vue'
4 |
5 | Vue.use(Router)
6 |
7 | export default new Router({
8 | routes: [
9 | {
10 | path: '/',
11 | name: 'home',
12 | component: Home
13 | }
14 | ]
15 | })
16 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/demo/src/main.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store'
5 | import './registerServiceWorker'
6 | import 'prismjs'
7 | import 'prismjs/themes/prism.css'
8 |
9 | Vue.config.productionTip = false
10 |
11 | new Vue({
12 | router,
13 | store,
14 | render: h => h(App)
15 | }).$mount('#app')
16 |
--------------------------------------------------------------------------------
/demo/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue'
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended"
5 | ],
6 | "jsRules": {},
7 | "rules": {
8 | "semicolon": [true, "never"],
9 | "space-before-function-paren": [true, "always"],
10 | "quotemark": [true, "single"],
11 | "interface-name": false
12 | },
13 | "rulesDirectory": []
14 | }
--------------------------------------------------------------------------------
/release-it.json:
--------------------------------------------------------------------------------
1 | {
2 | "src": {
3 | "tagName": "v%s",
4 | "commitMessage": "chore(release): %s"
5 | },
6 | "github": {
7 | "release": true,
8 | "releaseName": "🚀 Release %s",
9 | "tokenRef": "GITHUB_TOKEN"
10 | },
11 | "npm": {
12 | "publish": true
13 | },
14 | "changelogCommand": "git log --pretty=format:'* %s (%h)' [REV_RANGE]"
15 | }
--------------------------------------------------------------------------------
/demo/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | '@vue/standard',
9 | '@vue/typescript'
10 | ],
11 | rules: {
12 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
14 | },
15 | parserOptions: {
16 | parser: '@typescript-eslint/parser'
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.ts',
5 | devtool: 'inline-source-map',
6 | module: {
7 | rules: [
8 | {
9 | test: /\.ts$/,
10 | use: 'ts-loader',
11 | exclude: /node_modules/
12 | }
13 | ]
14 | },
15 | resolve: {
16 | extensions: [ '.ts', '.js' ]
17 | },
18 | output: {
19 | filename: 'bundle.js',
20 | path: path.resolve(__dirname, 'dist')
21 | }
22 | }
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # demo
2 |
3 | ## Project setup
4 | ```
5 | yarn install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | yarn run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | yarn run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | yarn run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | yarn run lint
26 | ```
27 |
28 | ### Customize configuration
29 | See [Configuration Reference](https://cli.vuejs.org/config/).
30 |
--------------------------------------------------------------------------------
/demo/src/components/Editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
21 |
22 |
27 |
--------------------------------------------------------------------------------
/demo/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "short_name": "demo",
4 | "icons": [
5 | {
6 | "src": "./img/icons/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./img/icons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "start_url": "./index.html",
17 | "display": "standalone",
18 | "background_color": "#000000",
19 | "theme_color": "#4DBA87"
20 | }
21 |
--------------------------------------------------------------------------------
/demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Vue2Svelte Demo
9 |
10 |
11 |
12 | We're sorry but demo doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/demo/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
32 |
--------------------------------------------------------------------------------
/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "jsx": "preserve",
6 | "importHelpers": true,
7 | "moduleResolution": "node",
8 | "experimentalDecorators": true,
9 | "esModuleInterop": true,
10 | "allowSyntheticDefaultImports": true,
11 | "sourceMap": true,
12 | "baseUrl": ".",
13 | "types": [
14 | "webpack-env"
15 | ],
16 | "paths": {
17 | "@/*": [
18 | "src/*"
19 | ]
20 | },
21 | "lib": [
22 | "esnext",
23 | "dom",
24 | "dom.iterable",
25 | "scripthost"
26 | ]
27 | },
28 | "include": [
29 | "src/**/*.ts",
30 | "src/**/*.tsx",
31 | "src/**/*.vue",
32 | "tests/**/*.ts",
33 | "tests/**/*.tsx"
34 | ],
35 | "exclude": [
36 | "node_modules"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/demo/src/components/Presets.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Select a Preset
5 |
6 |
7 |
13 | {{ key }}
14 |
15 |
16 |
17 |
18 |
19 |
28 |
29 |
42 |
--------------------------------------------------------------------------------
/demo/src/registerServiceWorker.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { register } from 'register-service-worker'
4 |
5 | if (process.env.NODE_ENV === 'production') {
6 | register(`${process.env.BASE_URL}service-worker.js`, {
7 | ready () {
8 | console.log(
9 | 'App is being served from cache by a service worker.\n' +
10 | 'For more details, visit https://goo.gl/AFskqB'
11 | )
12 | },
13 | registered () {
14 | console.log('Service worker has been registered.')
15 | },
16 | cached () {
17 | console.log('Content has been cached for offline use.')
18 | },
19 | updatefound () {
20 | console.log('New content is downloading.')
21 | },
22 | updated () {
23 | console.log('New content is available; please refresh.')
24 | },
25 | offline () {
26 | console.log('No internet connection found. App is running in offline mode.')
27 | },
28 | error (error) {
29 | console.error('Error during service worker registration:', error)
30 | }
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "version": "0.1.1",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^2.6.5",
12 | "prismjs": "^1.17.1",
13 | "register-service-worker": "^1.6.2",
14 | "vue": "^2.6.10",
15 | "vue-class-component": "^7.0.2",
16 | "vue-property-decorator": "^8.1.0",
17 | "vue-router": "^3.0.3",
18 | "vuex": "^3.0.1"
19 | },
20 | "devDependencies": {
21 | "@vue/cli-plugin-babel": "^3.9.0",
22 | "@vue/cli-plugin-eslint": "^3.9.0",
23 | "@vue/cli-plugin-pwa": "^3.9.0",
24 | "@vue/cli-plugin-typescript": "^3.9.0",
25 | "@vue/cli-service": "^3.9.0",
26 | "@vue/eslint-config-standard": "^4.0.0",
27 | "@vue/eslint-config-typescript": "^4.0.0",
28 | "babel-eslint": "^10.0.1",
29 | "eslint": "^5.16.0",
30 | "eslint-plugin-vue": "^5.0.0",
31 | "node-sass": "^4.9.0",
32 | "sass-loader": "^7.1.0",
33 | "typescript": "^3.4.3",
34 | "vue-template-compiler": "^2.6.10"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2019 Patrick Stival Chaerke
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Javascript Node CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | - image: circleci/node:8.10
11 |
12 | # Specify service dependencies here if necessary
13 | # CircleCI maintains a library of pre-built images
14 | # documented at https://circleci.com/docs/2.0/circleci-images/
15 | # - image: circleci/mongo:3.4.4
16 |
17 | working_directory: ~/repo
18 |
19 | steps:
20 | - checkout
21 |
22 | # Download and cache dependencies
23 | - restore_cache:
24 | keys:
25 | - v1-dependencies-{{ checksum "package.json" }}
26 | # fallback to using the latest cache if no exact match is found
27 | - v1-dependencies-
28 |
29 | - run: yarn install
30 |
31 | - save_cache:
32 | paths:
33 | - node_modules
34 | key: v1-dependencies-{{ checksum "package.json" }}
35 |
36 | - run: yarn lint
37 | # run tests!
38 | - run: yarn test:unit
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue2svelte",
3 | "version": "0.0.11",
4 | "description": "A Vue SFC to Svelte Transpiler",
5 | "main": "dist/index.js",
6 | "author": "trickstival",
7 | "repository": {
8 | "url": "https://github.com/trickstival/vue2svelte"
9 | },
10 | "license": "MIT",
11 | "files": [
12 | "dist"
13 | ],
14 | "scripts": {
15 | "test:unit": "jest",
16 | "lint": "tslint -c tslint.json 'src/**/*.ts'",
17 | "dev": "jest --watchAll",
18 | "build": "webpack --mode=production"
19 | },
20 | "types": "dist/src/index.d.ts",
21 | "devDependencies": {
22 | "@types/jest": "^24.0.15",
23 | "jest": "^24.8.0",
24 | "ts-jest": "^24.0.2",
25 | "ts-loader": "^6.0.4",
26 | "tslint": "^5.18.0",
27 | "typescript": "^3.5.2",
28 | "vue-template-compiler": "^2.6.10",
29 | "webpack": "^4.35.2",
30 | "webpack-cli": "^3.3.5"
31 | },
32 | "dependencies": {
33 | "prismjs": "^1.17.1",
34 | "svelte": "^3.6.2",
35 | "vue": "^2.6.10",
36 | "vue-prism-editor": "^0.2.1"
37 | },
38 | "keywords": [
39 | "vue",
40 | "svelte",
41 | "compiler",
42 | "transpiler",
43 | "transform"
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/src/SvelteComponent.ts:
--------------------------------------------------------------------------------
1 | // This is an intermediary entity between vue and svelte
2 |
3 | export interface SvelteProp {
4 | name: string
5 | default: any
6 | }
7 |
8 | export interface SvelteData {
9 | name: string,
10 | initialValue: any,
11 |
12 | }
13 |
14 | export default class SvelteComponent {
15 | private props: SvelteProp[]
16 | private data: SvelteData[]
17 | private template: string
18 |
19 | constructor () {
20 | this.props = []
21 | this.data = []
22 | }
23 | public setTemplate (template: string) {
24 | this.template = template
25 | }
26 | public addProp (prop: SvelteProp) {
27 | this.props.push(prop)
28 | }
29 | public addData (data: SvelteData) {
30 | this.data.push(data)
31 | }
32 | public getCode () {
33 | const propsCode = this.props
34 | .map((prop) => `export let ${prop.name}=${JSON.stringify(prop.default)};`)
35 | .join('\n')
36 |
37 | const dataCode = this.data
38 | .map((data) => `let ${data.name}=${JSON.stringify(data.initialValue)};`)
39 | .join('\n')
40 |
41 | return `${this.template}`
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/demo/src/utils/presets.ts:
--------------------------------------------------------------------------------
1 | interface Preset {
2 | script: string
3 | template: string
4 | }
5 |
6 | const presets: Record = {
7 | default: {
8 | template: `
9 |
10 |
`,
11 | script: `{
12 | props: {
13 | prop1: {
14 | default: 'yeeah Im a prop'
15 | }
16 | },
17 | data() {
18 | return {
19 | data1: 'Just normal data'
20 | }
21 | }
22 | }`
23 | },
24 | 'v-if and v-else': {
25 | template: `
26 |
never gonna be shown
27 |
data1 shows
28 |
just v-else
29 |
`,
30 | script: `{
31 | props: {
32 | prop1: {
33 | default: 'yeeah Im a prop'
34 | }
35 | },
36 | data() {
37 | return {
38 | data1: 'Just normal data'
39 | }
40 | }
41 | }`
42 | },
43 | 'v-for': {
44 | template: `
45 |
{{ idx }} {{ name }}
46 | `,
47 | script: `{
48 | data () {
49 | return {
50 | list: [{ name: 'Bob' }, { name: 'Dylan' }]
51 | }
52 | }
53 | }`
54 | },
55 | 'print data': {
56 | template: `
57 | Printing prop: {{ prop1 }}
58 |
`,
59 | script: `{
60 | props: {
61 | prop1: {
62 | default: 'yeeah Im a prop'
63 | }
64 | }
65 | }`
66 | }
67 | }
68 |
69 | export default presets
70 |
--------------------------------------------------------------------------------
/test/index.spec.ts:
--------------------------------------------------------------------------------
1 | import Vue, { ComponentOptions, CreateElement } from 'vue';
2 | import { ComponentCompiler } from '../src/Compiler';
3 | import * as fs from 'fs'
4 |
5 | const getOutput = (filename: string) => fs.readFileSync(__dirname + `/output/${filename}.svelte`, 'utf-8')
6 | const compile = (options: ComponentOptions) => new ComponentCompiler(options).compile()
7 |
8 | describe('The Compiler', () => {
9 | it('Static html rendering', () => {
10 | const myComponent: ComponentOptions = {
11 | template: 'I am just \nSTATIC '
12 | }
13 |
14 | const result = compile(myComponent)
15 | const expected = getOutput('static')
16 | expect(result).toBe(expected)
17 | })
18 | it('Simple v-if and props compiling', () => {
19 | const myComponent: ComponentOptions = {
20 | template: `sup {{ heyProp }} plp {{ heyProp }} {{ hey }} `,
21 | props: {
22 | heyProp: {
23 | default: 'Im a prop'
24 | }
25 | },
26 | data () {
27 | return {
28 |
29 | hey: 'Im hey data'
30 | }
31 | }
32 | }
33 |
34 | const compiler = new ComponentCompiler(myComponent)
35 | const result = compiler.compile()
36 | const expected = getOutput('simple')
37 | expect(result).toBe(expected)
38 | })
39 | })
--------------------------------------------------------------------------------
/src/Compiler.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import { ComponentOptions } from 'vue/types/options'
3 | import SvelteComponent, { SvelteData, SvelteProp } from './SvelteComponent'
4 | import TemplateCompiler from './TemplateCompiler'
5 |
6 | export class ComponentCompiler> {
7 | public vm: T
8 | public svelteComponent: SvelteComponent
9 | constructor (vm: T) {
10 | this.vm = vm
11 | this.svelteComponent = new SvelteComponent()
12 | }
13 |
14 | public compile (): string {
15 | this.mapProps()
16 | this.mapData()
17 | this.svelteComponent.setTemplate(new TemplateCompiler(this.vm).compile())
18 | return this.svelteComponent.getCode()
19 | }
20 |
21 | public mapProps () {
22 | const props = this.vm.props || {}
23 | for (const [vuePropKey, vueProp = {}] of Object.entries(props)) {
24 | const svelteProp: SvelteProp = {
25 | default: vueProp.default,
26 | name: vuePropKey,
27 | }
28 | this.svelteComponent.addProp(svelteProp)
29 | }
30 | }
31 |
32 | public mapData () {
33 | let data = this.vm.data || {}
34 | data = typeof data === 'function'
35 | ? data()
36 | : data
37 |
38 | for (const [vueDataKey, vueData = {}] of Object.entries(data)) {
39 | const svelteData: SvelteData = {
40 | initialValue: vueData,
41 | name: vueDataKey,
42 | }
43 | this.svelteComponent.addData(svelteData)
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vue2Svelte
2 |
3 | [Demo](https://blissful-goldstine-5db493.netlify.com)
4 | [](https://blissful-goldstine-5db493.netlify.com)
5 |
6 | Still under development and there's still a long way to go :o
7 |
8 | ## Install
9 |
10 | ```bash
11 | npm i vue2svelte
12 | # or
13 | yarn add vue2svelte
14 | ```
15 |
16 | ## Main Goal
17 |
18 | Get a Vue options object and convert it into a svelte component
19 |
20 | Compiler Roadmap:
21 |
22 | - [x] Simple HTML elements rendering
23 | - [x] Default props values
24 | - [x] Simple properties declaration
25 | - [x] v-if statements
26 | - [x] v-else and v-else-if statements
27 | - [x] v-for statements
28 | - [ ] v-once statements
29 | - [ ] v-model support
30 | - [x] v-bind:prop / :prop support
31 | - [ ] v-bind="obj" support
32 | - [ ] Methods
33 | - [ ] Computed properties
34 | - [ ] Mixins
35 | - [ ] Lifecycle hooks
36 | - [ ] Calls to $nextTick
37 | - [ ] Filters
38 | - [ ] Calls to $options
39 |
40 | ...
41 |
42 | ## Usage
43 |
44 | ```js
45 | import Vue2Svelte from 'vue2svelte'
46 |
47 | const VueComponent = {
48 | template: `{{ item }}
`,
49 | props: {
50 | list: {
51 | default: ['item 1', 'item 2']
52 | }
53 | },
54 | data () {
55 | return {
56 | hello: 'world'
57 | }
58 | }
59 | }
60 |
61 | const SvelteComponent = new Vue2Svelte(VueComponent)
62 |
63 | console.log(SvelteComponent.compile())
64 | // Output: {#each list as item}{item} {/each}
65 |
66 | ```
67 |
68 | Currently it can compile simple pure components with props and data.
69 |
70 | This project is a little bit complex, so if you can help please do it!
71 |
--------------------------------------------------------------------------------
/demo/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Vue2Svelte demo
4 |
5 |
6 |
7 | Template
8 |
13 | Script
14 |
19 |
20 |
21 |
22 | Svelte Result
23 |
24 |
25 | {{ svelteCode }}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
84 |
99 |
--------------------------------------------------------------------------------
/src/TemplateCompiler.ts:
--------------------------------------------------------------------------------
1 | import { ComponentOptions } from 'vue'
2 | import * as Compiler from 'vue-template-compiler'
3 | import { Vue } from 'vue/types/vue'
4 |
5 | const FromTypes = {
6 | isASTElement (T: Compiler.ASTNode): T is Compiler.ASTElement {
7 | return T.type === 1
8 | },
9 | isASTExpression (T: Compiler.ASTNode): T is Compiler.ASTExpression {
10 | return T.type === 2
11 | },
12 | isASTText (T: Compiler.ASTNode): T is Compiler.ASTText {
13 | return T.type === 3
14 | },
15 | }
16 |
17 | export default class TemplateCompiler {
18 | private rawTemplate: string
19 | private compiledVueTemplate: Compiler.CompiledResult
20 | constructor (options: ComponentOptions) {
21 | this.rawTemplate = options.template
22 | // @ts-ignore
23 | this.compiledVueTemplate = Compiler.compile(this.rawTemplate, options)
24 | }
25 | public compile (ast = this.compiledVueTemplate.ast) {
26 | const children = ast.children.map((astChild) => this.compileNode(astChild)).join('')
27 | return `<${ast.tag}>${children}${ast.tag}>`
28 | }
29 | private compileAttrs (node: Compiler.ASTElement): string {
30 | if (!node.attrs) {
31 | return ''
32 | }
33 | return node.attrs.map((attr) => {
34 | // "dynamic" property is not mapped by vue-template-compiler declaration files.
35 | // maybe opening an issue is the right thing to do, but I think it's moving to ts anyway.
36 | // @ts-ignore
37 | if (attr.dynamic !== undefined) {
38 | return `${attr.name}={${attr.value}}`
39 | }
40 | return `${attr.name}=${attr.value}`
41 | }).join(' ')
42 | }
43 | private compileSurroundings (node: Compiler.ASTElement, template: string) {
44 | // Compile ifs and elses
45 | if (node.if) {
46 | const [, ...elses] = node.ifConditions
47 | const elsesTemplate = elses.map((elseItem) => {
48 | const block = this.compileNode(elseItem.block)
49 | if (elseItem.exp) {
50 | return `{:else if ${elseItem.exp}} ${block}`
51 | }
52 | return `{:else} ${block}`
53 | }).join('')
54 | template = `{#if ${node.if}}${template}${elsesTemplate}{/if}`
55 | }
56 | // Compile for
57 | if (node.for) {
58 | // I think Svelte only supports one iterator
59 | let alias = node.alias
60 | if (node.iterator1) {
61 | alias += `, ${node.iterator1}`
62 | }
63 | template = `{#each ${node.for} as ${alias}}${template}{/each}`
64 | }
65 | return template
66 | }
67 | private compileNode (node: Compiler.ASTNode) {
68 | if (FromTypes.isASTText(node)) {
69 | return node.text
70 | }
71 | if (FromTypes.isASTExpression(node)) {
72 | return node.tokens.map((token) => {
73 | if (typeof token === 'string') {
74 | return token
75 | }
76 | return `{${token['@binding']}}`
77 | }).join('')
78 | }
79 | if (FromTypes.isASTElement(node)) {
80 | const compileChildren = (): string => node.children
81 | .map((child) => this.compileNode(child))
82 | .join('\n')
83 |
84 | const attrs = this.compileAttrs(node)
85 |
86 | const trailingAttrs = attrs ? ' ' + attrs : ''
87 | const childrenOrEmpty = node.children ? compileChildren() : ''
88 |
89 | let currentTemplate = `<${node.tag + trailingAttrs}>${childrenOrEmpty}${node.tag}>`
90 |
91 | currentTemplate = this.compileSurroundings(node, currentTemplate)
92 |
93 | return currentTemplate
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/demo/public/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.11, written by Peter Selinger 2001-2013
9 |
10 |
12 |
148 |
149 |
150 |
--------------------------------------------------------------------------------