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

feat(stylelint ✨): add stylelint test #572

Merged
merged 2 commits into from
Mar 4, 2021
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
1 change: 1 addition & 0 deletions goldens/api/@betterer/stylelint.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare function stylelint(configOverrides: Partial<Configuration>): BettererFileTest;
2 changes: 2 additions & 0 deletions lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"packages/fixture",
"packages/logger",
"packages/regexp",
"packages/stylelint",
"packages/tasks",
"packages/tsquery",
"packages/typescript"
],
Expand Down
15 changes: 0 additions & 15 deletions packages/betterer/src/results/escaper.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { swapKeyValues } from '../utils';
import { BettererExpectedResults } from './types';

// JS template string interpolation tokens
const JS_INTERP_ESCAPED = '$\\{';
const JS_INTERP_ESCAPED_REGEXP = /\$\\{/g;
const JS_INTERP_UNESCAPED = '${';
const JS_INTERP_UNESCAPED_REGEXP = /\$\{/g;

const ESCAPE_REPLACERS: Record<string, string> = {
Expand All @@ -18,19 +13,9 @@ const ESCAPE_REPLACERS: Record<string, string> = {
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};
const UNESCAPE_REPLACERS = swapKeyValues(ESCAPE_REPLACERS);

export function escape(printedValue: string): string {
return printedValue
.replace(/['`\\\b\f\r\t\u2028\u2029]/g, (char) => ESCAPE_REPLACERS[char])
.replace(JS_INTERP_UNESCAPED_REGEXP, JS_INTERP_ESCAPED);
}

export function unescape(results: BettererExpectedResults): BettererExpectedResults {
Object.keys(results).forEach((key) => {
results[key].value = results[key].value
.replace(JS_INTERP_ESCAPED_REGEXP, JS_INTERP_UNESCAPED)
.replace(/\\['`\\bfrt]|\\u2028|\\u2029/g, (char: string) => UNESCAPE_REPLACERS[char]);
});
return results;
}
5 changes: 2 additions & 3 deletions packages/betterer/src/results/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import assert from 'assert';

import { requireText } from '../require';
import { read } from '../reader';
import { unescape } from './escaper';
import { BettererExpectedResults } from './types';

const MERGE_CONFLICT_ANCESTOR = '|||||||';
Expand All @@ -20,14 +19,14 @@ export async function parse(resultsPath: string): Promise<BettererExpectedResult
if (hasMergeConflicts(file)) {
try {
const [ours, theirs] = extractConflicts(file);
return unescape({ ...requireText(ours), ...requireText(theirs) });
return { ...requireText(ours), ...requireText(theirs) };
} catch (e) {
throw new BettererError(`could not resolve merge conflict in "${resultsPath}". 😔`, e);
}
}

try {
return unescape(requireText(file));
return requireText(file);
} catch {
throw new BettererError(`could not read results from "${resultsPath}". 😔`);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/betterer/src/test/file-test/file-test-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export class BettererFileTestResultΩ implements BettererFileTestResult {
public addFile(absolutePath: string, fileText: string): BettererFile {
assert(this._resolver);
const file = new BettererFileΩ(absolutePath, createHash(fileText), this._resolver, fileText);
const existingFile = this._fileMap[absolutePath];
const existingFile = this._fileMap[file.absolutePath];
if (existingFile) {
file.addIssues(existingFile.issues);
}
this._fileMap[absolutePath] = file;
this._fileMap[file.absolutePath] = file;
return file;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/betterer/src/test/file-test/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@ type BettererIssuePositions = [number, number, number, number, string, string?];
type BettererIssueOverride = BettererIssueStartEnd | BettererIssueLineColLength | BettererIssuePositions;

export class BettererFileΩ implements BettererFile {
public readonly absolutePath: string;
public readonly key: string;

private _issues: BettererFileIssues = [];

constructor(
public readonly absolutePath: string,
absolutePath: string,
public readonly hash: string,
private _resolver: BettererFileResolver,
private _fileText: string
) {
this.absolutePath = this._resolver.resolve(absolutePath);
const { resultsPath } = getConfig();
const relativePath = getRelativePath(resultsPath, absolutePath);
this.key = `${relativePath}:${this.hash}`;
Expand Down
7 changes: 0 additions & 7 deletions packages/betterer/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,6 @@ export function flatten<T>(toFlatten: ReadonlyArray<T | ReadonlyArray<T>>): Arra
return flattened;
}

export function swapKeyValues(toSwap: Record<string, string>): Record<string, string> {
return Object.keys(toSwap).reduce((p: Record<string, string>, n: string) => {
p[toSwap[n]] = n;
return p;
}, {} as Record<string, string>);
}

function isItem<T>(pattern: unknown): pattern is T {
return !Array.isArray(pattern);
}
11 changes: 11 additions & 0 deletions packages/stylelint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[![Betterer](https://raw.githubusercontent.com/phenomnomnominal/betterer/master/website/static/img/header.png)](https://phenomnomnominal.github.io/betterer/)

# `@betterer/stylelint`

[![npm version](https://img.shields.io/npm/v/@betterer/stylelint.svg)](https://www.npmjs.com/package/@betterer/stylelint)

Stylelint test for [**`Betterer`**](https://github.com/phenomnomnominal/betterer).

## Docs

[Check out the docs at `phenomnomnominal.github.io/betterer`! 🎉](https://phenomnomnominal.github.io/betterer/docs/built-in-tests#bettererstylelint)
43 changes: 43 additions & 0 deletions packages/stylelint/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "@betterer/stylelint",
"description": "Stylelint test for @betterer/betterer",
"version": "4.0.0",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"author": "Craig Spence <[email protected]>",
"homepage": "https://phenomnomnominal.github.io/betterer",
"repository": {
"type": "git",
"url": "git+https://github.com/phenomnomnominal/betterer.git"
},
"bugs": {
"url": "https://github.com/phenomnomnominal/betterer/issues"
},
"scripts": {
"compile": "tsc -b .",
"api": "ts-api-guardian --out ../../goldens/api/@betterer/stylelint.d.ts dist/index.d.ts --allowModuleIdentifiers ts"
},
"engines": {
"node": ">=12"
},
"dependencies": {
"@betterer/betterer": "^4.0.0",
"@betterer/errors": "^4.0.0",
"tslib": "^2.0.3"
},
"devDependencies": {
"@types/stylelint": "^9.10.1",
"stylelint": "^13.11.0",
"stylelint-order": "^4.1.0"
},
"peerDependencies": {
"stylelint": "^13.0.0"
}
}
1 change: 1 addition & 0 deletions packages/stylelint/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { stylelint } from './stylelint';
31 changes: 31 additions & 0 deletions packages/stylelint/src/stylelint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { BettererFileResolver, BettererFileTest } from '@betterer/betterer';
import { BettererError } from '@betterer/errors';
import { promises as fs } from 'fs';
import { Configuration, lint } from 'stylelint';

export function stylelint(configOverrides: Partial<Configuration>): BettererFileTest {
if (!configOverrides) {
throw new BettererError(
'for `@betterer/stylelint` to work, you need to provide configuration options, e.g. `{ rules: { "unit-no-unknown": true } }`. ❌'
);
}

const resolver = new BettererFileResolver();
return new BettererFileTest(resolver, async (filePaths, fileTestResult) => {
const result = await lint({
files: [...filePaths],
configOverrides
});

await Promise.all(
result.results.map(async (result) => {
const contents = await fs.readFile(result.source, 'utf8');
const file = fileTestResult.addFile(result.source, contents);
result.warnings.forEach((warning) => {
const { line, column, text } = warning;
file.addIssue(line - 1, column - 1, line - 1, column - 1, text, text);
});
})
);
});
}
10 changes: 10 additions & 0 deletions packages/stylelint/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["./src/*.ts"],
"exclude": ["../node_modules/*", "./node_modules/*", "./dist/*"],
"references": [{ "path": "../betterer" }, { "path": "../errors" }]
}
3 changes: 3 additions & 0 deletions packages/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
{
"path": "reporter"
},
{
"path": "stylelint"
},
{
"path": "tasks"
},
Expand Down
Loading