UnrefinedBrain / vue-metamorph

Codemod Framework for Vue projects
https://vue-metamorph.dev/
MIT License
72 stars 1 forks source link

is it possible to add new VElement to sfcAST? #92

Closed haoliangwu closed 1 month ago

haoliangwu commented 1 month ago

the current project I migrated contains lots of locales files related to i18n feature and we have to migrate them, something like this:

// vue2
<template lang="pug">
  div(v-show='media(["lg", "sm"])') {{ $t('msg_id_top_game_result_notification_1') }}
</template>

<script>
import messages from '@/locales/pages'

export default {
  i18n: {
    messages
  }
};
</script>

// vue3
<template lang="pug">
  div(v-show='media(["lg", "sm"])') {{ t('msg_id_top_game_result_notification_1') }}
</template>

<script setup>
   const { t } = useI18n({
     useScope: "local",
   });
</script>

<i18n lang="json">
  {
    "en": {
      "msg_id_top_game_result_notification_1": "The standings are currently not displayed due to the [Hide Results] setting.",
    },
    "ja": {
      "msg_id_top_game_result_notification_1": "[試合結果を表示しない]に設定しているため、表示されていません。",
    }
  }
</i18n>

except the migration for javascript part(I have implemented by traverseScriptAST successfully), the challenge here is how to append <script setup> and <i18n lang="json"> to sfcAST and keep its content?

I write a plugin like this to implement it:

import { namedTypes as n } from 'ast-types'
import { CodemodPlugin } from 'vue-metamorph'

export const appendSetupScriptCodemod: CodemodPlugin = {
  type: 'codemod',
  name: 'append-setup-script',
  transform({ scriptASTs, sfcAST, utils: { traverseScriptAST, traverseTemplateAST, builders, astHelpers }, opts }) {
    const transformCount = 0

    const scriptSetupVStartTag = builders.vStartTag(
      [builders.vAttribute(builders.vIdentifier('setup', 'setup'), null)],
      false,
    )
    const scriptSetupVText = builders.vText(`
const { t } = useI18n({
  useScope: "local",
});
`)
    const scriptSetupVElement = builders.vElement(
      'script',
      scriptSetupVStartTag,
      [scriptSetupVText],
      'http://www.w3.org/1999/xhtml',
    )

    if (sfcAST) {
      traverseTemplateAST(sfcAST, {
        enterNode(node, parent) {
          if (node.type === 'VDocumentFragment') {
            node.children.push(scriptSetupVElement)
          }
        },
      })

      builders.setParents(sfcAST)
    }

    return transformCount
  },
}

anyway, the <script setup> could be appended successfully but its content is missing, see the failed unit test screenshot: image

is there any suggestion here? 😂 feel free to point me something wrong and I will update it.

haoliangwu commented 1 month ago

I found maybe the challenge here could be easily solved by magic-string. 😂

UnrefinedBrain commented 1 month ago

Should be fixed in 3.1.8