@studiometa/stylelint-formatter-gitlab 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## v0.0.0 - 2024-05-31
10
+
11
+ First release 🎉
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Studio Meta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # StyleLint formatter for GitLab Code Quality
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/@studiometa/stylelint-formatter-gitlab.svg?style=flat-square)](https://www.npmjs.com/package/@studiometa/stylelint-formatter-gitlab/)
4
+
5
+ > Format StyleLint errors for Gitlab Code Quality reports.
6
+
7
+ ## Installation
8
+
9
+ Install the package with NPM:
10
+
11
+ ```bash
12
+ npm install -D stylelint@16 @studiometa/stylelint-formatter-gitlab
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Define a GitLab job to run `stylelint`.
18
+
19
+ _.gitlab-ci.yml_:
20
+
21
+ ```yaml
22
+ stylelint:
23
+ image: node
24
+ script:
25
+ - npm ci
26
+ - npx stylelint --custom-formatter=@studiometa/stylelint-formatter-gitlab .
27
+ artifacts:
28
+ reports:
29
+ codequality: gl-codequality.json
30
+ ```
31
+
32
+ The formatter will automatically detect a GitLab CI environment. It will detect where to output the
33
+ code quality report based on the GitLab configuration file.
34
+
35
+ ## Configuration Options
36
+
37
+ StyleLint formatters don’t take any configuration options. In order to still allow some way of
38
+ configuration, options are passed using environment variables.
39
+
40
+ | Environment Variable | Description |
41
+ | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
+ | `STYLELINT_CODE_QUALITY_REPORT` | The location to store the code quality report. By default it will detect the location of the codequality artifact defined in the GitLab CI configuration file. |
43
+ | `STYLELINT_FORMATTER` | The Stylelint formatter to use for the console output. This defaults to string, the default Stylelint formatter. |
44
+
45
+ ## Notes
46
+
47
+ This project is based on the [`stylelint-formatter-gitlab`](https://gitlab.com/leon0399/stylelint-formatter-gitlab) package which seems unmaintained and does not support StyleLint v16.
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@studiometa/stylelint-formatter-gitlab",
3
+ "version": "0.0.0",
4
+ "description": "A StyleLint formatter for the GitLab Code Quality report",
5
+ "main": "src/index.js",
6
+ "type": "module",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "files": [
11
+ "src/",
12
+ "LICENSE",
13
+ "CHANGELOG.md"
14
+ ],
15
+ "scripts": {
16
+ "test": "bun test test/",
17
+ "lint": "eslint . --cache",
18
+ "fix": "eslint . --cache --fix"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/studiometa/stylelint-formatter-gitlab.git"
23
+ },
24
+ "keywords": [
25
+ "gitlab",
26
+ "stylelint",
27
+ "formatter",
28
+ "code",
29
+ "quality"
30
+ ],
31
+ "author": "Studio Meta <agence@studiometa.fr> (https://www.studiometa.fr/)",
32
+ "license": "MIT",
33
+ "bugs": {
34
+ "url": "https://github.com/studiometa/stylelint-formatter-gitlab/issues"
35
+ },
36
+ "homepage": "https://github.com/studiometa/stylelint-formatter-gitlab#readme",
37
+ "devDependencies": {
38
+ "@studiometa/eslint-config": "^4.0.1",
39
+ "@studiometa/prettier-config": "^4.0.0",
40
+ "@studiometa/stylelint-config": "4.0.0",
41
+ "bun": "^1.1.3",
42
+ "eslint": "^9.0.0",
43
+ "prettier": "^3.2.5",
44
+ "stylelint": "16.6.1"
45
+ },
46
+ "dependencies": {
47
+ "chalk": "^5.3.0",
48
+ "jest-diff": "^29.7.0",
49
+ "js-yaml": "^4.1.0"
50
+ },
51
+ "peerDependencies": {
52
+ "stylelint": "^16.0"
53
+ }
54
+ }
package/src/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import { writeFileSync } from 'node:fs';
2
+ import stylelint from 'stylelint';
3
+ import { getOutputPath, convert, getEnv } from './utils.js';
4
+
5
+ /**
6
+ * GitLab formatter.
7
+ * @param {import('stylelint').LintResult[]} results
8
+ * @param {import('stylelint').LinterResult} returnValue
9
+ * @returns {void}
10
+ */
11
+ export default function gitlabFormatter(results, returnValue) {
12
+ const { CI_JOB_NAME, STYLELINT_CODE_QUALITY_REPORT, STYLELINT_FORMATTER } = getEnv();
13
+
14
+ if (CI_JOB_NAME || STYLELINT_CODE_QUALITY_REPORT) {
15
+ writeFileSync(
16
+ STYLELINT_CODE_QUALITY_REPORT || getOutputPath(),
17
+ JSON.stringify(convert(results), null, 2),
18
+ );
19
+ }
20
+
21
+ stylelint.formatters[STYLELINT_FORMATTER].then((fallbackFormatter) => {
22
+ console.log(fallbackFormatter(results, returnValue));
23
+ });
24
+ }
package/src/types.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ import type { Formatters } from 'stylelint';
2
+
3
+ export interface FileInfo {
4
+ filename: string;
5
+ input: string;
6
+ output: string;
7
+ isFormatted: boolean;
8
+ }
9
+
10
+ export interface CodeQualityReport {
11
+ type: 'issue';
12
+ check_name: string;
13
+ description: string;
14
+ severity: string;
15
+ fingerprint: string;
16
+ location: {
17
+ path: string;
18
+ lines: {
19
+ begin: number;
20
+ end: number;
21
+ };
22
+ };
23
+ }
24
+
25
+ export interface Env {
26
+ CI_CONFIG_PATH: string;
27
+ CI_JOB_NAME: string;
28
+ CI_PROJECT_DIR: string;
29
+ STYLELINT_CODE_QUALITY_REPORT: string;
30
+ STYLELINT_FORMATTER: keyof Formatters;
31
+ }
package/src/utils.js ADDED
@@ -0,0 +1,120 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { join, resolve, relative } from 'node:path';
3
+ import { readFileSync } from 'node:fs';
4
+ import isGlob from 'is-glob';
5
+ import yaml from 'js-yaml';
6
+
7
+ /**
8
+ * Get environment variables with sane defaults.
9
+ * @returns {import('./types.d.ts').Env}
10
+ */
11
+ export function getEnv() {
12
+ const {
13
+ // Used as a fallback for local testing.
14
+ CI_CONFIG_PATH = '.gitlab-ci.yml',
15
+ CI_JOB_NAME,
16
+ CI_PROJECT_DIR = process.cwd(),
17
+ STYLELINT_CODE_QUALITY_REPORT,
18
+ STYLELINT_FORMATTER = 'string',
19
+ } = process.env;
20
+
21
+ return {
22
+ CI_CONFIG_PATH,
23
+ CI_JOB_NAME,
24
+ CI_PROJECT_DIR,
25
+ STYLELINT_CODE_QUALITY_REPORT,
26
+ STYLELINT_FORMATTER,
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Get the output path.
32
+ * @returns {string}
33
+ */
34
+ export function getOutputPath() {
35
+ const { CI_PROJECT_DIR, CI_CONFIG_PATH, CI_JOB_NAME } = getEnv();
36
+ const jobs = yaml.load(readFileSync(join(CI_PROJECT_DIR, CI_CONFIG_PATH), 'utf-8'));
37
+ const { artifacts } = jobs[CI_JOB_NAME];
38
+ const location = artifacts && artifacts.reports && artifacts.reports.codequality;
39
+ const msg = `Expected ${CI_JOB_NAME}.artifacts.reports.codequality to be one exact path`;
40
+ if (location === null || location === undefined) {
41
+ throw new Error(`${msg}, but no value was found.`);
42
+ }
43
+ if (Array.isArray(location)) {
44
+ throw new Error(`${msg}, but found an array instead.`);
45
+ }
46
+ if (typeof location !== 'string') {
47
+ throw new Error(`${msg}, but found ${JSON.stringify(location)} instead.`);
48
+ }
49
+ if (isGlob(location)) {
50
+ throw new Error(`${msg}, but found a glob instead.`);
51
+ }
52
+ return resolve(CI_PROJECT_DIR, location);
53
+ }
54
+
55
+ /**
56
+ * Create fingerprint.
57
+ * @param {string} filePath
58
+ * @param {string} message
59
+ * @returns {string}
60
+ */
61
+ export function createFingerprint(filePath, message) {
62
+ const md5 = createHash('md5');
63
+ md5.update(filePath);
64
+ if (message.rule) {
65
+ md5.update(message.rule);
66
+ }
67
+ md5.update(message.text);
68
+ return md5.digest('hex');
69
+ }
70
+
71
+ /**
72
+ * Map severity.
73
+ * @param {string} severity
74
+ * @returns {string}
75
+ */
76
+ export function mapSeverity(severity) {
77
+ switch (severity) {
78
+ case 'error':
79
+ return 'major';
80
+ case 'warning':
81
+ return 'minor';
82
+ default:
83
+ return 'minor';
84
+ }
85
+ }
86
+
87
+ /**
88
+ * @param {import('stylelint').Warning[]} results
89
+ * @param {string} source
90
+ * @returns {import('./types.d.ts').CodeQualityReport[]}
91
+ */
92
+ function formatter(results, source) {
93
+ const { CI_PROJECT_DIR } = getEnv();
94
+ const relativePath = relative(CI_PROJECT_DIR, source);
95
+ return results.map((result) => ({
96
+ type: 'issue',
97
+ check_name: result.rule,
98
+ severity: mapSeverity(result.severity),
99
+ description: result.text,
100
+ fingerprint: createFingerprint(relativePath, result),
101
+ location: {
102
+ path: relativePath,
103
+ lines: {
104
+ begin: result.line,
105
+ end: result.line,
106
+ },
107
+ },
108
+ }));
109
+ }
110
+
111
+ /**
112
+ * @param {import('stylelint').LintResult[]} results
113
+ * @returns {object[]}
114
+ */
115
+ export function convert(results) {
116
+ return results.reduce(
117
+ (acc, result) => [...acc, ...formatter(result.warnings, result.source)],
118
+ [],
119
+ );
120
+ }