@softlimit/theme-envy 0.1.2-alpha

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 (102) hide show
  1. package/.eslintrc.js +26 -0
  2. package/.github/CODEOWNERS +1 -0
  3. package/.github/workflows/release-please.yml +19 -0
  4. package/LICENSE +21 -0
  5. package/README.md +259 -0
  6. package/build/functions/failed-hook-installs.js +18 -0
  7. package/build/functions/get-all.js +102 -0
  8. package/build/functions/index.js +7 -0
  9. package/build/functions/liquid/functions/extend-liquid.js +77 -0
  10. package/build/functions/liquid/functions/flatten-shopify-directory-structure.js +29 -0
  11. package/build/functions/liquid/functions/index.js +6 -0
  12. package/build/functions/liquid/functions/list-dependencies.js +47 -0
  13. package/build/functions/liquid/functions/section-schema-inject.js +26 -0
  14. package/build/functions/liquid/index.js +36 -0
  15. package/build/functions/parent-theme-files.js +25 -0
  16. package/build/functions/tailwind.js +31 -0
  17. package/build/functions/theme-envy.js +85 -0
  18. package/build/functions/webpack.js +44 -0
  19. package/build/index.js +45 -0
  20. package/build/requires/assets.js +22 -0
  21. package/build/requires/config.js +44 -0
  22. package/build/requires/globals/index.js +10 -0
  23. package/build/requires/globals/parent-theme.js +28 -0
  24. package/build/requires/globals/prepare-install-hooks-schema.js +58 -0
  25. package/build/requires/globals/progress-bar.js +52 -0
  26. package/build/requires/globals/theme-require.js +190 -0
  27. package/build/requires/index.js +21 -0
  28. package/build/requires/locales.js +16 -0
  29. package/build/requires/scripts/index.js +5 -0
  30. package/build/requires/scripts/public-path.js +9 -0
  31. package/build/requires/scripts/script-builders/elements.build.js +44 -0
  32. package/build/requires/scripts/script-builders/features.build.js +15 -0
  33. package/build/requires/scripts/theme-envy.js +7 -0
  34. package/build/requires/snippets/index.js +11 -0
  35. package/build/requires/snippets/liquid-builders/theme-envy.liquid.build.js +21 -0
  36. package/build/requires/styles/index.js +1 -0
  37. package/build/requires/styles/styles-builders/theme-envy.css.js +11 -0
  38. package/build/requires/styles/tailwind-base.css +3 -0
  39. package/build/requires/templates.js +20 -0
  40. package/build/theme-envy.config.js +71 -0
  41. package/convert/functions/convert-sections-to-features.js +56 -0
  42. package/convert/functions/detect-children.js +30 -0
  43. package/convert/functions/index.js +6 -0
  44. package/convert/functions/install-hooks.js +68 -0
  45. package/convert/functions/set-settings-schema-js.js +14 -0
  46. package/convert/index.js +50 -0
  47. package/helpers/functions/dev.js +15 -0
  48. package/helpers/functions/dist-clean.js +19 -0
  49. package/helpers/functions/ensure-directories.js +26 -0
  50. package/helpers/functions/find-orphans.js +20 -0
  51. package/helpers/functions/global-theme-envy.js +20 -0
  52. package/helpers/functions/liquid-prettify.js +24 -0
  53. package/helpers/functions/liquid-tree/functions/count-results.js +13 -0
  54. package/helpers/functions/liquid-tree/functions/get-depth.js +12 -0
  55. package/helpers/functions/liquid-tree/functions/get-file-info.js +11 -0
  56. package/helpers/functions/liquid-tree/functions/index.js +5 -0
  57. package/helpers/functions/liquid-tree/index.js +48 -0
  58. package/helpers/functions/liquid-tree/objects/dependencies.js +74 -0
  59. package/helpers/functions/liquid-tree/objects/index.js +3 -0
  60. package/helpers/functions/log-symbols.js +28 -0
  61. package/helpers/functions/pull-json.js +22 -0
  62. package/helpers/functions/scaffold-new/functions/element.js +15 -0
  63. package/helpers/functions/scaffold-new/functions/feature.js +76 -0
  64. package/helpers/functions/scaffold-new/functions/index.js +6 -0
  65. package/helpers/functions/scaffold-new/functions/load-dir.js +24 -0
  66. package/helpers/functions/scaffold-new/functions/starter-content.js +21 -0
  67. package/helpers/functions/scaffold-new/functions/upper-first-letter.js +3 -0
  68. package/helpers/functions/scaffold-new/index.js +28 -0
  69. package/helpers/functions/scaffold-new/objects/index.js +3 -0
  70. package/helpers/functions/scaffold-new/objects/starter-configs.js +7 -0
  71. package/helpers/functions/unicode-supported.js +21 -0
  72. package/helpers/index.js +10 -0
  73. package/index.js +190 -0
  74. package/init/functions/add-theme-envy-features/features/theme-envy/install.js +6 -0
  75. package/init/functions/add-theme-envy-features/index.js +21 -0
  76. package/init/functions/copy-example-feature/example-feature/config/_example-feature.js +8 -0
  77. package/init/functions/copy-example-feature/example-feature/index.js +5 -0
  78. package/init/functions/copy-example-feature/example-feature/install.js +10 -0
  79. package/init/functions/copy-example-feature/example-feature/partials/_example-feature-partial.liquid +3 -0
  80. package/init/functions/copy-example-feature/example-feature/schema/schema-example-feature-schema-partial.js +16 -0
  81. package/init/functions/copy-example-feature/example-feature/schema/schema-example-feature-section.js +14 -0
  82. package/init/functions/copy-example-feature/example-feature/scripts/example-feature.js +3 -0
  83. package/init/functions/copy-example-feature/example-feature/sections/example-feature-section.liquid +11 -0
  84. package/init/functions/copy-example-feature/example-feature/snippets/example-feature-snippet.liquid +1 -0
  85. package/init/functions/copy-example-feature/index.js +25 -0
  86. package/init/functions/copy-starter-config-files/configs/postcss.config.js +9 -0
  87. package/init/functions/copy-starter-config-files/configs/tailwind.config.js +16 -0
  88. package/init/functions/copy-starter-config-files/configs/theme.config.js +25 -0
  89. package/init/functions/copy-starter-config-files/index.js +28 -0
  90. package/init/functions/copy-starter-config-files/utils/starter-config.js +17 -0
  91. package/init/functions/copy-starter-config-files/utils/starter-element.js +16 -0
  92. package/init/functions/copy-starter-config-files/utils/starter-install.js +14 -0
  93. package/init/functions/copy-starter-config-files/utils/starter-schema.js +32 -0
  94. package/init/functions/copy-starter-config-files/utils/starter-section.js +16 -0
  95. package/init/functions/create-empty-settings-data.js +19 -0
  96. package/init/functions/create-settings-schema.js +29 -0
  97. package/init/functions/if-shopify-theme-exists.js +26 -0
  98. package/init/functions/import-from-git.js +21 -0
  99. package/init/functions/index.js +10 -0
  100. package/init/functions/validate-source-theme.js +28 -0
  101. package/init/index.js +87 -0
  102. package/package.json +88 -0
