@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.
- package/.eslintrc.js +26 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/workflows/release-please.yml +19 -0
- package/LICENSE +21 -0
- package/README.md +259 -0
- package/build/functions/failed-hook-installs.js +18 -0
- package/build/functions/get-all.js +102 -0
- package/build/functions/index.js +7 -0
- package/build/functions/liquid/functions/extend-liquid.js +77 -0
- package/build/functions/liquid/functions/flatten-shopify-directory-structure.js +29 -0
- package/build/functions/liquid/functions/index.js +6 -0
- package/build/functions/liquid/functions/list-dependencies.js +47 -0
- package/build/functions/liquid/functions/section-schema-inject.js +26 -0
- package/build/functions/liquid/index.js +36 -0
- package/build/functions/parent-theme-files.js +25 -0
- package/build/functions/tailwind.js +31 -0
- package/build/functions/theme-envy.js +85 -0
- package/build/functions/webpack.js +44 -0
- package/build/index.js +45 -0
- package/build/requires/assets.js +22 -0
- package/build/requires/config.js +44 -0
- package/build/requires/globals/index.js +10 -0
- package/build/requires/globals/parent-theme.js +28 -0
- package/build/requires/globals/prepare-install-hooks-schema.js +58 -0
- package/build/requires/globals/progress-bar.js +52 -0
- package/build/requires/globals/theme-require.js +190 -0
- package/build/requires/index.js +21 -0
- package/build/requires/locales.js +16 -0
- package/build/requires/scripts/index.js +5 -0
- package/build/requires/scripts/public-path.js +9 -0
- package/build/requires/scripts/script-builders/elements.build.js +44 -0
- package/build/requires/scripts/script-builders/features.build.js +15 -0
- package/build/requires/scripts/theme-envy.js +7 -0
- package/build/requires/snippets/index.js +11 -0
- package/build/requires/snippets/liquid-builders/theme-envy.liquid.build.js +21 -0
- package/build/requires/styles/index.js +1 -0
- package/build/requires/styles/styles-builders/theme-envy.css.js +11 -0
- package/build/requires/styles/tailwind-base.css +3 -0
- package/build/requires/templates.js +20 -0
- package/build/theme-envy.config.js +71 -0
- package/convert/functions/convert-sections-to-features.js +56 -0
- package/convert/functions/detect-children.js +30 -0
- package/convert/functions/index.js +6 -0
- package/convert/functions/install-hooks.js +68 -0
- package/convert/functions/set-settings-schema-js.js +14 -0
- package/convert/index.js +50 -0
- package/helpers/functions/dev.js +15 -0
- package/helpers/functions/dist-clean.js +19 -0
- package/helpers/functions/ensure-directories.js +26 -0
- package/helpers/functions/find-orphans.js +20 -0
- package/helpers/functions/global-theme-envy.js +20 -0
- package/helpers/functions/liquid-prettify.js +24 -0
- package/helpers/functions/liquid-tree/functions/count-results.js +13 -0
- package/helpers/functions/liquid-tree/functions/get-depth.js +12 -0
- package/helpers/functions/liquid-tree/functions/get-file-info.js +11 -0
- package/helpers/functions/liquid-tree/functions/index.js +5 -0
- package/helpers/functions/liquid-tree/index.js +48 -0
- package/helpers/functions/liquid-tree/objects/dependencies.js +74 -0
- package/helpers/functions/liquid-tree/objects/index.js +3 -0
- package/helpers/functions/log-symbols.js +28 -0
- package/helpers/functions/pull-json.js +22 -0
- package/helpers/functions/scaffold-new/functions/element.js +15 -0
- package/helpers/functions/scaffold-new/functions/feature.js +76 -0
- package/helpers/functions/scaffold-new/functions/index.js +6 -0
- package/helpers/functions/scaffold-new/functions/load-dir.js +24 -0
- package/helpers/functions/scaffold-new/functions/starter-content.js +21 -0
- package/helpers/functions/scaffold-new/functions/upper-first-letter.js +3 -0
- package/helpers/functions/scaffold-new/index.js +28 -0
- package/helpers/functions/scaffold-new/objects/index.js +3 -0
- package/helpers/functions/scaffold-new/objects/starter-configs.js +7 -0
- package/helpers/functions/unicode-supported.js +21 -0
- package/helpers/index.js +10 -0
- package/index.js +190 -0
- package/init/functions/add-theme-envy-features/features/theme-envy/install.js +6 -0
- package/init/functions/add-theme-envy-features/index.js +21 -0
- package/init/functions/copy-example-feature/example-feature/config/_example-feature.js +8 -0
- package/init/functions/copy-example-feature/example-feature/index.js +5 -0
- package/init/functions/copy-example-feature/example-feature/install.js +10 -0
- package/init/functions/copy-example-feature/example-feature/partials/_example-feature-partial.liquid +3 -0
- package/init/functions/copy-example-feature/example-feature/schema/schema-example-feature-schema-partial.js +16 -0
- package/init/functions/copy-example-feature/example-feature/schema/schema-example-feature-section.js +14 -0
- package/init/functions/copy-example-feature/example-feature/scripts/example-feature.js +3 -0
- package/init/functions/copy-example-feature/example-feature/sections/example-feature-section.liquid +11 -0
- package/init/functions/copy-example-feature/example-feature/snippets/example-feature-snippet.liquid +1 -0
- package/init/functions/copy-example-feature/index.js +25 -0
- package/init/functions/copy-starter-config-files/configs/postcss.config.js +9 -0
- package/init/functions/copy-starter-config-files/configs/tailwind.config.js +16 -0
- package/init/functions/copy-starter-config-files/configs/theme.config.js +25 -0
- package/init/functions/copy-starter-config-files/index.js +28 -0
- package/init/functions/copy-starter-config-files/utils/starter-config.js +17 -0
- package/init/functions/copy-starter-config-files/utils/starter-element.js +16 -0
- package/init/functions/copy-starter-config-files/utils/starter-install.js +14 -0
- package/init/functions/copy-starter-config-files/utils/starter-schema.js +32 -0
- package/init/functions/copy-starter-config-files/utils/starter-section.js +16 -0
- package/init/functions/create-empty-settings-data.js +19 -0
- package/init/functions/create-settings-schema.js +29 -0
- package/init/functions/if-shopify-theme-exists.js +26 -0
- package/init/functions/import-from-git.js +21 -0
- package/init/functions/index.js +10 -0
- package/init/functions/validate-source-theme.js +28 -0
- package/init/index.js +87 -0
- 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,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,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,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,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,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
|
+
}
|
package/helpers/index.js
ADDED
|
@@ -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,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
|
+
}
|