Skip to content

Latest commit

ย 

History

History
573 lines (405 loc) ยท 17.6 KB

File metadata and controls

573 lines (405 loc) ยท 17.6 KB

Montage ์ฝ”๋“œ ๋ฌธ์„œํ™” ๊ฐ€์ด๋“œ๋ผ์ธ

English | ํ•œ๊ตญ์–ด

์ด ๋ฌธ์„œ๋Š” scripts/docc_to_md.js ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๊ธฐ ์œ„ํ•ด Montage ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ ์ค€์ˆ˜ํ•ด์•ผ ํ•  ์‚ฌํ•ญ๋“ค์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

1. ์ ‘๊ทผ ์ œ์–ด์ž

โš ๏ธ ํ•„์ˆ˜: public ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ

  • ์Šคํฌ๋ฆฝํŠธ๋Š” ์ •๊ทœ์‹์œผ๋กœ public ํ‚ค์›Œ๋“œ๋ฅผ ์ฐพ์•„ ํƒ€์ž…๊ณผ ๋ฉค๋ฒ„๋ฅผ ์ธ์‹ํ•ฉ๋‹ˆ๋‹ค.
  • public์ด ์—†์œผ๋ฉด ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
// โŒ Not documented
struct MyComponent {
    func myMethod() { }
}

