From ef85221563bdfcdd37402f46097f7e585a79f154 Mon Sep 17 00:00:00 2001 From: Nick Messing Date: Wed, 8 Jan 2020 10:38:39 +0200 Subject: [PATCH] init --- .gitignore | 1 + lerna.json | 8 + package.json | 10 + .../package.json | 24 + .../src/babel-traverse-shims.d.ts | 8 + .../src/index.ts | 18 + .../src/shims.d.ts | 17 + .../src/transforms.ts | 176 + .../src/types.ts | 91 + .../src/utils.ts | 217 + .../tsconfig.json | 15 + .../yarn-error.log | 174 + .../babel-plugin-transform-vue-jsx/yarn.lock | 116 + .../babel-sugar-functional-vue/package.json | 15 + .../babel-sugar-functional-vue/src/index.ts | 94 + .../babel-sugar-functional-vue/src/shims.d.ts | 6 + .../babel-sugar-functional-vue/tsconfig.json | 15 + packages/babel-sugar-functional-vue/yarn.lock | 82 + packages/jsx-explorer/.editorconfig | 5 + packages/jsx-explorer/.gitignore | 21 + packages/jsx-explorer/README.md | 24 + packages/jsx-explorer/babel.config.js | 5 + packages/jsx-explorer/package.json | 69 + packages/jsx-explorer/public/favicon.ico | Bin 0 -> 4286 bytes packages/jsx-explorer/public/index.html | 17 + packages/jsx-explorer/src/App.vue | 194 + .../jsx-explorer/src/components/Editor.vue | 57 + .../jsx-explorer/src/components/Frame.vue | 60 + .../jsx-explorer/src/components/Header.vue | 69 + packages/jsx-explorer/src/main.ts | 8 + packages/jsx-explorer/src/shims-tsx.d.ts | 13 + packages/jsx-explorer/src/shims-vue.d.ts | 4 + packages/jsx-explorer/tsconfig.json | 39 + packages/jsx-explorer/vue.config.js | 3 + packages/jsx-explorer/yarn.lock | 9030 +++++++++++++++++ yarn.lock | 4808 +++++++++ 36 files changed, 15513 insertions(+) create mode 100644 .gitignore create mode 100644 lerna.json create mode 100644 package.json create mode 100644 packages/babel-plugin-transform-vue-jsx/package.json create mode 100644 packages/babel-plugin-transform-vue-jsx/src/babel-traverse-shims.d.ts create mode 100644 packages/babel-plugin-transform-vue-jsx/src/index.ts create mode 100644 packages/babel-plugin-transform-vue-jsx/src/shims.d.ts create mode 100644 packages/babel-plugin-transform-vue-jsx/src/transforms.ts create mode 100644 packages/babel-plugin-transform-vue-jsx/src/types.ts create mode 100644 packages/babel-plugin-transform-vue-jsx/src/utils.ts create mode 100644 packages/babel-plugin-transform-vue-jsx/tsconfig.json create mode 100644 packages/babel-plugin-transform-vue-jsx/yarn-error.log create mode 100644 packages/babel-plugin-transform-vue-jsx/yarn.lock create mode 100644 packages/babel-sugar-functional-vue/package.json create mode 100644 packages/babel-sugar-functional-vue/src/index.ts create mode 100644 packages/babel-sugar-functional-vue/src/shims.d.ts create mode 100644 packages/babel-sugar-functional-vue/tsconfig.json create mode 100644 packages/babel-sugar-functional-vue/yarn.lock create mode 100644 packages/jsx-explorer/.editorconfig create mode 100644 packages/jsx-explorer/.gitignore create mode 100644 packages/jsx-explorer/README.md create mode 100644 packages/jsx-explorer/babel.config.js create mode 100644 packages/jsx-explorer/package.json create mode 100644 packages/jsx-explorer/public/favicon.ico create mode 100644 packages/jsx-explorer/public/index.html create mode 100644 packages/jsx-explorer/src/App.vue create mode 100644 packages/jsx-explorer/src/components/Editor.vue create mode 100644 packages/jsx-explorer/src/components/Frame.vue create mode 100644 packages/jsx-explorer/src/components/Header.vue create mode 100644 packages/jsx-explorer/src/main.ts create mode 100644 packages/jsx-explorer/src/shims-tsx.d.ts create mode 100644 packages/jsx-explorer/src/shims-vue.d.ts create mode 100644 packages/jsx-explorer/tsconfig.json create mode 100644 packages/jsx-explorer/vue.config.js create mode 100644 packages/jsx-explorer/yarn.lock create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/lerna.json b/lerna.json new file mode 100644 index 0000000..8e0a097 --- /dev/null +++ b/lerna.json @@ -0,0 +1,8 @@ +{ + "packages": [ + "packages/*" + ], + "npmClient": "yarn", + "useWorkspaces": true, + "version": "0.0.0" +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b0f56bc --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "root", + "private": true, + "devDependencies": { + "lerna": "^3.18.4" + }, + "dependencies": { + "lodash.debounce": "^4.0.8" + } +} diff --git a/packages/babel-plugin-transform-vue-jsx/package.json b/packages/babel-plugin-transform-vue-jsx/package.json new file mode 100644 index 0000000..8578eea --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/package.json @@ -0,0 +1,24 @@ +{ + "name": "@vue/babel-plugin-transform-vue-jsx", + "version": "1.0.0", + "description": "Babel plugin for Vue 2.0 JSX", + "main": "dist/index.js", + "repository": "https://github.com/vuejs/jsx/tree/master/packages/babel-plugin-transform-vue-jsx", + "author": "Evan You", + "license": "MIT", + "private": false, + "dependencies": { + "@babel/helper-module-imports": "^7.7.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "html-tags": "^3.1.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0", + "typescript": "^3.7.2" + }, + "devDependencies": { + "@babel/types": "^7.7.2", + "@types/babel__core": "^7.1.3", + "@types/babel__traverse": "^7.0.7", + "@types/lodash.kebabcase": "^4.1.6" + } +} diff --git a/packages/babel-plugin-transform-vue-jsx/src/babel-traverse-shims.d.ts b/packages/babel-plugin-transform-vue-jsx/src/babel-traverse-shims.d.ts new file mode 100644 index 0000000..ef40b3a --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/src/babel-traverse-shims.d.ts @@ -0,0 +1,8 @@ +import { NodePath } from '@babel/traverse' +import * as t from "@babel/types"; + +declare module '@babel/traverse' { + export interface NodePath { + isJSXSpreadChild(opts?: object): this is NodePath; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-vue-jsx/src/index.ts b/packages/babel-plugin-transform-vue-jsx/src/index.ts new file mode 100644 index 0000000..e49cb5c --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/src/index.ts @@ -0,0 +1,18 @@ +import { PluginObj } from '@babel/core' + +import syntaxJsx from '@babel/plugin-syntax-jsx' +import { transformJSXElement } from './transforms' + +const plugin: PluginObj = { + name: 'babel-plugin-transform-vue-js', + inherits: syntaxJsx, + visitor: { + JSXElement: { + exit(path) { + path.replaceWith(transformJSXElement(path)) + } + } + } +} + +export default plugin \ No newline at end of file diff --git a/packages/babel-plugin-transform-vue-jsx/src/shims.d.ts b/packages/babel-plugin-transform-vue-jsx/src/shims.d.ts new file mode 100644 index 0000000..83ac3d2 --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/src/shims.d.ts @@ -0,0 +1,17 @@ +declare module '@babel/plugin-syntax-jsx' { + import { PluginObj } from '@babel/core' + + const syntaxJsx: PluginObj + export default syntaxJsx +} + +declare module 'svg-tags' { + const svgTags: readonly string[] + export default svgTags +} + +declare module '@babel/helper-module-imports' { + import { NodePath } from '@babel/core' + import { Identifier } from '@babel/types' + const addDefault: (path: NodePath, importedSource: string, opts?: { nameHint?: string }) => Identifier +} diff --git a/packages/babel-plugin-transform-vue-jsx/src/transforms.ts b/packages/babel-plugin-transform-vue-jsx/src/transforms.ts new file mode 100644 index 0000000..1140fad --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/src/transforms.ts @@ -0,0 +1,176 @@ +import { NodePath } from '@babel/core'; +import { JSXElement, callExpression, identifier, JSXText, stringLiteral, JSXExpressionContainer, isJSXEmptyExpression, JSXSpreadChild, spreadElement, JSXMemberExpression, MemberExpression, nullLiteral, memberExpression, JSXAttribute, JSXSpreadAttribute, Node, isJSXIdentifier, booleanLiteral, isIdentifier, isStringLiteral, isExpression } from '@babel/types'; +import { hCallArguments, getJSXAttributeName, getJSXAttributeValue, notEmpty, } from './utils'; +import { ParsedAttribute, SpreadAttribute, ParsedAttributeType, isRootAttributeKey, RootAttribute, isRootPrefixKey, rootPrefixKeys, RootPrefixKey, RootAttributeKey } from './types'; + +export const directiveMatchRE = /^v[-A-Z]/ +export const directiveReplaceRE = /^v-?/ + +export const transformJSXAttribute = (path: NodePath): ParsedAttribute => { + let name = getJSXAttributeName(path) + const value = getJSXAttributeValue(path) || booleanLiteral(true) + if (name === 'class' && isStringLiteral(value)) { + return { + type: ParsedAttributeType.Root, + key: RootAttributeKey.StaticClass, + value + } + } + if (isRootAttributeKey(name)) { + return { + type: ParsedAttributeType.Root, + key: name, + value + } + } else if (isRootPrefixKey(name)) { + return { + type: ParsedAttributeType.PrefixGroup, + prefix: name, + value + } + } else if (name.match(directiveMatchRE)) { + const rawName = name + const [nameWithArgument, ...modifiers] = name.split('_') + const [justName, argument] = nameWithArgument.split(':') + name = justName.replace(directiveReplaceRE, '') + name = name[0].toLowerCase() + name.substr(1) + return { + type: ParsedAttributeType.Directive, + rawName, + name, + value, + modifiers, + argument + } + } else { + const prefix = rootPrefixKeys.find(el => name.startsWith(el)) || RootPrefixKey.Attrs + if (name.startsWith(prefix)) { + name = name.replace(new RegExp(`^${prefix}\-?`), '') + name = name[0].toLowerCase() + name.substr(1) + } + return { + type: ParsedAttributeType.PrefixSimple, + prefix, + name, + value + } + } +} + +export const transformJSXSpreadAttribute = (path: NodePath): ParsedAttribute[] => { + const defaultResult: SpreadAttribute = { + type: ParsedAttributeType.Spread, + value: path.node.argument + } + const argument = path.get('argument') + if (argument.isObjectExpression()) { + const properties = argument.get('properties') + const result = [] as ParsedAttribute[] + + for (let property of properties) { + if (property.isSpreadElement()) { + result.push({ + type: ParsedAttributeType.Spread, + value: property.node.argument + }) + } else if (property.isObjectProperty()) { + const { key, value } = property.node + + let name = '' + if (isIdentifier(key)) { + name = key.name + } else if (isStringLiteral(key)) { + name = key.value + } + + if (name && !name.startsWith('on') && !name.startsWith('nativeOn') && isRootPrefixKey(name) && isExpression(value)) { + result.push({ + type: ParsedAttributeType.PrefixGroup, + prefix: name, + value + }) + } else { + return [defaultResult] + } + } else { + return [defaultResult] + } + } + return result + } + return [defaultResult] +} + +export const transformAttribute = (path: NodePath): ParsedAttribute[] => + path.isJSXAttribute() + ? [transformJSXAttribute(path)] + : transformJSXSpreadAttribute(path as NodePath) + +export const transformJSXText = (path: NodePath) => { + const node = path.node + const lines = node.value.split(/\r\n|\n|\r/) + + let lastNonEmptyLine = 0 + + for (let i = 0; i < lines.length; i++) { + if (lines[i].match(/[^ \t]/)) { + lastNonEmptyLine = i + } + } + + let str = '' + + for (let i = 0; i < lines.length; i++) { + const line = lines[i] + + const isFirstLine = i === 0 + const isLastLine = i === lines.length - 1 + const isLastNonEmptyLine = i === lastNonEmptyLine + + // replace rendered whitespace tabs with spaces + let trimmedLine = line.replace(/\t/g, ' ') + + // trim whitespace touching a newline + if (!isFirstLine) { + trimmedLine = trimmedLine.replace(/^[ ]+/, '') + } + + // trim whitespace touching an endline + if (!isLastLine) { + trimmedLine = trimmedLine.replace(/[ ]+$/, '') + } + + if (trimmedLine) { + if (!isLastNonEmptyLine) { + trimmedLine += ' ' + } + + str += trimmedLine + } + } + + return str !== '' ? stringLiteral(str) : null +} + +export const transformJSXMemberExpression = (path: NodePath): MemberExpression => { + const objectPath = path.get('object') + const propertyPath = path.get('property') + const transformedObject = objectPath.isJSXMemberExpression() + ? transformJSXMemberExpression(objectPath) + : objectPath.isJSXIdentifier() + ? identifier(objectPath.node.name) + : nullLiteral() + const transformedProperty = identifier(propertyPath.node.name) + return memberExpression(transformedObject, transformedProperty) +} + +export const transformJSXExpressionContainer = (path: NodePath) => { + const expression = path.node.expression + return isJSXEmptyExpression(expression) ? null : expression +} + +export const transformJSXSpreadChild = (path: NodePath) => spreadElement(path.node.expression) + +export const transformJSXElement = (path: NodePath) => { + return callExpression(identifier('h'), hCallArguments(path)) +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-vue-jsx/src/types.ts b/packages/babel-plugin-transform-vue-jsx/src/types.ts new file mode 100644 index 0000000..fffb18d --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/src/types.ts @@ -0,0 +1,91 @@ +import { Expression, isExpression } from '@babel/types'; + +export enum RootAttributeKey { + StaticClass = 'staticClass', + Class = 'class', + Style = 'style', + Key = 'key', + Ref = 'ref', + RefInFor = 'refInFor', + Slot = 'slot', + ScopedSlots = 'scopedSlots', + Model = 'model' +} +export enum RootPrefixKey { + Props = 'props', + DomProps = 'domProps', + On = 'on', + NativeOn = 'nativeOn', + Hook = 'hook', + Attrs = 'attrs', +} + +export const toArryJoin: RootPrefixKey[] = [RootPrefixKey.On, RootPrefixKey.NativeOn] + +export enum ParsedAttributeType { + Spread = 'spread', + Root = 'root', + PrefixSimple = 'prefix-simple', + PrefixGroup = 'prefix-group', + Directive = 'directive' +} + +export interface AttributeBase { + value: Expression +} +export interface NamedAttributeBase extends AttributeBase { + name: string +} +export interface DirectiveAttribute extends NamedAttributeBase { + type: ParsedAttributeType.Directive + rawName: string + argument: string + modifiers: string[] +} +export interface SimplePrefixAttribute extends NamedAttributeBase { + type: ParsedAttributeType.PrefixSimple + prefix: RootPrefixKey +} +export interface GroupPrefixAttribute extends AttributeBase { + type: ParsedAttributeType.PrefixGroup + prefix: RootPrefixKey +} +export interface SpreadAttribute extends AttributeBase { + type: ParsedAttributeType.Spread +} +export interface RootAttribute extends AttributeBase { + type: ParsedAttributeType.Root + key: RootAttributeKey +} +export type OptimizedAttribute = SpreadAttribute | VNodeOptions +export type ParsedAttribute = SimplePrefixAttribute | GroupPrefixAttribute | SpreadAttribute | RootAttribute | DirectiveAttribute + +export type VNodeOptionsRoot = { [key in RootAttributeKey]?: Expression } +export type VNodeOptionsPrefix = { [key in RootPrefixKey]?: VNodeOptionsPrefixValue[] } +export type VNodeOptionsPrefixValue = NamedAttributeBase | Expression +export type VNodeOptions = { type: 'VNodeOptions', directives: DirectiveAttribute[] } & VNodeOptionsRoot & VNodeOptionsPrefix + +export const rootAttributeKeys = Object.values(RootAttributeKey) +export const rootPrefixKeys = Object.values(RootPrefixKey) + +export const isRootAttributeKey = (key: string): key is RootAttributeKey => + rootAttributeKeys.includes(key as RootAttributeKey) +export const isRootPrefixKey = (key: string): key is RootPrefixKey => + rootPrefixKeys.includes(key as RootPrefixKey) + +export const isRootAttribute = (attribute: ParsedAttribute): attribute is RootAttribute => + attribute.type === ParsedAttributeType.Root +export const isSpreadAttribute = (attribute: ParsedAttribute | OptimizedAttribute): attribute is SpreadAttribute => + attribute.type === ParsedAttributeType.Spread +export const isSimplePrefixAttribute = (attribute: ParsedAttribute): attribute is SimplePrefixAttribute => + attribute.type === ParsedAttributeType.PrefixSimple +export const isGroupPrefixAttribute = (attribute: ParsedAttribute): attribute is GroupPrefixAttribute => + attribute.type === ParsedAttributeType.PrefixGroup +export const isDirectiveAttribute = (attribute: ParsedAttribute): attribute is DirectiveAttribute => + attribute.type === ParsedAttributeType.Directive + +export const isNamedAttribute = (attribute: VNodeOptionsPrefixValue): attribute is NamedAttributeBase => + attribute.hasOwnProperty('name') && attribute.hasOwnProperty('value') && !isExpression(attribute) + +export const isVNodeOptions = (attr: OptimizedAttribute): attr is VNodeOptions => + attr.type === 'VNodeOptions' diff --git a/packages/babel-plugin-transform-vue-jsx/src/utils.ts b/packages/babel-plugin-transform-vue-jsx/src/utils.ts new file mode 100644 index 0000000..565774d --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/src/utils.ts @@ -0,0 +1,217 @@ +import { NodePath } from '@babel/core'; +import { addDefault } from '@babel/helper-module-imports' +import htmlTags from 'html-tags' +import svgTags from 'svg-tags' +import { JSXElement, Expression, isJSXIdentifier, stringLiteral, isJSXMemberExpression, identifier, arrayExpression, CallExpression, JSXAttribute, spreadElement, objectExpression, objectProperty, callExpression, booleanLiteral, isStringLiteral, StringLiteral, isArrayExpression } from '@babel/types'; +import { transformJSXText, transformJSXExpressionContainer, transformJSXSpreadChild, transformJSXElement, transformJSXMemberExpression, transformAttribute } from './transforms'; +import { ParsedAttribute, OptimizedAttribute, isSpreadAttribute, isSimplePrefixAttribute, isVNodeOptions, VNodeOptions, VNodeOptionsPrefixValue, isGroupPrefixAttribute, rootAttributeKeys, rootPrefixKeys, RootPrefixKey, isNamedAttribute, isDirectiveAttribute, DirectiveAttribute, toArryJoin } from './types' + +export function notEmpty(value: TValue | null | undefined): value is TValue { + return value !== null && value !== undefined; +} + +export const getTag = (path: NodePath) => { + const namePath = path.get('openingElement').get('name') + if (namePath.isJSXIdentifier()) { + const name = namePath.node.name + if (path.scope.hasBinding(name) && !htmlTags.includes(name) && !svgTags.includes(name)) { + return identifier(name) + } else { + return stringLiteral(name) + } + } + + if (namePath.isJSXMemberExpression()) { + return transformJSXMemberExpression(namePath) + } + /* istanbul ignore next */ + throw new Error(`getTag: ${namePath.type} is not supported`) +} + +export const getChildren = (path: NodePath) => + path + .get('children') + .map(path => { + if (path.isJSXText()) { + return transformJSXText(path) + } + if (path.isJSXExpressionContainer()) { + return transformJSXExpressionContainer(path) + } + if (path.isJSXSpreadChild()) { + return transformJSXSpreadChild(path) + } + if (path.isJSXElement()) { + return transformJSXElement(path) + } + if (path.isCallExpression()) { + return path.node as CallExpression + } + throw new Error(`getChildren: ${path.type} is not supported`) + }) + .filter(notEmpty) + +export const optimizeAttributes = (list: OptimizedAttribute[], element: ParsedAttribute) => { + if (isSpreadAttribute(element)) { + list.push(element) + } else { + if (list.length === 0 || !isVNodeOptions(list[list.length - 1])) { + list.push({ type: 'VNodeOptions', directives: [] }) + } + const opts = list[list.length - 1] as VNodeOptions + if (isSimplePrefixAttribute(element)) { + const { prefix, name, value } = element + if (!opts[prefix]) { + opts[prefix] = [] + } + const list = opts[prefix] as VNodeOptionsPrefixValue[] + list.push({ name, value }) + } else if (isGroupPrefixAttribute(element)) { + const { prefix, value } = element + if (!opts[prefix]) { + opts[prefix] = [] + } + const list = opts[prefix] as VNodeOptionsPrefixValue[] + list.push(value) + } else if (isDirectiveAttribute(element)) { + opts.directives.push(element) + } else { + const { key, value } = element + const option = opts[key] + if (option && key === 'staticClass' && isStringLiteral(value) && isStringLiteral(option)) { + option.value = `${option.value} ${value.value}` + + } else { + opts[key] = value + } + } + } + return list +} + +export const reduceVNodeOptionsPrefixValues = + (key: RootPrefixKey) => + (list: VNodeOptionsPrefixValue[], value: VNodeOptionsPrefixValue): VNodeOptionsPrefixValue[] => + toArryJoin.includes(key) && isNamedAttribute(value) && list.find(el => isNamedAttribute(el) && el.name === value.name) + ? list.map(el => + isNamedAttribute(el) && el.name === value.name + ? isArrayExpression(el.value) + ? { name: el.name, value: arrayExpression([...el.value.elements, value.value]) } + : { name: el.name, value: arrayExpression([el.value, value.value]) } + : el + ) + : [...list, value] + +export const buildPrefixAttribute = (key: RootPrefixKey, values: VNodeOptionsPrefixValue[]) => { + if (values.length === 1 && !isNamedAttribute(values[0])) { + return values[0] + } + return objectExpression( + values + .reduce(reduceVNodeOptionsPrefixValues(key), []) + .map(value => + isNamedAttribute(value) + ? objectProperty(stringLiteral(value.name), value.value) + : spreadElement(value) + ) + ) +} + +export const generateDirective = (directive: DirectiveAttribute) => + objectExpression([ + objectProperty(stringLiteral('name'), stringLiteral(directive.name)), + objectProperty(stringLiteral('rawName'), stringLiteral(directive.rawName)), + objectProperty(stringLiteral('value'), directive.value), + ( + directive.argument + ? objectProperty(stringLiteral('arg'), stringLiteral(directive.argument)) + : null + ), + ( + directive.modifiers.length > 0 + ? objectProperty( + stringLiteral('modifiers'), + objectExpression( + directive.modifiers.map(modifier => + objectProperty(stringLiteral(modifier), booleanLiteral(true)) + ) + ) + ) + : null + ), + ].filter(notEmpty)) + +export const buildAttributeExpression = (attribute: OptimizedAttribute) => { + if (isSpreadAttribute(attribute)) { + return attribute.value + } else { + return objectExpression([ + ...rootAttributeKeys.map(key => + attribute[key] + ? objectProperty(stringLiteral(key), attribute[key] as Expression) + : null + ).filter(notEmpty), + ...rootPrefixKeys.map(key => + attribute[key] + ? objectProperty(stringLiteral(key), buildPrefixAttribute(key, attribute[key] as VNodeOptionsPrefixValue[])) + : null + ).filter(notEmpty), + ( + attribute.directives.length > 0 + ? objectProperty(stringLiteral('directives'), arrayExpression(attribute.directives.map(generateDirective))) + : null + ) + ].filter(notEmpty)) + } +} + +export const buildAttributes = (path: NodePath, attributes: ParsedAttribute[]) => { + const builtAttributes = attributes.reduce(optimizeAttributes, [] as OptimizedAttribute[]).map(buildAttributeExpression) + if (builtAttributes.length > 1) { + const helper = addDefault(path, '@vue/babel-helper-vue-jsx-merge-props', { nameHint: '_mergeJSXProps' }) + return callExpression(helper, builtAttributes) + } else if (builtAttributes.length === 1) { + return builtAttributes[0] + } else { + return null + } +} + +export const getAttributes = (path: NodePath) => + buildAttributes(path, path.get('openingElement').get('attributes').map(transformAttribute).flat().filter(notEmpty)) + +export const getJSXAttributeName = (path: NodePath) => { + const nameNode = path.node.name + if (isJSXIdentifier(nameNode)) { + return nameNode.name + } else { + return `${nameNode.namespace.name}:${nameNode.name.name}` + } +} + +export const getJSXAttributeValue = (path: NodePath) => { + const valuePath = path.get('value') + if (valuePath.isJSXElement()) { + return transformJSXElement(valuePath) + } else if (valuePath.isStringLiteral()) { + return valuePath.node + } else if (valuePath.isJSXExpressionContainer()) { + return transformJSXExpressionContainer(valuePath) + } else { + return null + } +} + +export const hCallArguments = (path: NodePath) => { + const args: Expression[] = [getTag(path)] + const attributes = getAttributes(path) + const children = getChildren(path) + if (attributes) { + // console.log(attributes) + args.push(attributes) + } + if (children.length) { + args.push(arrayExpression(children)) + } + return args +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-vue-jsx/tsconfig.json b/packages/babel-plugin-transform-vue-jsx/tsconfig.json new file mode 100644 index 0000000..74f3f8e --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "lib": [ + "esnext" + ], + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "outDir": "./dist", + "strictNullChecks": true, + "noImplicitAny": true, + "esModuleInterop": true + }, + "include" : ["src/*.ts"] +} diff --git a/packages/babel-plugin-transform-vue-jsx/yarn-error.log b/packages/babel-plugin-transform-vue-jsx/yarn-error.log new file mode 100644 index 0000000..0d5aff4 --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/yarn-error.log @@ -0,0 +1,174 @@ +Arguments: + /home/nickmessing/.nvm/versions/node/v12.10.0/bin/node /home/nickmessing/.yarn/bin/yarn.js add @types/babel__helper-module-imports -D + +PATH: + /home/nickmessing/.yarn/bin:/home/nickmessing/.config/yarn/global/node_modules/.bin:/home/nickmessing/.nvm/versions/node/v12.10.0/bin:/home/nickmessing/.local/bin:/home/nickmessing/bin:/usr/share/Modules/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin + +Yarn version: + 1.19.1 + +Node version: + 12.10.0 + +Platform: + linux x64 + +Trace: + Error: https://registry.yarnpkg.com/@types%2fbabel__helper-module-imports: Not found + at Request.params.callback [as _callback] (/home/nickmessing/.yarn/lib/cli.js:66926:18) + at Request.self.callback (/home/nickmessing/.yarn/lib/cli.js:140564:22) + at Request.emit (events.js:209:13) + at Request. (/home/nickmessing/.yarn/lib/cli.js:141536:10) + at Request.emit (events.js:209:13) + at IncomingMessage. (/home/nickmessing/.yarn/lib/cli.js:141458:12) + at Object.onceWrapper (events.js:298:28) + at IncomingMessage.emit (events.js:214:15) + at endReadableNT (_stream_readable.js:1178:12) + at processTicksAndRejections (internal/process/task_queues.js:80:21) + +npm manifest: + { + "name": "@vue/babel-plugin-transform-vue-jsx", + "version": "1.0.0", + "description": "Babel plugin for Vue 2.0 JSX", + "main": "dist/index.js", + "repository": "https://github.com/vuejs/jsx/tree/master/packages/babel-plugin-transform-vue-jsx", + "author": "Evan You", + "license": "MIT", + "private": false, + "dependencies": { + "@babel/helper-module-imports": "^7.7.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "html-tags": "^3.1.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0", + "typescript": "^3.7.2" + }, + "devDependencies": { + "@babel/types": "^7.7.2", + "@types/babel__core": "^7.1.3", + "@types/babel__traverse": "^7.0.7", + "@types/lodash.kebabcase": "^4.1.6" + } + } + +yarn manifest: + No manifest + +Lockfile: + # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + # yarn lockfile v1 + + + "@babel/helper-module-imports@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.0.tgz#99c095889466e5f7b6d66d98dffc58baaf42654d" + integrity sha512-Dv3hLKIC1jyfTkClvyEkYP2OlkzNvWs5+Q8WgPbxM5LMeorons7iPP91JM+DU7tRbhqA1ZeooPaMFvQrn23RHw== + dependencies: + "@babel/types" "^7.7.0" + + "@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + + "@babel/parser@^7.1.0": + version "7.7.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.3.tgz#5fad457c2529de476a248f75b0f090b3060af043" + integrity sha512-bqv+iCo9i+uLVbI0ILzKkvMorqxouI+GbV13ivcARXn9NNEabi2IEz912IgNpT/60BNXac5dgcfjb94NjsF33A== + + "@babel/plugin-syntax-jsx@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz#0b85a3b4bc7cdf4cc4b8bf236335b907ca22e7c7" + integrity sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + + "@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.7.0", "@babel/types@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.2.tgz#550b82e5571dcd174af576e23f0adba7ffc683f7" + integrity sha512-YTf6PXoh3+eZgRCBzzP25Bugd2ngmpQVrk7kXX0i5N9BO7TFBtIgZYs7WtxtOGs8e6A4ZI7ECkbBCEHeXocvOA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + + "@types/babel__core@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30" + integrity sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + + "@types/babel__generator@*": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.0.tgz#f1ec1c104d1bb463556ecb724018ab788d0c172a" + integrity sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw== + dependencies: + "@babel/types" "^7.0.0" + + "@types/babel__template@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" + integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + + "@types/babel__traverse@*", "@types/babel__traverse@^7.0.7": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.7.tgz#2496e9ff56196cc1429c72034e07eab6121b6f3f" + integrity sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw== + dependencies: + "@babel/types" "^7.3.0" + + "@types/lodash.kebabcase@^4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/lodash.kebabcase/-/lodash.kebabcase-4.1.6.tgz#07b07aeca6c0647836de46f87a3cdfff72166c8e" + integrity sha512-+RAD9pCAa8kuVyCYTeDNiwBXwD/0u0p+hos3NSqD+tXTjJextbfF3farfYB+ssAKgEssoewXEtBsfwBpsI7gsA== + dependencies: + "@types/lodash" "*" + + "@types/lodash@*": + version "4.14.149" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" + integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== + + esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + + html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== + + lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= + + lodash@^4.17.13: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + + svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= + + to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + + typescript@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb" + integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ== diff --git a/packages/babel-plugin-transform-vue-jsx/yarn.lock b/packages/babel-plugin-transform-vue-jsx/yarn.lock new file mode 100644 index 0000000..65276bc --- /dev/null +++ b/packages/babel-plugin-transform-vue-jsx/yarn.lock @@ -0,0 +1,116 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/helper-module-imports@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.0.tgz#99c095889466e5f7b6d66d98dffc58baaf42654d" + integrity sha512-Dv3hLKIC1jyfTkClvyEkYP2OlkzNvWs5+Q8WgPbxM5LMeorons7iPP91JM+DU7tRbhqA1ZeooPaMFvQrn23RHw== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + +"@babel/parser@^7.1.0": + version "7.7.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.3.tgz#5fad457c2529de476a248f75b0f090b3060af043" + integrity sha512-bqv+iCo9i+uLVbI0ILzKkvMorqxouI+GbV13ivcARXn9NNEabi2IEz912IgNpT/60BNXac5dgcfjb94NjsF33A== + +"@babel/plugin-syntax-jsx@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz#0b85a3b4bc7cdf4cc4b8bf236335b907ca22e7c7" + integrity sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.7.0", "@babel/types@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.2.tgz#550b82e5571dcd174af576e23f0adba7ffc683f7" + integrity sha512-YTf6PXoh3+eZgRCBzzP25Bugd2ngmpQVrk7kXX0i5N9BO7TFBtIgZYs7WtxtOGs8e6A4ZI7ECkbBCEHeXocvOA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@types/babel__core@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30" + integrity sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.0.tgz#f1ec1c104d1bb463556ecb724018ab788d0c172a" + integrity sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" + integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.7": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.7.tgz#2496e9ff56196cc1429c72034e07eab6121b6f3f" + integrity sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw== + dependencies: + "@babel/types" "^7.3.0" + +"@types/lodash.kebabcase@^4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/lodash.kebabcase/-/lodash.kebabcase-4.1.6.tgz#07b07aeca6c0647836de46f87a3cdfff72166c8e" + integrity sha512-+RAD9pCAa8kuVyCYTeDNiwBXwD/0u0p+hos3NSqD+tXTjJextbfF3farfYB+ssAKgEssoewXEtBsfwBpsI7gsA== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.149" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" + integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== + +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= + +lodash@^4.17.13: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +typescript@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb" + integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ== diff --git a/packages/babel-sugar-functional-vue/package.json b/packages/babel-sugar-functional-vue/package.json new file mode 100644 index 0000000..f52b448 --- /dev/null +++ b/packages/babel-sugar-functional-vue/package.json @@ -0,0 +1,15 @@ +{ + "name": "babel-sugar-functional-vue", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.7.4", + "@babel/types": "^7.7.4", + "typescript": "^3.7.2" + }, + "devDependencies": { + "@types/babel__core": "^7.1.3", + "@types/babel__traverse": "^7.0.8" + } +} diff --git a/packages/babel-sugar-functional-vue/src/index.ts b/packages/babel-sugar-functional-vue/src/index.ts new file mode 100644 index 0000000..0c5a680 --- /dev/null +++ b/packages/babel-sugar-functional-vue/src/index.ts @@ -0,0 +1,94 @@ +import { PluginObj, NodePath } from '@babel/core' + +import syntaxJsx from '@babel/plugin-syntax-jsx' +import { ArrowFunctionExpression, identifier, objectProperty, booleanLiteral, arrowFunctionExpression, stringLiteral, objectExpression, VariableDeclarator, Identifier } from '@babel/types' +// import { transformJSXElement } from './transforms' + +const isInMethod = (path: NodePath, parentLimitPath: NodePath): boolean => { + if (!path || path === parentLimitPath) { + return false + } + if (path.isObjectMethod()) { + return true + } + return isInMethod(path.parentPath, parentLimitPath) +} + +export const hasJSX = (path: NodePath) => { + let hasJSX = false + + path.traverse({ + JSXElement(elPath) { + if (!isInMethod(elPath, path)) { + hasJSX = true + } + }, + }) + + return hasJSX +} + +export const convertFunctionalComponent = (path: NodePath, name: string | null = null) => { + const params = [identifier('h'), ...path.node.params] + const body = path.node.body + const props = [ + objectProperty(identifier('functional'), booleanLiteral(true)), + objectProperty(identifier('render'), arrowFunctionExpression(params, body)), + ] + if (process.env.NODE_ENV === 'development' && name) { + props.unshift(objectProperty(identifier('name'), stringLiteral(name))) + } + path.replaceWith(objectExpression(props)) +} + +export const isFunctionalComponentDeclarator = (path: NodePath) => { + const id = path.get('id') + if (!id.isIdentifier()) { + return false + } + + const firstCharacter = id.node.name[0] + if (firstCharacter < 'A' || firstCharacter > 'Z') { + return false + } + + return hasJSX(path) +} + +const plugin: PluginObj = { + name: 'babel-plugin-transform-vue-js', + inherits: syntaxJsx, + visitor: { + ExportDefaultDeclaration (path) { + const declaration = path.get('declaration') + if (!declaration.isArrowFunctionExpression() || !hasJSX(path)) { + return + } + + convertFunctionalComponent(declaration) + }, + VariableDeclaration (path) { + const declarations = path.get('declarations') + const firstDeclaration = declarations[0] + + if (declarations.length !== 1 || !firstDeclaration.isVariableDeclarator()) { + return + } + + const init = firstDeclaration.get('init') + + if(!init.isArrowFunctionExpression()) { + return + } + + if (!isFunctionalComponentDeclarator(firstDeclaration)) { + return + } + + const name = (path.node.declarations[0].id as Identifier).name + convertFunctionalComponent(init, name) + } + } +} + +export default plugin \ No newline at end of file diff --git a/packages/babel-sugar-functional-vue/src/shims.d.ts b/packages/babel-sugar-functional-vue/src/shims.d.ts new file mode 100644 index 0000000..661eef6 --- /dev/null +++ b/packages/babel-sugar-functional-vue/src/shims.d.ts @@ -0,0 +1,6 @@ +declare module '@babel/plugin-syntax-jsx' { + import { PluginObj } from '@babel/core' + + const syntaxJsx: PluginObj + export default syntaxJsx +} diff --git a/packages/babel-sugar-functional-vue/tsconfig.json b/packages/babel-sugar-functional-vue/tsconfig.json new file mode 100644 index 0000000..74f3f8e --- /dev/null +++ b/packages/babel-sugar-functional-vue/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "lib": [ + "esnext" + ], + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "outDir": "./dist", + "strictNullChecks": true, + "noImplicitAny": true, + "esModuleInterop": true + }, + "include" : ["src/*.ts"] +} diff --git a/packages/babel-sugar-functional-vue/yarn.lock b/packages/babel-sugar-functional-vue/yarn.lock new file mode 100644 index 0000000..0d010f0 --- /dev/null +++ b/packages/babel-sugar-functional-vue/yarn.lock @@ -0,0 +1,82 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + +"@babel/parser@^7.1.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" + integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== + +"@babel/plugin-syntax-jsx@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz#dab2b56a36fb6c3c222a1fbc71f7bf97f327a9ec" + integrity sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" + integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@types/babel__core@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30" + integrity sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.0.tgz#f1ec1c104d1bb463556ecb724018ab788d0c172a" + integrity sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" + integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.8": + version "7.0.8" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.8.tgz#479a4ee3e291a403a1096106013ec22cf9b64012" + integrity sha512-yGeB2dHEdvxjP0y4UbRtQaSkXJ9649fYCmIdRoul5kfAoGCwxuCbMhag0k3RPfnuh9kPGm8x89btcfDEXdVWGw== + dependencies: + "@babel/types" "^7.3.0" + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +lodash@^4.17.13: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +typescript@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb" + integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ== diff --git a/packages/jsx-explorer/.editorconfig b/packages/jsx-explorer/.editorconfig new file mode 100644 index 0000000..7053c49 --- /dev/null +++ b/packages/jsx-explorer/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/packages/jsx-explorer/.gitignore b/packages/jsx-explorer/.gitignore new file mode 100644 index 0000000..a0dddc6 --- /dev/null +++ b/packages/jsx-explorer/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/packages/jsx-explorer/README.md b/packages/jsx-explorer/README.md new file mode 100644 index 0000000..42b5f01 --- /dev/null +++ b/packages/jsx-explorer/README.md @@ -0,0 +1,24 @@ +# jsx-explorer + +## Project setup +``` +yarn install +``` + +### Compiles and hot-reloads for development +``` +yarn serve +``` + +### Compiles and minifies for production +``` +yarn build +``` + +### Lints and fixes files +``` +yarn lint +``` + +### Customize configuration +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/packages/jsx-explorer/babel.config.js b/packages/jsx-explorer/babel.config.js new file mode 100644 index 0000000..df19538 --- /dev/null +++ b/packages/jsx-explorer/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset', + ], +} diff --git a/packages/jsx-explorer/package.json b/packages/jsx-explorer/package.json new file mode 100644 index 0000000..0014ea8 --- /dev/null +++ b/packages/jsx-explorer/package.json @@ -0,0 +1,69 @@ +{ + "name": "jsx-explorer", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.2.0", + "core-js": "^3.3.2", + "vue": "^2.6.10", + "vue-codemirror": "^4.0.6" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "^4.0.0", + "@vue/cli-plugin-eslint": "^4.0.0", + "@vue/cli-plugin-typescript": "^4.0.5", + "@vue/cli-service": "^4.0.0", + "@vue/eslint-config-standard": "^4.0.0", + "@vue/eslint-config-typescript": "^4.0.0", + "babel-eslint": "^10.0.3", + "eslint": "^5.16.0", + "eslint-plugin-vue": "^5.0.0", + "lint-staged": "^9.4.2", + "typescript": "~3.5.3", + "vue-template-compiler": "^2.6.10" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/recommended", + "@vue/standard", + "@vue/typescript" + ], + "rules": { + "comma-dangle": [ + "error", + "always-multiline" + ] + }, + "parserOptions": { + "parser": "@typescript-eslint/parser" + } + }, + "postcss": { + "plugins": { + "autoprefixer": {} + } + }, + "browserslist": [ + "> 1%", + "last 2 versions" + ], + "gitHooks": { + "pre-commit": "lint-staged" + }, + "lint-staged": { + "*.{js,vue}": [ + "vue-cli-service lint", + "git add" + ] + } +} diff --git a/packages/jsx-explorer/public/favicon.ico b/packages/jsx-explorer/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/packages/jsx-explorer/public/index.html b/packages/jsx-explorer/public/index.html new file mode 100644 index 0000000..17f2887 --- /dev/null +++ b/packages/jsx-explorer/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + jsx-explorer + + + +
+ + + diff --git a/packages/jsx-explorer/src/App.vue b/packages/jsx-explorer/src/App.vue new file mode 100644 index 0000000..ae19901 --- /dev/null +++ b/packages/jsx-explorer/src/App.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/packages/jsx-explorer/src/components/Editor.vue b/packages/jsx-explorer/src/components/Editor.vue new file mode 100644 index 0000000..5159721 --- /dev/null +++ b/packages/jsx-explorer/src/components/Editor.vue @@ -0,0 +1,57 @@ + + + diff --git a/packages/jsx-explorer/src/components/Frame.vue b/packages/jsx-explorer/src/components/Frame.vue new file mode 100644 index 0000000..b6d793c --- /dev/null +++ b/packages/jsx-explorer/src/components/Frame.vue @@ -0,0 +1,60 @@ +