Skip to content
Merged
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
4 changes: 4 additions & 0 deletions crates/oxc_linter/src/generated/rule_runner_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2915,6 +2915,10 @@ impl RuleRunner for crate::rules::vue::max_props::MaxProps {
const NODE_TYPES: Option<&AstTypesBitset> = None;
}

impl RuleRunner for crate::rules::vue::no_export_in_script_setup::NoExportInScriptSetup {
const NODE_TYPES: Option<&AstTypesBitset> = None;
}

impl RuleRunner for crate::rules::vue::no_multiple_slot_args::NoMultipleSlotArgs {
const NODE_TYPES: Option<&AstTypesBitset> =
Some(&AstTypesBitset::from_types(&[AstType::CallExpression]));
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@ pub(crate) mod vue {
pub mod define_props_declaration;
pub mod define_props_destructuring;
pub mod max_props;
pub mod no_export_in_script_setup;
pub mod no_multiple_slot_args;
pub mod no_required_prop_with_default;
pub mod prefer_import_from_vue;
Expand Down Expand Up @@ -1249,6 +1250,7 @@ oxc_macros::declare_all_lint_rules! {
vue::define_emits_declaration,
vue::define_props_declaration,
vue::max_props,
vue::no_export_in_script_setup,
vue::no_multiple_slot_args,
vue::no_required_prop_with_default,
vue::prefer_import_from_vue,
Expand Down
170 changes: 170 additions & 0 deletions crates/oxc_linter/src/rules/vue/no_export_in_script_setup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{
context::{ContextHost, LintContext},
frameworks::FrameworkOptions,
rule::Rule,
};

fn no_export_in_script_setup_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("<script setup>` cannot contain ES module exports.").with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct NoExportInScriptSetup;

declare_oxc_lint!(
/// ### What it does
///
/// Disallow `export` in `<script setup>`
///
/// ### Why is this bad?
///
/// The previous version of `<script setup>` RFC used `export` to define variables used in templates,
/// but the new `<script setup>` RFC has been updated to define without using `export`.
/// See [Vue RFCs - 0040-script-setup](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md) for more details.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```vue
/// <script setup>
/// export let msg = 'Hello!'
/// </script>
/// ```
///
/// Examples of **correct** code for this rule:
/// ```vue
/// <script setup>
/// let msg = 'Hello!'
/// </script>
/// ```
NoExportInScriptSetup,
vue,
correctness,
);

impl Rule for NoExportInScriptSetup {
fn run_once(&self, ctx: &LintContext) {
let modules = ctx.module_record();

for entry in &modules.local_export_entries {
if entry.is_type {
continue;
}

ctx.diagnostic(no_export_in_script_setup_diagnostic(entry.span));
}

for entry in &modules.indirect_export_entries {
if entry.is_type {
continue;
}

ctx.diagnostic(no_export_in_script_setup_diagnostic(entry.span));
}

for entry in &modules.star_export_entries {
if entry.is_type {
continue;
}
ctx.diagnostic(no_export_in_script_setup_diagnostic(entry.span));
}

if let Some(span) = modules.export_default {
ctx.diagnostic(no_export_in_script_setup_diagnostic(span));
}
}

fn should_run(&self, ctx: &ContextHost) -> bool {
ctx.frameworks_options() == FrameworkOptions::VueSetup
}
}

#[test]
fn test() {
use crate::tester::Tester;
use std::path::PathBuf;

let pass = vec![
(
"
<script>
export * from 'foo'
export default {}
export class A {}
</script>
",
None,
None,
Some(PathBuf::from("test.vue")),
),
(
"
<script>
export * from 'foo'
export default {}
export class A {}
</script>
<script setup>
let foo;
</script>
",
None,
None,
Some(PathBuf::from("test.vue")),
),
];

let fail = vec![
(
"
<script setup>
export * from 'foo'
export default {}
export class A {}
export const test = '123'
export function foo() {}
const a = 1
export { a }
export { fao } from 'bar'
</script>
",
None,
None,
Some(PathBuf::from("test.vue")),
),
(
"
<script>
let foo;
</script>
<script setup>
export * from 'foo'
export default {}
export class A {}
</script>
",
None,
None,
Some(PathBuf::from("test.vue")),
),
(
r#"
<script setup lang="ts">
export const Foo = {}
export enum Bar {}
export { }
</script>
"#,
None,
None,
Some(PathBuf::from("test.vue")),
), // { "parser": require("vue-eslint-parser"), "parserOptions": { "parser": require.resolve("@typescript-eslint/parser") } }
];

Tester::new(NoExportInScriptSetup::NAME, NoExportInScriptSetup::PLUGIN, pass, fail)
.test_and_snapshot();
}
114 changes: 114 additions & 0 deletions crates/oxc_linter/src/snapshots/vue_no_export_in_script_setup.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
source: crates/oxc_linter/src/tester.rs
---
⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:4:25]
3 │ export * from 'foo'
4 │ export default {}
· ──
5 │ export class A {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:5:17]
4 │ export default {}
5 │ export class A {}
· ──────────
6 │ export const test = '123'
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:6:17]
5 │ export class A {}
6 │ export const test = '123'
· ──────────────────
7 │ export function foo() {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:7:17]
6 │ export const test = '123'
7 │ export function foo() {}
· ─────────────────
8 │ const a = 1
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:9:19]
8 │ const a = 1
9 │ export { a }
· ─
10 │ export { fao } from 'bar'
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:10:19]
9 │ export { a }
10 │ export { fao } from 'bar'
· ───
11 │ </script>
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:3:10]
2 │ <script setup>
3 │ export * from 'foo'
· ───────────────────
4 │ export default {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:4:17]
3 │ export * from 'foo'
4 │ export default {}
· ───────
5 │ export class A {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:7:25]
6 │ export * from 'foo'
7 │ export default {}
· ──
8 │ export class A {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:8:17]
7 │ export default {}
8 │ export class A {}
· ──────────
9 │ </script>
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:6:10]
5 │ <script setup>
6 │ export * from 'foo'
· ───────────────────
7 │ export default {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:7:17]
6 │ export * from 'foo'
7 │ export default {}
· ───────
8 │ export class A {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:3:17]
2 │ <script setup lang="ts">
3 │ export const Foo = {}
· ──────────────
4 │ export enum Bar {}
╰────

⚠ eslint-plugin-vue(no-export-in-script-setup): <script setup>` cannot contain ES module exports.
╭─[no_export_in_script_setup.tsx:4:17]
3 │ export const Foo = {}
4 │ export enum Bar {}
· ───────────
5 │ export { }
╰────
Loading