Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/fancy-days-win.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'sv': minor
---

Fixed a typo in stylelint docs
5 changes: 5 additions & 0 deletions .changeset/tame-items-post.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'sv': patch
---

Add default severity option and add docs
5 changes: 5 additions & 0 deletions .changeset/ten-cities-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'sv': minor
---

Add Stylelint as an addon
64 changes: 64 additions & 0 deletions documentation/docs/30-add-ons/42-stylelint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: stylelint
---

[Stylelint](https://stylelint.io/) is a mighty CSS linter that helps you avoid errors and enforce conventions.

## Usage

```sh
npx sv add stylelint
```

## What you get

- the relevant packages installed including `postcss-html`
- a `stylelint.config.js` file
- updated `.vscode/extensions.json`

## Options

### validate (optional)

Which files Stylelint should validate:

- `svelte` — Validate style tags inside your `.svelte` files (default)
- `css` — Validate your `.css` files (default)
- `sass` — Validate your `.sass` files
- `scss` — Validate your `.scss` files

```sh
npx sv add stylelint="validate:svelte"
```

### plugins (optional)

Whether to add other Stylelint plugins:

- `stylistic` — [`@stylistic/stylelint-plugin`](https://github.com/stylelint-stylistic/stylelint-stylistic)

```sh
npx sv add stylelint="validate:svelte,css+plugins:stylistic"
```

### save (optional)

Configure when Stylelint should run on save.

- `explicit` — Runs every time the user saves the file explicitly, such as through File > Save or Ctrl + S.
- `always` — Runs every time the file saves, regardless of through user interaction of auto save.

```sh
npx sv add stylelint="validate:svelte,css+plugins:stylistic+save:always"
```

### severity

The default warning severity of Stylelint.

- `warn` — Linter warnings should show up as a warning. (default)
- `error` — Linter warnings should show up as an error.

```sh
npx sv add stylelint="validate:svelte,css+plugins:stylistic+save:always+severity:warn"
```
154 changes: 154 additions & 0 deletions packages/sv/src/addons/stylelint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { log } from '@clack/prompts';
import { transforms } from '@sveltejs/sv-utils';
import { defineAddon, defineAddonOptions } from '../core/config.ts';

const options = defineAddonOptions()
.add('validate', {
type: 'multiselect',
question: 'What files should Stylelint validate?',
default: ['svelte', 'css'],
options: [
{ value: 'svelte', label: 'Svelte', hint: 'Lint my Svelte files.' },
{ value: 'css', label: 'CSS', hint: 'Lint my CSS files.' },
{ value: 'sass', label: 'SASS', hint: 'Lint my SASS files.' },
{ value: 'scss', label: 'SCSS', hint: 'Lint my SCSS files.' },
],
required: false
})
.add('plugins', {
type: 'multiselect',
question: 'Would you like to add other Stylelint plugins?',
default: [],
options: [
{ value: 'stylistic', label: 'Stylistic', hint: 'A formatter for your css.' },
],
required: false
})
.add('save', {
type: 'select',
question: 'When should Stylelint run on save?',
default: '',
options: [
{ value: 'explicit', label: 'Explicitly', hint: 'Only if the user manually saves.' },
{ value: 'always', label: 'Always', hint: 'Whenever your files get saved.' },
],
})
.add('severity', {
type: 'select',
question: 'What should be the default warning severity of Stylelint?',
default: 'warn',
options: [
{ value: 'warn', label: 'Warning', hint: 'Lint warning show up as a warning.' },
{ value: 'error', label: 'Error', hint: 'Lint warnings show up as an error.' },
],
})
.build();

export default defineAddon({
id: 'stylelint',
shortDescription: 'linter',
homepage: 'https://stylelint.io/',
options,
run: ({ sv, options, dependencyVersion, file }) => {
const sass = Boolean(dependencyVersion('sass'));
const stylistic = options.plugins.includes('stylistic');

sv.devDependency('stylelint', '^17.11.1');
sv.devDependency('stylelint-config-standard', '^40.0.0')
sv.devDependency('postcss', '^8.5.8');
sv.devDependency('postcss-html', '^1.8.1');

if (sass) {
sv.devDependency('postcss-scss', '^4.0.9');
sv.devDependency('stylelint-scss', '^7.1.1');
sv.devDependency('stylelint-config-standard-scss', '^17.0.0')
}

if (stylistic) {
sv.devDependency('@stylistic/stylelint-plugin', '^5.1.0');
sv.devDependency('@stylistic/stylelint-config', '^5.0.0');
}

sv.file(
file.package,
transforms.json(({ data, json }) => {
json.packageScriptsUpsert(data, 'lintcss', 'stylelint "**/*.css"');
})
);

sv.file(
'stylelint.config.js',
transforms.script(({ ast, js }) => {
if (sass) {
js.imports.addDefault(ast, { from: 'postcss-scss', as: 'postcssSass' });
}

// TODO: Add this line right after the import:
// /** @type {import('stylelint').Config} */
const sampleConfig = {
extends: ['stylelint-config-standard'],
plugins: [] as string[],
defaultSeverity: 'warning', // make option
overrides: [
{
files: ['*.svelte', '**/*.svelte'],
customSyntax: 'postcss-html'
}
],
rules: {}
};

if (options.severity.includes('error')) {
sampleConfig.defaultSeverity = 'error';
}

if (sass) {
sampleConfig.extends.push('stylelint-config-standard-scss');
sampleConfig.plugins.push('stylelint-scss');

Object.defineProperty(sampleConfig, 'customSyntax', {
value: 'postcssScss'
});
}

if (stylistic) {
sampleConfig.extends.push('@stylistic/stylelint-config');
sampleConfig.plugins.push('@stylistic/stylelint-plugin');
}

const config = js.object.create(sampleConfig);
const { value: defaultExport } = js.exports.createDefault(ast, {
fallback: config
});

// If it's not the config we created, then we'll leave it alone and exit out
if (defaultExport !== config) {
log.warn('A Stylelint config is already defined. Skipping initialization.');
return false;
}

})
);

sv.file(
'.vscode/extensions.json',
transforms.json(({ data, json }) => {
json.arrayUpsert(data, 'recommendations', 'stylelint.vscode-stylelint');

// TODO: add these as settings
// "stylelint.validate": [
// "css", options.validate.includes('css')
// "scss", options.validate.includes('scss')
// "sass", options.validate.includes('sass')
// "svelte", options.validate.includes('svelte')
// ],
// "editor.codeActionsOnSave": {
// options.save.includes('always' | 'explicit)
// "source.fixAll.stylelint": "always" | "explicit"
// },
})
);


}
});