@rancher/create-extension 2.0.0 → 3.0.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.
@@ -0,0 +1,126 @@
1
+ /*
2
+ * Vue syntax specific utilities
3
+ */
4
+ const isSimpleIdentifier = (str) => /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(str.trim());
5
+ const isBracketedExpression = (str) => str.trim().startsWith('[') && str.trim().endsWith(']');
6
+ const isStringLiteral = (str) => /^['"].*['"]$/.test(str.trim());
7
+ // Extracts the key expression from a v-for directive.
8
+ const extractKeyExpression = (vForContent) => {
9
+ const vForMatch = vForContent.match(/^\s*\(([^,]+),\s*([^)]+)\)\s+in\s+(.*)$/);
10
+ let keyExpression = null;
11
+
12
+ if (vForMatch) {
13
+ // v-for="(item, key) in items"
14
+ keyExpression = vForMatch[2].trim();
15
+ } else {
16
+ const simpleVForMatch = vForContent.match(/^\s*([^\s]+)\s+in\s+(.*)$/);
17
+
18
+ if (simpleVForMatch) {
19
+ // v-for="item in items"
20
+ // Use 'item' as key if it's a simple identifier
21
+ keyExpression = isSimpleIdentifier(simpleVForMatch[1].trim()) ? simpleVForMatch[1].trim() : null;
22
+ }
23
+ }
24
+
25
+ return keyExpression;
26
+ };
27
+ // Adds the :key attribute to a tag if it doesn't already have one.
28
+ const addKeyAttribute = (tag, keyExpression) => {
29
+ // Add space if necessary
30
+ const space = tag.endsWith(' ') ? '' : ' ';
31
+
32
+ return `${ tag }${ space }:key="${ keyExpression }"`;
33
+ };
34
+ const vueSetReplacement = (match, obj, prop, val) => {
35
+ prop = prop.trim();
36
+ obj = obj.trim();
37
+ val = val.trim();
38
+
39
+ if (isBracketedExpression(prop)) {
40
+ return `${ obj }${ prop } = ${ val }`;
41
+ } else if (isStringLiteral(prop)) {
42
+ return `${ obj }[${ prop }] = ${ val }`;
43
+ } else if (isSimpleIdentifier(prop)) {
44
+ return `${ obj }.${ prop } = ${ val }`;
45
+ } else {
46
+ return `${ obj }[${ prop }] = ${ val }`;
47
+ }
48
+ };
49
+ const vueDeleteReplacement = (match, obj, prop) => {
50
+ prop = prop.trim();
51
+ obj = obj.trim();
52
+
53
+ if (isBracketedExpression(prop)) {
54
+ return `delete ${ obj }${ prop }`;
55
+ } else if (isStringLiteral(prop)) {
56
+ return `delete ${ obj }[${ prop }]`;
57
+ } else if (isSimpleIdentifier(prop)) {
58
+ return `delete ${ obj }.${ prop }`;
59
+ } else {
60
+ return `delete ${ obj }[${ prop }]`;
61
+ }
62
+ };
63
+ const vueKeyReplacement = (match, beforeTagEnd, vForContent, tagClose) => {
64
+ // Check if :key exists in the tag
65
+ if (beforeTagEnd.includes(':key=')) {
66
+ return match; // :key already exists, do not modify
67
+ }
68
+
69
+ const keyExpression = extractKeyExpression(vForContent);
70
+
71
+ if (keyExpression) {
72
+ const updatedTag = addKeyAttribute(beforeTagEnd, keyExpression);
73
+
74
+ return `${ updatedTag }${ tagClose }`;
75
+ } else {
76
+ // Cannot safely determine a key, so do not add one
77
+ return match;
78
+ }
79
+ };
80
+ const vueTemplateKeyReplacement = (match, templateStart, templateContent, templateEnd) => {
81
+ // Check if :key is on the <template> tag
82
+ const hasKeyOnTemplate = /:key=/.test(templateStart);
83
+
84
+ // Find any :key on direct child elements
85
+ const childWithKeyRegex = /(<\w+[^>]*)(\s+:key="([^"]+)")([^>]*>)/g;
86
+ let updatedContent = templateContent;
87
+ let movedKey = null;
88
+
89
+ updatedContent = updatedContent.replace(childWithKeyRegex, (childMatch, beforeKey, keyAttr, keyValue, afterKey) => {
90
+ if (!hasKeyOnTemplate && !movedKey) {
91
+ // Move the first encountered :key to the template
92
+ movedKey = keyValue;
93
+ }
94
+
95
+ // Remove :key from child element
96
+ return `${ beforeKey }${ afterKey }`;
97
+ });
98
+
99
+ if (!hasKeyOnTemplate && movedKey) {
100
+ // Add :key to the <template> tag
101
+ const updatedTemplateStart = `${ addKeyAttribute(templateStart.replace(/>$/, ''), movedKey) }>`;
102
+
103
+ return `${ updatedTemplateStart }${ updatedContent }${ templateEnd }`;
104
+ }
105
+
106
+ return `${ templateStart }${ updatedContent }${ templateEnd }`;
107
+ };
108
+ const vueTemplateKeyRemoval = (match, templateStart, templateContent, templateEnd) => {
109
+ const childWithKeyRegex = /(<\w+[^>]*)(\s+:key="[^"]+")([^>]*>)/g;
110
+ const updatedContent = templateContent.replace(childWithKeyRegex, '$1$3');
111
+
112
+ return `${ templateStart }${ updatedContent }${ templateEnd }`;
113
+ };
114
+
115
+ module.exports = {
116
+ isSimpleIdentifier,
117
+ isBracketedExpression,
118
+ isStringLiteral,
119
+ extractKeyExpression,
120
+ addKeyAttribute,
121
+ vueSetReplacement,
122
+ vueDeleteReplacement,
123
+ vueKeyReplacement,
124
+ vueTemplateKeyReplacement,
125
+ vueTemplateKeyRemoval
126
+ };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@rancher/create-extension",
3
3
  "description": "Rancher UI Extension generator",
