├── Screens
├── 1.png
└── 2.png
├── Examples
├── SwiftScript
│ ├── Example
│ │ ├── MixedUp3.png
│ │ ├── NotUsing.png
│ │ ├── MixedUp3@2x.png
│ │ ├── MixedUp3@3x.png
│ │ ├── NotUsing@2x.png
│ │ ├── Assets.xcassets
│ │ │ ├── A
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Section
│ │ │ │ ├── Contents.json
│ │ │ │ └── DuplicatedImage1.imageset
│ │ │ │ │ ├── DuplicatedImage50.png
│ │ │ │ │ ├── DuplicatedImage75.png
│ │ │ │ │ └── Contents.json
│ │ │ ├── BadRaster.imageset
│ │ │ │ ├── a1.png
│ │ │ │ ├── a2.png
│ │ │ │ └── Contents.json
│ │ │ ├── MixedUp1.imageset
│ │ │ │ ├── 1_1.png
│ │ │ │ ├── 1_2.png
│ │ │ │ ├── 1_3.png
│ │ │ │ └── Contents.json
│ │ │ ├── MixedUp2.imageset
│ │ │ │ ├── 2_2.png
│ │ │ │ ├── 2_3.png
│ │ │ │ └── Contents.json
│ │ │ ├── BigImages.imageset
│ │ │ │ ├── Bookmark.png
│ │ │ │ ├── Bookmark(3).png
│ │ │ │ └── Contents.json
│ │ │ ├── BigRastor.imageset
│ │ │ │ ├── BigRastor.png
│ │ │ │ └── Contents.json
│ │ │ ├── BigVector.imageset
│ │ │ │ ├── BigVector.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── TwoVectors.imageset
│ │ │ │ ├── TwoVector1.pdf
│ │ │ │ ├── TwoVector2.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── FalsePdf.imageset
│ │ │ │ ├── status_failed.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── MixedBookmark.imageset
│ │ │ │ ├── Bookmark.pdf
│ │ │ │ ├── Bookmark.png
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── Lite-Icon-icon.png
│ │ │ │ └── Contents.json
│ │ │ ├── NotFoundFile.imageset
│ │ │ │ ├── NotUsingImage.png
│ │ │ │ └── Contents.json
│ │ │ ├── Folder
│ │ │ │ ├── Contents.json
│ │ │ │ └── DuplicatedImage3.imageset
│ │ │ │ │ ├── DuplicateImage3.pdf
│ │ │ │ │ └── Contents.json
│ │ │ ├── NotUsingImage.imageset
│ │ │ │ ├── NotUsingImage100.png
│ │ │ │ ├── NotUsingImage50.png
│ │ │ │ └── Contents.json
│ │ │ ├── DuplicatedImage2.imageset
│ │ │ │ ├── DuplicateImage2.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── TruePng.imageset
│ │ │ │ ├── icons8-Cute Color-Connect.png
│ │ │ │ ├── icons8-Cute Color-Connect100.png
│ │ │ │ └── Contents.json
│ │ │ ├── Duplicate.imageset
│ │ │ │ ├── icons8-Color Glass-Connect.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── DuplicatedImage4.imageset
│ │ │ │ ├── DuplicatedImage50.png
│ │ │ │ ├── DuplicatedImage75.png
│ │ │ │ └── Contents.json
│ │ │ ├── TruePdf.imageset
│ │ │ │ ├── icons8-Color Glass-Bookmark.pdf
│ │ │ │ └── Contents.json
│ │ │ ├── FalseSVG.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── graphic.svg
│ │ │ ├── Empty.imageset
│ │ │ │ └── Contents.json
│ │ │ ├── checkSVG.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── CheckSVG.svg
│ │ │ └── AccentColor.colorset
│ │ │ │ └── Contents.json
│ │ ├── NotDuplicated.png
│ │ ├── NotDuplicated@2x.png
│ │ ├── NotDuplicated@3x.png
│ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ ├── ExampleApp.swift
│ │ ├── ContentView.swift
│ │ └── Generated
│ │ │ └── Assets+Generated.swift
│ ├── Example.xcodeproj
│ │ └── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── Podfile
│ ├── swiftgen.yml
│ ├── imagelinter.yaml
│ └── SwiftGen
│ │ ├── fonts.stencil
│ │ └── assets.stencil
└── SPMPlugin
│ ├── Example
│ ├── Modules
│ │ └── Images
│ │ │ ├── Sources
│ │ │ └── Images
│ │ │ │ ├── Resources
│ │ │ │ ├── Assets.xcassets
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ ├── A
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Section
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ ├── DuplicatedImage1.imageset
│ │ │ │ │ │ │ ├── DuplicatedImage50.png
│ │ │ │ │ │ │ ├── DuplicatedImage75.png
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── snake-case_image.imageset
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Folder
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ └── DuplicatedImage3.imageset
│ │ │ │ │ │ │ ├── DuplicateImage3.pdf
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── BadRaster.imageset
│ │ │ │ │ │ ├── a1.png
│ │ │ │ │ │ ├── a2.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── MixedUp1.imageset
│ │ │ │ │ │ ├── 1_1.png
│ │ │ │ │ │ ├── 1_2.png
│ │ │ │ │ │ ├── 1_3.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── MixedUp2.imageset
│ │ │ │ │ │ ├── 2_2.png
│ │ │ │ │ │ ├── 2_3.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── BigImages.imageset
│ │ │ │ │ │ ├── Bookmark.png
│ │ │ │ │ │ ├── Bookmark(3).png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── BigRastor.imageset
│ │ │ │ │ │ ├── BigRastor.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── BigVector.imageset
│ │ │ │ │ │ ├── BigVector.pdf
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── FalsePdf.imageset
│ │ │ │ │ │ ├── status_failed.pdf
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── MixedBookmark.imageset
│ │ │ │ │ │ ├── Bookmark.pdf
│ │ │ │ │ │ ├── Bookmark.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── TwoVectors.imageset
│ │ │ │ │ │ ├── TwoVector1.pdf
│ │ │ │ │ │ ├── TwoVector2.pdf
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── AppIcon.appiconset
│ │ │ │ │ │ ├── Lite-Icon-icon.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── NotFoundFile.imageset
│ │ │ │ │ │ ├── NotUsingImage.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── NotUsingImage.imageset
│ │ │ │ │ │ ├── NotUsingImage100.png
│ │ │ │ │ │ ├── NotUsingImage50.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── DuplicatedImage2.imageset
│ │ │ │ │ │ ├── DuplicateImage2.pdf
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── TruePng.imageset
│ │ │ │ │ │ ├── icons8-Cute Color-Connect.png
│ │ │ │ │ │ ├── icons8-Cute Color-Connect100.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── DuplicatedImage4.imageset
│ │ │ │ │ │ ├── DuplicatedImage50.png
│ │ │ │ │ │ ├── DuplicatedImage75.png
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── TruePdf.imageset
│ │ │ │ │ │ ├── icons8-Color Glass-Bookmark.pdf
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── Duplicate.imageset
│ │ │ │ │ │ ├── icons8-Color Glass-Connect.pdf
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── FalseSVG.imageset
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ └── graphic.svg
│ │ │ │ │ ├── Empty.imageset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── checkSVG.imageset
│ │ │ │ │ │ ├── Contents.json
│ │ │ │ │ │ └── CheckSVG.svg
│ │ │ │ │ └── AccentColor.colorset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── MixedUp3.png
│ │ │ │ ├── NotUsing.png
│ │ │ │ ├── MixedUp3@2x.png
│ │ │ │ ├── MixedUp3@3x.png
│ │ │ │ ├── NotDuplicated.png
│ │ │ │ ├── NotUsing@2x.png
│ │ │ │ ├── NotDuplicated@2x.png
│ │ │ │ └── NotDuplicated@3x.png
│ │ │ │ ├── imagelinter.yml
│ │ │ │ ├── ContentView.swift
│ │ │ │ └── Generated
│ │ │ │ └── Assets+Generated.swift
│ │ │ ├── Package.swift
│ │ │ └── imagelinter.yaml
│ └── ExampleApp.swift
│ ├── Example.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
│ ├── Podfile
│ ├── swiftgen.yml
│ └── SwiftGen
│ ├── fonts.stencil
│ └── assets.stencil
├── Sources
├── Imagelinter
│ └── EmptyFile.swift
└── ImagelinterExec
│ ├── SwiftGen.swift
│ ├── main.swift
│ └── ImageInfo.swift
├── Scripts
├── release.sh
├── MakeImageLinter.swift
├── releasenotes.sh
└── build.sh
├── Package.swift
├── LICENSE
├── Plugins
└── ImagelinterPlugin
│ └── plugin.swift
├── .gitignore
├── CHANGELOG.md
└── README.md
/Screens/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Screens/1.png
--------------------------------------------------------------------------------
/Screens/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Screens/2.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/MixedUp3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/MixedUp3.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/NotUsing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/NotUsing.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/MixedUp3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/MixedUp3@2x.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/MixedUp3@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/MixedUp3@3x.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/NotUsing@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/NotUsing@2x.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/A/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/NotDuplicated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/NotDuplicated.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Section/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/NotDuplicated@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/NotDuplicated@2x.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/NotDuplicated@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/NotDuplicated@3x.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/imagelinter.yml:
--------------------------------------------------------------------------------
1 | isCheckingDuplicatedByContent: true
2 | relativeImagesPaths:
3 | - /Resources
4 | relativeSourcePath:
5 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/A/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Section/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BadRaster.imageset/a1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/BadRaster.imageset/a1.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BadRaster.imageset/a2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/BadRaster.imageset/a2.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedUp1.imageset/1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/MixedUp1.imageset/1_1.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedUp1.imageset/1_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/MixedUp1.imageset/1_2.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedUp1.imageset/1_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/MixedUp1.imageset/1_3.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedUp2.imageset/2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/MixedUp2.imageset/2_2.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedUp2.imageset/2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/MixedUp2.imageset/2_3.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BigImages.imageset/Bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/BigImages.imageset/Bookmark.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/MixedUp3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/MixedUp3.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotUsing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotUsing.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BigImages.imageset/Bookmark(3).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/BigImages.imageset/Bookmark(3).png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BigRastor.imageset/BigRastor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/BigRastor.imageset/BigRastor.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BigVector.imageset/BigVector.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/BigVector.imageset/BigVector.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TwoVectors.imageset/TwoVector1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/TwoVectors.imageset/TwoVector1.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TwoVectors.imageset/TwoVector2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/TwoVectors.imageset/TwoVector2.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/FalsePdf.imageset/status_failed.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/FalsePdf.imageset/status_failed.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedBookmark.imageset/Bookmark.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/MixedBookmark.imageset/Bookmark.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedBookmark.imageset/Bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/MixedBookmark.imageset/Bookmark.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/MixedUp3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/MixedUp3@2x.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/MixedUp3@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/MixedUp3@3x.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotDuplicated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotDuplicated.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotUsing@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotUsing@2x.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/AppIcon.appiconset/Lite-Icon-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/AppIcon.appiconset/Lite-Icon-icon.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/NotFoundFile.imageset/NotUsingImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/NotFoundFile.imageset/NotUsingImage.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotDuplicated@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotDuplicated@2x.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotDuplicated@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/NotDuplicated@3x.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Folder/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | },
6 | "properties" : {
7 | "provides-namespace" : true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/NotUsingImage.imageset/NotUsingImage100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/NotUsingImage.imageset/NotUsingImage100.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/NotUsingImage.imageset/NotUsingImage50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/NotUsingImage.imageset/NotUsingImage50.png
--------------------------------------------------------------------------------
/Sources/Imagelinter/EmptyFile.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmptyFile.swift
3 | //
4 | //
5 | // Created by Sergey Balalaev on 02.04.2024.
6 | //
7 |
8 | // This empty file needs for fix the error with init library contented only Plugin
9 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage2.imageset/DuplicateImage2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage2.imageset/DuplicateImage2.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Duplicate.imageset/icons8-Color Glass-Connect.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/Duplicate.imageset/icons8-Color Glass-Connect.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage50.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage75.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage75.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TruePdf.imageset/icons8-Color Glass-Bookmark.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/TruePdf.imageset/icons8-Color Glass-Bookmark.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect100.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Folder/DuplicatedImage3.imageset/DuplicateImage3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/Folder/DuplicatedImage3.imageset/DuplicateImage3.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage50.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage75.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SwiftScript/Example/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage75.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Folder/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | },
6 | "properties" : {
7 | "provides-namespace" : true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BadRaster.imageset/a1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BadRaster.imageset/a1.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BadRaster.imageset/a2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BadRaster.imageset/a2.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp1.imageset/1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp1.imageset/1_1.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp1.imageset/1_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp1.imageset/1_2.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp1.imageset/1_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp1.imageset/1_3.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp2.imageset/2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp2.imageset/2_2.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp2.imageset/2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp2.imageset/2_3.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigImages.imageset/Bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigImages.imageset/Bookmark.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigRastor.imageset/BigRastor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigRastor.imageset/BigRastor.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigVector.imageset/BigVector.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigVector.imageset/BigVector.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigImages.imageset/Bookmark(3).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigImages.imageset/Bookmark(3).png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/FalsePdf.imageset/status_failed.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/FalsePdf.imageset/status_failed.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedBookmark.imageset/Bookmark.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedBookmark.imageset/Bookmark.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedBookmark.imageset/Bookmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedBookmark.imageset/Bookmark.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TwoVectors.imageset/TwoVector1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TwoVectors.imageset/TwoVector1.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TwoVectors.imageset/TwoVector2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TwoVectors.imageset/TwoVector2.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/AppIcon.appiconset/Lite-Icon-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/AppIcon.appiconset/Lite-Icon-icon.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/FalseSVG.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "graphic.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotFoundFile.imageset/NotUsingImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotFoundFile.imageset/NotUsingImage.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/FalsePdf.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "status_failed.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotUsingImage.imageset/NotUsingImage100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotUsingImage.imageset/NotUsingImage100.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotUsingImage.imageset/NotUsingImage50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotUsingImage.imageset/NotUsingImage50.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage2.imageset/DuplicateImage2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage2.imageset/DuplicateImage2.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect.png
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "DuplicateImage2.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TruePdf.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icons8-Color Glass-Bookmark.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage50.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage75.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage4.imageset/DuplicatedImage75.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePdf.imageset/icons8-Color Glass-Bookmark.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePdf.imageset/icons8-Color Glass-Bookmark.pdf
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Folder/DuplicatedImage3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "DuplicateImage3.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Duplicate.imageset/icons8-Color Glass-Connect.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Duplicate.imageset/icons8-Color Glass-Connect.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePng.imageset/icons8-Cute Color-Connect100.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Folder/DuplicatedImage3.imageset/DuplicateImage3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Folder/DuplicatedImage3.imageset/DuplicateImage3.pdf
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/FalseSVG.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "graphic.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage50.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage75.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ByteriX/ImageLinter/HEAD/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Section/DuplicatedImage1.imageset/DuplicatedImage75.png
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/FalsePdf.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "status_failed.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | platform :ios, '14.0'
3 |
4 | inhibit_all_warnings!
5 |
6 | target 'Example' do
7 | # Comment the next line if you don't want to use dynamic frameworks
8 | use_frameworks!
9 |
10 | pod "SwiftGen"
11 |
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "DuplicateImage2.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | platform :ios, '14.0'
3 |
4 | inhibit_all_warnings!
5 |
6 | target 'Example' do
7 | # Comment the next line if you don't want to use dynamic frameworks
8 | use_frameworks!
9 |
10 | pod "SwiftGen"
11 |
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Section/snake-case_image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "just_icon.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePdf.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icons8-Color Glass-Bookmark.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Folder/DuplicatedImage3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "DuplicateImage3.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/ExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleApp.swift
3 | // Example
4 | //
5 | // Created by Sergey Balalaev on 27.09.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct ExampleApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Lite-Icon-icon.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/ExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleApp.swift
3 | // Example
4 | //
5 | // Created by Sergey Balalaev on 27.09.2022.
6 | //
7 |
8 | import SwiftUI
9 | import Images
10 |
11 | @main
12 | struct ExampleApp: App {
13 | var body: some Scene {
14 | WindowGroup {
15 | ContentView()
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/swiftgen.yml:
--------------------------------------------------------------------------------
1 |
2 |
3 | input_dir: Example/
4 | output_dir: Example/Generated/
5 |
6 | ## see https://www.raywenderlich.com/23709326-swiftgen-tutorial-for-ios
7 |
8 | xcassets:
9 | inputs:
10 | - Assets.xcassets
11 | - *.png
12 | outputs:
13 | ##templateName: swift5
14 | templatePath: SwiftGen/assets.stencil
15 | output: Assets+Generated.swift
16 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Lite-Icon-icon.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/swiftgen.yml:
--------------------------------------------------------------------------------
1 |
2 |
3 | input_dir: Example/
4 | output_dir: Example/Generated/
5 |
6 | ## see https://www.raywenderlich.com/23709326-swiftgen-tutorial-for-ios
7 |
8 | xcassets:
9 | inputs:
10 | - Assets.xcassets
11 | - *.png
12 | outputs:
13 | ##templateName: swift5
14 | templatePath: SwiftGen/assets.stencil
15 | output: Assets+Generated.swift
16 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Empty.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "scale" : "3x"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Empty.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "scale" : "3x"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/checkSVG.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "CheckSVG.svg",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BigRastor.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BigRastor.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BigVector.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "BigVector.pdf",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/NotFoundFile.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "NotUsingImage50.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Duplicate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "icons8-Color Glass-Connect.pdf",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.000",
9 | "green" : "0.319",
10 | "red" : "1.000"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BadRaster.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "a1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "a2.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedUp2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "2_3.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "2_2.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigRastor.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BigRastor.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigVector.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "BigVector.pdf",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/checkSVG.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "CheckSVG.svg",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/BigImages.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "Bookmark(3).png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "Bookmark.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedBookmark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "Bookmark.pdf",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "Bookmark.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotFoundFile.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "NotUsingImage50.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TwoVectors.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "TwoVector1.pdf",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "TwoVector2.pdf",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.000",
9 | "green" : "0.319",
10 | "red" : "1.000"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Duplicate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "icons8-Color Glass-Connect.pdf",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/NotUsingImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "NotUsingImage50.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "NotUsingImage100.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/MixedUp1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "1_2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "1_1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "1_3.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BadRaster.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "a1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "a2.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "2_3.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "2_2.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/DuplicatedImage4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "DuplicatedImage50.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "DuplicatedImage75.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/Section/DuplicatedImage1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "DuplicatedImage50.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "DuplicatedImage75.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/TruePng.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icons8-Cute Color-Connect.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "icons8-Cute Color-Connect100.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/BigImages.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "Bookmark(3).png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "Bookmark.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedBookmark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "Bookmark.pdf",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "Bookmark.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TwoVectors.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "TwoVector1.pdf",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "TwoVector2.pdf",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/NotUsingImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "NotUsingImage50.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "NotUsingImage100.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/DuplicatedImage4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "DuplicatedImage50.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "DuplicatedImage75.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/MixedUp1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "1_2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "1_1.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "1_3.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/Section/DuplicatedImage1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "DuplicatedImage50.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "DuplicatedImage75.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/TruePng.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icons8-Cute Color-Connect.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "icons8-Cute Color-Connect100.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Example
4 | //
5 | // Created by Sergey Balalaev on 27.09.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ContentView: View {
11 | var body: some View {
12 | VStack {
13 | Image("TruePng")
14 | .imageScale(.large)
15 | .foregroundColor(.accentColor)
16 | Image("TruePdf")
17 |
18 | if let image = UIImage(named: "FalsePdf") {
19 | Image(uiImage: image)
20 | }
21 |
22 | Image("checkSVG")
23 | }
24 | .padding()
25 | }
26 | }
27 |
28 | struct ContentView_Previews: PreviewProvider {
29 | static var previews: some View {
30 | ContentView()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.9
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Images",
8 | platforms: [.iOS("13.0")],
9 | products: [
10 | .library(
11 | name: "Images",
12 | targets: ["Images"]
13 | ),
14 | ],
15 | dependencies: [
16 | .package(path: "../../../../..")
17 | ],
18 | targets: [
19 | .target(
20 | name: "Images",
21 | dependencies: [
22 | ],
23 | plugins: [
24 | .plugin(name: "ImagelinterPlugin", package: "Imagelinter"),
25 | ]
26 | )
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/Scripts/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | checkExit(){
4 | echo "$1\n"
5 | if [ $? != 0 ]; then
6 | echo "Building failed: $1\n"
7 | exit 1
8 | fi
9 | }
10 |
11 | CHANGELOG=$(cat CHANGELOG.md)
12 | VERSION_REGEX='## *\[([.0-9]*)\]'
13 | CURRENT_VERSION=""
14 | if [[ $CHANGELOG =~ $VERSION_REGEX ]]; then
15 | CURRENT_VERSION=${BASH_REMATCH[1]}
16 | fi
17 |
18 | echo "Release version $CURRENT_VERSION detected"
19 |
20 | APP_CONFIG_PATH="./build.config"
21 | echo "CURRENT_VERSION=$CURRENT_VERSION" > "$APP_CONFIG_PATH"
22 |
23 | checkExit "Start to make ImageLinter.swift script"
24 |
25 | swift Scripts/MakeImageLinter.swift -version "$CURRENT_VERSION"
26 |
27 | checkExit "Finished ImageLinter.swift script"
28 |
29 | git add "ImageLinter.swift"
30 | git commit -m "Release $CURRENT_VERSION version with updating Swift script"
31 |
32 | checkExit "Version $CURRENT_VERSION commited"
33 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.8
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Imagelinter",
8 | platforms: [.iOS(.v12), .macOS(.v11)],
9 | products: [
10 | .library(
11 | name: "Imagelinter",
12 | targets: ["Imagelinter"]
13 | ),
14 | .plugin(
15 | name: "ImagelinterPlugin",
16 | targets: ["ImagelinterPlugin"]
17 | ),
18 | ],
19 | dependencies: [
20 | ],
21 | targets: [
22 | .target(
23 | name: "Imagelinter",
24 | dependencies: []
25 | ),
26 | .executableTarget(
27 | name: "ImagelinterExec",
28 | dependencies: [ ]
29 | ),
30 | .plugin(name: "ImagelinterPlugin", capability: .buildTool(), dependencies: ["ImagelinterExec"])
31 | ]
32 | )
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 ByteriX
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Example
4 | //
5 | // Created by Sergey Balalaev on 27.09.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | public struct ContentView: View {
11 |
12 | public init() {}
13 |
14 | public var body: some View {
15 | VStack {
16 | Image("TruePng")
17 | .imageScale(.large)
18 | .foregroundColor(.accentColor)
19 | Image("TruePdf")
20 |
21 | if let image = UIImage(named: "FalsePdf") {
22 | Image(uiImage: image)
23 | }
24 |
25 | Image(uiImage: #imageLiteral(resourceName: "checkSVG"))
26 |
27 | Image("NotFoundedImage")
28 |
29 | // SwiftGen ussing:
30 | // Asset.Folder.duplicatedImage3.image
31 | // Asset.duplicatedImage1.image
32 | // Asset.snakeCaseImage.name
33 |
34 | Image("snake-case_image")
35 | }
36 | .padding()
37 | }
38 | }
39 |
40 | struct ContentView_Previews: PreviewProvider {
41 | static var previews: some View {
42 | ContentView()
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/imagelinter.yaml:
--------------------------------------------------------------------------------
1 |
2 | isEnabled: true
3 | relativeImagesPath: /
4 | relativeSourcePath: /
5 | usingTypes:
6 | - case: uiKit
7 | - case: swiftUI
8 | - case: swiftGen
9 | enumName: Asset
10 | - case: custom
11 | pattern: "(.*)".image
12 | isSwiftGen: false
13 | - case: custom
14 | pattern: "(.*)".image
15 | isSwiftGen: true
16 | - case: custom
17 | pattern: "(.*)".name
18 | ignoredUnusedImages:
19 | - temp
20 | ignoredUndefinedImages:
21 | - temp
22 | rastorExtensions:
23 | - png
24 | - jpg
25 | - jpeg
26 | vectorExtensions:
27 | - pdf
28 | - svg
29 | sourcesExtensions:
30 | - swift
31 | - mm
32 | resourcesExtensions:
33 | - storyboard
34 | - xib
35 | isAllFilesErrorShowing: false
36 | maxVectorFileSize: 30000
37 | maxVectorImageSize:
38 | width: 100
39 | height: 100
40 | maxRastorFileSize: 300000
41 | maxRastorImageSize:
42 | width: 300
43 | height: 300
44 | isCheckingFileSize: true
45 | isCheckingImageSize: true
46 | isCheckingPdfVector: true
47 | isCheckingSvgVector: true
48 | isCheckingScaleSize: true
49 | isCheckingDuplicatedByName: true
50 | isCheckingDuplicatedByContent: true
51 | targetPlatforms:
52 | - iOS
53 | - iPadOS
54 | - macOS
55 | - tvOS
56 | - visionOS
57 | - watchOS
58 |
--------------------------------------------------------------------------------
/Scripts/MakeImageLinter.swift:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env xcrun --sdk macosx swift
2 |
3 | import Foundation
4 | import AppKit
5 |
6 | let version = UserDefaults.standard.string(forKey: "version")!
7 |
8 | let path = "Sources/ImagelinterExec"
9 | let sourceFileEnumerator = FileManager.default.enumerator(atPath: path)
10 | let startStrings = """
11 | #!/usr/bin/env xcrun --sdk macosx swift
12 |
13 | import Foundation
14 | import AppKit
15 |
16 | /**
17 | ImageLinter.swift
18 | version \(version)
19 |
20 | Created by Sergey Balalaev on 23.09.22.
21 | Copyright (c) 2022-2025 ByteriX. All rights reserved.
22 |
23 | Using from build phase:
24 | ${SRCROOT}/Scripts/ImageLinter.swift
25 | */
26 |
27 |
28 | """
29 |
30 | var saveString = startStrings
31 |
32 | while let sourceFileName = sourceFileEnumerator?.nextObject() as? String {
33 | let fileExtension = (sourceFileName as NSString).pathExtension.uppercased()
34 | let filePath = "\(path)/\(sourceFileName)"
35 | // checks the extension to source
36 | if fileExtension.contains("SWIFT") {
37 | if let string = try? String(contentsOfFile: filePath, encoding: .utf8) {
38 | saveString.append(string)
39 | }
40 | }
41 | }
42 |
43 | try saveString.data(using: .utf8)?.write(to: URL(fileURLWithPath: "Imagelinter.swift"))
44 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/checkSVG.imageset/CheckSVG.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/checkSVG.imageset/CheckSVG.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/imagelinter.yaml:
--------------------------------------------------------------------------------
1 |
2 | isEnabled: true
3 | relativeImagesPath: /Sources/Images/Resources/Error
4 | relativeSourcePath: /
5 | relativeSourcePaths:
6 | - /Sources1
7 | - /Sources2
8 | usingTypes:
9 | - case: uiKit
10 | - case: uiKitLiteral
11 | - case: swiftUI
12 | - case: swiftGen
13 | enumName: Asset
14 | - case: custom
15 | pattern: "(.*)".image
16 | isSwiftGen: false
17 | - case: custom
18 | pattern: "(.*)".image
19 | isSwiftGen: true
20 | - case: custom
21 | pattern: "(.*)".name
22 | ignoredUnusedImages:
23 | - temp
24 | ignoredUndefinedImages:
25 | - temp
26 | rastorExtensions:
27 | - png
28 | - jpg
29 | - jpeg
30 | vectorExtensions:
31 | - pdf
32 | - svg
33 | sourcesExtensions:
34 | - swift
35 | - mm
36 | resourcesExtensions:
37 | - storyboard
38 | - xib
39 | isAllFilesErrorShowing: false
40 | maxVectorFileSize: 30000
41 | maxVectorImageSize:
42 | width: 100
43 | height: 100
44 | maxRastorFileSize: 300000
45 | maxRastorImageSize:
46 | width: 300
47 | height: 300
48 | isCheckingFileSize: true
49 | isCheckingImageSize: true
50 | isCheckingPdfVector: true
51 | isCheckingSvgVector: true
52 | isCheckingScaleSize: true
53 | isCheckingDuplicatedByName: true
54 | isCheckingDuplicatedByContent: true
55 | targetPlatforms:
56 | - iOS
57 | - iPadOS
58 | - macOS
59 | - tvOS
60 | - visionOS
61 | - watchOS
62 |
--------------------------------------------------------------------------------
/Plugins/ImagelinterPlugin/plugin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // plugin.swift
3 | //
4 | //
5 | // Created by Sergey Balalaev on 02.04.2024.
6 | //
7 |
8 | import PackagePlugin
9 |
10 | @main
11 | struct LocalinterPlugin: BuildToolPlugin {
12 | func createBuildCommands(context: PackagePlugin.PluginContext, target: Target) throws -> [PackagePlugin.Command] {
13 | let executable = try context.tool(named: "ImagelinterExec").path
14 |
15 | return [
16 | .buildCommand(
17 | displayName: "Running Imagelinter",
18 | executable: executable,
19 | arguments: [
20 | "--settingsPath", target.directory.string
21 | ]
22 | ),
23 | ]
24 | }
25 | }
26 |
27 | #if canImport(XcodeProjectPlugin)
28 | import XcodeProjectPlugin
29 |
30 | extension LocalinterPlugin: XcodeBuildToolPlugin {
31 | func createBuildCommands(context: XcodeProjectPlugin.XcodePluginContext, target: XcodeProjectPlugin.XcodeTarget) throws -> [PackagePlugin.Command] {
32 | let executable = try context.tool(named: "ImagelinterExec").path
33 |
34 | return [
35 | .buildCommand(
36 | displayName: "Running Imagelinter",
37 | executable: executable,
38 | arguments: [
39 | "--settingsPath", context.xcodeProject.directory.string
40 | ]
41 | ),
42 | ]
43 | }
44 | }
45 | #endif
46 |
--------------------------------------------------------------------------------
/Sources/ImagelinterExec/SwiftGen.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftGen.swift
3 | //
4 | //
5 | // Created by Sergey Balalaev on 18.04.2024.
6 | //
7 |
8 | import Foundation
9 |
10 | extension String {
11 |
12 | static let snakeSeporators = "-_"
13 |
14 | func lowercasedFirstLetter() -> String {
15 | return prefix(1).lowercased() + dropFirst()
16 | }
17 |
18 | func uppercasedFirstLetter() -> String {
19 | return prefix(1).uppercased() + dropFirst()
20 | }
21 | }
22 |
23 |
24 | fileprivate extension Array where Self.Element == String {
25 | func swiftGenFolders() -> [Self.Element] {
26 | guard let last = last else {
27 | return self
28 | }
29 | var result: [Self.Element] = dropLast()
30 | result.append(last.lowercasedFirstLetter())
31 | return result
32 | }
33 |
34 | func swiftGenCamel() -> [Self.Element] {
35 | guard let first = first else {
36 | return self
37 | }
38 | var result: [Self.Element] = dropFirst().map { $0.uppercasedFirstLetter() }
39 | result.insert(first, at: 0)
40 | return result
41 | }
42 | }
43 |
44 | extension String {
45 | func swiftGenCamel() -> String {
46 | return self
47 | .trimmingCharacters(in: CharacterSet(charactersIn: Self.snakeSeporators))
48 | .split(whereSeparator: { char in
49 | Self.snakeSeporators.contains { $0 == char }
50 | })
51 | .map { String($0) }
52 | .swiftGenCamel()
53 | .joined(separator: "")
54 | }
55 | }
56 |
57 | extension String {
58 | func swiftGenKey() -> String {
59 | return self
60 | .split(separator: "/")
61 | .map { String($0).swiftGenCamel() }
62 | .swiftGenFolders()
63 | .joined(separator: ".")
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Scripts/releasenotes.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | checkExit(){
4 | if [ $? != 0 ]; then
5 | echo "Building failed: $1\n"
6 | exit 1
7 | fi
8 | }
9 |
10 | CHANGELOG=$(cat CHANGELOG.md)
11 | VERSION_REGEX='##[[:space:]]*\[([.0-9]*)\]'
12 | CURRENT_VERSION=""
13 | if [[ $CHANGELOG =~ $VERSION_REGEX ]]; then
14 | CURRENT_VERSION=${BASH_REMATCH[1]}
15 | fi
16 |
17 | echo "Release version $CURRENT_VERSION detected"
18 |
19 | checkExit "Version detection"
20 |
21 | #perl scripts/releasenotes.pl
22 | #VERSION_MESSAGE=$(perl scripts/releasenotes.pl)
23 |
24 | VERSION_MESSAGE=
25 |
26 | VERSION_MESSAGE=$(
27 | perl -l - $cnt <<'EOF'
28 |
29 | open my $fh, '<', 'CHANGELOG.md' or die "Can't open file $!";
30 | my $CHANGELOG = do { local $/; <$fh> };
31 |
32 | if ($CHANGELOG =~ m/## *\[([.0-9]*)\]/) {
33 | $CURRENT_VERSION="$1"
34 | }
35 |
36 | if ($CHANGELOG =~ m/## *\[$CURRENT_VERSION\].*\s+((.|\s)*?)\s+## *\[[.0-9]*\]/) {
37 | print "$1"
38 | }
39 |
40 | EOF
41 | )
42 |
43 | checkExit "Release notes detection"
44 |
45 | echo "Release notes:"
46 | echo "$VERSION_MESSAGE"
47 |
48 | echo "Start upload release to GitHub"
49 |
50 | # GitHub CLI api
51 | # https://cli.github.com/manual/gh_api
52 | # I change '$CURRENT_VERSION' to "$CURRENT_VERSION"
53 | # If you need auth GitHub on Runner:
54 | # 1. install gh: `brew install gh`
55 | # 2. Start interactive setup `gh auth login`
56 | # 3. More: https://cli.github.com/manual/gh
57 | # About create Release API: https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release
58 |
59 | gh api \
60 | --method POST \
61 | -H "Accept: application/vnd.github+json" \
62 | -H "X-GitHub-Api-Version: 2022-11-28" \
63 | /repos/ByteriX/Imagelinter/releases \
64 | -f tag_name="$CURRENT_VERSION" \
65 | -f target_commitish='main' \
66 | -f name="$CURRENT_VERSION" \
67 | -f body="$VERSION_MESSAGE" \
68 | -F draft=false \
69 | -F prerelease=false \
70 | -F generate_release_notes=false
71 |
72 |
73 | checkExit "GitHub release upload"
74 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 | build.config
92 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Assets.xcassets/FalseSVG.imageset/graphic.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Resources/Assets.xcassets/FalseSVG.imageset/graphic.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | # Changelog
3 |
4 | Any significant changes made to this project will be documented in this file.
5 |
6 | ## [2.2.1] - 2025-11-29
7 |
8 | #### Added
9 |
10 | - #13 new case .uiKitLiteral for support image literals.
11 | - an example to use image literal.
12 | - #14 description about --settingsPath param to Readme.
13 |
14 | ## [2.2.0] - 2025-11-27
15 |
16 | #### Added
17 |
18 | - Addition the param relativeSourcePaths as extention of the relativeSourcePath. Before relativeSourcePath worked with issue.
19 | - Addition the same param relativeImagesPaths as extention of the relativeImagesPath.
20 |
21 | ## [2.1.2] - 2025-09-25
22 |
23 | #### Fixed
24 |
25 | - Reading the binary vector files.
26 | - Improvements vector files error messages.
27 |
28 | ## [2.1.1] - 2025-05-24
29 |
30 | #### Fixed
31 |
32 | - Examples for the SPM plugin using and the Swift Script using.
33 |
34 | ## [2.1.0] - 2025-05-24
35 |
36 | #### Added
37 |
38 | - Updating script version `ImageLinter.swift` from release script.
39 | - Actualization both examples for using with a Plugin and a Script.
40 |
41 | ## [2.0.3] - 2024-04-23
42 |
43 | #### Added
44 |
45 | - Supporting Settings with more yaml/yml extension from Root Library/target with inherited. Priority: target/root, yaml/yml.
46 | - Documentation of Settings file format.
47 |
48 | ## [2.0.2] - 2024-04-21
49 |
50 | #### Fixed
51 |
52 | - SwiftGen type options with using .name property.
53 |
54 | #### Added
55 |
56 | - To Custom type `isSwiftGen` attribute.
57 |
58 | ## [2.0.1] - 2024-04-18
59 |
60 | #### Fixed
61 |
62 | - Standart both SwiftGen image using.
63 | - #10 SwiftGen variation with name contains '-' and '_' symbols.
64 |
65 | ## [2.0.0] - 2024-04-10
66 |
67 | #### Added
68 |
69 | - Supporting SPM plugin.
70 | - Settings from YAML.
71 | - Changelog.
72 |
73 | #### Fixed
74 |
75 | - Documentation with intallation and setup settings sections.
76 |
77 | ## [1.7.0] - 2023-07-14
78 |
79 | #### Added
80 |
81 | - #3 added checking for platform target
82 |
83 | ## [1.6.1] - 2023-07-13
84 |
85 | #### Fixed
86 |
87 | - Readme: ImageLinter call with image and source path from command line
88 | - Example: new case with not found image.
89 | - #8 issue: duplicated errors.
90 |
91 | ## [1.6.0] - 2023-07-10
92 |
93 | #### Added
94 |
95 | - Image and source pathes from command line getting
96 |
97 | ## [1.5.1] - 2023-07-09
98 |
99 | #### Fixed
100 |
101 | - Commented error for scaled images.
102 |
103 | ## [1.5.0] - 2023-07-09
104 |
105 | #### Added
106 |
107 | - Analyse from sources and resources.
108 | - Properties sourcesExtensions, resourcesExtensions, isCheckingImageSize.
109 |
110 | ## [1.4.0] - 2022-11-21
111 |
112 | #### Added
113 |
114 | - Supporting checking of rastor in SVG.
115 |
116 | ## [1.3.1] - 2022-11-21
117 |
118 | #### Fixed
119 |
120 | - Supporting SVG format.
121 |
122 | ## [1.3.0] - 2022-11-21
123 |
124 | #### Added
125 |
126 | - Descriptions to Readme.
127 | - Seporated maxVectorImageSize and maxRastorImageSize.
128 | - Supporting SVG format.
129 |
130 | #### Fixed
131 |
132 | - Renamed maxVectorFileSize and maxRastorFileSize from maxPdfSize and maxPngSize
133 |
134 | ## [1.2.3] - 2022-10-07
135 |
136 | #### Added
137 |
138 | - Search empty and broken asset images.
139 |
140 | ## [1.2.2] - 2022-10-06
141 |
142 | #### Added
143 |
144 | - Image name to error message.
145 |
146 | #### Fixed
147 |
148 | - Bug with regular expressions.
149 | - Full support SwiftGen.
150 |
151 | ## [1.2.1] - 2022-10-05
152 |
153 | #### Added
154 |
155 | - Image file filter by extensions.
156 |
157 | #### Fixed
158 |
159 | - Supporting folder from Asset.
160 |
161 | ## [1.2.0] - 2022-10-04
162 |
163 | #### Added
164 |
165 | - Checking duplication images by content
166 | - More Examples error images.
167 | - UsingType settings with uiKit value.
168 | - Search undefined images.
169 | - Checking image size.
170 | - ignoredUnusedImages for excude errors.
171 |
172 | ## [1.1.0] - 2022-09-28
173 |
174 | #### Added
175 |
176 | - Searching unused images.
177 | - Checking duplication images by name
178 | - UsingType settings with swiftUI, swiftGen and custom pattern of search.
179 |
180 | ## [1.0.0] - 2022-09-24
181 |
182 | #### Added
183 |
184 | - Checking file size.
185 | - PDF vector validation.
186 | - Showing error in XCode.
187 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageLinter
2 |
3 | Check image files and resources for Swift
4 |
5 | ## Script allows
6 |
7 | 1. Checking size of vector(PDF) and rastor(PNG/JPEG) files
8 | 2. Catch raster from PDF
9 | 3. Checking unused image files
10 | 4. Search undefined images
11 | 5. Comparing scaled images size
12 | 6. Checking duplicate images by name
13 | 7. Checking duplicate images by content (but identical)
14 | 8. Search empty and broken asset images
15 | 9. Analysis scales of images with dependency on platforms target
16 |
17 | 
18 |
19 | ## Accessibility
20 |
21 | 1. Possible analyse the sources (swift, Objective-C files) and resources (Storyboard, xib files)
22 | 2. Support Assets and files with @Xx notation
23 | 3. vector/rastor diffenition and you can limit use formats by PNG, JPG, PDF, SVG, etc formats
24 | 4. Support any use notation: SwiftUI, UIKit, SwiftGen, and custom Regex
25 | 5. You can ignore any images
26 | 6. Any settings for generation errors or warnings
27 |
28 | ## Install
29 |
30 | ### Swift Package Manager (SPM)
31 |
32 | The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. `Imagelinter` supports its use on supported platforms as plugin tool.
33 |
34 | Once you have your Swift package set up, adding `Imagelinter` as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. Then you need call from your target plugin like this:
35 |
36 | ```swift
37 |
38 | dependencies: [
39 | .Package(url: "https://github.com/ByteriX/Imagelinter.git", majorVersion: 2)
40 | ],
41 | targets: [
42 | .target(
43 | name: "YourTarget",
44 | plugins: [
45 | .plugin(name: "ImagelinterPlugin", package: "Imagelinter"),
46 | ]
47 | )
48 | ]
49 |
50 | ```
51 |
52 | ### Swift script from Build Phases
53 |
54 | 1. Just copy ImageLinter.swift to project.
55 | 2. Exclude from "Build Phases" -> "Compile Sources"
56 | 3. Add to "Build Phases" run script:
57 | ```bash
58 | ${SRCROOT}/ImageLinter.swift
59 | ```
60 | 
61 |
62 | ## Settings:
63 |
64 | You need to add a settings file named `imagelinter.yaml` or/and `imagelinter.yml` to a `target` or/and `the root of the library` `dir` of the package.
65 | imagesPath and sourcePath are calculated from dir of this package.
66 |
67 | Supports more settings files with rewrite properties with priority: first a `target` then `the root of library `dir`, first `imagelinter.yaml` then `imagelinter.yml`.
68 | If you want to have a custom path to settings file, you can use `--settingsPath [path to your imagelinter.yaml or imagelinter.yml file]` command line param from script call only on build phase. In the plugin this would be set to target dirrectory all time.
69 |
70 | ### Example of Settings file format
71 |
72 | ```yaml
73 | isEnabled: true
74 | relativeImagesPath: /Sources/Images/Resources
75 | relativeImagesPaths:
76 | - /Module1/res
77 | - /Module2/res
78 | relativeSourcePath: /Sources/Code
79 | relativeSourcePaths:
80 | - /Module1/src
81 | - /Module2/src
82 | usingTypes:
83 | - case: uiKit
84 | - case: uiKitLiteral
85 | - case: swiftUI
86 | - case: swiftGen
87 | enumName: Asset
88 | - case: custom
89 | pattern: "(.*)".name
90 | isSwiftGen: true
91 | - case: custom
92 | pattern: "(.*)".image
93 | ignoredUnusedImages:
94 | - temp
95 | ignoredUndefinedImages:
96 | - temp
97 | rastorExtensions:
98 | - png
99 | - jpg
100 | - jpeg
101 | vectorExtensions:
102 | - pdf
103 | - svg
104 | sourcesExtensions:
105 | - swift
106 | - mm
107 | resourcesExtensions:
108 | - storyboard
109 | - xib
110 | isAllFilesErrorShowing: false
111 | maxVectorFileSize: 10000
112 | maxVectorImageSize:
113 | width: 100
114 | height: 100
115 | maxRastorFileSize: 300000
116 | maxRastorImageSize:
117 | width: 300
118 | height: 300
119 | isCheckingFileSize: true
120 | isCheckingImageSize: true
121 | isCheckingPdfVector: true
122 | isCheckingSvgVector: true
123 | isCheckingScaleSize: true
124 | isCheckingDuplicatedByName: true
125 | isCheckingDuplicatedByContent: true
126 | targetPlatforms:
127 | - iOS
128 | - iPadOS
129 | - macOS
130 | - tvOS
131 | - visionOS
132 | - watchOS
133 | ```
134 |
135 | ## Example
136 |
137 | You can review 
138 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/SwiftGen/fonts.stencil:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | {% if families %}
5 | {% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
6 | {% set fontType %}{{param.fontTypeName|default:"FontConvertible"}}{% endset %}
7 | #if os(macOS)
8 | import AppKit.NSFont
9 | #elseif os(iOS) || os(tvOS) || os(watchOS)
10 | import UIKit
11 | import SwiftUI
12 | #endif
13 |
14 | // Deprecated typealiases
15 | //@available(*, deprecated, renamed: "{{fontType}}.Font", message: "This typealias will be removed in SwiftGen 7.0")
16 | //{{accessModifier}} typealias {{param.fontAliasName|default:"Font"}} = {{fontType}}.Font
17 |
18 | // swiftlint:disable superfluous_disable_command
19 | // swiftlint:disable file_length
20 |
21 | // MARK: - Fonts
22 |
23 | // swiftlint:disable identifier_name line_length type_body_length
24 | {% macro transformPath path %}{% filter removeNewlines %}
25 | {% if param.preservePath %}
26 | {{path}}
27 | {% else %}
28 | {{path|basename}}
29 | {% endif %}
30 | {% endfilter %}{% endmacro %}
31 | {{accessModifier}} enum {{param.enumName|default:"FontFamily"}} {
32 | {% for family in families %}
33 | {{accessModifier}} enum {{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
34 | {% for font in family.fonts %}
35 | {{accessModifier}} static let {{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{fontType}}(name: "{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}")
36 | {% endfor %}
37 | {{accessModifier}} static let all: [{{fontType}}] = [{% for font in family.fonts %}{{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{{ ", " if not forloop.last }}{% endfor %}]
38 | }
39 | {% endfor %}
40 | {{accessModifier}} static let allCustomFonts: [{{fontType}}] = [{% for family in families %}{{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.all{{ ", " if not forloop.last }}{% endfor %}].flatMap { $0 }
41 | {{accessModifier}} static func registerAllCustomFonts() {
42 | allCustomFonts.forEach { $0.register() }
43 | }
44 | }
45 | // swiftlint:enable identifier_name line_length type_body_length
46 |
47 | // MARK: - Implementation Details
48 |
49 | public extension Font {
50 | init(uiFont: UIFont) {
51 | self = Font(uiFont as CTFont)
52 | }
53 | }
54 |
55 | {{accessModifier}} struct {{fontType}} {
56 | {{accessModifier}} let name: String
57 | {{accessModifier}} let family: String
58 | {{accessModifier}} let path: String
59 |
60 | #if os(macOS)
61 | {{accessModifier}} typealias Font = NSFont
62 | #elseif os(iOS) || os(tvOS) || os(watchOS)
63 | //{{accessModifier}} typealias Font = UIFont
64 | #endif
65 |
66 | {{accessModifier}} func font(size: CGFloat) -> Font {
67 | guard let font = UIFont(font: self, size: size) else {
68 | fatalError("Unable to initialize font '\(name)' (\(family))")
69 | }
70 | return Font(uiFont: font)
71 | }
72 |
73 | {{accessModifier}} func register() {
74 | // swiftlint:disable:next conditional_returns_on_newline
75 | guard let url = url else { return }
76 | CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
77 | }
78 |
79 | fileprivate var url: URL? {
80 | // swiftlint:disable:next implicit_return
81 | {% if param.lookupFunction %}
82 | return {{param.lookupFunction}}(name, family, path)
83 | {% else %}
84 | return {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil)
85 | {% endif %}
86 | }
87 | }
88 |
89 | {{accessModifier}} extension UIFont {
90 | convenience init?(font: {{fontType}}, size: CGFloat) {
91 | #if os(iOS) || os(tvOS) || os(watchOS)
92 | if !UIFont.fontNames(forFamilyName: font.family).contains(font.name) {
93 | font.register()
94 | }
95 | #elseif os(macOS)
96 | if let url = font.url, CTFontManagerGetScopeForURL(url as CFURL) == .none {
97 | font.register()
98 | }
99 | #endif
100 |
101 | self.init(name: font.name, size: size)
102 | }
103 | }
104 | {% if not param.bundle and not param.lookupFunction %}
105 |
106 | // swiftlint:disable convenience_type
107 | private final class BundleToken {
108 | static let bundle: Bundle = {
109 | #if SWIFT_PACKAGE
110 | return Bundle.module
111 | #else
112 | return Bundle(for: BundleToken.self)
113 | #endif
114 | }()
115 | }
116 | // swiftlint:enable convenience_type
117 | {% endif %}
118 | {% else %}
119 | // No fonts found
120 | {% endif %}
--------------------------------------------------------------------------------
/Examples/SwiftScript/SwiftGen/fonts.stencil:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | {% if families %}
5 | {% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
6 | {% set fontType %}{{param.fontTypeName|default:"FontConvertible"}}{% endset %}
7 | #if os(macOS)
8 | import AppKit.NSFont
9 | #elseif os(iOS) || os(tvOS) || os(watchOS)
10 | import UIKit
11 | import SwiftUI
12 | #endif
13 |
14 | // Deprecated typealiases
15 | //@available(*, deprecated, renamed: "{{fontType}}.Font", message: "This typealias will be removed in SwiftGen 7.0")
16 | //{{accessModifier}} typealias {{param.fontAliasName|default:"Font"}} = {{fontType}}.Font
17 |
18 | // swiftlint:disable superfluous_disable_command
19 | // swiftlint:disable file_length
20 |
21 | // MARK: - Fonts
22 |
23 | // swiftlint:disable identifier_name line_length type_body_length
24 | {% macro transformPath path %}{% filter removeNewlines %}
25 | {% if param.preservePath %}
26 | {{path}}
27 | {% else %}
28 | {{path|basename}}
29 | {% endif %}
30 | {% endfilter %}{% endmacro %}
31 | {{accessModifier}} enum {{param.enumName|default:"FontFamily"}} {
32 | {% for family in families %}
33 | {{accessModifier}} enum {{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
34 | {% for font in family.fonts %}
35 | {{accessModifier}} static let {{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{fontType}}(name: "{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}")
36 | {% endfor %}
37 | {{accessModifier}} static let all: [{{fontType}}] = [{% for font in family.fonts %}{{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{{ ", " if not forloop.last }}{% endfor %}]
38 | }
39 | {% endfor %}
40 | {{accessModifier}} static let allCustomFonts: [{{fontType}}] = [{% for family in families %}{{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.all{{ ", " if not forloop.last }}{% endfor %}].flatMap { $0 }
41 | {{accessModifier}} static func registerAllCustomFonts() {
42 | allCustomFonts.forEach { $0.register() }
43 | }
44 | }
45 | // swiftlint:enable identifier_name line_length type_body_length
46 |
47 | // MARK: - Implementation Details
48 |
49 | public extension Font {
50 | init(uiFont: UIFont) {
51 | self = Font(uiFont as CTFont)
52 | }
53 | }
54 |
55 | {{accessModifier}} struct {{fontType}} {
56 | {{accessModifier}} let name: String
57 | {{accessModifier}} let family: String
58 | {{accessModifier}} let path: String
59 |
60 | #if os(macOS)
61 | {{accessModifier}} typealias Font = NSFont
62 | #elseif os(iOS) || os(tvOS) || os(watchOS)
63 | //{{accessModifier}} typealias Font = UIFont
64 | #endif
65 |
66 | {{accessModifier}} func font(size: CGFloat) -> Font {
67 | guard let font = UIFont(font: self, size: size) else {
68 | fatalError("Unable to initialize font '\(name)' (\(family))")
69 | }
70 | return Font(uiFont: font)
71 | }
72 |
73 | {{accessModifier}} func register() {
74 | // swiftlint:disable:next conditional_returns_on_newline
75 | guard let url = url else { return }
76 | CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
77 | }
78 |
79 | fileprivate var url: URL? {
80 | // swiftlint:disable:next implicit_return
81 | {% if param.lookupFunction %}
82 | return {{param.lookupFunction}}(name, family, path)
83 | {% else %}
84 | return {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil)
85 | {% endif %}
86 | }
87 | }
88 |
89 | {{accessModifier}} extension UIFont {
90 | convenience init?(font: {{fontType}}, size: CGFloat) {
91 | #if os(iOS) || os(tvOS) || os(watchOS)
92 | if !UIFont.fontNames(forFamilyName: font.family).contains(font.name) {
93 | font.register()
94 | }
95 | #elseif os(macOS)
96 | if let url = font.url, CTFontManagerGetScopeForURL(url as CFURL) == .none {
97 | font.register()
98 | }
99 | #endif
100 |
101 | self.init(name: font.name, size: size)
102 | }
103 | }
104 | {% if not param.bundle and not param.lookupFunction %}
105 |
106 | // swiftlint:disable convenience_type
107 | private final class BundleToken {
108 | static let bundle: Bundle = {
109 | #if SWIFT_PACKAGE
110 | return Bundle.module
111 | #else
112 | return Bundle(for: BundleToken.self)
113 | #endif
114 | }()
115 | }
116 | // swiftlint:enable convenience_type
117 | {% endif %}
118 | {% else %}
119 | // No fonts found
120 | {% endif %}
--------------------------------------------------------------------------------
/Examples/SwiftScript/Example/Generated/Assets+Generated.swift:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | #if os(macOS)
5 | import AppKit
6 | #elseif os(iOS)
7 | import SwiftUI
8 | #elseif os(tvOS) || os(watchOS)
9 | import UIKit
10 | #endif
11 |
12 | // Deprecated typealiases
13 | @available(*, deprecated, renamed: "ColorAsset.Color", message: "This typealias will be removed in SwiftGen 7.0")
14 | internal typealias AssetColorTypeAlias = ColorAsset.Color
15 | @available(*, deprecated, renamed: "ImageAsset.Image", message: "This typealias will be removed in SwiftGen 7.0")
16 | internal typealias AssetImageTypeAlias = ImageAsset.Image
17 |
18 | // swiftlint:disable superfluous_disable_command file_length implicit_return
19 |
20 | // MARK: - Asset Catalogs
21 |
22 | // swiftlint:disable identifier_name line_length nesting type_body_length type_name
23 | internal enum Asset {
24 | internal static let accentColor = ColorAsset(name: "AccentColor")
25 | internal static let badRaster = ImageAsset(name: "BadRaster")
26 | internal static let bigRastor = ImageAsset(name: "BigRastor")
27 | internal static let bigVector = ImageAsset(name: "BigVector")
28 | internal static let duplicate = ImageAsset(name: "Duplicate")
29 | internal static let duplicatedImage2 = ImageAsset(name: "DuplicatedImage2")
30 | internal static let duplicatedImage4 = ImageAsset(name: "DuplicatedImage4")
31 | internal static let empty = ImageAsset(name: "Empty")
32 | internal static let falsePdf = ImageAsset(name: "FalsePdf")
33 | internal static let falseSVG = ImageAsset(name: "FalseSVG")
34 | internal enum Folder {
35 | internal static let duplicatedImage3 = ImageAsset(name: "Folder/DuplicatedImage3")
36 | }
37 | internal static let mixedBookmark = ImageAsset(name: "MixedBookmark")
38 | internal static let mixedUp1 = ImageAsset(name: "MixedUp1")
39 | internal static let mixedUp2 = ImageAsset(name: "MixedUp2")
40 | internal static let notFoundFile = ImageAsset(name: "NotFoundFile")
41 | internal static let notUsingImage = ImageAsset(name: "NotUsingImage")
42 | internal static let duplicatedImage1 = ImageAsset(name: "DuplicatedImage1")
43 | internal static let truePdf = ImageAsset(name: "TruePdf")
44 | internal static let truePng = ImageAsset(name: "TruePng")
45 | internal static let twoVectors = ImageAsset(name: "TwoVectors")
46 | internal static let checkSVG = ImageAsset(name: "checkSVG")
47 | }
48 | // swiftlint:enable identifier_name line_length nesting type_body_length type_name
49 |
50 | // MARK: - Implementation Details
51 |
52 | internal final class ColorAsset {
53 | internal fileprivate(set) var name: String
54 |
55 | #if os(macOS)
56 | internal typealias Color = NSColor
57 | #elseif os(iOS) || os(tvOS) || os(watchOS)
58 | internal typealias Color = SwiftUI.Color
59 | internal typealias UIColor = UIKit.UIColor
60 | #endif
61 |
62 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
63 | internal private(set) lazy var color: Color = {
64 | guard let color = Color(asset: self) else {
65 | fatalError("Unable to load color asset named \(name).")
66 | }
67 | return color
68 | }()
69 |
70 | internal private(set) lazy var uiColor: UIColor = {
71 | guard let color = UIColor(asset: self) else {
72 | fatalError("Unable to load color asset named \(name).")
73 | }
74 | return color
75 | }()
76 | /*
77 | #if os(iOS) || os(tvOS)
78 | @available(iOS 11.0, tvOS 11.0, *)
79 | internal func color(compatibleWith traitCollection: UITraitCollection) -> Color {
80 | let bundle = BundleToken.bundle
81 | guard let color = Color(named: name, bundle: bundle, compatibleWith: traitCollection) else {
82 | fatalError("Unable to load color asset named \(name).")
83 | }
84 | return color
85 | }
86 | #endif
87 | */
88 |
89 | fileprivate init(name: String) {
90 | self.name = name
91 | }
92 | }
93 |
94 | internal extension ColorAsset.Color {
95 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
96 | init?(asset: ColorAsset) {
97 | let bundle = BundleToken.bundle
98 | #if os(iOS) || os(tvOS)
99 | self.init(asset.name, bundle: bundle)
100 | #elseif os(macOS)
101 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
102 | #elseif os(watchOS)
103 | self.init(named: asset.name)
104 | #endif
105 | }
106 | }
107 | internal extension ColorAsset.UIColor {
108 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
109 | convenience init?(asset: ColorAsset) {
110 | let bundle = BundleToken.bundle
111 | #if os(iOS) || os(tvOS)
112 | self.init(named: asset.name, in: bundle, compatibleWith: nil)
113 | #elseif os(macOS)
114 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
115 | #elseif os(watchOS)
116 | self.init(named: asset.name)
117 | #endif
118 | }
119 | }
120 |
121 | internal struct ImageAsset {
122 | internal fileprivate(set) var name: String
123 |
124 | #if os(macOS)
125 | internal typealias Image = NSImage
126 | #elseif os(iOS) || os(tvOS) || os(watchOS)
127 | internal typealias Image = SwiftUI.Image
128 | #endif
129 |
130 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
131 | internal var image: Image {
132 | let bundle = BundleToken.bundle
133 | #if os(iOS) || os(tvOS)
134 | let image = Image(name, bundle: bundle)
135 | #elseif os(macOS)
136 | let name = NSImage.Name(self.name)
137 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
138 | #elseif os(watchOS)
139 | let image = Image(named: name)
140 | #endif
141 | //guard let result = image else {
142 | // fatalError("Unable to load image asset named \(name).")
143 | //}
144 | return image
145 | }
146 |
147 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
148 | internal var uiImage: UIImage {
149 | let bundle = BundleToken.bundle
150 | #if os(iOS) || os(tvOS)
151 | let image = UIImage(named: name, in: bundle, compatibleWith: nil)
152 | #elseif os(macOS)
153 | let name = NSImage.Name(self.name)
154 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
155 | #elseif os(watchOS)
156 | let image = Image(named: name)
157 | #endif
158 | guard let image = image else {
159 | fatalError("Unable to load image asset named \(name).")
160 | }
161 | return image
162 | }
163 | /*
164 | #if os(iOS) || os(tvOS)
165 | @available(iOS 8.0, tvOS 9.0, *)
166 | internal func image(compatibleWith traitCollection: UITraitCollection) -> Image {
167 | let bundle = BundleToken.bundle
168 | guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
169 | fatalError("Unable to load image asset named \(name).")
170 | }
171 | return result
172 | }
173 | #endif
174 | */
175 | }
176 |
177 | internal extension ImageAsset.Image {
178 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
179 | @available(macOS, deprecated,
180 | message: "This initializer is unsafe on macOS, please use the ImageAsset.image property")
181 | init?(asset: ImageAsset) {
182 | #if os(iOS) || os(tvOS)
183 | let bundle = BundleToken.bundle
184 | self.init(asset.name, bundle: bundle)
185 | #elseif os(macOS)
186 | self.init(named: NSImage.Name(asset.name))
187 | #elseif os(watchOS)
188 | self.init(named: asset.name)
189 | #endif
190 | }
191 | }
192 |
193 | // swiftlint:disable convenience_type
194 | private final class BundleToken {
195 | static let bundle: Bundle = {
196 | #if SWIFT_PACKAGE
197 | return Bundle.module
198 | #else
199 | return Bundle(for: BundleToken.self)
200 | #endif
201 | }()
202 | }
203 | // swiftlint:enable convenience_type
204 |
205 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example/Modules/Images/Sources/Images/Generated/Assets+Generated.swift:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | #if os(macOS)
5 | import AppKit
6 | #elseif os(iOS)
7 | import SwiftUI
8 | #elseif os(tvOS) || os(watchOS)
9 | import UIKit
10 | #endif
11 |
12 | // Deprecated typealiases
13 | @available(*, deprecated, renamed: "ColorAsset.Color", message: "This typealias will be removed in SwiftGen 7.0")
14 | internal typealias AssetColorTypeAlias = ColorAsset.Color
15 | @available(*, deprecated, renamed: "ImageAsset.Image", message: "This typealias will be removed in SwiftGen 7.0")
16 | internal typealias AssetImageTypeAlias = ImageAsset.Image
17 |
18 | // swiftlint:disable superfluous_disable_command file_length implicit_return
19 |
20 | // MARK: - Asset Catalogs
21 |
22 | // swiftlint:disable identifier_name line_length nesting type_body_length type_name
23 | internal enum Asset {
24 | internal static let accentColor = ColorAsset(name: "AccentColor")
25 | internal static let badRaster = ImageAsset(name: "BadRaster")
26 | internal static let bigRastor = ImageAsset(name: "BigRastor")
27 | internal static let bigVector = ImageAsset(name: "BigVector")
28 | internal static let duplicate = ImageAsset(name: "Duplicate")
29 | internal static let duplicatedImage2 = ImageAsset(name: "DuplicatedImage2")
30 | internal static let duplicatedImage4 = ImageAsset(name: "DuplicatedImage4")
31 | internal static let empty = ImageAsset(name: "Empty")
32 | internal static let falsePdf = ImageAsset(name: "FalsePdf")
33 | internal static let falseSVG = ImageAsset(name: "FalseSVG")
34 | internal enum Folder {
35 | internal static let duplicatedImage3 = ImageAsset(name: "Folder/DuplicatedImage3")
36 | }
37 | internal static let mixedBookmark = ImageAsset(name: "MixedBookmark")
38 | internal static let mixedUp1 = ImageAsset(name: "MixedUp1")
39 | internal static let mixedUp2 = ImageAsset(name: "MixedUp2")
40 | internal static let notFoundFile = ImageAsset(name: "NotFoundFile")
41 | internal static let notUsingImage = ImageAsset(name: "NotUsingImage")
42 | internal static let duplicatedImage1 = ImageAsset(name: "DuplicatedImage1")
43 | internal static let truePdf = ImageAsset(name: "TruePdf")
44 | internal static let truePng = ImageAsset(name: "TruePng")
45 | internal static let twoVectors = ImageAsset(name: "TwoVectors")
46 | internal static let checkSVG = ImageAsset(name: "checkSVG")
47 | }
48 | // swiftlint:enable identifier_name line_length nesting type_body_length type_name
49 |
50 | // MARK: - Implementation Details
51 |
52 | internal final class ColorAsset {
53 | internal fileprivate(set) var name: String
54 |
55 | #if os(macOS)
56 | internal typealias Color = NSColor
57 | #elseif os(iOS) || os(tvOS) || os(watchOS)
58 | internal typealias Color = SwiftUI.Color
59 | internal typealias UIColor = UIKit.UIColor
60 | #endif
61 |
62 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
63 | internal private(set) lazy var color: Color = {
64 | guard let color = Color(asset: self) else {
65 | fatalError("Unable to load color asset named \(name).")
66 | }
67 | return color
68 | }()
69 |
70 | internal private(set) lazy var uiColor: UIColor = {
71 | guard let color = UIColor(asset: self) else {
72 | fatalError("Unable to load color asset named \(name).")
73 | }
74 | return color
75 | }()
76 | /*
77 | #if os(iOS) || os(tvOS)
78 | @available(iOS 11.0, tvOS 11.0, *)
79 | internal func color(compatibleWith traitCollection: UITraitCollection) -> Color {
80 | let bundle = BundleToken.bundle
81 | guard let color = Color(named: name, bundle: bundle, compatibleWith: traitCollection) else {
82 | fatalError("Unable to load color asset named \(name).")
83 | }
84 | return color
85 | }
86 | #endif
87 | */
88 |
89 | fileprivate init(name: String) {
90 | self.name = name
91 | }
92 | }
93 |
94 | internal extension ColorAsset.Color {
95 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
96 | init?(asset: ColorAsset) {
97 | let bundle = BundleToken.bundle
98 | #if os(iOS) || os(tvOS)
99 | self.init(asset.name, bundle: bundle)
100 | #elseif os(macOS)
101 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
102 | #elseif os(watchOS)
103 | self.init(named: asset.name)
104 | #endif
105 | }
106 | }
107 | internal extension ColorAsset.UIColor {
108 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
109 | convenience init?(asset: ColorAsset) {
110 | let bundle = BundleToken.bundle
111 | #if os(iOS) || os(tvOS)
112 | self.init(named: asset.name, in: bundle, compatibleWith: nil)
113 | #elseif os(macOS)
114 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
115 | #elseif os(watchOS)
116 | self.init(named: asset.name)
117 | #endif
118 | }
119 | }
120 |
121 | internal struct ImageAsset {
122 | internal fileprivate(set) var name: String
123 |
124 | #if os(macOS)
125 | internal typealias Image = NSImage
126 | #elseif os(iOS) || os(tvOS) || os(watchOS)
127 | internal typealias Image = SwiftUI.Image
128 | #endif
129 |
130 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
131 | internal var image: Image {
132 | let bundle = BundleToken.bundle
133 | #if os(iOS) || os(tvOS)
134 | let image = Image(name, bundle: bundle)
135 | #elseif os(macOS)
136 | let name = NSImage.Name(self.name)
137 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
138 | #elseif os(watchOS)
139 | let image = Image(named: name)
140 | #endif
141 | //guard let result = image else {
142 | // fatalError("Unable to load image asset named \(name).")
143 | //}
144 | return image
145 | }
146 |
147 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
148 | internal var uiImage: UIImage {
149 | let bundle = BundleToken.bundle
150 | #if os(iOS) || os(tvOS)
151 | let image = UIImage(named: name, in: bundle, compatibleWith: nil)
152 | #elseif os(macOS)
153 | let name = NSImage.Name(self.name)
154 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
155 | #elseif os(watchOS)
156 | let image = Image(named: name)
157 | #endif
158 | guard let image = image else {
159 | fatalError("Unable to load image asset named \(name).")
160 | }
161 | return image
162 | }
163 | /*
164 | #if os(iOS) || os(tvOS)
165 | @available(iOS 8.0, tvOS 9.0, *)
166 | internal func image(compatibleWith traitCollection: UITraitCollection) -> Image {
167 | let bundle = BundleToken.bundle
168 | guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
169 | fatalError("Unable to load image asset named \(name).")
170 | }
171 | return result
172 | }
173 | #endif
174 | */
175 | }
176 |
177 | internal extension ImageAsset.Image {
178 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
179 | @available(macOS, deprecated,
180 | message: "This initializer is unsafe on macOS, please use the ImageAsset.image property")
181 | init?(asset: ImageAsset) {
182 | #if os(iOS) || os(tvOS)
183 | let bundle = BundleToken.bundle
184 | self.init(asset.name, bundle: bundle)
185 | #elseif os(macOS)
186 | self.init(named: NSImage.Name(asset.name))
187 | #elseif os(watchOS)
188 | self.init(named: asset.name)
189 | #endif
190 | }
191 | }
192 |
193 | // swiftlint:disable convenience_type
194 | private final class BundleToken {
195 | static let bundle: Bundle = {
196 | #if SWIFT_PACKAGE
197 | return Bundle.module
198 | #else
199 | return Bundle(for: BundleToken.self)
200 | #endif
201 | }()
202 | }
203 | // swiftlint:enable convenience_type
204 |
205 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 56;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | C37E670E2BBCA0620057DAFC /* Images in Resources */ = {isa = PBXBuildFile; fileRef = C37E670C2BBCA0610057DAFC /* Images */; };
11 | C37E67112BBCA0D00057DAFC /* Images in Frameworks */ = {isa = PBXBuildFile; productRef = C37E67102BBCA0D00057DAFC /* Images */; };
12 | C3F03CC928E37B90004CFE58 /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F03CC828E37B90004CFE58 /* ExampleApp.swift */; };
13 | /* End PBXBuildFile section */
14 |
15 | /* Begin PBXFileReference section */
16 | C31C728D2BBC935600113564 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = ""; };
17 | C37E670C2BBCA0610057DAFC /* Images */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Images; sourceTree = ""; };
18 | C3F03CC528E37B90004CFE58 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
19 | C3F03CC828E37B90004CFE58 /* ExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleApp.swift; sourceTree = ""; };
20 | /* End PBXFileReference section */
21 |
22 | /* Begin PBXFrameworksBuildPhase section */
23 | C3F03CC228E37B90004CFE58 /* Frameworks */ = {
24 | isa = PBXFrameworksBuildPhase;
25 | buildActionMask = 2147483647;
26 | files = (
27 | C37E67112BBCA0D00057DAFC /* Images in Frameworks */,
28 | );
29 | runOnlyForDeploymentPostprocessing = 0;
30 | };
31 | /* End PBXFrameworksBuildPhase section */
32 |
33 | /* Begin PBXGroup section */
34 | C37E670D2BBCA0610057DAFC /* Modules */ = {
35 | isa = PBXGroup;
36 | children = (
37 | C37E670C2BBCA0610057DAFC /* Images */,
38 | );
39 | path = Modules;
40 | sourceTree = "";
41 | };
42 | C37E670F2BBCA0D00057DAFC /* Frameworks */ = {
43 | isa = PBXGroup;
44 | children = (
45 | );
46 | name = Frameworks;
47 | sourceTree = "";
48 | };
49 | C3F03CBC28E37B90004CFE58 = {
50 | isa = PBXGroup;
51 | children = (
52 | C31C728D2BBC935600113564 /* README.md */,
53 | C3F03CC728E37B90004CFE58 /* Example */,
54 | C3F03CC628E37B90004CFE58 /* Products */,
55 | C37E670F2BBCA0D00057DAFC /* Frameworks */,
56 | );
57 | sourceTree = "";
58 | };
59 | C3F03CC628E37B90004CFE58 /* Products */ = {
60 | isa = PBXGroup;
61 | children = (
62 | C3F03CC528E37B90004CFE58 /* Example.app */,
63 | );
64 | name = Products;
65 | sourceTree = "";
66 | };
67 | C3F03CC728E37B90004CFE58 /* Example */ = {
68 | isa = PBXGroup;
69 | children = (
70 | C37E670D2BBCA0610057DAFC /* Modules */,
71 | C3F03CC828E37B90004CFE58 /* ExampleApp.swift */,
72 | );
73 | path = Example;
74 | sourceTree = "";
75 | };
76 | /* End PBXGroup section */
77 |
78 | /* Begin PBXNativeTarget section */
79 | C3F03CC428E37B90004CFE58 /* Example */ = {
80 | isa = PBXNativeTarget;
81 | buildConfigurationList = C3F03CD328E37B92004CFE58 /* Build configuration list for PBXNativeTarget "Example" */;
82 | buildPhases = (
83 | C3F03CC128E37B90004CFE58 /* Sources */,
84 | C3F03CC228E37B90004CFE58 /* Frameworks */,
85 | C3F03CC328E37B90004CFE58 /* Resources */,
86 | );
87 | buildRules = (
88 | );
89 | dependencies = (
90 | );
91 | name = Example;
92 | packageProductDependencies = (
93 | C37E67102BBCA0D00057DAFC /* Images */,
94 | );
95 | productName = Example;
96 | productReference = C3F03CC528E37B90004CFE58 /* Example.app */;
97 | productType = "com.apple.product-type.application";
98 | };
99 | /* End PBXNativeTarget section */
100 |
101 | /* Begin PBXProject section */
102 | C3F03CBD28E37B90004CFE58 /* Project object */ = {
103 | isa = PBXProject;
104 | attributes = {
105 | BuildIndependentTargetsInParallel = 1;
106 | LastSwiftUpdateCheck = 1400;
107 | LastUpgradeCheck = 1400;
108 | TargetAttributes = {
109 | C3F03CC428E37B90004CFE58 = {
110 | CreatedOnToolsVersion = 14.0;
111 | };
112 | };
113 | };
114 | buildConfigurationList = C3F03CC028E37B90004CFE58 /* Build configuration list for PBXProject "Example" */;
115 | compatibilityVersion = "Xcode 14.0";
116 | developmentRegion = en;
117 | hasScannedForEncodings = 0;
118 | knownRegions = (
119 | en,
120 | Base,
121 | );
122 | mainGroup = C3F03CBC28E37B90004CFE58;
123 | packageReferences = (
124 | );
125 | productRefGroup = C3F03CC628E37B90004CFE58 /* Products */;
126 | projectDirPath = "";
127 | projectRoot = "";
128 | targets = (
129 | C3F03CC428E37B90004CFE58 /* Example */,
130 | );
131 | };
132 | /* End PBXProject section */
133 |
134 | /* Begin PBXResourcesBuildPhase section */
135 | C3F03CC328E37B90004CFE58 /* Resources */ = {
136 | isa = PBXResourcesBuildPhase;
137 | buildActionMask = 2147483647;
138 | files = (
139 | C37E670E2BBCA0620057DAFC /* Images in Resources */,
140 | );
141 | runOnlyForDeploymentPostprocessing = 0;
142 | };
143 | /* End PBXResourcesBuildPhase section */
144 |
145 | /* Begin PBXSourcesBuildPhase section */
146 | C3F03CC128E37B90004CFE58 /* Sources */ = {
147 | isa = PBXSourcesBuildPhase;
148 | buildActionMask = 2147483647;
149 | files = (
150 | C3F03CC928E37B90004CFE58 /* ExampleApp.swift in Sources */,
151 | );
152 | runOnlyForDeploymentPostprocessing = 0;
153 | };
154 | /* End PBXSourcesBuildPhase section */
155 |
156 | /* Begin XCBuildConfiguration section */
157 | C3F03CD128E37B92004CFE58 /* Debug */ = {
158 | isa = XCBuildConfiguration;
159 | buildSettings = {
160 | ALWAYS_SEARCH_USER_PATHS = NO;
161 | CLANG_ANALYZER_NONNULL = YES;
162 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
163 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
164 | CLANG_ENABLE_MODULES = YES;
165 | CLANG_ENABLE_OBJC_ARC = YES;
166 | CLANG_ENABLE_OBJC_WEAK = YES;
167 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
168 | CLANG_WARN_BOOL_CONVERSION = YES;
169 | CLANG_WARN_COMMA = YES;
170 | CLANG_WARN_CONSTANT_CONVERSION = YES;
171 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
172 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
173 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
174 | CLANG_WARN_EMPTY_BODY = YES;
175 | CLANG_WARN_ENUM_CONVERSION = YES;
176 | CLANG_WARN_INFINITE_RECURSION = YES;
177 | CLANG_WARN_INT_CONVERSION = YES;
178 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
179 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
180 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
181 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
182 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
183 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
184 | CLANG_WARN_STRICT_PROTOTYPES = YES;
185 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
186 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
187 | CLANG_WARN_UNREACHABLE_CODE = YES;
188 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
189 | COPY_PHASE_STRIP = NO;
190 | DEBUG_INFORMATION_FORMAT = dwarf;
191 | ENABLE_STRICT_OBJC_MSGSEND = YES;
192 | ENABLE_TESTABILITY = YES;
193 | GCC_C_LANGUAGE_STANDARD = gnu11;
194 | GCC_DYNAMIC_NO_PIC = NO;
195 | GCC_NO_COMMON_BLOCKS = YES;
196 | GCC_OPTIMIZATION_LEVEL = 0;
197 | GCC_PREPROCESSOR_DEFINITIONS = (
198 | "DEBUG=1",
199 | "$(inherited)",
200 | );
201 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
202 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
203 | GCC_WARN_UNDECLARED_SELECTOR = YES;
204 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
205 | GCC_WARN_UNUSED_FUNCTION = YES;
206 | GCC_WARN_UNUSED_VARIABLE = YES;
207 | IPHONEOS_DEPLOYMENT_TARGET = 16.0;
208 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
209 | MTL_FAST_MATH = YES;
210 | ONLY_ACTIVE_ARCH = YES;
211 | SDKROOT = iphoneos;
212 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
213 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
214 | };
215 | name = Debug;
216 | };
217 | C3F03CD228E37B92004CFE58 /* Release */ = {
218 | isa = XCBuildConfiguration;
219 | buildSettings = {
220 | ALWAYS_SEARCH_USER_PATHS = NO;
221 | CLANG_ANALYZER_NONNULL = YES;
222 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
223 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
224 | CLANG_ENABLE_MODULES = YES;
225 | CLANG_ENABLE_OBJC_ARC = YES;
226 | CLANG_ENABLE_OBJC_WEAK = YES;
227 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
228 | CLANG_WARN_BOOL_CONVERSION = YES;
229 | CLANG_WARN_COMMA = YES;
230 | CLANG_WARN_CONSTANT_CONVERSION = YES;
231 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
232 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
233 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
234 | CLANG_WARN_EMPTY_BODY = YES;
235 | CLANG_WARN_ENUM_CONVERSION = YES;
236 | CLANG_WARN_INFINITE_RECURSION = YES;
237 | CLANG_WARN_INT_CONVERSION = YES;
238 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
239 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
240 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
241 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
242 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
243 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
244 | CLANG_WARN_STRICT_PROTOTYPES = YES;
245 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
246 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
247 | CLANG_WARN_UNREACHABLE_CODE = YES;
248 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
249 | COPY_PHASE_STRIP = NO;
250 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
251 | ENABLE_NS_ASSERTIONS = NO;
252 | ENABLE_STRICT_OBJC_MSGSEND = YES;
253 | GCC_C_LANGUAGE_STANDARD = gnu11;
254 | GCC_NO_COMMON_BLOCKS = YES;
255 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
256 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
257 | GCC_WARN_UNDECLARED_SELECTOR = YES;
258 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
259 | GCC_WARN_UNUSED_FUNCTION = YES;
260 | GCC_WARN_UNUSED_VARIABLE = YES;
261 | IPHONEOS_DEPLOYMENT_TARGET = 16.0;
262 | MTL_ENABLE_DEBUG_INFO = NO;
263 | MTL_FAST_MATH = YES;
264 | SDKROOT = iphoneos;
265 | SWIFT_COMPILATION_MODE = wholemodule;
266 | SWIFT_OPTIMIZATION_LEVEL = "-O";
267 | VALIDATE_PRODUCT = YES;
268 | };
269 | name = Release;
270 | };
271 | C3F03CD428E37B92004CFE58 /* Debug */ = {
272 | isa = XCBuildConfiguration;
273 | buildSettings = {
274 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
275 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
276 | CODE_SIGN_STYLE = Automatic;
277 | CURRENT_PROJECT_VERSION = 1;
278 | DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
279 | ENABLE_PREVIEWS = YES;
280 | GENERATE_INFOPLIST_FILE = YES;
281 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
282 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
283 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
284 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
285 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
286 | LD_RUNPATH_SEARCH_PATHS = (
287 | "$(inherited)",
288 | "@executable_path/Frameworks",
289 | );
290 | MARKETING_VERSION = 1.0;
291 | PRODUCT_BUNDLE_IDENTIFIER = Byterix.Example;
292 | PRODUCT_NAME = "$(TARGET_NAME)";
293 | SWIFT_EMIT_LOC_STRINGS = YES;
294 | SWIFT_VERSION = 5.0;
295 | TARGETED_DEVICE_FAMILY = "1,2";
296 | };
297 | name = Debug;
298 | };
299 | C3F03CD528E37B92004CFE58 /* Release */ = {
300 | isa = XCBuildConfiguration;
301 | buildSettings = {
302 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
303 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
304 | CODE_SIGN_STYLE = Automatic;
305 | CURRENT_PROJECT_VERSION = 1;
306 | DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
307 | ENABLE_PREVIEWS = YES;
308 | GENERATE_INFOPLIST_FILE = YES;
309 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
310 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
311 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
312 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
313 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
314 | LD_RUNPATH_SEARCH_PATHS = (
315 | "$(inherited)",
316 | "@executable_path/Frameworks",
317 | );
318 | MARKETING_VERSION = 1.0;
319 | PRODUCT_BUNDLE_IDENTIFIER = Byterix.Example;
320 | PRODUCT_NAME = "$(TARGET_NAME)";
321 | SWIFT_EMIT_LOC_STRINGS = YES;
322 | SWIFT_VERSION = 5.0;
323 | TARGETED_DEVICE_FAMILY = "1,2";
324 | };
325 | name = Release;
326 | };
327 | /* End XCBuildConfiguration section */
328 |
329 | /* Begin XCConfigurationList section */
330 | C3F03CC028E37B90004CFE58 /* Build configuration list for PBXProject "Example" */ = {
331 | isa = XCConfigurationList;
332 | buildConfigurations = (
333 | C3F03CD128E37B92004CFE58 /* Debug */,
334 | C3F03CD228E37B92004CFE58 /* Release */,
335 | );
336 | defaultConfigurationIsVisible = 0;
337 | defaultConfigurationName = Release;
338 | };
339 | C3F03CD328E37B92004CFE58 /* Build configuration list for PBXNativeTarget "Example" */ = {
340 | isa = XCConfigurationList;
341 | buildConfigurations = (
342 | C3F03CD428E37B92004CFE58 /* Debug */,
343 | C3F03CD528E37B92004CFE58 /* Release */,
344 | );
345 | defaultConfigurationIsVisible = 0;
346 | defaultConfigurationName = Release;
347 | };
348 | /* End XCConfigurationList section */
349 |
350 | /* Begin XCSwiftPackageProductDependency section */
351 | C37E67102BBCA0D00057DAFC /* Images */ = {
352 | isa = XCSwiftPackageProductDependency;
353 | productName = Images;
354 | };
355 | /* End XCSwiftPackageProductDependency section */
356 | };
357 | rootObject = C3F03CBD28E37B90004CFE58 /* Project object */;
358 | }
359 |
--------------------------------------------------------------------------------
/Examples/SPMPlugin/SwiftGen/assets.stencil:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | {% if catalogs %}
5 | {% set enumName %}{{param.enumName|default:"Asset"}}{% endset %}
6 | {% set arResourceGroupType %}{{param.arResourceGroupTypeName|default:"ARResourceGroupAsset"}}{% endset %}
7 | {% set colorType %}{{param.colorTypeName|default:"ColorAsset"}}{% endset %}
8 | {% set dataType %}{{param.dataTypeName|default:"DataAsset"}}{% endset %}
9 | {% set imageType %}{{param.imageTypeName|default:"ImageAsset"}}{% endset %}
10 | {% set symbolType %}{{param.symbolTypeName|default:"SymbolAsset"}}{% endset %}
11 | {% set forceNamespaces %}{{param.forceProvidesNamespaces|default:"false"}}{% endset %}
12 | {% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
13 | #if os(macOS)
14 | import AppKit
15 | #elseif os(iOS)
16 | {% if resourceCount.arresourcegroup > 0 %}
17 | import ARKit
18 | {% endif %}
19 | import SwiftUI
20 | #elseif os(tvOS) || os(watchOS)
21 | import UIKit
22 | #endif
23 |
24 | // Deprecated typealiases
25 | {% if resourceCount.color > 0 %}
26 | @available(*, deprecated, renamed: "{{colorType}}.Color", message: "This typealias will be removed in SwiftGen 7.0")
27 | {{accessModifier}} typealias {{param.colorAliasName|default:"AssetColorTypeAlias"}} = {{colorType}}.Color
28 | {% endif %}
29 | {% if resourceCount.image > 0 %}
30 | @available(*, deprecated, renamed: "{{imageType}}.Image", message: "This typealias will be removed in SwiftGen 7.0")
31 | {{accessModifier}} typealias {{param.imageAliasName|default:"AssetImageTypeAlias"}} = {{imageType}}.Image
32 | {% endif %}
33 |
34 | // swiftlint:disable superfluous_disable_command file_length implicit_return
35 |
36 | // MARK: - Asset Catalogs
37 |
38 | {% macro enumBlock assets %}
39 | {% call casesBlock assets %}
40 | {% if param.allValues %}
41 |
42 | // swiftlint:disable trailing_comma
43 | {% if resourceCount.arresourcegroup > 0 %}
44 | {{accessModifier}} static let allResourceGroups: [{{arResourceGroupType}}] = [
45 | {% filter indent:2 %}{% call allValuesBlock assets "arresourcegroup" "" %}{% endfilter %}
46 | ]
47 | {% endif %}
48 | {% if resourceCount.color > 0 %}
49 | {{accessModifier}} static let allColors: [{{colorType}}] = [
50 | {% filter indent:2 %}{% call allValuesBlock assets "color" "" %}{% endfilter %}
51 | ]
52 | {% endif %}
53 | {% if resourceCount.data > 0 %}
54 | {{accessModifier}} static let allDataAssets: [{{dataType}}] = [
55 | {% filter indent:2 %}{% call allValuesBlock assets "data" "" %}{% endfilter %}
56 | ]
57 | {% endif %}
58 | {% if resourceCount.image > 0 %}
59 | {{accessModifier}} static let allImages: [{{imageType}}] = [
60 | {% filter indent:2 %}{% call allValuesBlock assets "image" "" %}{% endfilter %}
61 | ]
62 | {% endif %}
63 | {% if resourceCount.symbol > 0 %}
64 | {{accessModifier}} static let allSymbols: [{{symbolType}}] = [
65 | {% filter indent:2 %}{% call allValuesBlock assets "symbol" "" %}{% endfilter %}
66 | ]
67 | {% endif %}
68 | // swiftlint:enable trailing_comma
69 | {% endif %}
70 | {% endmacro %}
71 | {% macro casesBlock assets %}
72 | {% for asset in assets %}
73 | {% if asset.type == "arresourcegroup" %}
74 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{arResourceGroupType}}(name: "{{asset.value}}")
75 | {% elif asset.type == "color" %}
76 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{colorType}}(name: "{{asset.value}}")
77 | {% elif asset.type == "data" %}
78 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{dataType}}(name: "{{asset.value}}")
79 | {% elif asset.type == "image" %}
80 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{imageType}}(name: "{{asset.value}}")
81 | {% elif asset.type == "symbol" %}
82 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{symbolType}}(name: "{{asset.value}}")
83 | {% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
84 | {{accessModifier}} enum {{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
85 | {% filter indent:2 %}{% call casesBlock asset.items %}{% endfilter %}
86 | }
87 | {% elif asset.items %}
88 | {% call casesBlock asset.items %}
89 | {% endif %}
90 | {% endfor %}
91 | {% endmacro %}
92 | {% macro allValuesBlock assets filter prefix %}
93 | {% for asset in assets %}
94 | {% if asset.type == filter %}
95 | {{prefix}}{{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}},
96 | {% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
97 | {% set prefix2 %}{{prefix}}{{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.{% endset %}
98 | {% call allValuesBlock asset.items filter prefix2 %}
99 | {% elif asset.items %}
100 | {% call allValuesBlock asset.items filter prefix %}
101 | {% endif %}
102 | {% endfor %}
103 | {% endmacro %}
104 | // swiftlint:disable identifier_name line_length nesting type_body_length type_name
105 | {{accessModifier}} enum {{enumName}} {
106 | {% if catalogs.count > 1 or param.forceFileNameEnum %}
107 | {% for catalog in catalogs %}
108 | {{accessModifier}} enum {{catalog.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
109 | {% filter indent:2 %}{% call enumBlock catalog.assets %}{% endfilter %}
110 | }
111 | {% endfor %}
112 | {% else %}
113 | {% call enumBlock catalogs.first.assets %}
114 | {% endif %}
115 | }
116 | // swiftlint:enable identifier_name line_length nesting type_body_length type_name
117 |
118 | // MARK: - Implementation Details
119 | {% if resourceCount.arresourcegroup > 0 %}
120 |
121 | {{accessModifier}} struct {{arResourceGroupType}} {
122 | {{accessModifier}} fileprivate(set) var name: String
123 |
124 | #if os(iOS)
125 | @available(iOS 11.3, *)
126 | {{accessModifier}} var referenceImages: Set {
127 | return ARReferenceImage.referenceImages(in: self)
128 | }
129 |
130 | @available(iOS 12.0, *)
131 | {{accessModifier}} var referenceObjects: Set {
132 | return ARReferenceObject.referenceObjects(in: self)
133 | }
134 | #endif
135 | }
136 |
137 | #if os(iOS)
138 | @available(iOS 11.3, *)
139 | {{accessModifier}} extension ARReferenceImage {
140 | static func referenceImages(in asset: {{arResourceGroupType}}) -> Set {
141 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
142 | return referenceImages(inGroupNamed: asset.name, bundle: bundle) ?? Set()
143 | }
144 | }
145 |
146 | @available(iOS 12.0, *)
147 | {{accessModifier}} extension ARReferenceObject {
148 | static func referenceObjects(in asset: {{arResourceGroupType}}) -> Set {
149 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
150 | return referenceObjects(inGroupNamed: asset.name, bundle: bundle) ?? Set()
151 | }
152 | }
153 | #endif
154 | {% endif %}
155 | {% if resourceCount.color > 0 %}
156 |
157 | {{accessModifier}} final class {{colorType}} {
158 | {{accessModifier}} fileprivate(set) var name: String
159 |
160 | #if os(macOS)
161 | {{accessModifier}} typealias Color = NSColor
162 | #elseif os(iOS) || os(tvOS) || os(watchOS)
163 | {{accessModifier}} typealias Color = SwiftUI.Color
164 | {{accessModifier}} typealias UIColor = UIKit.UIColor
165 | #endif
166 |
167 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
168 | {{accessModifier}} private(set) lazy var color: Color = {
169 | guard let color = Color(asset: self) else {
170 | fatalError("Unable to load color asset named \(name).")
171 | }
172 | return color
173 | }()
174 |
175 | {{accessModifier}} private(set) lazy var uiColor: UIColor = {
176 | guard let color = UIColor(asset: self) else {
177 | fatalError("Unable to load color asset named \(name).")
178 | }
179 | return color
180 | }()
181 | /*
182 | #if os(iOS) || os(tvOS)
183 | @available(iOS 11.0, tvOS 11.0, *)
184 | {{accessModifier}} func color(compatibleWith traitCollection: UITraitCollection) -> Color {
185 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
186 | guard let color = Color(named: name, bundle: bundle, compatibleWith: traitCollection) else {
187 | fatalError("Unable to load color asset named \(name).")
188 | }
189 | return color
190 | }
191 | #endif
192 | */
193 |
194 | fileprivate init(name: String) {
195 | self.name = name
196 | }
197 | }
198 |
199 | {{accessModifier}} extension {{colorType}}.Color {
200 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
201 | init?(asset: {{colorType}}) {
202 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
203 | #if os(iOS) || os(tvOS)
204 | self.init(asset.name, bundle: bundle)
205 | #elseif os(macOS)
206 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
207 | #elseif os(watchOS)
208 | self.init(named: asset.name)
209 | #endif
210 | }
211 | }
212 | {{accessModifier}} extension {{colorType}}.UIColor {
213 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
214 | convenience init?(asset: {{colorType}}) {
215 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
216 | #if os(iOS) || os(tvOS)
217 | self.init(named: asset.name, in: bundle, compatibleWith: nil)
218 | #elseif os(macOS)
219 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
220 | #elseif os(watchOS)
221 | self.init(named: asset.name)
222 | #endif
223 | }
224 | }
225 | {% endif %}
226 | {% if resourceCount.data > 0 %}
227 |
228 | {{accessModifier}} struct {{dataType}} {
229 | {{accessModifier}} fileprivate(set) var name: String
230 |
231 | @available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
232 | {{accessModifier}} var data: NSDataAsset {
233 | guard let data = NSDataAsset(asset: self) else {
234 | fatalError("Unable to load data asset named \(name).")
235 | }
236 | return data
237 | }
238 | }
239 |
240 | @available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
241 | {{accessModifier}} extension NSDataAsset {
242 | convenience init?(asset: {{dataType}}) {
243 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
244 | #if os(iOS) || os(tvOS) || os(watchOS)
245 | self.init(name: asset.name, bundle: bundle)
246 | #elseif os(macOS)
247 | self.init(name: NSDataAsset.Name(asset.name), bundle: bundle)
248 | #endif
249 | }
250 | }
251 | {% endif %}
252 | {% if resourceCount.image > 0 %}
253 |
254 | {{accessModifier}} struct {{imageType}} {
255 | {{accessModifier}} fileprivate(set) var name: String
256 |
257 | #if os(macOS)
258 | {{accessModifier}} typealias Image = NSImage
259 | #elseif os(iOS) || os(tvOS) || os(watchOS)
260 | {{accessModifier}} typealias Image = SwiftUI.Image
261 | #endif
262 |
263 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
264 | {{accessModifier}} var image: Image {
265 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
266 | #if os(iOS) || os(tvOS)
267 | let image = Image(name, bundle: bundle)
268 | #elseif os(macOS)
269 | let name = NSImage.Name(self.name)
270 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
271 | #elseif os(watchOS)
272 | let image = Image(named: name)
273 | #endif
274 | //guard let result = image else {
275 | // fatalError("Unable to load image asset named \(name).")
276 | //}
277 | return image
278 | }
279 |
280 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
281 | {{accessModifier}} var uiImage: UIImage {
282 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
283 | #if os(iOS) || os(tvOS)
284 | let image = UIImage(named: name, in: bundle, compatibleWith: nil)
285 | #elseif os(macOS)
286 | let name = NSImage.Name(self.name)
287 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
288 | #elseif os(watchOS)
289 | let image = Image(named: name)
290 | #endif
291 | guard let image = image else {
292 | fatalError("Unable to load image asset named \(name).")
293 | }
294 | return image
295 | }
296 | /*
297 | #if os(iOS) || os(tvOS)
298 | @available(iOS 8.0, tvOS 9.0, *)
299 | {{accessModifier}} func image(compatibleWith traitCollection: UITraitCollection) -> Image {
300 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
301 | guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
302 | fatalError("Unable to load image asset named \(name).")
303 | }
304 | return result
305 | }
306 | #endif
307 | */
308 | }
309 |
310 | {{accessModifier}} extension {{imageType}}.Image {
311 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
312 | @available(macOS, deprecated,
313 | message: "This initializer is unsafe on macOS, please use the {{imageType}}.image property")
314 | init?(asset: {{imageType}}) {
315 | #if os(iOS) || os(tvOS)
316 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
317 | self.init(asset.name, bundle: bundle)
318 | #elseif os(macOS)
319 | self.init(named: NSImage.Name(asset.name))
320 | #elseif os(watchOS)
321 | self.init(named: asset.name)
322 | #endif
323 | }
324 | }
325 | {% endif %}
326 | {% if resourceCount.symbol > 0 %}
327 |
328 | {{accessModifier}} struct {{symbolType}} {
329 | {{accessModifier}} fileprivate(set) var name: String
330 |
331 | #if os(iOS) || os(tvOS) || os(watchOS)
332 | @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
333 | {{accessModifier}} typealias Configuration = SwiftUI.Image.SymbolConfiguration
334 | {{accessModifier}} typealias Image = SwiftUI.Image
335 |
336 | @available(iOS 12.0, tvOS 12.0, watchOS 5.0, *)
337 | {{accessModifier}} var image: Image {
338 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
339 | #if os(iOS) || os(tvOS)
340 | let image = Image(named: name, in: bundle, compatibleWith: nil)
341 | #elseif os(watchOS)
342 | let image = Image(named: name)
343 | #endif
344 | guard let result = image else {
345 | fatalError("Unable to load symbol asset named \(name).")
346 | }
347 | return result
348 | }
349 |
350 | @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
351 | {{accessModifier}} func image(with configuration: Configuration) -> Image {
352 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
353 | guard let result = Image(named: name, in: bundle, with: configuration) else {
354 | fatalError("Unable to load symbol asset named \(name).")
355 | }
356 | return result
357 | }
358 | #endif
359 | }
360 | {% endif %}
361 | {% if not param.bundle %}
362 |
363 | // swiftlint:disable convenience_type
364 | private final class BundleToken {
365 | static let bundle: Bundle = {
366 | #if SWIFT_PACKAGE
367 | return Bundle.module
368 | #else
369 | return Bundle(for: BundleToken.self)
370 | #endif
371 | }()
372 | }
373 | // swiftlint:enable convenience_type
374 | {% endif %}
375 | {% else %}
376 | // No assets found
377 | {% endif %}
378 |
379 |
--------------------------------------------------------------------------------
/Examples/SwiftScript/SwiftGen/assets.stencil:
--------------------------------------------------------------------------------
1 | // swiftlint:disable all
2 | // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
3 |
4 | {% if catalogs %}
5 | {% set enumName %}{{param.enumName|default:"Asset"}}{% endset %}
6 | {% set arResourceGroupType %}{{param.arResourceGroupTypeName|default:"ARResourceGroupAsset"}}{% endset %}
7 | {% set colorType %}{{param.colorTypeName|default:"ColorAsset"}}{% endset %}
8 | {% set dataType %}{{param.dataTypeName|default:"DataAsset"}}{% endset %}
9 | {% set imageType %}{{param.imageTypeName|default:"ImageAsset"}}{% endset %}
10 | {% set symbolType %}{{param.symbolTypeName|default:"SymbolAsset"}}{% endset %}
11 | {% set forceNamespaces %}{{param.forceProvidesNamespaces|default:"false"}}{% endset %}
12 | {% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
13 | #if os(macOS)
14 | import AppKit
15 | #elseif os(iOS)
16 | {% if resourceCount.arresourcegroup > 0 %}
17 | import ARKit
18 | {% endif %}
19 | import SwiftUI
20 | #elseif os(tvOS) || os(watchOS)
21 | import UIKit
22 | #endif
23 |
24 | // Deprecated typealiases
25 | {% if resourceCount.color > 0 %}
26 | @available(*, deprecated, renamed: "{{colorType}}.Color", message: "This typealias will be removed in SwiftGen 7.0")
27 | {{accessModifier}} typealias {{param.colorAliasName|default:"AssetColorTypeAlias"}} = {{colorType}}.Color
28 | {% endif %}
29 | {% if resourceCount.image > 0 %}
30 | @available(*, deprecated, renamed: "{{imageType}}.Image", message: "This typealias will be removed in SwiftGen 7.0")
31 | {{accessModifier}} typealias {{param.imageAliasName|default:"AssetImageTypeAlias"}} = {{imageType}}.Image
32 | {% endif %}
33 |
34 | // swiftlint:disable superfluous_disable_command file_length implicit_return
35 |
36 | // MARK: - Asset Catalogs
37 |
38 | {% macro enumBlock assets %}
39 | {% call casesBlock assets %}
40 | {% if param.allValues %}
41 |
42 | // swiftlint:disable trailing_comma
43 | {% if resourceCount.arresourcegroup > 0 %}
44 | {{accessModifier}} static let allResourceGroups: [{{arResourceGroupType}}] = [
45 | {% filter indent:2 %}{% call allValuesBlock assets "arresourcegroup" "" %}{% endfilter %}
46 | ]
47 | {% endif %}
48 | {% if resourceCount.color > 0 %}
49 | {{accessModifier}} static let allColors: [{{colorType}}] = [
50 | {% filter indent:2 %}{% call allValuesBlock assets "color" "" %}{% endfilter %}
51 | ]
52 | {% endif %}
53 | {% if resourceCount.data > 0 %}
54 | {{accessModifier}} static let allDataAssets: [{{dataType}}] = [
55 | {% filter indent:2 %}{% call allValuesBlock assets "data" "" %}{% endfilter %}
56 | ]
57 | {% endif %}
58 | {% if resourceCount.image > 0 %}
59 | {{accessModifier}} static let allImages: [{{imageType}}] = [
60 | {% filter indent:2 %}{% call allValuesBlock assets "image" "" %}{% endfilter %}
61 | ]
62 | {% endif %}
63 | {% if resourceCount.symbol > 0 %}
64 | {{accessModifier}} static let allSymbols: [{{symbolType}}] = [
65 | {% filter indent:2 %}{% call allValuesBlock assets "symbol" "" %}{% endfilter %}
66 | ]
67 | {% endif %}
68 | // swiftlint:enable trailing_comma
69 | {% endif %}
70 | {% endmacro %}
71 | {% macro casesBlock assets %}
72 | {% for asset in assets %}
73 | {% if asset.type == "arresourcegroup" %}
74 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{arResourceGroupType}}(name: "{{asset.value}}")
75 | {% elif asset.type == "color" %}
76 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{colorType}}(name: "{{asset.value}}")
77 | {% elif asset.type == "data" %}
78 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{dataType}}(name: "{{asset.value}}")
79 | {% elif asset.type == "image" %}
80 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{imageType}}(name: "{{asset.value}}")
81 | {% elif asset.type == "symbol" %}
82 | {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{symbolType}}(name: "{{asset.value}}")
83 | {% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
84 | {{accessModifier}} enum {{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
85 | {% filter indent:2 %}{% call casesBlock asset.items %}{% endfilter %}
86 | }
87 | {% elif asset.items %}
88 | {% call casesBlock asset.items %}
89 | {% endif %}
90 | {% endfor %}
91 | {% endmacro %}
92 | {% macro allValuesBlock assets filter prefix %}
93 | {% for asset in assets %}
94 | {% if asset.type == filter %}
95 | {{prefix}}{{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}},
96 | {% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
97 | {% set prefix2 %}{{prefix}}{{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.{% endset %}
98 | {% call allValuesBlock asset.items filter prefix2 %}
99 | {% elif asset.items %}
100 | {% call allValuesBlock asset.items filter prefix %}
101 | {% endif %}
102 | {% endfor %}
103 | {% endmacro %}
104 | // swiftlint:disable identifier_name line_length nesting type_body_length type_name
105 | {{accessModifier}} enum {{enumName}} {
106 | {% if catalogs.count > 1 or param.forceFileNameEnum %}
107 | {% for catalog in catalogs %}
108 | {{accessModifier}} enum {{catalog.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
109 | {% filter indent:2 %}{% call enumBlock catalog.assets %}{% endfilter %}
110 | }
111 | {% endfor %}
112 | {% else %}
113 | {% call enumBlock catalogs.first.assets %}
114 | {% endif %}
115 | }
116 | // swiftlint:enable identifier_name line_length nesting type_body_length type_name
117 |
118 | // MARK: - Implementation Details
119 | {% if resourceCount.arresourcegroup > 0 %}
120 |
121 | {{accessModifier}} struct {{arResourceGroupType}} {
122 | {{accessModifier}} fileprivate(set) var name: String
123 |
124 | #if os(iOS)
125 | @available(iOS 11.3, *)
126 | {{accessModifier}} var referenceImages: Set {
127 | return ARReferenceImage.referenceImages(in: self)
128 | }
129 |
130 | @available(iOS 12.0, *)
131 | {{accessModifier}} var referenceObjects: Set {
132 | return ARReferenceObject.referenceObjects(in: self)
133 | }
134 | #endif
135 | }
136 |
137 | #if os(iOS)
138 | @available(iOS 11.3, *)
139 | {{accessModifier}} extension ARReferenceImage {
140 | static func referenceImages(in asset: {{arResourceGroupType}}) -> Set {
141 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
142 | return referenceImages(inGroupNamed: asset.name, bundle: bundle) ?? Set()
143 | }
144 | }
145 |
146 | @available(iOS 12.0, *)
147 | {{accessModifier}} extension ARReferenceObject {
148 | static func referenceObjects(in asset: {{arResourceGroupType}}) -> Set {
149 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
150 | return referenceObjects(inGroupNamed: asset.name, bundle: bundle) ?? Set()
151 | }
152 | }
153 | #endif
154 | {% endif %}
155 | {% if resourceCount.color > 0 %}
156 |
157 | {{accessModifier}} final class {{colorType}} {
158 | {{accessModifier}} fileprivate(set) var name: String
159 |
160 | #if os(macOS)
161 | {{accessModifier}} typealias Color = NSColor
162 | #elseif os(iOS) || os(tvOS) || os(watchOS)
163 | {{accessModifier}} typealias Color = SwiftUI.Color
164 | {{accessModifier}} typealias UIColor = UIKit.UIColor
165 | #endif
166 |
167 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
168 | {{accessModifier}} private(set) lazy var color: Color = {
169 | guard let color = Color(asset: self) else {
170 | fatalError("Unable to load color asset named \(name).")
171 | }
172 | return color
173 | }()
174 |
175 | {{accessModifier}} private(set) lazy var uiColor: UIColor = {
176 | guard let color = UIColor(asset: self) else {
177 | fatalError("Unable to load color asset named \(name).")
178 | }
179 | return color
180 | }()
181 | /*
182 | #if os(iOS) || os(tvOS)
183 | @available(iOS 11.0, tvOS 11.0, *)
184 | {{accessModifier}} func color(compatibleWith traitCollection: UITraitCollection) -> Color {
185 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
186 | guard let color = Color(named: name, bundle: bundle, compatibleWith: traitCollection) else {
187 | fatalError("Unable to load color asset named \(name).")
188 | }
189 | return color
190 | }
191 | #endif
192 | */
193 |
194 | fileprivate init(name: String) {
195 | self.name = name
196 | }
197 | }
198 |
199 | {{accessModifier}} extension {{colorType}}.Color {
200 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
201 | init?(asset: {{colorType}}) {
202 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
203 | #if os(iOS) || os(tvOS)
204 | self.init(asset.name, bundle: bundle)
205 | #elseif os(macOS)
206 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
207 | #elseif os(watchOS)
208 | self.init(named: asset.name)
209 | #endif
210 | }
211 | }
212 | {{accessModifier}} extension {{colorType}}.UIColor {
213 | @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
214 | convenience init?(asset: {{colorType}}) {
215 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
216 | #if os(iOS) || os(tvOS)
217 | self.init(named: asset.name, in: bundle, compatibleWith: nil)
218 | #elseif os(macOS)
219 | self.init(named: NSColor.Name(asset.name), bundle: bundle)
220 | #elseif os(watchOS)
221 | self.init(named: asset.name)
222 | #endif
223 | }
224 | }
225 | {% endif %}
226 | {% if resourceCount.data > 0 %}
227 |
228 | {{accessModifier}} struct {{dataType}} {
229 | {{accessModifier}} fileprivate(set) var name: String
230 |
231 | @available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
232 | {{accessModifier}} var data: NSDataAsset {
233 | guard let data = NSDataAsset(asset: self) else {
234 | fatalError("Unable to load data asset named \(name).")
235 | }
236 | return data
237 | }
238 | }
239 |
240 | @available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
241 | {{accessModifier}} extension NSDataAsset {
242 | convenience init?(asset: {{dataType}}) {
243 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
244 | #if os(iOS) || os(tvOS) || os(watchOS)
245 | self.init(name: asset.name, bundle: bundle)
246 | #elseif os(macOS)
247 | self.init(name: NSDataAsset.Name(asset.name), bundle: bundle)
248 | #endif
249 | }
250 | }
251 | {% endif %}
252 | {% if resourceCount.image > 0 %}
253 |
254 | {{accessModifier}} struct {{imageType}} {
255 | {{accessModifier}} fileprivate(set) var name: String
256 |
257 | #if os(macOS)
258 | {{accessModifier}} typealias Image = NSImage
259 | #elseif os(iOS) || os(tvOS) || os(watchOS)
260 | {{accessModifier}} typealias Image = SwiftUI.Image
261 | #endif
262 |
263 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
264 | {{accessModifier}} var image: Image {
265 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
266 | #if os(iOS) || os(tvOS)
267 | let image = Image(name, bundle: bundle)
268 | #elseif os(macOS)
269 | let name = NSImage.Name(self.name)
270 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
271 | #elseif os(watchOS)
272 | let image = Image(named: name)
273 | #endif
274 | //guard let result = image else {
275 | // fatalError("Unable to load image asset named \(name).")
276 | //}
277 | return image
278 | }
279 |
280 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
281 | {{accessModifier}} var uiImage: UIImage {
282 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
283 | #if os(iOS) || os(tvOS)
284 | let image = UIImage(named: name, in: bundle, compatibleWith: nil)
285 | #elseif os(macOS)
286 | let name = NSImage.Name(self.name)
287 | let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
288 | #elseif os(watchOS)
289 | let image = Image(named: name)
290 | #endif
291 | guard let image = image else {
292 | fatalError("Unable to load image asset named \(name).")
293 | }
294 | return image
295 | }
296 | /*
297 | #if os(iOS) || os(tvOS)
298 | @available(iOS 8.0, tvOS 9.0, *)
299 | {{accessModifier}} func image(compatibleWith traitCollection: UITraitCollection) -> Image {
300 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
301 | guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
302 | fatalError("Unable to load image asset named \(name).")
303 | }
304 | return result
305 | }
306 | #endif
307 | */
308 | }
309 |
310 | {{accessModifier}} extension {{imageType}}.Image {
311 | @available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
312 | @available(macOS, deprecated,
313 | message: "This initializer is unsafe on macOS, please use the {{imageType}}.image property")
314 | init?(asset: {{imageType}}) {
315 | #if os(iOS) || os(tvOS)
316 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
317 | self.init(asset.name, bundle: bundle)
318 | #elseif os(macOS)
319 | self.init(named: NSImage.Name(asset.name))
320 | #elseif os(watchOS)
321 | self.init(named: asset.name)
322 | #endif
323 | }
324 | }
325 | {% endif %}
326 | {% if resourceCount.symbol > 0 %}
327 |
328 | {{accessModifier}} struct {{symbolType}} {
329 | {{accessModifier}} fileprivate(set) var name: String
330 |
331 | #if os(iOS) || os(tvOS) || os(watchOS)
332 | @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
333 | {{accessModifier}} typealias Configuration = SwiftUI.Image.SymbolConfiguration
334 | {{accessModifier}} typealias Image = SwiftUI.Image
335 |
336 | @available(iOS 12.0, tvOS 12.0, watchOS 5.0, *)
337 | {{accessModifier}} var image: Image {
338 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
339 | #if os(iOS) || os(tvOS)
340 | let image = Image(named: name, in: bundle, compatibleWith: nil)
341 | #elseif os(watchOS)
342 | let image = Image(named: name)
343 | #endif
344 | guard let result = image else {
345 | fatalError("Unable to load symbol asset named \(name).")
346 | }
347 | return result
348 | }
349 |
350 | @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
351 | {{accessModifier}} func image(with configuration: Configuration) -> Image {
352 | let bundle = {{param.bundle|default:"BundleToken.bundle"}}
353 | guard let result = Image(named: name, in: bundle, with: configuration) else {
354 | fatalError("Unable to load symbol asset named \(name).")
355 | }
356 | return result
357 | }
358 | #endif
359 | }
360 | {% endif %}
361 | {% if not param.bundle %}
362 |
363 | // swiftlint:disable convenience_type
364 | private final class BundleToken {
365 | static let bundle: Bundle = {
366 | #if SWIFT_PACKAGE
367 | return Bundle.module
368 | #else
369 | return Bundle(for: BundleToken.self)
370 | #endif
371 | }()
372 | }
373 | // swiftlint:enable convenience_type
374 | {% endif %}
375 | {% else %}
376 | // No assets found
377 | {% endif %}
378 |
379 |
--------------------------------------------------------------------------------
/Sources/ImagelinterExec/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | //
4 | //
5 | // Created by Sergey Balalaev on 02.04.2024.
6 | //
7 |
8 | import Foundation
9 | import AppKit
10 |
11 | // MARK: begin of settings the script
12 |
13 | let settings = Settings()
14 |
15 | // MARK: end of settings the script
16 |
17 | let startDate = Date()
18 |
19 | let imageSetExtensions = settings.rastorExtensions.union(settings.vectorExtensions)
20 |
21 | struct RegexPattern {
22 | let pattern: NSRegularExpression
23 | let isSwiftGen: Bool
24 | }
25 | var sourcesRegex: [RegexPattern] = []
26 | var isSwiftGen = false
27 |
28 | private func addSourceRegexPattern(pattern: String, isSwiftGen: Bool) {
29 | guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
30 | printError(filePath: #file, message: "Not right pattern for regex: \(pattern)", line: #line)
31 | return
32 | }
33 | sourcesRegex.append(RegexPattern(pattern: regex, isSwiftGen: isSwiftGen))
34 | }
35 |
36 | for usingType in settings.usingTypes {
37 | switch usingType {
38 | case .custom(let pattern, let isSwiftGen):
39 | addSourceRegexPattern(pattern: pattern, isSwiftGen: isSwiftGen)
40 | case .swiftUI:
41 | addSourceRegexPattern(pattern: #"\bImage\(\s*"(.*)"\s*\)"#, isSwiftGen: false)
42 | case .uiKit:
43 | addSourceRegexPattern(pattern: #"\bUIImage\(\s*named:\s*"(.*)"\s*\)"#, isSwiftGen: false)
44 | case .uiKitLiteral:
45 | addSourceRegexPattern(pattern: ##"\#imageLiteral\(\s*resourceName:\s*"(.*)"\s*\)"##, isSwiftGen: false)
46 | case .swiftGen(let enumName):
47 | addSourceRegexPattern(pattern: enumName +
48 | #"\s*\.((?:\.*[A-Z]{1}[A-z0-9]*)*)\s*((?:\.*[a-z]{1}[A-z0-9]*))(?:\s*\.image|\s*\.uiImage|\s*\.name)"#, isSwiftGen: true)
49 | isSwiftGen = true
50 | }
51 | }
52 |
53 | let allImageScales = (1...3)
54 | var targetScales: Set = []
55 | for targetPlatform in settings.targetPlatforms {
56 | switch targetPlatform {
57 | case .iPadOS, .visionOS, .watchOS:
58 | targetScales.insert(2)
59 | case .iOS:
60 | targetScales.insert(2)
61 | targetScales.insert(3)
62 | case .macOS, .tvOS:
63 | targetScales.insert(1)
64 | targetScales.insert(2)
65 | }
66 | }
67 | if targetScales.count < 1 {
68 | print("\(CommandLine.arguments[0]):\(#line): error: targetPlatforms should have one or more values. It need for detect quality of images.")
69 | }
70 |
71 | // MARK: detection resources of images
72 |
73 |
74 |
75 | var warningsCount = 0
76 | var errorsCount = 0
77 |
78 | // MARK: start analyze
79 |
80 | if settings.isEnabled == false {
81 | print("\(CommandLine.arguments[0]):\(#line): warning: images checking cancelled")
82 | exit(000)
83 | }
84 |
85 | func printError(filePath: String, message: String,
86 | line: Int? = nil, isWarning: Bool = false) {
87 | var result = filePath
88 | if let line = line {
89 | result += ":\(line): "
90 | } else {
91 | result += ": "
92 | }
93 | result += isWarning ? "warning: " : "error: "
94 | print(result + message)
95 | if isWarning {
96 | warningsCount += 1
97 | } else {
98 | errorsCount += 1
99 | }
100 | }
101 |
102 | extension String {
103 | var linesCount: Int {
104 | return reduce(into: 1) { count, letter in
105 | if letter == "\n" { // This treats CRLF as one "letter", contrary to UnicodeScalars
106 | count += 1
107 | }
108 | }
109 | }
110 |
111 | var scale: Int? {
112 | guard (self as NSString).contains("x") else {
113 | return nil
114 | }
115 | return Int(dropLast(1))
116 | }
117 | }
118 |
119 | extension NSImage {
120 | var pixelSize: NSSize? {
121 | if let rep = representations.first {
122 | let size = NSSize(width: rep.pixelsWide, height: rep.pixelsHigh)
123 | return size
124 | }
125 | return nil
126 | }
127 | }
128 |
129 | extension CGImage {
130 | var png: Data? {
131 | guard let mutableData = CFDataCreateMutable(nil, 0),
132 | let destination = CGImageDestinationCreateWithData(mutableData, "public.png" as CFString, 1, nil) else { return nil }
133 | CGImageDestinationAddImage(destination, self, nil)
134 | guard CGImageDestinationFinalize(destination) else { return nil }
135 | return mutableData as Data
136 | }
137 | }
138 |
139 | func fileSize(fromPath path: String) -> UInt64 {
140 | let size: Any? = try? FileManager.default.attributesOfItem(atPath: path)[FileAttributeKey.size]
141 | guard let fileSize = size as? UInt64 else {
142 | printError(filePath: path, message: "Not read file size")
143 | return 0
144 | }
145 | return fileSize
146 | }
147 |
148 | func covertToString(fileSize: UInt64) -> String {
149 | ByteCountFormatter().string(fromByteCount: Int64(fileSize))
150 | }
151 |
152 | let pdfRasterPattern = #".*\/[Ii]mage.*"#
153 | let pdfRasterRegex = try? NSRegularExpression(pattern: pdfRasterPattern, options: [])
154 | let svgRasterPattern = #".* settings.maxVectorFileSize {
177 | printError(
178 | filePath: imageFilePath,
179 | message: "File size (\(covertToString(fileSize: fileSize))) of the image is very biggest. Max file size is \(covertToString(fileSize: settings.maxVectorFileSize)). Found for image '\(imageInfo.name)'"
180 | )
181 | }
182 |
183 | if settings.isCheckingPdfVector || settings.isCheckingSvgVector {
184 | if !FileManager.default.isReadableFile(atPath: imageFilePath) {
185 | printError(filePath: imageFilePath, message: "Can not read file with path: '\(imageFilePath)'")
186 | } else {
187 | do {
188 | let string = try String(contentsOfFile: imageFilePath, encoding: .isoLatin1)
189 |
190 | let range = NSRange(location: 0, length: string.count)
191 | if settings.isCheckingPdfVector, pdfRasterRegex?.firstMatch(in: string, options: [], range: range) != nil {
192 | printError(filePath: imageFilePath, message: "PDF File is not a pure vector. Found for image '\(imageInfo.name)'")
193 | }
194 | if settings.isCheckingSvgVector, svgRasterRegex?.firstMatch(in: string, options: [], range: range) != nil {
195 | printError(filePath: imageFilePath, message: "SVG File is not a pure vector. Found for image '\(imageInfo.name)'")
196 | }
197 | } catch let error {
198 | printError(filePath: imageFilePath, message: "Can not parse Vector file. Found for image '\(imageInfo.name)' with error: `\(error.localizedDescription)`")
199 | }
200 | }
201 | }
202 | } else if settings.rastorExtensions.contains(fileExtension) {
203 | if settings.isCheckingFileSize, fileSize > settings.maxRastorFileSize {
204 | printError(
205 | filePath: imageFilePath,
206 | message: "File size (\(covertToString(fileSize: fileSize))) of the image is very biggest. Max file size is \(covertToString(fileSize: settings.maxRastorFileSize)). Found for image '\(imageInfo.name)'"
207 | )
208 | }
209 | }
210 | }
211 | } else if imageFileName.hasSuffix(imagesetExtension) {
212 | let fileEnumerator = FileManager.default.enumerator(atPath: imageFilePath)
213 | var files: Set = []
214 | while let fileName = fileEnumerator?.nextObject() as? String {
215 | files.insert(fileName)
216 | }
217 | let name = ((imageFileName as NSString).lastPathComponent as NSString).deletingPathExtension
218 | if let content = load(AssetContents.self, dir: imagesPath, for: imageFileName) {
219 | let contentFileNames = Set(content.images.compactMap { $0.filename })
220 | if contentFileNames.isEmpty {
221 | printError(filePath: imageFileName, message: "Empty asset with name '\(name)'")
222 | }
223 | let notFoundFile = contentFileNames.subtracting(files)
224 | for file in notFoundFile {
225 | printError(filePath: imageFileName, message: "Not found file '\(file)' for Asset with name '\(name)'")
226 | }
227 | } else {
228 | printError(filePath: imageFileName, message: "Empty folder for Asset with name '\(name)'")
229 | }
230 | }
231 | }
232 | }
233 |
234 | // MARK: - detect unused Images
235 |
236 |
237 | var usedImages: [String] = []
238 | var usedImagesFromSwiftGen: [String] = []
239 | let resourcesRegex = try! NSRegularExpression(pattern: #"<\bimage name="(.[A-z0-9]*)""#, options: [])
240 |
241 | print("source folders: \(settings.relativeSourcePaths)")
242 | for relativeSourcePath in settings.relativeSourcePaths {
243 | let sourcePath = settings.dir + relativeSourcePath
244 | print("source path: \(sourcePath)")
245 | // Search all using
246 | let sourceFileEnumerator = FileManager.default.enumerator(atPath: sourcePath)
247 | while let sourceFileName = sourceFileEnumerator?.nextObject() as? String {
248 | let fileExtension = (sourceFileName as NSString).pathExtension.uppercased()
249 | let filePath = sourcePath + sourceFileName
250 | // checks the extension to source
251 | if settings.sourcesExtensions.contains(fileExtension) {
252 | if let string = try? String(contentsOfFile: filePath, encoding: .utf8) {
253 | let range = NSRange(location: 0, length: (string as NSString).length)
254 | sourcesRegex.forEach{ regex in
255 | regex.pattern.enumerateMatches(
256 | in: string,
257 | options: [],
258 | range: range) { result, _, _ in
259 | addUsedImage(from: string, result: result, path: filePath, isSwiftGen: regex.isSwiftGen)
260 | }
261 | }
262 | }
263 | } else if settings.resourcesExtensions.contains(fileExtension) { // checks the extension to resource
264 | if let string = try? String(contentsOfFile: filePath, encoding: .utf8) {
265 | let range = NSRange(location: 0, length: (string as NSString).length)
266 | resourcesRegex.enumerateMatches(in: string,
267 | options: [],
268 | range: range) { result, _, _ in
269 | addUsedImage(from: string, result: result, path: filePath)
270 | }
271 | }
272 | }
273 | }
274 | }
275 |
276 | func addUsedImage(from string: String, result: NSTextCheckingResult?, path: String, isSwiftGen: Bool = false) {
277 | guard let result = result, result.numberOfRanges > 0 else {
278 | return
279 | }
280 | // first range is matching, all next is groups
281 | let value = (1...result.numberOfRanges - 1).map { index in
282 | (string as NSString).substring(with: result.range(at: index))
283 | }.joined()
284 | var foundedImage: Any? = nil
285 | if isSwiftGen {
286 | usedImagesFromSwiftGen.append(value)
287 | foundedImage = foundedSwiftGenMirrorImages[value]
288 | } else {
289 | usedImages.append(value)
290 | foundedImage = foundedImages[value]
291 | }
292 |
293 | if foundedImage == nil, settings.ignoredUndefinedImages.contains(value) == false {
294 | let line = (string as NSString).substring(with: NSRange(location: 0, length: result.range(at: 0).location)).linesCount
295 |
296 | printError(filePath: path, message: "Not found image with name '\(value)'", line: line)
297 | }
298 | }
299 |
300 | let standartUnusedImages = Set(foundedImages.keys).subtracting(usedImages).subtracting(settings.ignoredUnusedImages)
301 | let swiftGenUnusedImages = Set(foundedSwiftGenMirrorImages.keys).subtracting(usedImagesFromSwiftGen).subtracting(settings.ignoredUnusedImages)
302 | let unusedImages = Set(standartUnusedImages).intersection(swiftGenUnusedImages.compactMap {foundedSwiftGenMirrorImages[$0]} )
303 |
304 | for unusedImage in unusedImages {
305 | if let imageInfo = foundedImages[unusedImage] {
306 | imageInfo.error(with: "File unused from code. Found for image '\(imageInfo.name)'")
307 | }
308 | }
309 |
310 | let images: [ImageInfo] = foundedImages.values.map { $0 }
311 | for imageInfo in images {
312 | if settings.isCheckingDuplicatedByName {
313 | imageInfo.checkDuplicateByName()
314 | }
315 | if settings.isCheckingScaleSize {
316 | imageInfo.checkImageSizeAndDetectType()
317 | }
318 | if settings.isCheckingDuplicatedByContent {
319 | if let data = imageInfo.calculateData() {
320 | imageInfo.hash = "\(data.count)"
321 | }
322 | }
323 | }
324 |
325 | if settings.isCheckingDuplicatedByContent {
326 | for (index, imageInfo1) in images.enumerated() {
327 | for i in index + 1.. 0 {
347 | exit(1)
348 | }
349 |
--------------------------------------------------------------------------------
/Scripts/build.sh:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # build.sh
4 | # version 2.4.2
5 | #
6 | # Created by Sergey Balalaev on 20.08.15.
7 | # Copyright (c) 2015-2023 ByteriX. All rights reserved.
8 | #
9 |
10 | PROJECT_NAME=""
11 | CONFIGURATION_NAME="Release"
12 | SCHEME_NAME=""
13 | SETUP_VERSION=auto
14 | IS_PODS_INIT=false
15 | IS_TAG_VERSION=false
16 | HAS_BITCODE=false
17 | HAS_TESTING=false
18 | HAS_IPA_BUILD=true
19 | IS_APP_STORE=false
20 | OUTPUT_NAME=""
21 | TEAM_ID=""
22 | TEST_DESTINATION="platform=iOS Simulator,name=iPhone 13,OS=15.0"
23 | TEST_PLAN=""
24 | SRC_DIR="${PWD}"
25 |
26 | EXPORT_PLIST=""
27 | PROVISIONING_PROFILE="" #reserver
28 |
29 | USERNAME=""
30 | PASSWORD=""
31 | API_KEY=""
32 | API_ISSUER=""
33 | AUTH_KEY=""
34 |
35 | GOOGLE_SERVICE_PLIST=""
36 |
37 | # get parameters of script
38 |
39 | POSITIONAL=()
40 |
41 | #if [ "$#" -le 3 ] && [ "$1" != "-h" ]; then
42 | # echo -e '\nSomething is missing... Type "./build -h" without the quotes to find out more...\n'
43 | # exit 0
44 | #fi
45 |
46 | while [[ $# -gt 0 ]]
47 | do
48 | key="$1"
49 |
50 | case $key in
51 | -p|--project)
52 | PROJECT_NAME="$2"
53 | shift # past argument
54 | shift # past value
55 | ;;
56 | -c|--configuration)
57 | CONFIGURATION_NAME="$2"
58 | shift # past argument
59 | shift # past value
60 | ;;
61 | -s|--scheme)
62 | SCHEME_NAME="$2"
63 | shift # past argument
64 | shift # past value
65 | ;;
66 | -u|--user)
67 | USERNAME="$2"
68 | PASSWORD="$3"
69 | if [ "$PASSWORD" == "" ]; then
70 | echo "ERROR: $1 need 2 parameters"
71 | exit
72 | fi
73 | IS_APP_STORE=true
74 | shift # past argument
75 | shift # past value 1
76 | shift # past value 2
77 | ;;
78 | -key|--key)
79 | API_KEY="$2"
80 | API_ISSUER="$3"
81 | AUTH_KEY="$4"
82 | if [ "$AUTH_KEY" == "" ]; then
83 | echo "ERROR: $1 need 3 parameters"
84 | exit
85 | fi
86 | IS_APP_STORE=true
87 | shift # past argument
88 | shift # past value 1
89 | shift # past value 2
90 | shift # past value 3
91 | ;;
92 | -v|--version)
93 | SETUP_VERSION="$2"
94 | shift # past argument
95 | shift # past value
96 | ;;
97 | -o|--output)
98 | OUTPUT_NAME=$2
99 | shift # past argument
100 | shift # past value
101 | ;;
102 | -t|--team)
103 | TEAM_ID=$2
104 | shift # past argument
105 | shift # past value
106 | ;;
107 | -ep|--exportPlist)
108 | EXPORT_PLIST="$2"
109 | shift # past argument
110 | shift # past value
111 | ;;
112 | -gsp|--googlePlist)
113 | GOOGLE_SERVICE_PLIST=$2
114 | shift # past argument
115 | shift # past value
116 | ;;
117 | -ip|--initPods)
118 | IS_PODS_INIT=true
119 | shift # past argument
120 | ;;
121 | -at|--addTag)
122 | IS_TAG_VERSION=true
123 | shift # past argument
124 | ;;
125 | -bc|--bitcode)
126 | HAS_BITCODE=true
127 | shift # past argument
128 | ;;
129 | -test|--test)
130 | TEST_VALUE=""
131 | if [[ ! "$2" =~ ^- ]]; then
132 | TEST_DESTINATION="$2"
133 | TEST_VALUE="$2"
134 | fi
135 | HAS_TESTING=true
136 | HAS_IPA_BUILD=false
137 | shift # past argument
138 | if [ "$TEST_VALUE" != "" ]; then
139 | shift # past value
140 | fi
141 | ;;
142 | -tp|--testPlan)
143 | TEST_PLAN="$2"
144 | shift # past argument
145 | shift # past value
146 | ;;
147 | -h|--help)
148 | echo ""
149 | echo "Help for call build script with parameters:"
150 | echo " -p, --project : name of project or workspase. Requered param."
151 | echo " -c, --configuration : name of configuration. Default is Release."
152 | echo " -s, --scheme : name of target scheme. Default is the same as project name."
153 | echo " -u, --user : 2 params: login password. It specialized user, who created in Connection of developer programm. If defined then App will be uploaded to Store."
154 | echo " -key, --key : 3 params: apiKey, apiIssuer and path to key with p8. It specialized user, who created in Connection of developer programm. If defined then App will be uploaded to Store."
155 | echo " -v, --version : number of bundle version of the App. If has 'auto' value then will be detected from tags. Default auto."
156 | echo " -o, --output : name of out ipa file. Default is SchemeName.ipa."
157 | echo " -t, --team : team identifier of your developer program for a upload IPA to Connection AppSore. If defined -ep doesn't meater and export plist will created automaticle."
158 | echo " -ep, --exportPlist : export plist file. When team is empty has default value of AdHoc.plist or AppStore.plist when defined -t/--team."
159 | echo " -gsp, --googlePlist : path to GoogleService.plist with information for sending to Firebase/Crashlytics"
160 | echo " -ip, --initPods : If selected then will update Pods as is as from 'Pods.lock' in a start. Default is not selected."
161 | echo " -at, --addTag : If selected then will add Tag after build. Default is not selected."
162 | echo " -bc, --bitcode : If selected then will export with bitcode (when defined team). Default is not selected."
163 | echo " -test, --test : If selected then will build and run tests for special destination who you can choise. Default is not selected. Example of destination: 'platform=iOS Simulator,name=iPhone 12,OS=14.0'"
164 | echo " -tp, --testPlan : If selected then with -test will use selected test plane after that"
165 | echo ""
166 | echo "Emample: sh build.sh -p ProjectName -ip -t --version auto\n\n"
167 | exit 0
168 | ;;
169 | *)
170 | shift
171 | ;;
172 | esac
173 | done
174 | set -- "${POSITIONAL[@]}" # restore positional parameters
175 |
176 | # Common Settings
177 |
178 |
179 | # Initalize
180 |
181 | APP_BUILD_PATH="${SRC_DIR}/.build"
182 | BUILD_DIR="${APP_BUILD_PATH}/xcode"
183 | APP_CURRENT_BUILD_PATH="${APP_BUILD_PATH}/Current"
184 | APP_CONFIG_PATH="./build.config"
185 | BUILD_VERSION_TAG_GROUP_NAME="build"
186 | PROJECT_PLIST="${PROJECT_NAME}/Resources/Plists/Info.plist"
187 |
188 | # Setup skiped parameters init
189 |
190 | if [ "$PROJECT_NAME" == "" ]; then
191 | echo "ERROR: Expected project name from build parameters. Please read the help (call with -h or -help)."
192 | exit 1
193 | fi
194 | if [ "$SCHEME_NAME" == "" ]; then
195 | SCHEME_NAME=$PROJECT_NAME
196 | fi
197 | if [ "$OUTPUT_NAME" == "" ]; then
198 | OUTPUT_NAME="${SCHEME_NAME}"
199 | fi
200 | if [ "$EXPORT_PLIST" == "" ]; then
201 | if [ "$USERNAME" == "" ]; then
202 | EXPORT_PLIST="./AdHoc.plist"
203 | else
204 | EXPORT_PLIST="./AppStore.plist"
205 | fi
206 | fi
207 |
208 | if [ -f "${PROJECT_NAME}.xcworkspace/contents.xcworkspacedata" ]; then
209 | XCODE_PROJECT="-workspace ${PROJECT_NAME}.xcworkspace"
210 | echo "Using for workspace: ${XCODE_PROJECT}\n"
211 | else
212 | XCODE_PROJECT="-project ${PROJECT_NAME}.xcodeproj"
213 | echo "Start for project: ${XCODE_PROJECT}\n"
214 | fi
215 |
216 | # Setup version
217 |
218 | if [ "$SETUP_VERSION" == "auto" ]; then
219 | echo "Pulling all tags from remote"
220 | git fetch --tags --force
221 |
222 | # get templated version number as max from git tags:
223 | VERSION_TAG=$(git tag --list "${BUILD_VERSION_TAG_GROUP_NAME}/*" | awk "/$BUILD_VERSION_TAG_GROUP_NAME\/[0-9.]+$"'/{print $0}' | sed -n "s/$BUILD_VERSION_TAG_GROUP_NAME\/\(\S*\)/\1/p" | awk '{if(min==""){min=$1}; if(max==""){max=$1}; if($1>max) {max=$1}; if($1 "$APP_CONFIG_PATH"
234 | else
235 | echo "CURRENT_PROJECT_VERSION=$SETUP_VERSION" > "$APP_CONFIG_PATH"
236 | fi
237 |
238 | . "$APP_CONFIG_PATH"
239 |
240 | # Create execution
241 |
242 | checkExit(){
243 | if [ $? != 0 ]; then
244 | echo "Building failed\n"
245 | exit 1
246 | fi
247 | }
248 |
249 | # Functions
250 |
251 | clearCurrentBuild(){
252 | rm -rf "${BUILD_DIR}"
253 | rm -r -f -d "${APP_CURRENT_BUILD_PATH}"
254 | }
255 |
256 | createIPA()
257 | {
258 | local CONFIGURATION_NAME=$1
259 | local SCHEME_NAME=$2
260 | local EXPORT_PLIST=$3
261 | local PROVISIONING_PROFILE=$4
262 |
263 | local ACTION="clean archive"
264 | APP_DIR="${BUILD_DIR}/${CONFIGURATION_NAME}-iphoneos"
265 | APP="${APP_DIR}/${PROJECT_NAME}.app"
266 | ARCHIVE_PATH="${BUILD_DIR}/${SCHEME_NAME}.xcarchive"
267 |
268 | clearCurrentBuild
269 | mkdir -p "${APP_CURRENT_BUILD_PATH}"
270 |
271 | PROVISIONING_PROFILE_PARAMS=""
272 | if [ "${PROVISIONING_PROFILE}" != "" ]; then
273 | PROVISIONING_PROFILE_PARAMS="PROVISIONING_PROFILE=${PROVISIONING_PROFILE}"
274 | fi
275 |
276 | xcodebuild \
277 | -allowProvisioningUpdates \
278 | -configuration ${CONFIGURATION_NAME} $XCODE_PROJECT \
279 | -scheme ${SCHEME_NAME} \
280 | -sdk iphoneos \
281 | -xcconfig "${APP_CONFIG_PATH}" BUILD_DIR="${BUILD_DIR}" \
282 | -archivePath "${ARCHIVE_PATH}" $PROVISIONING_PROFILE_PARAMS $ACTION
283 |
284 | if [ TEAM_ID != "" ] ; then
285 | EXPORT_PLIST="${APP_CURRENT_BUILD_PATH}/Export.plist"
286 | echo "Creating export plist:"
287 | createExportPlist "${EXPORT_PLIST}"
288 | cat "$EXPORT_PLIST"
289 | checkExit
290 | echo "Export plist was created in ${EXPORT_PLIST}\n"
291 | fi
292 |
293 | checkExit
294 | echo "Creating .ipa for ${APP} ${APP_CURRENT_BUILD_PATH} ${SIGNING_IDENTITY} ${PROVISIONING_PROFILE}\n"
295 |
296 |
297 | xcodebuild \
298 | -allowProvisioningUpdates \
299 | -exportArchive \
300 | -archivePath "${ARCHIVE_PATH}" \
301 | -exportOptionsPlist "${EXPORT_PLIST}" \
302 | -exportPath "${APP_CURRENT_BUILD_PATH}"
303 |
304 | checkExit
305 | echo "Created .ipa for ${PROJECT_NAME}\n"
306 |
307 | if [ "$GOOGLE_SERVICE_PLIST" != "" ] ; then
308 | uploadSymbolesToFirebase
309 | fi
310 | }
311 |
312 | uploadSymbolesToFirebase(){
313 | echo "dSYMs files uploading to Firebase/Crashlytics"
314 | find "${APP_DIR}" -name "*.dSYM" | xargs -I \{\} echo \{\}
315 | find "${APP_DIR}" -name "*.dSYM" | xargs -I \{\} "${SRC_DIR}/Pods/FirebaseCrashlytics/upload-symbols" -gsp "${SRC_DIR}/${GOOGLE_SERVICE_PLIST}" -p ios \{\}
316 | checkExit
317 | echo "dSYMs uploaded to Firebase for ${PROJECT_NAME}\n"
318 | }
319 |
320 | tests(){
321 | local TEST_ADDITION=""
322 | local RESULT_PATH="${APP_BUILD_PATH}/tests"
323 | if [ "$TEST_PLAN" == "" ]; then
324 | echo "We have not test plan"
325 | else
326 | echo "We have test plan "$TEST_PLAN""
327 | TEST_ADDITION="-testPlan "$TEST_PLAN""
328 | fi
329 | rm -rf "${RESULT_PATH}"
330 | echo "Strarting Tests with distination: ${TEST_DESTINATION}\n\n"
331 | local ACTION="clean build test ${TEST_ADDITION}"
332 | xcodebuild \
333 | $ACTION \
334 | $XCODE_PROJECT \
335 | -scheme ${SCHEME_NAME} \
336 | -destination "${TEST_DESTINATION}" \
337 | -resultBundlePath "${RESULT_PATH}/${PROJECT_NAME}"
338 |
339 | checkExit
340 | echo "Tests finished for ${PROJECT_NAME}\n\n"
341 | }
342 |
343 | createIpaAndSave(){
344 | local CONFIGURATION_NAME=$1
345 | local SCHEME_NAME=$2
346 | local EXPORT_PLIST=$3
347 | local PROVISIONING_PROFILE=$4
348 |
349 | createIPA "${CONFIGURATION_NAME}" "${SCHEME_NAME}" "${EXPORT_PLIST}" "${PROVISIONING_PROFILE}"
350 |
351 | RESULT_DIR=${APP_BUILD_PATH}/${CONFIGURATION_NAME}
352 | IPA_FILES=( ${APP_CURRENT_BUILD_PATH}/*.ipa )
353 | IPA_FILE=${IPA_FILES[0]}
354 | echo "Found builded ipa file: ${IPA_FILE}"
355 | IPA_PATH="${RESULT_DIR}/${OUTPUT_NAME}.ipa"
356 |
357 | rm -f -d -r "${RESULT_DIR}"
358 | mkdir -p "${RESULT_DIR}"
359 | cp "${IPA_FILE}" "${IPA_PATH}"
360 |
361 | checkExit
362 |
363 | echo "IPA saved to ${IPA_PATH}"
364 | }
365 |
366 | tagCommit(){
367 | git tag -f -a "${BUILD_VERSION_TAG_GROUP_NAME}/${CURRENT_PROJECT_VERSION}" -m build
368 | git push -f --tags
369 | checkExit
370 | echo "Tag addition complete"
371 | }
372 |
373 | createExportPlist(){
374 | local EXPORT_PLIST=$1
375 |
376 | if $IS_APP_STORE ; then
377 | SIGNING_METHOD=app-store
378 | else
379 | SIGNING_METHOD=ad-hoc
380 | fi
381 |
382 | cat > $EXPORT_PLIST << EOL
383 |
384 |
385 |
386 |
387 | signingStyle
388 | automatic
389 | signingCertificate
390 | Apple Distribution
391 | method
392 | ${SIGNING_METHOD}
393 | teamID
394 | ${TEAM_ID}
395 | iCloudContainerEnvironment
396 | Production
397 | compileBitcode
398 | <${HAS_BITCODE}/>
399 |
400 |
401 | EOL
402 | }
403 |
404 | #reserved
405 | copyToDownload(){
406 | # create plist for download
407 | local VERSION_NAME=`plutil -p "${PROJECT_PLIST}" | grep "CFBundleShortVersionString.*$ApplicationVersionNumber"`
408 | local VERSION=$(echo $VERSION_NAME | grep -o '"[[:digit:].]*"' | sed 's/"//g')
409 |
410 | APP_PLIST_PATH="${RESULT_DIR}/${OUTPUT_NAME}.plist"
411 |
412 | sed "s/CURRENT_PROJECT_VERSION/${VERSION}/" build_result.plist > "${APP_PLIST_PATH}"
413 |
414 | checkExit
415 |
416 | local SERVER_PATH="${HOME}/Projects/vapor"
417 | local SERVER_DOWNLOAD_PATH="${SERVER_PATH}/Public/download"
418 |
419 | cp -f "${APP_CURRENT_BUILD_PATH}/${PROJECT_NAME}.plist" "${SERVER_DOWNLOAD_PATH}/${PROJECT_NAME}.plist"
420 | cp -f "${APP_CURRENT_BUILD_PATH}/${PROJECT_NAME}.ipa" "${SERVER_DOWNLOAD_PATH}/${PROJECT_NAME}.ipa"
421 | }
422 |
423 | podSetup(){
424 | if [ -f Podfile.lock ]; then
425 | rm -rf ~/Library/Caches/CocoaPods
426 | rm -rf Pods
427 | pod install --repo-update
428 | checkExit
429 | elif [ -f Podfile ]; then
430 | pod update
431 | checkExit
432 | fi
433 | }
434 |
435 | uploadToStoreUser(){
436 | xcrun altool --upload-app -f "${IPA_PATH}" -t "iOS" -u $USERNAME -p $PASSWORD
437 | checkExit
438 | echo "Application uploading finished with success"
439 | }
440 |
441 | uploadToStoreKey(){
442 | KEYS_DIR="${PWD}/private_keys"
443 | rm -rf "${KEYS_DIR}"
444 | mkdir -p "${KEYS_DIR}"
445 | cp -f "${AUTH_KEY}" "${KEYS_DIR}/AuthKey_${API_KEY}.p8"
446 | xcrun altool --upload-app -f "${IPA_PATH}" -t "iOS" --apiKey "${API_KEY}" --apiIssuer "${API_ISSUER}"
447 | checkExit
448 | echo "Application uploading finished with success"
449 | }
450 |
451 | if $IS_PODS_INIT ; then
452 | echo "Starting pod init:"
453 | podSetup
454 | checkExit
455 | fi
456 |
457 | # General part of building:
458 |
459 | echo "Starting build script with parameters:"
460 | echo "PROJECT_NAME = ${PROJECT_NAME}"
461 | echo "CONFIGURATION_NAME = ${CONFIGURATION_NAME}"
462 | echo "SCHEME_NAME = ${SCHEME_NAME}"
463 | echo "OUTPUT_NAME = ${OUTPUT_NAME}"
464 | cat "$APP_CONFIG_PATH"
465 |
466 | if $HAS_TESTING ; then
467 | tests
468 | fi
469 |
470 | if $HAS_IPA_BUILD ; then
471 | createIpaAndSave "${CONFIGURATION_NAME}" "${SCHEME_NAME}" "${EXPORT_PLIST}" "${PROVISIONING_PROFILE}"
472 | fi
473 |
474 | if [ "$USERNAME" != "" ] ; then
475 | echo ""
476 | echo "Starting upload to store:"
477 | echo "USERNAME = ${USERNAME}"
478 |
479 | uploadToStoreUser
480 | elif [ "$API_KEY" != "" ] ; then
481 | echo ""
482 | echo "Starting upload to store:"
483 | echo "API KEY = ${API_KEY}"
484 |
485 | uploadToStoreKey
486 | fi
487 |
488 | if $IS_TAG_VERSION ; then
489 | echo "Starting addition tag:"
490 | tagCommit
491 | fi
492 |
493 | clearCurrentBuild
494 |
--------------------------------------------------------------------------------
/Sources/ImagelinterExec/ImageInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageInfo.swift
3 | //
4 | //
5 | // Created by Sergey Balalaev on 03.04.2024.
6 | //
7 |
8 | import Foundation
9 | import AppKit
10 |
11 | struct AssetContents: Decodable {
12 | let images: [Image]
13 | struct Image: Decodable {
14 | let filename: String?
15 | let scale: String?
16 | }
17 | }
18 |
19 | struct FolderContents: Decodable {
20 | let properties: Properties?
21 | struct Properties: Decodable {
22 | let isNamespace: Bool
23 |
24 | enum CodingKeys: String, CodingKey {
25 | case isNamespace = "provides-namespace"
26 | }
27 | }
28 | }
29 |
30 | func load(_ type: T.Type, dir: String, for folder: String) -> T? {
31 | let contentsPath = dir + folder + "/Contents.json"
32 | guard let contentsData = NSData(contentsOfFile: contentsPath) as? Data else {
33 | return nil
34 | }
35 | return try? JSONDecoder().decode(type, from: contentsData)
36 | }
37 |
38 | let imagesetExtension = ".imageset"
39 | let appIconExtension = ".appiconset"
40 | let assetExtension = ".xcassets"
41 |
42 | class ImageInfo {
43 | struct File {
44 | // needs concatinate with ImageInfo.dir
45 | let path: String
46 | // if nil that vector-universal
47 | let scale: Int?
48 |
49 | init(path: String, scale: Int?) {
50 | self.path = path
51 | self.scale = scale
52 | }
53 | }
54 |
55 | enum ImageType {
56 | case undefined
57 | case vector
58 | case rastor
59 | case mixed
60 | }
61 |
62 | let name: String
63 | // dir for current Asset
64 | let dir: String
65 | var files: [File]
66 |
67 | var hash: String = ""
68 |
69 | var type: ImageType = .undefined
70 |
71 | private func setAndCheckType(newType: ImageType, filePath: String){
72 | if type != .undefined, newType != type {
73 | printError(
74 | filePath: filePath,
75 | message: "The image with name '\(name)' has different types of files: \(newType) and \(type)"
76 | )
77 | type = .mixed
78 | } else {
79 | type = newType
80 | }
81 | }
82 |
83 | private init(name: String, dir: String, path: String, scale: Int?) {
84 | self.name = name
85 | self.dir = dir
86 | files = [File(path: path, scale: scale)]
87 | }
88 |
89 | static func processFound(dir: String, path: String) -> ImageInfo? {
90 | var isAsset = false
91 | var folderName = ""
92 | let components = path.split(separator: "/")
93 | for (index, component) in components.enumerated() {
94 | if component.hasSuffix(assetExtension) {
95 | isAsset = true
96 | } else {
97 | if isAsset == false { // only for asset
98 | continue
99 | }
100 | if component.hasSuffix(imagesetExtension) { // it is asset
101 | let name = (component as NSString).substring(to: component.count - imagesetExtension.count)
102 | if let contents = load(AssetContents.self, dir: dir, for: components[0.. ImageInfo {
136 | if let existImage = foundedImages[name] {
137 | existImage.files.append(File(path: path, scale: scale))
138 | return existImage
139 | } else {
140 | let result = ImageInfo(name: name, dir: dir, path: path, scale: scale)
141 | foundedImages[name] = result
142 | if isSwiftGen {
143 | foundedSwiftGenMirrorImages[name.swiftGenKey()] = name
144 | }
145 | return result
146 | }
147 | }
148 |
149 | private static func nameOfImageFile(path: String) -> (path: String, scale: Int) {
150 | return pathOfImageFile(path: (path as NSString).lastPathComponent)
151 | }
152 |
153 | private static func pathOfImageFile(path: String) -> (path: String, scale: Int) {
154 | var name = (path as NSString).deletingPathExtension
155 | var scale = 1
156 | for imageScale in allImageScales {
157 | let scaleSuffix = "@\(imageScale)x"
158 | if name.hasSuffix(scaleSuffix) {
159 | name = String(name.dropLast(scaleSuffix.count))
160 | scale = imageScale
161 | break
162 | }
163 | }
164 | return (name, scale)
165 | }
166 |
167 | private static func isTheSameImage(path1: String, path2: String) -> Bool {
168 | pathOfImageFile(path: path1).path == pathOfImageFile(path: path2).path
169 | }
170 |
171 | private var assetPath: String? {
172 | var result: String?
173 | for imageFile in files {
174 | let components = imageFile.path.split(separator: "/")
175 | if components.isEmpty { // it just image
176 | return nil
177 | } else {
178 | for component in components {
179 | if component.hasSuffix(imagesetExtension) { // it is asset
180 | var name = (imageFile.path as NSString).components(separatedBy: imagesetExtension).first ?? ""
181 | name = name + imagesetExtension
182 | if let result = result {
183 | if name != result {
184 | return nil
185 | }
186 | } else {
187 | result = name
188 | }
189 | }
190 | }
191 | }
192 | }
193 | return result
194 | }
195 |
196 | func error(with message: String) {
197 | for file in files {
198 | let imageFilePath = dir + file.path
199 | printError(filePath: imageFilePath, message: message)
200 | guard settings.isAllFilesErrorShowing else {
201 | break
202 | }
203 | }
204 | }
205 |
206 | func checkDuplicateByName() {
207 | guard files.count > 1 else {
208 | return
209 | }
210 | if assetPath == nil {
211 | var isDifferentImages = false
212 | for file in files {
213 | if !Self.isTheSameImage(path1: files.first?.path ?? "", path2: file.path) {
214 | isDifferentImages = true
215 | break
216 | }
217 | }
218 | if isDifferentImages {
219 | error(with: "Duplicated image with name: '\(name)'")
220 | }
221 | }
222 | }
223 |
224 | private static let svgSearchWidthHeightRegex = try! NSRegularExpression(pattern: #""#, options: [])
225 | private static let svgSearchHeightWidthRegex = try! NSRegularExpression(pattern: #""#, options: [])
226 |
227 | func checkImageSizeAndDetectType() {
228 | var scaledSize: (width: Int, height: Int)?
229 | for file in files {
230 | let imageFilePath = dir + file.path
231 | if let image = NSImage(contentsOfFile: imageFilePath) {
232 | let pixelSize = image.pixelSize ?? NSSize()
233 | let size = image.size
234 | if pixelSize.height == 0, pixelSize.width == 0 {
235 | if size.height != 0, size.width != 0 {
236 | setAndCheckType(newType: .vector, filePath: imageFilePath)
237 | // it's okey just vector image
238 | // but can problems
239 | if let scale = file.scale {
240 | printError(
241 | filePath: imageFilePath,
242 | message: "It is vector image. But it has scale = \(scale). Found for image '\(name)'",
243 | isWarning: true
244 | )
245 | }
246 | if size.width > settings.maxVectorImageSize.width || size.height > settings.maxVectorImageSize.height {
247 | printError(
248 | filePath: imageFilePath,
249 | message: "The vector image has very biggest image size (\(size.width), \(size.height)). Max image size for vector is (\(settings.maxVectorImageSize.width), \(settings.maxVectorImageSize.height)). Found for image '\(name)'"
250 | )
251 | }
252 | } else {
253 | printError(filePath: imageFilePath, message: "Image has zero size. Found for image '\(name)'", isWarning: true)
254 | }
255 | } else {
256 | if let scale = file.scale {
257 | setAndCheckType(newType: .rastor, filePath: imageFilePath)
258 | if Int(pixelSize.width) % scale != 0 || Int(pixelSize.height) % scale != 0 {
259 | let newScaledSize: (width: Double, height: Double) = (Double(pixelSize.width) / Double(scale), Double(pixelSize.height) / Double(scale))
260 | printError(
261 | filePath: imageFilePath,
262 | message: "Image has floating size from scaled images. Real size is \(pixelSize) and scale = \(scale). Please check the file, it must have integer size after apply this scale. But you actually have \(newScaledSize). Found for image '\(name)'."
263 | )
264 | } else {
265 | let newScaledSize: (width: Int, height: Int) = (Int(pixelSize.width) / scale, Int(pixelSize.height) / scale)
266 | if let scaledSize = scaledSize {
267 | if scaledSize != newScaledSize {
268 | printError(
269 | filePath: imageFilePath,
270 | message: "Image has different size for scaled group. Real size is \(pixelSize) with scale = \(scale) but expected \(NSSize(width: scaledSize.0 * scale, height: scaledSize.1 * scale)). Found for image '\(name)'"
271 | )
272 | }
273 | } else {
274 | scaledSize = newScaledSize
275 | }
276 | if CGFloat(newScaledSize.width) > settings.maxRastorImageSize.width || CGFloat(newScaledSize.height) > settings.maxRastorImageSize.height{
277 | printError(
278 | filePath: imageFilePath,
279 | message: "The rastor image has very biggest image size (\(newScaledSize.width), \(newScaledSize.height)). Max image size for rastor is (\(settings.maxRastorImageSize.width), \(settings.maxRastorImageSize.height)). Found for image '\(name)'"
280 | )
281 | }
282 | }
283 | }
284 | }
285 | } else if imageFilePath.uppercased().hasSuffix("SVG") { // NSImage can not support SVG files. You can use only from Assets
286 | setAndCheckType(newType: .vector, filePath: imageFilePath)
287 | if let scale = file.scale {
288 | printError(
289 | filePath: imageFilePath,
290 | message: "It is vector image. But it has scale = \(scale). Found for image '\(name)'",
291 | isWarning: true
292 | )
293 | }
294 |
295 | // Need parse SVG and extract width / height for checking
296 | // examples:
297 | // vector: