bundo-appgen 0.0.1-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +253 -0
  2. package/bin.mjs +21 -0
  3. package/lib/bin/bin.mjs +1141 -0
  4. package/lib/bin/plugin-sandbox-runner.mjs +105 -0
  5. package/lib/commonjs/index.js +125 -0
  6. package/lib/module/chunk-bhc5nymd.js +12 -0
  7. package/lib/module/chunk-dvyy3g4j.js +25 -0
  8. package/lib/module/chunk-ynqw05p0.js +70 -0
  9. package/lib/module/config/apple/create-osx-appiconset.js +6 -0
  10. package/lib/module/config/apple/index.js +7 -0
  11. package/lib/module/config/index.js +8 -0
  12. package/lib/module/index.js +8 -0
  13. package/lib/typescript/config/apple/asset-catalog-format/app-icon/index.d.ts +3 -0
  14. package/lib/typescript/config/apple/asset-catalog-format/app-icon/index.d.ts.map +1 -0
  15. package/lib/typescript/config/apple/asset-catalog-format/app-icon/set-type.d.ts +42 -0
  16. package/lib/typescript/config/apple/asset-catalog-format/app-icon/set-type.d.ts.map +1 -0
  17. package/lib/typescript/config/apple/asset-catalog-format/app-icon/size.d.ts +21 -0
  18. package/lib/typescript/config/apple/asset-catalog-format/app-icon/size.d.ts.map +1 -0
  19. package/lib/typescript/config/apple/asset-catalog-format/appearances.d.ts +13 -0
  20. package/lib/typescript/config/apple/asset-catalog-format/appearances.d.ts.map +1 -0
  21. package/lib/typescript/config/apple/asset-catalog-format/idiom.d.ts +5 -0
  22. package/lib/typescript/config/apple/asset-catalog-format/idiom.d.ts.map +1 -0
  23. package/lib/typescript/config/apple/asset-catalog-format/image/color-space.d.ts +2 -0
  24. package/lib/typescript/config/apple/asset-catalog-format/image/color-space.d.ts.map +1 -0
  25. package/lib/typescript/config/apple/asset-catalog-format/image/compression-type.d.ts +2 -0
  26. package/lib/typescript/config/apple/asset-catalog-format/image/compression-type.d.ts.map +1 -0
  27. package/lib/typescript/config/apple/asset-catalog-format/image/display-gamut.d.ts +2 -0
  28. package/lib/typescript/config/apple/asset-catalog-format/image/display-gamut.d.ts.map +1 -0
  29. package/lib/typescript/config/apple/asset-catalog-format/image/index.d.ts +6 -0
  30. package/lib/typescript/config/apple/asset-catalog-format/image/index.d.ts.map +1 -0
  31. package/lib/typescript/config/apple/asset-catalog-format/image/language-direction.d.ts +2 -0
  32. package/lib/typescript/config/apple/asset-catalog-format/image/language-direction.d.ts.map +1 -0
  33. package/lib/typescript/config/apple/asset-catalog-format/image/scale.d.ts +9 -0
  34. package/lib/typescript/config/apple/asset-catalog-format/image/scale.d.ts.map +1 -0
  35. package/lib/typescript/config/apple/asset-catalog-format/image/set-type.d.ts +58 -0
  36. package/lib/typescript/config/apple/asset-catalog-format/image/set-type.d.ts.map +1 -0
  37. package/lib/typescript/config/apple/asset-catalog-format/index.d.ts +5 -0
  38. package/lib/typescript/config/apple/asset-catalog-format/index.d.ts.map +1 -0
  39. package/lib/typescript/config/apple/asset-catalogs-namespaced.d.ts +5 -0
  40. package/lib/typescript/config/apple/asset-catalogs-namespaced.d.ts.map +1 -0
  41. package/lib/typescript/config/apple/asset-catalogs.d.ts +73 -0
  42. package/lib/typescript/config/apple/asset-catalogs.d.ts.map +1 -0
  43. package/lib/typescript/config/apple/create-osx-appiconset.d.mts +72 -0
  44. package/lib/typescript/config/apple/create-osx-appiconset.d.mts.map +1 -0
  45. package/lib/typescript/config/apple/data.d.ts +103 -0
  46. package/lib/typescript/config/apple/data.d.ts.map +1 -0
  47. package/lib/typescript/config/apple/index.d.mts +8 -0
  48. package/lib/typescript/config/apple/index.d.mts.map +1 -0
  49. package/lib/typescript/config/apple/info-plist-value.d.ts +8 -0
  50. package/lib/typescript/config/apple/info-plist-value.d.ts.map +1 -0
  51. package/lib/typescript/config/apple/info-plist.d.ts +4 -0
  52. package/lib/typescript/config/apple/info-plist.d.ts.map +1 -0
  53. package/lib/typescript/config/apple/string-catalog.d.ts +2 -0
  54. package/lib/typescript/config/apple/string-catalog.d.ts.map +1 -0
  55. package/lib/typescript/config/data.d.ts +50 -0
  56. package/lib/typescript/config/data.d.ts.map +1 -0
  57. package/lib/typescript/config/index.d.mts +5 -0
  58. package/lib/typescript/config/index.d.mts.map +1 -0
  59. package/lib/typescript/config/plugin-item.d.ts +2 -0
  60. package/lib/typescript/config/plugin-item.d.ts.map +1 -0
  61. package/lib/typescript/config/plugin-registry.d.ts +3 -0
  62. package/lib/typescript/config/plugin-registry.d.ts.map +1 -0
  63. package/lib/typescript/index.d.mts +3 -0
  64. package/lib/typescript/index.d.mts.map +1 -0
  65. package/lib/typescript/plugin/apple/context.d.ts +28 -0
  66. package/lib/typescript/plugin/apple/context.d.ts.map +1 -0
  67. package/lib/typescript/plugin/apple/files.d.ts +7 -0
  68. package/lib/typescript/plugin/apple/files.d.ts.map +1 -0
  69. package/lib/typescript/plugin/apple/index.d.ts +6 -0
  70. package/lib/typescript/plugin/apple/index.d.ts.map +1 -0
  71. package/lib/typescript/plugin/apple/pod-spec-source-from-cocoapods.d.ts +5 -0
  72. package/lib/typescript/plugin/apple/pod-spec-source-from-cocoapods.d.ts.map +1 -0
  73. package/lib/typescript/plugin/apple/pod-spec-source-from-git.d.ts +11 -0
  74. package/lib/typescript/plugin/apple/pod-spec-source-from-git.d.ts.map +1 -0
  75. package/lib/typescript/plugin/apple/pod-spec-source-from-local.d.ts +7 -0
  76. package/lib/typescript/plugin/apple/pod-spec-source-from-local.d.ts.map +1 -0
  77. package/lib/typescript/plugin/context.d.ts +9 -0
  78. package/lib/typescript/plugin/context.d.ts.map +1 -0
  79. package/lib/typescript/plugin/index.d.ts +3 -0
  80. package/lib/typescript/plugin/index.d.ts.map +1 -0
  81. package/package.json +49 -0
  82. package/src/_bin/_global-vars/_global-vars.mts +47 -0
  83. package/src/_bin/_global-vars/index.mts +30 -0
  84. package/src/_bin/_main/_check-config-validity.mts +94 -0
  85. package/src/_bin/_main/_evaluate-plugin-registry.mts +181 -0
  86. package/src/_bin/_main/_exec-plugin-runner/_spawn-plugin-sandbox-runner.mts +149 -0
  87. package/src/_bin/_main/_exec-plugin-runner/exec-plugin-runner.mts +92 -0
  88. package/src/_bin/_main/_exec-plugin-runner/index.mts +1 -0
  89. package/src/_bin/_main/_get-config.mts +64 -0
  90. package/src/_bin/_main/_helpers/config/get-name.mts +24 -0
  91. package/src/_bin/_main/_helpers/config/get-project-name.mts +27 -0
  92. package/src/_bin/_main/_helpers/config/index.mts +2 -0
  93. package/src/_bin/_main/_helpers/index.mts +2 -0
  94. package/src/_bin/_main/_helpers/platform/compatibility-error.mts +7 -0
  95. package/src/_bin/_main/_helpers/platform/data.ts +9 -0
  96. package/src/_bin/_main/_helpers/platform/get-data.mts +48 -0
  97. package/src/_bin/_main/_helpers/platform/index.mts +4 -0
  98. package/src/_bin/_main/_helpers/platform/is-compatible.mts +30 -0
  99. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_init-appiconsets.mts +223 -0
  100. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_init-imagesets.mts +241 -0
  101. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_metadata-check/appearances.mts +24 -0
  102. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_metadata-check/idiom.mts +22 -0
  103. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_metadata-check/image/compression-type.mts +15 -0
  104. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_metadata-check/image/display-gamut.mts +12 -0
  105. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_metadata-check/image/index.mts +3 -0
  106. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_metadata-check/image/language-direction.mts +12 -0
  107. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/_metadata-check/index.mts +3 -0
  108. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/create-asset-catalogs.mts +54 -0
  109. package/src/_bin/_main/_init-template/_init-apple/_create-asset-catalogs/index.mts +1 -0
  110. package/src/_bin/_main/_init-template/_init-apple/_create-string-catalogs/create-string-catalog.mts +134 -0
  111. package/src/_bin/_main/_init-template/_init-apple/_create-string-catalogs/index.mts +1 -0
  112. package/src/_bin/_main/_init-template/_init-apple/_mod-files/_app-delegate-swift.mts +62 -0
  113. package/src/_bin/_main/_init-template/_init-apple/_mod-files/_podfile.mts +31 -0
  114. package/src/_bin/_main/_init-template/_init-apple/_mod-files/index.mts +1 -0
  115. package/src/_bin/_main/_init-template/_init-apple/_mod-files/mod-files.mts +17 -0
  116. package/src/_bin/_main/_init-template/_init-apple/index.mts +1 -0
  117. package/src/_bin/_main/_init-template/_init-apple/init-apple.mts +81 -0
  118. package/src/_bin/_main/_init-template/index.mts +1 -0
  119. package/src/_bin/_main/_init-template/init-template.mts +39 -0
  120. package/src/_bin/_main/_mod-plugin/index.mts +1 -0
  121. package/src/_bin/_main/_mod-plugin/mod-plugin.mts +77 -0
  122. package/src/_bin/_main/_xcodegen/_create-project-spec/_init-resources.mts +86 -0
  123. package/src/_bin/_main/_xcodegen/_create-project-spec/create-project-spec.mts +216 -0
  124. package/src/_bin/_main/_xcodegen/_create-project-spec/index.mts +1 -0
  125. package/src/_bin/_main/_xcodegen/_mod-known-regions/index.ts +1 -0
  126. package/src/_bin/_main/_xcodegen/_mod-known-regions/mod-known-regions.mts +52 -0
  127. package/src/_bin/_main/_xcodegen/index.mts +1 -0
  128. package/src/_bin/_main/_xcodegen/xcodegen.mts +46 -0
  129. package/src/_bin/_main/index.mts +1 -0
  130. package/src/_bin/_main/main.mts +160 -0
  131. package/src/_bin/bin.mts +68 -0
  132. package/src/_bin/plugin-sandbox-runner/_exec-plugins.mts +135 -0
  133. package/src/_bin/plugin-sandbox-runner/argv-json.ts +20 -0
  134. package/src/_bin/plugin-sandbox-runner/evaluated-plugin-registry.ts +12 -0
  135. package/src/_bin/plugin-sandbox-runner/index.ts +3 -0
  136. package/src/_bin/plugin-sandbox-runner/plugin-runner-context-result.ts +33 -0
  137. package/src/_bin/plugin-sandbox-runner/plugin-sandbox-runner.mts +68 -0
  138. package/src/config/apple/asset-catalog-format/app-icon/index.ts +2 -0
  139. package/src/config/apple/asset-catalog-format/app-icon/set-type.ts +59 -0
  140. package/src/config/apple/asset-catalog-format/app-icon/size.ts +37 -0
  141. package/src/config/apple/asset-catalog-format/appearances.ts +10 -0
  142. package/src/config/apple/asset-catalog-format/idiom.ts +16 -0
  143. package/src/config/apple/asset-catalog-format/image/color-space.ts +3 -0
  144. package/src/config/apple/asset-catalog-format/image/compression-type.ts +6 -0
  145. package/src/config/apple/asset-catalog-format/image/display-gamut.ts +3 -0
  146. package/src/config/apple/asset-catalog-format/image/index.ts +6 -0
  147. package/src/config/apple/asset-catalog-format/image/language-direction.ts +3 -0
  148. package/src/config/apple/asset-catalog-format/image/scale.ts +11 -0
  149. package/src/config/apple/asset-catalog-format/image/set-type.ts +85 -0
  150. package/src/config/apple/asset-catalog-format/index.ts +4 -0
  151. package/src/config/apple/asset-catalogs-namespaced.ts +13 -0
  152. package/src/config/apple/asset-catalogs.ts +76 -0
  153. package/src/config/apple/create-osx-appiconset.mts +135 -0
  154. package/src/config/apple/data.ts +123 -0
  155. package/src/config/apple/index.mts +7 -0
  156. package/src/config/apple/info-plist-value.ts +16 -0
  157. package/src/config/apple/info-plist.ts +6 -0
  158. package/src/config/apple/string-catalog.ts +0 -0
  159. package/src/config/data.ts +59 -0
  160. package/src/config/index.mts +4 -0
  161. package/src/config/plugin-item.ts +4 -0
  162. package/src/config/plugin-registry.ts +5 -0
  163. package/src/index.mts +2 -0
  164. package/src/plugin/apple/context.ts +68 -0
  165. package/src/plugin/apple/files.ts +14 -0
  166. package/src/plugin/apple/index.ts +5 -0
  167. package/src/plugin/apple/pod-spec-source-from-cocoapods.ts +9 -0
  168. package/src/plugin/apple/pod-spec-source-from-git.ts +13 -0
  169. package/src/plugin/apple/pod-spec-source-from-local.ts +6 -0
  170. package/src/plugin/context.ts +12 -0
  171. package/src/plugin/index.ts +2 -0
