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

Support Vue #40

Merged
merged 1 commit into from Oct 26, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -372,8 +372,8 @@ Having some trouble or an issue? You can check [FAQ / Troubleshooting section](.
| NodeJS with ES Modules | ✅ Everything | - |
| React | ✅ Everything | - |
| Angular | ✅ Everything | Supported through `importOrderParserPlugins` API |
| Vue | ⚠️ Soon to be supported. | Any contribution is welcome. |
| Svelte | ⚠️ Soon to be supported. | Any contribution is welcome. |
| Vue | ✅ Everything | - |
| Svelte | ⚠️ Not yet | Contributions are welcome |

## Contribution

Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -52,7 +52,8 @@
"@babel/types": "^7.17.0",
"javascript-natural-sort": "0.7.1",
"lodash.clone": "^4.5.0",
"lodash.isequal": "^4.5.0"
"lodash.isequal": "^4.5.0",
"@vue/compiler-sfc": "3.2.40"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have instead been an optionalDependency? I admit I'm unfamiliar with the size/complexity of @vue/compiler-sfc

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optionalDependency and devDependency?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it can be optional, unless we have a good way to conditionally import() it, and I'm not sure how we'd know up-front when registering the plugin whether it will be needed or not.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try {
  var foo = require('foo')
  var fooVersion = require('foo/package.json').version
} catch (er) {
  foo = null
}
if ( notGoodFooVersion(fooVersion) ) {
  foo = null
}

Conditional import will require some shenanigans with require statements, but I think it's possible.

The way I'd do it, is by adding a wrapper function around the compiler call, that does that detection, and throws a clean error if the package is missing, but that codepath is executed. We would need some // @ts-ignore lines, I think.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would need to be in peerDependencies and we would set peerDependenciesMeta to treat it as optional. The main thing I'm not sure about is: Can we expect every Vue project to have this dependency?

@blake-newman, since you wrote the original PR and know the Vue landscape much better than I do, maybe you can talk about why you chose to use a regular dependency for @vue/compiler-sfc rather than a peerDependency?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@IanVS i used it as a devDependency for simplicity of use; however it is correct that not all will need it.

This is the stack it introduces: which is fairly heavy just to extract the script section. I may be able to remove this dependency tbh. As it's not a tricky job to do so.

"@vue/compiler-sfc@npm:^3.2.40":
  version: 3.2.41
  resolution: "@vue/compiler-sfc@npm:3.2.41"
  dependencies:
    "@babel/parser": ^7.16.4
    "@vue/compiler-core": 3.2.41
    "@vue/compiler-dom": 3.2.41
    "@vue/compiler-ssr": 3.2.41
    "@vue/reactivity-transform": 3.2.41
    "@vue/shared": 3.2.41
    estree-walker: ^2.0.2
    magic-string: ^0.25.7
    postcss: ^8.1.10
    source-map: ^0.6.1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trivago/prettier-plugin-sort-imports#183

I decided to keep with the compiler; as no point re-inventing the wheel. Most Vue projects will have this dependency by default anyway.

The scope of the API used is very minimal so there is no need to try to lock it into a specific version; it's quite unlikely the API will break this use case. If it ever does it'll be likely trivial changes to fix but won't break this package and fix can be added consumer side to lock a particular version until resolved upstream.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks for the explanations! I'll make it a peer dependency on this fork as well, then.

Also note, if you're using the trivago version, it's potentially unsafe to use side-effect-only imports, since it will re-arrange them, which is the reason this fork exists. Just giving you a heads-up in case you weren't aware.

},
"devDependencies": {
"@types/jest": "^29.2.0",
Expand Down
14 changes: 10 additions & 4 deletions src/index.ts
@@ -1,9 +1,11 @@
import type { RequiredOptions as PrettierRequiredOptions } from 'prettier';
import { parsers as babelParsers } from 'prettier/parser-babel';
import { parsers as flowParsers } from 'prettier/parser-flow';
import { parsers as htmlParsers } from 'prettier/parser-html';
import { parsers as typescriptParsers } from 'prettier/parser-typescript';

import { preprocessor } from './preprocessor';
import { defaultPreprocessor } from './preprocessors/default';
import { vuePreprocessor } from './preprocessors/vue';
import type { PrettierOptions } from './types';

// Not sure what the type from Prettier should be, but this is a good enough start.
Expand Down Expand Up @@ -85,15 +87,19 @@ module.exports = {
parsers: {
babel: {
...babelParsers.babel,
preprocess: preprocessor,
preprocess: defaultPreprocessor,
},
flow: {
...flowParsers.flow,
preprocess: preprocessor,
preprocess: defaultPreprocessor,
},
typescript: {
...typescriptParsers.typescript,
preprocess: preprocessor,
preprocess: defaultPreprocessor,
},
vue: {
...htmlParsers.vue,
preprocess: vuePreprocessor,
},
},
options,
Expand Down
7 changes: 7 additions & 0 deletions src/preprocessors/default.ts
@@ -0,0 +1,7 @@
import { PrettierOptions } from '../types';
import { preprocessor } from './preprocessor';

export function defaultPreprocessor(code: string, options: PrettierOptions) {
if (options.filepath?.endsWith('.vue')) return code;
return preprocessor(code, options);
}
8 changes: 4 additions & 4 deletions src/preprocessor.ts → src/preprocessors/preprocessor.ts
Expand Up @@ -2,10 +2,10 @@ import { ParserOptions, parse as babelParser } from '@babel/parser';
import traverse, { NodePath } from '@babel/traverse';
import { ImportDeclaration, isTSModuleDeclaration } from '@babel/types';

import { PrettierOptions } from './types';
import { getCodeFromAst } from './utils/get-code-from-ast';
import { getExperimentalParserPlugins } from './utils/get-experimental-parser-plugins';
import { getSortedNodes } from './utils/get-sorted-nodes';
import { PrettierOptions } from '../types';
import { getCodeFromAst } from '../utils/get-code-from-ast';
import { getExperimentalParserPlugins } from '../utils/get-experimental-parser-plugins';
import { getSortedNodes } from '../utils/get-sorted-nodes';

export function preprocessor(code: string, options: PrettierOptions): string {
const {
Expand Down
12 changes: 12 additions & 0 deletions src/preprocessors/vue.ts
@@ -0,0 +1,12 @@
import { parse } from '@vue/compiler-sfc';

import { PrettierOptions } from '../types';
import { preprocessor } from './preprocessor';

export function vuePreprocessor(code: string, options: PrettierOptions) {
const { descriptor } = parse(code);
const content =
(descriptor.script ?? descriptor.scriptSetup)?.content ?? code;

return code.replace(content, `\n${preprocessor(content, options)}\n`);
}
217 changes: 217 additions & 0 deletions tests/Vue/__snapshots__/ppsi.spec.js.snap
@@ -0,0 +1,217 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`setup.vue - vue-verify: setup.vue 1`] = `
<script setup>
// I am top level comment in this file.
import z from 'z';
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";
import thirdParty from "third-party";
import oneLevelRelativePath from "../oneLevelRelativePath";
import otherthing from "@core/otherthing";
import abc from "@core/abc";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import component from "@ui/hello";
import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import something from "@server/something";
import xyz from "@ui/xyz";
import { defineComponent } from 'vue'
function add(a,b) {
return a + b;
}
</script>

<template>
<div></div>
</template>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<script setup>
// I am top level comment in this file.
import thirdParty from "third-party";
import { defineComponent } from "vue";
import z from "z";

import abc from "@core/abc";
import otherthing from "@core/otherthing";

import something from "@server/something";

import component from "@ui/hello";
import xyz from "@ui/xyz";

import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import oneLevelRelativePath from "../oneLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";

function add(a, b) {
return a + b;
}
</script>

<template>
<div></div>
</template>

`;

exports[`sfc.vue - vue-verify: sfc.vue 1`] = `
<script>
// I am top level comment in this file.
import z from 'z';
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";
import thirdParty from "third-party";
import oneLevelRelativePath from "../oneLevelRelativePath";
import otherthing from "@core/otherthing";
import abc from "@core/abc";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import component from "@ui/hello";
import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import something from "@server/something";
import xyz from "@ui/xyz";
import { defineComponent } from 'vue';
function add(a,b) {
return a + b;
}
export default defineComponent({
})
</script>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<script>
// I am top level comment in this file.
import thirdParty from "third-party";
import { defineComponent } from "vue";
import z from "z";

import abc from "@core/abc";
import otherthing from "@core/otherthing";

import something from "@server/something";

import component from "@ui/hello";
import xyz from "@ui/xyz";

import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import oneLevelRelativePath from "../oneLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";

function add(a, b) {
return a + b;
}
export default defineComponent({});
</script>

`;

exports[`ts.vue - vue-verify: ts.vue 1`] = `
<script lang="ts">
// I am top level comment in this file.
import z from 'z';
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";
import thirdParty from "third-party";
import oneLevelRelativePath from "../oneLevelRelativePath";
import otherthing from "@core/otherthing";
import abc from "@core/abc";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import component from "@ui/hello";
import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import something from "@server/something";
import xyz from "@ui/xyz";
import { defineComponent } from 'vue';
function add(a,b) {
return a + b;
}
export default defineComponent({
})
</script>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<script lang="ts">
// I am top level comment in this file.
import thirdParty from "third-party";
import { defineComponent } from "vue";
import z from "z";

import abc from "@core/abc";
import otherthing from "@core/otherthing";

import something from "@server/something";

import component from "@ui/hello";
import xyz from "@ui/xyz";

import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import oneLevelRelativePath from "../oneLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";

function add(a, b) {
return a + b;
}
export default defineComponent({});
</script>

`;

exports[`tsx.vue - vue-verify: tsx.vue 1`] = `
<script lang="tsx">
// I am top level comment in this file.
import z from 'z';
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";
import thirdParty from "third-party";
import oneLevelRelativePath from "../oneLevelRelativePath";
import otherthing from "@core/otherthing";
import abc from "@core/abc";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import component from "@ui/hello";
import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import something from "@server/something";
import xyz from "@ui/xyz";
import { defineComponent } from 'vue';
function add(a,b) {
return a + b;
}
export default defineComponent({
render() {
return <div />
}
})
</script>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<script lang="tsx">
// I am top level comment in this file.
import thirdParty from "third-party";
import { defineComponent } from "vue";
import z from "z";

import abc from "@core/abc";
import otherthing from "@core/otherthing";

import something from "@server/something";

import component from "@ui/hello";
import xyz from "@ui/xyz";

import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import oneLevelRelativePath from "../oneLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";

function add(a, b) {
return a + b;
}
export default defineComponent({
render() {
return <div />;
},
});
</script>

`;
4 changes: 4 additions & 0 deletions tests/Vue/ppsi.spec.js
@@ -0,0 +1,4 @@
run_spec(__dirname, ["vue"], {
importOrder: ['^@core/(.*)$', '^@server/(.*)', '^@ui/(.*)$', '^[./]'],
importOrderSeparation: true,
});
23 changes: 23 additions & 0 deletions tests/Vue/setup.vue
@@ -0,0 +1,23 @@
<script setup>
// I am top level comment in this file.
import z from 'z';
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";
import thirdParty from "third-party";
import oneLevelRelativePath from "../oneLevelRelativePath";
import otherthing from "@core/otherthing";
import abc from "@core/abc";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import component from "@ui/hello";
import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import something from "@server/something";
import xyz from "@ui/xyz";
import { defineComponent } from 'vue'
function add(a,b) {
return a + b;
}
</script>

<template>
<div></div>
</template>
21 changes: 21 additions & 0 deletions tests/Vue/sfc.vue
@@ -0,0 +1,21 @@
<script>
// I am top level comment in this file.
import z from 'z';
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";
import thirdParty from "third-party";
import oneLevelRelativePath from "../oneLevelRelativePath";
import otherthing from "@core/otherthing";
import abc from "@core/abc";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import component from "@ui/hello";
import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import something from "@server/something";
import xyz from "@ui/xyz";
import { defineComponent } from 'vue';
function add(a,b) {
return a + b;
}
export default defineComponent({
})
</script>
21 changes: 21 additions & 0 deletions tests/Vue/ts.vue
@@ -0,0 +1,21 @@
<script lang="ts">
// I am top level comment in this file.
import z from 'z';
import threeLevelRelativePath from "../../../threeLevelRelativePath";
import sameLevelRelativePath from "./sameLevelRelativePath";
import thirdParty from "third-party";
import oneLevelRelativePath from "../oneLevelRelativePath";
import otherthing from "@core/otherthing";
import abc from "@core/abc";
import twoLevelRelativePath from "../../twoLevelRelativePath";
import component from "@ui/hello";
import fourLevelRelativePath from "../../../../fourLevelRelativePath";
import something from "@server/something";
import xyz from "@ui/xyz";
import { defineComponent } from 'vue';
function add(a,b) {
return a + b;
}
export default defineComponent({
})
</script>