@rancher/create-extension 1.0.1 → 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": "1.0.1",
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.1.3"
29
+ "@rancher/components": "0.3.0-alpha.1"
26
30
  }
27
31
  }
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',
@@ -36,28 +33,21 @@ console.log('Creating Skeleton UI Package');
36
33
 
37
34
  const args = process.argv;
38
35
 
39
- if (args.length !== 3) {
40
- console.log('Expected single argument of package name');
41
- }
42
-
43
36
  const name = args[2];
44
37
  const folder = path.resolve('.');
45
38
  const pkgFolder = path.join(folder, 'pkg', name);
46
39
  let shellVersion = '';
47
40
 
48
- let addTypeFolders = false;
49
- let addWorkflowFolder = false;
41
+ let addTypeFolders = true;
50
42
 
51
43
  if ( args.length >= 3 ) {
52
44
  shellVersion = args[3];
53
45
 
54
46
  for ( let i = 3; i < args.length; i++ ) {
55
47
  switch (args[i]) {
48
+ case '--skip-templates':
56
49
  case '-t':
57
- addTypeFolders = true;
58
- break;
59
- case '-w':
60
- addWorkflowFolder = true;
50
+ addTypeFolders = false;
61
51
  break;
62
52
  default:
63
53
  break;
@@ -86,19 +76,8 @@ const pkg = JSON.parse(rawdata);
86
76
  pkg.name = name;
87
77
  pkg.description = `${ name } plugin`;
88
78
 
89
- Object.keys(targets).forEach((target) => {
90
- if (!pkg.scripts[target]) {
91
- pkg.scripts[target] = targets[target];
92
- console.log(` Adding script '${ target }' to package.json`);
93
- }
94
- });
95
-
96
79
  writePackageJson();
97
80
 
98
- // Add dependencies
99
- // pkg.dependencies['@rancher/shell'] = '^0.6.2';
100
- // pkg.dependencies['core-js'] = '3.18.3';
101
-
102
81
  function writePackageJson() {
103
82
  fs.writeFileSync(path.join(pkgFolder, 'package.json'), JSON.stringify(pkg, null, 2));
104
83
  }
@@ -115,31 +94,6 @@ if (addTypeFolders) {
115
94
  });
116
95
  }
117
96
 
118
- // Add workflow folder if needed
119
- if (addWorkflowFolder) {
120
- const workflowDir = path.join(folder, '.github/workflows');
121
-
122
- if (!fs.existsSync(workflowDir)) {
123
- fs.mkdirSync(workflowDir, { recursive: true });
124
- }
125
-
126
- const files = [
127
- 'build-extension-catalog.yml',
128
- 'build-extension-charts.yml'
129
- ];
130
-
131
- files.forEach((fileName) => {
132
- const file = path.join(workflowDir, fileName);
133
-
134
- if (!fs.existsSync(file)) {
135
- const src = path.join(__dirname, 'files/.github/workflows', fileName);
136
-
137
- console.log(` Adding file ${ fileName } to root workflows`);
138
- fs.copySync(src, file);
139
- }
140
- });
141
- }
142
-
143
97
  // Copy base files
144
98
  files.forEach((file) => {
145
99
  const src = path.join(__dirname, 'files', file);
@@ -151,13 +105,6 @@ files.forEach((file) => {
151
105
  }
152
106
  });
153
107
 
154
- // require("child_process").spawn('yarn', ['install'], {
155
- // cwd: process.cwd(),
156
- // stdio: "inherit"
157
- // });
158
-
159
- // Update tsconfig
160
-
161
108
  const topLevelRawdata = fs.readFileSync(path.join(folder, 'package.json'));
162
109
  const topLevelPkg = JSON.parse(topLevelRawdata);
163
110
  let updated = false;
@@ -202,3 +149,5 @@ function updateArray(data) {
202
149
 
203
150
  return updated;
204
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",
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/*