@rancher/create-extension 0.2.1-rc.1 → 1.0.0-rc.2

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": "0.2.1-rc.1",
4
+ "version": "1.0.0-rc.2",
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,13 +76,6 @@ 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
  // Add annotation for the latest Rancher version by default
109
80
  function fetchLatestVersion() {
110
81
  console.log(' Fetching latest Rancher Version');
@@ -169,10 +140,6 @@ function fetchLatestVersion() {
169
140
  fetchLatestVersion();
170
141
  writePackageJson();
171
142
 
172
- // Add dependencies
173
- // pkg.dependencies['@rancher/shell'] = '^0.6.2';
174
- // pkg.dependencies['core-js'] = '3.18.3';
175
-
176
143
  function writePackageJson() {
177
144
  fs.writeFileSync(path.join(pkgFolder, 'package.json'), JSON.stringify(pkg, null, 2));
178
145
  }
@@ -189,31 +156,6 @@ if (addTypeFolders) {
189
156
  });
190
157
  }
191
158
 
192
- // Add workflow folder if needed
193
- if (addWorkflowFolder) {
194
- const workflowDir = path.join(folder, '.github/workflows');
195
-
196
- if (!fs.existsSync(workflowDir)) {
197
- fs.mkdirSync(workflowDir, { recursive: true });
198
- }
199
-
200
- const files = [
201
- 'build-extension-catalog.yml',
202
- 'build-extension-charts.yml'
203
- ];
204
-
205
- files.forEach((fileName) => {
206
- const file = path.join(workflowDir, fileName);
207
-
208
- if (!fs.existsSync(file)) {
209
- const src = path.join(__dirname, 'files/.github/workflows', fileName);
210
-
211
- console.log(` Adding file ${ fileName } to root workflows`);
212
- fs.copySync(src, file);
213
- }
214
- });
215
- }
216
-
217
159
  // Copy base files
218
160
  files.forEach((file) => {
219
161
  const src = path.join(__dirname, 'files', file);
@@ -225,13 +167,6 @@ files.forEach((file) => {
225
167
  }
226
168
  });
227
169
 
228
- // require("child_process").spawn('yarn', ['install'], {
229
- // cwd: process.cwd(),
230
- // stdio: "inherit"
231
- // });
232
-
233
- // Update tsconfig
234
-
235
170
  const topLevelRawdata = fs.readFileSync(path.join(folder, 'package.json'));
236
171
  const topLevelPkg = JSON.parse(topLevelRawdata);
237
172
  let updated = false;
@@ -276,3 +211,5 @@ function updateArray(data) {
276
211
 
277
212
  return updated;
278
213
  }
214
+
215
+ /* eslint-enable no-console */
package/pkg/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "init"
12
12
  ],
13
13
  "engines": {
14
- "node": ">=16.0.0"
14
+ "node": ">=20.0.0"
15
15
  },
16
16
  "resolutions": {
17
17
  "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/*