工厂
2022-12-17-a

ci build status

factory 是一个结构化的、类型安全的源代码生成工具。它旨在替代(并改进)gyb 工具!

factoryswift-syntax 驱动,因此它会随着工具链一起发展。您不能使用 5.6.2 发行版本的工具链运行它,因为 5.6.2 工具链版本太旧,不支持 factory 安全转换源代码所需的 API。

当前的工具链版本锁定为

swift-DEVELOPMENT-SNAPSHOT-2022-12-17-a

factory 生成 的 Swift 文件仍然是向后兼容的,事实上,factory 的主要用例之一就是向后部署。

平台

SPF 官方支持 Linux 和 macOS。

请注意,在 macOS 上,SPM 默认设置了错误的 @rpath,因此您需要在构建产物目录中手动添加指向 lib_InternalSwiftSyntaxParser.dylib 的符号链接。

概述

factory 的设计考虑了以下目标

  1. 模板文件应该看起来像普通的 .swift 文件,这样代码高亮器和 IDE 就不会出错。

  2. 模板应该是安全的,并禁止任意的字符串拼接或 token 替换。

  3. 模板应该与文档注释良好配合。

  4. 模板语法应该是最小化的、纯粹的附加性的,并且源代码生成工具应该接受并返回原生的 .swift 源代码,保持不变。

  5. 模板用户应该能够根据需要使用尽可能多或尽可能少的模板,并且在一个声明上使用模板不应增加文件中其余代码的认知负担。

  6. 模板系统应该引导用户尽可能少地使用模板,以满足他们的用例。

  7. 模板源代码应该是自解释的,并且对于从未听说过 swift-package-factory 的开发人员来说也应该是可以理解的。

  8. 模板用户应该能够*停止*使用模板系统,并且能够在任何时候承担维护生成的 .swift 文件的责任。

简而言之

Basic.spf

extension Int
{
    @matrix(__ordinal__: [i, j, k], __value__: [0, 1, 2])
    @inlinable public 
    var __ordinal__:Int 
    {
        __value__
    }

    @basis 
    let cases:[Never] = [a, b]

    enum Cases:Int
    {
        @matrix(__case__: cases)
        case __case__
    }

    @matrix(__case__: cases)
    public static 
    var __case__:Self 
    {
        Cases.__case__.rawValue
    }
}

Basic.spf.swift

extension Int
{
    @inlinable public 
    var i:Int 
    {
        0
    }
    @inlinable public 
    var j:Int 
    {
        1
    }
    @inlinable public 
    var k:Int 
    {
        2
    }

    enum Cases:Int
    {
        case a
        case b
    }

    public static 
    var a:Self 
    {
        Cases.a.rawValue
    }

    public static 
    var b:Self 
    {
        Cases.b.rawValue
    }
}

入门指南

查看 Examples 目录以了解如何使用 SPF!

功能特性

factory 使用三个属性扩展了 Swift 语言

  1. @basis

    定义了一个 token 序列,用于在从模板生成声明时进行迭代。它可以应用于 let 绑定,并且必须使用数组字面量进行初始化。

    它所附加的声明将从生成的 .swift 代码中删除,以及任何相关的注释和文档注释。

  2. @matrix

    复制它所附加的声明,以及任何相关的注释和文档注释。它接受 @basis 绑定或/和内联数组字面量作为参数,参数名称将成为循环变量的名称。如果给出多个 basis,@matrix 会将它们压缩在一起,并且如果它们的长度不同,则会丢弃尾部的 basis 元素。

    @matrix 可以应用于 associatedtypeactorclasscaseenumextensionfuncimportinitoperator、优先级组、protocolstructsubscripttypealiasletvar 声明。

  3. @retro

    将具有主关联类型的协议降级为不具有任何关联类型的协议,并通过 #if swift(>=5.7) 来分隔这两个变体。它可以应用于至少具有一个主关联类型的 protocol

    @retro 复制附加到原始 protocol 的任何注释和文档注释,并将它们包含在生成的 #if 代码块中。