@runwell/shopify-toolkit 0.14.0 → 0.14.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.
Files changed (2) hide show
  1. package/lib/sync.js +44 -2
  2. package/package.json +1 -1
package/lib/sync.js CHANGED
@@ -27,9 +27,19 @@ export async function sync(flags) {
27
27
  await syncBaseline({ baselineRoot, targetDir, config, dryRun, written: writtenFiles });
28
28
  }
29
29
 
30
- const moduleNames = Object.keys(config.modules);
30
+ // Modules to sync = explicit tenant config PLUS any module whose manifest
31
+ // declares always_enabled: true. The latter ensures foundation modules
32
+ // (css-tokens, css-typography) sync without requiring every tenant config
33
+ // to list them. Tenant config still wins for resolution (variant, config
34
+ // overrides), but always_enabled modules are auto-included.
35
+ const explicitModules = Object.keys(config.modules);
36
+ const alwaysEnabledModules = discoverAlwaysEnabledModules(flags.toolkitRoot, explicitModules);
37
+ const moduleNames = [...explicitModules, ...alwaysEnabledModules];
38
+ if (alwaysEnabledModules.length && verbose) {
39
+ console.log(`Auto-including always_enabled modules: ${alwaysEnabledModules.join(', ')}`);
40
+ }
31
41
  for (const moduleName of moduleNames) {
32
- const cfgEntry = config.modules[moduleName];
42
+ const cfgEntry = config.modules[moduleName] || { enabled: true, config: {} };
33
43
  if (cfgEntry.enabled === false) {
34
44
  if (verbose) console.log(`[skip] ${moduleName} (disabled)`);
35
45
  continue;
@@ -131,3 +141,35 @@ function getToolkitVersion(toolkitRoot) {
131
141
  return pkg.version;
132
142
  } catch { return 'unknown'; }
133
143
  }
144
+
145
+ function discoverAlwaysEnabledModules(toolkitRoot, explicitModules) {
146
+ // Walks modules/ for top-level dirs AND modules/_shared/* for foundation modules.
147
+ // Returns names of any module whose module.json declares always_enabled: true,
148
+ // skipping those already in the explicit tenant config.
149
+ const modulesDir = path.join(toolkitRoot, 'modules');
150
+ if (!fs.existsSync(modulesDir)) return [];
151
+ const candidates = [];
152
+ for (const entry of fs.readdirSync(modulesDir)) {
153
+ if (entry.startsWith('.')) continue;
154
+ const fullPath = path.join(modulesDir, entry);
155
+ if (!fs.statSync(fullPath).isDirectory()) continue;
156
+ if (entry === '_shared') {
157
+ for (const sub of fs.readdirSync(fullPath)) {
158
+ if (sub.startsWith('.')) continue;
159
+ const subPath = path.join(fullPath, sub);
160
+ if (fs.statSync(subPath).isDirectory()) candidates.push(`_shared/${sub}`);
161
+ }
162
+ } else {
163
+ candidates.push(entry);
164
+ }
165
+ }
166
+ const out = [];
167
+ for (const name of candidates) {
168
+ if (explicitModules.includes(name)) continue;
169
+ try {
170
+ const manifest = loadModuleManifest(toolkitRoot, name);
171
+ if (manifest.always_enabled === true) out.push(name);
172
+ } catch { /* skip modules without a manifest */ }
173
+ }
174
+ return out;
175
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runwell/shopify-toolkit",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "Reusable Shopify theme modules from Runwell. Replaces typically app-driven features (reviews, wishlist, urgency, FAQ, post-purchase upsell, exit popups, free-ship progress, sticky ATC, testimonials, badges, bundles) with native Liquid + JS + CSS that ship across multiple client themes via a config-driven sync CLI.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",