mollenhauer

Форк
0
/
setup.js 
487 строк · 13.6 Кб
1
import fs from 'fs-extra'
2
import replace from 'replace-in-file'
3
import { log } from 'console'
4
import enquirer from 'enquirer'
5
import chalk from 'chalk'
6

7
class ModuleObject {
8
  constructor(config = {}) {
9
    this.moduleName = null
10
    this.filesAndFolders = null
11
    this.htmlConnectStrings = null
12

13
    Object.assign(this, config)
14
  }
15
}
16
class VariableTemplate {
17
  constructor(config = {}) {
18
    this.fields = null
19
    this.message = null
20
    this.template = null
21
    this.snippetName = null
22
    this.variableFilePath = null
23

24
    Object.assign(this, config)
25
  }
26
}
27

28
const pathToProject = './',
29
  distFolderName = pathToProject + 'dist/',
30
  snippetsFolderName = pathToProject + 'snippets/',
31
  readmeFolder = pathToProject + 'readmeFiles/',
32
  sources = pathToProject + 'sources/',
33
  readmeFilePath = pathToProject + 'README.md',
34
  scriptsFolder = sources + 'scripts/',
35
  stylesFolder = sources + 'styles/',
36
  componentsFolder = sources + 'components/',
37
  assets = sources + 'assets/',
38
  environmentFilePath = stylesFolder + '_environment.pcss',
39
  baseStyleFile = stylesFolder + 'normalize.pcss',
40
  stateStyleFile = stylesFolder + 'thirdLevelRules.pcss',
41
  layoutHtmlFile = componentsFolder + 'layout.html',
42
  fontsGitkeep = sources + 'fonts/.gitkeep',
43
  indexPage = sources + 'index.html'
44

45

46
logSomeImportantInConsole(
47
  `Salute!
48
You will have to use some keys, such as: 
49
${chalk.greenBright('↑')} - focus up,
50
${chalk.greenBright('↓')} - focus down,
51
${chalk.greenBright('← →')} - choosing between elements on the same line,
52
${chalk.greenBright('space')} - to select an option,
53
${chalk.greenBright('⭾')} - tab, to move to a next element, for example, in templates.
54
`,
55
  chalk.green
56
)
57

58
await enquirer.toggle({
59
  message: chalk.italic('Any questions?'),
60
  enabled: chalk.magenta('Nope, i totally understand!'),
61
  disabled: chalk.magenta('Nope, i understand!'),
62
})
63

64

