@diia-inhouse/oxc-config 4.0.2 → 5.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../oxlint/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAsC,MAAM,QAAQ,CAAA;AAE9E,KAAK,MAAM,GAAG,YAAY,GAAG;IAAE,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../oxlint/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAsC,MAAM,QAAQ,CAAA;AAE9E,KAAK,MAAM,GAAG,YAAY,GAAG;IAAE,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAsjBzD,eAAO,MAAM,IAAI,EAAE,MAAuC,CAAA;AAE1D,eAAO,MAAM,UAAU,EAAE,MAKvB,CAAA;AAIF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,YAAY,KAAG,YAOnD,CAAA"}
|
package/dist/oxlint/config.js
CHANGED
|
@@ -206,6 +206,8 @@ const baseConfig = {
|
|
|
206
206
|
'@diia-inhouse/package/stale-overrides': 'warn',
|
|
207
207
|
'@diia-inhouse/package/peers-installed-locally': 'error',
|
|
208
208
|
'@diia-inhouse/package/exports-package-json': 'error',
|
|
209
|
+
'@diia-inhouse/package/no-dev-dependency-import': 'error',
|
|
210
|
+
'@diia-inhouse/package/no-undeclared-import': 'error',
|
|
209
211
|
'@diia-inhouse/locale/no-hardcoded-cyrillic': 'error',
|
|
210
212
|
'@diia-inhouse/code/no-promise-settimeout': 'error',
|
|
211
213
|
'@diia-inhouse/code/no-inline-object-return-type': 'error',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
-
import {
|
|
2
|
+
import { isBuiltin } from 'node:module'
|
|
3
|
+
import { dirname, join, relative, resolve } from 'node:path'
|
|
3
4
|
|
|
4
5
|
const FIX_FLAGS = new Set(['--fix', '--fix-suggestions', '--fix-dangerously'])
|
|
5
6
|
const DEPENDENCY_FIELDS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']
|
|
@@ -56,6 +57,7 @@ const DEV_TOOL_PATTERNS = [
|
|
|
56
57
|
/^rimraf$/,
|
|
57
58
|
/^tsc-alias$/,
|
|
58
59
|
/^tsc-watch$/,
|
|
60
|
+
/^@bufbuild\/buf$/,
|
|
59
61
|
/^@diia-inhouse\/(test|oxc-config|configs|scaffold|eslint-config|eslint-plugin)$/,
|
|
60
62
|
]
|
|
61
63
|
const DEFAULT_NODE_MAJOR = 24
|
|
@@ -63,6 +65,9 @@ const DEFAULT_AUTHOR = 'diia-team'
|
|
|
63
65
|
const DEV_SCRIPT = 'diia-dev'
|
|
64
66
|
const COMMITLINT_CONFIG = '@diia-inhouse/configs/dist/commitlint'
|
|
65
67
|
const MADGE_TS_CONFIG = './tsconfig.json'
|
|
68
|
+
const RUNTIME_SOURCE_PATTERN = /^src\//
|
|
69
|
+
const TEST_SOURCE_PATTERN = /(^|\/)(tests?|__tests__|__mocks__)\/|\.(spec|test)\.[cm]?[jt]sx?$/
|
|
70
|
+
const RUNTIME_DEPENDENCY_FIELDS = ['dependencies', 'peerDependencies', 'optionalDependencies']
|
|
66
71
|
|
|
67
72
|
const isFixRun = () => process.argv.some((arg) => FIX_FLAGS.has(arg))
|
|
68
73
|
|
|
@@ -614,7 +619,151 @@ function defineRule(name, { messages, schema = [], check, fix }) {
|
|
|
614
619
|
}
|
|
615
620
|
}
|
|
616
621
|
|
|
622
|
+
function importedPackage(specifier) {
|
|
623
|
+
if (typeof specifier !== 'string' || /^[./#]/.test(specifier) || isBuiltin(specifier)) {
|
|
624
|
+
return null
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const [scope, name] = specifier.split('/')
|
|
628
|
+
|
|
629
|
+
return scope.startsWith('@') ? `${scope}/${name}` : scope
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const isTypeOnly = (node, kindField) =>
|
|
633
|
+
node[kindField] === 'type' || (node.specifiers?.length > 0 && node.specifiers.every((specifier) => specifier[kindField] === 'type'))
|
|
634
|
+
|
|
635
|
+
function runtimeManifest(context) {
|
|
636
|
+
const path = findManifest(context.filename)
|
|
637
|
+
const entry = path && loadManifest(path)
|
|
638
|
+
const source = path && relative(dirname(path), resolve(context.filename))
|
|
639
|
+
|
|
640
|
+
return entry && RUNTIME_SOURCE_PATTERN.test(source) && !TEST_SOURCE_PATTERN.test(source) ? entry : null
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const runtimeImports = (check) => ({
|
|
644
|
+
ImportDeclaration(node) {
|
|
645
|
+
if (!isTypeOnly(node, 'importKind')) {
|
|
646
|
+
check(node, node.source.value)
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
ExportNamedDeclaration(node) {
|
|
650
|
+
if (node.source && !isTypeOnly(node, 'exportKind')) {
|
|
651
|
+
check(node, node.source.value)
|
|
652
|
+
}
|
|
653
|
+
},
|
|
654
|
+
ExportAllDeclaration(node) {
|
|
655
|
+
if (node.exportKind !== 'type') {
|
|
656
|
+
check(node, node.source.value)
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
TSImportEqualsDeclaration(node) {
|
|
660
|
+
if (node.importKind !== 'type' && node.moduleReference.type === 'TSExternalModuleReference') {
|
|
661
|
+
check(node, node.moduleReference.expression.value)
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
CallExpression(node) {
|
|
665
|
+
const [argument] = node.arguments
|
|
666
|
+
|
|
667
|
+
if (node.callee.type === 'Identifier' && node.callee.name === 'require' && argument?.type === 'Literal') {
|
|
668
|
+
check(node, argument.value)
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
})
|
|
672
|
+
|
|
673
|
+
function isInstalled(entry, name) {
|
|
674
|
+
entry.installed ??= new Map()
|
|
675
|
+
|
|
676
|
+
if (!entry.installed.has(name)) {
|
|
677
|
+
const dirs = []
|
|
678
|
+
|
|
679
|
+
for (let dir = dirname(entry.path); !dirs.includes(dir); dir = dirname(dir)) {
|
|
680
|
+
dirs.push(dir)
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
entry.installed.set(
|
|
684
|
+
name,
|
|
685
|
+
dirs.some((dir) => existsSync(join(dir, 'node_modules', name))),
|
|
686
|
+
)
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return entry.installed.get(name)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const noDevDependencyImport = {
|
|
693
|
+
meta: {
|
|
694
|
+
type: 'problem',
|
|
695
|
+
messages: {
|
|
696
|
+
devDependency:
|
|
697
|
+
'"{{ name }}" is only a devDependency, and the release image does not install devDependencies. If only types are imported, use `import type`; if the code needs it at runtime, declare it in dependencies, or in peerDependencies in a library.',
|
|
698
|
+
},
|
|
699
|
+
schema: [],
|
|
700
|
+
},
|
|
701
|
+
create(context) {
|
|
702
|
+
const entry = runtimeManifest(context)
|
|
703
|
+
|
|
704
|
+
if (!entry) {
|
|
705
|
+
return {}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const { data } = entry
|
|
709
|
+
|
|
710
|
+
return runtimeImports((node, specifier) => {
|
|
711
|
+
const name = importedPackage(specifier)
|
|
712
|
+
const isDevOnly =
|
|
713
|
+
name !== null &&
|
|
714
|
+
name !== data.name &&
|
|
715
|
+
Object.hasOwn(data.devDependencies ?? {}, name) &&
|
|
716
|
+
!RUNTIME_DEPENDENCY_FIELDS.some((field) => Object.hasOwn(data[field] ?? {}, name))
|
|
717
|
+
|
|
718
|
+
if (isDevOnly) {
|
|
719
|
+
context.report({ node, messageId: 'devDependency', data: { name } })
|
|
720
|
+
}
|
|
721
|
+
})
|
|
722
|
+
},
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const noUndeclaredImport = {
|
|
726
|
+
meta: {
|
|
727
|
+
type: 'problem',
|
|
728
|
+
messages: {
|
|
729
|
+
undeclared:
|
|
730
|
+
'"{{ name }}" is not declared in package.json and resolves only because another package installs it. If only types are imported, use `import type`. Not auto-fixed, because package-lock.json must change with it: run `npm i {{ name }}`, or declare it in peerDependencies in a library.',
|
|
731
|
+
},
|
|
732
|
+
schema: [],
|
|
733
|
+
},
|
|
734
|
+
create(context) {
|
|
735
|
+
const entry = runtimeManifest(context)
|
|
736
|
+
|
|
737
|
+
if (!entry) {
|
|
738
|
+
return {}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const { data } = entry
|
|
742
|
+
const declared = allDependencies(data)
|
|
743
|
+
const check = (node, specifier) => {
|
|
744
|
+
const name = importedPackage(specifier)
|
|
745
|
+
|
|
746
|
+
if (name !== null && name !== data.name && !Object.hasOwn(declared, name) && isInstalled(entry, name)) {
|
|
747
|
+
context.report({ node, messageId: 'undeclared', data: { name } })
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return {
|
|
752
|
+
...runtimeImports(check),
|
|
753
|
+
ImportExpression(node) {
|
|
754
|
+
if (node.source.type === 'Literal') {
|
|
755
|
+
check(node, node.source.value)
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
}
|
|
761
|
+
|
|
617
762
|
export default {
|
|
618
763
|
meta: { name: '@diia-inhouse/oxlint-plugin-package' },
|
|
619
|
-
rules:
|
|
764
|
+
rules: {
|
|
765
|
+
...Object.fromEntries(Object.entries(manifestRules).map(([name, rule]) => [name, defineRule(name, rule)])),
|
|
766
|
+
'no-dev-dependency-import': noDevDependencyImport,
|
|
767
|
+
'no-undeclared-import': noUndeclaredImport,
|
|
768
|
+
},
|
|
620
769
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
-
import {
|
|
2
|
+
import { isBuiltin } from 'node:module'
|
|
3
|
+
import { dirname, join, relative, resolve } from 'node:path'
|
|
3
4
|
|
|
4
5
|
const FIX_FLAGS = new Set(['--fix', '--fix-suggestions', '--fix-dangerously'])
|
|
5
6
|
const DEPENDENCY_FIELDS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']
|
|
@@ -56,6 +57,7 @@ const DEV_TOOL_PATTERNS = [
|
|
|
56
57
|
/^rimraf$/,
|
|
57
58
|
/^tsc-alias$/,
|
|
58
59
|
/^tsc-watch$/,
|
|
60
|
+
/^@bufbuild\/buf$/,
|
|
59
61
|
/^@diia-inhouse\/(test|oxc-config|configs|scaffold|eslint-config|eslint-plugin)$/,
|
|
60
62
|
]
|
|
61
63
|
const DEFAULT_NODE_MAJOR = 24
|
|
@@ -63,6 +65,9 @@ const DEFAULT_AUTHOR = 'diia-team'
|
|
|
63
65
|
const DEV_SCRIPT = 'diia-dev'
|
|
64
66
|
const COMMITLINT_CONFIG = '@diia-inhouse/configs/dist/commitlint'
|
|
65
67
|
const MADGE_TS_CONFIG = './tsconfig.json'
|
|
68
|
+
const RUNTIME_SOURCE_PATTERN = /^src\//
|
|
69
|
+
const TEST_SOURCE_PATTERN = /(^|\/)(tests?|__tests__|__mocks__)\/|\.(spec|test)\.[cm]?[jt]sx?$/
|
|
70
|
+
const RUNTIME_DEPENDENCY_FIELDS = ['dependencies', 'peerDependencies', 'optionalDependencies']
|
|
66
71
|
|
|
67
72
|
const isFixRun = () => process.argv.some((arg) => FIX_FLAGS.has(arg))
|
|
68
73
|
|
|
@@ -614,7 +619,151 @@ function defineRule(name, { messages, schema = [], check, fix }) {
|
|
|
614
619
|
}
|
|
615
620
|
}
|
|
616
621
|
|
|
622
|
+
function importedPackage(specifier) {
|
|
623
|
+
if (typeof specifier !== 'string' || /^[./#]/.test(specifier) || isBuiltin(specifier)) {
|
|
624
|
+
return null
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const [scope, name] = specifier.split('/')
|
|
628
|
+
|
|
629
|
+
return scope.startsWith('@') ? `${scope}/${name}` : scope
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const isTypeOnly = (node, kindField) =>
|
|
633
|
+
node[kindField] === 'type' || (node.specifiers?.length > 0 && node.specifiers.every((specifier) => specifier[kindField] === 'type'))
|
|
634
|
+
|
|
635
|
+
function runtimeManifest(context) {
|
|
636
|
+
const path = findManifest(context.filename)
|
|
637
|
+
const entry = path && loadManifest(path)
|
|
638
|
+
const source = path && relative(dirname(path), resolve(context.filename))
|
|
639
|
+
|
|
640
|
+
return entry && RUNTIME_SOURCE_PATTERN.test(source) && !TEST_SOURCE_PATTERN.test(source) ? entry : null
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const runtimeImports = (check) => ({
|
|
644
|
+
ImportDeclaration(node) {
|
|
645
|
+
if (!isTypeOnly(node, 'importKind')) {
|
|
646
|
+
check(node, node.source.value)
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
ExportNamedDeclaration(node) {
|
|
650
|
+
if (node.source && !isTypeOnly(node, 'exportKind')) {
|
|
651
|
+
check(node, node.source.value)
|
|
652
|
+
}
|
|
653
|
+
},
|
|
654
|
+
ExportAllDeclaration(node) {
|
|
655
|
+
if (node.exportKind !== 'type') {
|
|
656
|
+
check(node, node.source.value)
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
TSImportEqualsDeclaration(node) {
|
|
660
|
+
if (node.importKind !== 'type' && node.moduleReference.type === 'TSExternalModuleReference') {
|
|
661
|
+
check(node, node.moduleReference.expression.value)
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
CallExpression(node) {
|
|
665
|
+
const [argument] = node.arguments
|
|
666
|
+
|
|
667
|
+
if (node.callee.type === 'Identifier' && node.callee.name === 'require' && argument?.type === 'Literal') {
|
|
668
|
+
check(node, argument.value)
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
})
|
|
672
|
+
|
|
673
|
+
function isInstalled(entry, name) {
|
|
674
|
+
entry.installed ??= new Map()
|
|
675
|
+
|
|
676
|
+
if (!entry.installed.has(name)) {
|
|
677
|
+
const dirs = []
|
|
678
|
+
|
|
679
|
+
for (let dir = dirname(entry.path); !dirs.includes(dir); dir = dirname(dir)) {
|
|
680
|
+
dirs.push(dir)
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
entry.installed.set(
|
|
684
|
+
name,
|
|
685
|
+
dirs.some((dir) => existsSync(join(dir, 'node_modules', name))),
|
|
686
|
+
)
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return entry.installed.get(name)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const noDevDependencyImport = {
|
|
693
|
+
meta: {
|
|
694
|
+
type: 'problem',
|
|
695
|
+
messages: {
|
|
696
|
+
devDependency:
|
|
697
|
+
'"{{ name }}" is only a devDependency, and the release image does not install devDependencies. If only types are imported, use `import type`; if the code needs it at runtime, declare it in dependencies, or in peerDependencies in a library.',
|
|
698
|
+
},
|
|
699
|
+
schema: [],
|
|
700
|
+
},
|
|
701
|
+
create(context) {
|
|
702
|
+
const entry = runtimeManifest(context)
|
|
703
|
+
|
|
704
|
+
if (!entry) {
|
|
705
|
+
return {}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const { data } = entry
|
|
709
|
+
|
|
710
|
+
return runtimeImports((node, specifier) => {
|
|
711
|
+
const name = importedPackage(specifier)
|
|
712
|
+
const isDevOnly =
|
|
713
|
+
name !== null &&
|
|
714
|
+
name !== data.name &&
|
|
715
|
+
Object.hasOwn(data.devDependencies ?? {}, name) &&
|
|
716
|
+
!RUNTIME_DEPENDENCY_FIELDS.some((field) => Object.hasOwn(data[field] ?? {}, name))
|
|
717
|
+
|
|
718
|
+
if (isDevOnly) {
|
|
719
|
+
context.report({ node, messageId: 'devDependency', data: { name } })
|
|
720
|
+
}
|
|
721
|
+
})
|
|
722
|
+
},
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const noUndeclaredImport = {
|
|
726
|
+
meta: {
|
|
727
|
+
type: 'problem',
|
|
728
|
+
messages: {
|
|
729
|
+
undeclared:
|
|
730
|
+
'"{{ name }}" is not declared in package.json and resolves only because another package installs it. If only types are imported, use `import type`. Not auto-fixed, because package-lock.json must change with it: run `npm i {{ name }}`, or declare it in peerDependencies in a library.',
|
|
731
|
+
},
|
|
732
|
+
schema: [],
|
|
733
|
+
},
|
|
734
|
+
create(context) {
|
|
735
|
+
const entry = runtimeManifest(context)
|
|
736
|
+
|
|
737
|
+
if (!entry) {
|
|
738
|
+
return {}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const { data } = entry
|
|
742
|
+
const declared = allDependencies(data)
|
|
743
|
+
const check = (node, specifier) => {
|
|
744
|
+
const name = importedPackage(specifier)
|
|
745
|
+
|
|
746
|
+
if (name !== null && name !== data.name && !Object.hasOwn(declared, name) && isInstalled(entry, name)) {
|
|
747
|
+
context.report({ node, messageId: 'undeclared', data: { name } })
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return {
|
|
752
|
+
...runtimeImports(check),
|
|
753
|
+
ImportExpression(node) {
|
|
754
|
+
if (node.source.type === 'Literal') {
|
|
755
|
+
check(node, node.source.value)
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
}
|
|
761
|
+
|
|
617
762
|
export default {
|
|
618
763
|
meta: { name: '@diia-inhouse/oxlint-plugin-package' },
|
|
619
|
-
rules:
|
|
764
|
+
rules: {
|
|
765
|
+
...Object.fromEntries(Object.entries(manifestRules).map(([name, rule]) => [name, defineRule(name, rule)])),
|
|
766
|
+
'no-dev-dependency-import': noDevDependencyImport,
|
|
767
|
+
'no-undeclared-import': noUndeclaredImport,
|
|
768
|
+
},
|
|
620
769
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diia-inhouse/oxc-config",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "OXC toolchain configs for Diia services: oxlint, oxfmt, oxc transformer",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "diia-team",
|
|
@@ -57,6 +57,9 @@
|
|
|
57
57
|
"oxlint": ">= 1.87.0",
|
|
58
58
|
"oxlint-tsgolint": ">= 7.0.0"
|
|
59
59
|
},
|
|
60
|
+
"overrides": {
|
|
61
|
+
"handlebars": "4.7.10"
|
|
62
|
+
},
|
|
60
63
|
"commitlint": {
|
|
61
64
|
"extends": "@diia-inhouse/configs/dist/commitlint"
|
|
62
65
|
},
|