@@ -0,0 +1,48 @@
1
+ import {
2
+ CompatibilityError,
3
+ } from "./compatibility-error.mts"
4
+
5
+ import type {
6
+ Data,
7
+ } from "./data.ts"
8
+
9
+ import {
10
+ isCompatible,
11
+ } from "./is-compatible.mts"
12
+
13
+ let cache: Data
14
+
15
+ /**
16
+ * Throw error if this run in non compatible platform or non JavaScript development runtime.
17
+ */
18
+ export function getData(): Data {
19
+ if(cache) {
20
+ return cache
21
+ }
22
+
23
+ if(!isCompatible()) {
24
+ throw CompatibilityError
25
+ }
26
+
27
+ const isBun = typeof Bun !== "undefined" || !!process.versions.bun
28
+
29
+ let developmentRuntime: Data["developmentRuntime"]
30
+
31
+ if(isBun) {
32
+ developmentRuntime = {
33
+ type: "bun",
34
+ version: process.versions.bun,
35
+ }
36
+ } else {
37
+ developmentRuntime = {
38
+ type: "node",
39
+ version: process.versions.node,
40
+ }
41
+ }
42
+
43
+ cache = {
44
+ developmentRuntime,
45
+ }
46
+
47
+ return cache
48
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./compatibility-error.mts"
2
+ export * from "./get-data.mts"
3
+ export * from "./is-compatible.mts"
4
+ export type * from "./data.ts"
@@ -0,0 +1,30 @@
1
+ import {
2
+ GlobalVars,
3
+ } from "../../../_global-vars/index.mts"
4
+
5
+ /**
6
+ * This is a mono helper if the bundo runs for non compatible platform and JS development runtime.
7
+ */
8
+ export function isCompatible(): boolean {
9
+
10
+ const
11
+ /**
12
+ * We only support macOS and Windows for bundo-appgen,
13
+ * unless client is using the option `--force-cross-platform`.
14
+ */
15
+ supportdRNPlatforms: NodeJS.Platform[] =
16
+ [
17
+ "darwin",
18
+ "win32",
19
+ ],
20
+
21
+ osCompatible =
22
+ supportdRNPlatforms.indexOf(process.platform) > -1
23
+
24
+ if(!osCompatible) {
25
+ return GlobalVars.argv.get().forceCrossPlatform
26
+ }
27
+
28
+ return false
29
+
30
+ }
@@ -0,0 +1,223 @@
1
+ import * as node_fs from "node:fs"
2
+ import * as node_path from "node:path"
3
+
4
+ import type {
5
+ Config,
6
+ } from "../../../../../index.mts"
7
+
8
+ import {
9
+ GlobalVars,
10
+ } from "../../../../_global-vars/index.mts"
11
+
12
+ import * as MetadataCheck from "./_metadata-check/index.mts"
13
+
14
+ /**
15
+ * Similar as the _init-imagesets.mts
16
+ */
17
+ export function initAppiconsets(
18
+ appiconsets: Config.Apple.AssetCatalogs["appiconsets"],
19
+ metadata: {
20
+ bundleIdentifier: string,
21
+ projectName: string,
22
+ platform: "ios" | "macos",
23
+ },
24
+ ) {
25
+
26
+ if(!appiconsets?.length) {
27
+ return
28
+ }
29
+
30
+ const projectDirectory = node_path.dirname(GlobalVars.configFilePath.get())
31
+
32
+ const targetDirectory = node_path.join(
33
+ projectDirectory,
34
+ "macos",
35
+ metadata.projectName,
36
+ "Assets.xcassets",
37
+ )
38
+
39
+ let appiconset_index = -1
40
+ for(const appiconset of appiconsets) {
41
+ if(!appiconset.images.length) {
42
+ break
43
+ }
44
+
45
+ appiconset_index++
46
+
47
+ // +++++ create <name>.appiconset directory inside of the target directory
48
+ const _appiconset_directory = node_path.join(
49
+ targetDirectory,
50
+ `${appiconset.name}.appiconset`,
51
+ )
52
+ if(!node_fs.existsSync(_appiconset_directory)) {
53
+ node_fs.mkdirSync(_appiconset_directory)
54
+ }
55
+ // -----
56
+
57
+ // Intentionally commented the `existingImageFilenames`
58
+ // At this moment, we are allowing use the same file for different variant
59
+
60
+ // store a fast lookup of image filename
61
+ // const existingImageFilenames: string[] = []
62
+
63
+ const contentsJson: CatalogContentsJson = {
64
+ images: [],
65
+ info: {
66
+ version: 1,
67
+ author: metadata.bundleIdentifier,
68
+ },
69
+ }
70
+
71
+ let image_index = -1
72
+ for(const { path: imagePath, ...image } of appiconset.images) {
73
+ image_index++
74
+
75
+ const
76
+ imageFilePath =
77
+ node_path.resolve(projectDirectory, imagePath),
78
+
79
+ imageMetadata: (typeof contentsJson.images)[0] =
80
+ {
81
+ appearances: image.appearances?.[0]
82
+ ? [{
83
+ appearance: image.appearances[0].appearance,
84
+ value: image.appearances[0].value,
85
+ }]
86
+ : undefined,
87
+ "display-gamut": image["display-gamut"] || undefined,
88
+ filename: node_path.basename(imageFilePath),
89
+ size: image.size,
90
+ idiom: image.idiom || "universal",
91
+ scale: image.scale || "1x",
92
+ }
93
+
94
+ {
95
+ const traceStr = `\`appiconsets[${appiconset_index}].images[${image_index}]\``
96
+
97
+ if(!imagePath) {
98
+ throw new Error(`Not a valid image path in the ${traceStr}.`)
99
+ }
100
+
101
+ if(
102
+ image.appearances?.length &&
103
+ !MetadataCheck.appearances(image.appearances)
104
+ ) {
105
+ throw new Error(`Not a valid appearances in the ${traceStr}.`)
106
+ }
107
+
108
+ if(
109
+ image["display-gamut"] &&
110
+ !MetadataCheck.Image.displayGamut(image["display-gamut"])
111
+ ) {
112
+ throw new Error(`Not a valid image "display-gamut" in the ${traceStr}.`)
113
+ }
114
+
115
+ if(!mapImageSize[image.size]) {
116
+ throw new Error(`Not a valid image size in the ${traceStr}.`)
117
+ }
118
+
119
+ if(
120
+ image["idiom"] &&
121
+ !MetadataCheck.idiom(image.idiom)
122
+ ) {
123
+ throw new Error(`Not a valid idiom in the ${traceStr}.`)
124
+ }
125
+
126
+ // throw Error if the image is not existed
127
+ if(!node_fs.existsSync(imageFilePath)) {
128
+ throw new Error(`Cannot find ${imagePath} relatively from your project directory.`)
129
+ }
130
+
131
+ // throw if the image extname is not supported by Xcode
132
+ const imageExtname = node_path.extname(imageFilePath)
133
+ if(imageExtname !== ".png") {
134
+ throw new Error(`${imageExtname} file is not supported in Asset Catalogs.`)
135
+ }
136
+
137
+ // if(existingImageFilenames.indexOf(imageMetadata.filename) > -1) {
138
+ // throw new Error("Cannot use the same image file for different variant.")
139
+ // }
140
+
141
+ // It has different filename,
142
+ // but it is prohibited to use same variant
143
+ if(contentsJson.images.length) {
144
+ for(const existingImageMetadata of contentsJson.images) {
145
+ /**
146
+ * Fix me.
147
+ * This is just a lazy comparison.
148
+ */
149
+ const isSimilar =
150
+ JSON.stringify(existingImageMetadata) ===
151
+ JSON.stringify(imageMetadata)
152
+
153
+ if(isSimilar) {
154
+ throw new Error("Cannot use multiple images with same variant.")
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ // Copy the image file
161
+ // place it to the `Assets.xcassets/<namespace?>/<name>.imageset/<imageFilename>
162
+ node_fs.copyFileSync(
163
+ imageFilePath,
164
+ node_path.join(_appiconset_directory, imageMetadata.filename),
165
+ )
166
+
167
+ // add the image data to the Contents.json
168
+ contentsJson.images.push({ ...imageMetadata })
169
+
170
+ // existingImageFilenames.push(imageMetadata.filename)
171
+ }
172
+
173
+ // Create Contents.json file inside of <name>.imageset directory
174
+ node_fs.writeFileSync(
175
+ node_path.join(_appiconset_directory, "Contents.json"),
176
+ JSON.stringify(
177
+ contentsJson,
178
+ null,
179
+ 2,
180
+ ),
181
+ "utf8",
182
+ )
183
+ }
184
+
185
+ }
186
+
187
+ /**
188
+ * An actual Xcode Contents.json for an asset catalog
189
+ */
190
+ interface CatalogContentsJson {
191
+ images: (Omit<Config.Apple.AssetCatalogFormat.AppIcon.SetType["images"][0], "path"> & {
192
+ filename: string,
193
+ })[],
194
+ info: {
195
+ version: number,
196
+ author: string,
197
+ },
198
+ }
199
+
200
+ const
201
+ /**
202
+ * This is just for a fast check if user input about the size is wrong
203
+ */
204
+ mapImageSize: Record<Config.Apple.AssetCatalogFormat.AppIcon.Size, 1> =
205
+ {
206
+ "16x16": 1,
207
+ "20x20": 1,
208
+ "24x24": 1,
209
+ "27.5x27.5": 1,
210
+ "29x29": 1,
211
+ "32x32": 1,
212
+ "40x40": 1,
213
+ "44x44": 1,
214
+ "60x60": 1,
215
+ "76x76": 1,
216
+ "83.5x83.5": 1,
217
+ "86x86": 1,
218
+ "98x98": 1,
219
+ "128x128": 1,
220
+ "256x256": 1,
221
+ "512x512": 1,
222
+ "1024x1024": 1,
223
+ }
@@ -0,0 +1,241 @@
1
+ import * as node_fs from "node:fs"
2
+ import * as node_path from "node:path"
3
+
4
+ import type {
5
+ Config,
6
+ } from "../../../../../index.mts"
7
+
8
+ import {
9
+ GlobalVars,
10
+ } from "../../../../_global-vars/index.mts"
11
+
12
+ import * as MetadataCheck from "./_metadata-check/index.mts"
13
+
14
+ export function initImagesets(
15
+ imagesets: Config.Apple.AssetCatalogs["imagesets"],
16
+ metadata: {
17
+ bundleIdentifier: string,
18
+ namespace?: string,
19
+ projectName: string,
20
+ },
21
+ ) {
22
+
23
+ if(!imagesets?.length) {
24
+ return
25
+ }
26
+
27
+ const projectDirectory = node_path.dirname(GlobalVars.configFilePath.get())
28
+
29
+ let targetDirectory = node_path.join(
30
+ projectDirectory,
31
+ "macos",
32
+ metadata.projectName,
33
+ "Assets.xcassets",
34
+ )
35
+
36
+ if(metadata.namespace) {
37
+ // append a namespace directory after Assets.xcassets
38
+ targetDirectory = node_path.join(targetDirectory, metadata.namespace)
39
+
40
+ // Create a namespace directory inside of "Assets.xcassets"
41
+ node_fs.mkdirSync(
42
+ targetDirectory,
43
+ {
44
+ recursive: true,
45
+ },
46
+ )
47
+
48
+ // create Contents.json in the namespace directory
49
+ node_fs.writeFileSync(
50
+ node_path.join(targetDirectory, "Contents.json"),
51
+ JSON.stringify({
52
+ info: {
53
+ version: 1,
54
+ author: metadata.bundleIdentifier,
55
+ },
56
+ properties: {
57
+ "provides-namespace": true,
58
+ },
59
+ }, null, 2),
60
+ "utf8",
61
+ )
62
+ }
63
+
64
+ let imageset_index = -1
65
+ for(const imageset of imagesets) {
66
+ if(!imageset.images.length) {
67
+ break
68
+ }
69
+
70
+ imageset_index++
71
+
72
+ // +++++ create <name>.imageset directory inside of the target directory
73
+ const _imageset_directory = node_path.join(
74
+ targetDirectory,
75
+ `${imageset.name}.imageset`,
76
+ )
77
+ if(!node_fs.existsSync(_imageset_directory)) {
78
+ node_fs.mkdirSync(_imageset_directory)
79
+ }
80
+ // -----
81
+
82
+ // store a fast lookup of image filename
83
+ const existingImageFilenames: string[] = []
84
+
85
+ const contentsJson: CatalogContentsJson = {
86
+ images: [],
87
+ info: {
88
+ version: 1,
89
+ author: metadata.bundleIdentifier,
90
+ },
91
+ }
92
+
93
+ let image_index = -1
94
+ for(const { path: imagePath, ...image } of imageset.images) {
95
+ image_index++
96
+
97
+ if(
98
+ !imagePath
99
+ ) {
100
+ throw new Error("Not a valid image metadata object in the `imagesets[number].images[number]`")
101
+ }
102
+
103
+ const
104
+ imageFilePath =
105
+ node_path.resolve(projectDirectory, imagePath),
106
+
107
+ imageMetadata: (typeof contentsJson.images)[0] =
108
+ {
109
+ appearances: image.appearances?.[0]
110
+ // intentional for comparison with JSON.stringify
111
+ ? [{
112
+ appearance: image.appearances[0].appearance,
113
+ value: image.appearances[0].value,
114
+ }]
115
+ : undefined,
116
+ "compression-type": image["compression-type"] || undefined,
117
+ "display-gamut": image["display-gamut"] || undefined,
118
+ filename: node_path.basename(imageFilePath),
119
+ idiom: image.idiom || "universal",
120
+ languageDirection: image.languageDirection,
121
+ scale: image.scale || "1x",
122
+ }
123
+
124
+ {
125
+ const traceStr = `\`appiconsets[${imageset_index}].images[${image_index}]\``
126
+
127
+ if(!imagePath) {
128
+ throw new Error(`Not a valid image path in the ${traceStr}.`)
129
+ }
130
+
131
+ if(
132
+ image.appearances?.length &&
133
+ !MetadataCheck.appearances(image.appearances)
134
+ ) {
135
+ throw new Error(`Not a valid appearances in the ${traceStr}.`)
136
+ }
137
+
138
+ if(
139
+ image["compression-type"] &&
140
+ !MetadataCheck.Image.compressionType(image["compression-type"])
141
+ ) {
142
+ throw new Error(`Not a valid image compression-type in the ${traceStr}.`)
143
+ }
144
+
145
+ if(
146
+ image["display-gamut"] &&
147
+ !MetadataCheck.Image.displayGamut(image["display-gamut"])
148
+ ) {
149
+ throw new Error(`Not a valid image "display-gamut" in the ${traceStr}.`)
150
+ }
151
+
152
+ if(
153
+ image["idiom"] &&
154
+ !MetadataCheck.idiom(image.idiom)
155
+ ) {
156
+ throw new Error(`Not a valid idiom in the ${traceStr}.`)
157
+ }
158
+
159
+ if(
160
+ image.languageDirection &&
161
+ !MetadataCheck.Image.languageDirection(image.languageDirection)
162
+ ) {
163
+ throw new Error(`Not a valid image language direction in the ${traceStr}.`)
164
+ }
165
+
166
+ // throw Error if the image is not existed
167
+ if(!node_fs.existsSync(imageFilePath)) {
168
+ throw new Error(`Cannot find ${imagePath} relatively from your project directory.`)
169
+ }
170
+
171
+ // throw if the image extname is not supported by Xcode
172
+ const imageExtname = node_path.extname(imageFilePath)
173
+ if(supportedImageExts.indexOf(imageExtname) == -1) {
174
+ throw new Error(`${imageExtname} file is not supported in Asset Catalogs.`)
175
+ }
176
+
177
+ if(existingImageFilenames.indexOf(imageMetadata.filename) > -1) {
178
+ throw new Error("Cannot use the same image file for different variant.")
179
+ }
180
+
181
+ // It has different filename,
182
+ // but it is prohibited to use same variant
183
+ if(contentsJson.images.length) {
184
+ for(const existingImageMetadata of contentsJson.images) {
185
+ const isSimilar =
186
+ JSON.stringify(existingImageMetadata) ===
187
+ JSON.stringify(imageMetadata)
188
+
189
+ if(isSimilar) {
190
+ throw new Error("Cannot use multiple images with same variant.")
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+
197
+ // Copy the image file
198
+ // place it to the `Assets.xcassets/<namespace?>/<name>.imageset/<imageFilename>
199
+ node_fs.copyFileSync(
200
+ imageFilePath,
201
+ node_path.join(_imageset_directory, imageMetadata.filename),
202
+ )
203
+
204
+ // add the image data to the Contents.json
205
+ contentsJson.images.push({ ...imageMetadata })
206
+ }
207
+
208
+ // Create Contents.json file inside of <name>.imageset directory
209
+ node_fs.writeFileSync(
210
+ node_path.join(_imageset_directory, "Contents.json"),
211
+ JSON.stringify(
212
+ contentsJson,
213
+ null,
214
+ 2,
215
+ ),
216
+ "utf8",
217
+ )
218
+ }
219
+
220
+ }
221
+
222
+ /**
223
+ * An actual Xcode Contents.json for an asset catalog
224
+ */
225
+ interface CatalogContentsJson {
226
+ images: (Omit<Config.Apple.AssetCatalogFormat.Image.SetType["images"][0], "path"> & {
227
+ filename: string,
228
+ })[],
229
+ info: {
230
+ version: number,
231
+ author: string,
232
+ },
233
+ }
234
+
235
+ const supportedImageExts = [
236
+ ".heic",
237
+ ".heif",
238
+ ".jpg",
239
+ ".jpeg",
240
+ ".png",
241
+ ]
@@ -0,0 +1,24 @@
1
+ import type * as Config from "../../../../../../config/index.mts"
2
+
3
+ export function appearances(value: Array<unknown>): boolean {
4
+ if(!Array.isArray(value) || value.length != 1 || !value[0] || typeof value[0] != "object") {
5
+ return false
6
+ }
7
+
8
+ const it = value[0] as Record<string, string>
9
+
10
+ return !!__appearance[it.appearance as never] && !!__value[it.value as never]
11
+ }
12
+
13
+ const
14
+ __appearance: Record<Config.Apple.AssetCatalogFormat.Appearances[0]["appearance"], 1> =
15
+ {
16
+ contrast: 1,
17
+ luminosity: 1,
18
+ },
19
+
20
+ __value: Record<Config.Apple.AssetCatalogFormat.Appearances[0]["value"], 1> =
21
+ {
22
+ dark: 1,
23
+ light: 1,
24
+ }
@@ -0,0 +1,22 @@
1
+ import type * as Config from "../../../../../../config/index.mts"
2
+
3
+ export function idiom(value: string): boolean {
4
+ return !!value && !!__idiom[value as never]
5
+ }
6
+
7
+ const
8
+ __idiom: Record<Config.Apple.AssetCatalogFormat.Idiom, 1> =
9
+ {
10
+ "ios-marketing": 1,
11
+ "watch-marketing": 1,
12
+ appLauncher: 1,
13
+ companionSettings: 1,
14
+ ipad: 1,
15
+ iphone: 1,
16
+ mac: 1,
17
+ notificationCenter: 1,
18
+ quickLook: 1,
19
+ tv: 1,
20
+ universal: 1,
21
+ watch: 1,
22
+ }
@@ -0,0 +1,15 @@
1
+ import type * as Config from "../../../../../../../config/index.mts"
2
+
3
+ export function compressionType(value: string): boolean {
4
+ return !!value && !!__compressionType[value as never]
5
+ }
6
+
7
+ const
8
+ __compressionType: Record<Config.Apple.AssetCatalogFormat.Image.CompressionType, 1> =
9
+ {
10
+ "gpu-optimized-best": 1,
11
+ "gpu-optimized-smallest": 1,
12
+ automatic: 1,
13
+ lossless: 1,
14
+ lossy: 1,
15
+ }
@@ -0,0 +1,12 @@
1
+ import type * as Config from "../../../../../../../config/index.mts"
2
+
3
+ export function displayGamut(value: string): boolean {
4
+ return !!value && !!displayGamuts[value as never]
5
+ }
6
+
7
+ const
8
+ displayGamuts: Record<Config.Apple.AssetCatalogFormat.Image.DisplayGamut, 1> =
9
+ {
10
+ "display-P3": 1,
11
+ sRGB: 1,
12
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./compression-type.mts"
2
+ export * from "./display-gamut.mts"
3
+ export * from "./language-direction.mts"
@@ -0,0 +1,12 @@
1
+ import type * as Config from "../../../../../../../config/index.mts"
2
+
3
+ export function languageDirection(value: string): boolean {
4
+ return !!value && !!__languageDirection[value as never]
5
+ }
6
+
7
+ const
8
+ __languageDirection: Record<Config.Apple.AssetCatalogFormat.Image.LanguageDirection, 1> =
9
+ {
10
+ "left-to-right": 1,
11
+ "right-to-left": 1,
12
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./appearances.mts"
2
+ export * from "./idiom.mts"
3
+ export * as Image from "./image/index.mts"
@@ -0,0 +1,54 @@
1
+ import type {
2
+ Config,
3
+ } from "../../../../../index.mts"
4
+
5
+ import {
6
+ initAppiconsets,
7
+ } from "./_init-appiconsets.mts"
8
+
9
+ import {
10
+ initImagesets,
11
+ } from "./_init-imagesets.mts"
12
+
13
+ export function createAssetCatalogs(
14
+ assetCatalogs: Config.Apple.Data["assetCatalogs"],
15
+ metadata: {
16
+ bundleIdentifier: string,
17
+ namespace?: string,
18
+ platform: "macos" | "ios",
19
+ projectName: string,
20
+ },
21
+ ) {
22
+ if(!assetCatalogs) {
23
+ return
24
+ }
25
+
26
+ for(const _key of Object.keys(assetCatalogs)) {
27
+ const key = _key as keyof typeof assetCatalogs
28
+
29
+ if(key == "imagesets") {
30
+ initImagesets(
31
+ assetCatalogs.imagesets,
32
+ metadata,
33
+ )
34
+ } else if(key == "appiconsets") {
35
+ initAppiconsets(
36
+ assetCatalogs.appiconsets,
37
+ metadata,
38
+ )
39
+ } else {
40
+ // key is namespace
41
+ const namespacedCatalogs = assetCatalogs[key] as unknown as Config.Apple.AssetCatalogs
42
+
43
+ if(namespacedCatalogs && Object.keys(namespacedCatalogs).length) {
44
+ createAssetCatalogs(
45
+ namespacedCatalogs,
46
+ {
47
+ ...metadata,
48
+ namespace: key,
49
+ },
50
+ )
51
+ }
52
+ }
53
+ }
54
+ }
@@ -0,0 +1 @@
1
+ export * from "./create-asset-catalogs.mts"