@firenet-designs/fnd-cli 1.0.1
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/README.md +75 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/create-app.d.ts +10 -0
- package/dist/commands/create-app.js +154 -0
- package/dist/hooks/init/check-for-updates.d.ts +3 -0
- package/dist/hooks/init/check-for-updates.js +28 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/oclif.manifest.json +45 -0
- package/package.json +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
fnd
|
|
2
|
+
=================
|
|
3
|
+
|
|
4
|
+
A new CLI generated with oclif
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
[](https://oclif.io)
|
|
8
|
+
[](https://npmjs.org/package/fnd)
|
|
9
|
+
[](https://npmjs.org/package/fnd)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
<!-- toc -->
|
|
13
|
+
* [Usage](#usage)
|
|
14
|
+
* [Commands](#commands)
|
|
15
|
+
<!-- tocstop -->
|
|
16
|
+
# Usage
|
|
17
|
+
<!-- usage -->
|
|
18
|
+
```sh-session
|
|
19
|
+
$ npm install -g @firenet-designs/fnd-cli
|
|
20
|
+
$ fnd-cli COMMAND
|
|
21
|
+
running command...
|
|
22
|
+
$ fnd-cli (--version)
|
|
23
|
+
@firenet-designs/fnd-cli/1.0.1 darwin-x64 node-v24.12.0
|
|
24
|
+
$ fnd-cli --help [COMMAND]
|
|
25
|
+
USAGE
|
|
26
|
+
$ fnd-cli COMMAND
|
|
27
|
+
...
|
|
28
|
+
```
|
|
29
|
+
<!-- usagestop -->
|
|
30
|
+
# Commands
|
|
31
|
+
<!-- commands -->
|
|
32
|
+
* [`fnd-cli create-app`](#fnd-cli-create-app)
|
|
33
|
+
* [`fnd-cli help [COMMAND]`](#fnd-cli-help-command)
|
|
34
|
+
|
|
35
|
+
## `fnd-cli create-app`
|
|
36
|
+
|
|
37
|
+
sets up a preconfigued vite app directory on for a shopify theme
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
USAGE
|
|
41
|
+
$ fnd-cli create-app [-d <value>] [-s]
|
|
42
|
+
|
|
43
|
+
FLAGS
|
|
44
|
+
-d, --dir=<value> [default: src] directory to create the vite app in
|
|
45
|
+
-s, --skip-check skips the checking of the parent directory for a shopify theme
|
|
46
|
+
|
|
47
|
+
DESCRIPTION
|
|
48
|
+
sets up a preconfigued vite app directory on for a shopify theme
|
|
49
|
+
|
|
50
|
+
EXAMPLES
|
|
51
|
+
$ fnd-cli create-app
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
_See code: [src/commands/create-app.ts](https://github.com/FireNet-Designs/fnd-cli/blob/v1.0.1/src/commands/create-app.ts)_
|
|
55
|
+
|
|
56
|
+
## `fnd-cli help [COMMAND]`
|
|
57
|
+
|
|
58
|
+
Display help for fnd-cli.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
USAGE
|
|
62
|
+
$ fnd-cli help [COMMAND...] [-n]
|
|
63
|
+
|
|
64
|
+
ARGUMENTS
|
|
65
|
+
[COMMAND...] Command to show help for.
|
|
66
|
+
|
|
67
|
+
FLAGS
|
|
68
|
+
-n, --nested-commands Include all nested commands in the output.
|
|
69
|
+
|
|
70
|
+
DESCRIPTION
|
|
71
|
+
Display help for fnd-cli.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.37/src/commands/help.ts)_
|
|
75
|
+
<!-- commandsstop -->
|
package/bin/dev.cmd
ADDED
package/bin/dev.js
ADDED
package/bin/run.cmd
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class CreateApp extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
dir: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'skip-check': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { mkdirSync, rmSync, statSync } from 'node:fs';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import { simpleGit } from 'simple-git';
|
|
8
|
+
/**
|
|
9
|
+
* Executes a series of shell commands sequentially in a single shell session.
|
|
10
|
+
*
|
|
11
|
+
* This function takes an array of shell commands and executes them in sequence
|
|
12
|
+
* within a single shell session, sourcing the user's zsh configuration first.
|
|
13
|
+
* It provides callbacks for handling stdout and stderr data as it's received,
|
|
14
|
+
* and returns the final output, error, and exit code.
|
|
15
|
+
*
|
|
16
|
+
* @param commands - An array of shell commands to execute
|
|
17
|
+
* @param options - Execution options including environment variables and callbacks
|
|
18
|
+
* @returns A promise that resolves with the command output, error, and exit code
|
|
19
|
+
*/
|
|
20
|
+
const execCommands = async (commands, options) => {
|
|
21
|
+
const cmdStr = ['source ~/.zshrc', ...commands].join(' && ');
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
let stdout = '';
|
|
24
|
+
let stderr = '';
|
|
25
|
+
let output = '';
|
|
26
|
+
const child = spawn(cmdStr, {
|
|
27
|
+
...options,
|
|
28
|
+
shell: 'zsh',
|
|
29
|
+
});
|
|
30
|
+
child.stdout.on('data', (data) => {
|
|
31
|
+
stdout += data;
|
|
32
|
+
output += data;
|
|
33
|
+
options.onOutput?.(output);
|
|
34
|
+
options.onStdout?.(stdout);
|
|
35
|
+
});
|
|
36
|
+
child.stderr.on('data', (data) => {
|
|
37
|
+
stderr += data;
|
|
38
|
+
output += data;
|
|
39
|
+
options.onOutput?.(output);
|
|
40
|
+
options.onStderr?.(stderr);
|
|
41
|
+
});
|
|
42
|
+
child.on('close', (code) => {
|
|
43
|
+
resolve({ code, output, stderr, stdout });
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Checks if a directory exists at the specified path.
|
|
49
|
+
*
|
|
50
|
+
* This function attempts to retrieve the file status of the given directory path.
|
|
51
|
+
* If the operation succeeds, it means the directory exists; otherwise, it throws
|
|
52
|
+
* an error indicating that the directory does not exist.
|
|
53
|
+
*
|
|
54
|
+
* @param dirPath - The path to the directory to check
|
|
55
|
+
* @returns true if the directory exists, false otherwise
|
|
56
|
+
*/
|
|
57
|
+
const checkDirectoryExists = (dirPath) => {
|
|
58
|
+
try {
|
|
59
|
+
statSync(dirPath);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
class OutputFormatter {
|
|
67
|
+
tail;
|
|
68
|
+
formatting;
|
|
69
|
+
onData = (data) => {
|
|
70
|
+
const lines = data.split('\n').slice(-this.tail);
|
|
71
|
+
const str = lines.join('\n');
|
|
72
|
+
this.ora.suffixText = this.formatting
|
|
73
|
+
? this.formatting(`\n${str}`.trimEnd())
|
|
74
|
+
: `\n${str}`.trimEnd();
|
|
75
|
+
};
|
|
76
|
+
setOra = (ora) => {
|
|
77
|
+
this.ora = ora;
|
|
78
|
+
};
|
|
79
|
+
ora = null;
|
|
80
|
+
constructor(tail = 10, formatting) {
|
|
81
|
+
this.tail = tail;
|
|
82
|
+
this.formatting = formatting;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export default class CreateApp extends Command {
|
|
86
|
+
static description = 'sets up a preconfigued vite app directory on for a shopify theme';
|
|
87
|
+
static examples = [
|
|
88
|
+
'<%= config.bin %> <%= command.id %>',
|
|
89
|
+
];
|
|
90
|
+
static flags = {
|
|
91
|
+
dir: Flags.string({ char: 'd', default: 'src', description: 'directory to create the vite app in' }),
|
|
92
|
+
'skip-check': Flags.boolean({ char: 's', description: 'skips the checking of the parent directory for a shopify theme' }),
|
|
93
|
+
};
|
|
94
|
+
async run() {
|
|
95
|
+
const { flags } = await this.parse(CreateApp);
|
|
96
|
+
// Checking if a src folder already exists
|
|
97
|
+
const targetDir = join(process.cwd(), flags.dir);
|
|
98
|
+
if (checkDirectoryExists(targetDir)) {
|
|
99
|
+
this.log(chalk.red('Directory', chalk.bold(targetDir), 'already exists'));
|
|
100
|
+
this.log(chalk.yellow('Use the', chalk.bold.white('--dir <dir>'), 'flag to specify a different directory.'));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Checking if the dir is a shopify theme
|
|
104
|
+
if (!flags['skip-check']) {
|
|
105
|
+
const requiredDirs = ['snippets', 'assets', 'sections', 'templates', 'config', 'layout'];
|
|
106
|
+
const targetDirParent = resolve(targetDir, '..');
|
|
107
|
+
const hasAll = requiredDirs.every(dir => checkDirectoryExists(join(targetDirParent, dir)));
|
|
108
|
+
if (!hasAll) {
|
|
109
|
+
this.log(chalk.red('Parent directory of target is not a Shopify theme directory.'));
|
|
110
|
+
this.log(chalk.yellow('Use the', chalk.bold.white('--skip-check'), 'flag to disable checking for a Shopify theme.'));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Making directory
|
|
115
|
+
mkdirSync(targetDir);
|
|
116
|
+
// Cloning the vite template from FireNet-Designs
|
|
117
|
+
const git = simpleGit(targetDir, { binary: 'git' });
|
|
118
|
+
const formatter = new OutputFormatter(10, chalk.dim);
|
|
119
|
+
{
|
|
120
|
+
const spinner = ora('Cloning template...').start();
|
|
121
|
+
await git.clone('git@github.com:FireNet-Designs/vite-template.git', targetDir);
|
|
122
|
+
spinner.succeed('Cloned template');
|
|
123
|
+
}
|
|
124
|
+
{
|
|
125
|
+
const spinner = ora('Deleting .git directory...').start();
|
|
126
|
+
const gitDir = join(targetDir, '.git');
|
|
127
|
+
rmSync(gitDir, { recursive: true });
|
|
128
|
+
spinner.succeed('Deleted .git directory');
|
|
129
|
+
}
|
|
130
|
+
{
|
|
131
|
+
const spinner = ora('Switching/installing node version...').start();
|
|
132
|
+
formatter.setOra(spinner);
|
|
133
|
+
const { stderr } = await execCommands([`cd ${targetDir}`, 'nvm install'], { onOutput: formatter.onData, timeout: 10_000 });
|
|
134
|
+
if (stderr.length > 0 && !stderr.includes('already installed')) {
|
|
135
|
+
spinner.fail('Failed to install node version');
|
|
136
|
+
return this.error(stderr, { code: '1' });
|
|
137
|
+
}
|
|
138
|
+
spinner.suffixText = '';
|
|
139
|
+
spinner.succeed('Installed node version');
|
|
140
|
+
}
|
|
141
|
+
{
|
|
142
|
+
const spinner = ora('Installing dependencies...').start();
|
|
143
|
+
formatter.setOra(spinner);
|
|
144
|
+
const { stderr } = await execCommands([`cd ${targetDir}`, 'nvm use', 'npm ci'], { onOutput: formatter.onData, timeout: 60_000 });
|
|
145
|
+
if (stderr.length > 0) {
|
|
146
|
+
spinner.fail('Failed to install dependencies');
|
|
147
|
+
return this.error(stderr, { code: '1' });
|
|
148
|
+
}
|
|
149
|
+
spinner.suffixText = '';
|
|
150
|
+
spinner.succeed('Installed dependencies');
|
|
151
|
+
}
|
|
152
|
+
this.log("You're good to go :-)");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { simpleGit } from 'simple-git';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { rmSync, readFileSync } from 'node:fs';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
const hook = async function (opts) {
|
|
7
|
+
const tempRepo = join(os.tmpdir(), 'fnd-cli');
|
|
8
|
+
try {
|
|
9
|
+
const git = simpleGit({ binary: 'git' });
|
|
10
|
+
await git.clone('git@github.com:FireNet-Designs/fnd-cli.git', tempRepo, { '--depth': 1 });
|
|
11
|
+
// Getting package.json file to check version
|
|
12
|
+
const pjson = JSON.parse(readFileSync(join(tempRepo, 'package.json'), 'utf-8'));
|
|
13
|
+
const newestVersion = pjson.version;
|
|
14
|
+
const ourVersion = opts.config.pjson.version;
|
|
15
|
+
if (newestVersion !== ourVersion) {
|
|
16
|
+
console.log(chalk.yellow('💡 Version', chalk.green(newestVersion), 'available! Run', chalk.green('`npm i -g git@github.com:FireNet-Designs/fnd-cli.git`'), 'to update to the latest version!\n'));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
// Deleting the temp repo but ignoring errors
|
|
21
|
+
try {
|
|
22
|
+
rmSync(tempRepo, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
catch { }
|
|
25
|
+
;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export default hook;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { run } from '@oclif/core';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { run } from '@oclif/core';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"commands": {
|
|
3
|
+
"create-app": {
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"args": {},
|
|
6
|
+
"description": "sets up a preconfigued vite app directory on for a shopify theme",
|
|
7
|
+
"examples": [
|
|
8
|
+
"<%= config.bin %> <%= command.id %>"
|
|
9
|
+
],
|
|
10
|
+
"flags": {
|
|
11
|
+
"dir": {
|
|
12
|
+
"char": "d",
|
|
13
|
+
"description": "directory to create the vite app in",
|
|
14
|
+
"name": "dir",
|
|
15
|
+
"default": "src",
|
|
16
|
+
"hasDynamicHelp": false,
|
|
17
|
+
"multiple": false,
|
|
18
|
+
"type": "option"
|
|
19
|
+
},
|
|
20
|
+
"skip-check": {
|
|
21
|
+
"char": "s",
|
|
22
|
+
"description": "skips the checking of the parent directory for a shopify theme",
|
|
23
|
+
"name": "skip-check",
|
|
24
|
+
"allowNo": false,
|
|
25
|
+
"type": "boolean"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"hasDynamicHelp": false,
|
|
29
|
+
"hiddenAliases": [],
|
|
30
|
+
"id": "create-app",
|
|
31
|
+
"pluginAlias": "@firenet-designs/fnd-cli",
|
|
32
|
+
"pluginName": "@firenet-designs/fnd-cli",
|
|
33
|
+
"pluginType": "core",
|
|
34
|
+
"strict": true,
|
|
35
|
+
"enableJsonFlag": false,
|
|
36
|
+
"isESM": true,
|
|
37
|
+
"relativePath": [
|
|
38
|
+
"dist",
|
|
39
|
+
"commands",
|
|
40
|
+
"create-app.js"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"version": "1.0.1"
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@firenet-designs/fnd-cli",
|
|
3
|
+
"description": "A new CLI generated with oclif",
|
|
4
|
+
"version": "1.0.1",
|
|
5
|
+
"author": "Cole Denslow",
|
|
6
|
+
"bin": {
|
|
7
|
+
"fnd-cli": "bin/run.js"
|
|
8
|
+
},
|
|
9
|
+
"bugs": "https://github.com/FireNet-Designs/fnd-cli/issues",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@oclif/core": "^4",
|
|
12
|
+
"@oclif/plugin-help": "^6",
|
|
13
|
+
"@oclif/plugin-plugins": "^5",
|
|
14
|
+
"chalk": "^5.6.2",
|
|
15
|
+
"ora": "^9.3.0",
|
|
16
|
+
"simple-git": "^3.32.2"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@eslint/compat": "^1",
|
|
20
|
+
"@oclif/prettier-config": "^0.2.1",
|
|
21
|
+
"@oclif/test": "^4",
|
|
22
|
+
"@types/chai": "^4",
|
|
23
|
+
"@types/mocha": "^10",
|
|
24
|
+
"@types/node": "^18.19.130",
|
|
25
|
+
"chai": "^4",
|
|
26
|
+
"eslint": "^9",
|
|
27
|
+
"eslint-config-oclif": "^6",
|
|
28
|
+
"eslint-config-prettier": "^10",
|
|
29
|
+
"mocha": "^10",
|
|
30
|
+
"oclif": "^4",
|
|
31
|
+
"shx": "^0.3.3",
|
|
32
|
+
"ts-node": "^10",
|
|
33
|
+
"typescript": "^5"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"./bin",
|
|
40
|
+
"./dist",
|
|
41
|
+
"./oclif.manifest.json"
|
|
42
|
+
],
|
|
43
|
+
"homepage": "https://github.com/FireNet-Designs/fnd-cli",
|
|
44
|
+
"keywords": [
|
|
45
|
+
"oclif"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"main": "dist/index.js",
|
|
49
|
+
"type": "module",
|
|
50
|
+
"oclif": {
|
|
51
|
+
"bin": "fnd-cli",
|
|
52
|
+
"dirname": "fnd-cli",
|
|
53
|
+
"commands": "./dist/commands",
|
|
54
|
+
"hooks": {
|
|
55
|
+
"init": [
|
|
56
|
+
"./dist/hooks/init/check-for-updates"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"plugins": [
|
|
60
|
+
"@oclif/plugin-help"
|
|
61
|
+
],
|
|
62
|
+
"topicSeparator": " ",
|
|
63
|
+
"topics": {
|
|
64
|
+
"hello": {
|
|
65
|
+
"description": "Say hello to the world and others"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"repository": {
|
|
70
|
+
"type": "git",
|
|
71
|
+
"url": "git+https://github.com/FireNet-Designs/fnd-cli.git"
|
|
72
|
+
},
|
|
73
|
+
"scripts": {
|
|
74
|
+
"build": "shx rm -rf dist && tsc -b",
|
|
75
|
+
"lint": "eslint",
|
|
76
|
+
"postpack": "shx rm -f oclif.manifest.json",
|
|
77
|
+
"posttest": "npm run lint",
|
|
78
|
+
"prepack": "oclif manifest && oclif readme",
|
|
79
|
+
"version": "oclif readme && git add README.md",
|
|
80
|
+
"release": "npm run build && npm run prepack && npm publish --access public"
|
|
81
|
+
},
|
|
82
|
+
"types": "dist/index.d.ts"
|
|
83
|
+
}
|