65
await includeModuleByQuestion(
66
  'Whether you want to save the plugin...',
67

68
  new ModuleObject({
69
    moduleName: 'Just Validate',
70
    filesAndFolders: assets + 'justValidate/',
71
    htmlConnectStrings: { strings: `justValidate=false` },
72
  }),
73
  new ModuleObject({
74
    moduleName: 'Slider Swiper',
75
    filesAndFolders: assets + 'swiper/',
76
    htmlConnectStrings: { strings: `swiper=false` },
77
  }),
78
  new ModuleObject({
79
    moduleName: 'Typed',
80
    filesAndFolders: assets + 'typed/',
81
    htmlConnectStrings: { strings: `typed=false` },
82
  }),
83
  new ModuleObject({
84
    moduleName: 'Input Mask',
85
    filesAndFolders: assets + 'inputmask.min.js',
86
  }),
87
  new ModuleObject({
88
    moduleName: 'Photo Swipe',
89
    filesAndFolders: assets + 'photoswipe/',
90
    htmlConnectStrings: { strings: `photoSwipe=false` },
91
  }),
92
  new ModuleObject({
93
    moduleName: 'No Ui Slider',
94
    filesAndFolders: assets + 'nouislider/',
95
    htmlConnectStrings: { strings: `noUiSlider=false` },
96
  })
97
)
98
await includeModuleByQuestion(
99
  'Whether you want to save the module...',
100

101
  new ModuleObject({
102
    moduleName: 'Scripts for dialog',
103
    filesAndFolders: [
104
      scriptsFolder + 'dialogs/',
105
      componentsFolder + 'modals.html',
106
    ],
107
    htmlConnectStrings: [
108
      { strings: `<x-modals></x-modals>`, },
109
      { strings: `dialogs=false` },
110
    ],
111
  }),
112
  new ModuleObject({
113
    moduleName: 'Tabs',
114
    filesAndFolders: scriptsFolder + 'tab/',
115
    htmlConnectStrings: [
116
      { strings: `tabs=false` }
117
    ],
118
  }),
119
  new ModuleObject({
120
    moduleName: 'Parallax by mouse',
121
    filesAndFolders: scriptsFolder + 'mouseParallax/',
122
    htmlConnectStrings: [
123
      { strings: `mouseParallax=false` }
124
    ],
125
  }),
126
  new ModuleObject({
127
    moduleName: 'AutoScrollPadding',
128
    filesAndFolders: scriptsFolder + 'autoScrollPadding/',
129
    htmlConnectStrings: [
130
      { strings: `autoScrollPadding=false` }
131
    ],
132
  }),
133
  new ModuleObject({
134
    moduleName: 'Tools for observer',
135
    filesAndFolders: scriptsFolder + 'observerTools/',
136
    htmlConnectStrings: [
137
      { strings: `observerTools=false` }
138
    ],
139
  }),
140
  new ModuleObject({
141
    moduleName: 'Horizontal scroll by mouse wheel',
142
    filesAndFolders: scriptsFolder + 'horizontalMouseScroll.ts',
143
    htmlConnectStrings: [
144
      { strings: `horizontalMouseScroll=false` }
145
    ],
146
  }),
147
  new ModuleObject({
148
    moduleName: 'Switching by swipe',
149
    filesAndFolders: scriptsFolder + 'toggleBySwipe/',
150
    htmlConnectStrings: [
151
      { strings: `toggleBySwipe=false` }
152
    ],
153
  }),
154
  new ModuleObject({
155
    moduleName: 'Step By Step block',
156
    filesAndFolders: scriptsFolder + 'stepByStepBlock/',
157
    htmlConnectStrings: [
158
      { strings: `stepByStep=false` }
159
    ],
160
  }),
161
  new ModuleObject({
162
    moduleName: 'scroll-timeline polyfill',
163
    filesAndFolders: scriptsFolder + 'scroll-timeline.js',
164
    htmlConnectStrings: [
165
      { strings: `scrollTimeline=false` }
166
    ],
167
  }),
168
  new ModuleObject({
169
    moduleName: 'Infinite auto-scroll',
170
    filesAndFolders: scriptsFolder + 'infiniteScroll/',
171
    htmlConnectStrings: [
172
      { strings: `infiniteScroll=false` }
173
    ],
174
  }),
175
)
176

177

178
logSomeImportantInConsole(
179
  `\nThe configuration of files and folders is complete.\n`,
180
  chalk.greenBright
181
)
182
logSomeImportantInConsole(
183
  `\nNow, i suggest you change the values of the main variables.\n`,
184
  chalk.magentaBright
185
)
186

