Skip to content

Vue class based to vue2 with TS support #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add vuex global actions/state/getter support, vue hooks
  • Loading branch information
matrunchyk committed Oct 23, 2021
commit 7cd28fd0263f211b5fe74d89dbbd471fd9565db0
Original file line number Diff line number Diff line change
Expand Up @@ -31,35 +31,43 @@
</template>

<script lang="ts">
import {
ActionProps,
ActionType,
NotificationType,
NotifictionProps,
} from '@/components/actionableNotification/consts';
import * as something from '@/consts';
import { BatchFile } from '@/utils/classes/UploadResults';
import { BUTTONS_ACTIONS, WARNING_MODALS, ROUTES } from '@/utils/consts';
import { eventBus } from '@/utils/eventBus';
import { Subscription } from 'rxjs';
import Vue from 'vue';
import Component from 'vue-class-component';
import { Prop } from 'vue-property-decorator';
import VClamp from 'vue-clamp';
import { namespace } from 'vuex-class';

const a = {
...mapActions('addSampleModule', ['realSaveSample']),
//b: 1,
}

//var abc = 1;
//const addSampleModule1 = namespace('addSampleModule');
//let removeSampleModule2 = namespace('removeSampleModule');

import { Watch } from 'vue-property-decorator';
import { Action, namespace } from 'vuex-class';
import { BATCH_PROCESSING_STATUSES, BatchStatus, SAMPLE_STATUSES } from '../consts/consts';
import { Filters } from '../models/UploadResultsSummaryState';
import { VIEWS_TABS_VALUES } from '../services/utils';

const uploadResultSummaryModule = namespace('uploadResultSummaryModule');
const plateRawDataModule = namespace('plateRawDataModule');
const patientDetailsModule = namespace('patientDetailsModule');
const reportsModule = namespace('reportsModule');
const uploadResultsModule = namespace('uploadResultsModule');

@Component

@Component({
components: {
IgcTitleLine: () => import('igentify-ui-core/lib/shared/components/IgcTitleLine/IgcTitleLine.vue'),
rbTitle: () => import('@/components/rbTitle.vue'),
IgnTitle: () => import('@/components/IgnTitle.vue'),
SearchInput: () => import('@/components/SearchInput.vue'),
ViewsTabs: () => import('@/components/ViewsTabs.vue'),
MutationInfo: () => import('@/components/mutation-info/MutationInfo.vue'),
},
})
export default class ActionableNotification extends Vue {
@addSampleModule.Action('realSaveSample') saveSample: (slimSample: SlimSample) => Promise<void>;
@addSampleModule.Action('doSomething') doSomething: (slimSample: SlimSample) => Promise<void>;
@addPatientModule.Action('addPatient') addPatient: (slimSample: SlimSample) => Promise<void>;
@Action('setMessage') setMessage: any;
@Action('clearMessage') clearMessage: any;
@Action('navigateTo') navigateTo: ({ name: string }) => void;

@uploadResultSummaryModule.Action('realSaveSample') saveSample: (slimSample: SlimSample) => Promise<void>;
@uploadResultSummaryModule.Action('doSomething') doSomething: (slimSample: SlimSample) => Promise<void>;
@plateRawDataModule.Action('addPatient') addPatient: (slimSample: SlimSample) => Promise<void>;

@uploadResultSummaryModule.State('data') currentData: any;
@uploadResultSummaryModule.State('incomingSampleStatuses') incomingSampleStatuses: any;
Expand All @@ -86,6 +94,7 @@ export default class ActionableNotification extends Vue {
@uploadResultSummaryModule.Action('updateData') updateData: () => void;
@patientDetailsModule.Action('clearMutationInfoResult')
clearMutationInfoResult: any;
@Action('setMessage') setMessage: any;

@Prop() message?: string;
@Prop({ default: () => NotificationType.INFO }) notificationType: NotificationType;
Expand Down
3 changes: 2 additions & 1 deletion transformations/remove-extraneous-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ export const transformAST: ASTTransformation<Params> = (
'vue-router',
'vuex',
'@vue/composition-api',
]
];

if (
peerSpecifiers.length === 1 &&
safelyRemovableModules.includes(source)
Expand Down
114 changes: 72 additions & 42 deletions transformations/vue-class-component-v8.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import {
arrayExpression,
arrowFunctionExpression,
arrowFunctionExpression, blockStatement,
booleanLiteral, callExpression,
CallExpression,
ClassDeclaration,
ClassMethod,
ClassProperty,
Decorator,
exportDefaultDeclaration,
ExportDefaultDeclaration,
ExportDefaultDeclaration, expressionStatement,
Identifier,
identifier,
ImportDeclaration,
literal,
ObjectExpression,
objectExpression, ObjectMethod,
objectMethod, objectProperty,
objectExpression,
objectMethod,
objectProperty,
Property,
property,
spreadElement,
stringLiteral,
VariableDeclaration
stringLiteral, variableDeclaration,
VariableDeclaration, variableDeclarator
} from 'jscodeshift'
import type { ASTTransformation, Context } from '../src/wrapAstTransformation'
import wrap from '../src/wrapAstTransformation'
Expand Down Expand Up @@ -68,18 +69,27 @@ function removeImports(context: Context) {
})
}

