@atomicsmash/cli 11.0.0 → 12.0.0-beta.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.
@@ -1 +1 @@
1
- {"version":3,"file":"pull-database.d.ts","sourceRoot":"","sources":["../../src/commands/pull-database.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,OAAO,kBAAkB,CAAC;AACvC,eAAO,MAAM,QAAQ,oEAC6C,CAAC;AACnE,wBAAsB,OAAO,kBAgJ5B"}
1
+ {"version":3,"file":"pull-database.d.ts","sourceRoot":"","sources":["../../src/commands/pull-database.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,OAAO,kBAAkB,CAAC;AACvC,eAAO,MAAM,QAAQ,oEAC6C,CAAC;AAEnE,wBAAsB,OAAO,kBA4I5B"}
@@ -8,128 +8,104 @@ export const command = "pull-database";
8
8
  export const describe = "Pull the database down from staging and replace local database.";
9
9
  export async function handler() {
10
10
  const execute = promisify(exec);
11
- const smashConfig = await getSmashConfig();
12
- const stagingSSHUsername = process.env.STAGING_SSH_USERNAME;
13
- const stagingSSHHost = process.env.STAGING_SSH_HOST;
14
- const stagingSSHPort = process.env.STAGING_SSH_PORT;
15
- const stagingDBPrefix = process.env.STAGING_DB_PREFIX ?? "wp_";
16
- const stagingWebRoot = process.env.STAGING_WEB_ROOT ?? "public/current";
17
- const stagingUrl = process.env.STAGING_URL?.endsWith("/")
18
- ? process.env.STAGING_URL.slice(0, -1)
19
- : process.env.STAGING_URL;
20
- if (!smashConfig) {
21
- throw new Error("Unable to determine project setup information. Please add a smash.config.ts file with the required info.");
22
- }
23
- else if (!stagingSSHUsername) {
24
- throw new Error("STAGING_SSH_USERNAME is missing from .env file.");
25
- }
26
- else if (!stagingSSHHost) {
27
- throw new Error("STAGING_SSH_HOST is missing from .env file.");
28
- }
29
- else if (!stagingSSHPort) {
30
- throw new Error("STAGING_SSH_PORT is missing from .env file.");
31
- }
32
- else if (!stagingUrl) {
33
- throw new Error("STAGING_URL is missing from .env file.");
34
- }
35
- else {
36
- const { projectName } = smashConfig;
37
- const stopRunningMessage = startRunningMessage("Pulling database from staging");
38
- performance.mark("Start");
39
- await (async () => {
40
- const tmpFile = "/tmp/staging-database.sql";
41
- const dbPrefixFile = "/tmp/db-prefix.txt";
42
- const tablesToExclude = [
43
- // WordFence
44
- "wfauditevents",
45
- "wfblockediplog",
46
- "wfblocks7",
47
- "wfconfig",
48
- "wfcrawlers",
49
- "wffilemods",
50
- "wfhits",
51
- "wfhoover",
52
- "wfissues",
53
- "wfknownfilelist",
54
- "wflivetraffichuman",
55
- "wflocs",
56
- "wflogins",
57
- "wfls_2fa_secrets",
58
- "wfls_role_counts",
59
- "wfls_settings",
60
- "wfnotifications",
61
- "wfpendingissues",
62
- "wfreversecache",
63
- "wfsecurityevents",
64
- "wfsnipcache",
65
- "wfstatus",
66
- "wftrafficrates",
67
- "wfwaffailures",
68
- // WP All Import/Export
69
- "pmxi_files",
70
- "pmxi_geocoding",
71
- "pmxi_hash",
72
- "pmxi_history",
73
- "pmxi_images",
74
- "pmxi_imports",
75
- "pmxi_posts",
76
- "pmxi_templates",
77
- ].map((tableName) => stagingDBPrefix + tableName);
78
- await execute(`ssh -o "StrictHostKeyChecking no" ${stagingSSHUsername}@${stagingSSHHost} -p ${stagingSSHPort} "${stagingWebRoot !== "" ? `cd ${stagingWebRoot} && ` : ""}wp db export - --add-drop-table --exclude_tables=${tablesToExclude.join(",")}" > ${tmpFile}`)
79
- .then(async () => {
80
- await stopRunningMessage();
81
- console.log("Database downloaded.");
82
- await execute(`wp db check`).catch(async () => {
83
- await execute(`wp db create`);
84
- console.log("Local database created.");
85
- });
86
- const stopRunningMessage2 = startRunningMessage("Importing database");
87
- await execute(`wp db query < ${tmpFile}`)
88
- .then(async () => {
89
- await stopRunningMessage2();
90
- console.log("Database imported.");
91
- })
92
- .catch(async (error) => {
93
- await stopRunningMessage2();
94
- throw error;
95
- });
96
- })
11
+ const smashConfig = await getSmashConfig(2);
12
+ const { projectName, staging: { url: stagingURL, dbPrefix: stagingDBPrefix, webRoot: stagingWebRoot, ssh: { username: stagingSSHUsername, host: stagingSSHHost, port: stagingSSHPort, }, }, } = smashConfig;
13
+ const stopRunningMessage = startRunningMessage("Pulling database from staging");
14
+ performance.mark("Start");
15
+ await (async () => {
16
+ const tmpFile = "/tmp/staging-database.sql";
17
+ const dbPrefixFile = "/tmp/db-prefix.txt";
18
+ const tablesToExclude = [
19
+ // WordFence
20
+ "wfauditevents",
21
+ "wfblockediplog",
22
+ "wfblocks7",
23
+ "wfconfig",
24
+ "wfcrawlers",
25
+ "wffilemods",
26
+ "wfhits",
27
+ "wfhoover",
28
+ "wfissues",
29
+ "wfknownfilelist",
30
+ "wflivetraffichuman",
31
+ "wflocs",
32
+ "wflogins",
33
+ "wfls_2fa_secrets",
34
+ "wfls_role_counts",
35
+ "wfls_settings",
36
+ "wfnotifications",
37
+ "wfpendingissues",
38
+ "wfreversecache",
39
+ "wfsecurityevents",
40
+ "wfsnipcache",
41
+ "wfstatus",
42
+ "wftrafficrates",
43
+ "wfwaffailures",
44
+ // WP All Import/Export
45
+ "pmxi_files",
46
+ "pmxi_geocoding",
47
+ "pmxi_hash",
48
+ "pmxi_history",
49
+ "pmxi_images",
50
+ "pmxi_imports",
51
+ "pmxi_posts",
52
+ "pmxi_templates",
53
+ ].map((tableName) => stagingDBPrefix + tableName);
54
+ const port = stagingSSHPort ? `-p ${stagingSSHPort.toString()}` : ``;
55
+ await execute(`ssh -o "StrictHostKeyChecking no" ${stagingSSHUsername}@${stagingSSHHost} ${port} "${stagingWebRoot !== "" ? `cd ${stagingWebRoot} && ` : ""} wp db export - --add-drop-table --exclude_tables=${tablesToExclude.join(",")}" > ${tmpFile}`)
56
+ .then(async () => {
57
+ await stopRunningMessage();
58
+ console.log("Database downloaded.");
59
+ await execute(`wp db check`).catch(async () => {
60
+ await execute(`wp db create`);
61
+ console.log("Local database created.");
62
+ });
63
+ const stopRunningMessage2 = startRunningMessage("Importing database");
64
+ await execute(`wp db query < ${tmpFile}`)
97
65
  .then(async () => {
98
- const stopRunningMessage3 = startRunningMessage("Running search and replace");
99
- await execute(`wp search-replace --url=${projectName}.test ${stagingUrl} '//${projectName}.test' --skip-columns=guid`)
100
- .then(async () => {
101
- await stopRunningMessage3();
102
- console.log("Search and replace completed.");
103
- })
104
- .catch(async (error) => {
105
- await stopRunningMessage3();
106
- throw error;
107
- });
66
+ await stopRunningMessage2();
67
+ console.log("Database imported.");
108
68
  })
69
+ .catch(async (error) => {
70
+ await stopRunningMessage2();
71
+ throw error;
72
+ });
73
+ })
74
+ .then(async () => {
75
+ const stopRunningMessage3 = startRunningMessage("Running search and replace");
76
+ await execute(`wp search-replace --url=${projectName}.test //${stagingURL} '//${projectName}.test'`)
109
77
  .then(async () => {
110
- const stopRunningMessage4 = startRunningMessage("Cleaning up");
111
- await Promise.allSettled([
112
- deleteFile(tmpFile),
113
- deleteFile(dbPrefixFile),
114
- ]).then(async () => {
115
- await stopRunningMessage4();
116
- });
117
- console.log(`Database import complete! ${convertMeasureToPrettyString(performance.measure("everything", "Start"))}`);
118
- console.log("If you want to download recent media you can use `npm run pull:media`, you can also change the number of months to download in your `.env` file.");
78
+ await stopRunningMessage3();
79
+ console.log("Search and replace completed.");
119
80
  })
120
81
  .catch(async (error) => {
121
- await stopRunningMessage();
122
- console.error("Error during database pull:", error);
123
- const cleanupResults = await Promise.allSettled([
124
- deleteFile(tmpFile),
125
- deleteFile(dbPrefixFile),
126
- ]);
127
- const failedCleanups = cleanupResults.filter((result) => result.status === "rejected");
128
- if (failedCleanups.length > 0) {
129
- console.warn(`Warning: Failed to delete ${failedCleanups.length.toString()} temporary file(s). You may need to clean them up manually.`);
130
- }
131
- process.exitCode = 1;
82
+ await stopRunningMessage3();
83
+ throw error;
84
+ });
85
+ })
86
+ .then(async () => {
87
+ const stopRunningMessage4 = startRunningMessage("Cleaning up");
88
+ await Promise.allSettled([
89
+ deleteFile(tmpFile),
90
+ deleteFile(dbPrefixFile),
91
+ ]).then(async () => {
92
+ await stopRunningMessage4();
132
93
  });
133
- })();
134
- }
94
+ console.log(`Database import complete! ${convertMeasureToPrettyString(performance.measure("everything", "Start"))}`);
95
+ console.log("If you want to download recent media you can use `npm run pull:media`, you can also change the number of months to download in your `.env` file.");
96
+ })
97
+ .catch(async (error) => {
98
+ await stopRunningMessage();
99
+ console.error("Error during database pull:", error);
100
+ const cleanupResults = await Promise.allSettled([
101
+ deleteFile(tmpFile),
102
+ deleteFile(dbPrefixFile),
103
+ ]);
104
+ const failedCleanups = cleanupResults.filter((result) => result.status === "rejected");
105
+ if (failedCleanups.length > 0) {
106
+ console.warn(`Warning: Failed to delete ${failedCleanups.length.toString()} temporary file(s). You may need to clean them up manually.`);
107
+ }
108
+ process.exitCode = 1;
109
+ });
110
+ })();
135
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pull-media.d.ts","sourceRoot":"","sources":["../../src/commands/pull-media.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,OAAO,eAAe,CAAC;AACpC,eAAO,MAAM,QAAQ,gDAAgD,CAAC;AACtE,wBAAsB,OAAO,kBA+E5B"}
1
+ {"version":3,"file":"pull-media.d.ts","sourceRoot":"","sources":["../../src/commands/pull-media.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,OAAO,eAAe,CAAC;AACpC,eAAO,MAAM,QAAQ,gDAAgD,CAAC;AACtE,wBAAsB,OAAO,kBAgE5B"}
@@ -4,13 +4,15 @@ import { resolve } from "node:path";
4
4
  import { performance } from "node:perf_hooks";
5
5
  import { promisify } from "node:util";
6
6
  import { startRunningMessage } from "../utils.js";
7
+ import { getSmashConfig } from "@atomicsmash/smash-config";
7
8
  const execute = promisify(exec);
8
9
  async function downloadFiles(remotePath, localPath, ssh) {
10
+ const port = ssh.port ? `-P ${ssh.port.toString()}` : ``;
9
11
  try {
10
12
  // Create local directory if it doesn't exist
11
13
  await mkdir(localPath, { recursive: true });
12
14
  // Download files using scp
13
- await execute(`scp -r -p -O -o "StrictHostKeyChecking no" -P ${ssh.port} "${ssh.username}@${ssh.host}:${remotePath}" "${localPath}"`);
15
+ await execute(`scp -r -p -O -o "StrictHostKeyChecking no" ${port} "${ssh.username}@${ssh.host}:${remotePath}" "${localPath}"`);
14
16
  }
15
17
  catch (error) {
16
18
  console.log(`Failed to download ${remotePath}`);
@@ -23,78 +25,48 @@ async function downloadFiles(remotePath, localPath, ssh) {
23
25
  export const command = "pull-media";
24
26
  export const describe = "Pull the media items from the staging site.";
25
27
  export async function handler() {
26
- const stagingSSHUsername = process.env.STAGING_SSH_USERNAME;
27
- const stagingSSHHost = process.env.STAGING_SSH_HOST;
28
- const stagingSSHPort = process.env.STAGING_SSH_PORT;
29
- const stagingUrl = process.env.STAGING_URL?.endsWith("/")
30
- ? process.env.STAGING_URL.slice(0, -1)
31
- : process.env.STAGING_URL;
32
- const mediaMonths = parseInt(process.env.MEDIA_DOWNLOAD_MONTHS ?? "-1");
33
- const mediaPath = process.env.MEDIA_DOWNLOAD_PATH;
34
- const mediaLocalPath = process.env.MEDIA_DOWNLOAD_LOCAL_PATH;
35
- if (!stagingSSHUsername) {
36
- throw new Error("STAGING_SSH_USERNAME is missing from .env file.");
37
- }
38
- else if (!stagingSSHHost) {
39
- throw new Error("STAGING_SSH_HOST is missing from .env file.");
40
- }
41
- else if (!stagingSSHPort) {
42
- throw new Error("STAGING_SSH_PORT is missing from .env file.");
43
- }
44
- else if (!stagingUrl) {
45
- throw new Error("STAGING_URL is missing from .env file.");
46
- }
47
- else if (!mediaPath) {
48
- throw new Error("MEDIA_DOWNLOAD_PATH is missing from .env file.");
49
- }
50
- else if (!mediaLocalPath) {
51
- throw new Error("MEDIA_DOWNLOAD_LOCAL_PATH is missing from .env file.");
52
- }
53
- else {
54
- const ssh = {
55
- port: stagingSSHPort,
56
- host: stagingSSHHost,
57
- username: stagingSSHUsername,
58
- };
59
- const stopRunningMessage = startRunningMessage("Pulling media from staging");
60
- performance.mark("Start");
61
- await (async () => {
62
- if (mediaMonths === -1) {
63
- console.log("Downloading entire uploads directory...");
64
- const localPath = resolve(mediaLocalPath, "..");
65
- console.log(`Downloading entire uploads directory: ${mediaPath} -> ${localPath}`);
66
- await downloadFiles(mediaPath, localPath, ssh);
67
- }
68
- else {
69
- console.log(`Downloading media for the last ${mediaMonths.toString()} months...`);
70
- // Download media for each month
71
- for (let i = 0; i < mediaMonths; i++) {
72
- const date = new Date();
73
- date.setMonth(date.getMonth() - i);
74
- const year = date.getFullYear();
75
- const month = String(date.getMonth() + 1).padStart(2, "0");
76
- const remotePath = `${mediaPath}/${year.toString()}/${month}`;
77
- const localPath = `${mediaLocalPath}/${year.toString()}`;
78
- console.log(`Attempting to download: ${remotePath} -> ${localPath}`);
79
- try {
80
- await downloadFiles(remotePath, localPath, ssh);
81
- }
82
- catch {
83
- console.log(`Skipping uploads/${year.toString()}/${month} - directory does not exist on remote server`);
84
- return; // Skip to next iteration
85
- }
28
+ const { uploadsPath: uploadsPath, staging: { uploadsPath: stagingUploadsPath, webRoot: stagingWebRoot, ssh: stagingSSHDetails, }, cli: { pullMedia: { monthsToPull }, }, } = await getSmashConfig(2);
29
+ const mediaMonths = monthsToPull;
30
+ const mediaServerPath = `${stagingWebRoot}/${stagingUploadsPath}`;
31
+ const mediaLocalPath = uploadsPath;
32
+ const stopRunningMessage = startRunningMessage("Pulling media from staging");
33
+ performance.mark("Start");
34
+ await (async () => {
35
+ if (mediaMonths === -1) {
36
+ console.log("Downloading entire uploads directory...");
37
+ const localPath = resolve(mediaLocalPath, "..");
38
+ console.log(`Downloading entire uploads directory: ${mediaServerPath} -> ${localPath}`);
39
+ await downloadFiles(mediaServerPath, localPath, stagingSSHDetails);
40
+ }
41
+ else {
42
+ console.log(`Downloading media for the last ${mediaMonths.toString()} months...`);
43
+ // Download media for each month
44
+ for (let i = 0; i < mediaMonths; i++) {
45
+ const date = new Date();
46
+ date.setMonth(date.getMonth() - i);
47
+ const year = date.getFullYear();
48
+ const month = String(date.getMonth() + 1).padStart(2, "0");
49
+ const remotePath = `${mediaServerPath}/${year.toString()}/${month}`;
50
+ const localPath = `${mediaLocalPath}/${year.toString()}`;
51
+ console.log(`Attempting to download: ${remotePath} -> ${localPath}`);
52
+ try {
53
+ await downloadFiles(remotePath, localPath, stagingSSHDetails);
54
+ }
55
+ catch {
56
+ console.log(`Skipping uploads/${year.toString()}/${month} - directory does not exist on remote server`);
57
+ return; // Skip to next iteration
86
58
  }
87
- console.log("Finished attempting to download all requested months");
88
59
  }
89
- })()
90
- .then(async () => {
91
- await stopRunningMessage();
92
- console.log("Media download complete!");
93
- })
94
- .catch(async () => {
95
- await stopRunningMessage();
96
- console.log("There was an error downloading the media, see the message above.");
97
- process.exitCode = 1;
98
- });
99
- }
60
+ console.log("Finished attempting to download all requested months");
61
+ }
62
+ })()
63
+ .then(async () => {
64
+ await stopRunningMessage();
65
+ console.log("Media download complete!");
66
+ })
67
+ .catch(async () => {
68
+ await stopRunningMessage();
69
+ console.log("There was an error downloading the media, see the message above.");
70
+ process.exitCode = 1;
71
+ });
100
72
  }
@@ -1,5 +1,6 @@
1
1
  import "dotenv/config";
2
2
  export declare const command = "setup-database";
3
3
  export declare const describe = "Create a new database and initialise the site with no content.";
4
+ export declare const deprecated = "You probably no longer need this with changes to the pull database script. If you do, migrate a copy of these commands into a local project script.";
4
5
  export declare function handler(): Promise<void>;
5
6
  //# sourceMappingURL=setup-database.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup-database.d.ts","sourceRoot":"","sources":["../../src/commands/setup-database.ts"],"names":[],"mappings":"AAKA,OAAO,eAAe,CAAC;AA+EvB,eAAO,MAAM,OAAO,mBAAmB,CAAC;AACxC,eAAO,MAAM,QAAQ,mEAC4C,CAAC;AAClE,wBAAsB,OAAO,kBA6H5B"}
1
+ {"version":3,"file":"setup-database.d.ts","sourceRoot":"","sources":["../../src/commands/setup-database.ts"],"names":[],"mappings":"AAKA,OAAO,eAAe,CAAC;AA+EvB,eAAO,MAAM,OAAO,mBAAmB,CAAC;AACxC,eAAO,MAAM,QAAQ,mEAC4C,CAAC;AAClE,eAAO,MAAM,UAAU,wJAC+H,CAAC;AACvJ,wBAAsB,OAAO,kBAuH5B"}
@@ -61,6 +61,7 @@ async function activatePluginsWithRetry(execute, pluginsToActivate, excludedPlug
61
61
  }
62
62
  export const command = "setup-database";
63
63
  export const describe = "Create a new database and initialise the site with no content.";
64
+ export const deprecated = "You probably no longer need this with changes to the pull database script. If you do, migrate a copy of these commands into a local project script.";
64
65
  export async function handler() {
65
66
  const execute = promisify(exec);
66
67
  const smashConfig = await getSmashConfig();
@@ -74,69 +75,64 @@ export async function handler() {
74
75
  password: process.env.WORDPRESS_PASSWORD,
75
76
  }
76
77
  : null;
77
- if (!smashConfig) {
78
- throw new Error("Unable to determine project setup information. Please add a smash.config.ts file with the required info.");
79
- }
80
- else {
81
- const { projectName, themeFolderName } = smashConfig;
82
- const stopRunningMessage = startRunningMessage("Initialising database");
83
- performance.mark("Start");
84
- await execute("wp db create")
85
- .then(() => {
86
- return execute(`wp core install --url=http://${process.env.CI ? "127.0.0.1" : `${projectName}.test`}/ --title=Temp --admin_user=Bot --admin_email=fake@fake.com --admin_password=password`);
87
- })
88
- .then(() => {
89
- performance.mark("wordpress-tables");
90
- console.log(`Wordpress database tables installed. (${convertMeasureToPrettyString(performance.measure("wordpress-tables", "Start"))})`);
91
- if (newUserToAdd) {
92
- return execute(`wp user create ${newUserToAdd.user} ${newUserToAdd.email} --user_pass=${newUserToAdd.password} --role=administrator`);
93
- }
94
- })
95
- .then(async () => {
96
- if (newUserToAdd) {
97
- performance.mark("add-custom-user");
98
- console.log(`Custom user ${newUserToAdd.user} added. (${convertMeasureToPrettyString(performance.measure("add-custom-user", "wordpress-tables"))})`);
99
- }
100
- const excludedPlugins = [
101
- "stream",
102
- "shortpixel-image-optimiser",
103
- "wordfence",
104
- "wp-mail-smtp",
105
- "modular-connector",
106
- ];
107
- const { stdout: pluginList } = await execute("wp plugin list --format=json");
108
- const allPlugins = JSON.parse(pluginList);
109
- // Filter out excluded plugins and already active plugins
110
- const pluginsToActivate = allPlugins
111
- .filter((plugin) => !excludedPlugins.includes(plugin.name) &&
112
- plugin.status !== "active")
113
- .map((plugin) => plugin.name);
114
- await activatePluginsWithRetry(execute, pluginsToActivate, excludedPlugins);
115
- })
116
- .then(() => {
117
- performance.mark("plugins");
118
- console.log(`Plugins activated. (${convertMeasureToPrettyString(performance.measure("plugins", newUserToAdd ? "add-custom-user" : "wordpress-tables"))})`);
119
- return execute(`wp theme activate ${themeFolderName}`);
120
- })
121
- .then(async () => {
122
- performance.mark("theme");
123
- console.log(`Theme activated. (${convertMeasureToPrettyString(performance.measure("theme", "plugins"))})`);
124
- await stopRunningMessage();
125
- console.log(`Database set up${newUserToAdd ? ` and ${newUserToAdd.user} user added` : !process.env.CI ? ". To set up a user, run the `wp user create` command." : ""}. (${convertMeasureToPrettyString(performance.measure("everything", "Start"))})`);
126
- })
127
- .catch(async (error) => {
128
- await stopRunningMessage();
129
- if (typeof error === "object" &&
130
- error &&
131
- "stderr" in error &&
132
- typeof error.stderr === "string" &&
133
- error.stderr.startsWith("ERROR 1007")) {
134
- console.error("Database already exists with the name in the wp-config. Please delete that database first with `wp db drop --yes`");
135
- }
136
- else {
137
- console.error(error);
138
- process.exitCode = 1;
139
- }
140
- });
141
- }
78
+ const { projectName, themeFolderName } = smashConfig;
79
+ const stopRunningMessage = startRunningMessage("Initialising database");
80
+ performance.mark("Start");
81
+ await execute("wp db create")
82
+ .then(() => {
83
+ return execute(`wp core install --url=http://${process.env.CI ? "127.0.0.1" : `${projectName}.test`}/ --title=Temp --admin_user=Bot --admin_email=fake@fake.com --admin_password=password`);
84
+ })
85
+ .then(() => {
86
+ performance.mark("wordpress-tables");
87
+ console.log(`Wordpress database tables installed. (${convertMeasureToPrettyString(performance.measure("wordpress-tables", "Start"))})`);
88
+ if (newUserToAdd) {
89
+ return execute(`wp user create ${newUserToAdd.user} ${newUserToAdd.email} --user_pass=${newUserToAdd.password} --role=administrator`);
90
+ }
91
+ })
92
+ .then(async () => {
93
+ if (newUserToAdd) {
94
+ performance.mark("add-custom-user");
95
+ console.log(`Custom user ${newUserToAdd.user} added. (${convertMeasureToPrettyString(performance.measure("add-custom-user", "wordpress-tables"))})`);
96
+ }
97
+ const excludedPlugins = [
98
+ "stream",
99
+ "shortpixel-image-optimiser",
100
+ "wordfence",
101
+ "wp-mail-smtp",
102
+ "modular-connector",
103
+ ];
104
+ const { stdout: pluginList } = await execute("wp plugin list --format=json");
105
+ const allPlugins = JSON.parse(pluginList);
106
+ // Filter out excluded plugins and already active plugins
107
+ const pluginsToActivate = allPlugins
108
+ .filter((plugin) => !excludedPlugins.includes(plugin.name) &&
109
+ plugin.status !== "active")
110
+ .map((plugin) => plugin.name);
111
+ await activatePluginsWithRetry(execute, pluginsToActivate, excludedPlugins);
112
+ })
113
+ .then(() => {
114
+ performance.mark("plugins");
115
+ console.log(`Plugins activated. (${convertMeasureToPrettyString(performance.measure("plugins", newUserToAdd ? "add-custom-user" : "wordpress-tables"))})`);
116
+ return execute(`wp theme activate ${themeFolderName}`);
117
+ })
118
+ .then(async () => {
119
+ performance.mark("theme");
120
+ console.log(`Theme activated. (${convertMeasureToPrettyString(performance.measure("theme", "plugins"))})`);
121
+ await stopRunningMessage();
122
+ console.log(`Database set up${newUserToAdd ? ` and ${newUserToAdd.user} user added` : !process.env.CI ? ". To set up a user, run the `wp user create` command." : ""}. (${convertMeasureToPrettyString(performance.measure("everything", "Start"))})`);
123
+ })
124
+ .catch(async (error) => {
125
+ await stopRunningMessage();
126
+ if (typeof error === "object" &&
127
+ error &&
128
+ "stderr" in error &&
129
+ typeof error.stderr === "string" &&
130
+ error.stderr.startsWith("ERROR 1007")) {
131
+ console.error("Database already exists with the name in the wp-config. Please delete that database first with `wp db drop --yes`");
132
+ }
133
+ else {
134
+ console.error(error);
135
+ process.exitCode = 1;
136
+ }
137
+ });
142
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,eAAO,MAAM,QAAQ,kDAAkD,CAAC;AACxE,wBAAsB,OAAO,kBAoQ5B"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,eAAO,MAAM,QAAQ,kDAAkD,CAAC;AACxE,wBAAsB,OAAO,kBA+P5B"}
@@ -20,167 +20,162 @@ export async function handler() {
20
20
  });
21
21
  const isCI = process.env.CI ?? false;
22
22
  const smashConfig = await getSmashConfig();
23
- if (!smashConfig) {
24
- throw new Error("Unable to determine project setup information. Please add a smash.config.ts file with the required info.");
25
- }
26
- else {
27
- const { projectName, composerInstallPaths, npmInstallPaths } = smashConfig;
28
- const stopRunningMessage = startRunningMessage("Running setup");
29
- performance.mark("Start");
30
- await Promise.allSettled([
31
- ...(isCI || shouldInstallAndBuildOnly
32
- ? []
33
- : [
34
- (async () => {
35
- if (existsSync(".env.example")) {
36
- if (existsSync(".config/environments/.env.dev")) {
37
- throw new Error("Both .env.example and .config/environments/.env.dev files found. Please copy values from the .env.example to the .config/environments/.env.dev file and then delete the .env.example file.");
38
- }
39
- else {
40
- console.log("Moving .env.example to .config/environments/.env.dev");
41
- if (!existsSync(".config/environments")) {
42
- await mkdir(".config/environments", { recursive: true });
43
- }
44
- await copyFile(".env.example", ".config/environments/.env.dev", constants.COPYFILE_EXCL);
45
- await deleteFile(".env.example");
23
+ const { projectName, composerInstallPaths, npmInstallPaths } = smashConfig;
24
+ const stopRunningMessage = startRunningMessage("Running setup");
25
+ performance.mark("Start");
26
+ await Promise.allSettled([
27
+ ...(isCI || shouldInstallAndBuildOnly
28
+ ? []
29
+ : [
30
+ (async () => {
31
+ if (existsSync(".env.example")) {
32
+ if (existsSync(".config/environments/.env.dev")) {
33
+ throw new Error("Both .env.example and .config/environments/.env.dev files found. Please copy values from the .env.example to the .config/environments/.env.dev file and then delete the .env.example file.");
34
+ }
35
+ else {
36
+ console.log("Moving .env.example to .config/environments/.env.dev");
37
+ if (!existsSync(".config/environments")) {
38
+ await mkdir(".config/environments", { recursive: true });
46
39
  }
40
+ await copyFile(".env.example", ".config/environments/.env.dev", constants.COPYFILE_EXCL);
41
+ await deleteFile(".env.example");
47
42
  }
48
- await copyFile(".config/environments/.env.dev", ".env", constants.COPYFILE_EXCL)
43
+ }
44
+ await copyFile(".config/environments/.env.dev", ".env", constants.COPYFILE_EXCL)
45
+ .then(() => {
46
+ console.log(`.config/environments/.env.dev file copied to .env. (${convertMeasureToPrettyString(performance.measure("Copy env file", "Start"))})`);
47
+ })
48
+ .catch((error) => {
49
+ if (error instanceof Error &&
50
+ "code" in error &&
51
+ error.code === "EEXIST") {
52
+ console.log(`Didn't copy .env file because one already exists. (${convertMeasureToPrettyString(performance.measure("Copy env file", "Start"))})`);
53
+ return;
54
+ }
55
+ console.error(error);
56
+ throw new Error("Failed to copy .env file.");
57
+ });
58
+ })(),
59
+ (async () => {
60
+ const ONE_MINUTE_IN_MS = 60000;
61
+ const timeout = setTimeout(() => {
62
+ throw new Error("Herd/Valet commands timed out. Please try again.");
63
+ }, ONE_MINUTE_IN_MS * 1.5);
64
+ if (await execute(`herd --version`)
65
+ .then(() => true)
66
+ .catch(() => false)) {
67
+ if (!existsSync(resolve(process.cwd(), "herd.yaml")) &&
68
+ !existsSync(resolve(process.cwd(), "herd.yml"))) {
69
+ throw new Error("Herd is present on your machine, but the project is missing a herd.yaml file. Please do the initial setup by running herd init.");
70
+ }
71
+ await execute(`herd link ${projectName} --secure`)
49
72
  .then(() => {
50
- console.log(`.config/environments/.env.dev file copied to .env. (${convertMeasureToPrettyString(performance.measure("Copy env file", "Start"))})`);
73
+ performance.mark("herd link done");
74
+ console.log(`Herd is linked and secured. (${convertMeasureToPrettyString(performance.measure("herd link", "Start"))})`);
51
75
  })
52
76
  .catch((error) => {
53
- if (error instanceof Error &&
54
- "code" in error &&
55
- error.code === "EEXIST") {
56
- console.log(`Didn't copy .env file because one already exists. (${convertMeasureToPrettyString(performance.measure("Copy env file", "Start"))})`);
57
- return;
58
- }
59
77
  console.error(error);
60
- throw new Error("Failed to copy .env file.");
78
+ throw new Error("Failed to link the site using Herd.");
61
79
  });
62
- })(),
63
- (async () => {
64
- const ONE_MINUTE_IN_MS = 60000;
65
- const timeout = setTimeout(() => {
66
- throw new Error("Herd/Valet commands timed out. Please try again.");
67
- }, ONE_MINUTE_IN_MS * 1.5);
68
- if (await execute(`herd --version`)
69
- .then(() => true)
70
- .catch(() => false)) {
71
- if (!existsSync(resolve(process.cwd(), "herd.yaml")) &&
72
- !existsSync(resolve(process.cwd(), "herd.yml"))) {
73
- throw new Error("Herd is present on your machine, but the project is missing a herd.yaml file. Please do the initial setup by running herd init.");
74
- }
75
- await execute(`herd link ${projectName} --secure`)
76
- .then(() => {
77
- performance.mark("herd link done");
78
- console.log(`Herd is linked and secured. (${convertMeasureToPrettyString(performance.measure("herd link", "Start"))})`);
79
- })
80
- .catch((error) => {
81
- console.error(error);
82
- throw new Error("Failed to link the site using Herd.");
83
- });
84
- await execute(`herd isolate --site=${projectName}`)
85
- .then(() => {
86
- console.log(`Herd is isolated. (${convertMeasureToPrettyString(performance.measure("herd isolate", "herd link done"))})`);
87
- clearTimeout(timeout);
88
- })
89
- .catch((error) => {
90
- console.error(error);
91
- throw new Error("Failed to isolate the site using Herd.");
92
- });
93
- }
94
- else if (await execute(`valet --version`)
95
- .then(() => true)
96
- .catch(() => false)) {
97
- await execute(`valet link ${projectName} --secure --isolate`)
98
- .then(() => {
99
- clearTimeout(timeout);
100
- console.log(`Valet is linked, secured and isolated. (${convertMeasureToPrettyString(performance.measure("herd-or-valet", "Start"))})`);
101
- })
102
- .catch((error) => {
103
- console.error(error);
104
- throw new Error("Failed to link the site using valet.");
105
- });
106
- }
107
- else {
108
- throw new Error(`Neither Herd nor Valet is present on your machine, check everything is installed correctly.`);
109
- }
110
- })(),
111
- ]),
112
- execute(`composer install${isCI ? " --prefer-dist" : ""}`)
80
+ await execute(`herd isolate --site=${projectName}`)
81
+ .then(() => {
82
+ console.log(`Herd is isolated. (${convertMeasureToPrettyString(performance.measure("herd isolate", "herd link done"))})`);
83
+ clearTimeout(timeout);
84
+ })
85
+ .catch((error) => {
86
+ console.error(error);
87
+ throw new Error("Failed to isolate the site using Herd.");
88
+ });
89
+ }
90
+ else if (await execute(`valet --version`)
91
+ .then(() => true)
92
+ .catch(() => false)) {
93
+ await execute(`valet link ${projectName} --secure --isolate`)
94
+ .then(() => {
95
+ clearTimeout(timeout);
96
+ console.log(`Valet is linked, secured and isolated. (${convertMeasureToPrettyString(performance.measure("herd-or-valet", "Start"))})`);
97
+ })
98
+ .catch((error) => {
99
+ console.error(error);
100
+ throw new Error("Failed to link the site using valet.");
101
+ });
102
+ }
103
+ else {
104
+ throw new Error(`Neither Herd nor Valet is present on your machine, check everything is installed correctly.`);
105
+ }
106
+ })(),
107
+ ]),
108
+ execute(`composer install${isCI ? " --prefer-dist" : ""}`)
109
+ .then(() => {
110
+ console.log(`Root composer install done. (${convertMeasureToPrettyString(performance.measure("root composer install", "Start"))})`);
111
+ })
112
+ .catch((error) => {
113
+ console.error(error);
114
+ throw new Error("Failed to run composer install in the root directory.");
115
+ }),
116
+ ...composerInstallPaths.map((path, index) => {
117
+ return execute(`cd "${resolve(process.cwd(), path)}"; composer install${isCI ? " --no-dev --classmap-authoritative" : ""}`)
113
118
  .then(() => {
114
- console.log(`Root composer install done. (${convertMeasureToPrettyString(performance.measure("root composer install", "Start"))})`);
119
+ console.log(`Additional composer install ${(index + 1).toString()} done. (${convertMeasureToPrettyString(performance.measure(`additional composer install ${(index + 1).toString()}`, "Start"))})`);
115
120
  })
116
121
  .catch((error) => {
117
122
  console.error(error);
118
- throw new Error("Failed to run composer install in the root directory.");
119
- }),
120
- ...composerInstallPaths.map((path, index) => {
121
- return execute(`cd "${resolve(process.cwd(), path)}"; composer install${isCI ? " --no-dev --classmap-authoritative" : ""}`)
122
- .then(() => {
123
- console.log(`Additional composer install ${(index + 1).toString()} done. (${convertMeasureToPrettyString(performance.measure(`additional composer install ${(index + 1).toString()}`, "Start"))})`);
124
- })
125
- .catch((error) => {
126
- console.error(error);
127
- throw new Error(`Failed to run additional composer install ${(index + 1).toString()}.`);
128
- });
129
- }),
130
- (async () => {
131
- await execute(`npm ${isCI ? "ci" : "install"}`)
132
- .then(() => {
133
- performance.mark("root npm install done");
134
- console.log(`Root npm install done. (${convertMeasureToPrettyString(performance.measure("root npm install", "Start"))})`);
135
- })
136
- .catch((error) => {
137
- console.error(error);
138
- throw new Error("Failed to run npm install in the root directory.");
139
- });
140
- await execute("npm run build")
141
- .then(() => {
142
- console.log(`Initial build done. (${convertMeasureToPrettyString(performance.measure("build", "root npm install done"))})`);
143
- })
144
- .catch((error) => {
145
- console.error(error);
146
- throw new Error("Failed to run a build after installing.");
147
- });
148
- })().catch((reason) => {
149
- if (typeof reason === "string") {
150
- throw new Error(reason);
151
- }
152
- throw reason;
153
- }),
154
- ...npmInstallPaths.map((path, index) => {
155
- return execute(`cd "${resolve(process.cwd(), path)}"; npm ${isCI ? "ci --omit=dev" : "install"}`)
156
- .then(() => {
157
- console.log(`Additional npm install ${(index + 1).toString()} done. (${convertMeasureToPrettyString(performance.measure(`additional npm install ${(index + 1).toString()}`, "Start"))})`);
158
- })
159
- .catch((error) => {
160
- console.error(error);
161
- throw new Error(`Failed to run additional npm install ${(index + 1).toString()}.`);
162
- });
163
- }),
164
- ])
165
- .then(async (results) => {
166
- await stopRunningMessage();
167
- if (results.some((result) => result.status === "rejected")) {
168
- process.exitCode = 1;
169
- console.error("Setup failed with the following errors:\n");
170
- console.error(results
171
- .filter((result) => result.status === "rejected")
172
- .map((result) => {
173
- return `- ${typeof result.reason === "string" ? result.reason : "Unknown reason."}`;
174
- })
175
- .join(`\n`));
176
- }
177
- else {
178
- console.log(`Setup is complete. ${convertMeasureToPrettyString(performance.measure("everything", "Start"))}`);
123
+ throw new Error(`Failed to run additional composer install ${(index + 1).toString()}.`);
124
+ });
125
+ }),
126
+ (async () => {
127
+ await execute(`npm ${isCI ? "ci" : "install"}`)
128
+ .then(() => {
129
+ performance.mark("root npm install done");
130
+ console.log(`Root npm install done. (${convertMeasureToPrettyString(performance.measure("root npm install", "Start"))})`);
131
+ })
132
+ .catch((error) => {
133
+ console.error(error);
134
+ throw new Error("Failed to run npm install in the root directory.");
135
+ });
136
+ await execute("npm run build")
137
+ .then(() => {
138
+ console.log(`Initial build done. (${convertMeasureToPrettyString(performance.measure("build", "root npm install done"))})`);
139
+ })
140
+ .catch((error) => {
141
+ console.error(error);
142
+ throw new Error("Failed to run a build after installing.");
143
+ });
144
+ })().catch((reason) => {
145
+ if (typeof reason === "string") {
146
+ throw new Error(reason);
179
147
  }
180
- })
181
- .catch((error) => {
182
- console.error(error);
148
+ throw reason;
149
+ }),
150
+ ...npmInstallPaths.map((path, index) => {
151
+ return execute(`cd "${resolve(process.cwd(), path)}"; npm ${isCI ? "ci --omit=dev" : "install"}`)
152
+ .then(() => {
153
+ console.log(`Additional npm install ${(index + 1).toString()} done. (${convertMeasureToPrettyString(performance.measure(`additional npm install ${(index + 1).toString()}`, "Start"))})`);
154
+ })
155
+ .catch((error) => {
156
+ console.error(error);
157
+ throw new Error(`Failed to run additional npm install ${(index + 1).toString()}.`);
158
+ });
159
+ }),
160
+ ])
161
+ .then(async (results) => {
162
+ await stopRunningMessage();
163
+ if (results.some((result) => result.status === "rejected")) {
183
164
  process.exitCode = 1;
184
- });
185
- }
165
+ console.error("Setup failed with the following errors:\n");
166
+ console.error(results
167
+ .filter((result) => result.status === "rejected")
168
+ .map((result) => {
169
+ return `- ${typeof result.reason === "string" ? result.reason : "Unknown reason."}`;
170
+ })
171
+ .join(`\n`));
172
+ }
173
+ else {
174
+ console.log(`Setup is complete. ${convertMeasureToPrettyString(performance.measure("everything", "Start"))}`);
175
+ }
176
+ })
177
+ .catch((error) => {
178
+ console.error(error);
179
+ process.exitCode = 1;
180
+ });
186
181
  }
@@ -0,0 +1,4 @@
1
+ export declare const command = "toggle-media-proxy";
2
+ export declare const describe = "Toggle the media proxy in the local NGINX config within Herd.";
3
+ export declare function handler(): Promise<void>;
4
+ //# sourceMappingURL=toggle-media-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-media-proxy.d.ts","sourceRoot":"","sources":["../../src/commands/toggle-media-proxy.ts"],"names":[],"mappings":"AAuEA,eAAO,MAAM,OAAO,uBAAuB,CAAC;AAC5C,eAAO,MAAM,QAAQ,kEAC2C,CAAC;AAEjE,wBAAsB,OAAO,kBA2D5B"}
@@ -0,0 +1,91 @@
1
+ import { exec } from "node:child_process";
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { homedir, type } from "node:os";
4
+ import { join } from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { getSmashConfig } from "@atomicsmash/smash-config";
7
+ const PROXY_MARKER = "location @uploadsproxy";
8
+ const execute = promisify(exec);
9
+ function buildProxyBlock(stagingURL, httpAuth) {
10
+ const authHeader = httpAuth
11
+ ? `\n proxy_set_header Authorization "Basic ${httpAuth}";`
12
+ : "";
13
+ return `
14
+ location ^~ /wp-content/uploads/ {
15
+ try_files $uri @uploadsproxy;
16
+ }
17
+
18
+ location @uploadsproxy {
19
+ resolver 8.8.8.8 ipv6=off;
20
+ resolver_timeout 10s;
21
+ proxy_http_version 1.1;
22
+ proxy_ssl_server_name on;
23
+ proxy_pass https://${stagingURL}$uri$is_args$args;
24
+ proxy_ssl_verify off;
25
+ proxy_set_header Referer "";
26
+ proxy_set_header User-Agent "Mozilla/5.0";${authHeader}
27
+ }`;
28
+ }
29
+ function addProxyBlock(config, stagingURL, httpAuth) {
30
+ const listenDirective = "listen 127.0.0.1:443 ssl;";
31
+ const listenIndex = config.indexOf(listenDirective);
32
+ if (listenIndex === -1) {
33
+ throw new Error("Could not locate the SSL server block (listen 127.0.0.1:443 ssl;) in the NGINX config.");
34
+ }
35
+ const nextServerBlockIndex = config.indexOf("\nserver", listenIndex);
36
+ const searchUpTo = nextServerBlockIndex !== -1 ? nextServerBlockIndex : config.length;
37
+ const serverBlockEnd = config.lastIndexOf("}", searchUpTo);
38
+ if (serverBlockEnd === -1 || serverBlockEnd < listenIndex) {
39
+ throw new Error("Could not locate the closing brace of the SSL server block.");
40
+ }
41
+ return (config.slice(0, serverBlockEnd) +
42
+ buildProxyBlock(stagingURL, httpAuth) +
43
+ "\n" +
44
+ config.slice(serverBlockEnd));
45
+ }
46
+ function removeProxyBlock(config) {
47
+ return config.replace(/\n\s*location \^~ \/wp-content\/uploads\/\s*\{[\s\S]*?location @uploadsproxy\s*\{[\s\S]*?\}/, "");
48
+ }
49
+ export const command = "toggle-media-proxy";
50
+ export const describe = "Toggle the media proxy in the local NGINX config within Herd.";
51
+ export async function handler() {
52
+ const smashConfig = await getSmashConfig(2);
53
+ const { projectName, staging: { url: stagingURL, httpAuth: stagingHttpAuth }, } = smashConfig;
54
+ const isMacOS = type() === "Darwin";
55
+ const nginxConfigPath = join(homedir(), isMacOS
56
+ ? "Library/Application Support/Herd/config/valet/Nginx"
57
+ : ".config\\herd\\config\\nginx", `${projectName}.test`);
58
+ let config;
59
+ try {
60
+ config = await readFile(nginxConfigPath, "utf-8");
61
+ }
62
+ catch {
63
+ throw new Error(`Could not read NGINX config at: ${nginxConfigPath}\nMake sure the site exists in Herd.`);
64
+ }
65
+ const httpAuth = stagingHttpAuth
66
+ ? Buffer.from(`${stagingHttpAuth.username}:${stagingHttpAuth.password}`).toString("base64")
67
+ : undefined;
68
+ let updatedConfig;
69
+ if (config.includes(PROXY_MARKER)) {
70
+ updatedConfig = removeProxyBlock(config);
71
+ console.log("Media proxy removed from NGINX config.");
72
+ }
73
+ else {
74
+ updatedConfig = addProxyBlock(config, stagingURL, httpAuth);
75
+ if (httpAuth) {
76
+ console.log("Media proxy added to NGINX config (with HTTP auth).");
77
+ }
78
+ else {
79
+ console.log("Media proxy added to NGINX config (no HTTP auth — STAGING_HTTP_AUTH_USERNAME and STAGING_HTTP_AUTH_PASSWORD not set).");
80
+ }
81
+ }
82
+ await writeFile(nginxConfigPath, updatedConfig, "utf-8");
83
+ console.log("Restarting Herd...");
84
+ await execute("herd restart")
85
+ .then(() => {
86
+ console.log("Herd restarted successfully.");
87
+ })
88
+ .catch(() => {
89
+ console.log("Failed to restart Herd automatically.");
90
+ });
91
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomicsmash/cli",
3
- "version": "11.0.0",
3
+ "version": "12.0.0-beta.1",
4
4
  "description": "A collection of CLI tools by Atomic Smash.",
5
5
  "keywords": [],
6
6
  "homepage": "https://www.atomicsmash.co.uk/",
@@ -40,21 +40,11 @@
40
40
  "lint:types": "tsc -b"
41
41
  },
42
42
  "dependencies": {
43
- "@atomicsmash/date-php": "^2.2.0",
44
- "@atomicsmash/smash-config": "^1.0.2",
45
- "@types/vinyl": "^2.0.12",
46
- "glob-promise": "^6.0.7",
47
- "svg-sprite": "^2.0.4",
48
- "vinyl": "^3.0.1",
43
+ "@atomicsmash/smash-config": "^2.0.0-beta.1",
44
+ "dotenv": "^17.4.2",
49
45
  "yargs": "^18.0.0"
50
46
  },
51
47
  "devDependencies": {
52
- "@atomicsmash/blocks-helpers": "^7.2.2",
53
- "@types/svg-sprite": "^0.0.39",
54
- "type-fest": "^5.6.0"
55
- },
56
- "peerDependencies": {
57
- "dotenv": "^17.3.1",
58
- "typescript": "~5.9.3"
48
+ "type-fest": "^5.7.0"
59
49
  }
60
50
  }
@@ -1,21 +0,0 @@
1
- import type { YargsInstance } from "../cli.js";
2
- import type { ArgumentsCamelCase } from "yargs";
3
- export declare const command = "svg";
4
- export declare const describe = "Generate an SVG sprite from a group of SVGs.";
5
- export declare const deprecated = "Migrate to using @atomicsmash/compiler, which supports an icons folder in the src folder.";
6
- export declare const builder: (yargs: YargsInstance) => import("yargs").Argv<import("yargs").Omit<{}, "in" | "out"> & import("yargs").InferredOptionTypes<{
7
- in: {
8
- demandOption: true;
9
- string: true;
10
- normalize: true;
11
- description: string;
12
- };
13
- out: {
14
- demandOption: true;
15
- string: true;
16
- normalize: true;
17
- description: string;
18
- };
19
- }>>;
20
- export declare function handler(args: ArgumentsCamelCase<Awaited<ReturnType<typeof builder>["argv"]>>): void;
21
- //# sourceMappingURL=svg.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../src/commands/svg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAOhD,eAAO,MAAM,OAAO,QAAQ,CAAC;AAC7B,eAAO,MAAM,QAAQ,iDAAiD,CAAC;AACvE,eAAO,MAAM,UAAU,8FACqE,CAAC;AAC7F,eAAO,MAAM,OAAO,GAAa,OAAO,aAAa;;;;;;;;;;;;;GAiBpD,CAAC;AAEF,wBAAgB,OAAO,CACtB,IAAI,EAAE,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAmErE"}
@@ -1,86 +0,0 @@
1
- import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
2
- import { resolve as resolvePath, join as joinPath, dirname } from "path";
3
- import glob from "glob-promise";
4
- import SVGSpriter from "svg-sprite";
5
- import File from "vinyl";
6
- export const command = "svg";
7
- export const describe = "Generate an SVG sprite from a group of SVGs.";
8
- export const deprecated = "Migrate to using @atomicsmash/compiler, which supports an icons folder in the src folder.";
9
- export const builder = function (yargs) {
10
- return yargs
11
- .options({
12
- in: {
13
- demandOption: true,
14
- string: true,
15
- normalize: true,
16
- description: "The directory where the SVGs can be found.",
17
- },
18
- out: {
19
- demandOption: true,
20
- string: true,
21
- normalize: true,
22
- description: "The directory where the SVG sprite will be output.",
23
- },
24
- })
25
- .example("$0 svg --in icons --out public/assets", "");
26
- };
27
- export function handler(args) {
28
- const config = {
29
- dest: args.out,
30
- shape: {
31
- dimension: {
32
- attributes: false,
33
- },
34
- transform: [
35
- {
36
- svgo: {},
37
- },
38
- ],
39
- },
40
- mode: {
41
- symbol: {
42
- dest: "",
43
- sprite: "sprite.svg",
44
- },
45
- },
46
- };
47
- const spriter = new SVGSpriter(config);
48
- const cwd = resolvePath(args.in);
49
- // Find SVG files recursively via `glob`
50
- glob("**/*.svg", { cwd })
51
- .then(async (files) => {
52
- await new Promise((resolve) => {
53
- files.forEach((file) => {
54
- // Create and add a vinyl file instance for each SVG
55
- spriter.add(new File({
56
- path: joinPath(cwd, file), // Absolute path to the SVG file
57
- base: cwd, // Base path (see `name` argument)
58
- contents: readFileSync(joinPath(cwd, file)), // SVG file contents
59
- }));
60
- });
61
- resolve();
62
- })
63
- .then(async () => {
64
- await spriter
65
- .compileAsync()
66
- .then((compiledResponse) => {
67
- const { result } = compiledResponse;
68
- for (const type of Object.values(result.symbol)) {
69
- if (type.contents) {
70
- mkdirSync(dirname(type.path), { recursive: true });
71
- // TODO: find out how to remove this error.
72
- // eslint-disable-next-line @typescript-eslint/no-base-to-string -- This works despite this error.
73
- writeFileSync(type.path, type.contents.toString());
74
- }
75
- }
76
- });
77
- })
78
- .then(() => {
79
- console.log(`SVG sprite was successfully generated in ${args.out}.`);
80
- });
81
- })
82
- .catch((error) => {
83
- console.error({ error });
84
- throw error;
85
- });
86
- }