mirror of
https://gitee.com/newgateway/vtj.git
synced 2026-06-24 04:03:38 +08:00
- 新增 compositionPatch 功能,实现 <script setup> 代码中标识符到 this.xxx 的自动转换 - 扩展全局 API map,新增 pinia 和 vue-i18n 相关全局变量支持与合并声明 - 增加 ScriptSetup 解析模块,完整解析 refs、reactives、computed、methods 等组成部分 - 修改 parseVue 实现,单点分流支持 Composition API 和 Options API 两种模式解析 - 修正工具函数,调整 props 替换逻辑,避免不必要的 this.props 访问替换 - 扩展 Vitest 测试用例,覆盖 Composition API 使用场景 - 增加对 defineProps、defineEmits、inject、provide 等新语法的支持与提取 - 优化 AST 遍历,准确识别 setup 函数内容及生命周期函数映射 - 添加全局 @vueuse/core 和自定义 composable 支持逻辑 - 规范代码结构,拆分解析细节并提升整体可维护性与扩展性
199 lines
3.8 KiB
TypeScript
199 lines
3.8 KiB
TypeScript
import { expect, test, describe } from 'vitest';
|
|
import { ComponentValidator } from '../src';
|
|
|
|
const validValidatorSFC = `
|
|
<template>
|
|
<div>Hello</div>
|
|
<VanIcon name="user" />
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
setup() {
|
|
const state = reactive({
|
|
count: 1,
|
|
name: ''
|
|
});
|
|
const msg = ref('hello');
|
|
return { count, name, msg };
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.test { color: red; }
|
|
</style>
|
|
`;
|
|
|
|
const missingScriptSFC = `
|
|
<template>
|
|
<div>Hello</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.test { }
|
|
</style>
|
|
`;
|
|
|
|
const tooFewSetupLines = `
|
|
<template>
|
|
<div>Hello</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
setup() {
|
|
const msg = ref('hello');
|
|
return { msg };
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|
|
`;
|
|
|
|
const tooManySetupLines = `
|
|
<template>
|
|
<div>Hello</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
setup() {
|
|
const state = reactive({
|
|
count: 1
|
|
});
|
|
const msg = ref('hello');
|
|
const title = ref('world');
|
|
return { count, msg, title };
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|
|
`;
|
|
|
|
const incompleteCodeSFC = `
|
|
<template>
|
|
<div>Hello</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
setup() {
|
|
const state = reactive({
|
|
count: 1
|
|
});
|
|
// 其他逻辑保持不变
|
|
return { count };
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|
|
`;
|
|
|
|
const illegalVantIconSFC = `
|
|
<template>
|
|
<div>Hello</div>
|
|
<VanIcon name="non-existent-icon-name" />
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
setup() {
|
|
const state = reactive({
|
|
count: 1
|
|
});
|
|
return { count };
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|
|
`;
|
|
|
|
const illegalVtjIconSFC = `
|
|
<template>
|
|
<div>Hello</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { NonExistentIcon } from '@vtj/icons';
|
|
export default {
|
|
data() {
|
|
return {};
|
|
},
|
|
setup() {
|
|
const state = reactive({
|
|
count: 1
|
|
});
|
|
return { NonExistentIcon, count };
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|
|
`;
|
|
|
|
describe('ComponentValidator', () => {
|
|
const validator = new ComponentValidator();
|
|
|
|
test('should validate a proper SFC', () => {
|
|
const result = validator.validate(validValidatorSFC);
|
|
expect(result.valid).toBe(true);
|
|
expect(result.errors.length).toBe(0);
|
|
});
|
|
|
|
test('should reject SFC missing script', () => {
|
|
const result = validator.validate(missingScriptSFC);
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('should reject setup with too few lines', () => {
|
|
const result = validator.validate(tooFewSetupLines);
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors.some((e) => e.includes('setup'))).toBe(true);
|
|
});
|
|
|
|
test('should reject setup with too many lines', () => {
|
|
const result = validator.validate(tooManySetupLines);
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors.some((e) => e.includes('setup'))).toBe(true);
|
|
});
|
|
|
|
test('should detect unchanged comment', () => {
|
|
const result = validator.validate(incompleteCodeSFC);
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors.some((e) => e.includes('不能有任何省略'))).toBe(true);
|
|
});
|
|
|
|
test('should detect illegal Vant icons', () => {
|
|
const result = validator.validate(illegalVantIconSFC);
|
|
expect(result.illegalVantIcons.length).toBeGreaterThan(0);
|
|
expect(result.illegalVantIcons).toContain('non-existent-icon-name');
|
|
});
|
|
|
|
test('should detect illegal Vtj icons', () => {
|
|
const result = validator.validate(illegalVtjIconSFC);
|
|
expect(result.illegalVtjIcons.length).toBeGreaterThan(0);
|
|
expect(result.illegalVtjIcons).toContain('NonExistentIcon');
|
|
});
|
|
|
|
test('should handle syntax error gracefully', () => {
|
|
const result = validator.validate(`
|
|
<template><div/></template>
|
|
<script>export default { bad syntax ! }</script>
|
|
<style></style>
|
|
`);
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors.length).toBeGreaterThan(0);
|
|
});
|
|
});
|