IndexStore 是一个库,它提供了一种基于查询的方法,用于在索引代码库中搜索和使用源代码符号。 它构建于 Apple IndexStoreDB 库之上,该库提供了对 swift 编译器生成的索引数据的访问。
使用此库,您可以轻松地搜索和分析代码中的符号,使其成为构建开发者工具、静态分析器和代码重构实用程序的强大工具。
Apple IndexStoreDB 库尚未被认为是稳定的,因为它没有可解析的语义版本标签。 此项目指向 repo 上的一个发布分支,并被积极维护。
IndexStore
是 indexstore-db
之上的一个抽象层,旨在简化查询并使代码库探索更加直观。 以下是驱动其功能的关键概念
在其核心,代码中的每个不同的命名实体(例如函数、类或变量)都表示为一个符号。 当您在 IndexStore
中查询符号时,您正在寻找其主要定义和关联的元数据。
将 USR 视为符号的唯一指纹。 这是一个一致的标识符,可以确保即使符号出现在不同的位置或跨项目中,我们也会知道它是同一个实体。
SourceSymbol
实例不仅仅是静态实体; 它们存在并贯穿于您的代码中。 当您查询符号的出现位置时,它旨在捕获项目中符号的每个特定实例或引用,从而揭示该符号在代码库中的足迹。
除了找到符号存在或出现的位置之外,通常重要的是了解其更广泛的上下文和关系。 Related Occurrences 就是这样做的,它会获取与查询符号共享定义关系的符号和实例。 这可以包括覆盖、实现、关联等,从而提供更丰富的特定符号如何与项目中其他符号交互的图景。
要在您的项目中使用 IndexStore
,您需要使用有效的 Configuration
实例来实例化一个索引。
Configuration
包含项目目录、libIndexStore 和 IndexStoreDB 数据库的路径等。 开始使用的唯一必需值是 projectDirectory
位置,它是您正在评估的项目的工作目录。
默认情况下,配置将根据正在运行的进程自动解析所需的 indexStorePath
和 libIndexStorePath
。 这将使用 xcode-select
和 ProcessInfo().environment
来获取 projectDirectory
中项目的索引存储详细信息。
您也可以通过提供自己的值来覆盖此设置。
准备好配置后,您可以创建一个 IndexStore
实例
// Manual Configuration
let configuration = Configuration(projectDirectory: "path/to/project/root")
instanceUnderTest = IndexStore(configuration: configuration)
Configuration
也是 Decodable
,可以从 JSON 文件构建
let configuration = try Configuration.fromJson(at: configPath)
instanceUnderTest = IndexStore(configuration: configuration)
配置好 IndexStore
实例后,您可以开始查询符号
IndexStore
import IndexStore
IndexStore
实例查询符号、出现位置或其他信息// Query for functions by name
let results = indexStore.querySymbols(.functions("someFunctionName"))
// Find all class symbols
let classSymbols = indexStore.querySymbols(.kinds([.class]))
// Find all extensions of a type
let results = indexStore.querySymbols(.extensions(ofType: "MyClass"))
// Find all extensions of a class within specific source files
let results = indexStore.querySymbols(.extensions(in: ["path", "path"], matching: "XCTest"))
// Find all invocations of a function symbol
let function = indexStore.querySymbols(.functions("someFunctionName"))[0]
let results = indexStore.invocationsOfSymbol(function)
// Find all symbols declared in a specific file
let symbols = indexStore.querySymbols(
.withSourceFiles(["/path/to/your/project/SourceFile.swift"])
.withKinds(SourceKind.allCases)
.withRoles(.all)
)
获得符号后,无论是通过一般查询还是从其他结果中提取,您还可以通过符号(或 usr)查找出现位置。 您还可以提供有效的查询来进一步过滤结果。
// Find UIColor declaration
let colorSymbol indexStore.querySymbols(
.withQuery("UIColor")
.withAnchorStart(true)
.withAnchorEnd(true)
.withRestrictingToProjectDirectory(false)
.withKinds([.class])
.first!
// Look up any occurrences of the UIColor symbol
let occurrences = indexStore.queryOccurrences(ofSymbol: colorSymbol, query: .empty)
获得符号后,无论是通过一般查询还是从其他结果中提取,您还可以通过符号(或 usr)查找相关的出现位置。 您还可以提供有效的查询来进一步过滤结果。
// Find UIColor declaration
let colorSymbol indexStore.querySymbols(
.withQuery("UIColor")
.withAnchorStart(true)
.withAnchorEnd(true)
.withRestrictingToProjectDirectory(false)
.withKinds([.class])
.first!
// Look up any occurrences of the UIColor symbol
let occurrences = indexStore.queryRelatedOccurences(ofSymbol: colorSymbol, query: .empty)
IndexStore 为常见的静态分析任务提供了便捷方法
let conformingSymbols = indexStore.sourceSymbols(conformingToProtocol: "SomeProtocol")
let subclassingSymbols = indexStore.sourceSymbols(subclassing: "SomeClass")
let invocations = indexStore.invocationsOfSymbol(someSymbol)
let isInvokedByTestCase = indexStore.isSymbolInvokedByTestCase(someSymbol)
let emptyExtensions = indexStore.sourceSymbols(forEmptyExtensionsMatching: "SomeType")
将以下内容添加到您的 Package.swift
文件中
let package = Package(
// name, platforms, products, etc.
dependencies: [
// other dependencies
.package(url: "https://github.com/CheekyGhost-Labs/IndexStore.git", branch: "release/3.0"),
],
targets: [
.executableTarget(name: "<command-line-tool>", dependencies: [
// other dependencies
.product(name: "IndexStore", package: "IndexStore")
]),
// other targets
]
)
IndexStore 在 MIT 许可证下可用。 有关更多信息,请参阅 LICENSE 文件。
Swift Markdown 使用 GitHub Issues 跟踪所有错误报告。 您可以使用“IndexStore”组件来处理特定于 IndexStore 的问题和功能请求。 当您提交错误报告时,我们要求您尽可能详细地描述并包含尽可能多的信息来记录或重新创建该问题。
对于功能请求,请随时提交 GitHub issue
如果您发现可以通过改进 IndexStore 来更好地满足您的需求,请不要犹豫提交功能请求。
由于 Apple IndexStoreDB Library repo 使用分支进行发布而不是标记稳定版本,因此 IndexStore repo 无法遵循传统的语义版本和 Git Flow 方法。
IndexStore 采用的发布方法是
发布分支将具有语义版本,但不考虑补丁更新。 例如
release/1.0
release/1.1
任何 patch
更改(不更改公共界面的错误修复和改进)都将根据需要拉入相应的发布分支。
任何 minor
更新(向后兼容的公开可见更改)都将拥有自己的发布分支。
任何 major
更新(不向后兼容的公开可见更改)都将拥有自己的发布分支。
当 Apple IndexStoreDB Library 变得稳定时,发布仍将被标记。 这也将使我们能够更轻松地管理补丁版本。
在大多数情况下,应该针对 develop
分支发出拉取请求,以协调具有多个功能和修复的发布。 这还提供了一种在实际环境中使用 develop
分支进行测试的方法,以进一步测试待发布的版本。 准备好发布后,它将被合并到 main
中,并且从 main
分支创建/更新发布分支。
如果要修复旧版本,则可以针对预期的发布分支发出拉取请求,并且可以根据需要借助维护人员将更改纳入其他分支。
开始使用
Fork 存储库:首先,将项目 fork 到您自己的 GitHub 帐户。
克隆 fork 的存储库:fork 后,将 fork 的存储库克隆到您的本地计算机,以便您可以进行更改。
git clone https://github.com/CheekyGhost-Labs/IndexStore.git
git switch -c your-feature-branch
遵循 Swift 语言指南:确保您的代码遵循 Swift 语言指南,以了解样式和语法约定。
进行更改:实现您的功能或错误修复,遵循项目的代码风格和最佳实践。 不要忘记添加测试并根据需要更新文档。
提交您的更改:使用描述性和简洁的提交消息提交您的更改。 使用祈使语气,并解释您的提交所做的事情,而不是您做了什么。
# Feature
git commit -m "Feature: Adding convenience method for resolving awesomeness"
# Bug
git commit -m "Bug: Fixing issue where awesome query was not including awesome"
git pull origin develop
git push origin your-feature-branch
develop
分支为目标。 在拉取请求模板中填写必要的详细信息,并等待项目维护人员审查您的贡献。请确保为任何更改添加单元测试。 目标不是 100%
的覆盖率,而是有意义的测试覆盖率,以确保您的更改按预期运行,而不会对现有行为产生负面影响。
请注意,项目维护人员可能会要求您对您的贡献进行更改或提供其他信息。 乐于接受反馈,并愿意根据需要进行调整。 一旦您的拉取请求获得批准并合并,您的更改将成为项目的一部分!