1
+ #!/usr/bin/env node
2
+
3
+ // NodeJS script to create the icon components modules:
4
+ // src/icons/icons.js
5
+ // src/icons/plugin.js
6
+ // src/icons/icons.d.ts
7
+ //
8
+ // Source is bootstrap-icons/icons
9
+ import { promises as fsPromises , readdirSync , writeFileSync } from 'fs'
10
+ import { fileURLToPath } from 'url' ;
11
+ import * as path from 'path'
12
+ import lodash from 'lodash'
13
+ // for now we will have duplicate utils until the main package
14
+ // removes bootstrap as a JS dependency
15
+ import { pascalCase } from 'bootstrap-vue-3-icons'
16
+
17
+
18
+ // Bootstrap Icons package.json
19
+ /* eslint-disable no-eval */
20
+ import bsIconsPkg from '../package.json' assert { type : 'json '}
21
+
22
+
23
+ // BootstrapVue icons package.json
24
+ // import IconsPkg from '../src/components/Icons/package.json' assert {type: 'json'}
25
+
26
+ import { createRequire } from "module" ;
27
+
28
+ const require = createRequire ( import . meta. url ) ;
29
+ const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) )
30
+
31
+ //Bootstrap icon asssets and SVGs
32
+ const bootstrapIconsBase = path . dirname ( require . resolve ( 'bootstrap-icons/package.json' ) )
33
+ const bootstrapIconsDir = path . join ( bootstrapIconsBase , 'icons/' )
34
+ const bsIconsMetaFile = path . join ( bootstrapIconsBase , 'package.json' )
35
+
36
+ //Bootstrap vue Icons - where all output files will be relative too
37
+ const bvBase = path . resolve ( __dirname , '..' )
38
+ const bvIconsBase = path . join ( bvBase , 'src' , 'components' , 'Icons' )
39
+
40
+ const iconsFile = path . resolve ( bvIconsBase , 'icons.ts' )
41
+ const pluginFile = path . resolve ( bvIconsBase , 'plugin.js' )
42
+ const typesFile = path . resolve ( bvIconsBase , 'icons.d.ts' )
43
+ const bvIconsPkgFile = path . resolve ( bvIconsBase , 'package.json' )
44
+
45
+ // // --- Constants ---
46
+
47
+
48
+ // // BootstrapVue icons package.json
49
+ // const bvIconsPkg = require(bvIconsPkgFile)
50
+
51
+ // if (bvIconsPkg.meta['bootstrap-icons-version'] === bsIconsPkg.version) {
52
+ // // Exit early of no changes in bootstrap-icons version
53
+ // // Should also test if `src/icons/helper/make-icons.js` has changed (i.e. new props)
54
+ // // console.log(' No changes detected in bootstrap-icons version')
55
+ // // Commented out until this build process is stabilized
56
+ // // exit 0
57
+ // }
58
+
59
+ // Template for `src/icons/icons.js`
60
+ const iconsTemplateFn = lodash . template ( `// --- BEGIN AUTO-GENERATED FILE ---
61
+ //
62
+ // @IconsVersion: <%= version %>
63
+ // @Generated: <%= created %>
64
+ //
65
+ // This file is generated on each build. Do not edit this file!
66
+ /*!
67
+ * BootstrapVue Icons, generated from Bootstrap Icons <%= version %>
68
+ *
69
+ * @link <%= homepage %>
70
+ * @license <%= license %>
71
+ * https://github.com/twbs/icons/blob/master/LICENSE.md
72
+ */
73
+ import { makeIcon } from './helpers/make-icon'
74
+ // --- BootstrapVue custom icons ---
75
+ export const BIconBlank = /*#__PURE__*/ makeIcon('Blank', '')
76
+ // --- Bootstrap Icons ---
77
+ <% componentNames.forEach(component => { %>
78
+ // eslint-disable-next-line
79
+ export const <%= component %> = /*#__PURE__*/ makeIcon(
80
+ '<%= icons[component].name %>',
81
+ '<%= icons[component].content %>'
82
+ )
83
+ <% }) %>
84
+ // --- END AUTO-GENERATED FILE ---
85
+ ` )
86
+
87
+ // Template for `src/icons/plugin.js`
88
+ const pluginTemplateFn = lodash . template ( `// --- BEGIN AUTO-GENERATED FILE ---
89
+ //
90
+ // @IconsVersion: <%= version %>
91
+ // @Generated: <%= created %>
92
+ //
93
+ // This file is generated on each build. Do not edit this file!
94
+ // import { pluginFactoryNoConfig } from '../utils/plugins'
95
+ // Icon helper component
96
+ import BIcon from '../components/BIcon.vue'
97
+ // Icon stacking component
98
+ import BIconstack from '../components/BIconstack.vue'
99
+ import {
100
+ // BootstrapVue custom icons
101
+ BIconBlank,
102
+ // Bootstrap icons
103
+ <%= componentNames.join(',\\n ') %>
104
+ } from './icons'
105
+ // Icon component names for used in the docs
106
+ export const iconNames = [
107
+ // BootstrapVue custom icon component names
108
+ 'BIconBlank',
109
+ // Bootstrap icon component names
110
+ <%= componentNames.map(n => ("'" + n + "'")).join(',\\n ') %>
111
+ ]
112
+ // Export the icons plugin
113
+ // export const IconsPlugin = /*#__PURE__*/ pluginFactoryNoConfig({
114
+ // components: {
115
+ // // Icon helper component
116
+ // BIcon,
117
+ // // Icon stacking component
118
+ // BIconstack,
119
+ // // BootstrapVue custom icon components
120
+ // BIconBlank,
121
+ // // Bootstrap icon components
122
+ // <%= componentNames.join(',\\n ') %>
123
+ // }
124
+ // })
125
+ // Export the BootstrapVueIcons plugin installer
126
+ // Mainly for the stand-alone bootstrap-vue-icons.xxx.js builds
127
+ export const BootstrapVueIcons = /*#__PURE__*/ pluginFactoryNoConfig(
128
+ { plugins: { IconsPlugin } },
129
+ { NAME: 'BootstrapVueIcons' }
130
+ )
131
+ // --- END AUTO-GENERATED FILE ---
132
+ ` )
133
+
134
+ // Template for `src/icons/icons.d.ts`
135
+ const typesTemplateFn = lodash . template ( `// --- BEGIN AUTO-GENERATED FILE ---
136
+ //
137
+ // @IconsVersion: <%= version %>
138
+ // @Generated: <%= created %>
139
+ //
140
+ // This file is generated on each build. Do not edit this file!
141
+ import Vue from 'vue'
142
+ import { BvComponent } from '../'
143
+ // --- BootstrapVue custom icons ---
144
+ export declare class BIconBlank extends BvComponent {}
145
+ // --- Bootstrap Icons ---
146
+ <% componentNames.forEach(component => { %>
147
+ export declare class <%= component %> extends BvComponent {}
148
+ <% }) %>
149
+ // --- END AUTO-GENERATED FILE ---
150
+ ` )
151
+
152
+ // // --- Utility methods ---
153
+
154
+
155
+
156
+ // Parses a single SVG File
157
+ const processFile = ( file , data ) => {
158
+ return new Promise ( ( resolve , reject ) => {
159
+ file = path . join ( bootstrapIconsDir , file )
160
+ if ( path . extname ( file ) !== '.svg' ) {
161
+ resolve ( )
162
+ return
163
+ }
164
+ const name = pascalCase ( path . basename ( file , '.svg' ) )
165
+ const componentName = `BIcon${ name } `
166
+ fsPromises . readFile ( file , 'utf8' )
167
+ . then ( svg => {
168
+ const content = svg
169
+ // Remove <svg ...> and </svg>
170
+ . replace ( / < s v g [ ^ > ] + > / i, '' )
171
+ . replace ( / < \/ s v g > / i, '' )
172
+ // Remove whitespace between elements
173
+ . replace ( / > \s + < / g, '><' )
174
+ // Fix broken stroke colors in some components
175
+ // Might be fixed in 1.0.0-alpha3 release
176
+ . replace ( ' stroke="#000"' , ' stroke="currentColor"' )
177
+ // Remove leading/trailing whitespace
178
+ . trim ( )
179
+ // Add to the iconsData object
180
+ data . icons [ componentName ] = { name, content }
181
+ data . componentNames . push ( componentName )
182
+ // Resolve
183
+ resolve ( )
184
+ } )
185
+ . catch ( error => reject ( error ) )
186
+ } )
187
+ }
188
+
189
+ // Method to generate the updated `package.json` content
190
+ const updatePkgMeta = data => {
191
+ // Create a semi-deep clone of the current `package.json`
192
+ const newPkg = { ...bvIconsPkg , meta : { ...bvIconsPkg . meta } }
193
+ // Grab current component entries array and filter out auto-generated entries
194
+ const metaComponents = bvIconsPkg . meta . components . filter ( c => ! c [ 'auto-gen' ] )
195
+ // Grab the props definition array from `BIcon` and filter out `icon` prop
196
+ const iconProps = metaComponents
197
+ . find ( m => m . component === 'BIcon' )
198
+ . props . filter ( p => p . prop !== 'icon' )
199
+ // Build the icon component entries
200
+ const iconMeta = data . componentNames . map ( name => {
201
+ return {
202
+ component : name ,
203
+ 'auto-gen' : `bootstrap-icons ${ data . version } ` ,
204
+ props : iconProps
205
+ }
206
+ } )
207
+ // Update the package components meta info
208
+ newPkg . meta . components = [ ...metaComponents , ...iconMeta ]
209
+ // Update the bootstrap-icons-version reference
210
+ newPkg . meta [ 'bootstrap-icons-version' ] = data . version
211
+ // Return the updated `package.json` as a json string
212
+ return `${ JSON . stringify ( newPkg , null , 2 ) } \n`
213
+ }
214
+
215
+ // --- Main process ---
216
+ const main = async ( ) => {
217
+ // Information needed in the templates
218
+ const today = new Date ( )
219
+ const data = {
220
+ version : bsIconsPkg . version ,
221
+ license : bsIconsPkg . license ,
222
+ homepage : bsIconsPkg . homepage ,
223
+ created : today . toISOString ( ) ,
224
+ componentNames : [ ] ,
225
+ icons : { }
226
+ }
227
+
228
+ console . log ( ` Reading SVGs from bootstrap-icons version ${ data . version } ` )
229
+
230
+ // Read in the list of SVG Files
231
+ const files = readdirSync ( bootstrapIconsDir )
232
+ // Process the SVG Data for all files
233
+ await Promise . all ( files . map ( file => processFile ( file , data ) ) )
234
+ // Sort the icon component names
235
+ data . componentNames = data . componentNames . sort ( )
236
+
237
+ console . log ( ` Read ${ data . componentNames . length } SVGs...` )
238
+
239
+ // Write out the files
240
+ console . log ( ' Creating icon components...' )
241
+ writeFileSync ( iconsFile , iconsTemplateFn ( data ) , 'utf8' )
242
+ console . log ( ` Wrote to ${ iconsFile } ` )
243
+ console . log ( ' Creating icon plugin...' )
244
+ writeFileSync ( pluginFile , pluginTemplateFn ( data ) , 'utf8' )
245
+ console . log ( ` Wrote to ${ pluginFile } ` )
246
+ console . log ( ' Creating type declarations...' )
247
+ writeFileSync ( typesFile , typesTemplateFn ( data ) , 'utf8' )
248
+ console . log ( ` Wrote to ${ typesFile } ` )
249
+ console . log ( ' Updating icons meta info...' )
250
+ // writeFileSync(bvIconsPkgFile, updatePkgMeta(data), 'utf8')
251
+ // console.log(` Wrote to ${bvIconsPkgFile}`)
252
+ }
253
+
254
+ main ( )
0 commit comments