skott

repository·main·Indexed 21 days ago

https://github.com/antoine-coulon/skott

A minimalist developer tool for generating directed graphs from JavaScript, TypeScript, and Node.js projects. It is used to detect circular dependencies, find unused code and npm dependencies, and visualize project architecture via a CLI, a web application, or static files (SVG, PNG, JSON, Mermaid). It includes a JavaScript API for programmatic graph analysis and the @skottorg/static-file-plugin for static visualization exports.

Tokens
21.9K
Snippets
73
Records
90
Agent score
74%

What's inside skott

  1. Generate static visualizations with @skottorg/static-file-plugin

    main

    To generate static files like .svg, .png, .md, or .json, you must install the @skottorg/static-file-plugin. Skott uses the Node resolution algorithm to find the plugin automatically; you do not need to explicitly configure it in your command.

    Installation and Usage:

    npm install @skottorg/static-file-plugin
    skott src/index.js --displayMode=svg
  2. Use the skott web application

    main

    The skott web application is the visual interface used when running the skott CLI with the --displayMode=webapp flag. While it is embedded within the CLI, it is also published as a standalone library on npm and can be used independently of the skott CLI.

    # Example CLI usage to trigger the web application
    skott --displayMode=webapp
  3. Group modules into architectural blocks with groupBy

    main

    If you want to see links between high-level architectural components rather than individual files, use the groupBy option in SkottConfig.

    When groupBy is provided, getStructure() returns a groupedGraph. This graph contains nodes representing the groups, where each node's body includes:

    • size: The aggregate size of all files in the group.
    • files: An array of file paths belonging to that group.
    • thirdPartyDependencies: The combined set of third-party dependencies for the group.
    • builtinDependencies: The combined set of built-in dependencies for the group.

    Example usage:

    const instance = await skott({
      groupBy: (path) => {
        if (path.includes("core")) return "core";
        if (path.includes("feature-a")) return "feature-a";
        return undefined;
      }
    }).initialize();
    
    const { groupedGraph } = instance.getStructure();
    // Access a specific group
    const coreGroup = groupedGraph["core"];
    const instance = await skott({
      groupBy: (path) => {
        if (path.includes("core")) return "core";
        if (path.includes("feature-a")) return "feature-a";
        return undefined;
      }
    }).initialize();
    
    const { groupedGraph } = instance.getStructure();
    
    // groupedGraph["core"] contains aggregated data for all 'core' files
  4. How module resolution order works

    main

    When resolving an imported module path, skott attempts to match the declaration against several ECMAScript module combinations in a specific priority order. This ensures that directory imports (e.g., ./lib resolving to ./lib/index.js) and TypeScript-specific patterns (e.g., .js extensions in TS files resolving to .ts files) are handled correctly.

    The resolution order is:

    1. JS_INDEX_MODULE (module/index.js)
    2. TS_MODULE (module.ts)
    3. TS_INDEX_MODULE (module/index.ts)
    4. TS_MODULE_WITH_JS_EXTENSION (stripping .js and adding .ts)
    5. JS_MODULE (module.js)
    6. TSX_MODULE (module.tsx)
    7. TSX_INDEX_MODULE (module/index.tsx)
    8. JSX_MODULE (module.jsx)
    9. JSX_INDEX_MODULE (module/index.jsx)
    10. JS_INDEX_MODULE (fallback)

    If no match is found, a ModuleNotFoundError is raised.

  5. Understand the skott-webapp Application State structure

    main

    The application state is divided into two main branches: data and ui.

    Data State (DataState)

    Extends SkottStructureWithCycles and adds tracking options to control how dependencies are categorized:

    • builtin: Tracks built-in dependencies.
    • thirdParty: Tracks third-party dependencies.
    • typeOnly: Tracks type-only imports.

    UI State (UiState)

    Controls the visual presentation and filtering of the graph:

    • visualization: Controls granularity (either module or group).
    • filters: Uses a glob string to filter files.
    • network: Manages the selected node, dependency visibility toggles (deep, circular, builtin, thirdparty), and the layout configuration.
  6. Configure skott analysis options

    main

    When using the API, you can pass a configuration object to skott() to control the scope and depth of the analysis.

    Configuration Keys

    • cwd: (string) The current working directory to start the analysis from.
    • entrypoint: (string) A specific file path to start traversal from. This will discard all files not part of the graph reachable from this entrypoint.
    • ignorePatterns: (string[]) An array of glob patterns to exclude from the analysis.
    • dependencyTracking: (object) Controls which types of dependencies are collected.
      • builtin: (boolean) Whether to track built-in Node.js modules.
      • thirdParty: (boolean) Whether to track third-party npm dependencies.
      • typeOnly: (boolean) Whether to track TypeScript type-only imports.
    // Example configuration
    await skott({
        cwd: "packages/skott",
        entrypoint: "packages/skott/index.ts",
        ignorePatterns: ["**/node_modules/**"],
        dependencyTracking: {
            builtin: true,
            thirdParty: true,
            typeOnly: true
        }
    });
  7. Understand SkottStructureWithMetadata and SkottStructureWithCycles types

    main

    When working with the skott web application or consuming skott's output, you may encounter extended versions of the base SkottStructure.

    • SkottStructureWithMetadata: Combines the base SkottStructure with SkottMetadata, which includes the entrypoint string.
    • SkottStructureWithCycles: Extends SkottStructureWithMetadata by adding SkottCycles, which contains an array of cycles (where each cycle is represented as an array of module paths string[][]).
  8. Validation rules for entrypoint and cwd

    main

    Skott enforces specific constraints when using an entrypoint to ensure analysis consistency:

    1. includeBaseDir constraint: You cannot set includeBaseDir: true if an entrypoint is not provided.
    2. cwd constraint: If an entrypoint is provided, you cannot customize the cwd (it must match the current process working directory).
  9. Understand Skott's incremental caching mechanism

    main

    Skott uses an incremental caching system to speed up analysis by storing previously computed node data and configuration hashes.

    How it works:

    1. Configuration Hashing: On initialization, Skott hashes the current SkottConfig. If the configuration has changed since the last run, the existing cache is invalidated and a new one is created.
    2. File Hashing: Each source file is hashed based on its content. This allows Skott to determine if a file's dependencies or structure need re-computation.
    3. Cache Storage: The cache is stored in a file named .skott/cache.json in the current working directory.
    4. Incremental Mode: Caching is only active if incremental: true is set in your SkottConfig. If disabled, the cache is ignored.

    Cache Invalidation:

    • If the SkottConfig changes, the entire cache is wiped.
    • If a file's content changes, its hash will no longer match the cached version, triggering a re-analysis of that node.
  10. Use the skott CLI to analyze dependencies

    main

    The skott CLI starts a dependency analysis to build a graph of your project. You can specify an optional [entrypoint] file and use various flags to control how the graph is built, what is tracked, and how the results are displayed.

    Common Usage Examples

    # Analyze a specific entrypoint and display as a file tree
    ./node_modules/.bin/skott src/index.js --displayMode=file-tree --no-trackTypeOnlyDependencies
    
    # Specify file extensions and a custom tsconfig
    ./node_modules/.bin/skott --fileExtensions=.ts,.tsx --tsconfig=tsconfig.base.json
    
    # Show circular dependencies in raw mode with watch mode enabled
    ./node_modules/.bin/skott --showCircularDependencies --displayMode=raw --watch
    #!/usr/bin/env node
    # Example usage commands:
    ./node_modules/.bin/skott src/index.js --displayMode=file-tree --no-trackTypeOnlyDependencies
    ./node_modules/.bin/skott --fileExtensions=.ts,.tsx --tsconfig=tsconfig.base.json
    ./node_modules/.bin/skott --showCircularDependencies --displayMode=raw --watch
  11. Build a filesystem tree structure from flat paths with fs-tree-structure

    main

    fs-tree-structure is a utility that converts a flat array of file path strings into a nested object representing a filesystem tree structure. This is useful for visualizing directory hierarchies or processing file paths as a tree.

    To use it, pass an array of strings (paths) to the makeTreeStructure function. The resulting object uses directory names as keys and files as leaf nodes (empty objects).

    const filePaths = ["lib/feature/index.js", "lib/feature/util/index.js"];
    
    const treeStructure = makeTreeStructure(filePaths);
    
    // treeStructure will be:
    // {
    //   lib: {
    //     feature: {
    //       "index.js": {},
    //       util: {
    //         "index.js": {}
    //       }
    //     }
    //   }
    // }