@brnshkr/config 0.0.1-beta.1 → 0.0.1-beta.3
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 +55 -7
- package/conf/tsconfig.json +1 -0
- package/dist/eslint/index.d.mts +11 -0
- package/dist/eslint/index.mjs +242 -60
- package/dist/scripts/stylelint.mjs +2 -0
- package/dist/shared.mjs +2 -4
- package/dist/stylelint/index.mjs +13 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -190,7 +190,7 @@ bun eslint --config ./conf/eslint.config.mjs --cache --cache-location ./.cache/e
|
|
|
190
190
|
Example call, adjust as needed
|
|
191
191
|
|
|
192
192
|
```sh
|
|
193
|
-
bun stylelint --config ./conf/stylelint.config.mjs --cache --cache-location ./.cache/stylelint.cache.json **/*.{css,ejs,html,less,postcss,scss,svelte,svg,vue}
|
|
193
|
+
bun stylelint --config ./conf/stylelint.config.mjs --config-basedir ./ --cache --cache-location ./.cache/stylelint.cache.json **/*.{css,ejs,html,less,postcss,scss,svelte,svg,vue}
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
<!-- omit in toc -->
|
|
@@ -275,7 +275,7 @@ Here are some frequently used examples:
|
|
|
275
275
|
#### Composer
|
|
276
276
|
|
|
277
277
|
```sh
|
|
278
|
-
composer
|
|
278
|
+
composer r --dev brnshkr/config
|
|
279
279
|
```
|
|
280
280
|
|
|
281
281
|
This repository provides two ways to integrate configuration files and setup tools into your project:
|
|
@@ -336,6 +336,15 @@ cp -v ./vendor/brnshkr/config/conf/phpstan.php.example ./conf/phpstan.php \
|
|
|
336
336
|
&& cp -v ./vendor/brnshkr/config/conf/phpstan.dist.php.example ./conf/phpstan.dist.php
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
+
<!-- omit in toc -->
|
|
340
|
+
##### Twig CS Fixer
|
|
341
|
+
|
|
342
|
+
```sh
|
|
343
|
+
cp -v ./vendor/brnshkr/config/conf/twig-cs-fixer.php.example ./conf/twig-cs-fixer.php \
|
|
344
|
+
&& cp -v ./vendor/brnshkr/config/conf/twig-cs-fixer.php.example ./conf/twig-cs-fixer.php.example \
|
|
345
|
+
&& cp -v ./vendor/brnshkr/config/conf/twig-cs-fixer.dist.php.example ./conf/twig-cs-fixer.dist.php
|
|
346
|
+
```
|
|
347
|
+
|
|
339
348
|
<!-- omit in toc -->
|
|
340
349
|
##### Makefile
|
|
341
350
|
|
|
@@ -363,6 +372,9 @@ cp -v ./vendor/brnshkr/config/conf/php-cs-fixer.php.example ./conf/php-cs-fixer.
|
|
|
363
372
|
&& cp -v ./vendor/brnshkr/config/conf/phpstan.php.example ./conf/phpstan.php \
|
|
364
373
|
&& cp -v ./vendor/brnshkr/config/conf/phpstan.php.example ./conf/phpstan.php.example \
|
|
365
374
|
&& cp -v ./vendor/brnshkr/config/conf/phpstan.dist.php.example ./conf/phpstan.dist.php \
|
|
375
|
+
&& cp -v ./vendor/brnshkr/config/conf/twig-cs-fixer.php.example ./conf/twig-cs-fixer.php \
|
|
376
|
+
&& cp -v ./vendor/brnshkr/config/conf/twig-cs-fixer.php.example ./conf/twig-cs-fixer.php.example \
|
|
377
|
+
&& cp -v ./vendor/brnshkr/config/conf/twig-cs-fixer.dist.php.example ./conf/twig-cs-fixer.dist.php \
|
|
366
378
|
&& cp -v ./vendor/brnshkr/config/conf/Makefile.example ./Makefile \
|
|
367
379
|
&& cp -v ./vendor/brnshkr/config/conf/.gitignore.example ./.gitignore
|
|
368
380
|
```
|
|
@@ -418,6 +430,21 @@ use Brnshkr\Config\PhpStan;
|
|
|
418
430
|
return PhpStan::getConfig(/* customize */);
|
|
419
431
|
```
|
|
420
432
|
|
|
433
|
+
<!-- omit in toc -->
|
|
434
|
+
##### Twig CS Fixer
|
|
435
|
+
|
|
436
|
+
```php
|
|
437
|
+
// ./twig-cs-fixer.dist.php
|
|
438
|
+
|
|
439
|
+
<?php
|
|
440
|
+
|
|
441
|
+
declare(strict_types=1);
|
|
442
|
+
|
|
443
|
+
use Brnshkr\Config\TwigCsFixer;
|
|
444
|
+
|
|
445
|
+
return TwigCsFixer::getConfig(/* customize */);
|
|
446
|
+
```
|
|
447
|
+
|
|
421
448
|
<p align="right"><a href="#top" title="Back to top"> ⬆ </a></p>
|
|
422
449
|
|
|
423
450
|
### 👀 Usage
|
|
@@ -458,6 +485,15 @@ Example call, adjust as needed
|
|
|
458
485
|
php ./vendor/bin/phpstan analyze --configuration ./conf/phpstan.php -vv --memory-limit=-1
|
|
459
486
|
```
|
|
460
487
|
|
|
488
|
+
<!-- omit in toc -->
|
|
489
|
+
###### Twig CS Fixer
|
|
490
|
+
|
|
491
|
+
Example call, adjust as needed
|
|
492
|
+
|
|
493
|
+
```sh
|
|
494
|
+
php ./vendor/bin/twig-cs-fixer fix --config ./conf/twig-cs-fixer.php -v
|
|
495
|
+
```
|
|
496
|
+
|
|
461
497
|
<!-- omit in toc -->
|
|
462
498
|
##### Option 2 — Run Helper Scripts (Make Only, @brnshkr Convention)
|
|
463
499
|
|
|
@@ -496,6 +532,15 @@ Expected configuration file: `./conf/phpstan.php`
|
|
|
496
532
|
make phpstan
|
|
497
533
|
```
|
|
498
534
|
|
|
535
|
+
<!-- omit in toc -->
|
|
536
|
+
###### Twig CS Fixer
|
|
537
|
+
|
|
538
|
+
Expected configuration file: `./conf/twig-cs-fixer.php`
|
|
539
|
+
|
|
540
|
+
```sh
|
|
541
|
+
make twig-cs-fixer
|
|
542
|
+
```
|
|
543
|
+
|
|
499
544
|
<!-- omit in toc -->
|
|
500
545
|
#### IDE Setup
|
|
501
546
|
|
|
@@ -528,7 +573,8 @@ Install dependencies and setup project tooling with the following commands and a
|
|
|
528
573
|
composer install \
|
|
529
574
|
&& cp -v ./conf/php-cs-fixer.php.example ./conf/php-cs-fixer.php \
|
|
530
575
|
&& cp -v ./conf/rector.php.example ./conf/rector.php \
|
|
531
|
-
&& cp -v ./conf/phpstan.php.example ./conf/phpstan.php
|
|
576
|
+
&& cp -v ./conf/phpstan.php.example ./conf/phpstan.php \
|
|
577
|
+
&& cp -v ./conf/twig-cs-fixer.php.example ./conf/twig-cs-fixer.php
|
|
532
578
|
```
|
|
533
579
|
|
|
534
580
|
<!-- omit in toc -->
|
|
@@ -551,14 +597,13 @@ Here are some frequently used examples (see `make help` for the complete list):
|
|
|
551
597
|
- `make phpstan` — Run PHPStan static analysis
|
|
552
598
|
- `make test` — Run PHPUnit test suite
|
|
553
599
|
- `make test-update` — Run PHPUnit test suite and update snapshots
|
|
554
|
-
- `make check` — Run Rector, PHP-CS-Fixer, PHPStan and PHPUnit
|
|
600
|
+
- `make check` — Run Rector, PHP-CS-Fixer, Twig-CS-Fixer, PHPStan and PHPUnit
|
|
555
601
|
|
|
556
602
|
## 🔨 TODOs / Roadmap
|
|
557
603
|
|
|
558
604
|
- Add setup command for JS package (like `composer brnshkr:config:setup`)
|
|
559
605
|
- Expand [`⚙️ Worflows`](#️-workflows) section in readme
|
|
560
606
|
- Write sections about custom PHPStan and ESLint rules
|
|
561
|
-
- Add all around support for enforcing TypeScript aliases with ESLint
|
|
562
607
|
- Add Vue support
|
|
563
608
|
- Add React support
|
|
564
609
|
- Add Tailwind support via <https://github.com/schoero/eslint-plugin-better-tailwindcss>
|
|
@@ -599,7 +644,9 @@ See [./.github/workflows](https://github.com/brnshkr/config/blob/master/.github/
|
|
|
599
644
|
|
|
600
645
|
This project follows [Semantic Versioning 2.0.0][semver-2.0.0-url].
|
|
601
646
|
The NPM and Composer packages are versioned in sync, so a version change does not necessarily indicate a change in a specific package.
|
|
602
|
-
|
|
647
|
+
|
|
648
|
+
> ❗ **Note** ❗
|
|
649
|
+
> Since changes to rules and dependencies are not considered breaking, even a patch release may introduce new errors in code that hasn't changed and break your CI without notice. We therefore strongly recommend pinning to an exact version (`-E` for the JS package managers, `composer r --dev brnshkr/config:X.Y.Z` for Composer) so updates stay opt-in and can be applied on your own schedule.
|
|
603
650
|
|
|
604
651
|
<!-- omit in toc -->
|
|
605
652
|
### Changes Considered as Breaking Changes
|
|
@@ -632,8 +679,9 @@ Distributed under the MIT License. See [LICENSE](./LICENSE) for more information
|
|
|
632
679
|
- [PHP](https://www.php.net)
|
|
633
680
|
- [PHPStan](https://github.com/phpstan/phpstan)
|
|
634
681
|
- [Rector](https://github.com/rectorphp/rector)
|
|
682
|
+
- [PHP-CS-Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer)
|
|
683
|
+
- [Twig-CS-Fixer](https://github.com/VincentLanglet/Twig-CS-Fixer)
|
|
635
684
|
- [GNU Make](https://www.gnu.org/software/make)
|
|
636
|
-
- [PHP Coding Standards Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer)
|
|
637
685
|
- [Best-README-Template](https://github.com/othneildrew/Best-README-Template) by [othneildrew](https://github.com/othneildrew)
|
|
638
686
|
- [Choose an Open Source License](https://choosealicense.com)
|
|
639
687
|
- [Shields.io](https://shields.io)
|
package/conf/tsconfig.json
CHANGED
package/dist/eslint/index.d.mts
CHANGED
|
@@ -125,6 +125,10 @@ interface RuleOptions {
|
|
|
125
125
|
* @deprecated
|
|
126
126
|
*/
|
|
127
127
|
'brace-style'?: Linter.RuleEntry<BraceStyle>;
|
|
128
|
+
/**
|
|
129
|
+
* Require imports to use TypeScript path aliases when the target file is reachable through a configured alias.
|
|
130
|
+
*/
|
|
131
|
+
'brnshkr/require-import-alias'?: Linter.RuleEntry<BrnshkrRequireImportAlias>;
|
|
128
132
|
/**
|
|
129
133
|
* Require non-JavaScript imports (e.g. .json and .css) to include import attributes.
|
|
130
134
|
*/
|
|
@@ -6522,6 +6526,13 @@ type ArrowSpacing = [] | [{
|
|
|
6522
6526
|
type BlockSpacing = [] | [("always" | "never")]; // ----- brace-style -----
|
|
6523
6527
|
type BraceStyle = [] | [("1tbs" | "stroustrup" | "allman")] | [("1tbs" | "stroustrup" | "allman"), {
|
|
6524
6528
|
allowSingleLine?: boolean;
|
|
6529
|
+
}]; // ----- brnshkr/require-import-alias -----
|
|
6530
|
+
type BrnshkrRequireImportAlias = [] | [{
|
|
6531
|
+
aliases?: {
|
|
6532
|
+
[k: string]: string[] | undefined;
|
|
6533
|
+
};
|
|
6534
|
+
tsConfigPath?: string;
|
|
6535
|
+
ignoredPaths?: string[];
|
|
6525
6536
|
}]; // ----- callback-return -----
|
|
6526
6537
|
type CallbackReturn = [] | [string[]]; // ----- camelcase -----
|
|
6527
6538
|
type Camelcase = [] | [{
|
package/dist/eslint/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { c as objectAssign, d as
|
|
1
|
+
import { c as objectAssign, d as packageOrganization, f as packageOrganizationUpper, i as resolvePackagesSharedAsynchronously, l as objectEntries, n as GLOB_IGNORES, o as ESLINT_PACKAGES, p as version, r as isModuleEnabledByDefault, t as QUOTES, u as objectFromEntries } from "../shared.mjs";
|
|
2
2
|
import { FlatConfigComposer } from "eslint-flat-config-utils";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
3
5
|
import jsEslint from "@eslint/js";
|
|
4
6
|
import confusingBrowserGlobals from "confusing-browser-globals";
|
|
5
7
|
import globals from "globals";
|
|
6
|
-
import fs from "node:fs/promises";
|
|
7
|
-
import path from "node:path";
|
|
8
8
|
//#region ../src/js/eslint/types/scopes.ts
|
|
9
9
|
const MAIN_SCOPES = {
|
|
10
10
|
[packageOrganizationUpper]: "builtin",
|
|
@@ -118,7 +118,182 @@ const GLOB_TEST_FILES = [
|
|
|
118
118
|
"**/*.benchmark.?(c|m)[jt]s"
|
|
119
119
|
];
|
|
120
120
|
//#endregion
|
|
121
|
-
//#region ../src/js/eslint/
|
|
121
|
+
//#region ../src/js/eslint/utils/tsconfig.ts
|
|
122
|
+
const DEFAULT_TSCONFIG_FILENAME = "tsconfig.json";
|
|
123
|
+
const JSONC_TOKEN_PATTERN = /"(?:[^"\\]|\\.)*"|\/\/[^\n]*|\/\*[\s\S]*?\*\//gv;
|
|
124
|
+
const TRAILING_COMMA_PATTERN = /,(?=\s*[\]\}])/gv;
|
|
125
|
+
const stripJsonc = (input) => input.replaceAll(JSONC_TOKEN_PATTERN, (match) => match.startsWith("\"") ? match : "").replaceAll(TRAILING_COMMA_PATTERN, "");
|
|
126
|
+
const parseTsConfigFile = (filePath) => {
|
|
127
|
+
try {
|
|
128
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
129
|
+
return JSON.parse(stripJsonc(content));
|
|
130
|
+
} catch {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const resolveExtends = (extendsValue, fromDirectory) => {
|
|
135
|
+
if (extendsValue.startsWith(".") || path.isAbsolute(extendsValue)) {
|
|
136
|
+
const resolved = path.resolve(fromDirectory, extendsValue);
|
|
137
|
+
return path.extname(resolved) === "" ? `${resolved}.json` : resolved;
|
|
138
|
+
}
|
|
139
|
+
return path.resolve(fromDirectory, "node_modules", extendsValue);
|
|
140
|
+
};
|
|
141
|
+
const normalizeExtends = (raw) => {
|
|
142
|
+
if (raw.extends === void 0) return [];
|
|
143
|
+
return Array.isArray(raw.extends) ? raw.extends : [raw.extends];
|
|
144
|
+
};
|
|
145
|
+
const loadInternal = (filePath, visitedPaths) => {
|
|
146
|
+
if (visitedPaths.has(filePath)) return;
|
|
147
|
+
visitedPaths.add(filePath);
|
|
148
|
+
const parsedConfig = parseTsConfigFile(filePath);
|
|
149
|
+
if (!parsedConfig) return;
|
|
150
|
+
const fromDirectory = path.dirname(filePath);
|
|
151
|
+
let compilerOptions = {};
|
|
152
|
+
for (const value of normalizeExtends(parsedConfig)) compilerOptions = {
|
|
153
|
+
...compilerOptions,
|
|
154
|
+
...loadInternal(resolveExtends(value, fromDirectory), visitedPaths)?.compilerOptions
|
|
155
|
+
};
|
|
156
|
+
return { compilerOptions: {
|
|
157
|
+
...compilerOptions,
|
|
158
|
+
...parsedConfig.compilerOptions
|
|
159
|
+
} };
|
|
160
|
+
};
|
|
161
|
+
const cache = /* @__PURE__ */ new Map();
|
|
162
|
+
const toPosix$1 = (filePath) => filePath.replaceAll("\\", "/");
|
|
163
|
+
const loadTsConfigPaths = (tsConfigPath) => {
|
|
164
|
+
const absolutePath = path.resolve(tsConfigPath);
|
|
165
|
+
if (cache.has(absolutePath)) return cache.get(absolutePath);
|
|
166
|
+
const mergedConfig = loadInternal(absolutePath, /* @__PURE__ */ new Set());
|
|
167
|
+
const paths = mergedConfig?.compilerOptions?.paths;
|
|
168
|
+
if (!paths) {
|
|
169
|
+
cache.set(absolutePath, void 0);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const baseUrl = path.resolve(path.dirname(absolutePath), mergedConfig.compilerOptions?.baseUrl ?? ".");
|
|
173
|
+
const result = objectFromEntries(objectEntries(paths).map(([pattern, targets]) => [pattern, targets.map((target) => toPosix$1(path.resolve(baseUrl, target)))]));
|
|
174
|
+
cache.set(absolutePath, result);
|
|
175
|
+
return result;
|
|
176
|
+
};
|
|
177
|
+
const doesTsConfigExist = (tsConfigPath) => {
|
|
178
|
+
try {
|
|
179
|
+
fs.accessSync(tsConfigPath, fs.constants.R_OK);
|
|
180
|
+
return true;
|
|
181
|
+
} catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const resolveTsConfigPath = (typescriptOptions) => {
|
|
186
|
+
let tsconfig = DEFAULT_TSCONFIG_FILENAME;
|
|
187
|
+
if (typescriptOptions) {
|
|
188
|
+
if (typeof typescriptOptions.typeAware === "string") tsconfig = typescriptOptions.typeAware;
|
|
189
|
+
else if (typeof typescriptOptions.typeAware === "object") tsconfig = typescriptOptions.typeAware.tsconfig ?? DEFAULT_TSCONFIG_FILENAME;
|
|
190
|
+
}
|
|
191
|
+
return path.resolve(process.cwd(), tsconfig);
|
|
192
|
+
};
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region ../src/js/eslint/configs/builtin/require-import-alias.ts
|
|
195
|
+
const MESSAGE_ID_PREFER_ALIAS = "preferAlias";
|
|
196
|
+
const MESSAGE_ID_MISSING_ALIAS = "missingAlias";
|
|
197
|
+
const WILDCARD_SUFFIX = "/*";
|
|
198
|
+
const WILDCARD_SUFFIX_LENGTH = 2;
|
|
199
|
+
const RELATIVE_SPECIFIER_PREFIXES = ["./", "../"];
|
|
200
|
+
const resolveAliases = (options) => options.aliases ?? loadTsConfigPaths(options.tsConfigPath ?? resolveTsConfigPath()) ?? {};
|
|
201
|
+
const toPosix = (value) => value.replaceAll("\\", "/");
|
|
202
|
+
const buildAliasMappings = (aliases) => objectEntries(aliases).filter(([pattern]) => pattern.endsWith(WILDCARD_SUFFIX)).flatMap(([pattern, targets]) => {
|
|
203
|
+
const prefix = pattern.slice(0, -WILDCARD_SUFFIX_LENGTH);
|
|
204
|
+
return targets.filter((target) => target.endsWith(WILDCARD_SUFFIX)).map((target) => ({
|
|
205
|
+
prefix,
|
|
206
|
+
baseDirectory: toPosix(target).slice(0, -WILDCARD_SUFFIX_LENGTH)
|
|
207
|
+
}));
|
|
208
|
+
}).toSorted((left, right) => right.baseDirectory.length - left.baseDirectory.length);
|
|
209
|
+
const findAliasReplacement = (mappings, absolutePath) => {
|
|
210
|
+
for (const { prefix, baseDirectory } of mappings) {
|
|
211
|
+
if (absolutePath === baseDirectory) return prefix;
|
|
212
|
+
if (absolutePath.startsWith(`${baseDirectory}/`)) return `${prefix}/${absolutePath.slice(baseDirectory.length + 1)}`;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const isRelativeSpecifier = (source) => RELATIVE_SPECIFIER_PREFIXES.some((prefix) => source.startsWith(prefix));
|
|
216
|
+
const isAlreadyAliased = (source, mappings) => mappings.some(({ prefix }) => source === prefix || source.startsWith(`${prefix}/`));
|
|
217
|
+
const isFileIgnored = (filename, patterns) => patterns.some((pattern) => path.matchesGlob(toPosix(filename), pattern) || path.matchesGlob(toPosix(path.relative(process.cwd(), filename)), pattern));
|
|
218
|
+
const getQuote = (sourceNode) => "raw" in sourceNode && typeof sourceNode.raw === "string" && sourceNode.raw.startsWith("\"") ? "\"" : "'";
|
|
219
|
+
const requireImportAliasRule = {
|
|
220
|
+
meta: {
|
|
221
|
+
type: "suggestion",
|
|
222
|
+
fixable: "code",
|
|
223
|
+
docs: { description: "Require imports to use TypeScript path aliases when the target file is reachable through a configured alias." },
|
|
224
|
+
schema: [{
|
|
225
|
+
type: "object",
|
|
226
|
+
additionalProperties: false,
|
|
227
|
+
properties: {
|
|
228
|
+
aliases: {
|
|
229
|
+
type: "object",
|
|
230
|
+
additionalProperties: {
|
|
231
|
+
type: "array",
|
|
232
|
+
items: { type: "string" }
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
tsConfigPath: { type: "string" },
|
|
236
|
+
ignoredPaths: {
|
|
237
|
+
type: "array",
|
|
238
|
+
items: { type: "string" }
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}],
|
|
242
|
+
messages: {
|
|
243
|
+
[MESSAGE_ID_PREFER_ALIAS]: "Import path '{{ source }}' must use the configured alias '{{ alias }}'.",
|
|
244
|
+
[MESSAGE_ID_MISSING_ALIAS]: "Import path '{{ source }}' resolves outside any configured TypeScript path alias. Add an alias for this location, remove all other aliases, or disable this rule."
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
create: (context) => {
|
|
248
|
+
const options = context.options[0] ?? {};
|
|
249
|
+
const ignoredPaths = options.ignoredPaths ?? [];
|
|
250
|
+
const mappings = buildAliasMappings(resolveAliases(options));
|
|
251
|
+
if (mappings.length === 0 || isFileIgnored(context.filename, ignoredPaths)) return {};
|
|
252
|
+
const fileDirectory = toPosix(path.dirname(context.filename));
|
|
253
|
+
const checkSource = (sourceNode) => {
|
|
254
|
+
if (sourceNode?.type !== "Literal" || typeof sourceNode.value !== "string") return;
|
|
255
|
+
const source = sourceNode.value;
|
|
256
|
+
if (!isRelativeSpecifier(source) || isAlreadyAliased(source, mappings)) return;
|
|
257
|
+
const replacement = findAliasReplacement(mappings, path.posix.normalize(`${fileDirectory}/${source}`));
|
|
258
|
+
if (replacement === void 0) {
|
|
259
|
+
context.report({
|
|
260
|
+
node: sourceNode,
|
|
261
|
+
messageId: MESSAGE_ID_MISSING_ALIAS,
|
|
262
|
+
data: { source }
|
|
263
|
+
});
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
context.report({
|
|
267
|
+
node: sourceNode,
|
|
268
|
+
messageId: MESSAGE_ID_PREFER_ALIAS,
|
|
269
|
+
data: {
|
|
270
|
+
source,
|
|
271
|
+
alias: replacement
|
|
272
|
+
},
|
|
273
|
+
fix: (fixer) => fixer.replaceText(sourceNode, `${getQuote(sourceNode)}${replacement}${getQuote(sourceNode)}`)
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
return {
|
|
277
|
+
ImportDeclaration: (node) => {
|
|
278
|
+
checkSource(node.source);
|
|
279
|
+
},
|
|
280
|
+
ExportNamedDeclaration: (node) => {
|
|
281
|
+
checkSource(node.source);
|
|
282
|
+
},
|
|
283
|
+
ExportAllDeclaration: (node) => {
|
|
284
|
+
checkSource(node.source);
|
|
285
|
+
},
|
|
286
|
+
ImportExpression: (node) => {
|
|
287
|
+
checkSource(node.source);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region ../src/js/eslint/configs/builtin/require-import-attributes.ts
|
|
294
|
+
const MESSAGE_ID_MISSING_WITH_KEYWORD = "missingWithKeyword";
|
|
295
|
+
const MESSAGE_ID_MISSING_TYPE_PROPERTY = "missingTypeProperty";
|
|
296
|
+
const MESSAGE_ID_WRONG_TYPE_VALUE = "wrongTypeValue";
|
|
122
297
|
const FILE_TYPE_MAP = {
|
|
123
298
|
".json": "json",
|
|
124
299
|
".css": "css",
|
|
@@ -130,58 +305,59 @@ const FILE_TYPE_MAP = {
|
|
|
130
305
|
".oct": "bytes",
|
|
131
306
|
".wasm": "webassembly"
|
|
132
307
|
};
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region ../src/js/eslint/configs/builtin/index.ts
|
|
310
|
+
const RULE_DEFINITIONS = {
|
|
311
|
+
"require-import-attributes": {
|
|
312
|
+
meta: {
|
|
313
|
+
type: "problem",
|
|
314
|
+
docs: { description: "Require non-JavaScript imports (e.g. .json and .css) to include import attributes." },
|
|
315
|
+
messages: {
|
|
316
|
+
[MESSAGE_ID_MISSING_WITH_KEYWORD]: "Non-JavaScript import ('{{ extension }}') requires an import attributes object with the 'type' property set to '{{ expectedValue }}'.",
|
|
317
|
+
[MESSAGE_ID_MISSING_TYPE_PROPERTY]: "Import attributes for non-JavaScript imports must include the 'type' property.",
|
|
318
|
+
[MESSAGE_ID_WRONG_TYPE_VALUE]: "Import attribute 'type' for '{{ file }}' must be '{{ expectedValue }}'."
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
create: (context) => ({ ImportDeclaration: (node) => {
|
|
322
|
+
const sourceValue = node.source.value;
|
|
323
|
+
const extensionIndex = sourceValue.lastIndexOf(".");
|
|
324
|
+
if (extensionIndex === -1) return;
|
|
325
|
+
const extension = sourceValue.slice(extensionIndex).toLowerCase();
|
|
326
|
+
const expectedValue = FILE_TYPE_MAP[extension];
|
|
327
|
+
if (expectedValue === void 0) return;
|
|
328
|
+
const { attributes } = node;
|
|
329
|
+
if (attributes.length === 0) {
|
|
330
|
+
context.report({
|
|
331
|
+
node,
|
|
332
|
+
messageId: MESSAGE_ID_MISSING_WITH_KEYWORD,
|
|
333
|
+
data: {
|
|
334
|
+
extension,
|
|
335
|
+
expectedValue
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const typeProperty = attributes.find((attribute) => attribute.key.type === "Identifier" && "name" in attribute.key && attribute.key.name === "type" || attribute.key.type === "Literal" && "value" in attribute.key && attribute.key.value === "type");
|
|
341
|
+
if (!typeProperty) {
|
|
342
|
+
context.report({
|
|
343
|
+
node,
|
|
344
|
+
messageId: MESSAGE_ID_MISSING_TYPE_PROPERTY
|
|
345
|
+
});
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (typeProperty.value.value !== expectedValue) context.report({
|
|
156
349
|
node,
|
|
157
|
-
messageId:
|
|
350
|
+
messageId: MESSAGE_ID_WRONG_TYPE_VALUE,
|
|
158
351
|
data: {
|
|
159
|
-
|
|
160
|
-
|
|
352
|
+
expectedValue,
|
|
353
|
+
file: sourceValue
|
|
161
354
|
}
|
|
162
355
|
});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
node,
|
|
169
|
-
messageId: MESSAGE_ID_MISSING_TYPE_PROPERTY
|
|
170
|
-
});
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
if (typeProperty.value.value !== expectedValue) context.report({
|
|
174
|
-
node,
|
|
175
|
-
messageId: MESSAGE_ID_WRONG_TYPE_VALUE,
|
|
176
|
-
data: {
|
|
177
|
-
expectedValue,
|
|
178
|
-
file: sourceValue
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
} })
|
|
182
|
-
} };
|
|
183
|
-
const RULES = objectFreeze(objectFromEntries(objectKeys(RULE_DEFINITIONS).map((ruleName) => [`${packageOrganization}/${ruleName}`, "error"])));
|
|
184
|
-
const builtin = () => [{
|
|
356
|
+
} })
|
|
357
|
+
},
|
|
358
|
+
"require-import-alias": requireImportAliasRule
|
|
359
|
+
};
|
|
360
|
+
const builtin = (typescriptOptions) => [{
|
|
185
361
|
name: buildConfigName(MAIN_SCOPES[packageOrganizationUpper], SUB_SCOPES.SETUP),
|
|
186
362
|
plugins: { [packageOrganization]: {
|
|
187
363
|
meta: {
|
|
@@ -193,7 +369,10 @@ const builtin = () => [{
|
|
|
193
369
|
}, {
|
|
194
370
|
name: buildConfigName(MAIN_SCOPES[packageOrganizationUpper], SUB_SCOPES.RULES),
|
|
195
371
|
files: GLOB_SCRIPT_FILES,
|
|
196
|
-
rules:
|
|
372
|
+
rules: {
|
|
373
|
+
[`${packageOrganization}/require-import-alias`]: ["error", { tsConfigPath: resolveTsConfigPath(typeof typescriptOptions === "object" ? typescriptOptions : void 0) }],
|
|
374
|
+
[`${packageOrganization}/require-import-attributes`]: "error"
|
|
375
|
+
}
|
|
197
376
|
}];
|
|
198
377
|
const builtinConfig = { [packageOrganization]: builtin };
|
|
199
378
|
//#endregion
|
|
@@ -354,6 +533,14 @@ const imports = async () => {
|
|
|
354
533
|
if (pluginImport) {
|
|
355
534
|
plugins["import"] = pluginImport;
|
|
356
535
|
settings["import-x/resolver-next"] = [pluginImport.createNodeResolver(), importResovlerTypescript === void 0 ? void 0 : importResovlerTypescript.createTypeScriptImportResolver({ bun: true })].filter(Boolean);
|
|
536
|
+
settings["import-x/core-modules"] = [
|
|
537
|
+
"bun",
|
|
538
|
+
"bun:bundle",
|
|
539
|
+
"bun:ffi",
|
|
540
|
+
"bun:jsc",
|
|
541
|
+
"bun:sqlite",
|
|
542
|
+
"bun:test"
|
|
543
|
+
];
|
|
357
544
|
const pluginImportTsRules = isModuleEnabled(MODULES.typescript) ? renameRules(pluginImport.flatConfigs.typescript.rules, { "import-x": "import" }) : {};
|
|
358
545
|
pluginImportRules = {
|
|
359
546
|
...renameRules(pluginImport.flatConfigs.recommended.rules, { "import-x": "import" }),
|
|
@@ -809,15 +996,10 @@ const typescript = async (options) => {
|
|
|
809
996
|
if (!isTypescriptInstalled || !tsEslint) return [];
|
|
810
997
|
const { optional: [, pluginUnusedImports] } = await resolvePackages(MODULES.javascript);
|
|
811
998
|
const cwd = process.cwd();
|
|
812
|
-
let hasTsConfig = false;
|
|
813
|
-
try {
|
|
814
|
-
await fs.access(path.resolve(cwd, "tsconfig.json"), fs.constants.R_OK);
|
|
815
|
-
hasTsConfig = true;
|
|
816
|
-
} catch {}
|
|
817
999
|
const resolvedOptions = {
|
|
818
1000
|
extraFileExtensions: [],
|
|
819
1001
|
parserOptions: {},
|
|
820
|
-
typeAware:
|
|
1002
|
+
typeAware: doesTsConfigExist(resolveTsConfigPath(options)),
|
|
821
1003
|
...options
|
|
822
1004
|
};
|
|
823
1005
|
const ignores = resolvedOptions.ignores ?? [];
|
|
@@ -2626,7 +2808,7 @@ const getConfig = (optionsAndGlobalConfig, ...additionalConfigs) => {
|
|
|
2626
2808
|
if (isModuleEnabled(MODULES.test)) appendToComposer(configs.test());
|
|
2627
2809
|
if (isModuleEnabled(MODULES.jsdoc)) appendToComposer(configs.jsdoc());
|
|
2628
2810
|
if (isModuleEnabled(MODULES.node)) appendToComposer(configs.node(typeof resolvedOptions.node === "object" ? resolvedOptions.node : void 0));
|
|
2629
|
-
if (isModuleEnabled(MODULES[packageOrganization])) appendToComposer(configs[packageOrganization]());
|
|
2811
|
+
if (isModuleEnabled(MODULES[packageOrganization])) appendToComposer(configs[packageOrganization](resolvedOptions.typescript));
|
|
2630
2812
|
if (isModuleEnabled(MODULES.comments)) appendToComposer(configs.comments());
|
|
2631
2813
|
if (isModuleEnabled(MODULES.regexp)) appendToComposer(configs.regexp());
|
|
2632
2814
|
if (isModuleEnabled(MODULES.unicorn)) appendToComposer(configs.unicorn());
|
package/dist/shared.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isPackageExists } from "local-pkg";
|
|
2
2
|
//#region ../package.json
|
|
3
3
|
var name = "@brnshkr/config";
|
|
4
|
-
var version = "0.0.1-beta.
|
|
4
|
+
var version = "0.0.1-beta.3";
|
|
5
5
|
//#endregion
|
|
6
6
|
//#region ../src/js/shared/utils/package-json.ts
|
|
7
7
|
const packageOrganizationInternal = name.split("/").at(0)?.replace(/^@/v, "");
|
|
@@ -16,10 +16,8 @@ const log = (type, message, context) => {
|
|
|
16
16
|
};
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region ../src/js/shared/utils/object.ts
|
|
19
|
-
const objectKeys = (object) => Object.keys(object);
|
|
20
19
|
const objectEntries = (object) => Object.entries(object);
|
|
21
20
|
const objectFromEntries = (entries) => Object.fromEntries(entries);
|
|
22
|
-
const objectFreeze = (object) => Object.freeze(object);
|
|
23
21
|
const objectAssign = (target, source) => Object.assign(target, source);
|
|
24
22
|
//#endregion
|
|
25
23
|
//#region ../src/js/shared/utils/interop-import.ts
|
|
@@ -230,4 +228,4 @@ const GLOB_IGNORES = [
|
|
|
230
228
|
//#region ../src/js/shared/utils/constants.ts
|
|
231
229
|
const QUOTES = "single";
|
|
232
230
|
//#endregion
|
|
233
|
-
export { resolvePackagesSharedSynchronously as a, objectAssign as c,
|
|
231
|
+
export { resolvePackagesSharedSynchronously as a, objectAssign as c, packageOrganization as d, packageOrganizationUpper as f, resolvePackagesSharedAsynchronously as i, objectEntries as l, GLOB_IGNORES as n, ESLINT_PACKAGES as o, version as p, isModuleEnabledByDefault as r, STYLELINT_PACKAGES as s, QUOTES as t, objectFromEntries as u };
|
package/dist/stylelint/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resolvePackagesSharedSynchronously,
|
|
1
|
+
import { a as resolvePackagesSharedSynchronously, d as packageOrganization, l as objectEntries, n as GLOB_IGNORES, r as isModuleEnabledByDefault, s as STYLELINT_PACKAGES, t as QUOTES } from "../shared.mjs";
|
|
2
2
|
//#region ../src/js/stylelint/utils/module.ts
|
|
3
3
|
const MODULES = {
|
|
4
4
|
baseline: {
|
|
@@ -126,14 +126,18 @@ const defensive = () => {
|
|
|
126
126
|
return [{
|
|
127
127
|
plugins: STYLELINT_PACKAGES.STYLELINT_PLUGIN_DEFENSIVE_CSS,
|
|
128
128
|
extends: `${STYLELINT_PACKAGES.STYLELINT_PLUGIN_DEFENSIVE_CSS}/configs/strict`,
|
|
129
|
-
rules: {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
129
|
+
rules: {
|
|
130
|
+
"defensive-css/require-custom-property-fallback": true,
|
|
131
|
+
"defensive-css/require-pure-selectors": [true, {
|
|
132
|
+
ignoreElements: [
|
|
133
|
+
"*",
|
|
134
|
+
"html",
|
|
135
|
+
"body"
|
|
136
|
+
],
|
|
137
|
+
ignoreAttributeSelectors: true,
|
|
138
|
+
strict: true
|
|
139
|
+
}]
|
|
140
|
+
}
|
|
137
141
|
}];
|
|
138
142
|
};
|
|
139
143
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@brnshkr/config",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.3",
|
|
5
5
|
"description": "Centralized collection of configuration and tooling used across all @brnshkr projects",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Patrick Rupp",
|