@canva/cli 0.0.1-beta.21 → 0.0.1-beta.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canva/cli",
3
- "version": "0.0.1-beta.21",
3
+ "version": "0.0.1-beta.23",
4
4
  "description": "The official Canva CLI.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Canva Pty Ltd.",
@@ -25,7 +25,8 @@
25
25
  ],
26
26
  "dependencies": {
27
27
  "ink": "5.1.0",
28
- "react": "18.3.1"
28
+ "react": "18.3.1",
29
+ "@modelcontextprotocol/sdk": "1.8.0"
29
30
  },
30
31
  "keywords": [
31
32
  "apps sdk",
@@ -1,17 +1,4 @@
1
- import path from "node:path";
2
- import { fileURLToPath } from "node:url";
3
- import js from "@eslint/js";
4
- import { FlatCompat } from "@eslint/eslintrc";
5
- import general from "./conf/eslint_general.mjs";
6
- import i18n from "./conf/eslint_i18n.mjs";
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const compat = new FlatCompat({
11
- baseDirectory: __dirname,
12
- recommendedConfig: js.configs.recommended,
13
- allConfig: js.configs.all,
14
- });
1
+ import canvaPlugin from "@canva/app-eslint-plugin";
15
2
 
16
3
  export default [
17
4
  {
@@ -23,15 +10,5 @@ export default [
23
10
  "**/*.config.*",
24
11
  ],
25
12
  },
26
- ...compat.extends(
27
- "eslint:recommended",
28
- "plugin:@typescript-eslint/recommended",
29
- "plugin:@typescript-eslint/eslint-recommended",
30
- "plugin:@typescript-eslint/strict",
31
- "plugin:@typescript-eslint/stylistic",
32
- "plugin:react/recommended",
33
- "plugin:jest/recommended",
34
- ),
35
- ...general,
36
- ...i18n,
13
+ ...canvaPlugin.configs.apps,
37
14
  ];
@@ -7,7 +7,7 @@
7
7
  "author": "Canva Pty Ltd.",
8
8
  "dependencies": {
9
9
  "@canva/app-ui-kit": "^4.8.0",
10
- "@canva/asset": "^2.1.0",
10
+ "@canva/asset": "^2.2.0",
11
11
  "@canva/design": "^2.4.0",
12
12
  "@canva/error": "^2.1.0",
13
13
  "@canva/platform": "^2.1.0",
@@ -17,13 +17,12 @@ export async function generateHash(message: string) {
17
17
  }
18
18
 
19
19
  const imageUrls = [
20
- "https://cdn.pixabay.com/photo/2023/09/16/18/26/hummingbird-8257355_1280.jpg",
21
- "https://cdn.pixabay.com/photo/2023/12/10/03/00/peacock-8440548_1280.jpg",
22
- "https://cdn.pixabay.com/photo/2023/12/20/07/04/mountains-8459056_1280.jpg",
23
- "https://cdn.pixabay.com/photo/2023/11/26/07/29/sparrow-8413000_1280.jpg",
24
- "https://cdn.pixabay.com/photo/2023/12/12/16/11/mountain-8445543_1280.jpg",
20
+ "https://images.pexels.com/photos/1495580/pexels-photo-1495580.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
21
+ "https://images.pexels.com/photos/3943197/pexels-photo-3943197.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
22
+ "https://images.pexels.com/photos/7195267/pexels-photo-7195267.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
23
+ "https://images.pexels.com/photos/2904142/pexels-photo-2904142.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
24
+ "https://images.pexels.com/photos/5403478/pexels-photo-5403478.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
25
25
  ];
26
-
27
26
  export const createDamRouter = () => {
28
27
  const router = express.Router();
29
28
 
@@ -52,7 +51,7 @@ export const createDamRouter = () => {
52
51
  if (types.includes("IMAGE")) {
53
52
  resources = await Promise.all(
54
53
  Array.from({ length: 40 }, async (_, i) => ({
55
- id: await generateHash(imageUrls[i % imageUrls.length]),
54
+ id: await generateHash(i + ""),
56
55
  mimeType: "image/jpeg",
57
56
  name: `My new thing in ${locale}`, // Use the `locale` value from the request if your backend supports i18n
58
57
  type: "IMAGE",
@@ -1,17 +1,4 @@
1
- import path from "node:path";
2
- import { fileURLToPath } from "node:url";
3
- import js from "@eslint/js";
4
- import { FlatCompat } from "@eslint/eslintrc";
5
- import general from "./conf/eslint_general.mjs";
6
- // import i18n from "./conf/eslint_i18n.mjs";
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const compat = new FlatCompat({
11
- baseDirectory: __dirname,
12
- recommendedConfig: js.configs.recommended,
13
- allConfig: js.configs.all,
14
- });
1
+ import canvaPlugin from "@canva/app-eslint-plugin";
15
2
 
16
3
  export default [
17
4
  {
@@ -20,21 +7,9 @@ export default [
20
7
  "**/dist",
21
8
  "**/*.d.ts",
22
9
  "**/*.d.tsx",
23
- "**/sdk",
24
- "**/internal",
25
10
  "**/*.config.*",
26
11
  ],
27
12
  },
28
- ...compat.extends(
29
- "eslint:recommended",
30
- "plugin:@typescript-eslint/recommended",
31
- "plugin:@typescript-eslint/eslint-recommended",
32
- "plugin:@typescript-eslint/strict",
33
- "plugin:@typescript-eslint/stylistic",
34
- "plugin:react/recommended",
35
- "plugin:jest/recommended",
36
- ),
37
- ...general,
38
- // This template is not yet translated, enable these rules when it is
39
- // ...i18n,
13
+ // This template is not yet translated, switch to apps when it is
14
+ ...canvaPlugin.configs.apps_no_i18n,
40
15
  ];
@@ -18,10 +18,10 @@
18
18
  "postinstall": "ts-node ./scripts/copy_env.ts"
19
19
  },
20
20
  "dependencies": {
21
- "@canva/app-components": "^1.1.0",
21
+ "@canva/app-components": "^1.2.0",
22
22
  "@canva/app-i18n-kit": "^1.0.2",
23
23
  "@canva/app-ui-kit": "^4.8.0",
24
- "@canva/asset": "^2.1.0",
24
+ "@canva/asset": "^2.2.0",
25
25
  "@canva/design": "^2.4.0",
26
26
  "@canva/error": "^2.1.0",
27
27
  "@canva/platform": "^2.1.0",
@@ -34,8 +34,7 @@
34
34
  },
35
35
  "devDependencies": {
36
36
  "@canva/cli": ">= 0.0.1-beta.13 < 0.0.2",
37
- "@eslint/eslintrc": "3.2.0",
38
- "@eslint/js": "9.18.0",
37
+ "@canva/app-eslint-plugin": "^1.0.0-beta.3",
39
38
  "@formatjs/cli": "6.3.15",
40
39
  "@formatjs/ts-transformer": "3.13.27",
41
40
  "@ngrok/ngrok": "1.4.1",
@@ -56,8 +55,6 @@
56
55
  "@types/react": "18.3.12",
57
56
  "@types/react-dom": "18.3.1",
58
57
  "@types/webpack-env": "1.18.5",
59
- "@typescript-eslint/eslint-plugin": "8.20.0",
60
- "@typescript-eslint/parser": "8.20.0",
61
58
  "chalk": "4.1.2",
62
59
  "cli-table3": "0.6.5",
63
60
  "css-loader": "7.1.2",
@@ -65,11 +62,6 @@
65
62
  "cssnano": "7.0.6",
66
63
  "debug": "4.4.0",
67
64
  "dotenv": "16.4.7",
68
- "eslint": "9.18.0",
69
- "eslint-plugin-formatjs": "5.2.8",
70
- "eslint-plugin-jest": "28.11.0",
71
- "eslint-plugin-react": "7.37.4",
72
- "eslint-plugin-unicorn": "56.0.1",
73
65
  "exponential-backoff": "3.1.1",
74
66
  "express": "4.21.2",
75
67
  "express-basic-auth": "1.2.1",
@@ -22,48 +22,48 @@ const imageUrls: ImageResponse[] = [
22
22
  fullsize: {
23
23
  width: 1280,
24
24
  height: 853,
25
- url: "https://cdn.pixabay.com/photo/2023/02/03/05/11/youtube-background-7764170_1280.jpg",
25
+ url: "https://images.pexels.com/photos/1145720/pexels-photo-1145720.jpeg?auto=compress&cs=tinysrgb&w=1280&h=853&dpr=2",
26
26
  },
27
27
  thumbnail: {
28
28
  width: 640,
29
29
  height: 427,
30
- url: "https://cdn.pixabay.com/photo/2023/02/03/05/11/youtube-background-7764170_640.jpg",
30
+ url: "https://images.pexels.com/photos/1145720/pexels-photo-1145720.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
31
31
  },
32
32
  },
33
33
  {
34
34
  fullsize: {
35
35
  width: 1280,
36
36
  height: 853,
37
- url: "https://cdn.pixabay.com/photo/2023/02/03/05/12/youtube-background-7764172_1280.jpg",
37
+ url: "https://images.pexels.com/photos/4010108/pexels-photo-4010108.jpeg?auto=compress&cs=tinysrgb&w=1280&h=863&dpr=2",
38
38
  },
39
39
  thumbnail: {
40
40
  width: 640,
41
41
  height: 427,
42
- url: "https://cdn.pixabay.com/photo/2023/02/03/05/12/youtube-background-7764172_640.jpg",
42
+ url: "https://images.pexels.com/photos/4010108/pexels-photo-4010108.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
43
43
  },
44
44
  },
45
45
  {
46
46
  fullsize: {
47
47
  width: 1280,
48
48
  height: 853,
49
- url: "https://cdn.pixabay.com/photo/2023/02/03/05/07/colorful-7764162_1280.jpg",
49
+ url: "https://images.pexels.com/photos/1327496/pexels-photo-1327496.jpeg?auto=compress&cs=tinysrgb&w=1280&h=853&dpr=2",
50
50
  },
51
51
  thumbnail: {
52
52
  width: 640,
53
53
  height: 427,
54
- url: "https://cdn.pixabay.com/photo/2023/02/03/05/07/colorful-7764162_640.jpg",
54
+ url: "https://images.pexels.com/photos/1327496/pexels-photo-1327496.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
55
55
  },
56
56
  },
57
57
  {
58
58
  fullsize: {
59
59
  width: 1280,
60
60
  height: 853,
61
- url: "https://cdn.pixabay.com/photo/2023/02/03/04/57/swirls-7764142_1280.jpg",
61
+ url: "https://images.pexels.com/photos/4693135/pexels-photo-4693135.jpeg?auto=compress&cs=tinysrgb&w=1280&h=853&dpr=2",
62
62
  },
63
63
  thumbnail: {
64
64
  width: 640,
65
65
  height: 427,
66
- url: "https://cdn.pixabay.com/photo/2023/02/03/04/57/swirls-7764142_640.jpg",
66
+ url: "https://images.pexels.com/photos/4693135/pexels-photo-4693135.jpeg?auto=compress&cs=tinysrgb&w=640&h=427&dpr=2",
67
67
  },
68
68
  },
69
69
  ];
@@ -1,17 +1,4 @@
1
- import path from "node:path";
2
- import { fileURLToPath } from "node:url";
3
- import js from "@eslint/js";
4
- import { FlatCompat } from "@eslint/eslintrc";
5
- import general from "./conf/eslint_general.mjs";
6
- import i18n from "./conf/eslint_i18n.mjs";
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const compat = new FlatCompat({
11
- baseDirectory: __dirname,
12
- recommendedConfig: js.configs.recommended,
13
- allConfig: js.configs.all,
14
- });
1
+ import canvaPlugin from "@canva/app-eslint-plugin";
15
2
 
16
3
  export default [
17
4
  {
@@ -23,15 +10,5 @@ export default [
23
10
  "**/*.config.*",
24
11
  ],
25
12
  },
26
- ...compat.extends(
27
- "eslint:recommended",
28
- "plugin:@typescript-eslint/recommended",
29
- "plugin:@typescript-eslint/eslint-recommended",
30
- "plugin:@typescript-eslint/strict",
31
- "plugin:@typescript-eslint/stylistic",
32
- "plugin:react/recommended",
33
- "plugin:jest/recommended",
34
- ),
35
- ...general,
36
- ...i18n,
13
+ ...canvaPlugin.configs.apps,
37
14
  ];
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@canva/app-i18n-kit": "^1.0.2",
22
22
  "@canva/app-ui-kit": "^4.8.0",
23
- "@canva/asset": "^2.1.0",
23
+ "@canva/asset": "^2.2.0",
24
24
  "@canva/design": "^2.4.0",
25
25
  "@canva/error": "^2.1.0",
26
26
  "@canva/platform": "^2.1.0",
@@ -37,8 +37,7 @@
37
37
  },
38
38
  "devDependencies": {
39
39
  "@canva/cli": ">= 0.0.1-beta.13 < 0.0.2",
40
- "@eslint/eslintrc": "3.2.0",
41
- "@eslint/js": "9.18.0",
40
+ "@canva/app-eslint-plugin": "^1.0.0-beta.3",
42
41
  "@formatjs/cli": "6.3.15",
43
42
  "@formatjs/ts-transformer": "3.13.27",
44
43
  "@ngrok/ngrok": "1.4.1",
@@ -60,8 +59,6 @@
60
59
  "@types/webpack": "5.28.5",
61
60
  "@types/webpack-dev-server": "4.7.1",
62
61
  "@types/webpack-env": "1.18.5",
63
- "@typescript-eslint/eslint-plugin": "8.20.0",
64
- "@typescript-eslint/parser": "8.20.0",
65
62
  "chalk": "4.1.2",
66
63
  "cli-table3": "0.6.5",
67
64
  "css-loader": "7.1.2",
@@ -69,11 +66,6 @@
69
66
  "cssnano": "7.0.6",
70
67
  "debug": "4.4.0",
71
68
  "dotenv": "16.4.7",
72
- "eslint": "9.18.0",
73
- "eslint-plugin-formatjs": "5.2.8",
74
- "eslint-plugin-jest": "28.11.0",
75
- "eslint-plugin-react": "7.37.4",
76
- "eslint-plugin-unicorn": "56.0.1",
77
69
  "exponential-backoff": "3.1.1",
78
70
  "express": "4.21.2",
79
71
  "express-basic-auth": "1.2.1",
@@ -1,17 +1,4 @@
1
- import path from "node:path";
2
- import { fileURLToPath } from "node:url";
3
- import js from "@eslint/js";
4
- import { FlatCompat } from "@eslint/eslintrc";
5
- import general from "./conf/eslint_general.mjs";
6
- import i18n from "./conf/eslint_i18n.mjs";
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const compat = new FlatCompat({
11
- baseDirectory: __dirname,
12
- recommendedConfig: js.configs.recommended,
13
- allConfig: js.configs.all,
14
- });
1
+ import canvaPlugin from "@canva/app-eslint-plugin";
15
2
 
16
3
  export default [
17
4
  {
@@ -23,15 +10,5 @@ export default [
23
10
  "**/*.config.*",
24
11
  ],
25
12
  },
26
- ...compat.extends(
27
- "eslint:recommended",
28
- "plugin:@typescript-eslint/recommended",
29
- "plugin:@typescript-eslint/eslint-recommended",
30
- "plugin:@typescript-eslint/strict",
31
- "plugin:@typescript-eslint/stylistic",
32
- "plugin:react/recommended",
33
- "plugin:jest/recommended",
34
- ),
35
- ...general,
36
- ...i18n,
13
+ ...canvaPlugin.configs.apps,
37
14
  ];
@@ -21,7 +21,7 @@
21
21
  "dependencies": {
22
22
  "@canva/app-i18n-kit": "^1.0.2",
23
23
  "@canva/app-ui-kit": "^4.8.0",
24
- "@canva/asset": "^2.1.0",
24
+ "@canva/asset": "^2.2.0",
25
25
  "@canva/design": "^2.4.0",
26
26
  "@canva/error": "^2.1.0",
27
27
  "@canva/platform": "^2.1.0",
@@ -32,8 +32,7 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@canva/cli": ">= 0.0.1-beta.13 < 0.0.2",
35
- "@eslint/eslintrc": "3.2.0",
36
- "@eslint/js": "9.18.0",
35
+ "@canva/app-eslint-plugin": "^1.0.0-beta.3",
37
36
  "@formatjs/cli": "6.3.15",
38
37
  "@formatjs/ts-transformer": "3.13.27",
39
38
  "@ngrok/ngrok": "1.4.1",
@@ -51,8 +50,6 @@
51
50
  "@types/react": "18.3.12",
52
51
  "@types/react-dom": "18.3.1",
53
52
  "@types/webpack-env": "1.18.5",
54
- "@typescript-eslint/eslint-plugin": "8.20.0",
55
- "@typescript-eslint/parser": "8.20.0",
56
53
  "chalk": "4.1.2",
57
54
  "cli-table3": "0.6.5",
58
55
  "css-loader": "7.1.2",
@@ -60,11 +57,6 @@
60
57
  "cssnano": "7.0.6",
61
58
  "debug": "4.4.0",
62
59
  "dotenv": "16.4.7",
63
- "eslint": "9.18.0",
64
- "eslint-plugin-formatjs": "5.2.8",
65
- "eslint-plugin-jest": "28.11.0",
66
- "eslint-plugin-react": "7.37.4",
67
- "eslint-plugin-unicorn": "56.0.1",
68
60
  "express": "4.21.2",
69
61
  "express-basic-auth": "1.2.1",
70
62
  "jest": "29.7.0",
@@ -1,181 +0,0 @@
1
- /**
2
- * ESLint rule that identifies and flags untranslated user-facing strings in object properties.
3
- *
4
- * This rule helps maintain internationalization consistency by detecting untranslated
5
- * strings in specific object properties (default: 'label'). It suggests using
6
- * intl.formatMessage for proper translation.
7
- *
8
- * Note: The rule is currently implemented as a local rule, with plans to publish as
9
- * an npm package to make it available to the broader development community.
10
- *
11
- * @example
12
- * // ❌ Incorrect - Untranslated strings
13
- * const options = [
14
- * { value: "inbox", label: "Inbox" },
15
- * { value: "starred", label: "Starred messages" },
16
- * { value: "spam", label: "Spam folder" }
17
- * ];
18
- *
19
- * // ✅ Correct - Using intl.formatMessage with descriptions
20
- * const options = [
21
- * {
22
- * value: "inbox",
23
- * label: intl.formatMessage({
24
- * defaultMessage: "Inbox",
25
- * description: "Label for main message inbox folder option"
26
- * })
27
- * },
28
- * {
29
- * value: "starred",
30
- * label: intl.formatMessage({
31
- * defaultMessage: "Starred messages",
32
- * description: "Label for folder containing messages marked as important"
33
- * })
34
- * },
35
- * {
36
- * value: "spam",
37
- * label: intl.formatMessage({
38
- * defaultMessage: "Spam folder",
39
- * description: "Label for folder containing filtered spam messages"
40
- * })
41
- * }
42
- * ];
43
- *
44
- * @see https://www.canva.dev/docs/apps/localization/
45
- */
46
- export default {
47
- rules: {
48
- "enforce-object-property-translation": {
49
- meta: {
50
- type: "problem",
51
- docs: {
52
- description:
53
- "Enforce translation of specific properties using intl.formatMessage",
54
- category: "Possible Errors",
55
- recommended: true,
56
- },
57
- fixable: "code",
58
- schema: [
59
- {
60
- type: "object",
61
- properties: {
62
- properties: {
63
- type: "array",
64
- items: { type: "string" },
65
- default: ["label"],
66
- },
67
- intlObjectName: {
68
- type: "string",
69
- default: "intl",
70
- },
71
- },
72
- additionalProperties: false,
73
- },
74
- ],
75
- messages: {
76
- untranslatedProperty: `If "{{ originalMessage }}" is a user-facing string, you should translate it using "intl.formatMessage". See https://www.canva.dev/docs/apps/localization/.`,
77
- },
78
- },
79
- create(context) {
80
- const config = context.options[0] || {};
81
- const propertiesToCheck = config.properties || ["label"];
82
- const intlObjectName = config.intlObjectName || "intl";
83
-
84
- function getTemplateLiteralString(node) {
85
- const src = context.getSourceCode();
86
- return src.getText(node);
87
- }
88
-
89
- // Extract string content from different node types
90
- function extractStringContent(node) {
91
- if (!node) return [];
92
-
93
- switch (node.type) {
94
- // label: "Foo"
95
- case "Literal":
96
- return typeof node.value === "string"
97
- ? [{ node, value: node.value }]
98
- : [];
99
-
100
- // label: `Foo ${bar}`
101
- case "TemplateLiteral":
102
- return [{ node, value: getTemplateLiteralString(node) }];
103
- // label: foo || "Bar"
104
- case "LogicalExpression": {
105
- if (node.operator === "||") {
106
- return [
107
- ...extractStringContent(node.left),
108
- ...extractStringContent(node.right),
109
- ];
110
- }
111
- return [];
112
- }
113
- // label: "Foo" + "Bar" + "Baz"
114
- case "BinaryExpression":
115
- if (node.operator === "+") {
116
- return [
117
- ...extractStringContent(node.left),
118
- ...extractStringContent(node.right),
119
- ];
120
- }
121
- return [];
122
- // label: foo ? "Foo" : "Bar"
123
- case "ConditionalExpression":
124
- return [
125
- ...extractStringContent(node.consequent),
126
- ...extractStringContent(node.alternate),
127
- ];
128
-
129
- default:
130
- return [];
131
- }
132
- }
133
-
134
- function isTranslated(node) {
135
- return (
136
- node.parent.type === "CallExpression" &&
137
- node.parent.callee.type === "MemberExpression" &&
138
- node.parent.callee.object.name === intlObjectName &&
139
- node.parent.callee.property.name === "formatMessage"
140
- );
141
- }
142
-
143
- return {
144
- Property(node) {
145
- const keyName = node.key.name || node.key.value;
146
- if (propertiesToCheck.includes(keyName)) {
147
- const results = extractStringContent(node.value);
148
- if (!results) return;
149
- results.forEach((result) => {
150
- const { node: stringNode, value: stringValue } = result;
151
-
152
- if (!isTranslated(stringNode)) {
153
- context.report({
154
- node: stringNode,
155
- messageId: "untranslatedProperty",
156
- data: {
157
- property: keyName,
158
- originalMessage:
159
- stringValue.length > 40
160
- ? stringValue.split(" ").slice(0, 4).join(" ") + "..."
161
- : stringValue,
162
- intlObjectName,
163
- },
164
- fix(fixer) {
165
- const newText = `${intlObjectName}.formatMessage({
166
- defaultMessage: ${JSON.stringify(stringValue)},
167
- // TODO: Provide a meaningful description for translators
168
- description: ""
169
- })`;
170
- return fixer.replaceText(stringNode, newText);
171
- },
172
- });
173
- }
174
- });
175
- }
176
- },
177
- };
178
- },
179
- },
180
- },
181
- };