Skip to content
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

feat: vue extractor error reporting #1924

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`vue extractor should catch template errors 1`] = `[Error: Vue template compilation failed]`;

exports[`vue extractor should catch warnings during parsing 1`] = `[Error: Vue parsing failed]`;

exports[`vue extractor should extract message from functional component 1`] = `
[
{
Expand Down
53 changes: 48 additions & 5 deletions packages/extractor-vue/src/extractor.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ExtractedMessage } from "@lingui/babel-plugin-extract-messages"
import { makeConfig } from "@lingui/conf"
import fs from "fs"
import path from "path"
import { vueExtractor } from "."
import type { ExtractedMessage } from "@lingui/babel-plugin-extract-messages"

function normalizePath(entries: ExtractedMessage[]): ExtractedMessage[] {
return entries.map((entry) => {
Expand All @@ -16,6 +16,11 @@ function normalizePath(entries: ExtractedMessage[]): ExtractedMessage[] {
})
}

function getFixtureCode(filename: string) {
const filePath = path.resolve(__dirname, "fixtures", filename)
return fs.readFileSync(filePath, "utf-8")
}

describe("vue extractor", () => {
const linguiConfig = makeConfig({
locales: ["en", "nb"],
Expand All @@ -41,8 +46,7 @@ describe("vue extractor", () => {
})

it("should extract message from vue file", async () => {
const filePath = path.resolve(__dirname, "fixtures/test.vue")
const code = fs.readFileSync(filePath, "utf-8")
const code = getFixtureCode("test.vue")

let messages: ExtractedMessage[] = []

Expand All @@ -63,8 +67,7 @@ describe("vue extractor", () => {
})

it("should extract message from functional component", async () => {
const filePath = path.resolve(__dirname, "fixtures/functional.vue")
const code = fs.readFileSync(filePath, "utf-8")
const code = getFixtureCode("functional.vue")

let messages: ExtractedMessage[] = []

Expand All @@ -83,4 +86,44 @@ describe("vue extractor", () => {

expect(messages).toMatchSnapshot()
})

it("should catch warnings during parsing", async () => {
// ref: https://github.com/vuejs/core/blob/main/packages/compiler-sfc/__tests__/parse.spec.ts
const code = getFixtureCode("test-parse.vue")

let messages: ExtractedMessage[] = []

expect(
vueExtractor.extract(
"test-parse.vue",
code,
(res) => messages.push(res),
{
linguiConfig,
}
)
).rejects.toMatchSnapshot()

expect(messages).toHaveLength(0)
})

it("should catch template errors", async () => {
// ref: https://github.com/vuejs/core/blob/main/packages/compiler-sfc/__tests__/compileTemplate.spec.ts
const source = getFixtureCode("test-compile.vue")

let messages: ExtractedMessage[] = []

expect(
vueExtractor.extract(
"test-compile.vue",
source,
(res) => messages.push(res),
{
linguiConfig,
}
)
).rejects.toMatchSnapshot()

expect(messages).toHaveLength(0)
})
})
10 changes: 10 additions & 0 deletions packages/extractor-vue/src/fixtures/test-compile.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script setup lang="ts">
import { i18n } from '@lingui/core';

let message = i18n._("Hello World")
</script>

<template lang="pug">
<div :bar="a[" v-model="baz"/>
{{ message }}
</template>
15 changes: 15 additions & 0 deletions packages/extractor-vue/src/fixtures/test-parse.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup lang="ts">
import { i18n } from "@lingui/core";

let firstMessage = i18n._('Hello World')
let secondMessage = i18n._('Goodbye Vue')
</script>

<template>
<p>1st template</p>
<small>{{ firstMessage }}</small>
</template>
<template>
<p>2nd template</p>
<small>{{ secondMessage }}</small>
</template>
14 changes: 12 additions & 2 deletions packages/extractor-vue/src/vue-extractor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { parse, compileTemplate, SFCBlock } from "@vue/compiler-sfc"
import { extractor } from "@lingui/cli/api"
import type { ExtractorCtx, ExtractorType } from "@lingui/conf"
import { SFCBlock, compileTemplate, parse } from "@vue/compiler-sfc"

export const vueExtractor: ExtractorType = {
match(filename: string) {
Expand All @@ -12,12 +12,17 @@ export const vueExtractor: ExtractorType = {
onMessageExtracted,
ctx: ExtractorCtx
) {
const { descriptor } = parse(code, {
const { descriptor, errors: parsedErrors } = parse(code, {
sourceMap: true,
filename,
ignoreEmpty: true,
})

if (parsedErrors.length) {
parsedErrors.forEach(console.log)
throw new Error("Vue parsing failed")
}

const isTsBlock = (block: SFCBlock) => block?.lang === "ts"

const compiledTemplate =
Expand All @@ -33,6 +38,11 @@ export const vueExtractor: ExtractorType = {
},
})

if (compiledTemplate?.errors?.length) {
compiledTemplate.errors.forEach(console.log)
throw new Error("Vue template compilation failed")
}

const targets = [
[
descriptor.script?.content,
Expand Down
Loading