187
await setVariables(
188
  new VariableTemplate({
189
    snippetName: 'htmlLayout',
190
    message: chalk.cyanBright('Fill in the fields in the html-layout.'),
191
    variableFilePath: layoutHtmlFile,
192
    fields: [
193
      { name: 'mainLangOfPages', initial: 'en' },
194
      { name: 'preloadedFontFilename', initial: 'none', },
195
    ],
196
    template:
197
      `// Set the main language of pages below.
198
  lang: '\${mainLangOfPages}',
199
  // Set a name for a preloaded font. Must be a file name without extension.
200
  preloadedFontName: '\${preloadedFontFilename}',`
201
  }),
202

203
  new VariableTemplate({
204
    snippetName: 'Title of index page',
205
    message: chalk.cyanBright('Title of index page...'),
206
    variableFilePath: indexPage,
207
    fields: [
208
      { name: 'title', initial: 'Unnamed Page' },
209
    ],
210
    template:
211
      `<x-layout title='\${title}'`
212
  }),
213

214
  new VariableTemplate({
215
    snippetName: 'stylesheetVariables',
216
    message: chalk.cyanBright(
217
      `Fill in some css variables (file - ${chalk.underline(baseStyleFile)}).`),
218
    variableFilePath: baseStyleFile,
219
    fields: [
220
      { name: 'mainFontName', initial: 'arial', },
221
      { name: 'mainTextColor', initial: 'black', },
222
      { name: 'backgroundColor', initial: 'white', },
223
    ],
224
    template:
225
      `--main-font-family: \${mainFontName};
226
--main-text-color: \${mainTextColor};
227
--background: \${backgroundColor};`
228
  }),
229

230
  new VariableTemplate({
231
    snippetName: 'stylesheetSassLikeVariables',
232
    message: chalk.cyanBright(
233
      'Fill in sass-like variables that are used in custom media. \n'
234
      + `(file - ${chalk.underline(environmentFilePath)})`),
235
    variableFilePath: environmentFilePath,
236
    fields: [
237
      { name: 'widthOfYourDesignLayout', initial: '1440', },
238
      { name: 'minimalWidthOfYourDesign', initial: '320', },
239
      { name: 'mainSize', initial: '16', },
240
      { name: 'minSize', initial: '12', },
241
    ],
242
    template:
243
      `@custom-media --is-large-layout (width > $layoutWidth);
244
@custom-media --is-layout-width (769px <= width <= $layoutWidth);
245
@custom-media --is-tablet (426px <= width <= 769px);
246
@custom-media --is-mobile (width <= 426px);
247

248
$layoutWidth: \${widthOfYourDesignLayout}px;
249
$minLayoutWidth: \${minimalWidthOfYourDesign}px;
250
$mainFontSize: \${mainSize}px;
251
$minFontSize: \${minSize}px;`
252
  }),
253

254
  new VariableTemplate({
255
    snippetName: 'some name',
256
    message: chalk.cyanBright(
257
      'Set the values of the paddings that are assigned using the .content_paddings class (used to center content in blocks)\n'
258
      + `(file - ${chalk.underline(stateStyleFile)}.`),
259
    variableFilePath: stateStyleFile,
260
    fields: [
261
      { name: 'largePaddings', initial: '15vw', },
262
    ],
263
    template:
264
      `
265
@media (--is-large-layout) {
266
  --content-inline-padding: \${largePaddings};
267
}`,
268
  }),
269

270
  new VariableTemplate({
271
    snippetName: 'some name 2',
272
    message: chalk.cyan('Layout width...'),
273
    variableFilePath: stateStyleFile,
274
    fields: [
275
      { name: 'defaultPaddings', initial: '10vw', },
276
    ],
277
    template:
278
      `
279
@media (--is-layout-width) {
280
  --content-inline-padding: \${defaultPaddings};
281
}`,
282
  }),
283

284
  new VariableTemplate({
285
    snippetName: 'some name 3',
286
    message: chalk.cyan('Tablets...'),
287
    variableFilePath: stateStyleFile,
288
    fields: [
289
      { name: 'tabletPaddings', initial: '5vw', },
290
    ],
291
    template:
292
      `
293
@media (--is-tablet) {
294
  --content-inline-padding: \${tabletPaddings};
295
}`,
296
  }),
297

298
  new VariableTemplate({
299
    snippetName: 'some name 4',
300
    message: chalk.cyan('Mobiles...'),
301
    variableFilePath: stateStyleFile,
302
    fields: [
303
      { name: 'mobilePaddings', initial: '2.5vw', },
304
    ],
305
    template:
306
      `
307
@media (--is-mobile) {
308
  --content-inline-padding: \${mobilePaddings};
309
}`,
310
  }),
311
)
312

313
deleteUnnecessaryFilesAndFolders()
314

315

316
writeCompletelyPhrase()
317

318

319
async function includeModuleByQuestion(title, ...moduleObjects) {
320
  let selectedModules = await enquirer.multiselect({
321
    name: 'value',
322
    message: chalk.magentaBright(title),
323
    limit: 5,
324
    choices: moduleObjects.map(module => {
325
      return {
326
        name: module.moduleName, value: module.moduleName,
327
      }
328
    }),
329

330
    footer: () => chalk.gray.italic('use ↑ and ↓ to switch, you can "scroll" this list')
331
  })
332

333

334
  for (let module of moduleObjects) {
335
    let confirmedModuleName = selectedModules.find(answer => answer == module.moduleName)
336

337
    if (confirmedModuleName) {
338
      replaceHtmlConnectionString(module.htmlConnectStrings, 'false', 'true')
339
      continue
340
    }
341

342
    if (!Array.isArray(module.filesAndFolders))
343
      module.filesAndFolders = new Array(module.filesAndFolders)
344

345
    for (let fileOrFolder of module.filesAndFolders) {
346
      fs.removeSync(fileOrFolder)
347
    }
348

349
    replaceHtmlConnectionString(module.htmlConnectStrings)
350
  }
351
}
352
async function setVariables(...variableTemplates) {
353
  for (let variableTemplate of variableTemplates) {
354
    let result = await enquirer.snippet({
355
      name: variableTemplate.snippetName,
356
      message: variableTemplate.message + '\n',
357
      required: true,
358
      fields: variableTemplate.fields,
359
      template: variableTemplate.template,
360

361
      footer: () => chalk.gray.italic("use tab to move, when you're done, press enter")
362
    })
363

364
    let formattedTemplate = replaceEnquirerTemplateValues(
365
      variableTemplate.template,
366
      variableTemplate.fields,
367
      result.values,
368
      true
369
    )
370
    let newTemplate = replaceEnquirerTemplateValues(
371
      variableTemplate.template,
372
      variableTemplate.fields,
373
      result.values
374
    )
375

376
    let templateStrings = formattedTemplate.split('\n')
377
    let newTemplateStrings = newTemplate.split('\n')
378

379
    for (let i = 0; i < templateStrings.length; i++) {
380
      await replace({
381
        files: variableTemplate.variableFilePath,
382
        from: templateStrings[i],
383
        to: newTemplateStrings[i],
384
      })
385
    }
386
  }
387
}
388