const vueHooks = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
]

function classToOptions(context: Context) {
console.log('------')
const prevDefaultExportDeclaration = context.root.find(ExportDefaultDeclaration)
const newDefaultExportDeclaration = exportDefaultDeclaration(identifier('default'))
const prevClass = prevDefaultExportDeclaration.find(ClassDeclaration)
const prevClassProperties = prevDefaultExportDeclaration.find(ClassProperty)
const prevClassComputed = prevDefaultExportDeclaration.find(ClassMethod, {
kind: 'get'
})
const prevClassMethods = prevDefaultExportDeclaration.find(ClassMethod, {
kind: 'method'
})
const prevClassMethods = prevDefaultExportDeclaration.find(ClassMethod, dec => dec.kind === 'method' && !vueHooks.includes(dec.key.name))
const prevClassHooks = prevDefaultExportDeclaration.find(ClassMethod, dec => dec.kind === 'method' && vueHooks.includes(dec.key.name))
const componentDecorator = prevClass.get(0).node.decorators.find(d => d.expression.callee?.name === 'Component' || d.expression.name === 'Component')
const newClassProperties = componentDecorator.expression?.arguments?.[0]?.properties || []
const variableDeclarations = context.root.find(VariableDeclaration)
Expand All @@ -95,11 +105,10 @@ function classToOptions(context: Context) {
Getter: new Map<string, VuexMappingItem>(),
GetterAlias: new Map<string, VuexMappingItem>(),
}
// We need this object as a reference for vuex accessors (actions/getters/etc) class members decorators
const vuexNamespaceMap: Record<string, string> = {}

if (variableDeclarations.length) {
// We need this object as a reference for vuex accessors (actions/getters/etc) class members decorators
const vuexNamespaceMap: Record<string, string> = {}

context
.root
.get(0)
Expand All @@ -111,16 +120,15 @@ function classToOptions(context: Context) {
// We assume there are no multiple declarations like "const a = 1, b = 2" __for vuex namespaces__
const [declaration] = vd.declarations;

// console.log(declaration.init.properties?.[0]?.argument?.arguments[1])
if (declaration.init.properties?.[0]) {
// console.log(spreadElement(callExpression(identifier('mapActions'), [
// stringLiteral('addSampleModule')
// ])))
}
// We're interested in namespace('...') call expressions __only with arguments__
if (
declaration.init.type !== 'CallExpression'
|| !declaration.init.arguments?.[0]?.value
|| declaration.init.callee.name !== 'namespace'
) return;

// We're interested in namespace('...') call expressions only with arguments
if (declaration.init.type !== 'CallExpression' && !declaration.init.arguments?.[0]?.value) return;
vuexNamespaceMap[declaration.id.name] = declaration.init.arguments[0].value;
context.root.find(VariableDeclaration, (value => value.declarations?.[0].init?.callee?.name === 'namespace')).remove();
})
}