@@ -0,0 +1,12 @@
1
+ const getDepth = (obj, depth = 0, arr = []) => {
2
+ // collect object depth and key for each entry into an array so we can output a smaller, less verbose version of the tree
3
+ Object.keys(obj).forEach(key => {
4
+ arr.push({ depth, key, type: obj[key].type })
5
+ if (obj[key].tree) {
6
+ getDepth(obj[key].tree, depth + 1, arr)
7
+ }
8
+ })
9
+ return arr
10
+ }
11
+
12
+ module.exports = getDepth
@@ -0,0 +1,11 @@
1
+ const path = require('path')
2
+
3
+ module.exports = (filePath) => {
4
+ const file = {
5
+ name: path.basename(filePath, '.liquid'),
6
+ type: filePath.includes('sections/') ? 'section' : filePath.includes('snippets/') ? 'snippet' : filePath.includes('partials/') ? 'partial' : filePath.includes('layout/') ? 'layout' : filePath.includes('templates/') ? 'template' : filePath.includes('assets/') ? 'asset' : null,
7
+ path: path.resolve(filePath),
8
+ tree: {}
9
+ }
10
+ return file
11
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ countResults: require('./count-results.js'),
3
+ getDepth: require('./get-depth.js'),
4
+ getFileInfo: require('./get-file-info.js'),
5
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ @file returns an array of all liquid files that are in the dependency tree of the given file.
3
+ @example npx theme-envy tree filepath1,filepath2,filepath3
4
+ */
5
+
6
+ const chalk = require('chalk')
7
+ const { dependencies } = require('./objects')
8
+ const { countResults, getDepth } = require('./functions')
9
+
10
+ module.exports = function(filepaths, options) {
11
+ const files = filepaths.split(',')
12
+ if (!files) {
13
+ console.error('Provide relative file path(s) to find')
14
+ return
15
+ }
16
+ // create our output and run our functions on each file passed in as a command line argument
17
+ files.forEach((filePath, i) => {
18
+ // add a new line between each file
19
+ if (i > 0) console.log('\n')
20
+ const result = dependencies.check(filePath)
21
+ console.log(chalk.bgWhite.black.bold('------------------------------------------'))
22
+ console.log(chalk.bgWhite.black.bold(` ${countResults(result)} files in liquid dependency tree for: \n ${filePath} `))
23
+ console.log(chalk.bgWhite.black.bold('------------------------------------------'))
24
+ if (options.verbose) {
25
+ // our "verbose" output
26
+ console.dir(result, { depth: null, colors: true })
27
+ } else {
28
+ // our "simple" output
29
+ getDepth(result).forEach(entry => {
30
+ let weight, bg
31
+ if (entry.type === 'section') {
32
+ bg = 'bgGray'
33
+ weight = 'bold'
34
+ } else {
35
+ bg = 'bgBlack'
36
+ weight = entry.depth === 0 ? 'bold' : false
37
+ }
38
+ const color = entry.depth === 0 ? 'green' : entry.depth === 1 ? 'yellow' : entry.depth === 2 ? 'blue' : entry.depth === 3 ? 'red' : 'gray'
39
+ if (weight) {
40
+ // output our bold items
41
+ console.log(chalk[weight][color](`${' '.repeat(entry.depth)}${chalk[weight][color][bg](`${entry.key} (${entry.type})`)}`))
42
+ } else {
43
+ console.log(chalk[color](`${' '.repeat(entry.depth)}${entry.key} (${entry.type})`))
44
+ }
45
+ })
46
+ }
47
+ })
48
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @file This file contains the logic for collecting all of the dependencies for a given file.
3
+ */
4
+
5
+ const fs = require('fs')
6
+ const glob = require('glob')
7
+ const path = require('path')
8
+ const { getFileInfo } = require('../functions')
9
+
10
+ // Collect all of our liquid files
11
+ const liquidFiles = glob.sync(path.resolve(ThemeEnvy.themePath, '**/*.liquid'))
12
+ // define our strings that we want to find in the files
13
+ const searchStrings = (file) => {
14
+ return {
15
+ asset: [`'${file.name}' | asset_url`, `"${file.name}" | asset_url`],
16
+ snippet: [`render '${file.name}'`, `render "${file.name}"`, `include '${file.name}'`, `include "${file.name}"`],
17
+ partial: [`partial '${file.name}'`, `partial "${file.name}"`],
18
+ section: [`section '${file.name}'`, `section "${file.name}"`],
19
+ }
20
+ }
21
+
22
+ module.exports = {
23
+ check(filePath) {
24
+ this.results = {}
25
+ const fileName = filePath.includes('.') ? filePath : path.basename(filePath, '.liquid')
26
+ this.results[fileName] = getFileInfo(filePath)
27
+ this.results = this.collect(this.results)
28
+
29
+ // remove all searchString attributes and empty trees from our results
30
+ this.results = this.cleanForReport(this.results)
31
+ return this.results
32
+ },
33
+ collect(results) {
34
+ // iterate through each file in our results object
35
+ Object.entries(results).forEach(file => {
36
+ const fileInfo = file[1]
37
+ // get the tree for the file
38
+ fileInfo.tree = this.getFileTree(fileInfo)
39
+ })
40
+ return results
41
+ },
42
+ getFileTree(fileInfo) {
43
+ // do not check "templates", or "layouts" for dependencies
44
+ if (['template', 'layout'].includes(fileInfo.type)) return fileInfo.tree
45
+ const tree = {}
46
+ this.numberOfFiles = this.numberOfFiles > 0 ? this.numberOfFiles : 0
47
+ // check all liquid files for references to the file
48
+ liquidFiles.filter(file => file !== fileInfo.path).forEach(liquid => {
49
+ const source = fs.readFileSync(path.resolve(process.cwd(), liquid), 'utf8')
50
+ searchStrings(fileInfo)[fileInfo.type].forEach(string => {
51
+ if (source.includes(string)) {
52
+ // add the partial to our results object and continue down its tree
53
+ const fileName = path.basename(liquid, '.liquid')
54
+ tree[fileName] = getFileInfo(liquid)
55
+ tree[fileName].tree = this.getFileTree(tree[fileName])
56
+ }
57
+ })
58
+ })
59
+ return tree
60
+ },
61
+ cleanForReport(results) {
62
+ // remove any empty trees from our results for a cleaner report
63
+ Object.entries(results).forEach(file => {
64
+ const fileInfo = file[1]
65
+ delete fileInfo.name
66
+ if (Object.keys(fileInfo.tree).length === 0) delete fileInfo.tree
67
+ })
68
+ // clean the sub trees
69
+ Object.entries(results).forEach(file => {
70
+ if (file[1].tree) file[1].tree = this.cleanForReport(file[1].tree)
71
+ })
72
+ return results
73
+ }
74
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ dependencies: require('./dependencies.js'),
3
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file Returns the appropriate log symbols based on unicode support
3
+ * @example
4
+ * console.log(logSymbols.info, 'Info message')
5
+ * @returns {Object} - An object containing the appropriate log symbols
6
+ */
7
+ // based on https://github.com/sindresorhus/log-symbols
8
+
9
+ const chalk = require('chalk')
10
+ const isUnicodeSupported = require('./unicode-supported')
11
+
12
+ const main = {
13
+ info: chalk.cyan('ℹ'),
14
+ success: chalk.green('✔'),
15
+ warning: chalk.yellow('⚠'),
16
+ error: chalk.red('✖'),
17
+ }
18
+
19
+ const fallback = {
20
+ info: chalk.cyan('i'),
21
+ success: chalk.green('√'),
22
+ warning: chalk.yellow('‼'),
23
+ error: chalk.red('×'),
24
+ }
25
+
26
+ const logSymbols = isUnicodeSupported() ? main : fallback
27
+
28
+ module.exports = logSymbols
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @file A function that pulls the JSON files from Shopify and copies them to the theme directory.
3
+ * @example
4
+ * npx theme-envy pull-json
5
+ * @returns {Void}
6
+ */
7
+
8
+ const glob = require('glob')
9
+ const path = require('path')
10
+ const fs = require('fs-extra')
11
+ const { spawn } = require('child_process')
12
+
13
+ module.exports = function() {
14
+ const relativeDistPath = path.relative(process.cwd(), ThemeEnvy.outputPath)
15
+ const themePull = ['theme', 'pull', `--store=${ThemeEnvy.store}`, `--path=${relativeDistPath}`, '--only=templates/*.json,config/settings_data.json,sections/*.json']
16
+ const shopify = spawn('shopify', themePull, { cwd: ThemeEnvy.outputPath, stdio: 'inherit' })
17
+
18
+ shopify.on('exit', function() {
19
+ const files = glob.sync(path.resolve(ThemeEnvy.outputPath, '{templates,config,sections}/**/*.json')).filter(file => file.indexOf('settings_schema') > -1)
20
+ files.forEach(file => fs.copyFileSync(file, file.replace(ThemeEnvy.outputPath, ThemeEnvy.themePath)))
21
+ })
22
+ }
@@ -0,0 +1,15 @@
1
+ const path = require('path')
2
+ const fs = require('fs-extra')
3
+ const upperFirstLetter = require('./upper-first-letter')
4
+ const starterContent = require('./starter-content')
5
+ const { starterConfigs } = require('../objects')
6
+
7
+ module.exports = (name) => {
8
+ const ELEMENTS = path.resolve(ThemeEnvy.themePath, 'theme-envy/elements')
9
+ const EXT_NAME = name.toLowerCase()
10
+
11
+ const EXT_COMPONENT_NAME = EXT_NAME.indexOf('-') > -1 ? EXT_NAME : EXT_NAME + '-component'
12
+ const EXT_CLASS_NAME = EXT_COMPONENT_NAME.split('-').map(part => upperFirstLetter(part)).join('')
13
+
14
+ fs.writeFileSync(path.resolve(ELEMENTS, `${EXT_NAME}.js`), starterContent(starterConfigs.element, [EXT_NAME, EXT_CLASS_NAME]))
15
+ }
@@ -0,0 +1,76 @@
1
+ const path = require('path')
2
+ const loadDir = require('./load-dir')
3
+ const upperFirstLetter = require('./upper-first-letter')
4
+ const starterContent = require('./starter-content')
5
+ const { starterConfigs } = require('../objects')
6
+
7
+ module.exports = (name, include) => {
8
+ const FEATURES = path.resolve(ThemeEnvy.themePath, 'theme-envy/features')
9
+ const starters = include?.split(',') || 'all'
10
+
11
+ const DIRS = []
12
+ const EXT_NAME = name.toLowerCase()
13
+ const INCLUDE_ANY = starters
14
+ const INCLUDE_ALL = INCLUDE_ANY && starters.includes('all')
15
+ const INCLUDE_ELEMENT = INCLUDE_ANY && (starters.includes('elements') || INCLUDE_ALL)
16
+ const INCLUDE_STYLE = INCLUDE_ANY && (starters.includes('styles') || INCLUDE_ALL)
17
+ const INCLUDE_INSTALL = INCLUDE_ANY && (starters.includes('install') || INCLUDE_ALL)
18
+ const INCLUDE_SECTION = INCLUDE_ANY && (starters.includes('sections') || INCLUDE_ALL)
19
+ const INCLUDE_SNIPPET = INCLUDE_ANY && (starters.includes('snippets') || INCLUDE_ALL)
20
+ const INCLUDE_CONFIG = INCLUDE_ANY && (starters.includes('config') || INCLUDE_ALL)
21
+ const INCLUDE_SCHEMA = INCLUDE_ANY && (starters.includes('schema') || INCLUDE_ALL)
22
+ const EXT_COMPONENT_NAME = EXT_NAME.indexOf('-') > -1 ? EXT_NAME : EXT_NAME + '-component'
23
+ const EXT_CLASS_NAME = EXT_COMPONENT_NAME.split('-').map(part => upperFirstLetter(part)).join('')
24
+ const EXT_READABLE_NAME = EXT_COMPONENT_NAME.split('-').map(part => upperFirstLetter(part)).join(' ')
25
+
26
+ // import strings
27
+ const scriptImport = ''
28
+ let styleImport = ''
29
+
30
+ /*
31
+ DEFAULT FILE CONTENTS & import strings
32
+ */
33
+
34
+ const FILES = {}
35
+ if (INCLUDE_CONFIG) {
36
+ DIRS.push('config')
37
+
38
+ FILES[`config/${EXT_NAME}.js`] = starterContent(starterConfigs.config, [EXT_READABLE_NAME])
39
+ }
40
+
41
+ if (INCLUDE_SCHEMA) {
42
+ DIRS.push('schema')
43
+ FILES[`schema/schema-${EXT_NAME}.js`] = starterContent(starterConfigs.schema, [EXT_NAME, EXT_READABLE_NAME])
44
+ }
45
+
46
+ if (INCLUDE_INSTALL) {
47
+ FILES['install.js'] = starterContent(starterConfigs.install, [EXT_NAME])
48
+ }
49
+ if (INCLUDE_ELEMENT) {
50
+ DIRS.push('elements')
51
+ FILES[`elements/${EXT_COMPONENT_NAME}.js`] = starterContent(starterConfigs.element, [EXT_COMPONENT_NAME, EXT_CLASS_NAME])
52
+ }
53
+ if (INCLUDE_STYLE) {
54
+ styleImport = `import './styles/${EXT_NAME}.css'
55
+ `
56
+ DIRS.push('styles')
57
+ const COMPONENT_CSS = `${EXT_COMPONENT_NAME} {
58
+
59
+ }`
60
+ FILES[`styles/${EXT_NAME}.css`] = INCLUDE_ELEMENT ? COMPONENT_CSS : ''
61
+ }
62
+ if (INCLUDE_SECTION) {
63
+ DIRS.push('sections')
64
+ const TAG = INCLUDE_ELEMENT ? EXT_COMPONENT_NAME : 'div'
65
+ FILES[`sections/${EXT_NAME}.liquid`] = starterContent(starterConfigs.section, [TAG, EXT_NAME])
66
+ }
67
+
68
+ if (INCLUDE_SNIPPET) {
69
+ DIRS.push('snippets')
70
+ FILES[`snippets/${EXT_NAME}.liquid`] = ''
71
+ }
72
+
73
+ FILES['index.js'] = `${scriptImport}${styleImport}`
74
+
75
+ loadDir({ location: FEATURES, DIRS, EXT_NAME, FILES })
76
+ }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ element: require('./element'),
3
+ feature: require('./feature'),
4
+ starterContent: require('./starter-content'),
5
+ upperFirstLetter: require('./upper-first-letter.js'),
6
+ }
@@ -0,0 +1,24 @@
1
+ const chalk = require('chalk')
2
+ const fs = require('fs-extra')
3
+ const logSymbols = require('#LogSymbols')
4
+ const path = require('path')
5
+
6
+ module.exports = ({ location, DIRS, EXT_NAME, FILES }) => {
7
+ if (fs.existsSync(path.resolve(location, EXT_NAME))) {
8
+ console.log(logSymbols.error, chalk.red('Error:'), `Feature ${EXT_NAME} already exists. Rename or update feature directly instead.`)
9
+ process.exit()
10
+ }
11
+ fs.ensureDirSync(path.resolve(location, EXT_NAME))
12
+
13
+ for (const DIR of DIRS) {
14
+ fs.ensureDirSync(path.resolve(location, EXT_NAME, DIR))
15
+ }
16
+
17
+ for (const FILE of Object.entries(FILES)) {
18
+ fs.writeFileSync(path.resolve(location, EXT_NAME, FILE[0]), FILE[1], (err) => {
19
+ if (err) throw new Error(`${logSymbols.error} Error creating file ${FILE[0]}`)
20
+ })
21
+ }
22
+
23
+ console.log(`${logSymbols.success} ${chalk.green.bold(EXT_NAME)} created\n ${chalk.dim(location)}`)
24
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @file Returns starter content by file name, defaults to package file
3
+ * @param {string} fileName - The name of the starter file to return
4
+ * @param {array} args - An array of arguments to pass to the starter file
5
+ * @returns {string} - The starter file content
6
+ */
7
+
8
+ const path = require('path')
9
+ const fs = require('fs-extra')
10
+ const logSymbols = require('#LogSymbols')
11
+ const chalk = require('chalk')
12
+
13
+ module.exports = (fileName, args) => {
14
+ const fileExists = fs.existsSync(path.join(process.cwd(), '/utils/', fileName))
15
+ if (!fileExists) {
16
+ console.log(logSymbols.error, chalk.red('Error:'), `Starter file ${fileName} not found`)
17
+ process.exit()
18
+ }
19
+ const content = require(path.join(process.cwd(), '/utils/', fileName))
20
+ return content(...args)
21
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = (string) => {
2
+ return string[0].toUpperCase() + string.substring(1)
3
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file Creates a directory in theme-envy/features or theme-envy/elements with starter files to build your feature or element
3
+ * @param {string} type - The type of feature or element to create.
4
+ * @param {string} name - The name of the feature or element to create.
5
+ * @param {string} include - A comma separated list of files/directory to include in a new feature (not applicable to elements).
6
+ * @example
7
+ * npx theme-envy new <feature|element> <feature-name> [all|sections|snippets|schema|install|styles|config]
8
+ */
9
+
10
+ const chalk = require('chalk')
11
+ const logSymbols = require('#LogSymbols')
12
+ const { element, feature } = require('./functions')
13
+
14
+ module.exports = function(type, name, include) {
15
+ console.log(logSymbols.info, chalk.cyan('Creating new'), chalk.green.bold(name), chalk.underline.bold(type), chalk.cyan('...'))
16
+
17
+ switch (type) {
18
+ case 'feature':
19
+ feature(name, include)
20
+ break
21
+ case 'element':
22
+ element(name)
23
+ break
24
+ default:
25
+ console.log(logSymbols.error, chalk.red('Error:'), `Invalid type ${type}`)
26
+ process.exit()
27
+ }
28
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ starterConfigs: require('./starter-configs'),
3
+ }
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ config: 'starter-config.js',
3
+ install: 'starter-install.js',
4
+ schema: 'starter-schema.js',
5
+ element: 'starter-element.js',
6
+ section: 'starter-section.js',
7
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @file Check if the terminal supports unicode
3
+ */
4
+
5
+ module.exports = () => {
6
+ if (process.platform !== 'win32') {
7
+ return process.env.TERM !== 'linux' // Linux console (kernel)
8
+ }
9
+
10
+ return (
11
+ Boolean(process.env.CI) ||
12
+ Boolean(process.env.WT_SESSION) /* Windows Terminal */ ||
13
+ Boolean(process.env.TERMINUS_SUBLIME) /* Terminus (<0.2.27) */ ||
14
+ process.env.ConEmuTask === '{cmd::Cmder}' /* ConEmu and cmder */ ||
15
+ process.env.TERM_PROGRAM === 'Terminus-Sublime' ||
16
+ process.env.TERM_PROGRAM === 'vscode' ||
17
+ process.env.TERM === 'xterm-256color' ||
18
+ process.env.TERM === 'alacritty' ||
19
+ process.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm'
20
+ )
21
+ }
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ distClean: require('./functions/dist-clean.js'),
3
+ ensureDirectories: require('./functions/ensure-directories.js'),
4
+ findOrphans: require('./functions/find-orphans.js'),
5
+ globalThemeEnvy: require('./functions/global-theme-envy.js'),
6
+ liquidPrettify: require('./functions/liquid-prettify.js'),
7
+ liquidTree: require('./functions/liquid-tree'),
8
+ pullJson: require('./functions/pull-json.js'),
9
+ scaffoldNew: require('./functions/scaffold-new'),
10
+ }
package/index.js ADDED
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @file Theme Envy CLI
4
+ * @description Theme Envy CLI Tools
5
+ * @example npx theme-envy
6
+ */
7
+
8
+ const chalk = require('chalk')
9
+ const commander = require('commander')
10
+ const emoji = require('node-emoji')
11
+ const fs = require('fs-extra')
12
+ const program = new commander.Command()
13
+ const promptly = require('promptly')
14
+
15
+ const { directories } = require('#EnsureDirectories')
16
+ require('#Helpers/functions/global-theme-envy.js')
17
+
18
+ const themeEnvyCommands = {
19
+ build: require('#Build'),
20
+ clean: require('#Helpers/functions/dist-clean.js'),
21
+ convert: require('#Convert'),
22
+ dev: require('#Helpers/functions/dev.js'),
23
+ init: require('#Init'),
24
+ new: require('#Helpers/functions/scaffold-new/index.js'),
25
+ orphans: require('#Helpers/functions/find-orphans.js'),
26
+ 'pull-json': require('#Helpers/functions/pull-json.js'),
27
+ tree: require('#Helpers/functions/liquid-tree/index.js'),
28
+ }
29
+
30
+ const scriptMessage = (scriptName) => {
31
+ console.log(`\n ${emoji.get('rocket')} Shopify Theme Envy ${chalk.green.bgBlack.bold(`\n theme-envy ${scriptName}\n`)}`)
32
+ }
33
+
34
+ program
35
+ .command('init')
36
+ .description('Initialize a new Shopify theme project with Theme Envy directory structure')
37
+ .usage('[source] -e|--example -c|--convert')
38
+ .argument('[source]', 'Specify the path/git url to your theme source directory to process, if not provided will create the directory structure in /src')
39
+ .option('-s, --store <store>', 'Specify the myshopify domain for your store', 'my-store.myshopify.com')
40
+ .option('-c, --convert', 'Convert theme sections to features, add hooks, and install theme-envy feature on import')
41
+ .option('-e, --example', 'Output example feature structure and dummy files with readme documentation in each subdirectory')
42
+ .action(async (source, options, command) => {
43
+ scriptMessage(command.name())
44
+ if (!source) {
45
+ let choice = await promptly.choose(`${chalk.yellow('Would you like to:')}
46
+ a) Import an existing repo from a .git url
47
+ b) Initialize from a Shopify theme in the current directory, or initialize empty directories if no Shopify theme exists?
48
+
49
+ (a/b)?`, ['a', 'b', 'A', 'B'])
50
+ choice = choice.toLowerCase()
51
+ if (choice === 'a') {
52
+ const gitUrl = await promptly.prompt(chalk.yellow('Please provide the git url for your source theme:\n'), {
53
+ validator(value) {
54
+ if (value.includes('git@') || value.includes('https://')) return value
55
+ throw new Error(chalk.red.bold('Please enter a valid git url'))
56
+ }
57
+ })
58
+ if (gitUrl) {
59
+ source = gitUrl
60
+ }
61
+ }
62
+ }
63
+ // check for existing Shopify theme in root
64
+ const rootDirs = fs.readdirSync(process.cwd()).filter(res => !res.includes('.'))
65
+ const shopifyThemeExistsInRoot = directories.every(dir => rootDirs.includes(dir))
66
+ if (!options.convert && (shopifyThemeExistsInRoot || source)) {
67
+ const convert = await promptly.confirm(`
68
+ ${chalk.yellow('Do you want to convert the existing theme and install Theme Envy?')} ${chalk.green('(recommended)')}
69
+ This does the following things:
70
+ • Converts your theme sections to Theme Envy features (where possible)
71
+ • Adds ${chalk.cyan('{% hook %}')} tags to ${chalk.cyan('theme.liquid')}
72
+ • Installs the Theme Envy integration feature to ${chalk.cyan('theme-envy/features')}
73
+ (Y/n)`)
74
+ if (convert) {
75
+ options.convert = true
76
+ }
77
+ }
78
+ if (!options.example) {
79
+ const example = await promptly.confirm(`${chalk.yellow('Would you like to output an example Theme Envy "Feature"?')}\n(Y/n)?`)
80
+ if (example) {
81
+ options.example = true
82
+ }
83
+ }
84
+ if (options.store === 'my-store.myshopify.com') {
85
+ options.store = await promptly.prompt(chalk.yellow('Please provide the myshopify.com domain of your store (this can be changed later in theme.config.js):\n '))
86
+ }
87
+ themeEnvyCommands.init(source, options)
88
+ })
89
+
90
+ program
91
+ .command('dev')
92
+ .description('Start development process and sync with Shopify using the Shopify CLI')
93
+ .action((options, command) => {
94
+ scriptMessage(command.name())
95
+ themeEnvyCommands.dev()
96
+ })
97
+
98
+ program
99
+ .description('Theme Envy CLI Tools')
100
+ .addHelpText('beforeAll', `
101
+ ${emoji.get('green_heart') + chalk.green.bold(' Softlimit Shopify Theme Envy ') + emoji.get('green_heart')}
102
+ ${chalk.green.bold('===================================')}
103
+ `)
104
+ .addHelpText('afterAll', `
105
+ ${chalk.cyan.bold('===================================')}
106
+ ${emoji.get('thinking_face')} ${chalk.cyan.bold.underline('Need more help?')}
107
+ We are always looking for ways to improve our tools
108
+ and make your Shopify development life smoother.
109
+
110
+ Let us know what we missed! Create an issue on our github repo:
111
+ ${chalk.dim.underline('https://github.com/softlimit/shopify-env/issues')}
112
+ `)
113
+
114
+ program
115
+ .command('build')
116
+ .description('Build Shopify theme')
117
+ .usage('[development|production] -w|--watch')
118
+ .addArgument(new commander.Argument('[env]', 'Specify the build environment to run').choices(['development', 'production']))
119
+ .option('-w, --watch', 'Watch for changed files and update dist, serve with Shopify CLI')
120
+ .option('-v, --verbose', 'Show Tailwind and Webpack in output')
121
+ .action((env, options, command) => {
122
+ scriptMessage(command.name())
123
+ themeEnvyCommands.build(env, options)
124
+ })
125
+
126
+ program
127
+ .command('clean')
128
+ .description('Empty output directory')
129
+ .action((options, command) => {
130
+ scriptMessage(command.name())
131
+ themeEnvyCommands.clean()
132
+ })
133
+
134
+ program
135
+ .command('new')
136
+ .description('Create new Feature or Element from starter files')
137
+ .usage('<type> <name> [include]')
138
+ .addArgument(new commander.Argument('<type>', 'Define the type of scaffold to create').choices(['feature', 'element']))
139
+ .argument('<name>', 'Handleized name for the new element|feature')
140
+ .argument('[include]', 'Comma-separated list of starter directories and files to include in your scaffold. Defaults to all if not provided. all,config,install,sections,snippets,schema,styles')
141
+ .action((type, name, include, options, command) => {
142
+ scriptMessage(command.name())
143
+ if (name.includes(',') || name.includes(' ')) {
144
+ console.error(
145
+ chalk.red('Invalid Name:'),
146
+ 'Name argument should only include text and dashes, no commas or spaces. Rename with handle version to continue.'
147
+ )
148
+ return
149
+ }
150
+ themeEnvyCommands.new(type, name, include)
151
+ })
152
+
153
+ program
154
+ .command('find-orphans')
155
+ .description('Find unused snippets, partials, and assets in your Shopify theme')
156
+ .action((options, command) => {
157
+ scriptMessage(command.name())
158
+ themeEnvyCommands.orphans()
159
+ })
160
+
161
+ program
162
+ .command('pull-json')
163
+ .description('Pull json template, section, and settings_data files from theme using Shopify CLI')
164
+ .action((options, command) => {
165
+ scriptMessage(command.name())
166
+ themeEnvyCommands['pull-json']()
167
+ })
168
+
169
+ program
170
+ .command('tree')
171
+ .description('Display the dependency tree for a .liquid file')
172
+ .usage('[filepaths]')
173
+ .argument('[filepaths]', 'Project relative path(s) to .liquid files. Separate multiple paths with commas.')
174
+ .option('-v, --verbose', 'display as JS Object instead of formatted tree')
175
+ .action((filepath, options, command) => {
176
+ scriptMessage(command.name())
177
+ themeEnvyCommands.tree(filepath, options)
178
+ })
179
+
180
+ program
181
+ .command('convert')
182
+ .description('Convert an existing Shopify theme to Theme Envy directory structure')
183
+ .usage('[source] -a|--add-theme-envy-feature')
184
+ .argument('[source]', 'Specify the path to your theme source directory to process, defaults to project root ./src directory if not provided')
185
+ .option('-a, --add-theme-envy-feature', 'Add theme-envy feature and install to hook')
186
+ .action((source, options, command) => {
187
+ scriptMessage(command.name())
188
+ themeEnvyCommands.convert(source)
189
+ })
190
+ program.parse()
@@ -0,0 +1,6 @@
1
+ module.exports = [
2
+ {
3
+ hook: 'head-end',
4
+ content: "{% render 'theme-envy' %}"
5
+ }
6
+ ]
@@ -0,0 +1,21 @@
1
+ /*
2
+ Copies theme-envy features during theme-envy init
3
+ */
4
+ const fs = require('fs-extra')
5
+ const path = require('path')
6
+ const glob = require('glob')
7
+ const chalk = require('chalk')
8
+ const logSymbols = require('#LogSymbols')
9
+
10
+ module.exports = function({ dest }) {
11
+ const featuresDir = path.resolve(__dirname, './features')
12
+ const initFeatures = glob.sync(`${featuresDir}/*`).filter(ref => fs.statSync(ref).isDirectory() && ref !== featuresDir)
13
+ initFeatures.forEach(feature => {
14
+ const target = path.resolve(dest, './theme-envy/features', path.basename(feature))
15
+ if (fs.existsSync(target)) return
16
+ fs.copy(feature, target, err => {
17
+ if (err) return console.error(err)
18
+ console.log(`${logSymbols.success} ${chalk.green.bold(path.basename(feature))} feature copied and connected`)
19
+ })
20
+ })
21
+ }