4
- "version": "2.0.0",
4
+ "version": "3.0.0",
5
5
  "license": "Apache-2.0",
6
6
  "author": "SUSE",
7
- "packageManager": "yarn@4.4.1",
7
+ "packageManager": "yarn@4.5.0",
8
8
  "bin": {
9
9
  "create-extension": "./init"
10
10
  },
@@ -13,15 +13,19 @@
13
13
  "init"
14
14
  ],
15
15
  "engines": {
16
- "node": ">=16"
16
+ "node": ">=20"
17
17
  },
18
18
  "dependencies": {
19
- "fs-extra": "^10.0.0"
19
+ "diff": "^7.0.0",
20
+ "fs-extra": "^10.0.0",
21
+ "glob": "^11.0.0",
22
+ "path": "^0.12.7",
23
+ "semver": "^7.6.3"
20
24
  },
21
25
  "_pkgs": {
22
- "core-js": "3.21.1",
26
+ "core-js": "3.25.3",
23
27
  "css-loader": "6.7.3",
24
28
  "@types/lodash": "4.14.184",
25
- "@rancher/components": "0.2.1-alpha.0"
29
+ "@rancher/components": "0.3.0-alpha.1"
26
30
  }
27
31
  }
@@ -10,13 +10,13 @@
10
10
  "skipLibCheck": true,
11
11
  "esModuleInterop": true,
12
12
  "allowSyntheticDefaultImports": true,
13
- "sourceMap": false,
13
+ "sourceMap": true,
14
14
  "baseUrl": ".",
15
15
  "preserveSymlinks": true,
16
16
  "typeRoots": [
17
17
  "../../node_modules",
18
18
  "../../node_modules/@rancher/shell/types"
19
- ],
19
+ ],
20
20
  "types": [
21
21
  "node",
22
22
  "webpack-env",
@@ -50,4 +50,4 @@
50
50
  "exclude": [
51
51
  "../../node_modules"
52
52
  ]
53
- }
53
+ }
package/pkg/init CHANGED
@@ -1,14 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ /* eslint-disable no-console */
2
3
 
4
+ const { execSync } = require('child_process');
3
5
  const fs = require('fs-extra');
4
6
  const path = require('path');
5
7
  const https = require('https');
6
8
 
