codex-terminal-themes 1.0.0
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.
- package/CHANGELOG.md +8 -0
- package/CONTRIBUTING.md +23 -0
- package/LICENSE +21 -0
- package/LICENSE.txt +21 -0
- package/README.md +169 -0
- package/SECURITY.md +5 -0
- package/SUPPORT.md +5 -0
- package/bin/codex-terminal-themes.mjs +12 -0
- package/docs/app.js +1393 -0
- package/docs/assets/theme-gallery-header.png +0 -0
- package/docs/favicon.svg +10 -0
- package/docs/index.html +240 -0
- package/docs/preview.svg +24 -0
- package/docs/site-data.json +51078 -0
- package/docs/styles.css +780 -0
- package/metadata/README.md +71 -0
- package/metadata/themes.json +16185 -0
- package/metadata/themes.schema.json +218 -0
- package/package.json +109 -0
- package/src/cli.mjs +1763 -0
- package/stylelint.config.mjs +12 -0
- package/themes/80s.tmTheme +229 -0
- package/themes/Active4D.tmTheme +407 -0
- package/themes/All Hallow's Eve Custom.tmTheme +275 -0
- package/themes/All Hallow's Eve.tmTheme +277 -0
- package/themes/All Hallows Eve.tmTheme +277 -0
- package/themes/Amy.tmTheme +559 -0
- package/themes/Artic Fall.tmTheme +275 -0
- package/themes/BBEdit.tmTheme +439 -0
- package/themes/Bespin.tmTheme +516 -0
- package/themes/Black Pearl II.tmTheme +496 -0
- package/themes/Black Pearl.tmTheme +400 -0
- package/themes/Blackboard 2.tmTheme +348 -0
- package/themes/Blackboard Black.tmTheme +350 -0
- package/themes/Blackboard.tmTheme +348 -0
- package/themes/Blueberry Jelly.tmTheme +242 -0
- package/themes/Bluesy.tmTheme +242 -0
- package/themes/Blurb 2.tmTheme +229 -0
- package/themes/Blurb.tmTheme +229 -0
- package/themes/Bongzilla 2.tmTheme +223 -0
- package/themes/Bongzilla.tmTheme +223 -0
- package/themes/Brightly Dark.tmTheme +242 -0
- package/themes/Brilliance Black.tmTheme +2619 -0
- package/themes/Brilliance Dull.tmTheme +2243 -0
- package/themes/Bromozoid.tmTheme +227 -0
- package/themes/CSSEdit.tmTheme +203 -0
- package/themes/Classic Modified.tmTheme +469 -0
- package/themes/Clouds Midnight.tmTheme +361 -0
- package/themes/Clouds of Ruby.tmTheme +649 -0
- package/themes/Clouds.tmTheme +348 -0
- package/themes/Cloudy Fields.tmTheme +240 -0
- package/themes/Coal Graal.tmTheme +282 -0
- package/themes/Cobalt.tmTheme +561 -0
- package/themes/Coda.tmTheme +317 -0
- package/themes/Colorful.tmTheme +307 -0
- package/themes/Cool Glow.tmTheme +234 -0
- package/themes/Corona.tmTheme +290 -0
- package/themes/Cowabunga.tmTheme +242 -0
- package/themes/DanBurst.tmTheme +665 -0
- package/themes/Daniel Fischer.tmTheme +627 -0
- package/themes/Dark Ocean.tmTheme +242 -0
- package/themes/DarkNeon.tmTheme +818 -0
- package/themes/Dawn.tmTheme +437 -0
- package/themes/DawnCustom.tmTheme +443 -0
- package/themes/Django (Smoothy).tmTheme +453 -0
- package/themes/Django Blues.tmTheme +182 -0
- package/themes/Django Extended.tmTheme +495 -0
- package/themes/Django.tmTheme +436 -0
- package/themes/Dobdark.tmTheme +615 -0
- package/themes/Dominion Day.tmTheme +562 -0
- package/themes/Doo-Daa.tmTheme +242 -0
- package/themes/Drankin Purp.tmTheme +227 -0
- package/themes/Dreamweaver_Blackbam_Aptana303.tmTheme +980 -0
- package/themes/Easy on my Eyes There Buddy.tmTheme +227 -0
- package/themes/Eiffel.tmTheme +435 -0
- package/themes/Emacs Strict.tmTheme +241 -0
- package/themes/Emacs.tmTheme +241 -0
- package/themes/Epic Blue.tmTheme +320 -0
- package/themes/Erebus.tmTheme +467 -0
- package/themes/Espresso Libre.tmTheme +402 -0
- package/themes/Espresso Tutti.tmTheme +392 -0
- package/themes/Espresso.tmTheme +329 -0
- package/themes/Fade to Grey.tmTheme +308 -0
- package/themes/Fluidvision.tmTheme +443 -0
- package/themes/ForLaTeX.tmTheme +214 -0
- package/themes/Freckle.tmTheme +279 -0
- package/themes/Friendship Bracelet.tmTheme +303 -0
- package/themes/GaGaGaGroovy.tmTheme +227 -0
- package/themes/Gangrene.tmTheme +242 -0
- package/themes/GitHub.tmTheme +653 -0
- package/themes/GlitterBomb.tmTheme +387 -0
- package/themes/Halloween Night.tmTheme +303 -0
- package/themes/Happy happy joy joy.tmTheme +841 -0
- package/themes/Happydeluxe.tmTheme +184 -0
- package/themes/HelvectorLight.tmTheme +557 -0
- package/themes/Humane.tmTheme +220 -0
- package/themes/IDLE.tmTheme +235 -0
- package/themes/IR_Black.tmTheme +810 -0
- package/themes/IR_White.tmTheme +792 -0
- package/themes/Jane Fonda, Baby Redux.tmTheme +264 -0
- package/themes/Johnny.tmTheme +798 -0
- package/themes/Juicy.tmTheme +250 -0
- package/themes/Kuroir Theme.tmTheme +707 -0
- package/themes/LAZY.tmTheme +291 -0
- package/themes/Lowlight.tmTheme +605 -0
- package/themes/Mac Classic.tmTheme +476 -0
- package/themes/Made of Code.tmTheme +695 -0
- package/themes/MagicWB (Amiga).tmTheme +376 -0
- package/themes/Malibu Nights.tmTheme +257 -0
- package/themes/Menage A Trois.tmTheme +881 -0
- package/themes/Merbivore Soft.tmTheme +285 -0
- package/themes/Merbivore.tmTheme +285 -0
- package/themes/Midnight.tmTheme +321 -0
- package/themes/Mmm Sandy.tmTheme +227 -0
- package/themes/Monokai.tmTheme +289 -0
- package/themes/MultiMarkdown.tmTheme +183 -0
- package/themes/Mustang.tmTheme +339 -0
- package/themes/Neopro Inverted.tmTheme +328 -0
- package/themes/Neopro.tmTheme +330 -0
- package/themes/Nice One.tmTheme +222 -0
- package/themes/No Way.tmTheme +255 -0
- package/themes/Overcast.tmTheme +659 -0
- package/themes/Pastels on Dark.tmTheme +703 -0
- package/themes/Pastie.tmTheme +321 -0
- package/themes/Peridinkle.tmTheme +240 -0
- package/themes/Play!.tmTheme +736 -0
- package/themes/Puss.tmTheme +227 -0
- package/themes/Putty.tmTheme +275 -0
- package/themes/Quail.tmTheme +257 -0
- package/themes/RDark.tmTheme +235 -0
- package/themes/Rails Envy.tmTheme +299 -0
- package/themes/Railscasts 2.tmTheme +368 -0
- package/themes/Railscasts.tmTheme +278 -0
- package/themes/Resesif.tmTheme +298 -0
- package/themes/Ringo.tmTheme +240 -0
- package/themes/Ruby Blue.tmTheme +366 -0
- package/themes/RubyRobot.tmTheme +250 -0
- package/themes/Ryan Light.tmTheme +232 -0
- package/themes/Seafoam.tmTheme +242 -0
- package/themes/Sidewalk Chalk.tmTheme +276 -0
- package/themes/Sin City (that yellow bastard).tmTheme +585 -0
- package/themes/Slate.tmTheme +436 -0
- package/themes/Slush & Poppies.tmTheme +336 -0
- package/themes/Slush and Poppies.tmTheme +336 -0
- package/themes/Smokey Morning.tmTheme +229 -0
- package/themes/Smoothy original.tmTheme +623 -0
- package/themes/Smoothy.tmTheme +623 -0
- package/themes/Solarized (dark).tmTheme +2051 -0
- package/themes/Solarized-dark.tmTheme +312 -0
- package/themes/Solarized-light.tmTheme +305 -0
- package/themes/Sometheme.tmTheme +240 -0
- package/themes/SoylentTheme.tmTheme +353 -0
- package/themes/SpaceCadet.tmTheme +212 -0
- package/themes/Spectacular.tmTheme +436 -0
- package/themes/Starlight.tmTheme +857 -0
- package/themes/Stoneship Bright.tmTheme +348 -0
- package/themes/Stoneship.tmTheme +361 -0
- package/themes/Summer Camp Mod.tmTheme +229 -0
- package/themes/Summer Camp.tmTheme +229 -0
- package/themes/Summery Drink.tmTheme +242 -0
- package/themes/Sunburst.tmTheme +665 -0
- package/themes/Swyphs II.tmTheme +306 -0
- package/themes/Tango Bright.tmTheme +1 -0
- package/themes/Tango.tmTheme +450 -0
- package/themes/Teenage Dream.tmTheme +242 -0
- package/themes/Texari.tmTheme +727 -0
- package/themes/Text Ex Machina.tmTheme +295 -0
- package/themes/Tomorrow-Night-Blue.tmTheme +175 -0
- package/themes/Tomorrow-Night-Eighties.tmTheme +175 -0
- package/themes/Tomorrow-Night.tmTheme +175 -0
- package/themes/Tomorrow.tmTheme +349 -0
- package/themes/ToyChest.tmTheme +503 -0
- package/themes/TravisJeffery.tmTheme +1261 -0
- package/themes/Tubster.tmTheme +280 -0
- package/themes/Twilight BG FG.tmTheme +1000 -0
- package/themes/Twilight.tmTheme +516 -0
- package/themes/TwilightMod.tmTheme +529 -0
- package/themes/Two Days Ago.tmTheme +242 -0
- package/themes/Vibrant Fin.tmTheme +447 -0
- package/themes/Vibrant Ink.tmTheme +447 -0
- package/themes/Vibrant Scala.tmTheme +292 -0
- package/themes/Vibrant Tango.tmTheme +438 -0
- package/themes/Wandering.tmTheme +681 -0
- package/themes/Whimsy in Blue.tmTheme +240 -0
- package/themes/Why/342/200/231s Poignant.tmTheme" +191 -0
- package/themes/Windows XP.tmTheme +350 -0
- package/themes/Witch.tmTheme +282 -0
- package/themes/Yurple.tmTheme +227 -0
- package/themes/ZZZ.tmTheme +131 -0
- package/themes/Zachstronaut.tmTheme +381 -0
- package/themes/Zenburnesque.tmTheme +343 -0
- package/themes/[ Argonaut ].tmTheme +387 -0
- package/themes/barf.tmTheme +254 -0
- package/themes/converted-vscode-AmoledShinyBlack.tmTheme +528 -0
- package/themes/converted-vscode-AmoledShinyBlack2.tmTheme +609 -0
- package/themes/converted-vscode-AmoledShinyBlack3.tmTheme +683 -0
- package/themes/converted-vscode-AmoledShinyBlack4.tmTheme +896 -0
- package/themes/converted-vscode-AmoledShinyBlack5.tmTheme +1023 -0
- package/themes/converted-vscode-AmoledShinyBlack6.tmTheme +2092 -0
- package/themes/eclips3.media (ECLM).tmTheme +294 -0
- package/themes/evin.tmTheme +253 -0
- package/themes/fake.tmTheme +669 -0
- package/themes/fapfap.tmTheme +508 -0
- package/themes/helloKitty.tmTheme +293 -0
- package/themes/iLife 05.tmTheme +619 -0
- package/themes/iPlastic.tmTheme +397 -0
- package/themes/idleFingers.tmTheme +380 -0
- package/themes/krTheme.tmTheme +551 -0
- package/themes/mark.james.name.tmTheme +1117 -0
- package/themes/minimal Theme.tmTheme +551 -0
- package/themes/mint.tmTheme +617 -0
- package/themes/mintBlue Dark.tmTheme +653 -0
- package/themes/mintBlue.tmTheme +655 -0
- package/themes/modifiedPastels.tmTheme +745 -0
- package/themes/monoindustrial.tmTheme +451 -0
- package/themes/my-theme-blackboard.tmTheme +363 -0
- package/themes/my-theme-classic.tmTheme +465 -0
- package/themes/nppGLua.tmTheme +293 -0
- package/themes/reST testing theme.tmTheme +554 -0
- package/themes/rose-pine-dawn.tmTheme +329 -0
- package/themes/rose-pine-moon.tmTheme +329 -0
- package/themes/rose-pine.tmTheme +329 -0
- package/themes/ryan-light.tmTheme +232 -0
- package/themes/wut.tmTheme +255 -0
- package/tools/build-pages-site.mjs +465 -0
- package/tools/generate-theme-metadata.mjs +680 -0
- package/tools/serve-pages-site.mjs +196 -0
- package/tools/validate-themes.mjs +272 -0
- package/types/index.d.ts +49 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>name</key>
|
|
6
|
+
<string>Wut</string>
|
|
7
|
+
<key>settings</key>
|
|
8
|
+
<array>
|
|
9
|
+
<dict>
|
|
10
|
+
<key>settings</key>
|
|
11
|
+
<dict>
|
|
12
|
+
<key>background</key>
|
|
13
|
+
<string>#FFFFFF</string>
|
|
14
|
+
<key>caret</key>
|
|
15
|
+
<string>#000000</string>
|
|
16
|
+
<key>foreground</key>
|
|
17
|
+
<string>#000000</string>
|
|
18
|
+
<key>invisibles</key>
|
|
19
|
+
<string>#CAE2FB3D</string>
|
|
20
|
+
<key>lineHighlight</key>
|
|
21
|
+
<string>#FFFFFF24</string>
|
|
22
|
+
<key>selection</key>
|
|
23
|
+
<string>#C8C8C8</string>
|
|
24
|
+
</dict>
|
|
25
|
+
</dict>
|
|
26
|
+
|
|
27
|
+
<dict>
|
|
28
|
+
<key>name</key>
|
|
29
|
+
<string>themes.sweyla.com</string>
|
|
30
|
+
<key>scope</key>
|
|
31
|
+
<string>meta.sweyla</string>
|
|
32
|
+
<key>settings</key>
|
|
33
|
+
<dict>
|
|
34
|
+
<key>fontStyle</key>
|
|
35
|
+
<string></string>
|
|
36
|
+
<key>foreground</key>
|
|
37
|
+
<string>#7E0A00</string>
|
|
38
|
+
</dict>
|
|
39
|
+
</dict>
|
|
40
|
+
|
|
41
|
+
<dict>
|
|
42
|
+
<key>name</key>
|
|
43
|
+
<string>Comment</string>
|
|
44
|
+
<key>scope</key>
|
|
45
|
+
<string>comment</string>
|
|
46
|
+
<key>settings</key>
|
|
47
|
+
<dict>
|
|
48
|
+
<key>fontStyle</key>
|
|
49
|
+
<string></string>
|
|
50
|
+
<key>foreground</key>
|
|
51
|
+
<string>#8DA708</string>
|
|
52
|
+
</dict>
|
|
53
|
+
</dict>
|
|
54
|
+
|
|
55
|
+
<dict>
|
|
56
|
+
<key>name</key>
|
|
57
|
+
<string>Constant</string>
|
|
58
|
+
<key>scope</key>
|
|
59
|
+
<string>constant</string>
|
|
60
|
+
<key>settings</key>
|
|
61
|
+
<dict>
|
|
62
|
+
<key>fontStyle</key>
|
|
63
|
+
<string></string>
|
|
64
|
+
<key>foreground</key>
|
|
65
|
+
<string>#FF0018</string>
|
|
66
|
+
</dict>
|
|
67
|
+
</dict>
|
|
68
|
+
|
|
69
|
+
<dict>
|
|
70
|
+
<key>name</key>
|
|
71
|
+
<string>Constant</string>
|
|
72
|
+
<key>scope</key>
|
|
73
|
+
<string>constant.language</string>
|
|
74
|
+
<key>settings</key>
|
|
75
|
+
<dict>
|
|
76
|
+
<key>fontStyle</key>
|
|
77
|
+
<string></string>
|
|
78
|
+
<key>foreground</key>
|
|
79
|
+
<string>#7E000E</string>
|
|
80
|
+
</dict>
|
|
81
|
+
</dict>
|
|
82
|
+
|
|
83
|
+
<dict>
|
|
84
|
+
<key>name</key>
|
|
85
|
+
<string>Entity</string>
|
|
86
|
+
<key>scope</key>
|
|
87
|
+
<string>entity</string>
|
|
88
|
+
<key>settings</key>
|
|
89
|
+
<dict>
|
|
90
|
+
<key>fontStyle</key>
|
|
91
|
+
<string></string>
|
|
92
|
+
<key>foreground</key>
|
|
93
|
+
<string>#E33028</string>
|
|
94
|
+
</dict>
|
|
95
|
+
</dict>
|
|
96
|
+
|
|
97
|
+
<dict>
|
|
98
|
+
<key>name</key>
|
|
99
|
+
<string>Entity Function</string>
|
|
100
|
+
<key>scope</key>
|
|
101
|
+
<string>entity.name.function</string>
|
|
102
|
+
<key>settings</key>
|
|
103
|
+
<dict>
|
|
104
|
+
<key>fontStyle</key>
|
|
105
|
+
<string></string>
|
|
106
|
+
<key>foreground</key>
|
|
107
|
+
<string>#E33028</string>
|
|
108
|
+
</dict>
|
|
109
|
+
</dict>
|
|
110
|
+
|
|
111
|
+
<dict>
|
|
112
|
+
<key>name</key>
|
|
113
|
+
<string>Entity Name</string>
|
|
114
|
+
<key>scope</key>
|
|
115
|
+
<string>entity.name</string>
|
|
116
|
+
<key>settings</key>
|
|
117
|
+
<dict>
|
|
118
|
+
<key>fontStyle</key>
|
|
119
|
+
<string></string>
|
|
120
|
+
<key>foreground</key>
|
|
121
|
+
<string>#FF5E00</string>
|
|
122
|
+
</dict>
|
|
123
|
+
</dict>
|
|
124
|
+
|
|
125
|
+
<dict>
|
|
126
|
+
<key>name</key>
|
|
127
|
+
<string>Keyword</string>
|
|
128
|
+
<key>scope</key>
|
|
129
|
+
<string>keyword</string>
|
|
130
|
+
<key>settings</key>
|
|
131
|
+
<dict>
|
|
132
|
+
<key>fontStyle</key>
|
|
133
|
+
<string></string>
|
|
134
|
+
<key>foreground</key>
|
|
135
|
+
<string>#7E0A00</string>
|
|
136
|
+
</dict>
|
|
137
|
+
</dict>
|
|
138
|
+
|
|
139
|
+
<dict>
|
|
140
|
+
<key>name</key>
|
|
141
|
+
<string>Operator</string>
|
|
142
|
+
<key>scope</key>
|
|
143
|
+
<string>keyword.operator</string>
|
|
144
|
+
<key>settings</key>
|
|
145
|
+
<dict>
|
|
146
|
+
<key>fontStyle</key>
|
|
147
|
+
<string></string>
|
|
148
|
+
<key>foreground</key>
|
|
149
|
+
<string>#2B0000</string>
|
|
150
|
+
</dict>
|
|
151
|
+
</dict>
|
|
152
|
+
|
|
153
|
+
<dict>
|
|
154
|
+
<key>name</key>
|
|
155
|
+
<string>Storage</string>
|
|
156
|
+
<key>scope</key>
|
|
157
|
+
<string>storage</string>
|
|
158
|
+
<key>settings</key>
|
|
159
|
+
<dict>
|
|
160
|
+
<key>fontStyle</key>
|
|
161
|
+
<string></string>
|
|
162
|
+
<key>foreground</key>
|
|
163
|
+
<string>#7E0A00</string>
|
|
164
|
+
</dict>
|
|
165
|
+
</dict>
|
|
166
|
+
|
|
167
|
+
<dict>
|
|
168
|
+
<key>name</key>
|
|
169
|
+
<string>Support</string>
|
|
170
|
+
<key>scope</key>
|
|
171
|
+
<string>support</string>
|
|
172
|
+
<key>settings</key>
|
|
173
|
+
<dict>
|
|
174
|
+
<key>fontStyle</key>
|
|
175
|
+
<string></string>
|
|
176
|
+
<key>foreground</key>
|
|
177
|
+
<string>#C44C54</string>
|
|
178
|
+
</dict>
|
|
179
|
+
</dict>
|
|
180
|
+
|
|
181
|
+
<dict>
|
|
182
|
+
<key>name</key>
|
|
183
|
+
<string>Support Function</string>
|
|
184
|
+
<key>scope</key>
|
|
185
|
+
<string>support.function</string>
|
|
186
|
+
<key>settings</key>
|
|
187
|
+
<dict>
|
|
188
|
+
<key>fontStyle</key>
|
|
189
|
+
<string></string>
|
|
190
|
+
<key>foreground</key>
|
|
191
|
+
<string>#C02125</string>
|
|
192
|
+
</dict>
|
|
193
|
+
</dict>
|
|
194
|
+
|
|
195
|
+
<dict>
|
|
196
|
+
<key>name</key>
|
|
197
|
+
<string>String</string>
|
|
198
|
+
<key>scope</key>
|
|
199
|
+
<string>string</string>
|
|
200
|
+
<key>settings</key>
|
|
201
|
+
<dict>
|
|
202
|
+
<key>fontStyle</key>
|
|
203
|
+
<string></string>
|
|
204
|
+
<key>foreground</key>
|
|
205
|
+
<string>#BF8D00</string>
|
|
206
|
+
</dict>
|
|
207
|
+
</dict>
|
|
208
|
+
|
|
209
|
+
<dict>
|
|
210
|
+
<key>name</key>
|
|
211
|
+
<string>Variable</string>
|
|
212
|
+
<key>scope</key>
|
|
213
|
+
<string>variable</string>
|
|
214
|
+
<key>settings</key>
|
|
215
|
+
<dict>
|
|
216
|
+
<key>fontStyle</key>
|
|
217
|
+
<string></string>
|
|
218
|
+
<key>foreground</key>
|
|
219
|
+
<string>#7E000E</string>
|
|
220
|
+
</dict>
|
|
221
|
+
</dict>
|
|
222
|
+
|
|
223
|
+
<dict>
|
|
224
|
+
<key>name</key>
|
|
225
|
+
<string>String constant</string>
|
|
226
|
+
<key>scope</key>
|
|
227
|
+
<string>string constant</string>
|
|
228
|
+
<key>settings</key>
|
|
229
|
+
<dict>
|
|
230
|
+
<key>fontStyle</key>
|
|
231
|
+
<string></string>
|
|
232
|
+
<key>foreground</key>
|
|
233
|
+
<string>#9E9B08</string>
|
|
234
|
+
</dict>
|
|
235
|
+
</dict>
|
|
236
|
+
|
|
237
|
+
<dict>
|
|
238
|
+
<key>name</key>
|
|
239
|
+
<string>Invalid</string>
|
|
240
|
+
<key>scope</key>
|
|
241
|
+
<string>invalid</string>
|
|
242
|
+
<key>settings</key>
|
|
243
|
+
<dict>
|
|
244
|
+
<key>fontStyle</key>
|
|
245
|
+
<string></string>
|
|
246
|
+
<key>foreground</key>
|
|
247
|
+
<string>#7E0A00</string>
|
|
248
|
+
</dict>
|
|
249
|
+
</dict>
|
|
250
|
+
|
|
251
|
+
</array>
|
|
252
|
+
<key>uuid</key>
|
|
253
|
+
<string>446e604a-ad3e-3292-b443-2ee9307764b4</string>
|
|
254
|
+
</dict>
|
|
255
|
+
</plist>
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { XMLParser } from "fast-xml-parser";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
|
|
5
|
+
const rootDirectory = process.cwd();
|
|
6
|
+
const docsDirectory = path.join(rootDirectory, "docs");
|
|
7
|
+
const metadataPath = path.join(rootDirectory, "metadata", "themes.json");
|
|
8
|
+
const siteDataPath = path.join(docsDirectory, "site-data.json");
|
|
9
|
+
const shouldCheck = process.argv.includes("--check");
|
|
10
|
+
const shouldWrite = process.argv.includes("--write");
|
|
11
|
+
|
|
12
|
+
const parser = new XMLParser({
|
|
13
|
+
ignoreAttributes: false,
|
|
14
|
+
preserveOrder: true,
|
|
15
|
+
trimValues: false,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {{
|
|
20
|
+
* readonly background?: string;
|
|
21
|
+
* readonly fontStyle?: string;
|
|
22
|
+
* readonly foreground?: string;
|
|
23
|
+
* readonly scope: string;
|
|
24
|
+
* }} PreviewRule
|
|
25
|
+
*
|
|
26
|
+
* @typedef {{
|
|
27
|
+
* readonly appearance: string;
|
|
28
|
+
* readonly author: null | string;
|
|
29
|
+
* readonly colors: Record<string, null | string>;
|
|
30
|
+
* readonly fileName: string;
|
|
31
|
+
* readonly id: string;
|
|
32
|
+
* readonly name: string;
|
|
33
|
+
* readonly path: string;
|
|
34
|
+
* readonly rules: readonly PreviewRule[];
|
|
35
|
+
* readonly statistics: Record<string, number>;
|
|
36
|
+
* readonly uuid: string;
|
|
37
|
+
* }} PreviewTheme
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @returns {Promise<Record<string, unknown>>}
|
|
42
|
+
*/
|
|
43
|
+
async function buildSiteData() {
|
|
44
|
+
const metadata = await readJson(metadataPath);
|
|
45
|
+
const themes = getThemes(metadata);
|
|
46
|
+
const previewThemes = await Promise.all(
|
|
47
|
+
themes.map((theme) => buildThemePreview(theme))
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
generatedBy: "npm run pages:build",
|
|
52
|
+
sourceManifest: "metadata/themes.json",
|
|
53
|
+
themeCount: previewThemes.length,
|
|
54
|
+
themes: previewThemes,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {Record<string, unknown>} theme
|
|
60
|
+
*
|
|
61
|
+
* @returns {Promise<PreviewTheme>}
|
|
62
|
+
*/
|
|
63
|
+
async function buildThemePreview(theme) {
|
|
64
|
+
const themePath = getRequiredString(theme, "path");
|
|
65
|
+
const absoluteThemePath = path.join(rootDirectory, themePath);
|
|
66
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Theme paths come from the committed metadata manifest.
|
|
67
|
+
const text = await readFile(absoluteThemePath, "utf8");
|
|
68
|
+
const parsedDocument = /** @type {unknown} */ (parser.parse(text));
|
|
69
|
+
const topLevelEntries = getTopLevelDictionary(parsedDocument);
|
|
70
|
+
const settings = getThemeSettings(topLevelEntries);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
appearance: getRequiredString(theme, "appearance"),
|
|
74
|
+
author: getNullableString(theme, "author"),
|
|
75
|
+
colors: getRecord(theme, "colors"),
|
|
76
|
+
fileName: getRequiredString(theme, "fileName"),
|
|
77
|
+
id: getRequiredString(theme, "id"),
|
|
78
|
+
name: getRequiredString(theme, "name"),
|
|
79
|
+
path: themePath,
|
|
80
|
+
rules: getPreviewRules(settings),
|
|
81
|
+
statistics: getNumberRecord(theme, "statistics"),
|
|
82
|
+
uuid: getRequiredString(theme, "uuid"),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {Record<string, unknown>} record
|
|
88
|
+
* @param {string} key
|
|
89
|
+
*
|
|
90
|
+
* @returns {readonly unknown[] | undefined}
|
|
91
|
+
*/
|
|
92
|
+
function getArrayProperty(record, key) {
|
|
93
|
+
const value = record[key];
|
|
94
|
+
return isUnknownArray(value) ? value : undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param {string} siteDataJson
|
|
99
|
+
*
|
|
100
|
+
* @returns {Promise<number>}
|
|
101
|
+
*/
|
|
102
|
+
async function getCheckExitCode(siteDataJson) {
|
|
103
|
+
const existingSiteData = await readExistingSiteData();
|
|
104
|
+
|
|
105
|
+
if (existingSiteData === siteDataJson) {
|
|
106
|
+
process.stdout.write("GitHub Pages site data is up to date.\n");
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
process.stderr.write(
|
|
111
|
+
"GitHub Pages site data is stale. Run `npm run pages:build`.\n"
|
|
112
|
+
);
|
|
113
|
+
return 1;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @param {readonly unknown[]} dictChildren
|
|
118
|
+
*
|
|
119
|
+
* @returns {ReadonlyMap<string, unknown>}
|
|
120
|
+
*/
|
|
121
|
+
function getDictionaryEntries(dictChildren) {
|
|
122
|
+
/** @type {Map<string, unknown>} */
|
|
123
|
+
const entries = new Map();
|
|
124
|
+
/** @type {string | undefined} */
|
|
125
|
+
let currentKey;
|
|
126
|
+
|
|
127
|
+
for (const child of dictChildren) {
|
|
128
|
+
if (hasOwnRecordKey(child, "key")) {
|
|
129
|
+
currentKey = getTextNodeValue(child.key);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (currentKey !== undefined && !hasOwnRecordKey(child, "#text")) {
|
|
134
|
+
entries.set(currentKey, child);
|
|
135
|
+
currentKey = undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return entries;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @param {ReadonlyMap<string, unknown>} entries
|
|
144
|
+
* @param {string} key
|
|
145
|
+
*
|
|
146
|
+
* @returns {ReadonlyMap<string, unknown>}
|
|
147
|
+
*/
|
|
148
|
+
function getDictionaryValue(entries, key) {
|
|
149
|
+
const value = entries.get(key);
|
|
150
|
+
|
|
151
|
+
if (!isRecord(value)) {
|
|
152
|
+
return new Map();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const dictChildren = getArrayProperty(value, "dict");
|
|
156
|
+
return dictChildren === undefined
|
|
157
|
+
? new Map()
|
|
158
|
+
: getDictionaryEntries(dictChildren);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @param {Record<string, unknown>} record
|
|
163
|
+
* @param {string} key
|
|
164
|
+
*
|
|
165
|
+
* @returns {null | string}
|
|
166
|
+
*/
|
|
167
|
+
function getNullableString(record, key) {
|
|
168
|
+
const value = record[key];
|
|
169
|
+
|
|
170
|
+
if (value === null || typeof value === "string") {
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {Record<string, unknown>} record
|
|
179
|
+
* @param {string} key
|
|
180
|
+
*
|
|
181
|
+
* @returns {Record<string, number>}
|
|
182
|
+
*/
|
|
183
|
+
function getNumberRecord(record, key) {
|
|
184
|
+
const value = record[key];
|
|
185
|
+
|
|
186
|
+
if (!isRecord(value)) {
|
|
187
|
+
return {};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** @type {Record<string, number>} */
|
|
191
|
+
const numberRecord = {};
|
|
192
|
+
|
|
193
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
194
|
+
if (typeof entryValue === "number") {
|
|
195
|
+
numberRecord[entryKey] = entryValue;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return numberRecord;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @param {ReadonlyMap<string, unknown>} settings
|
|
204
|
+
* @param {string} key
|
|
205
|
+
*
|
|
206
|
+
* @returns {string | undefined}
|
|
207
|
+
*/
|
|
208
|
+
function getOptionalString(settings, key) {
|
|
209
|
+
const value = settings.get(key);
|
|
210
|
+
|
|
211
|
+
if (!isRecord(value)) {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return getTextNodeValue(value.string);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @param {readonly unknown[]} settingsArray
|
|
220
|
+
*
|
|
221
|
+
* @returns {readonly PreviewRule[]}
|
|
222
|
+
*/
|
|
223
|
+
function getPreviewRules(settingsArray) {
|
|
224
|
+
return settingsArray.flatMap((item) => {
|
|
225
|
+
if (!hasOwnRecordKey(item, "dict")) {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const dictChildren = getArrayProperty(item, "dict");
|
|
230
|
+
const entries =
|
|
231
|
+
dictChildren === undefined
|
|
232
|
+
? new Map()
|
|
233
|
+
: getDictionaryEntries(dictChildren);
|
|
234
|
+
const scope = getOptionalString(entries, "scope");
|
|
235
|
+
|
|
236
|
+
if (scope === undefined) {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const settings = getDictionaryValue(entries, "settings");
|
|
241
|
+
const foreground = getOptionalString(settings, "foreground");
|
|
242
|
+
const background = getOptionalString(settings, "background");
|
|
243
|
+
const fontStyle = getOptionalString(settings, "fontStyle");
|
|
244
|
+
|
|
245
|
+
return scope
|
|
246
|
+
.split(",")
|
|
247
|
+
.map((scopePart) => scopePart.trim())
|
|
248
|
+
.filter((scopePart) => scopePart.length > 0)
|
|
249
|
+
.map((scopePart) => ({
|
|
250
|
+
...(background === undefined ? {} : { background }),
|
|
251
|
+
...(fontStyle === undefined ? {} : { fontStyle }),
|
|
252
|
+
...(foreground === undefined ? {} : { foreground }),
|
|
253
|
+
scope: scopePart,
|
|
254
|
+
}));
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @param {Record<string, unknown>} record
|
|
260
|
+
* @param {string} key
|
|
261
|
+
*
|
|
262
|
+
* @returns {Record<string, null | string>}
|
|
263
|
+
*/
|
|
264
|
+
function getRecord(record, key) {
|
|
265
|
+
const value = record[key];
|
|
266
|
+
|
|
267
|
+
if (!isRecord(value)) {
|
|
268
|
+
return {};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return Object.fromEntries(
|
|
272
|
+
Object.entries(value).map(([entryKey, entryValue]) => [
|
|
273
|
+
entryKey,
|
|
274
|
+
typeof entryValue === "string" ? entryValue : null,
|
|
275
|
+
])
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* @param {Record<string, unknown>} record
|
|
281
|
+
* @param {string} key
|
|
282
|
+
*
|
|
283
|
+
* @returns {string}
|
|
284
|
+
*/
|
|
285
|
+
function getRequiredString(record, key) {
|
|
286
|
+
const value = record[key];
|
|
287
|
+
|
|
288
|
+
if (typeof value !== "string") {
|
|
289
|
+
throw new TypeError(`Expected string field: ${key}`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return value;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* @param {unknown} value
|
|
297
|
+
*
|
|
298
|
+
* @returns {string | undefined}
|
|
299
|
+
*/
|
|
300
|
+
function getTextNodeValue(value) {
|
|
301
|
+
if (!isUnknownArray(value)) {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const firstValue = value[0];
|
|
306
|
+
if (!isRecord(firstValue)) {
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const textValue = firstValue["#text"];
|
|
311
|
+
return typeof textValue === "string" ? textValue : undefined;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* @param {unknown} metadata
|
|
316
|
+
*
|
|
317
|
+
* @returns {readonly Record<string, unknown>[]}
|
|
318
|
+
*/
|
|
319
|
+
function getThemes(metadata) {
|
|
320
|
+
if (!isRecord(metadata) || !isUnknownArray(metadata.themes)) {
|
|
321
|
+
throw new TypeError("metadata/themes.json does not contain themes.");
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return metadata.themes.filter((theme) => isRecord(theme));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* @param {ReadonlyMap<string, unknown>} topLevelEntries
|
|
329
|
+
*
|
|
330
|
+
* @returns {readonly unknown[]}
|
|
331
|
+
*/
|
|
332
|
+
function getThemeSettings(topLevelEntries) {
|
|
333
|
+
const settingsNode = topLevelEntries.get("settings");
|
|
334
|
+
|
|
335
|
+
if (!isRecord(settingsNode)) {
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return getArrayProperty(settingsNode, "array") ?? [];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* @param {unknown} parsedDocument
|
|
344
|
+
*
|
|
345
|
+
* @returns {ReadonlyMap<string, unknown>}
|
|
346
|
+
*/
|
|
347
|
+
function getTopLevelDictionary(parsedDocument) {
|
|
348
|
+
if (!isUnknownArray(parsedDocument)) {
|
|
349
|
+
return new Map();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const plistNode = parsedDocument.find((node) =>
|
|
353
|
+
hasOwnRecordKey(node, "plist")
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
if (!isRecord(plistNode)) {
|
|
357
|
+
return new Map();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const plistChildren = getArrayProperty(plistNode, "plist");
|
|
361
|
+
if (plistChildren === undefined) {
|
|
362
|
+
return new Map();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const dictNode = plistChildren.find((node) =>
|
|
366
|
+
hasOwnRecordKey(node, "dict")
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
if (!isRecord(dictNode)) {
|
|
370
|
+
return new Map();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const dictChildren = getArrayProperty(dictNode, "dict");
|
|
374
|
+
return dictChildren === undefined
|
|
375
|
+
? new Map()
|
|
376
|
+
: getDictionaryEntries(dictChildren);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @param {unknown} value
|
|
381
|
+
* @param {string} key
|
|
382
|
+
*
|
|
383
|
+
* @returns {value is Record<string, unknown>}
|
|
384
|
+
*/
|
|
385
|
+
function hasOwnRecordKey(value, key) {
|
|
386
|
+
return isRecord(value) && Object.hasOwn(value, key);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* @param {unknown} value
|
|
391
|
+
*
|
|
392
|
+
* @returns {value is Record<string, unknown>}
|
|
393
|
+
*/
|
|
394
|
+
function isRecord(value) {
|
|
395
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* @param {unknown} value
|
|
400
|
+
*
|
|
401
|
+
* @returns {value is readonly unknown[]}
|
|
402
|
+
*/
|
|
403
|
+
function isUnknownArray(value) {
|
|
404
|
+
return Array.isArray(value);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @returns {Promise<number>}
|
|
409
|
+
*/
|
|
410
|
+
async function main() {
|
|
411
|
+
if (shouldCheck === shouldWrite) {
|
|
412
|
+
process.stderr.write("Specify exactly one of --check or --write.\n");
|
|
413
|
+
return 1;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const siteData = await buildSiteData();
|
|
417
|
+
const siteDataJson = `${JSON.stringify(siteData, null, 4)}\n`;
|
|
418
|
+
|
|
419
|
+
if (shouldCheck) {
|
|
420
|
+
return getCheckExitCode(siteDataJson);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
await mkdir(docsDirectory, { recursive: true });
|
|
424
|
+
await writeFile(siteDataPath, siteDataJson, "utf8");
|
|
425
|
+
process.stdout.write("Wrote docs/site-data.json.\n");
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* @returns {Promise<string>}
|
|
431
|
+
*/
|
|
432
|
+
async function readExistingSiteData() {
|
|
433
|
+
try {
|
|
434
|
+
return await readFile(siteDataPath, "utf8");
|
|
435
|
+
} catch {
|
|
436
|
+
return "";
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* @param {string} filePath
|
|
442
|
+
*
|
|
443
|
+
* @returns {Promise<unknown>}
|
|
444
|
+
*/
|
|
445
|
+
async function readJson(filePath) {
|
|
446
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- JSON paths are fixed repo-local paths.
|
|
447
|
+
const text = await readFile(filePath, "utf8");
|
|
448
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return -- This is the typed boundary for a generated repo-local JSON file.
|
|
449
|
+
return JSON.parse(text);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* @returns {Promise<void>}
|
|
454
|
+
*/
|
|
455
|
+
async function run() {
|
|
456
|
+
try {
|
|
457
|
+
process.exitCode = await main();
|
|
458
|
+
} catch (error) {
|
|
459
|
+
process.stderr.write(`${String(error)}\n`);
|
|
460
|
+
process.exitCode = 1;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// eslint-disable-next-line unicorn/prefer-top-level-await -- This published-module config also enforces n/no-top-level-await.
|
|
465
|
+
void run();
|