@codebend3r/gale 0.2.0 → 0.2.2
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/README.md +1 -1
- package/bin/aarch64-apple-darwin/gale +0 -0
- package/bin/aarch64-unknown-linux-gnu/gale +0 -0
- package/bin/gale.cjs +52 -0
- package/bin/x86_64-apple-darwin/gale +0 -0
- package/bin/x86_64-unknown-linux-gnu/gale +0 -0
- package/index.d.ts +152 -0
- package/index.mjs +21 -4
- package/package.json +10 -6
- package/platform.cjs +49 -0
- package/test.mjs +76 -25
- package/bin/gale +0 -54
package/README.md
CHANGED
|
@@ -27,4 +27,4 @@ console.log(result.errored);
|
|
|
27
27
|
console.log(result.results);
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
See the full documentation at [github.com/
|
|
30
|
+
See the full documentation at [github.com/codebend3r/gale](https://github.com/codebend3r/gale).
|
|
Binary file
|
|
Binary file
|
package/bin/gale.cjs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Launches the bundled Gale binary for this platform.
|
|
6
|
+
*
|
|
7
|
+
* A Node script rather than a shell script so the same launcher works on
|
|
8
|
+
* Windows, where npm wraps it in a .cmd shim. Everything is forwarded: the
|
|
9
|
+
* arguments, stdin/stdout/stderr, the exit code, and any terminating signal.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { spawnSync } = require("node:child_process");
|
|
13
|
+
const { existsSync } = require("node:fs");
|
|
14
|
+
const path = require("node:path");
|
|
15
|
+
|
|
16
|
+
const { binaryFileName, resolveTarget, supportedPlatforms } = require("../platform.cjs");
|
|
17
|
+
|
|
18
|
+
const target = resolveTarget(process.platform, process.arch);
|
|
19
|
+
|
|
20
|
+
if (!target) {
|
|
21
|
+
process.stderr.write(`Unsupported platform: ${process.platform}-${process.arch}\n`);
|
|
22
|
+
process.stderr.write(`Supported: ${supportedPlatforms().join(", ")}\n`);
|
|
23
|
+
process.stderr.write("Build from source instead: cargo install gale-lint\n");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const binary = path.join(__dirname, target, binaryFileName(process.platform));
|
|
28
|
+
|
|
29
|
+
if (!existsSync(binary)) {
|
|
30
|
+
process.stderr.write(`Gale binary missing for ${target} at ${binary}\n`);
|
|
31
|
+
process.stderr.write(`This package should ship prebuilt binaries for ${target}.\n`);
|
|
32
|
+
process.stderr.write("Try reinstalling the package, or build from source:\n");
|
|
33
|
+
process.stderr.write(" cargo install gale-lint\n");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const result = spawnSync(binary, process.argv.slice(2), {
|
|
38
|
+
stdio: "inherit",
|
|
39
|
+
windowsHide: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (result.error) {
|
|
43
|
+
process.stderr.write(`Failed to run ${binary}: ${result.error.message}\n`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (result.signal) {
|
|
48
|
+
// Re-raise so the parent sees the same signal the linter died from.
|
|
49
|
+
process.kill(process.pid, result.signal);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
process.exit(result.status ?? 1);
|
|
Binary file
|
|
Binary file
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for @codebend3r/gale.
|
|
3
|
+
*
|
|
4
|
+
* The shapes mirror Stylelint's public API so a project can swap the import
|
|
5
|
+
* without touching its call sites. Fields Gale never populates are typed as
|
|
6
|
+
* they are in Stylelint but are always empty.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type Severity = "error" | "warning";
|
|
10
|
+
|
|
11
|
+
export type FormatterType = "string" | "json" | "compact" | "verbose" | "tap" | "unix";
|
|
12
|
+
|
|
13
|
+
/** A single problem reported for a source. */
|
|
14
|
+
export interface Warning {
|
|
15
|
+
line: number;
|
|
16
|
+
column: number;
|
|
17
|
+
endLine?: number;
|
|
18
|
+
endColumn?: number;
|
|
19
|
+
rule: string;
|
|
20
|
+
severity: Severity;
|
|
21
|
+
/** The message with ` (rule-name)` appended, as Stylelint prints it. */
|
|
22
|
+
text: string;
|
|
23
|
+
/** Present when the rule's `url` secondary option is set. */
|
|
24
|
+
url?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The result of linting one source. */
|
|
28
|
+
export interface LintResult {
|
|
29
|
+
source: string;
|
|
30
|
+
warnings: Warning[];
|
|
31
|
+
/** Always empty: Gale reports no deprecations. */
|
|
32
|
+
deprecations: unknown[];
|
|
33
|
+
/** Always empty: Gale does not validate rule options. */
|
|
34
|
+
invalidOptionWarnings: unknown[];
|
|
35
|
+
/** Always empty: parse errors surface as `parse-error` warnings. */
|
|
36
|
+
parseErrors: unknown[];
|
|
37
|
+
errored: boolean;
|
|
38
|
+
ignored: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface MaxWarningsExceeded {
|
|
42
|
+
maxWarnings: number;
|
|
43
|
+
foundWarnings: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** What `lint()` resolves to. */
|
|
47
|
+
export interface LinterResult {
|
|
48
|
+
cwd: string;
|
|
49
|
+
results: LintResult[];
|
|
50
|
+
errored: boolean;
|
|
51
|
+
/** The formatted report, in the formatter requested (JSON by default). */
|
|
52
|
+
report: string;
|
|
53
|
+
/** The fixed source when `fix` and `code` were both given. */
|
|
54
|
+
code?: string;
|
|
55
|
+
maxWarningsExceeded?: MaxWarningsExceeded;
|
|
56
|
+
/** Always empty: Gale exposes no per-rule metadata. */
|
|
57
|
+
ruleMetadata: Record<string, never>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type FormatterFunction = (
|
|
61
|
+
results: LintResult[],
|
|
62
|
+
returnValue: { cwd: string; results: LintResult[]; errored: boolean },
|
|
63
|
+
) => string;
|
|
64
|
+
|
|
65
|
+
/** Rule settings in any of Stylelint's accepted shapes. */
|
|
66
|
+
export type RuleSetting = boolean | null | string | number | unknown[];
|
|
67
|
+
|
|
68
|
+
export interface Config {
|
|
69
|
+
extends?: string | string[];
|
|
70
|
+
plugins?: string[];
|
|
71
|
+
rules?: Record<string, RuleSetting>;
|
|
72
|
+
overrides?: unknown[];
|
|
73
|
+
ignoreFiles?: string | string[];
|
|
74
|
+
ignorePatterns?: string | string[];
|
|
75
|
+
customSyntax?: string;
|
|
76
|
+
defaultSeverity?: Severity;
|
|
77
|
+
ignoreDisables?: boolean;
|
|
78
|
+
reportNeedlessDisables?: boolean;
|
|
79
|
+
reportInvalidScopeDisables?: boolean;
|
|
80
|
+
reportDescriptionlessDisables?: boolean;
|
|
81
|
+
reportUnscopedDisables?: boolean;
|
|
82
|
+
allowEmptyInput?: boolean;
|
|
83
|
+
quiet?: boolean;
|
|
84
|
+
fix?: boolean | "strict" | "lax";
|
|
85
|
+
cache?: boolean;
|
|
86
|
+
cacheLocation?: string;
|
|
87
|
+
[key: string]: unknown;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface LinterOptions {
|
|
91
|
+
/** Glob pattern(s) for files to lint. */
|
|
92
|
+
files?: string | string[];
|
|
93
|
+
/** CSS source to lint instead of files. */
|
|
94
|
+
code?: string;
|
|
95
|
+
/** Virtual filename for `code`, used for syntax detection. */
|
|
96
|
+
codeFilename?: string;
|
|
97
|
+
/** Inline config object. */
|
|
98
|
+
config?: Config;
|
|
99
|
+
/** Path to a config file. */
|
|
100
|
+
configFile?: string;
|
|
101
|
+
fix?: boolean | "strict" | "lax";
|
|
102
|
+
formatter?: FormatterType | FormatterFunction;
|
|
103
|
+
quiet?: boolean;
|
|
104
|
+
cache?: boolean;
|
|
105
|
+
cacheLocation?: string;
|
|
106
|
+
maxWarnings?: number;
|
|
107
|
+
allowEmptyInput?: boolean;
|
|
108
|
+
ignorePath?: string;
|
|
109
|
+
ignoreDisables?: boolean;
|
|
110
|
+
reportNeedlessDisables?: boolean;
|
|
111
|
+
reportInvalidScopeDisables?: boolean;
|
|
112
|
+
reportDescriptionlessDisables?: boolean;
|
|
113
|
+
/** Working directory; defaults to `process.cwd()`. */
|
|
114
|
+
cwd?: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Lint files or a code string and resolve with a Stylelint-shaped result. */
|
|
118
|
+
export function lint(options?: LinterOptions): Promise<LinterResult>;
|
|
119
|
+
|
|
120
|
+
/** Resolve the effective config for a file, or `undefined` when none applies. */
|
|
121
|
+
export function resolveConfig(
|
|
122
|
+
filePath: string,
|
|
123
|
+
options?: { configFile?: string; cwd?: string },
|
|
124
|
+
): Promise<Config | undefined>;
|
|
125
|
+
|
|
126
|
+
/** Promise-based formatter functions keyed by name, like `stylelint.formatters`. */
|
|
127
|
+
export const formatters: {
|
|
128
|
+
readonly json: Promise<FormatterFunction>;
|
|
129
|
+
readonly string: Promise<FormatterFunction>;
|
|
130
|
+
readonly compact: Promise<FormatterFunction>;
|
|
131
|
+
readonly verbose: Promise<FormatterFunction>;
|
|
132
|
+
readonly tap: Promise<FormatterFunction>;
|
|
133
|
+
readonly unix: Promise<FormatterFunction>;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Compatibility stub. Gale runs built-in Rust rules and cannot execute a
|
|
138
|
+
* JavaScript rule; calling this warns and returns an inert plugin object.
|
|
139
|
+
*/
|
|
140
|
+
export function createPlugin(
|
|
141
|
+
ruleName: string,
|
|
142
|
+
ruleFunction: (...args: unknown[]) => unknown,
|
|
143
|
+
): { ruleName: string; rule: (...args: unknown[]) => unknown };
|
|
144
|
+
|
|
145
|
+
declare const _default: {
|
|
146
|
+
lint: typeof lint;
|
|
147
|
+
formatters: typeof formatters;
|
|
148
|
+
resolveConfig: typeof resolveConfig;
|
|
149
|
+
createPlugin: typeof createPlugin;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export default _default;
|
package/index.mjs
CHANGED
|
@@ -12,6 +12,8 @@ import { tmpdir } from "node:os";
|
|
|
12
12
|
import { randomBytes } from "node:crypto";
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
14
|
|
|
15
|
+
import { binaryFileName, resolveTarget } from "./platform.cjs";
|
|
16
|
+
|
|
15
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
16
18
|
const __dirname = dirname(__filename);
|
|
17
19
|
|
|
@@ -20,10 +22,20 @@ const __dirname = dirname(__filename);
|
|
|
20
22
|
// ---------------------------------------------------------------------------
|
|
21
23
|
|
|
22
24
|
function findBinary() {
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// 0. An explicit override wins. Test suites and monorepos use this to point
|
|
26
|
+
// at a freshly built binary instead of the bundled one.
|
|
27
|
+
const override = process.env.GALE_BINARY;
|
|
28
|
+
if (override) {
|
|
29
|
+
return override;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 1. The binary bundled for this platform inside the npm package
|
|
33
|
+
const target = resolveTarget(process.platform, process.arch);
|
|
34
|
+
if (target) {
|
|
35
|
+
const bundled = join(__dirname, "bin", target, binaryFileName(process.platform));
|
|
36
|
+
if (existsSync(bundled)) {
|
|
37
|
+
return bundled;
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
// 2. Fall back to gale on PATH
|
|
@@ -122,9 +134,14 @@ function parseJsonOutput(jsonString) {
|
|
|
122
134
|
warnings: (entry.warnings || []).map((w) => ({
|
|
123
135
|
line: w.line,
|
|
124
136
|
column: w.column,
|
|
137
|
+
endLine: w.endLine,
|
|
138
|
+
endColumn: w.endColumn,
|
|
125
139
|
rule: w.rule,
|
|
126
140
|
severity: w.severity || "warning",
|
|
127
141
|
text: w.text,
|
|
142
|
+
// Only present when the rule's `url` secondary option is set, as in
|
|
143
|
+
// Stylelint, where an undefined url is dropped by JSON.stringify.
|
|
144
|
+
...(w.url !== undefined ? { url: w.url } : {}),
|
|
128
145
|
})),
|
|
129
146
|
deprecations: [],
|
|
130
147
|
invalidOptionWarnings: [],
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codebend3r/gale",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "An extremely fast CSS linter, written in Rust. Drop-in replacement for Stylelint.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/
|
|
8
|
+
"url": "https://github.com/codebend3r/gale"
|
|
9
9
|
},
|
|
10
|
-
"homepage": "https://github.com/
|
|
11
|
-
"bugs": "https://github.com/
|
|
10
|
+
"homepage": "https://github.com/codebend3r/gale",
|
|
11
|
+
"bugs": "https://github.com/codebend3r/gale/issues",
|
|
12
12
|
"keywords": [
|
|
13
13
|
"css",
|
|
14
14
|
"linter",
|
|
@@ -22,24 +22,28 @@
|
|
|
22
22
|
],
|
|
23
23
|
"type": "module",
|
|
24
24
|
"main": "index.mjs",
|
|
25
|
+
"types": "index.d.ts",
|
|
25
26
|
"exports": {
|
|
26
27
|
".": {
|
|
28
|
+
"types": "./index.d.ts",
|
|
27
29
|
"import": "./index.mjs",
|
|
28
30
|
"require": "./index.cjs"
|
|
29
31
|
}
|
|
30
32
|
},
|
|
31
33
|
"bin": {
|
|
32
|
-
"gale": "bin/gale"
|
|
34
|
+
"gale": "bin/gale.cjs"
|
|
33
35
|
},
|
|
34
36
|
"files": [
|
|
35
37
|
"bin/",
|
|
36
38
|
"index.cjs",
|
|
39
|
+
"index.d.ts",
|
|
37
40
|
"index.mjs",
|
|
41
|
+
"platform.cjs",
|
|
38
42
|
"test.mjs",
|
|
39
43
|
"README.md"
|
|
40
44
|
],
|
|
41
45
|
"engines": {
|
|
42
|
-
"node": ">=
|
|
46
|
+
"node": ">=20.0.0"
|
|
43
47
|
},
|
|
44
48
|
"scripts": {
|
|
45
49
|
"test": "node test.mjs"
|
package/platform.cjs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Maps a Node.js platform and architecture to the Rust target whose binary
|
|
5
|
+
* ships inside this package, and names the binary for that platform.
|
|
6
|
+
*
|
|
7
|
+
* Shared by the `gale` launcher and the programmatic API. CommonJS so the
|
|
8
|
+
* launcher can require it synchronously on every supported Node version.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const TARGETS = {
|
|
12
|
+
"darwin-arm64": "aarch64-apple-darwin",
|
|
13
|
+
"darwin-x64": "x86_64-apple-darwin",
|
|
14
|
+
"linux-arm64": "aarch64-unknown-linux-gnu",
|
|
15
|
+
"linux-x64": "x86_64-unknown-linux-gnu",
|
|
16
|
+
"win32-arm64": "aarch64-pc-windows-msvc",
|
|
17
|
+
"win32-x64": "x86_64-pc-windows-msvc",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The Rust target triple for a platform/arch pair, or `null` when Gale does
|
|
22
|
+
* not ship a binary for it.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} platform - `process.platform`
|
|
25
|
+
* @param {string} arch - `process.arch`
|
|
26
|
+
* @returns {string | null}
|
|
27
|
+
*/
|
|
28
|
+
function resolveTarget(platform, arch) {
|
|
29
|
+
return TARGETS[`${platform}-${arch}`] ?? null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The file name of the Gale binary on a platform.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} platform - `process.platform`
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function binaryFileName(platform) {
|
|
39
|
+
return platform === "win32" ? "gale.exe" : "gale";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Every `platform-arch` pair a binary ships for, for error messages. */
|
|
43
|
+
function supportedPlatforms() {
|
|
44
|
+
return Object.keys(TARGETS);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
exports.resolveTarget = resolveTarget;
|
|
48
|
+
exports.binaryFileName = binaryFileName;
|
|
49
|
+
exports.supportedPlatforms = supportedPlatforms;
|
package/test.mjs
CHANGED
|
@@ -8,18 +8,45 @@
|
|
|
8
8
|
* Requires a working gale binary (either in npm/bin/ or on PATH).
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { createRequire } from "node:module";
|
|
12
|
+
|
|
11
13
|
import { lint, formatters, resolveConfig, createPlugin } from "./index.mjs";
|
|
12
14
|
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
|
|
13
17
|
let passed = 0;
|
|
14
18
|
let failed = 0;
|
|
19
|
+
let current = "";
|
|
20
|
+
|
|
21
|
+
// Dots reporter: one "." per passing assertion, "F" per failure. Failure
|
|
22
|
+
// details are printed on their own line so the dots stay readable.
|
|
23
|
+
function section(name) {
|
|
24
|
+
current = name;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function fail(message) {
|
|
28
|
+
process.stdout.write("F");
|
|
29
|
+
console.error(`\n FAIL [${current}] ${message}`);
|
|
30
|
+
failed++;
|
|
31
|
+
}
|
|
15
32
|
|
|
16
33
|
function assert(condition, message) {
|
|
17
34
|
if (condition) {
|
|
18
|
-
|
|
35
|
+
process.stdout.write(".");
|
|
19
36
|
passed++;
|
|
20
37
|
} else {
|
|
21
|
-
|
|
22
|
-
|
|
38
|
+
fail(message);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Runs fn with console.warn muted, for APIs that warn by design.
|
|
43
|
+
function quietly(fn) {
|
|
44
|
+
const warn = console.warn;
|
|
45
|
+
console.warn = () => {};
|
|
46
|
+
try {
|
|
47
|
+
return fn();
|
|
48
|
+
} finally {
|
|
49
|
+
console.warn = warn;
|
|
23
50
|
}
|
|
24
51
|
}
|
|
25
52
|
|
|
@@ -28,7 +55,7 @@ function assert(condition, message) {
|
|
|
28
55
|
// ---------------------------------------------------------------------------
|
|
29
56
|
|
|
30
57
|
async function testLintCodeEmptyBlock() {
|
|
31
|
-
|
|
58
|
+
section("Test 1: lint({ code: 'a {}' })");
|
|
32
59
|
|
|
33
60
|
try {
|
|
34
61
|
const result = await lint({ code: "a {}" });
|
|
@@ -50,8 +77,7 @@ async function testLintCodeEmptyBlock() {
|
|
|
50
77
|
assert(typeof first.ignored === "boolean", "first result has ignored boolean");
|
|
51
78
|
}
|
|
52
79
|
} catch (err) {
|
|
53
|
-
|
|
54
|
-
failed++;
|
|
80
|
+
fail(`ERROR: ${err.message}`);
|
|
55
81
|
}
|
|
56
82
|
}
|
|
57
83
|
|
|
@@ -60,7 +86,7 @@ async function testLintCodeEmptyBlock() {
|
|
|
60
86
|
// ---------------------------------------------------------------------------
|
|
61
87
|
|
|
62
88
|
async function testLintCodeWithConfig() {
|
|
63
|
-
|
|
89
|
+
section("Test 2: lint({ code: 'a { color: pink; }', config: { rules: { 'color-named': 'never' } } })");
|
|
64
90
|
|
|
65
91
|
try {
|
|
66
92
|
const result = await lint({
|
|
@@ -86,13 +112,10 @@ async function testLintCodeWithConfig() {
|
|
|
86
112
|
w.rule === "color-named",
|
|
87
113
|
`warning rule is "color-named" (got "${w.rule}")`,
|
|
88
114
|
);
|
|
89
|
-
} else {
|
|
90
|
-
console.log(" INFO: No warnings returned (gale may not flag this without config).");
|
|
91
115
|
}
|
|
92
116
|
}
|
|
93
117
|
} catch (err) {
|
|
94
|
-
|
|
95
|
-
failed++;
|
|
118
|
+
fail(`ERROR: ${err.message}`);
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
121
|
|
|
@@ -101,7 +124,7 @@ async function testLintCodeWithConfig() {
|
|
|
101
124
|
// ---------------------------------------------------------------------------
|
|
102
125
|
|
|
103
126
|
async function testResolveConfig() {
|
|
104
|
-
|
|
127
|
+
section("Test 3: resolveConfig('test.css')");
|
|
105
128
|
|
|
106
129
|
try {
|
|
107
130
|
const config = await resolveConfig("test.css");
|
|
@@ -111,8 +134,7 @@ async function testResolveConfig() {
|
|
|
111
134
|
"resolveConfig returns object or undefined",
|
|
112
135
|
);
|
|
113
136
|
} catch (err) {
|
|
114
|
-
|
|
115
|
-
failed++;
|
|
137
|
+
fail(`ERROR: ${err.message}`);
|
|
116
138
|
}
|
|
117
139
|
}
|
|
118
140
|
|
|
@@ -121,7 +143,7 @@ async function testResolveConfig() {
|
|
|
121
143
|
// ---------------------------------------------------------------------------
|
|
122
144
|
|
|
123
145
|
async function testFormattersJson() {
|
|
124
|
-
|
|
146
|
+
section("Test 4: formatters.json resolves to a function");
|
|
125
147
|
|
|
126
148
|
try {
|
|
127
149
|
const jsonFormatter = await formatters.json;
|
|
@@ -144,8 +166,7 @@ async function testFormattersJson() {
|
|
|
144
166
|
const parsed = JSON.parse(output);
|
|
145
167
|
assert(Array.isArray(parsed), "JSON formatter output is parseable as array");
|
|
146
168
|
} catch (err) {
|
|
147
|
-
|
|
148
|
-
failed++;
|
|
169
|
+
fail(`ERROR: ${err.message}`);
|
|
149
170
|
}
|
|
150
171
|
}
|
|
151
172
|
|
|
@@ -154,9 +175,9 @@ async function testFormattersJson() {
|
|
|
154
175
|
// ---------------------------------------------------------------------------
|
|
155
176
|
|
|
156
177
|
async function testCreatePlugin() {
|
|
157
|
-
|
|
178
|
+
section("Test 5: createPlugin returns stub");
|
|
158
179
|
|
|
159
|
-
const plugin = createPlugin("my-rule", () => {});
|
|
180
|
+
const plugin = quietly(() => createPlugin("my-rule", () => {}));
|
|
160
181
|
assert(plugin.ruleName === "my-rule", 'plugin.ruleName is "my-rule"');
|
|
161
182
|
assert(typeof plugin.rule === "function", "plugin.rule is a function");
|
|
162
183
|
}
|
|
@@ -166,7 +187,7 @@ async function testCreatePlugin() {
|
|
|
166
187
|
// ---------------------------------------------------------------------------
|
|
167
188
|
|
|
168
189
|
async function testLinterResultShape() {
|
|
169
|
-
|
|
190
|
+
section("Test 6: LinterResult has correct shape");
|
|
170
191
|
|
|
171
192
|
try {
|
|
172
193
|
const result = await lint({ code: "a { color: red; }" });
|
|
@@ -179,8 +200,39 @@ async function testLinterResultShape() {
|
|
|
179
200
|
assert("maxWarningsExceeded" in result, "result has maxWarningsExceeded key");
|
|
180
201
|
assert("code" in result, "result has code key");
|
|
181
202
|
} catch (err) {
|
|
182
|
-
|
|
183
|
-
|
|
203
|
+
fail(`ERROR: ${err.message}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
// Test 7: CommonJS entry point bridges to the ESM implementation
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
|
|
211
|
+
async function testCommonJsEntry() {
|
|
212
|
+
section("Test 7: require('./index.cjs') exposes the same API");
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
const cjs = require("./index.cjs");
|
|
216
|
+
|
|
217
|
+
assert(typeof cjs.lint === "function", "cjs.lint is a function");
|
|
218
|
+
assert(typeof cjs.resolveConfig === "function", "cjs.resolveConfig is a function");
|
|
219
|
+
assert(typeof cjs.createPlugin === "function", "cjs.createPlugin is a function");
|
|
220
|
+
assert(cjs.default === cjs, "cjs.default points back at module.exports");
|
|
221
|
+
|
|
222
|
+
const jsonFormatter = await cjs.formatters.json;
|
|
223
|
+
assert(typeof jsonFormatter === "function", "cjs.formatters.json resolves to a function");
|
|
224
|
+
|
|
225
|
+
const result = await cjs.lint({
|
|
226
|
+
code: "a {}",
|
|
227
|
+
config: { rules: { "block-no-empty": true } },
|
|
228
|
+
});
|
|
229
|
+
assert(Array.isArray(result.results), "cjs.lint returns results");
|
|
230
|
+
assert(
|
|
231
|
+
result.results[0]?.warnings[0]?.rule === "block-no-empty",
|
|
232
|
+
"cjs.lint reports block-no-empty",
|
|
233
|
+
);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
fail(`ERROR: ${err.message}`);
|
|
184
236
|
}
|
|
185
237
|
}
|
|
186
238
|
|
|
@@ -189,16 +241,15 @@ async function testLinterResultShape() {
|
|
|
189
241
|
// ---------------------------------------------------------------------------
|
|
190
242
|
|
|
191
243
|
async function main() {
|
|
192
|
-
console.log("=== @codebend3r/gale programmatic API tests ===");
|
|
193
|
-
|
|
194
244
|
await testLintCodeEmptyBlock();
|
|
195
245
|
await testLintCodeWithConfig();
|
|
196
246
|
await testResolveConfig();
|
|
197
247
|
await testFormattersJson();
|
|
198
248
|
await testCreatePlugin();
|
|
199
249
|
await testLinterResultShape();
|
|
250
|
+
await testCommonJsEntry();
|
|
200
251
|
|
|
201
|
-
console.log(`\n
|
|
252
|
+
console.log(`\n${passed} passed, ${failed} failed (Node ${process.versions.node})`);
|
|
202
253
|
|
|
203
254
|
if (failed > 0) {
|
|
204
255
|
process.exit(1);
|
package/bin/gale
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
|
|
3
|
-
set -eu
|
|
4
|
-
|
|
5
|
-
platform="$(uname -s)-$(uname -m)"
|
|
6
|
-
|
|
7
|
-
case "$platform" in
|
|
8
|
-
Darwin-arm64)
|
|
9
|
-
target="aarch64-apple-darwin"
|
|
10
|
-
;;
|
|
11
|
-
Darwin-x86_64)
|
|
12
|
-
target="x86_64-apple-darwin"
|
|
13
|
-
;;
|
|
14
|
-
Linux-aarch64|Linux-arm64)
|
|
15
|
-
target="aarch64-unknown-linux-gnu"
|
|
16
|
-
;;
|
|
17
|
-
Linux-x86_64)
|
|
18
|
-
target="x86_64-unknown-linux-gnu"
|
|
19
|
-
;;
|
|
20
|
-
*)
|
|
21
|
-
echo "Unsupported platform: $platform" >&2
|
|
22
|
-
echo "Supported: Darwin-arm64, Darwin-x86_64, Linux-aarch64, Linux-x86_64" >&2
|
|
23
|
-
exit 1
|
|
24
|
-
;;
|
|
25
|
-
esac
|
|
26
|
-
|
|
27
|
-
script="$0"
|
|
28
|
-
|
|
29
|
-
while [ -L "$script" ]; do
|
|
30
|
-
script_dir="$(CDPATH= cd "$(dirname "$script")" && pwd)"
|
|
31
|
-
link="$(readlink "$script")"
|
|
32
|
-
|
|
33
|
-
case "$link" in
|
|
34
|
-
/*)
|
|
35
|
-
script="$link"
|
|
36
|
-
;;
|
|
37
|
-
*)
|
|
38
|
-
script="$script_dir/$link"
|
|
39
|
-
;;
|
|
40
|
-
esac
|
|
41
|
-
done
|
|
42
|
-
|
|
43
|
-
bin_dir="$(CDPATH= cd "$(dirname "$script")" && pwd)"
|
|
44
|
-
binary="$bin_dir/$target/gale"
|
|
45
|
-
|
|
46
|
-
if [ ! -x "$binary" ]; then
|
|
47
|
-
echo "Gale binary missing for $target at $binary" >&2
|
|
48
|
-
echo "This package should ship prebuilt binaries for $target." >&2
|
|
49
|
-
echo "Try reinstalling the package, or build from source:" >&2
|
|
50
|
-
echo " cargo install gale-lint" >&2
|
|
51
|
-
exit 1
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
exec "$binary" "$@"
|