File: Code.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (95 lines) | stat: -rw-r--r-- 5,253 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
 This source file is part of the Swift.org open source project

 Copyright (c) 2021-2023 Apple Inc. and the Swift project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See https://swift.org/LICENSE.txt for license information
 See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation
import Markdown

/**
A code file to display alongside a ``Step``.
*/
public final class Code: Semantic, DirectiveConvertible {
    public static let introducedVersion = "5.5"
    public static let directiveName = "Code"
    
    /// The original `BlockDirective` node that was parsed into this semantic code.
    public let originalMarkup: BlockDirective
    
    /// A reference to the file containing the code that should be loaded from the bundle.
    public let fileReference: ResourceReference
    /// The name of the file, for display and identification purposes.
    /// If the ``fileName`` does not change between two consecutive steps (possibly across ``TutorialSection``s),
    /// the changes between the two files may be indicated in the UI.
    public let fileName: String
    /// If specified, should present a diff between this property and ``fileReference``.
    public let previousFileReference: ResourceReference?
    /// Whether a diff should be shown. See ``Code/fileName`` for more information.
    public let shouldResetDiff: Bool
    /// A preview image or video overlay.
    public let preview: Media?
    
    enum Semantics {
        enum File: DirectiveArgument {
            static let argumentName = "file"
        }
        enum PreviousFile: DirectiveArgument {
            static let argumentName = "previousFile"
        }
        enum Name: DirectiveArgument {
            static let argumentName = "name"
        }
        enum ResetDiff: DirectiveArgument {
            typealias ArgumentValue = Bool
            static let argumentName = "reset"
        }
    }
    
    init(originalMarkup: BlockDirective, fileReference: ResourceReference, fileName: String, previousFileReference: ResourceReference?, shouldResetDiff: Bool, preview: Media?) {
        self.originalMarkup = originalMarkup
        self.fileReference = fileReference
        self.fileName = fileName
        self.previousFileReference = previousFileReference
        self.shouldResetDiff = shouldResetDiff
        self.preview = preview
    }
    
    public convenience init?(from directive: BlockDirective, source: URL?, for bundle: DocumentationBundle, in context: DocumentationContext, problems: inout [Problem]) {
        precondition(directive.name == Code.directiveName)
        
        let arguments = Semantic.Analyses.HasOnlyKnownArguments<Code>(severityIfFound: .warning, allowedArguments: [Semantics.File.argumentName, Semantics.PreviousFile.argumentName, Semantics.Name.argumentName, Semantics.ResetDiff.argumentName]).analyze(directive, children: directive.children, source: source, for: bundle, in: context, problems: &problems)
        
        Semantic.Analyses.HasOnlyKnownDirectives<Code>(severityIfFound: .warning, allowedDirectives: [ImageMedia.directiveName, VideoMedia.directiveName]).analyze(directive, children: directive.children, source: source, for: bundle, in: context, problems: &problems)
        
        guard let requiredFileReference = Semantic.Analyses.HasArgument<Code, Semantics.File>(severityIfNotFound: .warning).analyze(directive, arguments: arguments, problems: &problems) else { return nil }
        let fileReference = ResourceReference(bundleIdentifier: bundle.identifier, path: requiredFileReference)
        
        guard let requiredFileName = Semantic.Analyses.HasArgument<Code, Semantics.Name>(severityIfNotFound: .warning).analyze(directive, arguments: arguments, problems: &problems) else { return nil }
        
        // ResetDiff is optional and defaults to false. If it exists, however, extract it using analysis so we get
        // diagnostics for type mismatches.
        let shouldResetDiff: Bool
        if arguments.keys.contains(Semantics.ResetDiff.argumentName) {
            shouldResetDiff = Semantic.Analyses.HasArgument<Code, Semantics.ResetDiff>(severityIfNotFound: nil).analyze(directive, arguments: arguments, problems: &problems) ?? false
        } else {
            shouldResetDiff = false
        }
       
        let (optionalPreview, _) = Semantic.Analyses.HasExactlyOneImageOrVideoMedia<Code>(severityIfNotFound: nil).analyze(directive, children: directive.children, source: source, for: bundle, in: context, problems: &problems)
        
        let optionalPreviousFileReference = Semantic.Analyses.HasArgument<Code, Semantics.PreviousFile>(severityIfNotFound: nil).analyze(directive, arguments: arguments, problems: &problems).map { argument in
            ResourceReference(bundleIdentifier: bundle.identifier, path: argument)
        }
        
        self.init(originalMarkup: directive, fileReference: fileReference, fileName: requiredFileName, previousFileReference: optionalPreviousFileReference, shouldResetDiff: shouldResetDiff, preview: optionalPreview)
    }
    
    public override func accept<V>(_ visitor: inout V) -> V.Result where V : SemanticVisitor {
        return visitor.visitCode(self)
    }
}