@atomicsmash/cli 9.0.1-beta.0 → 9.0.1-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":"setup-database.d.ts","sourceRoot":"","sources":["../../src/commands/setup-database.ts"],"names":[],"mappings":"AAQA,OAAO,eAAe,CAAC;AAEvB,eAAO,MAAM,OAAO,mBAAmB,CAAC;AACxC,eAAO,MAAM,QAAQ,mEAC4C,CAAC;AAClE,wBAAsB,OAAO,kBAuF5B"}
1
+ {"version":3,"file":"setup-database.d.ts","sourceRoot":"","sources":["../../src/commands/setup-database.ts"],"names":[],"mappings":"AAUA,OAAO,eAAe,CAAC;AA4HvB,eAAO,MAAM,OAAO,mBAAmB,CAAC;AACxC,eAAO,MAAM,QAAQ,mEAC4C,CAAC;AAClE,wBAAsB,OAAO,kBAsH5B"}
@@ -1,8 +1,113 @@
1
1
  import { exec } from "node:child_process";
2
+ import { readFileSync, readdirSync } from "node:fs";
3
+ import { join } from "node:path";
2
4
  import { performance } from "node:perf_hooks";
3
5
  import { promisify } from "node:util";
4
6
  import { convertMeasureToPrettyString, getSmashConfig, startRunningMessage, } from "../utils.js";
5
7
  import "dotenv/config";
8
+ function parsePluginHeaders(pluginPath) {
9
+ try {
10
+ // Find the main plugin file by looking for the standard WordPress plugin header
11
+ const files = readdirSync(pluginPath).filter(file => file.endsWith('.php'));
12
+ let mainFile = null;
13
+ // Look for the file containing the standard plugin header
14
+ for (const file of files) {
15
+ const content = readFileSync(join(pluginPath, file), 'utf8');
16
+ // Check for the standard plugin header (Plugin Name: field)
17
+ if (/^\s*\/\*\*[\s\S]*?Plugin Name:/m.test(content)) {
18
+ mainFile = file;
19
+ break;
20
+ }
21
+ }
22
+ if (!mainFile)
23
+ return null;
24
+ const content = readFileSync(join(pluginPath, mainFile), 'utf8');
25
+ // Match the plugin header block
26
+ const headerPattern = /\/\*\*\s*([\s\S]*?)\s*\*\//;
27
+ const match = headerPattern.exec(content);
28
+ if (!match)
29
+ return null;
30
+ const headers = {};
31
+ const headerContent = match[1];
32
+ // Parse each header line
33
+ headerContent?.split('\n').forEach(line => {
34
+ const colonIndex = line.indexOf(':');
35
+ if (colonIndex > 0) {
36
+ const key = line.substring(0, colonIndex).trim().replace(/\*/g, '');
37
+ const value = line.substring(colonIndex + 1).trim();
38
+ if (key && value) {
39
+ headers[key] = value;
40
+ }
41
+ }
42
+ });
43
+ return headers;
44
+ }
45
+ catch (_error) {
46
+ return null;
47
+ }
48
+ }
49
+ async function buildDependencyGraph(execute) {
50
+ const graph = new Map();
51
+ const pluginPaths = new Map();
52
+ // Get the plugins directory path
53
+ const { stdout: pluginsDir } = await execute('wp plugin path');
54
+ const pluginsDirectory = pluginsDir.trim();
55
+ // Get all plugins
56
+ const { stdout: pluginList } = await execute('wp plugin list --format=json');
57
+ const plugins = JSON.parse(pluginList);
58
+ // Map plugin names to their paths
59
+ for (const plugin of plugins) {
60
+ const pluginPath = `${pluginsDirectory}/${plugin.name}`;
61
+ pluginPaths.set(plugin.name, pluginPath);
62
+ }
63
+ // Parse headers and build dependency graph
64
+ for (const [pluginName, pluginPath] of pluginPaths) {
65
+ const headers = parsePluginHeaders(pluginPath);
66
+ if (headers?.['Requires Plugins']) {
67
+ // Parse the Requires Plugins field (comma-separated list)
68
+ const dependencies = headers['Requires Plugins']
69
+ .split(',')
70
+ .map(dep => dep.trim())
71
+ .filter(dep => dep.length > 0);
72
+ graph.set(pluginName, dependencies);
73
+ }
74
+ else {
75
+ graph.set(pluginName, []);
76
+ }
77
+ }
78
+ return graph;
79
+ }
80
+ function topologicalSort(graph) {
81
+ const visited = new Set();
82
+ const temp = new Set();
83
+ const result = [];
84
+ function visit(node) {
85
+ if (temp.has(node)) {
86
+ throw new Error(`Circular dependency detected involving ${node}`);
87
+ }
88
+ if (visited.has(node)) {
89
+ return;
90
+ }
91
+ temp.add(node);
92
+ // Visit all dependencies first
93
+ const dependencies = graph.get(node) ?? [];
94
+ for (const dep of dependencies) {
95
+ if (graph.has(dep)) {
96
+ visit(dep);
97
+ }
98
+ }
99
+ temp.delete(node);
100
+ visited.add(node);
101
+ result.push(node);
102
+ }
103
+ // Visit all nodes
104
+ for (const node of graph.keys()) {
105
+ if (!visited.has(node)) {
106
+ visit(node);
107
+ }
108
+ }
109
+ return result;
110
+ }
6
111
  export const command = "setup-database";
