Skip to content

Commit d8df1e8

Browse files
authored
feat: add windows support (#1355)
1 parent 8e2bb0d commit d8df1e8

21 files changed

+116
-107
lines changed

.changeset/icy-rocks-camp.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'eslint-plugin-svelte': patch
3+
---
4+
5+
fix: properly support Windows in `no-unused-props` rule
6+
fix: properly support Windows in `valid-style-parse` rule
7+
fix: properly support Windows in `no-unnecessary-condition` rule

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.github/workflows/NodeCI.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ on:
99
env:
1010
project_root_path: ./packages/eslint-plugin-svelte
1111

12+
defaults:
13+
run:
14+
# Setting every runner to bash simplifies command calls;
15+
# plus, every platform supports it
16+
shell: bash
17+
1218
jobs:
1319
lint:
1420
runs-on: ubuntu-latest
@@ -51,7 +57,7 @@ jobs:
5157
runs-on: ${{ matrix.os }}
5258
strategy:
5359
matrix:
54-
os: [ubuntu-latest]
60+
os: [ubuntu-latest, windows-latest]
5561
eslint: [8, 9]
5662
node: [18.x, 20.x, 22.x, latest]
5763
steps:
@@ -84,7 +90,7 @@ jobs:
8490
runs-on: ${{ matrix.os }}
8591
strategy:
8692
matrix:
87-
os: [ubuntu-latest]
93+
os: [ubuntu-latest, windows-latest]
8894
eslint: [9]
8995
node: [18, 20, 22]
9096
steps:
@@ -115,7 +121,7 @@ jobs:
115121
runs-on: ${{ matrix.os }}
116122
strategy:
117123
matrix:
118-
os: [ubuntu-latest]
124+
os: [ubuntu-latest, windows-latest]
119125
node: [18]
120126
steps:
121127
- name: Checkout

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
"typescript.tsdk": "node_modules/typescript/lib",
1111
"[typescript]": {
1212
"editor.defaultFormatter": "esbenp.prettier-vscode"
13-
}
13+
},
14+
"files.eol": "\n"
1415
}

packages/eslint-plugin-svelte/src/rules/no-unused-props.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { TSESTree } from '@typescript-eslint/types';
44
import type ts from 'typescript';
55
import { findVariable } from '../utils/ast-utils.js';
66
import { toRegExp } from '../utils/regexp.js';
7+
import { normalize } from 'path';
78

89
type PropertyPathArray = string[];
910
type DeclaredPropertyNames = Set<{ originalName: string; aliasName: string }>;
@@ -122,7 +123,8 @@ export default createRule('no-unused-props', {
122123
const declarations = symbol.getDeclarations();
123124
if (!declarations || declarations.length === 0) return false;
124125

125-
return declarations.every((decl) => decl.getSourceFile().fileName === fileName);
126+
// TypeScript declaration file name is normalized to support Windows style paths
127+
return declarations.every((decl) => normalize(decl.getSourceFile().fileName) === fileName);
126128
}
127129

128130
/**

packages/eslint-plugin-svelte/src/rules/valid-style-parse.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createRule } from '../utils/index.js';
2+
import path from 'path';
23

34
export default createRule('valid-style-parse', {
45
meta: {
@@ -16,15 +17,20 @@ export default createRule('valid-style-parse', {
1617
if (!sourceCode.parserServices.isSvelte) {
1718
return {};
1819
}
19-
const cwd = `${context.cwd ?? process.cwd()}/`;
20+
const cwd = `${context.cwd ?? process.cwd()}${path.sep}`;
2021

2122
return {
2223
SvelteStyleElement(node) {
2324
const styleContext = sourceCode.parserServices.getStyleContext!();
2425
if (styleContext.status === 'parse-error') {
26+
// This will replace backslashes to forward slashes only
27+
// if Node.js reports Windows style path separators
28+
let message = styleContext.error.message.replace(cwd, '');
29+
if (path.sep === '\\') message = message.replace(/\\/g, '/');
30+
2531
context.report({
2632
loc: node.loc,
27-
message: `Error parsing style element. Error message: "${styleContext.error.message.replace(cwd, '')}"`
33+
message: `Error parsing style element. Error message: "${message}"`
2834
});
2935
}
3036
if (styleContext.status === 'unknown-lang') {

packages/eslint-plugin-svelte/tests/src/rules/@typescript-eslint/original-tests/no-unnecessary-condition.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
// https://github.com/typescript-eslint/typescript-eslint/blob/78467fc1bde9bd2db1e08b3d19f151f4adaff8a9/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts
33
/* eslint func-style: off, eslint-plugin/consistent-output: off -- respect original */
44
import * as path from 'path';
5+
import { fileURLToPath } from 'url';
56
import { RuleTester } from '../../../../utils/eslint-compat.js';
67
import type * as eslint from 'eslint';
78
import * as typescriptParser from '@typescript-eslint/parser';
89

910
import rule from '../../../../../src/rules/@typescript-eslint/no-unnecessary-condition.js';
1011

11-
const __dirname = path.dirname(new URL(import.meta.url).pathname);
12+
const url = new URL(import.meta.url);
13+
const __dirname = path.dirname(fileURLToPath(url));
1214

1315
function getFixturesRootDir(): string {
1416
return path.join(__dirname, 'fixtures');

packages/eslint-plugin-svelte/tests/utils/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import * as svelteParser from 'svelte-eslint-parser';
1212
import * as typescriptParser from '@typescript-eslint/parser';
1313
import Module from 'module';
1414
import globals from 'globals';
15+
import { fileURLToPath } from 'url';
1516

16-
const __dirname = path.dirname(new URL(import.meta.url).pathname);
17+
const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url)));
1718
const require = Module.createRequire(import.meta.url);
1819