Expand All @@ -134,8 +142,10 @@ function classToOptions(context: Context) {
const type = prop.typeAnnotation?.typeAnnotation?.type.replace(/^TS(.*)Keyword$/, '$1') || 'Object'

if (prop.decorators[0].expression.arguments?.[0]?.type as string === 'StringLiteral') {
const accessorType = prop.decorators[0].expression.callee.property.name;
const decoratorName = prop.decorators[0].expression.callee.object.name;
const accessorType = prop.decorators[0].expression.callee.property
? prop.decorators[0].expression.callee.property?.name
: prop.decorators[0].expression.callee.name;
const decoratorName = prop.decorators[0].expression.callee.object?.name || 'global';
const localName = prop.key.name;
const argumentValue = prop.decorators[0].expression.arguments[0].value;
const isAliased = localName !== argumentValue;
Expand Down Expand Up @@ -205,25 +215,33 @@ function classToOptions(context: Context) {
property('init', identifier('data'), arrowFunctionExpression([], objectExpression(data)))
)

// Computed
const computed: any[] = []

// Methods
const methods: any[] = []
const computed: any[] = [];
const methods: any[] = [];

vuex.Action.forEach((actionArguments, actionName: string) => {
if (!vuexNamespaceMap[actionName] && actionName !== 'global') {
throw new Error(`Unknown decorator @${actionName}. Make sure you have "const ${actionName} = namespace('${actionName}'); specified`)
}
methods.push(
spreadElement(callExpression(identifier('mapActions'), [
stringLiteral(actionName),
...(actionName === 'global' ? [] : [
stringLiteral(vuexNamespaceMap[actionName])
]),
arrayExpression(actionArguments.map(a => stringLiteral(a.remoteName))),
]))
)
})

vuex.ActionAlias.forEach((actionArguments, actionName: string) => {
if (!vuexNamespaceMap[actionName] && actionName !== 'global') {
throw new Error(`Unknown decorator @${actionName}. Make sure you have "const ${actionName} = namespace('${actionName}'); specified`)
}

methods.push(
spreadElement(callExpression(identifier('mapActions'), [
stringLiteral(actionName),
...(actionName === 'global' ? [] : [
stringLiteral(vuexNamespaceMap[actionName])
]),
objectExpression([
...actionArguments.map(arg => objectProperty(identifier(arg.localName), stringLiteral(arg.remoteName)))
])
Expand All @@ -235,7 +253,9 @@ function classToOptions(context: Context) {
vuex.State.forEach((actionArguments, actionName: string) => {
computed.push(
spreadElement(callExpression(identifier('mapState'), [
stringLiteral(actionName),
...(actionName === 'global' ? [] : [
stringLiteral(actionName)
]),
arrayExpression(actionArguments.map(a => stringLiteral(a.remoteName))),
]))
)
Expand All @@ -244,7 +264,9 @@ function classToOptions(context: Context) {
vuex.StateAlias.forEach((actionArguments, actionName: string) => {
computed.push(
spreadElement(callExpression(identifier('mapState'), [
stringLiteral(actionName),
...(actionName === 'global' ? [] : [
stringLiteral(actionName)
]),
objectExpression([
...actionArguments.map(arg => objectProperty(identifier(arg.localName), stringLiteral(arg.remoteName)))
])
Expand All @@ -255,7 +277,9 @@ function classToOptions(context: Context) {
vuex.Getter.forEach((actionArguments, actionName: string) => {
computed.push(
spreadElement(callExpression(identifier('mapGetters'), [
stringLiteral(actionName),
...(actionName === 'global' ? [] : [
stringLiteral(actionName)
]),
arrayExpression(actionArguments.map(a => stringLiteral(a.remoteName))),
]))
)
Expand All @@ -264,27 +288,33 @@ function classToOptions(context: Context) {
vuex.GetterAlias.forEach((actionArguments, actionName: string) => {
computed.push(
spreadElement(callExpression(identifier('mapGetters'), [
stringLiteral(actionName),
...(actionName === 'global' ? [] : [
stringLiteral(actionName)
]),
objectExpression([
...actionArguments.map(arg => objectProperty(identifier(arg.localName), stringLiteral(arg.remoteName)))
])
]))
)
})

// Computed
prevClassComputed.forEach(c => {
computed.push(objectMethod('method', identifier(c.node.key.name), [], c.node.body))
// console.log(objectMethod('method', c.node.key, [], c.node.body))
computed.push(objectMethod('method', c.node.key, [], c.node.body))
})
newClassProperties.push(
property('init', identifier('computed'), objectExpression(computed))
)
newClassProperties.push(property('init', identifier('computed'), objectExpression(computed)));

// Methods
prevClassMethods.forEach(m => {
methods.push(objectMethod('method', identifier(m.node.key.name), [], m.node.body))
methods.push(objectMethod('method', m.node.key, [], m.node.body))
})
newClassProperties.push(property('init', identifier('methods'), objectExpression(methods)))

// Hooks
prevClassHooks.forEach(m => {
newClassProperties.push(objectMethod('method', m.value.key, [], m.value.body));
})
newClassProperties.push(
property('init', identifier('methods'), objectExpression(methods))
)

newDefaultExportDeclaration.declaration = objectExpression(newClassProperties)
prevDefaultExportDeclaration.replaceWith(newDefaultExportDeclaration)
Expand Down