dev: add dependency cruiser to help visualise and cleanup imports

This commit is contained in:
SethBurkart123
2025-02-21 17:37:29 +11:00
parent 550f2cab54
commit 6247e17d70
5 changed files with 433 additions and 19 deletions
+414
View File
@@ -0,0 +1,414 @@
/** @type {import('dependency-cruiser').IConfiguration} */
module.exports = {
forbidden: [
{
name: 'no-circular',
severity: 'warn',
comment:
'This dependency is part of a circular relationship. You might want to revise ' +
'your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ',
from: {},
to: {
circular: true
}
},
{
name: 'no-orphans',
comment:
"This is an orphan module - it's likely not used (anymore?). Either use it or " +
"remove it. If it's logical this module is an orphan (i.e. it's a config file), " +
"add an exception for it in your dependency-cruiser configuration. By default " +
"this rule does not scrutinize dot-files (e.g. .eslintrc.js), TypeScript declaration " +
"files (.d.ts), tsconfig.json and some of the babel and webpack configs.",
severity: 'warn',
from: {
orphan: true,
pathNot: [
'(^|/)[.][^/]+[.](?:js|cjs|mjs|ts|cts|mts|json)$', // dot files
'[.]d[.]ts$', // TypeScript declaration files
'(^|/)tsconfig[.]json$', // TypeScript config
'(^|/)(?:babel|webpack)[.]config[.](?:js|cjs|mjs|ts|cts|mts|json)$' // other configs
]
},
to: {},
},
{
name: 'no-deprecated-core',
comment:
'A module depends on a node core module that has been deprecated. Find an alternative - these are ' +
"bound to exist - node doesn't deprecate lightly.",
severity: 'warn',
from: {},
to: {
dependencyTypes: [
'core'
],
path: [
'^v8/tools/codemap$',
'^v8/tools/consarray$',
'^v8/tools/csvparser$',
'^v8/tools/logreader$',
'^v8/tools/profile_view$',
'^v8/tools/profile$',
'^v8/tools/SourceMap$',
'^v8/tools/splaytree$',
'^v8/tools/tickprocessor-driver$',
'^v8/tools/tickprocessor$',
'^node-inspect/lib/_inspect$',
'^node-inspect/lib/internal/inspect_client$',
'^node-inspect/lib/internal/inspect_repl$',
'^async_hooks$',
'^punycode$',
'^domain$',
'^constants$',
'^sys$',
'^_linklist$',
'^_stream_wrap$'
],
}
},
{
name: 'not-to-deprecated',
comment:
'This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later ' +
'version of that module, or find an alternative. Deprecated modules are a security risk.',
severity: 'warn',
from: {},
to: {
dependencyTypes: [
'deprecated'
]
}
},
{
name: 'no-non-package-json',
severity: 'error',
comment:
"This module depends on an npm package that isn't in the 'dependencies' section of your package.json. " +
"That's problematic as the package either (1) won't be available on live (2 - worse) will be " +
"available on live with an non-guaranteed version. Fix it by adding the package to the dependencies " +
"in your package.json.",
from: {},
to: {
dependencyTypes: [
'npm-no-pkg',
'npm-unknown'
]
}
},
{
name: 'not-to-unresolvable',
comment:
"This module depends on a module that cannot be found ('resolved to disk'). If it's an npm " +
'module: add it to your package.json. In all other cases you likely already know what to do.',
severity: 'error',
from: {},
to: {
couldNotResolve: true
}
},
{
name: 'no-duplicate-dep-types',
comment:
"Likely this module depends on an external ('npm') package that occurs more than once " +
"in your package.json i.e. bot as a devDependencies and in dependencies. This will cause " +
"maintenance problems later on.",
severity: 'warn',
from: {},
to: {
moreThanOneDependencyType: true,
// as it's pretty common to have a type import be a type only import
// _and_ (e.g.) a devDependency - don't consider type-only dependency
// types for this rule
dependencyTypesNot: ["type-only"]
}
},
/* rules you might want to tweak for your specific situation: */
{
name: 'not-to-spec',
comment:
'This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. ' +
"If there's something in a spec that's of use to other modules, it doesn't have that single " +
'responsibility anymore. Factor it out into (e.g.) a separate utility/ helper or a mock.',
severity: 'error',
from: {},
to: {
path: '[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$'
}
},
{
name: 'not-to-dev-dep',
severity: 'error',
comment:
"This module depends on an npm package from the 'devDependencies' section of your " +
'package.json. It looks like something that ships to production, though. To prevent problems ' +
"with npm packages that aren't there on production declare it (only!) in the 'dependencies'" +
'section of your package.json. If this module is development only - add it to the ' +
'from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration',
from: {
path: '^(src)',
pathNot: '[.](?:spec|test)[.](?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$'
},
to: {
dependencyTypes: [
'npm-dev',
],
// type only dependencies are not a problem as they don't end up in the
// production code or are ignored by the runtime.
dependencyTypesNot: [
'type-only'
],
pathNot: [
'node_modules/@types/'
]
}
},
{
name: 'optional-deps-used',
severity: 'info',
comment:
"This module depends on an npm package that is declared as an optional dependency " +
"in your package.json. As this makes sense in limited situations only, it's flagged here. " +
"If you're using an optional dependency here by design - add an exception to your" +
"dependency-cruiser configuration.",
from: {},
to: {
dependencyTypes: [
'npm-optional'
]
}
},
{
name: 'peer-deps-used',
comment:
"This module depends on an npm package that is declared as a peer dependency " +
"in your package.json. This makes sense if your package is e.g. a plugin, but in " +
"other cases - maybe not so much. If the use of a peer dependency is intentional " +
"add an exception to your dependency-cruiser configuration.",
severity: 'warn',
from: {},
to: {
dependencyTypes: [
'npm-peer'
]
}
}
],
options: {
/* Which modules not to follow further when encountered */
doNotFollow: {
/* path: an array of regular expressions in strings to match against */
path: ['node_modules']
},
/* Which modules to exclude */
// exclude : {
// /* path: an array of regular expressions in strings to match against */
// path: '',
// },
/* Which modules to exclusively include (array of regular expressions in strings)
dependency-cruiser will skip everything not matching this pattern
*/
// includeOnly : [''],
/* List of module systems to cruise.
When left out dependency-cruiser will fall back to the list of _all_
module systems it knows of. It's the default because it's the safe option
It might come at a performance penalty, though.
moduleSystems: ['amd', 'cjs', 'es6', 'tsd']
As in practice only commonjs ('cjs') and ecmascript modules ('es6')
are widely used, you can limit the moduleSystems to those.
*/
// moduleSystems: ['cjs', 'es6'],
/*
false: don't look at JSDoc imports (the default)
true: dependency-cruiser will detect dependencies in JSDoc-style
import statements. Implies "parser": "tsc", so the dependency-cruiser
will use the typescript parser for JavaScript files.
For this to work the typescript compiler will need to be installed in the
same spot as you're running dependency-cruiser from.
*/
// detectJSDocImports: true,
/* prefix for links in html and svg output (e.g. 'https://github.com/you/yourrepo/blob/main/'
to open it on your online repo or `vscode://file/${process.cwd()}/` to
open it in visual studio code),
*/
// prefix: `vscode://file/${process.cwd()}/`,
/* false (the default): ignore dependencies that only exist before typescript-to-javascript compilation
true: also detect dependencies that only exist before typescript-to-javascript compilation
"specify": for each dependency identify whether it only exists before compilation or also after
*/
tsPreCompilationDeps: true,
/* list of extensions to scan that aren't javascript or compile-to-javascript.
Empty by default. Only put extensions in here that you want to take into
account that are _not_ parsable.
*/
// extraExtensionsToScan: [".json", ".jpg", ".png", ".svg", ".webp"],
/* if true combines the package.jsons found from the module up to the base
folder the cruise is initiated from. Useful for how (some) mono-repos
manage dependencies & dependency definitions.
*/
// combinedDependencies: false,
/* if true leave symlinks untouched, otherwise use the realpath */
// preserveSymlinks: false,
/* TypeScript project file ('tsconfig.json') to use for
(1) compilation and
(2) resolution (e.g. with the paths property)
The (optional) fileName attribute specifies which file to take (relative to
dependency-cruiser's current working directory). When not provided
defaults to './tsconfig.json'.
*/
tsConfig: {
fileName: 'tsconfig.json'
},
/* Webpack configuration to use to get resolve options from.
The (optional) fileName attribute specifies which file to take (relative
to dependency-cruiser's current working directory. When not provided defaults
to './webpack.conf.js'.
The (optional) `env` and `arguments` attributes contain the parameters
to be passed if your webpack config is a function and takes them (see
webpack documentation for details)
*/
// webpackConfig: {
// fileName: 'webpack.config.js',
// env: {},
// arguments: {}
// },
/* Babel config ('.babelrc', '.babelrc.json', '.babelrc.json5', ...) to use
for compilation
*/
// babelConfig: {
// fileName: '.babelrc',
// },
/* List of strings you have in use in addition to cjs/ es6 requires
& imports to declare module dependencies. Use this e.g. if you've
re-declared require, use a require-wrapper or use window.require as
a hack.
*/
// exoticRequireStrings: [],
/* options to pass on to enhanced-resolve, the package dependency-cruiser
uses to resolve module references to disk. The values below should be
suitable for most situations
If you use webpack: you can also set these in webpack.conf.js. The set
there will override the ones specified here.
*/
enhancedResolveOptions: {
/* What to consider as an 'exports' field in package.jsons */
exportsFields: ["exports"],
/* List of conditions to check for in the exports field.
Only works when the 'exportsFields' array is non-empty.
*/
conditionNames: ["import", "require", "node", "default", "types"],
/* The extensions, by default are the same as the ones dependency-cruiser
can access (run `npx depcruise --info` to see which ones that are in
_your_ environment). If that list is larger than you need you can pass
the extensions you actually use (e.g. [".js", ".jsx"]). This can speed
up module resolution, which is the most expensive step.
*/
// extensions: [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
/* What to consider a 'main' field in package.json */
mainFields: ["module", "main", "types", "typings"],
/* A list of alias fields in package.jsons
See [this specification](https://github.com/defunctzombie/package-browser-field-spec) and
the webpack [resolve.alias](https://webpack.js.org/configuration/resolve/#resolvealiasfields)
documentation.
Defaults to an empty array (= don't use alias fields).
*/
// aliasFields: ["browser"],
},
/* skipAnalysisNotInRules will make dependency-cruiser execute
analysis strictly necessary for checking the rule set only.
See https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#skipanalysisnotinrules
for details
*/
skipAnalysisNotInRules: true,
/* List of built-in modules to use on top of the ones node declares.
See https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#builtinmodules-influencing-what-to-consider-built-in--core-modules
for details
*/
builtInModules: {
add: [
"bun",
"bun:ffi",
"bun:jsc",
"bun:sqlite",
"bun:test",
"bun:wrap",
"detect-libc",
"undici",
"ws"
]
},
reporterOptions: {
dot: {
/* pattern of modules that can be consolidated in the detailed
graphical dependency graph. The default pattern in this configuration
collapses everything in node_modules to one folder deep so you see
the external modules, but their innards.
*/
collapsePattern: 'node_modules/(?:@[^/]+/[^/]+|[^/]+)',
/* Options to tweak the appearance of your graph.See
https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#reporteroptions
for details and some examples. If you don't specify a theme
dependency-cruiser falls back to a built-in one.
*/
// theme: {
// graph: {
// /* splines: "ortho" gives straight lines, but is slow on big graphs
// splines: "true" gives bezier curves (fast, not as nice as ortho)
// */
// splines: "true"
// },
// }
},
archi: {
/* pattern of modules that can be consolidated in the high level
graphical dependency graph. If you use the high level graphical
dependency graph reporter (`archi`) you probably want to tweak
this collapsePattern to your situation.
*/
collapsePattern: '^(?:packages|src|lib(s?)|app(s?)|bin|test(s?)|spec(s?))/[^/]+|node_modules/(?:@[^/]+/[^/]+|[^/]+)',
/* Options to tweak the appearance of your graph. If you don't specify a
theme for 'archi' dependency-cruiser will use the one specified in the
dot section above and otherwise use the default one.
*/
// theme: { },
},
"text": {
"highlightFocused": true
},
}
}
};
// generated: dependency-cruiser@16.10.0 on 2025-02-16T22:32:01.621Z
+2
View File
@@ -9,6 +9,8 @@ yarn.lock
.env
.env.submit
dependency-graph.svg
# Build
extension.zip
build/
+2
View File
@@ -12,6 +12,7 @@
"build:firefox": "cross-env MODE=firefox vite build",
"build:safari": "cross-env MODE=safari vite build",
"convert:safari": "xcrun safari-web-extension-converter dist/safari --project-location . --app-name $npm_package_name-safari",
"dependency-graph": "depcruise src --include-only \"^src\" --output-type dot | dot -T svg > dependency-graph.svg",
"release": "gh release create $npm_package_name@$npm_package_version ./dist/*.zip --generate-notes",
"publish": "bun lib/publish.js --b",
"zip": "bedframe zip"
@@ -38,6 +39,7 @@
"@types/mime-types": "^2.1.4",
"@vitejs/plugin-react-swc": "^3.7.2",
"cross-env": "^7.0.3",
"dependency-cruiser": "^16.10.0",
"eslint": "^8.57.1",
"glob": "^11.0.1",
"mime-types": "^2.1.35",
@@ -1,9 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import type { Background } from './types';
export let filteredBackgrounds: Background[];
let dispatch = createEventDispatcher();
let filters = $state({
@@ -13,9 +9,9 @@
orientation: [] as string[]
});
$: {
$effect(() => {
dispatch('filter', filters);
}
});
function toggleFilter(category: keyof typeof filters, value: string) {
if (filters[category].includes(value)) {
@@ -42,11 +38,11 @@
<h3 class="mb-2 font-medium">Type</h3>
<div class="space-y-2">
<label class="flex items-center">
<input type="checkbox" checked={filters.type.includes('image')} on:change={() => toggleFilter('type', 'image')}>
<input type="checkbox" checked={filters.type.includes('image')} onchange={() => toggleFilter('type', 'image')}>
<span class="ml-2">Image</span>
</label>
<label class="flex items-center">
<input type="checkbox" checked={filters.type.includes('video')} on:change={() => toggleFilter('type', 'video')}>
<input type="checkbox" checked={filters.type.includes('video')} onchange={() => toggleFilter('type', 'video')}>
<span class="ml-2">Video</span>
</label>
</div>
@@ -56,7 +52,7 @@
<button
class="px-4 py-2 mt-4 text-white bg-red-500 rounded hover:bg-red-600"
on:click={clearFilters}
onclick={clearFilters}
>
Clear Filters
</button>
@@ -98,7 +98,7 @@
</script>
<div
class="w-full pt-5 mb-1"
class="pt-5 mb-1 w-full"
role="list"
tabindex="-1"
ondragover={handleDragOver}
@@ -106,9 +106,9 @@
ondrop={handleDrop}
>
<div class="{isDragging ? 'opacity-100' : 'opacity-0'} transition pointer-events-none absolute w-full p-2 z-50">
<div class="sticky w-full h-64 bg-white shadow-xl dark:bg-zinc-900 top-5 dark:text-white rounded-xl outline-dashed outline-4 outline-zinc-200 dark:outline-zinc-700">
<div class="flex items-center justify-center h-full">
<div class="flex flex-col items-center justify-center">
<div class="sticky top-5 w-full h-64 bg-white rounded-xl shadow-xl dark:bg-zinc-900 dark:text-white outline-dashed outline-4 outline-zinc-200 dark:outline-zinc-700">
<div class="flex justify-center items-center h-full">
<div class="flex flex-col justify-center items-center">
<svg height="48" width="48" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
<g fill="currentColor">
<path d="M44,31a1,1,0,0,0-1,1v8a3,3,0,0,1-3,3H8a3,3,0,0,1-3-3V32a1,1,0,0,0-2,0v8a5.006,5.006,0,0,0,5,5H40a5.006,5.006,0,0,0,5-5V32A1,1,0,0,0,44,31Z" fill="currentColor"/>
@@ -130,7 +130,7 @@
>
{#if isEditMode}
<div
class="absolute z-20 flex w-6 h-6 p-2 text-white bg-red-600 rounded-full opacity-100 right-2 place-items-center top-2"
class="flex absolute top-2 right-2 z-20 place-items-center p-2 w-6 h-6 text-white bg-red-600 rounded-full opacity-100"
onclick={(event) => { event.stopPropagation(); handleThemeDelete(theme.id) }}
onkeydown={(event) => { if (event.key === 'Enter' || event.key === ' ') handleThemeDelete(theme.id) }}
role="button"
@@ -152,7 +152,7 @@
</div>
<div
class="absolute z-20 flex w-8 h-8 p-2 text-center transition-all -translate-y-1/2 rounded-full opacity-0 text-white/80 top-1/4 right-12 bg-black/50 place-items-center group-hover:opacity-100 group-hover:top-1/2"
class="flex absolute right-12 top-1/4 z-20 place-items-center p-2 w-8 h-8 text-center rounded-full opacity-0 transition-all -translate-y-1/2 text-white/80 bg-black/50 group-hover:opacity-100 group-hover:top-1/2"
onclick={(event) => { event.stopPropagation(); handleShareTheme(theme) }}
onkeydown={(event) => { if (event.key === 'Enter' || event.key === ' ') handleShareTheme(theme) }}
role="button"
@@ -167,7 +167,7 @@
<img
src={typeof theme.coverImage === 'string' ? theme.coverImage : URL.createObjectURL(theme.coverImage)}
alt={theme.name}
class="absolute inset-0 z-0 object-cover w-full h-full pointer-events-none"
class="object-cover absolute inset-0 z-0 w-full h-full pointer-events-none"
/>
{/if}
{#if !theme.hideThemeName}
@@ -179,7 +179,7 @@
{/if}
{#if tempTheme}
<div class="flex justify-center w-full bg-gray-200 rounded-xl dark:bg-zinc-700/50 place-items-center aspect-theme animate-pulse">
<div class="flex justify-center place-items-center w-full bg-gray-200 rounded-xl animate-pulse dark:bg-zinc-700/50 aspect-theme">
<svg class="w-5 h-5 text-white animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
@@ -193,7 +193,7 @@
<button
onclick={() => OpenStorePage()}
class="flex items-center justify-center w-full transition aspect-theme rounded-xl bg-zinc-100 dark:bg-zinc-900 dark:text-white"
class="flex justify-center items-center w-full rounded-xl transition aspect-theme bg-zinc-100 dark:bg-zinc-900 dark:text-white"
>
<span class="text-xl font-IconFamily">&#xecc5;</span>
<span class="ml-2">Theme Store</span>
@@ -201,7 +201,7 @@
<button
onclick={() => { OpenThemeCreator(); closeExtensionPopup() }}
class="flex items-center justify-center w-full transition aspect-theme rounded-xl bg-zinc-100 dark:bg-zinc-900 dark:text-white"
class="flex justify-center items-center w-full rounded-xl transition aspect-theme bg-zinc-100 dark:bg-zinc-900 dark:text-white"
>
<span class="text-xl font-IconFamily">&#xec60;</span>
<span class="ml-2">Create your own</span>