7
112
  export const describe = "Create a new database and initialise the site with no content.";
8
113
  export async function handler() {
@@ -30,12 +135,36 @@ export async function handler() {
30
135
  return execute(`wp user create ${process.env.WORDPRESS_USER} ${process.env.WORDPRESS_USER_EMAIL} --user_pass=${process.env.WORDPRESS_PASSWORD} --role=administrator`);
31
136
  }
32
137
  })
33
- .then(() => {
138
+ .then(async () => {
34
139
  if (addCustomUser) {
35
140
  performance.mark("add-custom-user");
36
141
  console.log(`Custom user ${process.env.WORDPRESS_USER} added. (${convertMeasureToPrettyString(performance.measure("add-custom-user", "wordpress-tables"))})`);
37
142
  }
38
- return execute(`wp plugin activate --all --exclude=wordfence,shortpixel-image-optimiser`);
143
+ const dependencyGraph = await buildDependencyGraph(execute);
144
+ const excludedPlugins = ['stream', 'shortpixel-image-optimiser', 'wordfence'];
145
+ const { stdout: pluginList } = await execute('wp plugin list --format=json');
146
+ const allPlugins = JSON.parse(pluginList);
147
+ // Filter out excluded plugins and already active plugins
148
+ const pluginsToActivate = allPlugins.filter(plugin => !excludedPlugins.includes(plugin.name) &&
149
+ plugin.status !== 'active');
150
+ const filteredGraph = new Map();
151
+ for (const plugin of pluginsToActivate) {
152
+ const dependencies = dependencyGraph.get(plugin.name) ?? [];
153
+ // Only include dependencies that are also in our activation list
154
+ const filteredDependencies = dependencies.filter(dep => pluginsToActivate.some(p => p.name === dep));
155
+ filteredGraph.set(plugin.name, filteredDependencies);
156
+ }
157
+ const activationOrder = topologicalSort(filteredGraph);
158
+ for (const pluginName of activationOrder) {
159
+ try {
160
+ await execute(`wp plugin activate ${pluginName}`);
161
+ console.log(`✓ Activated ${pluginName}`);
162
+ }
163
+ catch (error) {
164
+ const errorMessage = error instanceof Error ? error.message : String(error);
165
+ console.warn(`⚠ Warning: Could not activate ${pluginName}: ${errorMessage}`);
166
+ }
167
+ }
39
168
  })
40
169
  .then(() => {
41
170
  performance.mark("plugins");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomicsmash/cli",
3
- "version": "9.0.1-beta.0",
3
+ "version": "9.0.1-beta.1",
4
4
  "description": "A collection of CLI tools by Atomic Smash.",
5
5
  "keywords": [],
6
6
  "homepage": "https://www.atomicsmash.co.uk/",