1920
/**
@@ -304,7 +305,8 @@ function writeFixtures(
304305
}
305306

306307
function getConfig(ruleName: string, inputFile: string) {
307-
const filename = inputFile.slice(inputFile.indexOf(ruleName));
308+
// ruleName is normalized to support Windows style paths
309+
const filename = inputFile.slice(inputFile.indexOf(path.normalize(ruleName)));
308310
const code = fs.readFileSync(inputFile, 'utf8');
309311
let config;
310312
let configFile = [
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import getReleasePlan from '@changesets/get-release-plan';
2-
import path from 'path';
2+
import { fileURLToPath } from 'url';
33

4-
const __dirname = path.dirname(new URL(import.meta.url).pathname);
4+
const cwdURL = new URL('../../../..', import.meta.url);
55

66
/** Get new version string from changesets */
77
export async function getNewVersion(): Promise<string> {
8-
const releasePlan = await getReleasePlan(path.resolve(__dirname, '../../../..'));
8+
const releasePlan = await getReleasePlan(fileURLToPath(cwdURL));
99

1010
return releasePlan.releases.find(({ name }) => name === 'eslint-plugin-svelte')!.newVersion;
1111
}

packages/eslint-plugin-svelte/tools/lib/load-rules.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@ import path from 'path';
22
import fs from 'fs';
33
import type { RuleModule } from '../../src/types.js';
44

5-
const __dirname = path.dirname(new URL(import.meta.url).pathname);
5+
const rulesLibRootURL = new URL('../../src/rules/', import.meta.url);
66

77
/**
88
* Get the all rules
99
* @returns {Array} The all rules
1010
*/
1111
async function readRules() {
12-
const rulesLibRoot = path.resolve(__dirname, '../../src/rules');
1312
const rules: RuleModule[] = [];
1413
for (const name of iterateTsFiles()) {
15-
const module = await import(path.join(rulesLibRoot, name));
14+
const module = await import(new URL(name, rulesLibRootURL).href);
1615
const rule: RuleModule = module && module.default;
1716
if (!rule || typeof rule.create !== 'function') {
1817
continue;
@@ -27,19 +26,18 @@ export const rules = await readRules();
2726

2827
/** Iterate ts files */
2928
function* iterateTsFiles() {
30-
const rulesLibRoot = path.resolve(__dirname, '../../src/rules');
31-
const files = fs.readdirSync(rulesLibRoot);
29+
const files = fs.readdirSync(rulesLibRootURL);
3230

3331
while (files.length) {
3432
const file = files.shift()!;
3533
if (file.endsWith('.ts')) {
3634
yield file;
3735
continue;
3836
}
39-
const filePath = path.join(rulesLibRoot, file);
40-
if (!fs.statSync(filePath).isDirectory()) {
37+
const filePathURL = new URL(file, rulesLibRootURL);
38+
if (!fs.statSync(filePathURL).isDirectory()) {
4139
continue;
4240
}
43-
files.unshift(...fs.readdirSync(filePath).map((n) => path.join(file, n)));
41+
files.unshift(...fs.readdirSync(filePathURL).map((n) => path.join(file, n)));
4442
}
4543
}

0 commit comments

Comments
 (0)