7
- const targets = {
8
- dev: './node_modules/.bin/nuxt dev',
9
- nuxt: './node_modules/.bin/nuxt',
10
- };
11
-
12
9
  const files = [
13
10
  'tsconfig.json',
14
11
  'vue.config.js',
@@ -31,39 +28,26 @@ const typeFolders = [
31
28
  'detail'
32
29
  ];
33
30
 
34
- const shellPkgPath = 'node_modules/@rancher/shell';
35
-
36
31
  console.log('');
37
32
  console.log('Creating Skeleton UI Package');
38
33
 
39
34
  const args = process.argv;
40
35
 
41
- if (args.length !== 3) {
42
- console.log('Expected single argument of package name');
43
- }
44
-
45
36
  const name = args[2];
46
37
  const folder = path.resolve('.');
47
38
  const pkgFolder = path.join(folder, 'pkg', name);
48
39
  let shellVersion = '';
49
40
 
50
- let addTypeFolders = false;
51
- let addWorkflowFolder = false;
52
- let ignoreShellPkgPathCheck = false;
41
+ let addTypeFolders = true;
53
42
 
54
43
  if ( args.length >= 3 ) {
55
44
  shellVersion = args[3];
56
45
 
57
46
  for ( let i = 3; i < args.length; i++ ) {
58
47
  switch (args[i]) {
48
+ case '--skip-templates':
59
49
  case '-t':
60
- addTypeFolders = true;
61
- break;
62
- case '-w':
63
- addWorkflowFolder = true;
64
- break;
65
- case '-i':
66
- ignoreShellPkgPathCheck = true;
50
+ addTypeFolders = false;
67
51
  break;
68
52
  default:
69
53
  break;
@@ -71,12 +55,6 @@ if ( args.length >= 3 ) {
71
55
  }
72
56
  }
73
57
 
74
- if (!ignoreShellPkgPathCheck && !fs.existsSync(path.join(pkgFolder, `../../${ shellPkgPath }/package.json`))) {
75
- console.log('');
76
- console.log('@rancher/shell not found in node_modules! Please do "yarn install" and make sure you run this command from the base folder of your app');
77
- process.exit(1);
78
- }
79
-
80
58
  const isNodeModulesShell = !fs.existsSync(path.join(folder, 'shell'));
81
59
 
82
60
  if (!isNodeModulesShell) {
@@ -98,19 +76,8 @@ const pkg = JSON.parse(rawdata);
98
76
  pkg.name = name;
99
77
  pkg.description = `${ name } plugin`;
100
78
 
101
- Object.keys(targets).forEach((target) => {
102
- if (!pkg.scripts[target]) {
103
- pkg.scripts[target] = targets[target];
104
- console.log(` Adding script '${ target }' to package.json`);
105
- }
106
- });
107
-
108
79
  writePackageJson();
109
80
 
110
- // Add dependencies
111
- // pkg.dependencies['@rancher/shell'] = '^0.6.2';
112
- // pkg.dependencies['core-js'] = '3.18.3';
113
-
114
81
  function writePackageJson() {
115
82
  fs.writeFileSync(path.join(pkgFolder, 'package.json'), JSON.stringify(pkg, null, 2));
116
83
  }
@@ -127,31 +94,6 @@ if (addTypeFolders) {
127
94
  });
128
95
  }
129
96
 
130
- // Add workflow folder if needed
131
- if (addWorkflowFolder) {
132
- const workflowDir = path.join(folder, '.github/workflows');
133
-
134
- if (!fs.existsSync(workflowDir)) {
135
- fs.mkdirSync(workflowDir, { recursive: true });
136
- }
137
-
138
- const files = [
139
- 'build-extension-catalog.yml',
140
- 'build-extension-charts.yml'
141
- ];
142
-
143
- files.forEach((fileName) => {
144
- const file = path.join(workflowDir, fileName);
145
-
146
- if (!fs.existsSync(file)) {
147
- const src = path.join(__dirname, 'files/.github/workflows', fileName);
148
-
149
- console.log(` Adding file ${ fileName } to root workflows`);
150
- fs.copySync(src, file);
151
- }
152
- });
153
- }
154
-
155
97
  // Copy base files
156
98
  files.forEach((file) => {
157
99
  const src = path.join(__dirname, 'files', file);
@@ -163,13 +105,6 @@ files.forEach((file) => {
163
105
  }
164
106
  });
165
107
 
166
- // require("child_process").spawn('yarn', ['install'], {
167
- // cwd: process.cwd(),
168
- // stdio: "inherit"
169
- // });
170
-
171
- // Update tsconfig
172
-
173
108
  const topLevelRawdata = fs.readFileSync(path.join(folder, 'package.json'));
174
109
  const topLevelPkg = JSON.parse(topLevelRawdata);
175
110
  let updated = false;
@@ -214,3 +149,5 @@ function updateArray(data) {
214
149
 
215
150
  return updated;
216
151
  }
152
+
153
+ /* eslint-enable no-console */
package/pkg/package.json CHANGED
@@ -12,12 +12,12 @@
12
12
  ],
13
13
  "rancher": {
14
14
  "annotations": {
15
- "catalog.cattle.io/rancher-version": ">= 2.9.0 < 2.10.0",
16
- "catalog.cattle.io/ui-extensions-version": "< 3.0.0"
15
+ "catalog.cattle.io/rancher-version": ">= 2.10.0",
16
+ "catalog.cattle.io/ui-extensions-version": ">= 3.0.0"
17
17
  }
18
18
  },
19
19
  "engines": {
20
- "node": ">=16.0.0"
20
+ "node": ">=20.0.0"
21
21
  },
22
22
  "resolutions": {
23
23
  "d3-color": "3.1.0",
package/update/init CHANGED
@@ -4,17 +4,18 @@ const path = require('path');
4
4
  const fs = require('fs-extra');
5
5
  const { spawnSync } = require('child_process');
6
6
 
7
- const scriptFolder = __dirname;
7
+ const scriptFolder = path.resolve(__dirname, '..');
8
8
  const dest = path.resolve('.');
9
9
 
10
10
  // Remove first two args
11
- let args = process.argv;
11
+ const args = process.argv;
12
+
12
13
  args.splice(0, 2);
13
14
 
14
- const res = spawnSync(`${__dirname}/upgrade`, args, {
15
- cwd: dest,
15
+ const res = spawnSync(path.join(__dirname, 'upgrade'), args, {
16
+ cwd: dest,
16
17
  shell: false,
17
- stdio: [ 'ignore', process.stdout, process.stderr ],
18
+ stdio: ['ignore', process.stdout, process.stderr],
18
19
  });
19
20
 
20
21
  if (res.status !== 0) {
@@ -34,9 +35,13 @@ rawdata = fs.readFileSync(path.join(scriptFolder, 'package.json'));
34
35
  const upgradePackage = JSON.parse(rawdata);
35
36
 
36
37
  // Update dependency versions to match the latest from the creator
37
- Object.keys(latestPackage._pkgs).forEach((key) => {
38
- appPackage.dependencies[key] = latestPackage._pkgs[key];
39
- });
38
+ if ( latestPackage.dependencies ) {
39
+ Object.keys(latestPackage.dependencies).forEach((key) => {
40
+ appPackage.dependencies[key] = latestPackage.dependencies[key];
41
+ });
42
+ } else {
43
+ console.warn('No dependencies found in latestPackage.'); // eslint-disable-line no-console
44
+ }
40
45
 
41
46
  // Add in the webpack resolution
42
47
  appPackage.resolutions = appPackage.resolutions || {};
@@ -47,10 +52,10 @@ const shellVersion = upgradePackage.version;
47
52
 
48
53
  appPackage.dependencies['@rancher/shell'] = shellVersion;
49
54
 
50
- fs.writeFileSync(path.join(dest, 'package.json'), JSON.stringify(appPackage, null, 2) + '\n');
55
+ fs.writeFileSync(path.join(dest, 'package.json'), `${ JSON.stringify(appPackage, null, 2) }\n`);
51
56
 
52
57
  spawnSync(`yarn`, ['install'], {
53
- cwd: dest,
58
+ cwd: dest,
54
59
  shell: false,
55
- stdio: [ 'ignore', process.stdout, process.stderr ],
60
+ stdio: ['ignore', process.stdout, process.stderr],
56
61
  });
@@ -12,7 +12,7 @@
12
12
  "upgrade"
13
13
  ],
14
14
  "engines": {
15
- "node": ">=16.0.0"
15
+ "node": ">=20.0.0"
16
16
  },
17
17
  "dependencies": {
18
18
  "fs-extra": "^10.0.0"
package/update/upgrade CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env sh
2
2
 
3
- SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
3
+ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"/.. &> /dev/null && pwd )
4
4
 
5
5
  echo "Upgrading Rancher Shell"
6
6
 
@@ -19,13 +19,13 @@ fi
19
19
  # Check for a clean git repository
20
20
  if [ ! -d ".git" ] && [ "${FORCE}" == "false" ]; then
21
21
  echo "Not runnning in a git repository. Re-run with -f to ignore this check"
22
- echo "Note: This action will update yuor files - running in a git repsository will ensure you have visibility over changes made"
22
+ echo "Note: This action will update your files - running in a git repository will ensure you have visibility over changes made"
23
23
  exit 1
24
24
  fi
25
25
 
26
26
  if [[ $(git diff --stat) != '' ]] && [ "${FORCE}" == "false" ]; then
27
27
  echo "Git repository is not clean. Re-run with -f to ignore this check"
28
- echo "Note: This action will update yuor files - running in a clean git repsository will ensure you have visibility over changes made"
28
+ echo "Note: This action will update your files - running in a clean git repository will ensure you have visibility over changes made"
29
29
  exit 1
30
30
  fi
31
31
 
@@ -42,7 +42,7 @@ if [ "${HAS_SHELL}" != "1" ]; then
42
42
  fi
43
43
 
44
44
  # Copy files for the top-level folder (from the app creator)
45
- rsync --exclude nuxt.config.js ${SCRIPT_DIR}/app/files/* .
45
+ rsync ${SCRIPT_DIR}/app/files/* .
46
46
 
47
47
  # Go through each folder in the pkg folder and update their files
48
48
  for pkg in ./pkg/*