Hone logo
Hone
Problems

Vue Component Dependency Analyzer

This challenge requires you to build a system that can analyze the dependencies between Vue components. Understanding these dependencies is crucial for tasks like code splitting, performance optimization, and identifying potential circular dependencies. You will create a function that takes a map of Vue components and their source code, and returns a structured representation of their relationships.

Problem Description

Your task is to implement a analyzeVueDependencies function that takes a collection of Vue components, represented by their names and source code, and returns an object detailing the import relationships between them.

Key Requirements:

  1. Input: The function will receive an object where keys are component names (strings) and values are the raw Vue component source code (strings).
  2. Dependency Extraction: For each component, you need to identify which other components (from the provided input map) it imports. This analysis should focus on:
    • import ... from './ComponentName' (and variations with .vue extension)
    • import ... from '@/ComponentName' (assuming @ resolves to the project root and ComponentName refers to a component within the input map)
    • import ... from '../components/ComponentName'
    • import ... from './subfolder/ComponentName'
    • Note: For simplicity, assume all imported components are directly available in the input map and do not require complex module resolution logic (like Webpack aliases beyond @). You are only looking for direct string matches within the import statements that correspond to component names in the input map.
  3. Output: The function should return an object where keys are component names, and values are arrays of component names that are directly imported by that component.
  4. Self-Dependencies: A component should not be listed as a dependency of itself.
  5. No Dependencies: If a component imports nothing or imports modules not present in the input map, its dependency list should be an empty array.

Expected Behavior:

The analyzer should accurately map each component to a list of other components it directly depends on.

Edge Cases:

  • Components with no imports.
  • Components that import external libraries or modules not defined in the input.
  • Components that import other components within the same directory.
  • Components that import components from parent or child directories.
  • Components using the @ alias.

Examples

Example 1:

Input: {
  "App.vue": `
    <template>
      <div>
        <MyComponent />
        <AnotherComponent />
      </div>
    </template>
    <script setup>
      import MyComponent from './MyComponent.vue';
      import AnotherComponent from '@/components/AnotherComponent';
      import { ref } from 'vue';
      import axios from 'axios';
    </script>
  `,
  "MyComponent.vue": `
    <template>
      <div>Hello from MyComponent</div>
    </template>
    <script setup>
      import BaseButton from './ui/BaseButton.vue';
      import AnotherComponent from '../components/AnotherComponent.vue';
    </script>
  `,
  "AnotherComponent.vue": `
    <template>
      <div>Hello from AnotherComponent</div>
    </template>
    <script setup>
      import { computed } from 'vue';
    </script>
  `,
  "BaseButton.vue": `
    <template>
      <button>Click Me</button>
    </template>
  `
}
Output: {
  "App.vue": ["MyComponent", "AnotherComponent"],
  "MyComponent.vue": ["BaseButton", "AnotherComponent"],
  "AnotherComponent.vue": [],
  "BaseButton.vue": []
}
Explanation:
- App.vue imports MyComponent and AnotherComponent.
- MyComponent imports BaseButton and AnotherComponent.
- AnotherComponent has no imports from the provided list.
- BaseButton has no imports.

Example 2:

Input: {
  "Parent.vue": `
    <template>
      <Child />
    </template>
    <script>
      import Child from './Child.vue';
    </script>
  `,
  "Child.vue": `
    <template>
      <div>I am a child</div>
    </template>
    <script setup>
      // No imports from the map
    </script>
  `
}
Output: {
  "Parent.vue": ["Child"],
  "Child.vue": []
}
Explanation: Parent.vue imports Child.vue. Child.vue has no imports.

Example 3: Circular Dependency (and irrelevant imports)

Input: {
  "A.vue": `
    <script>
      import B from './B.vue';
      import C from './C.vue'; // C is not in the input map
    </script>
  `,
  "B.vue": `
    <script setup>
      import A from './A.vue';
      import D from '../components/D.vue'; // D is not in the input map
    </script>
  `
}
Output: {
  "A.vue": ["B"],
  "B.vue": ["A"]
}
Explanation: A.vue imports B. B.vue imports A. Imports for C and D are ignored as they are not present in the input map.

Constraints

  • The input components object will contain at least one component.
  • Component names and source code will be valid strings.
  • The analysis should focus on import ... from '...' statements within <script> or <script setup> blocks.
  • Regular expressions can be used for parsing import statements, but ensure they are robust enough for common import patterns.
  • Performance is not a critical concern for this challenge, but the solution should be reasonably efficient.
  • Assume all relative paths (./, ../) and the @ alias point to potential component files that, if they were actual files, would be part of the same project and resolvable to one of the keys in the input map. The matching logic should be based on the last part of the path (e.g., MyComponent from ./MyComponent.vue or ./subfolder/MyComponent).

Notes

  • You'll likely need to parse the <script> and <script setup> blocks from the Vue SFC (Single File Component) source code.
  • Pay attention to how to extract the component name from import paths. For example, ./MyComponent.vue, ./subfolder/MyComponent, and ./subfolder/MyComponent.js should all resolve to the component name "MyComponent" if it exists in the input map.
  • Consider using a simple approach for resolving the @ alias, such as assuming it directly maps to the root directory where component names are expected.
  • This challenge is an exercise in static code analysis. You do not need to run any Vue code or consider runtime behavior.
  • The primary goal is to accurately identify direct import relationships between the provided components.
Loading editor...
typescript