@drupal-canvas/cli 0.4.0 → 0.5.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/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { Command } from 'commander';
4
4
  import * as p from '@clack/prompts';
5
5
  import * as fs from 'fs';
6
6
  import fs__default, { realpathSync as realpathSync$1, readlinkSync, readdirSync, readdir as readdir$1, lstatSync, promises } from 'fs';
7
- import path11, { win32, posix } from 'path';
7
+ import path3, { win32, posix } from 'path';
8
8
  import dotenv from 'dotenv';
9
9
  import { transform, Features } from 'lightningcss';
10
10
  import axios from 'axios';
@@ -25,16 +25,16 @@ import { parse } from '@babel/parser';
25
25
 
26
26
  // package.json
27
27
  var package_default = {
28
- version: "0.4.0"};
28
+ version: "0.5.1"};
29
29
  function loadEnvFiles() {
30
30
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
31
31
  if (homeDir) {
32
- const homeEnvPath = path11.resolve(homeDir, ".canvasrc");
32
+ const homeEnvPath = path3.resolve(homeDir, ".canvasrc");
33
33
  if (fs__default.existsSync(homeEnvPath)) {
34
34
  dotenv.config({ path: homeEnvPath });
35
35
  }
36
36
  }
37
- const localEnvPath = path11.resolve(process.cwd(), ".env");
37
+ const localEnvPath = path3.resolve(process.cwd(), ".env");
38
38
  if (fs__default.existsSync(localEnvPath)) {
39
39
  dotenv.config({ path: localEnvPath });
40
40
  }
@@ -10805,17 +10805,17 @@ function createApiService() {
10805
10805
  userAgent: config2.userAgent
10806
10806
  });
10807
10807
  }
