@drupal-canvas/cli 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +254 -7
- package/dist/index.js +714 -401
- package/dist/index.js.map +1 -1
- package/dist/templates/hello-world/component.yml +4 -4
- package/dist/templates/hello-world/index.jsx +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import chalk2 from 'chalk';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import * as
|
|
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
|
|
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';
|
|
@@ -14,27 +14,27 @@ import { transformSync } from '@swc/wasm';
|
|
|
14
14
|
import { basename } from 'path/win32';
|
|
15
15
|
import { ESLint } from 'eslint';
|
|
16
16
|
import { required } from '@drupal-canvas/eslint-config';
|
|
17
|
-
import { table } from 'table';
|
|
18
17
|
import { fileURLToPath } from 'url';
|
|
19
18
|
import { EventEmitter } from 'events';
|
|
20
19
|
import Stream from 'stream';
|
|
21
20
|
import { StringDecoder } from 'string_decoder';
|
|
21
|
+
import { table } from 'table';
|
|
22
22
|
import * as yaml from 'js-yaml';
|
|
23
23
|
import yaml__default from 'js-yaml';
|
|
24
24
|
import { parse } from '@babel/parser';
|
|
25
25
|
|
|
26
26
|
// package.json
|
|
27
27
|
var package_default = {
|
|
28
|
-
version: "0.
|
|
28
|
+
version: "0.5.0"};
|
|
29
29
|
function loadEnvFiles() {
|
|
30
30
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
31
31
|
if (homeDir) {
|
|
32
|
-
const homeEnvPath =
|
|
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 =
|
|
37
|
+
const localEnvPath = path3.resolve(process.cwd(), ".env");
|
|
38
38
|
if (fs__default.existsSync(localEnvPath)) {
|
|
39
39
|
dotenv.config({ path: localEnvPath });
|
|
40
40
|
}
|
|
@@ -65,7 +65,7 @@ async function ensureConfig(requiredKeys) {
|
|
|
65
65
|
async function promptForConfig(key) {
|
|
66
66
|
switch (key) {
|
|
67
67
|
case "siteUrl": {
|
|
68
|
-
const value = await
|
|
68
|
+
const value = await p.text({
|
|
69
69
|
message: "Enter the site URL",
|
|
70
70
|
placeholder: "https://example.com",
|
|
71
71
|
validate: (value2) => {
|
|
@@ -75,45 +75,45 @@ async function promptForConfig(key) {
|
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
});
|
|
78
|
-
if (
|
|
79
|
-
|
|
78
|
+
if (p.isCancel(value)) {
|
|
79
|
+
p.cancel("Operation cancelled");
|
|
80
80
|
process.exit(0);
|
|
81
81
|
}
|
|
82
82
|
setConfig({ siteUrl: value });
|
|
83
83
|
break;
|
|
84
84
|
}
|
|
85
85
|
case "clientId": {
|
|
86
|
-
const value = await
|
|
86
|
+
const value = await p.text({
|
|
87
87
|
message: "Enter your client ID",
|
|
88
88
|
validate: (value2) => {
|
|
89
89
|
if (!value2) return "Client ID is required";
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
});
|
|
93
|
-
if (
|
|
94
|
-
|
|
93
|
+
if (p.isCancel(value)) {
|
|
94
|
+
p.cancel("Operation cancelled");
|
|
95
95
|
process.exit(0);
|
|
96
96
|
}
|
|
97
97
|
setConfig({ clientId: value });
|
|
98
98
|
break;
|
|
99
99
|
}
|
|
100
100
|
case "clientSecret": {
|
|
101
|
-
const value = await
|
|
101
|
+
const value = await p.password({
|
|
102
102
|
message: "Enter your client secret",
|
|
103
103
|
validate: (value2) => {
|
|
104
104
|
if (!value2) return "Client secret is required";
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
});
|
|
108
|
-
if (
|
|
109
|
-
|
|
108
|
+
if (p.isCancel(value)) {
|
|
109
|
+
p.cancel("Operation cancelled");
|
|
110
110
|
process.exit(0);
|
|
111
111
|
}
|
|
112
112
|
setConfig({ clientSecret: value });
|
|
113
113
|
break;
|
|
114
114
|
}
|
|
115
115
|
case "componentDir": {
|
|
116
|
-
const value = await
|
|
116
|
+
const value = await p.text({
|
|
117
117
|
message: "Enter the component directory",
|
|
118
118
|
placeholder: "./components",
|
|
119
119
|
validate: (value2) => {
|
|
@@ -121,8 +121,8 @@ async function promptForConfig(key) {
|
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
|
-
if (
|
|
125
|
-
|
|
124
|
+
if (p.isCancel(value)) {
|
|
125
|
+
p.cancel("Operation cancelled");
|
|
126
126
|
process.exit(0);
|
|
127
127
|
}
|
|
128
128
|
setConfig({ componentDir: value });
|
|
@@ -10805,26 +10805,26 @@ function createApiService() {
|
|
|
10805
10805
|
userAgent: config2.userAgent
|
|
10806
10806
|
});
|
|
10807
10807
|
}
|
|
10808
|
-
var CANVAS_CACHE_DIR =
|
|
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 =
|
|
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
|
-
|
|
10818
|
+
path3.join(componentDir, `index.jsx`),
|
|
10819
10819
|
component.sourceCodeJs,
|
|
10820
10820
|
"utf-8"
|
|
10821
10821
|
);
|
|
10822
10822
|
}
|
|
10823
10823
|
} catch (error) {
|
|
10824
10824
|
if (error instanceof Error) {
|
|
10825
|
-
|
|
10825
|
+
p.note(chalk2.red(`Error: ${error.message}`));
|
|
10826
10826
|
} else {
|
|
10827
|
-
|
|
10827
|
+
p.note(chalk2.red(`Unknown error: ${String(error)}`));
|
|
10828
10828
|
}
|
|
10829
10829
|
}
|
|
10830
10830
|
}
|
|
@@ -10833,22 +10833,22 @@ 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 =
|
|
10836
|
+
const baseName = path3.basename(componentPath);
|
|
10837
10837
|
const sourcePath = componentPath;
|
|
10838
|
-
const targetPath =
|
|
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 =
|
|
10843
|
-
const targetFile =
|
|
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
|
}
|
|
10847
10847
|
} catch (error) {
|
|
10848
10848
|
if (error instanceof Error) {
|
|
10849
|
-
|
|
10849
|
+
p.note(chalk2.red(`Error: ${error.message}`));
|
|
10850
10850
|
} else {
|
|
10851
|
-
|
|
10851
|
+
p.note(chalk2.red(`Unknown error: ${String(error)}`));
|
|
10852
10852
|
}
|
|
10853
10853
|
}
|
|
10854
10854
|
}
|
|
@@ -10858,7 +10858,7 @@ async function cleanUpCacheDirectory() {
|
|
|
10858
10858
|
withFileTypes: true
|
|
10859
10859
|
});
|
|
10860
10860
|
for (const entry of cacheEntries) {
|
|
10861
|
-
const entryPath =
|
|
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 {
|
|
@@ -10866,15 +10866,39 @@ async function cleanUpCacheDirectory() {
|
|
|
10866
10866
|
}
|
|
10867
10867
|
}
|
|
10868
10868
|
} catch (error) {
|
|
10869
|
-
|
|
10869
|
+
p.note(
|
|
10870
10870
|
chalk2.red(
|
|
10871
10871
|
`Failed to clean cache directory contents: ${error instanceof Error ? error.message : String(error)}`
|
|
10872
10872
|
)
|
|
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) =>
|
|
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(
|
|
10928
|
+
await promises.writeFile(path3.join(distDir, "index.css"), transformedTwCss);
|
|
10905
10929
|
}
|
|
10906
10930
|
async function getClassNameCandidatesForComponent(dir) {
|
|
10907
|
-
const componentName =
|
|
10931
|
+
const componentName = path3.basename(dir);
|
|
10908
10932
|
const config2 = getConfig();
|
|
10909
10933
|
const componentsDir = config2.componentDir;
|
|
10910
|
-
const distDir =
|
|
10911
|
-
const jsSource = await promises.readFile(
|
|
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
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
11066
|
+
path3.join(componentDir, "index.jsx"),
|
|
11054
11067
|
"utf-8"
|
|
11055
11068
|
);
|
|
11056
11069
|
const jsCompiled = compileJS(jsSource);
|
|
11057
|
-
await promises.writeFile(
|
|
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
|
|
11066
|
-
const globalAssetLibrary = await apiService.getGlobalAssetLibrary();
|
|
11067
|
-
const globalSourceCodeCss = globalAssetLibrary.css.original;
|
|
11078
|
+
const globalSourceCodeCss = await getGlobalCss(useLocalGlobalCss);
|
|
11068
11079
|
try {
|
|
11069
|
-
const cssPath =
|
|
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(
|
|
11089
|
+
await promises.writeFile(path3.join(distDir, "index.css"), cssTranspiled);
|
|
11079
11090
|
}
|
|
11080
11091
|
} catch (error) {
|
|
11081
11092
|
result.success = false;
|
|
@@ -11086,57 +11097,28 @@ async function buildComponent(componentDir) {
|
|
|
11086
11097
|
}
|
|
11087
11098
|
return result;
|
|
11088
11099
|
}
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
const summary = `${succeededText}, ${failedText}`;
|
|
11097
|
-
if (results.length > 0) {
|
|
11098
|
-
const tableData = [
|
|
11099
|
-
hasDetails ? [chalk2.bold(title), "", ""] : [chalk2.bold(title), ""],
|
|
11100
|
-
hasDetails ? [itemLabel, "Status", "Details"] : [itemLabel, "Status"],
|
|
11101
|
-
...results.map(
|
|
11102
|
-
(r) => hasDetails ? [
|
|
11103
|
-
r.itemName,
|
|
11104
|
-
r.success ? chalk2.green("Success") : chalk2.red("Failed"),
|
|
11105
|
-
r.details?.map(
|
|
11106
|
-
(d2) => d2.heading ? `${chalk2.underline(d2.heading)}:
|
|
11107
|
-
${d2.content}` : d2.content
|
|
11108
|
-
).join("\n\n")
|
|
11109
|
-
] : [
|
|
11110
|
-
r.itemName,
|
|
11111
|
-
r.success ? chalk2.green("Success") : chalk2.red("Failed")
|
|
11112
|
-
]
|
|
11113
|
-
),
|
|
11114
|
-
hasDetails ? ["SUMMARY", "", summary] : ["SUMMARY", summary]
|
|
11115
|
-
];
|
|
11116
|
-
p9.log.info(
|
|
11117
|
-
table(tableData, {
|
|
11118
|
-
spanningCells: [
|
|
11119
|
-
{
|
|
11120
|
-
row: 0,
|
|
11121
|
-
col: 0,
|
|
11122
|
-
colSpan: hasDetails ? 3 : 2,
|
|
11123
|
-
alignment: "center"
|
|
11124
|
-
},
|
|
11125
|
-
{
|
|
11126
|
-
row: results.length + 2,
|
|
11127
|
-
col: 0,
|
|
11128
|
-
colSpan: hasDetails ? 2 : 1,
|
|
11129
|
-
alignment: hasDetails ? "right" : "left"
|
|
11130
|
-
}
|
|
11131
|
-
],
|
|
11132
|
-
columns: {
|
|
11133
|
-
// Limit the width of the details column for improved readability of long details.
|
|
11134
|
-
2: { width: 100, wrapWord: true }
|
|
11135
|
-
}
|
|
11136
|
-
})
|
|
11100
|
+
|
|
11101
|
+
// src/utils/command-helpers.ts
|
|
11102
|
+
var ALL_COMPONENTS_SELECTOR = "_allComponents";
|
|
11103
|
+
function validateComponentOptions(options) {
|
|
11104
|
+
if (options.components && options.all) {
|
|
11105
|
+
throw new Error(
|
|
11106
|
+
"Cannot use --all and --components options together. Please use either:\n \u2022 --components to specify specific components, or\n \u2022 --all to process everything."
|
|
11137
11107
|
);
|
|
11138
11108
|
}
|
|
11139
11109
|
}
|
|
11110
|
+
function updateConfigFromOptions(options) {
|
|
11111
|
+
if (options.clientId) setConfig({ clientId: options.clientId });
|
|
11112
|
+
if (options.clientSecret) setConfig({ clientSecret: options.clientSecret });
|
|
11113
|
+
if (options.siteUrl) setConfig({ siteUrl: options.siteUrl });
|
|
11114
|
+
if (options.dir) setConfig({ componentDir: options.dir });
|
|
11115
|
+
if (options.scope) setConfig({ scope: options.scope });
|
|
11116
|
+
if (options.all) setConfig({ all: options.all });
|
|
11117
|
+
if (options.verbose) setConfig({ verbose: true });
|
|
11118
|
+
}
|
|
11119
|
+
function pluralizeComponent(count) {
|
|
11120
|
+
return count === 1 ? "component" : "components";
|
|
11121
|
+
}
|
|
11140
11122
|
|
|
11141
11123
|
// ../node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
11142
11124
|
var balanced = (a, b, str) => {
|
|
@@ -17757,11 +17739,11 @@ async function findComponentDirectories(baseDir) {
|
|
|
17757
17739
|
const namedYmls = await glob(`${baseDir}/**/*.component.yml`);
|
|
17758
17740
|
const allComponentPaths = [...standardYmls, ...namedYmls];
|
|
17759
17741
|
const uniqueDirs = new Set(
|
|
17760
|
-
allComponentPaths.map((filePath) =>
|
|
17742
|
+
allComponentPaths.map((filePath) => path3.dirname(filePath))
|
|
17761
17743
|
);
|
|
17762
17744
|
let componentDirs = Array.from(uniqueDirs).sort();
|
|
17763
17745
|
let sdcs = await glob(`${baseDir}/**/*.twig`);
|
|
17764
|
-
sdcs = sdcs.map((sdc) =>
|
|
17746
|
+
sdcs = sdcs.map((sdc) => path3.dirname(sdc));
|
|
17765
17747
|
componentDirs = componentDirs.filter(
|
|
17766
17748
|
(componentDir) => !sdcs.includes(componentDir)
|
|
17767
17749
|
);
|
|
@@ -17772,50 +17754,333 @@ async function findComponentDirectories(baseDir) {
|
|
|
17772
17754
|
}
|
|
17773
17755
|
}
|
|
17774
17756
|
|
|
17775
|
-
// src/utils/
|
|
17776
|
-
|
|
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
|
+
}
|
|
17771
|
+
async function selectLocalComponents(options) {
|
|
17777
17772
|
const config2 = getConfig();
|
|
17778
|
-
const
|
|
17779
|
-
const
|
|
17780
|
-
if (
|
|
17781
|
-
|
|
17782
|
-
|
|
17773
|
+
const componentDir = options.componentDir || config2.componentDir;
|
|
17774
|
+
const globalCssSelection = determineGlobalCssSelection(options);
|
|
17775
|
+
if (options.cssOnly) {
|
|
17776
|
+
return {
|
|
17777
|
+
directories: [],
|
|
17778
|
+
includeGlobalCss: true
|
|
17779
|
+
};
|
|
17783
17780
|
}
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17781
|
+
const allLocalDirs = await findComponentDirectories(componentDir);
|
|
17782
|
+
if (allLocalDirs.length === 0) {
|
|
17783
|
+
throw new Error(`No local components were found in ${componentDir}`);
|
|
17787
17784
|
}
|
|
17788
|
-
|
|
17789
|
-
|
|
17790
|
-
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
|
|
17797
|
-
|
|
17798
|
-
|
|
17799
|
-
|
|
17785
|
+
if (options.components) {
|
|
17786
|
+
return selectSpecificLocalComponents(
|
|
17787
|
+
options.components,
|
|
17788
|
+
allLocalDirs,
|
|
17789
|
+
options,
|
|
17790
|
+
globalCssSelection
|
|
17791
|
+
);
|
|
17792
|
+
}
|
|
17793
|
+
if (options.all) {
|
|
17794
|
+
if (!options.skipConfirmation) {
|
|
17795
|
+
const confirmed = await confirmSelection(
|
|
17796
|
+
allLocalDirs.length,
|
|
17797
|
+
options.confirmMessage
|
|
17798
|
+
);
|
|
17799
|
+
if (!confirmed) {
|
|
17800
|
+
throw new Error("Operation cancelled by user");
|
|
17801
|
+
}
|
|
17802
|
+
}
|
|
17803
|
+
p.log.info(`Selected all components`);
|
|
17804
|
+
return {
|
|
17805
|
+
directories: allLocalDirs,
|
|
17806
|
+
includeGlobalCss: globalCssSelection
|
|
17807
|
+
};
|
|
17808
|
+
}
|
|
17809
|
+
return selectLocalComponentsInteractive(
|
|
17810
|
+
allLocalDirs,
|
|
17811
|
+
options,
|
|
17812
|
+
globalCssSelection
|
|
17813
|
+
);
|
|
17814
|
+
}
|
|
17815
|
+
async function selectSpecificLocalComponents(componentsInput, allLocalDirs, options, globalCssSelection) {
|
|
17816
|
+
const requestedNames = componentsInput.split(",").map((name) => name.trim()).filter((name) => name.length > 0);
|
|
17817
|
+
const notFound = [];
|
|
17818
|
+
const foundDirs = [];
|
|
17819
|
+
for (const requestedName of requestedNames) {
|
|
17820
|
+
const dir = allLocalDirs.find((d2) => path3.basename(d2) === requestedName);
|
|
17821
|
+
if (dir) {
|
|
17822
|
+
foundDirs.push(dir);
|
|
17823
|
+
} else {
|
|
17824
|
+
notFound.push(requestedName);
|
|
17825
|
+
}
|
|
17826
|
+
}
|
|
17827
|
+
if (notFound.length > 0) {
|
|
17828
|
+
const message = options.notFoundMessage || `The following component(s) were not found locally: ${notFound.join(", ")}`;
|
|
17829
|
+
throw new Error(message);
|
|
17830
|
+
}
|
|
17831
|
+
if (!options.skipConfirmation) {
|
|
17832
|
+
const confirmed = await confirmSelection(
|
|
17833
|
+
foundDirs.length,
|
|
17834
|
+
options.confirmMessage
|
|
17835
|
+
);
|
|
17836
|
+
if (!confirmed) {
|
|
17837
|
+
throw new Error("Operation cancelled by user");
|
|
17838
|
+
}
|
|
17839
|
+
}
|
|
17840
|
+
return {
|
|
17841
|
+
directories: foundDirs,
|
|
17842
|
+
includeGlobalCss: globalCssSelection
|
|
17843
|
+
};
|
|
17844
|
+
}
|
|
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] : [],
|
|
17800
17868
|
required: true
|
|
17801
17869
|
});
|
|
17802
|
-
if (
|
|
17803
|
-
|
|
17804
|
-
|
|
17870
|
+
if (p.isCancel(selectedItems)) {
|
|
17871
|
+
throw new Error("Operation cancelled by user");
|
|
17872
|
+
}
|
|
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
|
+
);
|
|
17882
|
+
if (!options.skipConfirmation) {
|
|
17883
|
+
const confirmed = await confirmSelection(
|
|
17884
|
+
finalDirs.length,
|
|
17885
|
+
options.confirmMessage
|
|
17886
|
+
);
|
|
17887
|
+
if (!confirmed) {
|
|
17888
|
+
throw new Error("Operation cancelled by user");
|
|
17889
|
+
}
|
|
17890
|
+
}
|
|
17891
|
+
const finalGlobalCss = options.includeGlobalCss ? includesGlobalCss : globalCssSelection;
|
|
17892
|
+
return {
|
|
17893
|
+
directories: finalDirs,
|
|
17894
|
+
includeGlobalCss: finalGlobalCss
|
|
17895
|
+
};
|
|
17896
|
+
}
|
|
17897
|
+
async function selectRemoteComponents(allComponents, options) {
|
|
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
|
+
}
|
|
17906
|
+
if (componentCount === 0) {
|
|
17907
|
+
throw new Error("No components found");
|
|
17908
|
+
}
|
|
17909
|
+
if (options.all) {
|
|
17910
|
+
if (!options.skipConfirmation) {
|
|
17911
|
+
const confirmed = await confirmSelection(
|
|
17912
|
+
componentCount,
|
|
17913
|
+
options.confirmMessage
|
|
17914
|
+
);
|
|
17915
|
+
if (!confirmed) {
|
|
17916
|
+
throw new Error("Operation cancelled by user");
|
|
17917
|
+
}
|
|
17918
|
+
}
|
|
17919
|
+
return {
|
|
17920
|
+
components: allComponents,
|
|
17921
|
+
includeGlobalCss: globalCssSelection
|
|
17922
|
+
};
|
|
17923
|
+
}
|
|
17924
|
+
if (options.components) {
|
|
17925
|
+
return selectSpecificRemoteComponents(
|
|
17926
|
+
options.components,
|
|
17927
|
+
allComponents,
|
|
17928
|
+
options,
|
|
17929
|
+
globalCssSelection
|
|
17930
|
+
);
|
|
17931
|
+
}
|
|
17932
|
+
return selectRemoteComponentsInteractive(
|
|
17933
|
+
allComponents,
|
|
17934
|
+
options,
|
|
17935
|
+
globalCssSelection
|
|
17936
|
+
);
|
|
17937
|
+
}
|
|
17938
|
+
async function selectSpecificRemoteComponents(componentsInput, allComponents, options, globalCssSelection) {
|
|
17939
|
+
const requestedNames = componentsInput.split(",").map((name) => name.trim()).filter((name) => name.length > 0);
|
|
17940
|
+
const notFound = [];
|
|
17941
|
+
const selected = {};
|
|
17942
|
+
for (const requestedName of requestedNames) {
|
|
17943
|
+
const component = allComponents[requestedName];
|
|
17944
|
+
if (component) {
|
|
17945
|
+
selected[requestedName] = component;
|
|
17946
|
+
} else {
|
|
17947
|
+
notFound.push(requestedName);
|
|
17948
|
+
}
|
|
17949
|
+
}
|
|
17950
|
+
if (notFound.length > 0) {
|
|
17951
|
+
const message = options.notFoundMessage || `The following component(s) were not found: ${notFound.join(", ")}`;
|
|
17952
|
+
throw new Error(message);
|
|
17953
|
+
}
|
|
17954
|
+
if (!options.skipConfirmation) {
|
|
17955
|
+
const confirmed = await confirmSelection(
|
|
17956
|
+
Object.keys(selected).length,
|
|
17957
|
+
options.confirmMessage
|
|
17958
|
+
);
|
|
17959
|
+
if (!confirmed) {
|
|
17960
|
+
throw new Error("Operation cancelled by user");
|
|
17961
|
+
}
|
|
17962
|
+
}
|
|
17963
|
+
return {
|
|
17964
|
+
components: selected,
|
|
17965
|
+
includeGlobalCss: globalCssSelection
|
|
17966
|
+
};
|
|
17967
|
+
}
|
|
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
|
+
});
|
|
17805
17980
|
}
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
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] : [],
|
|
17991
|
+
required: true
|
|
17992
|
+
});
|
|
17993
|
+
if (p.isCancel(selectedItems)) {
|
|
17994
|
+
throw new Error("Operation cancelled by user");
|
|
17995
|
+
}
|
|
17996
|
+
const includesAllComponents = selectedItems.includes(
|
|
17997
|
+
ALL_COMPONENTS_SELECTOR
|
|
17998
|
+
);
|
|
17999
|
+
const includesGlobalCss = selectedItems.includes(
|
|
18000
|
+
GLOBAL_CSS_SELECTOR
|
|
18001
|
+
);
|
|
18002
|
+
const selected = includesAllComponents ? allComponents : Object.fromEntries(
|
|
18003
|
+
Object.entries(allComponents).filter(
|
|
18004
|
+
([, component]) => selectedItems.includes(component.machineName)
|
|
18005
|
+
)
|
|
18006
|
+
);
|
|
18007
|
+
if (!options.skipConfirmation) {
|
|
18008
|
+
const confirmed = await confirmSelection(
|
|
18009
|
+
Object.keys(selected).length,
|
|
18010
|
+
options.confirmMessage
|
|
18011
|
+
);
|
|
18012
|
+
if (!confirmed) {
|
|
18013
|
+
throw new Error("Operation cancelled by user");
|
|
18014
|
+
}
|
|
18015
|
+
}
|
|
18016
|
+
const finalGlobalCss = options.includeGlobalCss ? includesGlobalCss : globalCssSelection;
|
|
18017
|
+
return {
|
|
18018
|
+
components: selected,
|
|
18019
|
+
includeGlobalCss: finalGlobalCss
|
|
18020
|
+
};
|
|
18021
|
+
}
|
|
18022
|
+
async function confirmSelection(count, customMessage) {
|
|
18023
|
+
const componentLabel = count === 1 ? "component" : "components";
|
|
18024
|
+
const message = customMessage || `Process ${count} ${componentLabel}?`;
|
|
18025
|
+
const confirmed = await p.confirm({
|
|
18026
|
+
message,
|
|
17809
18027
|
initialValue: true
|
|
17810
18028
|
});
|
|
17811
|
-
if (
|
|
17812
|
-
|
|
17813
|
-
return null;
|
|
18029
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
18030
|
+
return false;
|
|
17814
18031
|
}
|
|
17815
|
-
|
|
17816
|
-
|
|
18032
|
+
return true;
|
|
18033
|
+
}
|
|
18034
|
+
function reportResults(results, title, itemLabel = "Component") {
|
|
18035
|
+
results.sort((a, b) => a.itemName.localeCompare(b.itemName));
|
|
18036
|
+
const successful = results.filter((r) => r.success).length;
|
|
18037
|
+
const failed = results.filter((r) => !r.success).length;
|
|
18038
|
+
const hasDetails = results.some((r) => (r.details?.length ?? 0) > 0);
|
|
18039
|
+
const succeededText = failed === 0 ? chalk2.green(`${successful} succeeded`) : `${successful} succeeded`;
|
|
18040
|
+
const failedText = failed > 0 ? chalk2.red(`${failed} failed`) : chalk2.dim(`${failed} failed`);
|
|
18041
|
+
const summary = `${succeededText}, ${failedText}`;
|
|
18042
|
+
if (results.length > 0) {
|
|
18043
|
+
const tableData = [
|
|
18044
|
+
hasDetails ? [chalk2.bold(title), "", ""] : [chalk2.bold(title), ""],
|
|
18045
|
+
hasDetails ? [itemLabel, "Status", "Details"] : [itemLabel, "Status"],
|
|
18046
|
+
...results.map(
|
|
18047
|
+
(r) => hasDetails ? [
|
|
18048
|
+
r.itemName,
|
|
18049
|
+
r.success ? chalk2.green("Success") : chalk2.red("Failed"),
|
|
18050
|
+
r.details?.map(
|
|
18051
|
+
(d2) => d2.heading ? `${chalk2.underline(d2.heading)}:
|
|
18052
|
+
${d2.content}` : d2.content
|
|
18053
|
+
).join("\n\n") ?? ""
|
|
18054
|
+
] : [
|
|
18055
|
+
r.itemName,
|
|
18056
|
+
r.success ? chalk2.green("Success") : chalk2.red("Failed")
|
|
18057
|
+
]
|
|
18058
|
+
),
|
|
18059
|
+
hasDetails ? ["SUMMARY", "", summary] : ["SUMMARY", summary]
|
|
18060
|
+
];
|
|
18061
|
+
p.log.info(
|
|
18062
|
+
table(tableData, {
|
|
18063
|
+
spanningCells: [
|
|
18064
|
+
{
|
|
18065
|
+
row: 0,
|
|
18066
|
+
col: 0,
|
|
18067
|
+
colSpan: hasDetails ? 3 : 2,
|
|
18068
|
+
alignment: "center"
|
|
18069
|
+
},
|
|
18070
|
+
{
|
|
18071
|
+
row: results.length + 2,
|
|
18072
|
+
col: 0,
|
|
18073
|
+
colSpan: hasDetails ? 2 : 1,
|
|
18074
|
+
alignment: hasDetails ? "right" : "left"
|
|
18075
|
+
}
|
|
18076
|
+
],
|
|
18077
|
+
columns: {
|
|
18078
|
+
// Limit the width of the details column for improved readability of long details.
|
|
18079
|
+
2: { width: 100, wrapWord: true }
|
|
18080
|
+
}
|
|
18081
|
+
})
|
|
18082
|
+
);
|
|
17817
18083
|
}
|
|
17818
|
-
return selectedDirs;
|
|
17819
18084
|
}
|
|
17820
18085
|
|
|
17821
18086
|
// src/commands/build.ts
|
|
@@ -17823,75 +18088,89 @@ function buildCommand(program2) {
|
|
|
17823
18088
|
program2.command("build").description("build local components and Tailwind CSS assets").option(
|
|
17824
18089
|
"-d, --dir <directory>",
|
|
17825
18090
|
"Component directory to build the components in"
|
|
17826
|
-
).option("--all", "Build all components").option(
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
|
|
17834
|
-
|
|
17835
|
-
|
|
17836
|
-
|
|
17837
|
-
|
|
17838
|
-
|
|
17839
|
-
|
|
17840
|
-
|
|
17841
|
-
|
|
17842
|
-
|
|
17843
|
-
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
|
|
17847
|
-
const s1 = p9.spinner();
|
|
17848
|
-
s1.start(`Building ${componentLabelPluralized}`);
|
|
17849
|
-
const results = [];
|
|
17850
|
-
for (const componentDir of selectedComponents) {
|
|
17851
|
-
results.push(await buildComponent(componentDir));
|
|
17852
|
-
}
|
|
17853
|
-
s1.stop(
|
|
17854
|
-
chalk2.green(
|
|
17855
|
-
`Processed ${selectedComponents.length} ${componentLabelPluralized}`
|
|
17856
|
-
)
|
|
17857
|
-
);
|
|
17858
|
-
reportResults(results, "Built components", "Component");
|
|
17859
|
-
if (results.map((result) => result.success).includes(false)) {
|
|
17860
|
-
process.exit(1);
|
|
17861
|
-
}
|
|
17862
|
-
if (skipTailwind) {
|
|
17863
|
-
p9.log.info("Skipping Tailwind CSS build");
|
|
17864
|
-
} else {
|
|
17865
|
-
const s2 = p9.spinner();
|
|
17866
|
-
s2.start("Building Tailwind CSS");
|
|
17867
|
-
const tailwindResult = await buildTailwindForComponents(
|
|
17868
|
-
selectedComponents
|
|
18091
|
+
).option("--all", "Build all components").option(
|
|
18092
|
+
"-c, --components <names>",
|
|
18093
|
+
"Specific component(s) to build (comma-separated)"
|
|
18094
|
+
).option("--no-tailwind", "Skip Tailwind CSS building").option("-y, --yes", "Skip confirmation prompts").option("--client-id <id>", "Client ID").option("--client-secret <secret>", "Client Secret").option("--site-url <url>", "Site URL").option("--verbose", "Enable verbose output").action(async (options) => {
|
|
18095
|
+
try {
|
|
18096
|
+
p.intro(chalk2.bold("Drupal Canvas CLI: build"));
|
|
18097
|
+
validateComponentOptions(options);
|
|
18098
|
+
const allFlag = options.all || options.yes && !options.components || false;
|
|
18099
|
+
const skipTailwind = !options.tailwind;
|
|
18100
|
+
updateConfigFromOptions(options);
|
|
18101
|
+
if (!skipTailwind) {
|
|
18102
|
+
await ensureConfig(["siteUrl", "clientId", "clientSecret"]);
|
|
18103
|
+
}
|
|
18104
|
+
const { directories: componentsToBuild } = await selectLocalComponents({
|
|
18105
|
+
all: allFlag,
|
|
18106
|
+
components: options.components,
|
|
18107
|
+
skipConfirmation: options.yes,
|
|
18108
|
+
selectMessage: "Select components to build"
|
|
18109
|
+
});
|
|
18110
|
+
const componentLabelPluralized = pluralizeComponent(
|
|
18111
|
+
componentsToBuild.length
|
|
17869
18112
|
);
|
|
17870
|
-
|
|
18113
|
+
const s1 = p.spinner();
|
|
18114
|
+
s1.start(`Building ${componentLabelPluralized}`);
|
|
18115
|
+
const results = [];
|
|
18116
|
+
for (const componentDir of componentsToBuild) {
|
|
18117
|
+
results.push(await buildComponent(componentDir));
|
|
18118
|
+
}
|
|
18119
|
+
s1.stop(
|
|
17871
18120
|
chalk2.green(
|
|
17872
|
-
`Processed
|
|
18121
|
+
`Processed ${componentsToBuild.length} ${componentLabelPluralized}`
|
|
17873
18122
|
)
|
|
17874
18123
|
);
|
|
17875
|
-
reportResults(
|
|
17876
|
-
if (
|
|
17877
|
-
|
|
18124
|
+
reportResults(results, "Built components", "Component");
|
|
18125
|
+
if (results.map((result) => result.success).includes(false)) {
|
|
18126
|
+
process.exit(1);
|
|
18127
|
+
}
|
|
18128
|
+
if (skipTailwind) {
|
|
18129
|
+
p.log.info("Skipping Tailwind CSS build");
|
|
18130
|
+
} else {
|
|
18131
|
+
const s2 = p.spinner();
|
|
18132
|
+
s2.start("Building Tailwind CSS");
|
|
18133
|
+
const tailwindResult = await buildTailwindForComponents(
|
|
18134
|
+
componentsToBuild
|
|
18135
|
+
);
|
|
18136
|
+
s2.stop(
|
|
18137
|
+
chalk2.green(
|
|
18138
|
+
`Processed Tailwind CSS classes from ${componentsToBuild.length} selected local ${componentLabelPluralized} and all online components`
|
|
18139
|
+
)
|
|
18140
|
+
);
|
|
18141
|
+
reportResults([tailwindResult], "Built assets", "Asset");
|
|
18142
|
+
if (!tailwindResult.success) {
|
|
18143
|
+
return process.exit(1);
|
|
18144
|
+
}
|
|
18145
|
+
}
|
|
18146
|
+
p.outro(`\u{1F4E6} Build completed`);
|
|
18147
|
+
} catch (error) {
|
|
18148
|
+
if (error instanceof Error) {
|
|
18149
|
+
p.note(chalk2.red(`Error: ${error.message}`));
|
|
18150
|
+
} else {
|
|
18151
|
+
p.note(chalk2.red(`Unknown error: ${String(error)}`));
|
|
17878
18152
|
}
|
|
18153
|
+
process.exit(1);
|
|
17879
18154
|
}
|
|
17880
|
-
p9.outro(`\u{1F4E6} Build completed`);
|
|
17881
18155
|
});
|
|
17882
18156
|
}
|
|
17883
18157
|
function downloadCommand(program2) {
|
|
17884
|
-
program2.command("download").description("download components to your local filesystem").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(
|
|
17885
|
-
|
|
18158
|
+
program2.command("download").description("download components to your local filesystem").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(
|
|
18159
|
+
"-c, --components <names>",
|
|
18160
|
+
"Specific component(s) to download (comma-separated)"
|
|
18161
|
+
).option("--all", "Download all components").option("-y, --yes", "Skip all confirmation prompts").option(
|
|
18162
|
+
"--skip-overwrite",
|
|
18163
|
+
"Skip downloading components that already exist locally"
|
|
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) => {
|
|
18165
|
+
p.intro(chalk2.bold("Drupal Canvas CLI: download"));
|
|
17886
18166
|
try {
|
|
17887
|
-
|
|
17888
|
-
if (options.
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
if (options.verbose) setConfig({ verbose: true });
|
|
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
|
+
}
|
|
18173
|
+
updateConfigFromOptions(options);
|
|
17895
18174
|
await ensureConfig([
|
|
17896
18175
|
"siteUrl",
|
|
17897
18176
|
"clientId",
|
|
@@ -17901,77 +18180,52 @@ function downloadCommand(program2) {
|
|
|
17901
18180
|
]);
|
|
17902
18181
|
const config2 = getConfig();
|
|
17903
18182
|
const apiService = await createApiService();
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
const
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
|
|
17910
|
-
|
|
17911
|
-
|
|
17912
|
-
|
|
17913
|
-
|
|
17914
|
-
}
|
|
17915
|
-
s.stop(`Found ${Object.keys(components).length} components`);
|
|
17916
|
-
let componentsToDownload = {};
|
|
17917
|
-
if (options.all) {
|
|
17918
|
-
componentsToDownload = components;
|
|
17919
|
-
} else if (options.component) {
|
|
17920
|
-
const component = Object.values(components).find(
|
|
17921
|
-
(c) => c.machineName === options.component || c.name === options.component
|
|
17922
|
-
);
|
|
17923
|
-
if (!component) {
|
|
17924
|
-
p9.note(chalk2.red(`Component "${options.component}" not found`));
|
|
17925
|
-
p9.outro("Download cancelled");
|
|
17926
|
-
return;
|
|
17927
|
-
}
|
|
17928
|
-
componentsToDownload = { component };
|
|
18183
|
+
let components = {};
|
|
18184
|
+
let globalCss;
|
|
18185
|
+
const s = p.spinner();
|
|
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");
|
|
17929
18193
|
} else {
|
|
17930
|
-
|
|
17931
|
-
|
|
17932
|
-
|
|
17933
|
-
|
|
17934
|
-
|
|
17935
|
-
|
|
17936
|
-
|
|
17937
|
-
|
|
17938
|
-
|
|
17939
|
-
|
|
17940
|
-
}))
|
|
17941
|
-
],
|
|
17942
|
-
required: true
|
|
17943
|
-
});
|
|
17944
|
-
if (p9.isCancel(selectedComponents)) {
|
|
17945
|
-
p9.cancel("Operation cancelled");
|
|
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");
|
|
17946
18204
|
return;
|
|
17947
18205
|
}
|
|
17948
|
-
|
|
17949
|
-
|
|
17950
|
-
|
|
17951
|
-
|
|
17952
|
-
|
|
17953
|
-
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
|
|
17961
|
-
const confirmDownload = await p9.confirm({
|
|
17962
|
-
message: `Download ${Object.keys(componentsToDownload).length} ${componentPluralized} to ${config2.componentDir}?`,
|
|
17963
|
-
initialValue: true
|
|
18206
|
+
s.stop(`Found ${Object.keys(components).length} components`);
|
|
18207
|
+
}
|
|
18208
|
+
const allFlag = options.all || options.yes && !options.components || false;
|
|
18209
|
+
const { components: componentsToDownload, includeGlobalCss } = await selectRemoteComponents(components, {
|
|
18210
|
+
all: allFlag,
|
|
18211
|
+
components: options.components,
|
|
18212
|
+
skipConfirmation: options.yes,
|
|
18213
|
+
skipCss: options.skipCss,
|
|
18214
|
+
cssOnly: options.cssOnly,
|
|
18215
|
+
includeGlobalCss: !options.skipCss,
|
|
18216
|
+
globalCssDefault: true,
|
|
18217
|
+
selectMessage: "Select items to download",
|
|
18218
|
+
confirmMessage: `Download to ${config2.componentDir}?`
|
|
17964
18219
|
});
|
|
17965
|
-
|
|
17966
|
-
|
|
17967
|
-
return;
|
|
17968
|
-
}
|
|
18220
|
+
const componentCount = Object.keys(componentsToDownload).length;
|
|
18221
|
+
const componentPluralized = pluralizeComponent(componentCount);
|
|
17969
18222
|
const results = [];
|
|
17970
|
-
|
|
18223
|
+
const downloadMessage = options.cssOnly ? "Downloading global CSS" : componentCount > 0 ? `Downloading ${componentPluralized}` : "Processing request";
|
|
18224
|
+
s.start(downloadMessage);
|
|
17971
18225
|
for (const key in componentsToDownload) {
|
|
17972
18226
|
const component = componentsToDownload[key];
|
|
17973
18227
|
try {
|
|
17974
|
-
const componentDir =
|
|
18228
|
+
const componentDir = path3.join(
|
|
17975
18229
|
config2.componentDir,
|
|
17976
18230
|
component.machineName
|
|
17977
18231
|
);
|
|
@@ -17979,13 +18233,27 @@ function downloadCommand(program2) {
|
|
|
17979
18233
|
if (dirExists) {
|
|
17980
18234
|
const files = await fs2.readdir(componentDir);
|
|
17981
18235
|
if (files.length > 0) {
|
|
17982
|
-
|
|
17983
|
-
|
|
17984
|
-
|
|
17985
|
-
|
|
17986
|
-
|
|
17987
|
-
|
|
17988
|
-
|
|
18236
|
+
if (options.skipOverwrite) {
|
|
18237
|
+
results.push({
|
|
18238
|
+
itemName: component.machineName,
|
|
18239
|
+
success: true,
|
|
18240
|
+
details: [
|
|
18241
|
+
{
|
|
18242
|
+
content: "Skipped (already exists)"
|
|
18243
|
+
}
|
|
18244
|
+
]
|
|
18245
|
+
});
|
|
18246
|
+
continue;
|
|
18247
|
+
}
|
|
18248
|
+
if (!options.yes) {
|
|
18249
|
+
const confirmDelete = await p.confirm({
|
|
18250
|
+
message: `The "${componentDir}" directory is not empty. Are you sure you want to delete and overwrite this directory?`,
|
|
18251
|
+
initialValue: true
|
|
18252
|
+
});
|
|
18253
|
+
if (p.isCancel(confirmDelete) || !confirmDelete) {
|
|
18254
|
+
p.cancel("Operation cancelled");
|
|
18255
|
+
process.exit(0);
|
|
18256
|
+
}
|
|
17989
18257
|
}
|
|
17990
18258
|
}
|
|
17991
18259
|
}
|
|
@@ -18002,20 +18270,20 @@ function downloadCommand(program2) {
|
|
|
18002
18270
|
slots: component.slots || {}
|
|
18003
18271
|
};
|
|
18004
18272
|
await fs2.writeFile(
|
|
18005
|
-
|
|
18273
|
+
path3.join(componentDir, `component.yml`),
|
|
18006
18274
|
yaml__default.dump(metadata),
|
|
18007
18275
|
"utf-8"
|
|
18008
18276
|
);
|
|
18009
18277
|
if (component.sourceCodeJs) {
|
|
18010
18278
|
await fs2.writeFile(
|
|
18011
|
-
|
|
18279
|
+
path3.join(componentDir, `index.jsx`),
|
|
18012
18280
|
component.sourceCodeJs,
|
|
18013
18281
|
"utf-8"
|
|
18014
18282
|
);
|
|
18015
18283
|
}
|
|
18016
18284
|
if (component.sourceCodeCss) {
|
|
18017
18285
|
await fs2.writeFile(
|
|
18018
|
-
|
|
18286
|
+
path3.join(componentDir, `index.css`),
|
|
18019
18287
|
component.sourceCodeCss,
|
|
18020
18288
|
"utf-8"
|
|
18021
18289
|
);
|
|
@@ -18036,16 +18304,15 @@ function downloadCommand(program2) {
|
|
|
18036
18304
|
});
|
|
18037
18305
|
}
|
|
18038
18306
|
}
|
|
18039
|
-
|
|
18040
|
-
|
|
18041
|
-
|
|
18042
|
-
)
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
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") {
|
|
18046
18313
|
let globalCssResult;
|
|
18047
18314
|
try {
|
|
18048
|
-
const globalCssPath =
|
|
18315
|
+
const globalCssPath = path3.join(config2.componentDir, "global.css");
|
|
18049
18316
|
await fs2.writeFile(globalCssPath, globalCss, "utf-8");
|
|
18050
18317
|
globalCssResult = {
|
|
18051
18318
|
itemName: "global.css",
|
|
@@ -18065,12 +18332,13 @@ function downloadCommand(program2) {
|
|
|
18065
18332
|
}
|
|
18066
18333
|
reportResults([globalCssResult], "Downloaded assets", "Asset");
|
|
18067
18334
|
}
|
|
18068
|
-
|
|
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);
|
|
18069
18337
|
} catch (error) {
|
|
18070
18338
|
if (error instanceof Error) {
|
|
18071
|
-
|
|
18339
|
+
p.note(chalk2.red(`Error: ${error.message}`));
|
|
18072
18340
|
} else {
|
|
18073
|
-
|
|
18341
|
+
p.note(chalk2.red(`Unknown error: ${String(error)}`));
|
|
18074
18342
|
}
|
|
18075
18343
|
process.exit(1);
|
|
18076
18344
|
}
|
|
@@ -18084,7 +18352,7 @@ function scaffoldCommand(program2) {
|
|
|
18084
18352
|
"-d, --dir <directory>",
|
|
18085
18353
|
"Component directory to create component in"
|
|
18086
18354
|
).option("--verbose", "Enable verbose output").action(async (options) => {
|
|
18087
|
-
|
|
18355
|
+
p.intro(chalk2.bold("Drupal Canvas CLI: scaffold"));
|
|
18088
18356
|
try {
|
|
18089
18357
|
if (options.dir) setConfig({ componentDir: options.dir });
|
|
18090
18358
|
if (options.verbose) setConfig({ verbose: options.verbose });
|
|
@@ -18092,7 +18360,7 @@ function scaffoldCommand(program2) {
|
|
|
18092
18360
|
const baseDir = config2.componentDir;
|
|
18093
18361
|
let componentName = options.name;
|
|
18094
18362
|
if (!componentName) {
|
|
18095
|
-
const name = await
|
|
18363
|
+
const name = await p.text({
|
|
18096
18364
|
message: "Enter the component name",
|
|
18097
18365
|
placeholder: "my-component",
|
|
18098
18366
|
validate: (value) => {
|
|
@@ -18102,57 +18370,57 @@ function scaffoldCommand(program2) {
|
|
|
18102
18370
|
return;
|
|
18103
18371
|
}
|
|
18104
18372
|
});
|
|
18105
|
-
if (
|
|
18106
|
-
|
|
18373
|
+
if (p.isCancel(name)) {
|
|
18374
|
+
p.cancel("Operation cancelled");
|
|
18107
18375
|
return;
|
|
18108
18376
|
}
|
|
18109
18377
|
componentName = name;
|
|
18110
18378
|
}
|
|
18111
|
-
const componentDir =
|
|
18112
|
-
const s =
|
|
18379
|
+
const componentDir = path3.join(baseDir, componentName);
|
|
18380
|
+
const s = p.spinner();
|
|
18113
18381
|
s.start(`Creating component "${componentName}"`);
|
|
18114
18382
|
try {
|
|
18115
18383
|
await fs2.mkdir(componentDir, { recursive: true });
|
|
18116
|
-
const templateDir =
|
|
18117
|
-
|
|
18384
|
+
const templateDir = path3.join(
|
|
18385
|
+
path3.dirname(new URL(import.meta.url).pathname),
|
|
18118
18386
|
"templates/hello-world"
|
|
18119
18387
|
);
|
|
18120
18388
|
const files = await fs2.readdir(templateDir);
|
|
18121
18389
|
const newDirFiles = await fs2.readdir(componentDir);
|
|
18122
18390
|
if (newDirFiles.length > 0) {
|
|
18123
|
-
const confirmDelete = await
|
|
18391
|
+
const confirmDelete = await p.confirm({
|
|
18124
18392
|
message: `The "${componentDir}" directory is not empty. Do you want to proceed and potentially overwrite existing files?`,
|
|
18125
18393
|
initialValue: true
|
|
18126
18394
|
});
|
|
18127
|
-
if (
|
|
18128
|
-
|
|
18395
|
+
if (p.isCancel(confirmDelete) || !confirmDelete) {
|
|
18396
|
+
p.cancel("Operation cancelled");
|
|
18129
18397
|
process.exit(0);
|
|
18130
18398
|
}
|
|
18131
18399
|
}
|
|
18132
18400
|
for (const file of files) {
|
|
18133
|
-
const srcPath =
|
|
18134
|
-
const destPath =
|
|
18401
|
+
const srcPath = path3.join(templateDir, file);
|
|
18402
|
+
const destPath = path3.join(componentDir, file);
|
|
18135
18403
|
let content = await fs2.readFile(srcPath, "utf-8");
|
|
18136
18404
|
const { pascalCaseName, className, displayName, machineName } = generateComponentNameFormats(componentName);
|
|
18137
18405
|
content = content.replace(/HelloWorld/g, pascalCaseName).replace(/hello-world-component/g, className).replace(/Hello World/g, displayName).replace(/hello_world/g, machineName);
|
|
18138
18406
|
await fs2.writeFile(destPath, content, "utf-8");
|
|
18139
18407
|
}
|
|
18140
18408
|
s.stop(chalk2.green(`Created component "${componentName}"`));
|
|
18141
|
-
|
|
18409
|
+
p.note(`Component "${componentName}" has been created:
|
|
18142
18410
|
- Directory: ${componentDir}
|
|
18143
|
-
- Component metadata: ${
|
|
18144
|
-
- Source file: ${
|
|
18145
|
-
- CSS file: ${
|
|
18146
|
-
|
|
18411
|
+
- Component metadata: ${path3.join(componentDir, `component.yml`)}
|
|
18412
|
+
- Source file: ${path3.join(componentDir, `index.jsx`)}
|
|
18413
|
+
- CSS file: ${path3.join(componentDir, `index.css`)}`);
|
|
18414
|
+
p.outro("\u{1F3D7}\uFE0F Scaffold command completed");
|
|
18147
18415
|
} catch (error) {
|
|
18148
18416
|
s.stop(chalk2.red(`Failed to create component "${componentName}"`));
|
|
18149
18417
|
throw error;
|
|
18150
18418
|
}
|
|
18151
18419
|
} catch (error) {
|
|
18152
18420
|
if (error instanceof Error) {
|
|
18153
|
-
|
|
18421
|
+
p.note(chalk2.red(`Error: ${error.message}`));
|
|
18154
18422
|
} else {
|
|
18155
|
-
|
|
18423
|
+
p.note(chalk2.red(`Unknown error: ${String(error)}`));
|
|
18156
18424
|
}
|
|
18157
18425
|
process.exit(1);
|
|
18158
18426
|
}
|
|
@@ -18220,20 +18488,20 @@ var getDataDependenciesFromAst = (ast) => ast.program.body.filter((d2) => d2.typ
|
|
|
18220
18488
|
async function processComponentFiles(componentDir) {
|
|
18221
18489
|
const metadataPath = await findMetadataPath(componentDir);
|
|
18222
18490
|
const metadata = await readComponentMetadata(metadataPath);
|
|
18223
|
-
const distDir =
|
|
18491
|
+
const distDir = path3.join(componentDir, "dist");
|
|
18224
18492
|
const sourceCodeJs = await promises.readFile(
|
|
18225
|
-
|
|
18493
|
+
path3.join(componentDir, "index.jsx"),
|
|
18226
18494
|
"utf-8"
|
|
18227
18495
|
);
|
|
18228
|
-
const compiledJs = await promises.readFile(
|
|
18496
|
+
const compiledJs = await promises.readFile(path3.join(distDir, "index.js"), "utf-8");
|
|
18229
18497
|
let sourceCodeCss = "";
|
|
18230
18498
|
let compiledCss = "";
|
|
18231
18499
|
try {
|
|
18232
18500
|
sourceCodeCss = await promises.readFile(
|
|
18233
|
-
|
|
18501
|
+
path3.join(componentDir, "index.css"),
|
|
18234
18502
|
"utf-8"
|
|
18235
18503
|
);
|
|
18236
|
-
compiledCss = await promises.readFile(
|
|
18504
|
+
compiledCss = await promises.readFile(path3.join(distDir, "index.css"), "utf-8");
|
|
18237
18505
|
} catch {
|
|
18238
18506
|
}
|
|
18239
18507
|
return {
|
|
@@ -18245,7 +18513,7 @@ async function processComponentFiles(componentDir) {
|
|
|
18245
18513
|
};
|
|
18246
18514
|
}
|
|
18247
18515
|
async function findMetadataPath(componentDir) {
|
|
18248
|
-
const metadataPath =
|
|
18516
|
+
const metadataPath = path3.join(componentDir, "component.yml");
|
|
18249
18517
|
try {
|
|
18250
18518
|
await promises.access(metadataPath);
|
|
18251
18519
|
return metadataPath;
|
|
@@ -18266,10 +18534,10 @@ async function readComponentMetadata(filePath) {
|
|
|
18266
18534
|
}
|
|
18267
18535
|
const metadata = rawMetadata;
|
|
18268
18536
|
if (!metadata.name) {
|
|
18269
|
-
metadata.name =
|
|
18537
|
+
metadata.name = path3.basename(path3.dirname(filePath));
|
|
18270
18538
|
}
|
|
18271
18539
|
if (!metadata.machineName) {
|
|
18272
|
-
metadata.machineName =
|
|
18540
|
+
metadata.machineName = path3.basename(path3.dirname(filePath));
|
|
18273
18541
|
}
|
|
18274
18542
|
if (!metadata.slots || typeof metadata.slots !== "object") {
|
|
18275
18543
|
metadata.slots = {};
|
|
@@ -18347,12 +18615,12 @@ async function processInPool(items, processor, concurrency = 10) {
|
|
|
18347
18615
|
}
|
|
18348
18616
|
return results.sort((a, b) => a.index - b.index);
|
|
18349
18617
|
}
|
|
18350
|
-
function createProgressCallback(
|
|
18618
|
+
function createProgressCallback(spinner6, operation, total) {
|
|
18351
18619
|
let completed = 0;
|
|
18352
18620
|
return () => {
|
|
18353
18621
|
completed++;
|
|
18354
18622
|
const percentage = Math.round(completed / total * 100);
|
|
18355
|
-
|
|
18623
|
+
spinner6.message(`${operation} (${completed}/${total} - ${percentage}%)`);
|
|
18356
18624
|
};
|
|
18357
18625
|
}
|
|
18358
18626
|
|
|
@@ -18436,19 +18704,21 @@ async function uploadComponents(uploadTasks, apiService, onProgress) {
|
|
|
18436
18704
|
});
|
|
18437
18705
|
}
|
|
18438
18706
|
function uploadCommand(program2) {
|
|
18439
|
-
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(
|
|
18440
|
-
|
|
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(
|
|
18708
|
+
"-c, --components <names>",
|
|
18709
|
+
"Specific component(s) to upload (comma-separated)"
|
|
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) => {
|
|
18711
|
+
const allFlag = options.all || options.yes && !options.components || false;
|
|
18441
18712
|
const skipTailwind = !options.tailwind;
|
|
18442
18713
|
try {
|
|
18443
|
-
|
|
18444
|
-
|
|
18445
|
-
if (options.
|
|
18446
|
-
|
|
18447
|
-
|
|
18448
|
-
|
|
18449
|
-
|
|
18450
|
-
|
|
18451
|
-
if (options.verbose) setConfig({ verbose: options.verbose });
|
|
18714
|
+
p.intro(chalk2.bold("Drupal Canvas CLI: upload"));
|
|
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
|
+
}
|
|
18721
|
+
updateConfigFromOptions(options);
|
|
18452
18722
|
await ensureConfig([
|
|
18453
18723
|
"siteUrl",
|
|
18454
18724
|
"clientId",
|
|
@@ -18457,28 +18727,42 @@ function uploadCommand(program2) {
|
|
|
18457
18727
|
"componentDir"
|
|
18458
18728
|
]);
|
|
18459
18729
|
const config2 = getConfig();
|
|
18460
|
-
const componentsToUpload = await selectLocalComponents(
|
|
18461
|
-
allFlag,
|
|
18462
|
-
|
|
18463
|
-
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
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
|
+
});
|
|
18467
18740
|
const apiService = await createApiService();
|
|
18468
|
-
|
|
18469
|
-
|
|
18470
|
-
|
|
18471
|
-
|
|
18472
|
-
|
|
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
|
+
}
|
|
18752
|
+
}
|
|
18473
18753
|
if (skipTailwind) {
|
|
18474
|
-
|
|
18754
|
+
p.log.info("Skipping Tailwind CSS build");
|
|
18475
18755
|
} else {
|
|
18476
|
-
const s2 =
|
|
18756
|
+
const s2 = p.spinner();
|
|
18477
18757
|
s2.start("Building Tailwind CSS");
|
|
18478
18758
|
const tailwindResult = await buildTailwindForComponents(
|
|
18479
|
-
componentsToUpload
|
|
18759
|
+
componentsToUpload,
|
|
18760
|
+
includeGlobalCss
|
|
18761
|
+
// Use local CSS if includeGlobalCss is true
|
|
18762
|
+
);
|
|
18763
|
+
const componentLabelPluralized = pluralizeComponent(
|
|
18764
|
+
componentsToUpload.length
|
|
18480
18765
|
);
|
|
18481
|
-
const componentLabelPluralized = componentsToUpload.length === 1 ? "component" : "components";
|
|
18482
18766
|
s2.stop(
|
|
18483
18767
|
chalk2.green(
|
|
18484
18768
|
`Processed Tailwind CSS classes from ${componentsToUpload.length} selected local ${componentLabelPluralized} and all online components`
|
|
@@ -18486,23 +18770,29 @@ function uploadCommand(program2) {
|
|
|
18486
18770
|
);
|
|
18487
18771
|
if (!tailwindResult.success && tailwindResult.details) {
|
|
18488
18772
|
reportResults([tailwindResult], "Built assets", "Asset");
|
|
18489
|
-
|
|
18773
|
+
p.note(
|
|
18490
18774
|
chalk2.red(`Tailwind build failed, global assets upload aborted.`)
|
|
18491
18775
|
);
|
|
18492
18776
|
} else {
|
|
18493
|
-
|
|
18494
|
-
|
|
18495
|
-
|
|
18496
|
-
|
|
18497
|
-
|
|
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
|
+
}
|
|
18498
18786
|
}
|
|
18499
18787
|
}
|
|
18500
|
-
|
|
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);
|
|
18501
18791
|
} catch (error) {
|
|
18502
18792
|
if (error instanceof Error) {
|
|
18503
|
-
|
|
18793
|
+
p.note(chalk2.red(`Error: ${error.message}`));
|
|
18504
18794
|
} else {
|
|
18505
|
-
|
|
18795
|
+
p.note(chalk2.red(`Unknown error: ${String(error)}`));
|
|
18506
18796
|
}
|
|
18507
18797
|
process.exit(1);
|
|
18508
18798
|
}
|
|
@@ -18513,11 +18803,11 @@ async function prepareComponentsForUpload(successfulBuilds, componentsToUpload)
|
|
|
18513
18803
|
const failed = [];
|
|
18514
18804
|
for (const buildResult of successfulBuilds) {
|
|
18515
18805
|
const dir = buildResult.itemName ? componentsToUpload.find(
|
|
18516
|
-
(d2) =>
|
|
18806
|
+
(d2) => path3.basename(d2) === buildResult.itemName
|
|
18517
18807
|
) : void 0;
|
|
18518
18808
|
if (!dir) continue;
|
|
18519
18809
|
try {
|
|
18520
|
-
const componentName =
|
|
18810
|
+
const componentName = path3.basename(dir);
|
|
18521
18811
|
const { sourceCodeJs, compiledJs, sourceCodeCss, compiledCss, metadata } = await processComponentFiles(dir);
|
|
18522
18812
|
if (!metadata) {
|
|
18523
18813
|
throw new Error("Invalid metadata file");
|
|
@@ -18534,7 +18824,7 @@ async function prepareComponentsForUpload(successfulBuilds, componentsToUpload)
|
|
|
18534
18824
|
importedJsComponents = getImportsFromAst(ast, scope);
|
|
18535
18825
|
dataDependencies = getDataDependenciesFromAst(ast);
|
|
18536
18826
|
} catch (error) {
|
|
18537
|
-
|
|
18827
|
+
p.note(chalk2.red(`Error: ${error}`));
|
|
18538
18828
|
}
|
|
18539
18829
|
const componentPayloadArg = {
|
|
18540
18830
|
metadata,
|
|
@@ -18570,32 +18860,35 @@ async function prepareComponentsForUpload(successfulBuilds, componentsToUpload)
|
|
|
18570
18860
|
}
|
|
18571
18861
|
return { prepared, failed };
|
|
18572
18862
|
}
|
|
18573
|
-
async function getBuildAndUploadResults(componentsToUpload, apiService) {
|
|
18863
|
+
async function getBuildAndUploadResults(componentsToUpload, apiService, includeGlobalCss) {
|
|
18574
18864
|
const results = [];
|
|
18575
|
-
const
|
|
18576
|
-
|
|
18577
|
-
const buildResults = await buildSelectedComponents(
|
|
18865
|
+
const spinner6 = p.spinner();
|
|
18866
|
+
spinner6.start("Building components");
|
|
18867
|
+
const buildResults = await buildSelectedComponents(
|
|
18868
|
+
componentsToUpload,
|
|
18869
|
+
includeGlobalCss
|
|
18870
|
+
);
|
|
18578
18871
|
const successfulBuilds = buildResults.filter((build) => build.success);
|
|
18579
18872
|
const failedBuilds = buildResults.filter((build) => !build.success);
|
|
18580
18873
|
if (successfulBuilds.length === 0) {
|
|
18581
18874
|
const message = "All component builds failed.";
|
|
18582
|
-
|
|
18875
|
+
spinner6.stop(chalk2.red(message));
|
|
18583
18876
|
return failedBuilds;
|
|
18584
18877
|
}
|
|
18585
|
-
|
|
18878
|
+
spinner6.message("Preparing components for upload");
|
|
18586
18879
|
const { prepared: preparedComponents, failed: preparationFailures } = await prepareComponentsForUpload(successfulBuilds, componentsToUpload);
|
|
18587
18880
|
results.push(...preparationFailures);
|
|
18588
18881
|
if (preparedComponents.length === 0) {
|
|
18589
|
-
|
|
18882
|
+
spinner6.stop(chalk2.red("All component preparations failed"));
|
|
18590
18883
|
return [...results, ...failedBuilds];
|
|
18591
18884
|
}
|
|
18592
18885
|
const machineNames = preparedComponents.map((c) => c.machineName);
|
|
18593
18886
|
const existenceProgress = createProgressCallback(
|
|
18594
|
-
|
|
18887
|
+
spinner6,
|
|
18595
18888
|
"Checking component existence",
|
|
18596
18889
|
machineNames.length
|
|
18597
18890
|
);
|
|
18598
|
-
|
|
18891
|
+
spinner6.message("Checking component existence");
|
|
18599
18892
|
const existenceResults = await checkComponentsExist(
|
|
18600
18893
|
machineNames,
|
|
18601
18894
|
apiService,
|
|
@@ -18607,11 +18900,11 @@ async function getBuildAndUploadResults(componentsToUpload, apiService) {
|
|
|
18607
18900
|
shouldUpdate: existenceResults[index]?.exists || false
|
|
18608
18901
|
}));
|
|
18609
18902
|
const uploadProgress = createProgressCallback(
|
|
18610
|
-
|
|
18903
|
+
spinner6,
|
|
18611
18904
|
"Uploading components",
|
|
18612
18905
|
uploadTasks.length
|
|
18613
18906
|
);
|
|
18614
|
-
|
|
18907
|
+
spinner6.message("Uploading components");
|
|
18615
18908
|
const uploadResults = await uploadComponents(
|
|
18616
18909
|
uploadTasks,
|
|
18617
18910
|
apiService,
|
|
@@ -18644,34 +18937,33 @@ async function getBuildAndUploadResults(componentsToUpload, apiService) {
|
|
|
18644
18937
|
}
|
|
18645
18938
|
results.push(...failedBuilds);
|
|
18646
18939
|
const componentLabelPluralized = results.length === 1 ? "component" : "components";
|
|
18647
|
-
|
|
18940
|
+
spinner6.stop(
|
|
18648
18941
|
chalk2.green(`Processed ${results.length} ${componentLabelPluralized}`)
|
|
18649
18942
|
);
|
|
18650
18943
|
return results;
|
|
18651
18944
|
}
|
|
18652
|
-
async function buildSelectedComponents(componentDirs) {
|
|
18945
|
+
async function buildSelectedComponents(componentDirs, useLocalGlobalCss = true) {
|
|
18653
18946
|
const buildResults = [];
|
|
18654
18947
|
for (const dir of componentDirs) {
|
|
18655
|
-
buildResults.push(await buildComponent(dir));
|
|
18948
|
+
buildResults.push(await buildComponent(dir, useLocalGlobalCss));
|
|
18656
18949
|
}
|
|
18657
18950
|
return buildResults;
|
|
18658
18951
|
}
|
|
18659
18952
|
async function uploadGlobalAssetLibrary(apiService, componentDir) {
|
|
18660
18953
|
try {
|
|
18661
|
-
const distDir =
|
|
18662
|
-
const globalCompiledCssPath =
|
|
18954
|
+
const distDir = path3.join(componentDir, "dist");
|
|
18955
|
+
const globalCompiledCssPath = path3.join(distDir, "index.css");
|
|
18663
18956
|
const globalCompiledCssExists = await fileExists(globalCompiledCssPath);
|
|
18664
18957
|
if (globalCompiledCssExists) {
|
|
18665
18958
|
const globalCompiledCss = await fs2.readFile(
|
|
18666
|
-
|
|
18959
|
+
path3.join(distDir, "index.css"),
|
|
18667
18960
|
"utf-8"
|
|
18668
18961
|
);
|
|
18669
18962
|
const classNameCandidateIndexFile = await fs2.readFile(
|
|
18670
|
-
|
|
18963
|
+
path3.join(distDir, "index.js"),
|
|
18671
18964
|
"utf-8"
|
|
18672
18965
|
);
|
|
18673
|
-
const
|
|
18674
|
-
const originalCss = current.css.original;
|
|
18966
|
+
const originalCss = await getGlobalCss();
|
|
18675
18967
|
await apiService.updateGlobalAssetLibrary({
|
|
18676
18968
|
css: {
|
|
18677
18969
|
original: originalCss,
|
|
@@ -18714,33 +19006,54 @@ function validateCommand(program2) {
|
|
|
18714
19006
|
program2.command("validate").description("validate local components").option(
|
|
18715
19007
|
"-d, --dir <directory>",
|
|
18716
19008
|
"Component directory to validate the components in"
|
|
18717
|
-
).option(
|
|
19009
|
+
).option(
|
|
19010
|
+
"-c, --components <names>",
|
|
19011
|
+
"Specific component(s) to validate (comma-separated)"
|
|
19012
|
+
).option("--all", "Validate all components").option("-y, --yes", "Skip confirmation prompts").option("--verbose", "Enable verbose output").option(
|
|
18718
19013
|
"--fix",
|
|
18719
19014
|
"Apply available automatic fixes for linting issues",
|
|
18720
19015
|
false
|
|
18721
19016
|
).action(async (options) => {
|
|
18722
|
-
|
|
18723
|
-
|
|
18724
|
-
|
|
18725
|
-
|
|
18726
|
-
|
|
18727
|
-
|
|
18728
|
-
|
|
18729
|
-
|
|
18730
|
-
|
|
18731
|
-
|
|
18732
|
-
|
|
18733
|
-
|
|
18734
|
-
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
|
|
18738
|
-
|
|
18739
|
-
|
|
18740
|
-
|
|
19017
|
+
try {
|
|
19018
|
+
p.intro(chalk2.bold("Drupal Canvas CLI: validate"));
|
|
19019
|
+
validateComponentOptions(options);
|
|
19020
|
+
const allFlag = options.all || options.yes && !options.components || false;
|
|
19021
|
+
updateConfigFromOptions(options);
|
|
19022
|
+
const { directories: componentsToValidate } = await selectLocalComponents({
|
|
19023
|
+
all: allFlag,
|
|
19024
|
+
components: options.components,
|
|
19025
|
+
skipConfirmation: options.yes,
|
|
19026
|
+
selectMessage: "Select components to validate"
|
|
19027
|
+
});
|
|
19028
|
+
const componentPluralized = pluralizeComponent(
|
|
19029
|
+
componentsToValidate.length
|
|
19030
|
+
);
|
|
19031
|
+
const s = p.spinner();
|
|
19032
|
+
s.start(`Validating ${componentPluralized}`);
|
|
19033
|
+
const results = [];
|
|
19034
|
+
for (const componentDir of componentsToValidate) {
|
|
19035
|
+
results.push(await validateComponent(componentDir, options.fix));
|
|
19036
|
+
}
|
|
19037
|
+
s.stop(
|
|
19038
|
+
chalk2.green(
|
|
19039
|
+
`Processed ${componentsToValidate.length} ${componentPluralized}`
|
|
19040
|
+
)
|
|
19041
|
+
);
|
|
19042
|
+
reportResults(results, "Validation results", "Component");
|
|
19043
|
+
const hasErrors = results.some((r) => !r.success);
|
|
19044
|
+
if (hasErrors) {
|
|
19045
|
+
p.outro(`\u274C Validation completed with errors`);
|
|
19046
|
+
process.exit(1);
|
|
19047
|
+
}
|
|
19048
|
+
p.outro(`\u2705 Validation completed`);
|
|
19049
|
+
} catch (error) {
|
|
19050
|
+
if (error instanceof Error) {
|
|
19051
|
+
p.note(chalk2.red(`Error: ${error.message}`));
|
|
19052
|
+
} else {
|
|
19053
|
+
p.note(chalk2.red(`Unknown error: ${String(error)}`));
|
|
19054
|
+
}
|
|
18741
19055
|
process.exit(1);
|
|
18742
19056
|
}
|
|
18743
|
-
p9.outro(`\u2705 Validation completed`);
|
|
18744
19057
|
});
|
|
18745
19058
|
}
|
|
18746
19059
|
|