// โœ… Documented
public struct MyComponent {
    public func myMethod() { }
}
        const typeRegex = /public\s+(enum|struct|class|protocol|actor)\s+(\w+)/g;
        let match;
        while ((match = typeRegex.exec(content)) !== null) {
          const typeName = match[2];
          swiftFileMap[typeName] = relBase;
        }
    const funcRegex = /public\s+(?:(static|class|mutating|nonmutating)\s+)?func\s+([^\{]+)/g;
    let result;
    while ((result = funcRegex.exec(body)) !== null) {
      const modifier = (result[1] || '').trim();
      const signatureBody = (result[2] || '').trim().replace(/\s+$/g, '');
      const kind = modifier ? `${modifier} func` : 'func';
      recordComponentExtensionSignature(componentTitle, typeName, kind, signatureBody);
    }

2. ํŒŒ์ผ๋ช…๊ณผ ํƒ€์ž…๋ช… ๋งคํ•‘

โš ๏ธ ์ฃผ์˜: ํŒŒ์ผ๋ช…์ด ์ปดํฌ๋„ŒํŠธ ์ œ๋ชฉ์œผ๋กœ ์‚ฌ์šฉ๋จ

  • ํŒŒ์ผ๋ช…(.swift ์ œ๊ฑฐ)์ด ์ปดํฌ๋„ŒํŠธ ์ œ๋ชฉ์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • ํŒŒ์ผ ๋‚ด๋ถ€์˜ ํƒ€์ž…๋ช…๊ณผ ํŒŒ์ผ๋ช…์ด ๋‹ค๋ฅด๋ฉด ๋งคํ•‘์ด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํŒŒ์ผ๋ช…๊ณผ ์ฃผ์š” ํƒ€์ž…๋ช…์„ ์ผ์น˜์‹œํ‚ค์„ธ์š”.

  • ์˜ˆ: Button.swift โ†’ public struct Button

      // Filename-based mapping (keep existing logic)
      const componentTitle = file.replace(/\.swift$/, '');
      swiftFileMap[componentTitle] = relBase;
      if (relPath.includes('1 Components')) {
        convertedSwiftFileMap[componentTitle.toLowerCase()] = { componentTitle, isConverted: false };
      }

๐Ÿšจ ์ค‘์š”: View Extension๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฌธ์„œ ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ

Popover.swift์ฒ˜๋Ÿผ ํŒŒ์ผ ๋‚ด์— public enum Popover ๊ฐ™์€ ํƒ€์ž…์ด ์—†๊ณ , View extension ํ•จ์ˆ˜๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ:

// Popover.swift
import SwiftUI

extension View {
    public func popover(...) -> some View {
        // Implementation
    }
}

์ด ๊ฒฝ์šฐ ๋ฌธ์„œ ํŽ˜์ด์ง€ ์ž์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  1. DocC๋Š” ํŒŒ์ผ ๋‚ด์˜ public ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ JSON ๋ฌธ์„œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  2. View extension๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ, DocC๊ฐ€ ํ•ด๋‹น ํŒŒ์ผ์— ๋Œ€ํ•œ ๋…๋ฆฝ์ ์ธ JSON ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (SwiftUICore ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ๋Š” ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ extension ํ•จ์ˆ˜๊ฐ€ ๋งŽ์•„์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ฐพ๊ธฐ์— ๋ถˆํŽธํ•ฉ๋‹ˆ๋‹ค.)
  3. ์Šคํฌ๋ฆฝํŠธ๋Š” DocC๊ฐ€ ์ƒ์„ฑํ•œ JSON ํŒŒ์ผ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งˆํฌ๋‹ค์šด์„ ์ƒ์„ฑํ•˜๋ฏ€๋กœ, JSON์ด ์—†์œผ๋ฉด ๋ฌธ์„œ ํŽ˜์ด์ง€๋„ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŒŒ์ผ๋ช…๊ณผ ๋™์ผํ•œ ์ด๋ฆ„์˜ View struct๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋นˆ enum ํ˜น์€ struct ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

// Popover.swift
import SwiftUI

// โœ… Add type for documentation page generation
public enum Popover {
    // Empty enum is sufficient (namespace role)
}

extension View {
    public func popover(...) -> some View {
        // Implementation
    }
}

๋˜๋Š”:

// Popover.swift
import SwiftUI

// โœ… Or use struct
public struct Popover {
    // Empty struct is sufficient
}

extension View {
    public func popover(...) -> some View {
        // Implementation
    }
}
  • ์—ฐ๊ด€๋œ ๋‹ค๋ฅธ ํƒ€์ž…์˜ Extension ํ•จ์ˆ˜๋“ค์€ ํ•ด๋‹น ํƒ€์ž…์˜ "Associated Extensions" ์„น์…˜์— ์ž๋™์œผ๋กœ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
  • ํƒ€์ž… ์ž์ฒด๋Š” ๋น„์–ด์žˆ์–ด๋„ ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ๋ฌธ์„œ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ "์•ต์ปค" ์—ญํ• ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿšจ ์ค‘์š”: ์ปดํฌ๋„ŒํŠธ ํ•˜์œ„ ํƒ€์ž…์€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์•ˆ์— ์ •์˜ํ•ด์•ผ ํ•จ

์ปดํฌ๋„ŒํŠธ์™€ ๊ด€๋ จ๋œ ํ•˜์œ„ ํƒ€์ž…(์˜ˆ: Style, Size, Configuration ๋“ฑ)์„ ๋ณ„๋„์˜ ์ตœ์ƒ์œ„ ํƒ€์ž…์œผ๋กœ ์ •์˜ํ•˜๋ฉด, ๊ฐ๊ฐ์ด ๋…๋ฆฝ์ ์ธ ๋ฌธ์„œ ํŽ˜์ด์ง€๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

// Button.swift
public struct Button { }

// โŒ Defined as separate top-level type in separate file or same file
public enum ButtonStyle { }
public enum ButtonSize { }

์ด ๊ฒฝ์šฐ ButtonStyle๊ณผ ButtonSize๊ฐ€ ๊ฐ๊ฐ ๋ณ„๋„์˜ ๋ฌธ์„œ ํŽ˜์ด์ง€๋กœ ์ƒ์„ฑ๋˜์–ด, ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ ๋ฌธ์„œ๋กœ ํ†ตํ•ฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์˜ enum ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์•ˆ์— ํ•˜์œ„ ํƒ€์ž…์„ ์ •์˜ํ•˜์„ธ์š”:

// Button.swift
public struct Button { }

// โœ… Defined within component namespace
public enum Button {
    public enum Style {
        case primary
        case secondary
    }

    public enum Size {
        case small
        case medium
        case large
    }
}
  1. ์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž…๋ช…์— ์ (.)์ด ์žˆ๋Š” ์ค‘์ฒฉ ํƒ€์ž…(Button.Style, Button.Size)์„ ๋ณ„๊ฐœ์˜ ๋ฌธ์„œ๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  2. ๋Œ€์‹  ๋ถ€๋ชจ ํƒ€์ž…์˜ Topics ์„น์…˜์— ํฌํ•จ์‹œ์ผœ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ ๋ฌธ์„œ๋กœ ํ†ตํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  3. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ด€๋ จ ํƒ€์ž…๋“ค์ด ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ทธ๋ฃนํ™”๋˜์–ด ์‚ฌ์šฉ์ž๊ฐ€ ์ฐพ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
      json.metadata.roleHeading === 'Enumeration' && json.metadata.title.split('.').length > 1 ||
      json.metadata.roleHeading === 'Case' ||
      json.metadata.roleHeading === 'Extended Class' ||
      json.metadata.roleHeading === 'Extended Structure' ||
      json.metadata.roleHeading === 'Extended Enumeration' ||
      json.metadata.roleHeading === 'Extended Protocol' ||
      json.metadata.roleHeading === 'API Collection' ||
      json.metadata.roleHeading === 'Structure' && json.metadata.title.split('.').length > 1) {
// โœ… Correct example: Integrated into a single component document
public struct Button {
    // Button implementation
}

public enum Button {
    public enum Style { }
    public enum Size { }
    public struct Configuration { }
}

// โŒ Incorrect example: Each generated as separate document
public struct Button { }
public enum ButtonStyle { }  // Separate document
public enum ButtonSize { }    // Separate document

3. ์ปดํฌ๋„ŒํŠธ์™€ ์—ฐ๊ด€๋œ ๋‹ค๋ฅธ ํƒ€์ž…์˜ Extension ์ž‘์„ฑ ๊ทœ์น™

โš ๏ธ ํ•„์ˆ˜: ์—ฐ๊ด€ Extension ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜/ํ”„๋กœํผํ‹ฐ๋Š” public์œผ๋กœ ์„ ์–ธํ•ด์•ผ ํ•จ

  • Extension ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜๋‚˜ ํ”„๋กœํผํ‹ฐ์— public ํ‚ค์›Œ๋“œ๊ฐ€ ์—†์œผ๋ฉด ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์Šคํฌ๋ฆฝํŠธ๋Š” ์ •๊ทœ์‹์œผ๋กœ ๊ฐ ๋ฉค๋ฒ„ ์„ ์–ธ ์•ž์˜ public ํ‚ค์›Œ๋“œ๋ฅผ ์ฐพ์•„ extension ๋ฉค๋ฒ„๋ฅผ ์ธ์‹ํ•ฉ๋‹ˆ๋‹ค.
extension View {
    // โŒ Not documented
    func button() -> some View { }

    // โœ… Documented
    public func button() -> some View { }
}

// โŒ Even if extension is public, members without public are not documented
public extension View {
    func button() -> some View { }  // No public โ†’ Not documented
}

// โœ… Both extension and members must be public
public extension View {
    public func button() -> some View { }  // Has public โ†’ Documented
}

โš ๏ธ ํ•„์ˆ˜: ์—ฐ๊ด€ Extension์€ ํŠน์ • ํŒจํ„ด๋งŒ ์ธ์‹๋จ

  • Extension ๋‚ด๋ถ€์˜ public func์™€ public var๋งŒ ์ธ์‹๋ฉ๋‹ˆ๋‹ค.
  • public subscript, public init ๋“ฑ์€ ์ •๊ทœ์‹์— ํฌํ•จ๋˜์ง€ ์•Š์•„ ์ธ์‹๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ณต์žกํ•œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋‚˜ ํŠน์ˆ˜ํ•œ ํŒจํ„ด์€ ํŒŒ์‹ฑ์— ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
// โœ… Recognized
extension SomeType {
    public func myMethod() { }
    public static func myStaticMethod() { }
    public class func myClassMethod() { }
    public mutating func myMutatingMethod() { }
    public var myProperty: String { }
    public static var myStaticProperty: String { }
}

// โŒ May not be recognized
extension SomeType {
    func privateMethod() { }  // No public
    public subscript(index: Int) -> Element { }  // subscript not in regex
    public init() { }  // init not in regex
}
    const funcRegex = /public\s+(?:(static|class|mutating|nonmutating)\s+)?func\s+([^\{]+)/g;
    let result;
    while ((result = funcRegex.exec(body)) !== null) {
      const modifier = (result[1] || '').trim();
      const signatureBody = (result[2] || '').trim().replace(/\s+$/g, '');
      const kind = modifier ? `${modifier} func` : 'func';
      recordComponentExtensionSignature(componentTitle, typeName, kind, signatureBody);
    }

    const varRegex = /public\s+(?:(static|class)\s+)?var\s+([^=\{]+)/g;
    while ((result = varRegex.exec(body)) !== null) {
      const modifier = (result[1] || '').trim();
      const signatureBody = (result[2] || '').trim().replace(/\s+$/g, '');
      const kind = modifier ? `${modifier} var` : 'var';
      recordComponentExtensionSignature(componentTitle, typeName, kind, signatureBody);
    }

โš ๏ธ ์ฃผ์˜: ์—ฐ๊ด€ Extension ๋ณธ๋ฌธ ํŒŒ์‹ฑ ์ œํ•œ

  • ์ค‘๊ด„ํ˜ธ ๋งค์นญ์œผ๋กœ extension ๋ณธ๋ฌธ์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
  • ์ค‘์ฒฉ๋œ ์ค‘๊ด„ํ˜ธ๊ฐ€ ๋งŽ๊ฑฐ๋‚˜ ๋ณต์žกํ•œ ๊ตฌ์กฐ์—์„œ๋Š” ํŒŒ์‹ฑ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
function extractExtensionBodies(content) {
  const bodies = [];
  const extRegex = /extension\s+(?:[A-Za-z0-9_]+\.)?([A-Za-z0-9_]+)\s*\{/g;
  let match;
  while ((match = extRegex.exec(content)) !== null) {
    const typeName = match[1];
    let braceDepth = 1;
    let idx = extRegex.lastIndex;
    while (idx < content.length && braceDepth > 0) {
      const char = content[idx];
      if (char === '{') braceDepth++;
      else if (char === '}') braceDepth--;
      idx++;
    }
    const body = content.slice(extRegex.lastIndex, idx - 1);
    bodies.push({ typeName, body });
    extRegex.lastIndex = idx;
  }
  return bodies;
}

4. ์—ฐ๊ด€ Extension ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ฃผ์˜์‚ฌํ•ญ

โš ๏ธ ๋ฌธ์ œ: ์—ฐ๊ด€ Extension์ด ์ปดํฌ๋„ŒํŠธ ๋ฌธ์„œ์— ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

Button.swift ํŒŒ์ผ์— extension View { func button(...) }๋ฅผ ์ž‘์„ฑํ–ˆ๋Š”๋ฐ, ์ƒ์„ฑ๋œ Button ์ปดํฌ๋„ŒํŠธ ๋ฌธ์„œ์˜ "Associated Extensions" ์„น์…˜์— ์ด ํ•จ์ˆ˜๊ฐ€ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฝํŠธ๊ฐ€ Swift ํŒŒ์ผ์˜ extension ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ DocC๊ฐ€ ์ƒ์„ฑํ•œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๋น„๊ตํ•  ๋•Œ, ์ •๊ทœํ™” ๊ณผ์ •์—์„œ ์ผ๋ถ€ ์ •๋ณด๊ฐ€ ์ œ๊ฑฐ๋˜์–ด ๋งค์นญ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// โŒ May cause issues: Matching fails if type names differ
extension View {
    public func button(title: String) -> some View { }
}
// Matching fails if DocC recognizes different type names
  • ์ œ๋„ค๋ฆญ ์ œ์•ฝ์ด ์žˆ๋Š” ๊ฒฝ์šฐ

  • ํŒŒ๋ผ๋ฏธํ„ฐ ์†์„ฑ(@escaping, @ViewBuilder ๋“ฑ)์ด ๋งŽ์€ ๊ฒฝ์šฐ

  • ๊ธฐ๋ณธ๊ฐ’์ด ์žˆ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋งŽ์€ ๊ฒฝ์šฐ

  • ๊ณต๋ฐฑ ์ฐจ์ด๋Š” ์ž๋™์œผ๋กœ ์ •๋ฆฌ๋˜๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • @escaping, @ViewBuilder ๊ฐ™์€ ์†์„ฑ์€ ์ •๊ทœํ™” ๊ณผ์ •์—์„œ ์ œ๊ฑฐ๋˜๋ฏ€๋กœ, ์ด๊ฒƒ๋งŒ์œผ๋กœ๋Š” ๋งค์นญ์ด ์‹คํŒจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ๋ฌธ์ œ๋Š” ์ฃผ๋กœ ํƒ€์ž…๋ช…, ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…, ํ•จ์ˆ˜๋ช…์˜ ์ฐจ์ด์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ •๊ทœํ™” ํ•จ์ˆ˜ (Signature Normalization Function):

function canonicalizeSignature(signature) {
  let normalized = signature
    .replace(/\s+/g, ' ')
    .replace(/\(\s+/g, '(')
    .replace(/\s+\)/g, ')')
    .replace(/\s*,\s*/g, ', ')
    .replace(/\s*:\s*/g, ': ')
    .replace(/\s*->\s*/g, ' -> ')
    .replace(/\s+where\s+/g, ' where ');

  // Remove parameter attributes (e.g., @escaping, @ViewBuilder, etc.)
  normalized = normalized.replace(/@\w+\s+/g, '');

  if (signature.includes('func')) {
    // Remove generic constraints (<T: Foo, U: Bar> -> <T, U>)
    normalized = normalized.replace(/<([^>]+)>/g, (_, contents) => {
      const cleaned = contents
        .split(',')
        .map((part) => part.trim().replace(/([A-Za-z0-9_]+)\s*:\s*[^,]+/, '$1'))
        .join(', ');
      return `<${cleaned}>`;
    });


    // Normalize external/internal parameter names
    normalized = normalized
      // Remove internal name when external label + internal name exist
      .replace(/([A-Za-z0-9_]+)\s+[A-Za-z0-9_]+\s*:/g, '$1:')
      // Remove label when external label is _
      .replace(/_\s*:\s*/g, '');

    // Remove parameter default values
    normalized = stripParameterDefaults(normalized);
  }

  // Remove unnecessary whitespace
  normalized = normalized
    .replace(/,\s+\)/g, ')')
    .replace(/\s*,\s*/g, ', ')
    .replace(/\(\s+/g, '(')
    .replace(/\s+\)/g, ')')
    .replace(/\s{2,}/g, ' ')
    .replace(/\s+,/g, ',')
    .replace(/:\s+/g, ': ')
    .replace(/\(\s+/g, '(')
    .replace(/\s+\)/g, ')');

  return normalized.trim();
}

DocC JSON์—์„œ extension ๋ฉค๋ฒ„ ๋ Œ๋”๋ง ์‹œ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋น„๊ต (Signature Comparison When Rendering Extension Members from DocC JSON):

function renderExtensionMemberMarkdown(ref, dataRoot, mdPath = 'documentation/utilities/ios-extensions') {
  if (!ref) return null;

  const signatureRaw = (ref.fragments || []).map((f) => f.text).join('') || ref.title || '';
  const canonicalSignature = canonicalizeSignature(signatureRaw);
  const hash = generateHash(canonicalSignature);

5. ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ์˜์กด์„ฑ

โš ๏ธ ํ•„์ˆ˜: "1 Components" ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

  • ์—ฐ๊ด€ Extension ์ˆ˜์ง‘์€ 1 Components ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์˜ ํŒŒ์ผ์—๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ๋‹ค๋ฅธ ๋””๋ ‰ํ† ๋ฆฌ์˜ ํŒŒ์ผ์€ extension์ด ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
      if (relPath.includes('1 Components')) {
        convertedSwiftFileMap[componentTitle.toLowerCase()] = { componentTitle, isConverted: false };
      }

      // Extract public type names from Swift files
      try {
        const content = fs.readFileSync(fullPath, 'utf-8');
        // Find public enum, struct, class, protocol, actor, etc.
        const typeRegex = /public\s+(enum|struct|class|protocol|actor)\s+(\w+)/g;
        let match;
        while ((match = typeRegex.exec(content)) !== null) {
          const typeName = match[2];
          swiftFileMap[typeName] = relBase;
        }

        if (/\b1 Components\b/.test(relBase)) {
          collectComponentExtensionHashes(componentTitle, content);
        }

6. ํƒ€์ž… ์ธ์‹ ์ œํ•œ

โš ๏ธ ์ฃผ์˜: ํŠน์ • ํƒ€์ž…๋งŒ ์ธ์‹๋จ

์ธ์‹๋˜๋Š” ํƒ€์ž…:

  • public enum
  • public struct
  • public class
  • public protocol
  • public actor

์ธ์‹๋˜์ง€ ์•Š๋Š” ํƒ€์ž…:

  • typealias
  • associatedtype (ํ”„๋กœํ† ์ฝœ ๋‚ด๋ถ€)
  • ์ค‘์ฒฉ ํƒ€์ž… (๋ณ„๋„ ์ฒ˜๋ฆฌ ์—†์Œ)
        const typeRegex = /public\s+(enum|struct|class|protocol|actor)\s+(\w+)/g;

7. UIKit ๊ด€๋ จ ํ•„ํ„ฐ๋ง

โš ๏ธ ์ฃผ์˜: UIKit ๊ด€๋ จ ๋ฌธ์„œ๋Š” ์ œ์™ธ๋จ

  • ํŒŒ์ผ๋ช…์ด ui๋กœ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ montage.json์œผ๋กœ ๋๋‚˜๋Š” ํŒŒ์ผ์€ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.
  • UIKit ๊ด€๋ จ ํƒ€์ž…์€ ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    if (ref.title === 'UIKit') continue;
      const urlPathLastComponent = url.split('/').at(-1);
      if (urlPathLastComponent.startsWith('UI')) {
        // Exclude UIKit-related documentation
        return;
      }
    const jsonFileName = jsonPath.split('/').at(-1);
    if (jsonFileName.startsWith('ui') || jsonFileName.endsWith('montage.json')) {
      // Exclude UIKit-related documentation
      return;

8. ํŠน์ • Role ์ œ์™ธ

โš ๏ธ ์ฃผ์˜: ํŠน์ • Role์˜ ๋ฌธ์„œ๋Š” ๋‹จ๋… ํŽ˜์ด์ง€๋กœ๋Š” ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ

๋‹จ, ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์— ์ •์˜๋œ enum๊ณผ struct๋Š” ๋‹จ๋… ํŽ˜์ด์ง€๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • Initializer
  • Instance Method
  • Instance Property
  • Type Method
  • Type Property
  • Operator
  • Class
  • Enumeration (์ตœ์ƒ์œ„ ๋ށ์Šค๋Š” ์ œ์™ธ)
  • Case
  • Extended Class
  • Extended Structure
  • Extended Enumeration
  • Extended Protocol
  • API Collection
  • Structure (์ตœ์ƒ์œ„ ๋ށ์Šค๋Š” ์ œ์™ธ)
    if (json.metadata.roleHeading === 'Initializer' ||
      json.metadata.roleHeading === 'Instance Method' ||
      json.metadata.roleHeading === 'Instance Property' ||
      json.metadata.roleHeading === 'Type Method' ||
      json.metadata.roleHeading === 'Type Property' ||
      json.metadata.roleHeading === 'Operator' ||
      json.metadata.roleHeading === 'Class' ||
      json.metadata.roleHeading === 'Enumeration' && json.metadata.title.split('.').length > 1 ||
      json.metadata.roleHeading === 'Case' ||
      json.metadata.roleHeading === 'Extended Class' ||
      json.metadata.roleHeading === 'Extended Structure' ||
      json.metadata.roleHeading === 'Extended Enumeration' ||
      json.metadata.roleHeading === 'Extended Protocol' ||
      json.metadata.roleHeading === 'API Collection' ||
      json.metadata.roleHeading === 'Structure' && json.metadata.title.split('.').length > 1) {
      // Exclude Topic section items from separate document generation
      return;
    }

์š”์•ฝ: ๋ฌธ์ œ ๋ฐœ์ƒ ์‹œ

๋ฌธ์„œํ™”๊ฐ€ ์ œ๋Œ€๋กœ ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด:

  1. public ํ‚ค์›Œ๋“œ ํ™•์ธ
  2. ํŒŒ์ผ๋ช…๊ณผ ํƒ€์ž…๋ช… ์ผ์น˜ ํ™•์ธ
  3. ์—ฐ๊ด€ Extension์ด 1 Components ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ๋Š”์ง€ ํ™•์ธ
  4. ์—ฐ๊ด€ Extension ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜/ํ”„๋กœํผํ‹ฐ๋Š” public์œผ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
  5. UIKit ๊ด€๋ จ ํƒ€์ž…์ด ์•„๋‹Œ์ง€ ํ™•์ธ
  6. ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ๋กœ๊ทธ์—์„œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ™•์ธ