389
function deleteUnnecessaryFilesAndFolders() {
390
  deleteFolder(readmeFolder, 'The readme folder have been deleted.')
391
  deleteFolder(readmeFilePath)
392
  fs.createFileSync('README.md')
393

394
  log(chalk.gray.italic('✅ The readme file are clean.'))
395

396
  deleteFolder(distFolderName, 'Dist have been deleted.')
397
  deleteFolder(snippetsFolderName, 'Snippets have been deleted.')
398
  deleteFolder(fontsGitkeep, 'Gitkeep in fonts have been deleted.')
399
}
400

401
function replaceHtmlConnectionString(htmlConnectStrings, replacedValue, replacedNewValue) {
402
  if (!htmlConnectStrings) return
403

404
  if (!Array.isArray(htmlConnectStrings))
405
    htmlConnectStrings = new Array(htmlConnectStrings)
406

407
  for (let htmlConnectStringData of htmlConnectStrings) {
408
    if (!htmlConnectStringData.path)
409
      htmlConnectStringData.path = indexPage
410

411
    let newHtmlConnectString
412

413
    if (!replacedValue || !replacedNewValue) {
414
      newHtmlConnectString = ''
415
    } else {
416
      newHtmlConnectString = htmlConnectStringData.strings.replace(replacedValue, replacedNewValue)
417
    }
418

419
    replace.sync({
420
      files: htmlConnectStringData.path,
421
      from: htmlConnectStringData.strings, to: newHtmlConnectString,
422
    })
423
  }
424
}
425
function deleteFolder(folderPath, messageOnSuccessful) {
426
  try {
427
    fs.removeSync(folderPath)
428

429
    if (messageOnSuccessful)
430
      log(chalk.gray.italic('✅ ' + messageOnSuccessful))
431
  }
432
  catch (error) {
433
    log(chalk.red('❌ ' + error))
434
  }
435
}
436
function replaceEnquirerTemplateValues(template, fields, values, replaceNamesToDefaults) {
437
  let newTemplate = template
438

439
  if (replaceNamesToDefaults) {
440
    for (let field of fields) {
441
      newTemplate = newTemplate.replaceAll(
442
        '${' + field.name + '}',
443
        field.initial ?? ''
444
      )
445
    }
446
  }
447
  else {
448
    for (let field of fields) {
449
      newTemplate = newTemplate.replaceAll(
450
        '${' + field.name + '}',
451
        values[field.name] ?? field.initial
452
      )
453
    }
454
  }
455

456
  return newTemplate
457
}
458
function logSomeImportantInConsole(message, chalkColor) {
459
  log(chalkColor(message))
460
}
461

462
function writeCompletelyPhrase() {
463
  let
464
    topPhrase = 'The setup is completely complete!',
465
    middlePhrase = 'I wish You a successful job.',
466
    bottomPhrase = '🎆🎆🎆',
467

468
    positionOfTop = Math.round(process.stdout.columns / 2) - Math.round(topPhrase.length / 2),
469
    positionOfMiddle = Math.round(process.stdout.columns / 2) - Math.round(middlePhrase.length / 2),
470
    positionOfBottom = Math.round(process.stdout.columns / 2) - Math.round(bottomPhrase.length / 2)
471

472
  topPhrase = ' '.repeat(positionOfTop) + topPhrase
473
  middlePhrase = ' '.repeat(positionOfMiddle) + middlePhrase
474
  bottomPhrase = ' '.repeat(positionOfBottom) + bottomPhrase
475

476
  logSomeImportantInConsole(
477
    '\n'
478
    + topPhrase + '\n'
479
    + middlePhrase + '\n'
480
    + bottomPhrase + '\n'
481

482
    , chalk.greenBright
483
  )
484

485
  // An empty line to correct one error in the visualization
486
  console.log('')
487
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.