10808
- var CANVAS_CACHE_DIR = path11.join(os.homedir(), ".canvas");
10808
+ var CANVAS_CACHE_DIR = path3.join(os.homedir(), ".canvas");
10809
10809
  async function downloadJsSourceFromCanvas(componentsToDownload) {
10810
10810
  for (const key in componentsToDownload) {
10811
10811
  const component = componentsToDownload[key];
10812
10812
  try {
10813
- const componentDir = path11.join(CANVAS_CACHE_DIR, component.machineName);
10813
+ const componentDir = path3.join(CANVAS_CACHE_DIR, component.machineName);
10814
10814
  await fs2.rm(componentDir, { recursive: true, force: true });
10815
10815
  await fs2.mkdir(componentDir, { recursive: true });
10816
10816
  if (component.sourceCodeJs) {
10817
10817
  await fs2.writeFile(
10818
- path11.join(componentDir, `index.jsx`),
10818
+ path3.join(componentDir, `index.jsx`),
10819
10819
  component.sourceCodeJs,
10820
10820
  "utf-8"
10821
10821
  );
@@ -10833,14 +10833,14 @@ async function copyLocalJsSource(componentsToCopy) {
10833
10833
  try {
10834
10834
  await fs2.mkdir(CANVAS_CACHE_DIR, { recursive: true });
10835
10835
  for (const componentPath of componentsToCopy) {
10836
- const baseName = path11.basename(componentPath);
10836
+ const baseName = path3.basename(componentPath);
10837
10837
  const sourcePath = componentPath;
10838
- const targetPath = path11.join(CANVAS_CACHE_DIR, baseName);
10838
+ const targetPath = path3.join(CANVAS_CACHE_DIR, baseName);
10839
10839
  const stats = await fs2.stat(sourcePath);
10840
10840
  if (stats.isDirectory()) {
10841
10841
  await fs2.mkdir(targetPath, { recursive: true });
10842
- const sourceFile = path11.join(sourcePath, "index.jsx");
10843
- const targetFile = path11.join(targetPath, "index.jsx");
10842
+ const sourceFile = path3.join(sourcePath, "index.jsx");
10843
+ const targetFile = path3.join(targetPath, "index.jsx");
10844
10844
  await fs2.copyFile(sourceFile, targetFile);
10845
10845
  }
10846
10846
  }
@@ -10858,7 +10858,7 @@ async function cleanUpCacheDirectory() {
10858
10858
  withFileTypes: true
10859
10859
  });
10860
10860
  for (const entry of cacheEntries) {
10861
- const entryPath = path11.join(CANVAS_CACHE_DIR, entry.name);
10861
+ const entryPath = path3.join(CANVAS_CACHE_DIR, entry.name);
10862
10862
  if (entry.isDirectory()) {
10863
10863
  await fs2.rm(entryPath, { recursive: true, force: true });
10864
10864
  } else {
@@ -10873,8 +10873,32 @@ async function cleanUpCacheDirectory() {
10873
10873
  );
10874
10874
  }
10875
10875
  }
10876
+ async function fileExists(filePath) {
10877
+ try {
10878
+ await fs2.access(filePath);
10879
+ return true;
10880
+ } catch {
10881
+ return false;
10882
+ }
10883
+ }
10884
+ async function directoryExists(dirPath) {
10885
+ return await fs2.stat(dirPath).then(() => true).catch(() => false);
10886
+ }
10876
10887
 
10877
10888
  // src/utils/build-tailwind.ts
10889
+ async function downloadGlobalCssInBackground() {
10890
+ const apiService = await createApiService();
10891
+ const globalAssetLibrary = await apiService.getGlobalAssetLibrary();
10892
+ return globalAssetLibrary.css.original;
10893
+ }
10894
+ async function getGlobalCss(useLocal = true) {
10895
+ const config2 = getConfig();
10896
+ const localGlobalCssPath = path3.join(config2.componentDir, "global.css");
10897
+ if (useLocal && await fileExists(localGlobalCssPath)) {
10898
+ return await promises.readFile(localGlobalCssPath, "utf-8");
10899
+ }
10900
+ return await downloadGlobalCssInBackground();
10901
+ }
10878
10902
  async function getAllClassNameCandidatesFromCacheDir(componentsToDownload, localComponentsToCopy) {
10879
10903
  if (Object.keys(componentsToDownload).length > 0) {
10880
10904
  await downloadJsSourceFromCanvas(componentsToDownload);
@@ -10883,7 +10907,7 @@ async function getAllClassNameCandidatesFromCacheDir(componentsToDownload, local
10883
10907
  const cacheEntries = await promises.readdir(CANVAS_CACHE_DIR, {
10884
10908
  withFileTypes: true
10885
10909
  });
10886
- const cacheDirs = cacheEntries.filter((entry) => entry.isDirectory()).map((dir) => path11.join(CANVAS_CACHE_DIR, dir.name));
10910
+ const cacheDirs = cacheEntries.filter((entry) => entry.isDirectory()).map((dir) => path3.join(CANVAS_CACHE_DIR, dir.name));
10887
10911
  let allClassNameCandidates = [];
10888
10912
  for (const cacheDir of cacheDirs) {
10889
10913
  const componentClassNameCandidates = await getClassNameCandidatesForComponent(cacheDir);
@@ -10901,16 +10925,16 @@ async function buildTailwindCss(classNameCandidates, globalSourceCodeCss, distDi
10901
10925
  globalSourceCodeCss
10902
10926
  );
10903
10927
  const transformedTwCss = await transformCss(compiledTwCss);
10904
- await promises.writeFile(path11.join(distDir, "index.css"), transformedTwCss);
10928
+ await promises.writeFile(path3.join(distDir, "index.css"), transformedTwCss);
10905
10929
  }
10906
10930
  async function getClassNameCandidatesForComponent(dir) {
10907
- const componentName = path11.basename(dir);
10931
+ const componentName = path3.basename(dir);
10908
10932
  const config2 = getConfig();
10909
10933
  const componentsDir = config2.componentDir;
10910
- const distDir = path11.join(componentsDir, "dist");
10911
- const jsSource = await promises.readFile(path11.join(dir, "index.jsx"), "utf-8");
10934
+ const distDir = path3.join(componentsDir, "dist");
10935
+ const jsSource = await promises.readFile(path3.join(dir, "index.jsx"), "utf-8");
10912
10936
  const currentGlobalSourceCodeJs = await promises.readFile(
10913
- path11.join(distDir, "index.js"),
10937
+ path3.join(distDir, "index.js"),
10914
10938
  "utf-8"
10915
10939
  );
10916
10940
  const classNameCandidates = OE(jsSource);
@@ -10919,20 +10943,20 @@ async function getClassNameCandidatesForComponent(dir) {
10919
10943
  componentName,
10920
10944
  classNameCandidates
10921
10945
  );
10922
- await promises.writeFile(path11.join(distDir, "index.js"), globalJSClassNameIndex);
10946
+ await promises.writeFile(path3.join(distDir, "index.js"), globalJSClassNameIndex);
10923
10947
  return nextClassNameCandidates;
10924
10948
  }
10925
- async function buildTailwindForComponents(selectedComponents) {
10949
+ async function buildTailwindForComponents(selectedComponents, useLocalGlobalCss = true) {
10926
10950
  try {
10927
10951
  const config2 = getConfig();
10928
10952
  const apiService = await createApiService();
10929
10953
  const onlineComponents = await apiService.listComponents();
10954
+ const globalSourceCodeCss = await getGlobalCss(useLocalGlobalCss);
10930
10955
  const globalAssetLibrary = await apiService.getGlobalAssetLibrary();
10931
10956
  const globalSourceCodeJs = globalAssetLibrary.js.original;
10932
- const globalSourceCodeCss = globalAssetLibrary.css.original;
10933
- const distDir = path11.join(config2.componentDir, "dist");
10957
+ const distDir = path3.join(config2.componentDir, "dist");
10934
10958
  await promises.mkdir(distDir, { recursive: true });
10935
- const targetFile = path11.join(distDir, "index.js");
10959
+ const targetFile = path3.join(distDir, "index.js");
10936
10960
  await promises.writeFile(targetFile, globalSourceCodeJs, "utf-8");
10937
10961
  const allClassNameCandidates = await getAllClassNameCandidatesFromCacheDir(
10938
10962
  onlineComponents,
@@ -10984,17 +11008,6 @@ function compileJS(source) {
10984
11008
  const { code } = transformSync(source, SWC_OPTIONS);
10985
11009
  return code;
10986
11010
  }
10987
- async function fileExists(filePath) {
10988
- try {
10989
- await fs2.access(filePath);
10990
- return true;
10991
- } catch {
10992
- return false;
10993
- }
10994
- }
10995
- async function directoryExists(dirPath) {
10996
- return await fs2.stat(dirPath).then(() => true).catch(() => false);
10997
- }
10998
11011
  async function validateComponent(componentDir, fix = false) {
10999
11012
  const eslint = new ESLint({
11000
11013
  overrideConfigFile: true,
@@ -11012,7 +11025,7 @@ async function validateComponent(componentDir, fix = false) {
11012
11025
  (msg) => `Line ${msg.line}, Column ${msg.column}: ` + msg.message + (msg.ruleId ? ` (${msg.ruleId})` : "")
11013
11026
  );
11014
11027
  details.push({
11015
- heading: path11.relative(process.cwd(), result.filePath),
11028
+ heading: path3.relative(process.cwd(), result.filePath),
11016
11029
  content: messages.join("\n\n")
11017
11030
  });
11018
11031
  });
@@ -11024,8 +11037,8 @@ async function validateComponent(componentDir, fix = false) {
11024
11037
  }
11025
11038
 
11026
11039
  // src/utils/build.ts
11027
- async function buildComponent(componentDir) {
11028
- const componentName = path11.basename(componentDir);
11040
+ async function buildComponent(componentDir, useLocalGlobalCss = true) {
11041
+ const componentName = path3.basename(componentDir);
11029
11042
  const result = {
11030
11043
  itemName: componentName,
11031
11044
  success: true,
@@ -11037,7 +11050,7 @@ async function buildComponent(componentDir) {
11037
11050
  result.details = validationResult.details;
11038
11051
  return result;
11039
11052
  }
11040
- const distDir = path11.join(componentDir, "dist");
11053
+ const distDir = path3.join(componentDir, "dist");
11041
11054
  try {
11042
11055
  await promises.mkdir(distDir, { recursive: true });
11043
11056
  } catch (error) {
@@ -11050,11 +11063,11 @@ async function buildComponent(componentDir) {
11050
11063
  }
11051
11064
  try {
11052
11065
  const jsSource = await promises.readFile(
11053
- path11.join(componentDir, "index.jsx"),
11066
+ path3.join(componentDir, "index.jsx"),
11054
11067
  "utf-8"
11055
11068
  );
11056
11069
  const jsCompiled = compileJS(jsSource);
11057
- await promises.writeFile(path11.join(distDir, "index.js"), jsCompiled);
11070
+ await promises.writeFile(path3.join(distDir, "index.js"), jsCompiled);
11058
11071
  } catch (error) {
11059
11072
  result.success = false;
11060
11073
  result.details?.push({
@@ -11062,11 +11075,9 @@ async function buildComponent(componentDir) {
11062
11075
  content: String(error)
11063
11076
  });
11064
11077
  }
11065
- const apiService = await createApiService();
11066
- const globalAssetLibrary = await apiService.getGlobalAssetLibrary();
11067
- const globalSourceCodeCss = globalAssetLibrary.css.original;
11078
+ const globalSourceCodeCss = await getGlobalCss(useLocalGlobalCss);
11068
11079
  try {
11069
- const cssPath = path11.join(componentDir, "index.css");
11080
+ const cssPath = path3.join(componentDir, "index.css");
11070
11081
  const cssFileExists = await fileExists(cssPath);
11071
11082
  if (cssFileExists) {
11072
11083
  const cssSource = await promises.readFile(cssPath, "utf-8");
@@ -11075,7 +11086,7 @@ async function buildComponent(componentDir) {
11075
11086
  globalSourceCodeCss
11076
11087
  );
11077
11088
  const cssTranspiled = await transformCss(cssCompiled);
11078
- await promises.writeFile(path11.join(distDir, "index.css"), cssTranspiled);
11089
+ await promises.writeFile(path3.join(distDir, "index.css"), cssTranspiled);
11079
11090
  }
11080
11091
  } catch (error) {
11081
11092
  result.success = false;
@@ -17728,11 +17739,11 @@ async function findComponentDirectories(baseDir) {
17728
17739
  const namedYmls = await glob(`${baseDir}/**/*.component.yml`);
17729
17740
  const allComponentPaths = [...standardYmls, ...namedYmls];
17730
17741
  const uniqueDirs = new Set(
17731
- allComponentPaths.map((filePath) => path11.dirname(filePath))
17742
+ allComponentPaths.map((filePath) => path3.dirname(filePath))
17732
17743
  );
17733
17744
  let componentDirs = Array.from(uniqueDirs).sort();
17734
17745
  let sdcs = await glob(`${baseDir}/**/*.twig`);
17735
- sdcs = sdcs.map((sdc) => path11.dirname(sdc));
17746
+ sdcs = sdcs.map((sdc) => path3.dirname(sdc));
17736
17747
  componentDirs = componentDirs.filter(
17737
17748
  (componentDir) => !sdcs.includes(componentDir)
17738
17749
  );
@@ -17744,9 +17755,29 @@ async function findComponentDirectories(baseDir) {
17744
17755
  }
17745
17756
 
17746
17757
  // src/utils/component-selector.ts
17758
+ var GLOBAL_CSS_SELECTOR = "__GLOBAL_CSS__";
17759
+ function determineGlobalCssSelection(options) {
17760
+ if (options.cssOnly) {
17761
+ return true;
17762
+ }
17763
+ if (options.skipCss) {
17764
+ return false;
17765
+ }
17766
+ if (!options.includeGlobalCss) {
17767
+ return void 0;
17768
+ }
17769
+ return options.globalCssDefault !== false;
17770
+ }
17747
17771
  async function selectLocalComponents(options) {
17748
17772
  const config2 = getConfig();
17749
17773
  const componentDir = options.componentDir || config2.componentDir;
17774
+ const globalCssSelection = determineGlobalCssSelection(options);
17775
+ if (options.cssOnly) {
17776
+ return {
17777
+ directories: [],
17778
+ includeGlobalCss: true
17779
+ };
17780
+ }
17750
17781
  const allLocalDirs = await findComponentDirectories(componentDir);
17751
17782
  if (allLocalDirs.length === 0) {
17752
17783
  throw new Error(`No local components were found in ${componentDir}`);
@@ -17755,7 +17786,8 @@ async function selectLocalComponents(options) {
17755
17786
  return selectSpecificLocalComponents(
17756
17787
  options.components,
17757
17788
  allLocalDirs,
17758
- options
17789
+ options,
17790
+ globalCssSelection
17759
17791
  );
17760
17792
  }
17761
17793
  if (options.all) {
@@ -17769,16 +17801,23 @@ async function selectLocalComponents(options) {
17769
17801
  }
17770
17802
  }
17771
17803
  p.log.info(`Selected all components`);
17772
- return { directories: allLocalDirs };
17804
+ return {
17805
+ directories: allLocalDirs,
17806
+ includeGlobalCss: globalCssSelection
17807
+ };
17773
17808
  }
17774
- return selectLocalComponentsInteractive(allLocalDirs, options);
17809
+ return selectLocalComponentsInteractive(
17810
+ allLocalDirs,
17811
+ options,
17812
+ globalCssSelection
17813
+ );
17775
17814
  }
17776
- async function selectSpecificLocalComponents(componentsInput, allLocalDirs, options) {
17815
+ async function selectSpecificLocalComponents(componentsInput, allLocalDirs, options, globalCssSelection) {
17777
17816
  const requestedNames = componentsInput.split(",").map((name) => name.trim()).filter((name) => name.length > 0);
17778
17817
  const notFound = [];
17779
17818
  const foundDirs = [];
17780
17819
  for (const requestedName of requestedNames) {
17781
- const dir = allLocalDirs.find((d2) => path11.basename(d2) === requestedName);
17820
+ const dir = allLocalDirs.find((d2) => path3.basename(d2) === requestedName);
17782
17821
  if (dir) {
17783
17822
  foundDirs.push(dir);
17784
17823
  } else {
@@ -17798,27 +17837,48 @@ async function selectSpecificLocalComponents(componentsInput, allLocalDirs, opti
17798
17837
  throw new Error("Operation cancelled by user");
17799
17838
  }
17800
17839
  }
17801
- return { directories: foundDirs };
17840
+ return {
17841
+ directories: foundDirs,
17842
+ includeGlobalCss: globalCssSelection
17843
+ };
17802
17844
  }
17803
- async function selectLocalComponentsInteractive(allLocalDirs, options) {
17804
- const selectedDirs = await p.multiselect({
17805
- message: options.selectMessage || "Select components",
17806
- options: [
17807
- {
17808
- value: ALL_COMPONENTS_SELECTOR,
17809
- label: "All components"
17810
- },
17811
- ...allLocalDirs.map((dir) => ({
17812
- value: dir,
17813
- label: path11.basename(dir)
17814
- }))
17815
- ],
17845
+ async function selectLocalComponentsInteractive(allLocalDirs, options, globalCssSelection) {
17846
+ const multiSelectOptions = [
17847
+ {
17848
+ value: ALL_COMPONENTS_SELECTOR,
17849
+ label: "All components"
17850
+ }
17851
+ ];
17852
+ if (options.includeGlobalCss) {
17853
+ multiSelectOptions.push({
17854
+ value: GLOBAL_CSS_SELECTOR,
17855
+ label: "Global CSS"
17856
+ });
17857
+ }
17858
+ multiSelectOptions.push(
17859
+ ...allLocalDirs.map((dir) => ({
17860
+ value: dir,
17861
+ label: path3.basename(dir)
17862
+ }))
17863
+ );
17864
+ const selectedItems = await p.multiselect({
17865
+ message: options.selectMessage || "Select items",
17866
+ options: multiSelectOptions,
17867
+ initialValues: options.includeGlobalCss && options.globalCssDefault !== false ? [GLOBAL_CSS_SELECTOR] : [],
17816
17868
  required: true
17817
17869
  });
17818
- if (p.isCancel(selectedDirs)) {
17870
+ if (p.isCancel(selectedItems)) {
17819
17871
  throw new Error("Operation cancelled by user");
17820
17872
  }
17821
- const finalDirs = selectedDirs.includes(ALL_COMPONENTS_SELECTOR) ? allLocalDirs : selectedDirs;
17873
+ const includesAllComponents = selectedItems.includes(
17874
+ ALL_COMPONENTS_SELECTOR
17875
+ );
17876
+ const includesGlobalCss = selectedItems.includes(
17877
+ GLOBAL_CSS_SELECTOR
17878
+ );
17879
+ const finalDirs = includesAllComponents ? allLocalDirs : selectedItems.filter(
17880
+ (item) => item !== ALL_COMPONENTS_SELECTOR && item !== GLOBAL_CSS_SELECTOR
17881
+ );
17822
17882
  if (!options.skipConfirmation) {
17823
17883
  const confirmed = await confirmSelection(
17824
17884
  finalDirs.length,
@@ -17828,10 +17888,21 @@ async function selectLocalComponentsInteractive(allLocalDirs, options) {
17828
17888
  throw new Error("Operation cancelled by user");
17829
17889
  }
17830
17890
  }
17831
- return { directories: finalDirs };
17891
+ const finalGlobalCss = options.includeGlobalCss ? includesGlobalCss : globalCssSelection;
17892
+ return {
17893
+ directories: finalDirs,
17894
+ includeGlobalCss: finalGlobalCss
17895
+ };
17832
17896
  }
17833
17897
  async function selectRemoteComponents(allComponents, options) {
17834
17898
  const componentCount = Object.keys(allComponents).length;
17899
+ const globalCssSelection = determineGlobalCssSelection(options);
17900
+ if (options.cssOnly) {
17901
+ return {
17902
+ components: {},
17903
+ includeGlobalCss: true
17904
+ };
17905
+ }
17835
17906
  if (componentCount === 0) {
17836
17907
  throw new Error("No components found");
17837
17908
  }
@@ -17845,18 +17916,26 @@ async function selectRemoteComponents(allComponents, options) {
17845
17916
  throw new Error("Operation cancelled by user");
17846
17917
  }
17847
17918
  }
17848
- return { components: allComponents };
17919
+ return {
17920
+ components: allComponents,
17921
+ includeGlobalCss: globalCssSelection
17922
+ };
17849
17923
  }
17850
17924
  if (options.components) {
17851
17925
  return selectSpecificRemoteComponents(
17852
17926
  options.components,
17853
17927
  allComponents,
17854
- options
17928
+ options,
17929
+ globalCssSelection
17855
17930
  );
17856
17931
  }
17857
- return selectRemoteComponentsInteractive(allComponents, options);
17932
+ return selectRemoteComponentsInteractive(
17933
+ allComponents,
17934
+ options,
17935
+ globalCssSelection
17936
+ );
17858
17937
  }
17859
- async function selectSpecificRemoteComponents(componentsInput, allComponents, options) {
17938
+ async function selectSpecificRemoteComponents(componentsInput, allComponents, options, globalCssSelection) {
17860
17939
  const requestedNames = componentsInput.split(",").map((name) => name.trim()).filter((name) => name.length > 0);
17861
17940
  const notFound = [];
17862
17941
  const selected = {};
@@ -17881,31 +17960,48 @@ async function selectSpecificRemoteComponents(componentsInput, allComponents, op
17881
17960
  throw new Error("Operation cancelled by user");
17882
17961
  }
17883
17962
  }
17884
- return { components: selected };
17963
+ return {
17964
+ components: selected,
17965
+ includeGlobalCss: globalCssSelection
17966
+ };
17885
17967
  }
17886
- async function selectRemoteComponentsInteractive(allComponents, options) {
17887
- const selectedMachineNames = await p.multiselect({
17888
- message: options.selectMessage || "Select components to download",
17889
- options: [
17890
- {
17891
- value: ALL_COMPONENTS_SELECTOR,
17892
- label: "All components"
17893
- },
17894
- ...Object.keys(allComponents).map((key) => ({
17895
- value: allComponents[key].machineName,
17896
- label: `${allComponents[key].name} (${allComponents[key].machineName})`
17897
- }))
17898
- ],
17968
+ async function selectRemoteComponentsInteractive(allComponents, options, globalCssSelection) {
17969
+ const multiSelectOptions = [
17970
+ {
17971
+ value: ALL_COMPONENTS_SELECTOR,
17972
+ label: "All components"
17973
+ }
17974
+ ];
17975
+ if (options.includeGlobalCss) {
17976
+ multiSelectOptions.push({
17977
+ value: GLOBAL_CSS_SELECTOR,
17978
+ label: "Global CSS"
17979
+ });
17980
+ }
17981
+ multiSelectOptions.push(
17982
+ ...Object.keys(allComponents).map((key) => ({
17983
+ value: allComponents[key].machineName,
17984
+ label: `${allComponents[key].name} (${allComponents[key].machineName})`
17985
+ }))
17986
+ );
17987
+ const selectedItems = await p.multiselect({
17988
+ message: options.selectMessage || "Select items to download",
17989
+ options: multiSelectOptions,
17990
+ initialValues: options.includeGlobalCss && options.globalCssDefault !== false ? [GLOBAL_CSS_SELECTOR] : [],
17899
17991
  required: true
17900
17992
  });
17901
- if (p.isCancel(selectedMachineNames)) {
17993
+ if (p.isCancel(selectedItems)) {
17902
17994
  throw new Error("Operation cancelled by user");
17903
17995
  }
17904
- const selected = selectedMachineNames.includes(
17996
+ const includesAllComponents = selectedItems.includes(
17905
17997
  ALL_COMPONENTS_SELECTOR
17906
- ) ? allComponents : Object.fromEntries(
17998
+ );
17999
+ const includesGlobalCss = selectedItems.includes(
18000
+ GLOBAL_CSS_SELECTOR
18001
+ );
18002
+ const selected = includesAllComponents ? allComponents : Object.fromEntries(
17907
18003
  Object.entries(allComponents).filter(
17908
- ([, component]) => selectedMachineNames.includes(component.machineName)
18004
+ ([, component]) => selectedItems.includes(component.machineName)
17909
18005
  )
17910
18006
  );
17911
18007
  if (!options.skipConfirmation) {
@@ -17917,7 +18013,11 @@ async function selectRemoteComponentsInteractive(allComponents, options) {
17917
18013
  throw new Error("Operation cancelled by user");
17918
18014
  }
17919
18015
  }
17920
- return { components: selected };
18016
+ const finalGlobalCss = options.includeGlobalCss ? includesGlobalCss : globalCssSelection;
18017
+ return {
18018
+ components: selected,
18019
+ includeGlobalCss: finalGlobalCss
18020
+ };
17921
18021
  }
17922
18022
  async function confirmSelection(count, customMessage) {
17923
18023
  const componentLabel = count === 1 ? "component" : "components";
@@ -18061,10 +18161,15 @@ function downloadCommand(program2) {
18061
18161
  ).option("--all", "Download all components").option("-y, --yes", "Skip all confirmation prompts").option(
18062
18162
  "--skip-overwrite",
18063
18163
  "Skip downloading components that already exist locally"
18064
- ).option("--verbose", "Enable verbose output").action(async (options) => {
18164
+ ).option("--skip-css", "Skip downloading global CSS").option("--css-only", "Download only global CSS (skip components)").option("--verbose", "Enable verbose output").action(async (options) => {
18065
18165
  p.intro(chalk2.bold("Drupal Canvas CLI: download"));
18066
18166
  try {
18067
18167
  validateComponentOptions(options);
18168
+ if (options.skipCss && options.cssOnly) {
18169
+ throw new Error(
18170
+ "Cannot use both --skip-css and --css-only flags together"
18171
+ );
18172
+ }
18068
18173
  updateConfigFromOptions(options);
18069
18174
  await ensureConfig([
18070
18175
  "siteUrl",
@@ -18075,35 +18180,52 @@ function downloadCommand(program2) {
18075
18180
  ]);
18076
18181
  const config2 = getConfig();
18077
18182
  const apiService = await createApiService();
18183
+ let components = {};
18184
+ let globalCss;
18078
18185
  const s = p.spinner();
18079
- s.start("Fetching components");
18080
- const components = await apiService.listComponents();
18081
- const {
18082
- css: { original: globalCss }
18083
- } = await apiService.getGlobalAssetLibrary();
18084
- if (Object.keys(components).length === 0) {
18085
- s.stop("No components found");
18086
- p.outro("Download cancelled - no components were found");
18087
- return;
18186
+ if (options.cssOnly) {
18187
+ s.start("Fetching global CSS");
18188
+ const {
18189
+ css: { original }
18190
+ } = await apiService.getGlobalAssetLibrary();
18191
+ globalCss = original;
18192
+ s.stop("Global CSS fetched");
18193
+ } else {
18194
+ s.start("Fetching components and global CSS");
18195
+ const [fetchedComponents, globalAssetLibrary] = await Promise.all([
18196
+ apiService.listComponents(),
18197
+ apiService.getGlobalAssetLibrary()
18198
+ ]);
18199
+ components = fetchedComponents;
18200
+ globalCss = globalAssetLibrary.css.original;
18201
+ if (Object.keys(components).length === 0) {
18202
+ s.stop("No components found");
18203
+ p.outro("Download cancelled - no components were found");
18204
+ return;
18205
+ }
18206
+ s.stop(`Found ${Object.keys(components).length} components`);
18088
18207
  }
18089
- s.stop(`Found ${Object.keys(components).length} components`);
18090
18208
  const allFlag = options.all || options.yes && !options.components || false;
18091
- const { components: componentsToDownload } = await selectRemoteComponents(components, {
18209
+ const { components: componentsToDownload, includeGlobalCss } = await selectRemoteComponents(components, {
18092
18210
  all: allFlag,
18093
18211
  components: options.components,
18094
18212
  skipConfirmation: options.yes,
18095
- selectMessage: "Select components to download",
18213
+ skipCss: options.skipCss,
18214
+ cssOnly: options.cssOnly,
18215
+ includeGlobalCss: !options.skipCss,
18216
+ globalCssDefault: true,
18217
+ selectMessage: "Select items to download",
18096
18218
  confirmMessage: `Download to ${config2.componentDir}?`
18097
18219
  });
18098
- const componentPluralized = pluralizeComponent(
18099
- Object.keys(componentsToDownload).length
18100
- );
18220
+ const componentCount = Object.keys(componentsToDownload).length;
18221
+ const componentPluralized = pluralizeComponent(componentCount);
18101
18222
  const results = [];
18102
- s.start(`Downloading ${componentPluralized}`);
18223
+ const downloadMessage = options.cssOnly ? "Downloading global CSS" : componentCount > 0 ? `Downloading ${componentPluralized}` : "Processing request";
18224
+ s.start(downloadMessage);
18103
18225
  for (const key in componentsToDownload) {
18104
18226
  const component = componentsToDownload[key];
18105
18227
  try {
18106
- const componentDir = path11.join(
18228
+ const componentDir = path3.join(
18107
18229
  config2.componentDir,
18108
18230
  component.machineName
18109
18231
  );
@@ -18148,20 +18270,20 @@ function downloadCommand(program2) {
18148
18270
  slots: component.slots || {}
18149
18271
  };
18150
18272
  await fs2.writeFile(
18151
- path11.join(componentDir, `component.yml`),
18273
+ path3.join(componentDir, `component.yml`),
18152
18274
  yaml__default.dump(metadata),
18153
18275
  "utf-8"
18154
18276
  );
18155
18277
  if (component.sourceCodeJs) {
18156
18278
  await fs2.writeFile(
18157
- path11.join(componentDir, `index.jsx`),
18279
+ path3.join(componentDir, `index.jsx`),
18158
18280
  component.sourceCodeJs,
18159
18281
  "utf-8"
18160
18282
  );
18161
18283
  }
18162
18284
  if (component.sourceCodeCss) {
18163
18285
  await fs2.writeFile(
18164
- path11.join(componentDir, `index.css`),
18286
+ path3.join(componentDir, `index.css`),
18165
18287
  component.sourceCodeCss,
18166
18288
  "utf-8"
18167
18289
  );
@@ -18182,16 +18304,15 @@ function downloadCommand(program2) {
18182
18304
  });
18183
18305
  }
18184
18306
  }
18185
- s.stop(
18186
- chalk2.green(
18187
- `Processed ${Object.keys(componentsToDownload).length} ${componentPluralized}`
18188
- )
18189
- );
18190
- reportResults(results, "Downloaded components", "Component");
18191
- if (globalCss) {
18307
+ const successMessage = options.cssOnly && componentCount === 0 ? "Global CSS download completed" : `Processed ${componentCount} ${componentPluralized}`;
18308
+ s.stop(chalk2.green(successMessage));
18309
+ if (componentCount > 0) {
18310
+ reportResults(results, "Downloaded components", "Component");
18311
+ }
18312
+ if (includeGlobalCss && typeof globalCss === "string") {
18192
18313
  let globalCssResult;
18193
18314
  try {
18194
- const globalCssPath = path11.join(config2.componentDir, "global.css");
18315
+ const globalCssPath = path3.join(config2.componentDir, "global.css");
18195
18316
  await fs2.writeFile(globalCssPath, globalCss, "utf-8");
18196
18317
  globalCssResult = {
18197
18318
  itemName: "global.css",
@@ -18211,7 +18332,8 @@ function downloadCommand(program2) {
18211
18332
  }
18212
18333
  reportResults([globalCssResult], "Downloaded assets", "Asset");
18213
18334
  }
18214
- p.outro(`\u2B07\uFE0F Download command completed`);
18335
+ const outroMessage = options.cssOnly && componentCount === 0 ? "\u2B07\uFE0F Global CSS downloaded successfully" : includeGlobalCss && componentCount > 0 ? "\u2B07\uFE0F Components and global CSS downloaded successfully" : componentCount > 0 ? "\u2B07\uFE0F Components downloaded successfully" : "\u2B07\uFE0F Download command completed";
18336
+ p.outro(outroMessage);
18215
18337
  } catch (error) {
18216
18338
  if (error instanceof Error) {
18217
18339
  p.note(chalk2.red(`Error: ${error.message}`));
@@ -18254,13 +18376,13 @@ function scaffoldCommand(program2) {
18254
18376
  }
18255
18377
  componentName = name;
18256
18378
  }
18257
- const componentDir = path11.join(baseDir, componentName);
18379
+ const componentDir = path3.join(baseDir, componentName);
18258
18380
  const s = p.spinner();
18259
18381
  s.start(`Creating component "${componentName}"`);
18260
18382
  try {
18261
18383
  await fs2.mkdir(componentDir, { recursive: true });
18262
- const templateDir = path11.join(
18263
- path11.dirname(new URL(import.meta.url).pathname),
18384
+ const templateDir = path3.join(
18385
+ path3.dirname(new URL(import.meta.url).pathname),
18264
18386
  "templates/hello-world"
18265
18387
  );
18266
18388
  const files = await fs2.readdir(templateDir);
@@ -18276,8 +18398,8 @@ function scaffoldCommand(program2) {
18276
18398
  }
18277
18399
  }
18278
18400
  for (const file of files) {
18279
- const srcPath = path11.join(templateDir, file);
18280
- const destPath = path11.join(componentDir, file);
18401
+ const srcPath = path3.join(templateDir, file);
18402
+ const destPath = path3.join(componentDir, file);
18281
18403
  let content = await fs2.readFile(srcPath, "utf-8");
18282
18404
  const { pascalCaseName, className, displayName, machineName } = generateComponentNameFormats(componentName);
18283
18405
  content = content.replace(/HelloWorld/g, pascalCaseName).replace(/hello-world-component/g, className).replace(/Hello World/g, displayName).replace(/hello_world/g, machineName);
@@ -18286,9 +18408,9 @@ function scaffoldCommand(program2) {
18286
18408
  s.stop(chalk2.green(`Created component "${componentName}"`));
18287
18409
  p.note(`Component "${componentName}" has been created:
18288
18410
  - Directory: ${componentDir}
18289
- - Component metadata: ${path11.join(componentDir, `component.yml`)}
18290
- - Source file: ${path11.join(componentDir, `index.jsx`)}
18291
- - CSS file: ${path11.join(componentDir, `index.css`)}`);
18411
+ - Component metadata: ${path3.join(componentDir, `component.yml`)}
18412
+ - Source file: ${path3.join(componentDir, `index.jsx`)}
18413
+ - CSS file: ${path3.join(componentDir, `index.css`)}`);
18292
18414
  p.outro("\u{1F3D7}\uFE0F Scaffold command completed");
18293
18415
  } catch (error) {
18294
18416
  s.stop(chalk2.red(`Failed to create component "${componentName}"`));
@@ -18366,20 +18488,20 @@ var getDataDependenciesFromAst = (ast) => ast.program.body.filter((d2) => d2.typ
18366
18488
  async function processComponentFiles(componentDir) {
18367
18489
  const metadataPath = await findMetadataPath(componentDir);
18368
18490
  const metadata = await readComponentMetadata(metadataPath);
18369
- const distDir = path11.join(componentDir, "dist");
18491
+ const distDir = path3.join(componentDir, "dist");
18370
18492
  const sourceCodeJs = await promises.readFile(
18371
- path11.join(componentDir, "index.jsx"),
18493
+ path3.join(componentDir, "index.jsx"),
18372
18494
  "utf-8"
18373
18495
  );
18374
- const compiledJs = await promises.readFile(path11.join(distDir, "index.js"), "utf-8");
18496
+ const compiledJs = await promises.readFile(path3.join(distDir, "index.js"), "utf-8");
18375
18497
  let sourceCodeCss = "";
18376
18498
  let compiledCss = "";
18377
18499
  try {
18378
18500
  sourceCodeCss = await promises.readFile(
18379
- path11.join(componentDir, "index.css"),
18501
+ path3.join(componentDir, "index.css"),
18380
18502
  "utf-8"
18381
18503
  );
18382
- compiledCss = await promises.readFile(path11.join(distDir, "index.css"), "utf-8");
18504
+ compiledCss = await promises.readFile(path3.join(distDir, "index.css"), "utf-8");
18383
18505
  } catch {
18384
18506
  }
18385
18507
  return {
@@ -18391,7 +18513,7 @@ async function processComponentFiles(componentDir) {
18391
18513
  };
18392
18514
  }
18393
18515
  async function findMetadataPath(componentDir) {
18394
- const metadataPath = path11.join(componentDir, "component.yml");
18516
+ const metadataPath = path3.join(componentDir, "component.yml");
18395
18517
  try {
18396
18518
  await promises.access(metadataPath);
18397
18519
  return metadataPath;
@@ -18412,10 +18534,10 @@ async function readComponentMetadata(filePath) {
18412
18534
  }
18413
18535
  const metadata = rawMetadata;
18414
18536
  if (!metadata.name) {
18415
- metadata.name = path11.basename(path11.dirname(filePath));
18537
+ metadata.name = path3.basename(path3.dirname(filePath));
18416
18538
  }
18417
18539
  if (!metadata.machineName) {
18418
- metadata.machineName = path11.basename(path11.dirname(filePath));
18540
+ metadata.machineName = path3.basename(path3.dirname(filePath));
18419
18541
  }
18420
18542
  if (!metadata.slots || typeof metadata.slots !== "object") {
18421
18543
  metadata.slots = {};
@@ -18585,12 +18707,17 @@ function uploadCommand(program2) {
18585
18707
  program2.command("upload").description("build and upload local components and global CSS assets").option("--client-id <id>", "Client ID").option("--client-secret <secret>", "Client Secret").option("--site-url <url>", "Site URL").option("--scope <scope>", "Scope").option("-d, --dir <directory>", "Component directory").option(
18586
18708
  "-c, --components <names>",
18587
18709
  "Specific component(s) to upload (comma-separated)"
18588
- ).option("--all", "Upload all components").option("-y, --yes", "Skip confirmation prompts").option("--verbose", "Verbose output").option("--no-tailwind", "Skip Tailwind CSS building").action(async (options) => {
18710
+ ).option("--all", "Upload all components").option("-y, --yes", "Skip confirmation prompts").option("--verbose", "Verbose output").option("--no-tailwind", "Skip Tailwind CSS building").option("--skip-css", "Skip global CSS upload").option("--css-only", "Upload only global CSS (skip components)").action(async (options) => {
18589
18711
  const allFlag = options.all || options.yes && !options.components || false;
18590
18712
  const skipTailwind = !options.tailwind;
18591
18713
  try {
18592
18714
  p.intro(chalk2.bold("Drupal Canvas CLI: upload"));
18593
18715
  validateComponentOptions(options);
18716
+ if (options.skipCss && options.cssOnly) {
18717
+ throw new Error(
18718
+ "Cannot use both --skip-css and --css-only flags together"
18719
+ );
18720
+ }
18594
18721
  updateConfigFromOptions(options);
18595
18722
  await ensureConfig([
18596
18723
  "siteUrl",
@@ -18600,22 +18727,28 @@ function uploadCommand(program2) {
18600
18727
  "componentDir"
18601
18728
  ]);
18602
18729
  const config2 = getConfig();
18603
- const { directories: componentsToUpload } = await selectLocalComponents(
18604
- {
18605
- all: allFlag,
18606
- components: options.components,
18607
- skipConfirmation: options.yes,
18608
- selectMessage: "Select components to upload"
18609
- }
18610
- );
18730
+ const { directories: componentsToUpload, includeGlobalCss } = await selectLocalComponents({
18731
+ all: allFlag,
18732
+ components: options.components,
18733
+ skipConfirmation: options.yes,
18734
+ skipCss: options.skipCss,
18735
+ cssOnly: options.cssOnly,
18736
+ includeGlobalCss: !options.skipCss,
18737
+ globalCssDefault: true,
18738
+ selectMessage: "Select items to upload"
18739
+ });
18611
18740
  const apiService = await createApiService();
18612
- const componentResults = await getBuildAndUploadResults(
18613
- componentsToUpload,
18614
- apiService
18615
- );
18616
- reportResults(componentResults, "Uploaded components", "Component");
18617
- if (componentResults.some((result) => !result.success)) {
18618
- process.exit(1);
18741
+ let componentResults = [];
18742
+ if (!options.cssOnly && componentsToUpload.length > 0) {
18743
+ componentResults = await getBuildAndUploadResults(
18744
+ componentsToUpload,
18745
+ apiService,
18746
+ includeGlobalCss ?? false
18747
+ );
18748
+ reportResults(componentResults, "Uploaded components", "Component");
18749
+ if (componentResults.some((result) => !result.success)) {
18750
+ process.exit(1);
18751
+ }
18619
18752
  }
18620
18753
  if (skipTailwind) {
18621
18754
  p.log.info("Skipping Tailwind CSS build");
@@ -18623,7 +18756,9 @@ function uploadCommand(program2) {
18623
18756
  const s2 = p.spinner();
18624
18757
  s2.start("Building Tailwind CSS");
18625
18758
  const tailwindResult = await buildTailwindForComponents(
18626
- componentsToUpload
18759
+ componentsToUpload,
18760
+ includeGlobalCss
18761
+ // Use local CSS if includeGlobalCss is true
18627
18762
  );
18628
18763
  const componentLabelPluralized = pluralizeComponent(
18629
18764
  componentsToUpload.length
@@ -18639,14 +18774,20 @@ function uploadCommand(program2) {
18639
18774
  chalk2.red(`Tailwind build failed, global assets upload aborted.`)
18640
18775
  );
18641
18776
  } else {
18642
- const globalCssResult = await uploadGlobalAssetLibrary(
18643
- apiService,
18644
- config2.componentDir
18645
- );
18646
- reportResults([globalCssResult], "Uploaded assets", "Asset");
18777
+ if (includeGlobalCss) {
18778
+ const globalCssResult = await uploadGlobalAssetLibrary(
18779
+ apiService,
18780
+ config2.componentDir
18781
+ );
18782
+ reportResults([globalCssResult], "Uploaded assets", "Asset");
18783
+ } else {
18784
+ p.log.info("Skipping global CSS upload");
18785
+ }
18647
18786
  }
18648
18787
  }
18649
- p.outro("\u2B06\uFE0F Upload command completed");
18788
+ const componentCount = componentsToUpload.length;
18789
+ const outroMessage = options.cssOnly && componentCount === 0 ? "\u2B06\uFE0F Global CSS uploaded successfully" : includeGlobalCss && componentCount > 0 ? "\u2B06\uFE0F Components and global CSS uploaded successfully" : componentCount > 0 ? "\u2B06\uFE0F Components uploaded successfully" : "\u2B06\uFE0F Upload command completed";
18790
+ p.outro(outroMessage);
18650
18791
  } catch (error) {
18651
18792
  if (error instanceof Error) {
18652
18793
  p.note(chalk2.red(`Error: ${error.message}`));
@@ -18662,11 +18803,11 @@ async function prepareComponentsForUpload(successfulBuilds, componentsToUpload)
18662
18803
  const failed = [];
18663
18804
  for (const buildResult of successfulBuilds) {
18664
18805
  const dir = buildResult.itemName ? componentsToUpload.find(
18665
- (d2) => path11.basename(d2) === buildResult.itemName
18806
+ (d2) => path3.basename(d2) === buildResult.itemName
18666
18807
  ) : void 0;
18667
18808
  if (!dir) continue;
18668
18809
  try {
18669
- const componentName = path11.basename(dir);
18810
+ const componentName = path3.basename(dir);
18670
18811
  const { sourceCodeJs, compiledJs, sourceCodeCss, compiledCss, metadata } = await processComponentFiles(dir);
18671
18812
  if (!metadata) {
18672
18813
  throw new Error("Invalid metadata file");
@@ -18719,11 +18860,14 @@ async function prepareComponentsForUpload(successfulBuilds, componentsToUpload)
18719
18860
  }
18720
18861
  return { prepared, failed };
18721
18862
  }
18722
- async function getBuildAndUploadResults(componentsToUpload, apiService) {
18863
+ async function getBuildAndUploadResults(componentsToUpload, apiService, includeGlobalCss) {
18723
18864
  const results = [];
18724
18865
  const spinner6 = p.spinner();
18725
18866
  spinner6.start("Building components");
18726
- const buildResults = await buildSelectedComponents(componentsToUpload);
18867
+ const buildResults = await buildSelectedComponents(
18868
+ componentsToUpload,
18869
+ includeGlobalCss
18870
+ );
18727
18871
  const successfulBuilds = buildResults.filter((build) => build.success);
18728
18872
  const failedBuilds = buildResults.filter((build) => !build.success);
18729
18873
  if (successfulBuilds.length === 0) {
@@ -18798,29 +18942,28 @@ async function getBuildAndUploadResults(componentsToUpload, apiService) {
18798
18942
  );
18799
18943
  return results;
18800
18944
  }
18801
- async function buildSelectedComponents(componentDirs) {
18945
+ async function buildSelectedComponents(componentDirs, useLocalGlobalCss = true) {
18802
18946
  const buildResults = [];
18803
18947
  for (const dir of componentDirs) {
18804
- buildResults.push(await buildComponent(dir));
18948
+ buildResults.push(await buildComponent(dir, useLocalGlobalCss));
18805
18949
  }
18806
18950
  return buildResults;
18807
18951
  }
18808
18952
  async function uploadGlobalAssetLibrary(apiService, componentDir) {
18809
18953
  try {
18810
- const distDir = path11.join(componentDir, "dist");
18811
- const globalCompiledCssPath = path11.join(distDir, "index.css");
18954
+ const distDir = path3.join(componentDir, "dist");
18955
+ const globalCompiledCssPath = path3.join(distDir, "index.css");
18812
18956
  const globalCompiledCssExists = await fileExists(globalCompiledCssPath);
18813
18957
  if (globalCompiledCssExists) {
18814
18958
  const globalCompiledCss = await fs2.readFile(
18815
- path11.join(distDir, "index.css"),
18959
+ path3.join(distDir, "index.css"),
18816
18960
  "utf-8"
18817
18961
  );
18818
18962
  const classNameCandidateIndexFile = await fs2.readFile(
18819
- path11.join(distDir, "index.js"),
18963
+ path3.join(distDir, "index.js"),
18820
18964
  "utf-8"
18821
18965
  );
18822
- const current = await apiService.getGlobalAssetLibrary();
18823
- const originalCss = current.css.original;
18966
+ const originalCss = await getGlobalCss();
18824
18967
  await apiService.updateGlobalAssetLibrary({
18825
18968
  css: {
18826
18969
  original: originalCss,