@contentful/app-scripts 1.33.0 → 1.33.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.
- package/lib/bin.js +3 -4
- package/lib/generate-function/build-generate-function-settings.d.ts +4 -3
- package/lib/generate-function/build-generate-function-settings.js +57 -103
- package/lib/generate-function/clone.js +4 -8
- package/lib/generate-function/constants.js +1 -1
- package/lib/generate-function/index.d.ts +2 -2
- package/lib/generate-function/index.js +25 -4
- package/lib/generate-function/types.d.ts +3 -0
- package/lib/generate-function/types.js +8 -1
- package/lib/types.d.ts +1 -13
- package/package.json +3 -3
package/lib/bin.js
CHANGED
|
@@ -86,10 +86,9 @@ async function runCommand(command, options) {
|
|
|
86
86
|
commander_1.program
|
|
87
87
|
.command('generate-function')
|
|
88
88
|
.description('Generate a new Contentful Function')
|
|
89
|
-
.option('--name <name>', 'Name of the function')
|
|
90
|
-
.option('--
|
|
91
|
-
.option('--
|
|
92
|
-
.option('--language <language>', 'Select a language for the function')
|
|
89
|
+
.option('-n, --name <name>', 'Name of the function')
|
|
90
|
+
.option('-e, --example <example>', 'Name of the reference example')
|
|
91
|
+
.option('-l, --language <language>', 'Select a language for the function')
|
|
93
92
|
.action(async (options) => {
|
|
94
93
|
await runCommand(index_1.generateFunction, options);
|
|
95
94
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { GenerateFunctionSettings
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function
|
|
1
|
+
import { GenerateFunctionSettings } from '../types';
|
|
2
|
+
export declare function buildGenerateFunctionSettingsInteractive(): Promise<GenerateFunctionSettings>;
|
|
3
|
+
export declare function validateArguments(options: GenerateFunctionSettings): void;
|
|
4
|
+
export declare function buildGenerateFunctionSettingsCLI(options: GenerateFunctionSettings): Promise<GenerateFunctionSettings>;
|
|
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
6
|
+
exports.buildGenerateFunctionSettingsInteractive = buildGenerateFunctionSettingsInteractive;
|
|
7
|
+
exports.validateArguments = validateArguments;
|
|
8
|
+
exports.buildGenerateFunctionSettingsCLI = buildGenerateFunctionSettingsCLI;
|
|
8
9
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
10
|
const path_1 = __importDefault(require("path"));
|
|
10
11
|
const get_github_folder_names_1 = require("./get-github-folder-names");
|
|
@@ -12,140 +13,93 @@ const constants_1 = require("./constants");
|
|
|
12
13
|
const ora_1 = __importDefault(require("ora"));
|
|
13
14
|
const chalk_1 = __importDefault(require("chalk"));
|
|
14
15
|
const logger_1 = require("./logger");
|
|
15
|
-
|
|
16
|
+
const types_1 = require("./types");
|
|
17
|
+
async function buildGenerateFunctionSettingsInteractive() {
|
|
16
18
|
const baseSettings = await inquirer_1.default.prompt([
|
|
17
19
|
{
|
|
18
20
|
name: 'name',
|
|
19
21
|
message: `Function name (${path_1.default.basename(process.cwd())}):`,
|
|
20
22
|
},
|
|
23
|
+
]);
|
|
24
|
+
validateFunctionName(baseSettings);
|
|
25
|
+
const filteredSources = await (0, get_github_folder_names_1.getGithubFolderNames)();
|
|
26
|
+
const sourceSpecificSettings = await inquirer_1.default.prompt([
|
|
27
|
+
{
|
|
28
|
+
name: 'example',
|
|
29
|
+
message: 'Select an example:',
|
|
30
|
+
type: 'list',
|
|
31
|
+
choices: filteredSources,
|
|
32
|
+
},
|
|
21
33
|
{
|
|
22
|
-
name: '
|
|
23
|
-
message: '
|
|
34
|
+
name: 'language',
|
|
35
|
+
message: 'Select a language',
|
|
24
36
|
type: 'list',
|
|
25
37
|
choices: [
|
|
26
|
-
{ name: '
|
|
27
|
-
{ name: '
|
|
38
|
+
{ name: 'TypeScript', value: 'typescript' },
|
|
39
|
+
{ name: 'JavaScript', value: 'javascript' },
|
|
28
40
|
],
|
|
29
|
-
default: '
|
|
41
|
+
default: 'typescript',
|
|
30
42
|
}
|
|
31
43
|
]);
|
|
44
|
+
baseSettings.example = sourceSpecificSettings.example;
|
|
45
|
+
baseSettings.language = sourceSpecificSettings.language;
|
|
46
|
+
return baseSettings;
|
|
47
|
+
}
|
|
48
|
+
function validateFunctionName(baseSettings) {
|
|
32
49
|
if (constants_1.BANNED_FUNCTION_NAMES.includes(baseSettings.name)) {
|
|
33
|
-
throw new
|
|
34
|
-
}
|
|
35
|
-
let sourceSpecificSettings;
|
|
36
|
-
if (baseSettings.sourceType === 'template') {
|
|
37
|
-
sourceSpecificSettings = await inquirer_1.default.prompt([
|
|
38
|
-
{
|
|
39
|
-
name: 'language',
|
|
40
|
-
message: 'Pick a template',
|
|
41
|
-
type: 'list',
|
|
42
|
-
choices: [
|
|
43
|
-
{ name: 'TypeScript', value: 'typescript' },
|
|
44
|
-
{ name: 'JavaScript', value: 'javascript' },
|
|
45
|
-
],
|
|
46
|
-
default: 'typescript',
|
|
47
|
-
}
|
|
48
|
-
]);
|
|
49
|
-
sourceSpecificSettings.sourceName = sourceSpecificSettings.language.toLowerCase();
|
|
50
|
+
throw new types_1.ValidationError(chalk_1.default.red(`Invalid function name: ${baseSettings.name} is not allowed.`));
|
|
50
51
|
}
|
|
51
|
-
else {
|
|
52
|
-
|
|
53
|
-
const filteredExamples = availableExamples.filter((template) => constants_1.ACCEPTED_EXAMPLE_FOLDERS.includes(template));
|
|
54
|
-
sourceSpecificSettings = await inquirer_1.default.prompt([
|
|
55
|
-
{
|
|
56
|
-
name: 'sourceName',
|
|
57
|
-
message: 'Select an example:',
|
|
58
|
-
type: 'list',
|
|
59
|
-
choices: filteredExamples,
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: 'language',
|
|
63
|
-
message: 'Pick a template',
|
|
64
|
-
type: 'list',
|
|
65
|
-
choices: [
|
|
66
|
-
{ name: 'TypeScript', value: 'typescript' },
|
|
67
|
-
{ name: 'JavaScript', value: 'javascript' },
|
|
68
|
-
],
|
|
69
|
-
default: 'typescript',
|
|
70
|
-
}
|
|
71
|
-
]);
|
|
52
|
+
else if (!(/^[a-z0-9]+$/i.test(baseSettings.name))) {
|
|
53
|
+
throw new types_1.ValidationError(chalk_1.default.red(`Invalid function name: ${baseSettings.name}. Note that function names must be alphanumeric.`));
|
|
72
54
|
}
|
|
73
|
-
baseSettings.sourceName = sourceSpecificSettings.sourceName;
|
|
74
|
-
baseSettings.language = sourceSpecificSettings.language;
|
|
75
|
-
return baseSettings;
|
|
76
55
|
}
|
|
77
56
|
function validateArguments(options) {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
throw new Error(`Invalid function name: ${options.name}`);
|
|
57
|
+
const requiredParams = ['name', 'example', 'language'];
|
|
58
|
+
if (!requiredParams.every((key) => key in options)) {
|
|
59
|
+
throw new types_1.ValidationError(chalk_1.default.red('You must specify a function name, an example, and a language'));
|
|
82
60
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
61
|
+
validateFunctionName(options);
|
|
62
|
+
// Check if the language is valid
|
|
63
|
+
if (!constants_1.ACCEPTED_LANGUAGES.includes(options.language)) {
|
|
64
|
+
(0, logger_1.warn)(`Invalid language: ${options.language}. Defaulting to TypeScript.`);
|
|
65
|
+
options.language = 'typescript';
|
|
87
66
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
67
|
+
// Convert options to lowercase and trim whitespace
|
|
68
|
+
for (const key in options) {
|
|
69
|
+
const optionKey = key;
|
|
70
|
+
const value = options[optionKey].toLowerCase().trim();
|
|
71
|
+
if (optionKey === 'language') {
|
|
72
|
+
options[optionKey] = value;
|
|
73
|
+
}
|
|
74
|
+
else if (optionKey === 'example') {
|
|
75
|
+
options[optionKey] = value;
|
|
76
|
+
}
|
|
77
|
+
else { // don't want to lowercase function names
|
|
78
|
+
options[optionKey] = options[optionKey].trim();
|
|
91
79
|
}
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
throw new Error('You must specify either --template or --example');
|
|
95
80
|
}
|
|
96
81
|
}
|
|
97
|
-
async function
|
|
82
|
+
async function buildGenerateFunctionSettingsCLI(options) {
|
|
98
83
|
const validateSpinner = (0, ora_1.default)('Validating your input\n').start();
|
|
99
84
|
const settings = {};
|
|
100
85
|
try {
|
|
101
86
|
validateArguments(options);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if ('example' in options) {
|
|
107
|
-
if ('template' in options) {
|
|
108
|
-
throw new Error('Cannot specify both --template and --example');
|
|
109
|
-
}
|
|
110
|
-
if (!constants_1.ACCEPTED_EXAMPLE_FOLDERS.includes(options.example)) {
|
|
111
|
-
throw new Error(`Invalid example name: ${options.example}`);
|
|
112
|
-
}
|
|
113
|
-
if (!constants_1.ACCEPTED_LANGUAGES.includes(options.language)) {
|
|
114
|
-
(0, logger_1.warn)(`Invalid language: ${options.language}. Defaulting to TypeScript.`);
|
|
115
|
-
settings.language = 'typescript';
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
settings.language = options.language;
|
|
119
|
-
}
|
|
120
|
-
settings.sourceType = 'example';
|
|
121
|
-
settings.sourceName = options.example;
|
|
122
|
-
settings.name = options.name;
|
|
123
|
-
}
|
|
124
|
-
else if ('template' in options) {
|
|
125
|
-
if ('language' in options && options.language && options.language != options.template) {
|
|
126
|
-
console.warn(`Ignoring language option: ${options.language}. Defaulting to ${options.template}.`);
|
|
127
|
-
}
|
|
128
|
-
if (!constants_1.ACCEPTED_LANGUAGES.includes(options.template)) {
|
|
129
|
-
console.warn(`Invalid language: ${options.template}. Defaulting to TypeScript.`);
|
|
130
|
-
settings.language = 'typescript';
|
|
131
|
-
settings.sourceName = 'typescript';
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
settings.language = options.template;
|
|
135
|
-
settings.sourceName = options.template;
|
|
136
|
-
}
|
|
137
|
-
settings.sourceType = 'template';
|
|
138
|
-
settings.name = options.name;
|
|
87
|
+
// Check if the source exists
|
|
88
|
+
const filteredSources = await (0, get_github_folder_names_1.getGithubFolderNames)();
|
|
89
|
+
if (!filteredSources.includes(options.example)) {
|
|
90
|
+
throw new types_1.ValidationError(`Invalid example name: ${options.example}. Please choose from: ${filteredSources.join(', ')}`);
|
|
139
91
|
}
|
|
92
|
+
settings.language = options.language;
|
|
93
|
+
settings.example = options.example;
|
|
94
|
+
settings.name = options.name;
|
|
140
95
|
return settings;
|
|
141
96
|
}
|
|
142
97
|
catch (err) {
|
|
143
98
|
console.log(`
|
|
144
99
|
${chalk_1.default.red('Validation failed')}
|
|
145
|
-
${err.message}
|
|
146
100
|
`);
|
|
147
101
|
// eslint-disable-next-line no-process-exit
|
|
148
|
-
|
|
102
|
+
throw err;
|
|
149
103
|
}
|
|
150
104
|
finally {
|
|
151
105
|
validateSpinner.stop();
|
|
@@ -41,23 +41,19 @@ async function cloneFunction(localPath, settings) {
|
|
|
41
41
|
}
|
|
42
42
|
catch (e) {
|
|
43
43
|
(0, logger_1.error)(`Failed to clone function ${(0, logger_1.highlight)(chalk_1.default.cyan(settings.name))}`, e);
|
|
44
|
-
|
|
44
|
+
throw Error(chalk_1.default.red('Failed to clone function ') + (0, logger_1.highlight)(chalk_1.default.cyan(settings.name)));
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
function getCloneURL(settings) {
|
|
48
|
-
|
|
49
|
-
if (settings.sourceType === 'example') {
|
|
50
|
-
cloneURL = `${constants_1.REPO_URL}/${settings.sourceName}/${settings.language}`;
|
|
51
|
-
}
|
|
52
|
-
return cloneURL;
|
|
48
|
+
return `${constants_1.REPO_URL}/${settings.example}/${settings.language}`;
|
|
53
49
|
}
|
|
54
50
|
async function touchupAppManifest(localPath, settings, renameFunctionFile) {
|
|
55
51
|
const appManifest = JSON.parse(node_fs_1.default.readFileSync(`${localPath}/${constants_1.CONTENTFUL_APP_MANIFEST}`, 'utf-8'));
|
|
56
52
|
const entry = appManifest["functions"][appManifest["functions"].length - 1];
|
|
57
53
|
entry.id = settings.name;
|
|
58
54
|
// the path always has a .js extension
|
|
59
|
-
entry.path =
|
|
60
|
-
entry.entryFile =
|
|
55
|
+
entry.path = `functions/${renameFunctionFile.replace('.ts', '.js')}`;
|
|
56
|
+
entry.entryFile = `functions/${renameFunctionFile}`;
|
|
61
57
|
await node_fs_1.default.writeFileSync(`${localPath}/${constants_1.CONTENTFUL_APP_MANIFEST}`, JSON.stringify(appManifest, null, 2));
|
|
62
58
|
}
|
|
63
59
|
function moveFilesToFinalDirectory(localTmpPath, localFunctionsPath) {
|
|
@@ -4,7 +4,7 @@ exports.BANNED_FUNCTION_NAMES = exports.CONTENTFUL_FUNCTIONS_EXAMPLE_REPO_PATH =
|
|
|
4
4
|
exports.EXAMPLES_PATH = 'contentful/apps/function-examples/';
|
|
5
5
|
exports.APP_MANIFEST = 'app-manifest.json';
|
|
6
6
|
exports.CONTENTFUL_APP_MANIFEST = 'contentful-app-manifest.json';
|
|
7
|
-
exports.IGNORED_CLONED_FILES = [exports.APP_MANIFEST, `package.json`];
|
|
7
|
+
exports.IGNORED_CLONED_FILES = [exports.APP_MANIFEST, exports.CONTENTFUL_APP_MANIFEST, `package.json`];
|
|
8
8
|
exports.REPO_URL = 'https://github.com/contentful/apps/function-examples';
|
|
9
9
|
exports.ACCEPTED_EXAMPLE_FOLDERS = [
|
|
10
10
|
'appevent-handler',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GenerateFunctionSettings } from "../types";
|
|
2
2
|
export declare const generateFunction: {
|
|
3
3
|
interactive: () => Promise<void>;
|
|
4
|
-
nonInteractive: (options:
|
|
4
|
+
nonInteractive: (options: GenerateFunctionSettings) => Promise<void>;
|
|
5
5
|
};
|
|
@@ -3,13 +3,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateFunction = void 0;
|
|
4
4
|
const build_generate_function_settings_1 = require("./build-generate-function-settings");
|
|
5
5
|
const create_function_1 = require("./create-function");
|
|
6
|
+
const types_1 = require("./types");
|
|
6
7
|
const interactive = async () => {
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
try {
|
|
9
|
+
const generateFunctionSettings = await (0, build_generate_function_settings_1.buildGenerateFunctionSettingsInteractive)();
|
|
10
|
+
return (0, create_function_1.create)(generateFunctionSettings);
|
|
11
|
+
}
|
|
12
|
+
catch (e) {
|
|
13
|
+
if (e instanceof types_1.ValidationError) {
|
|
14
|
+
console.error(e.message);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
console.error(e);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
9
20
|
};
|
|
10
21
|
const nonInteractive = async (options) => {
|
|
11
|
-
|
|
12
|
-
|
|
22
|
+
try {
|
|
23
|
+
const generateFunctionSettings = await (0, build_generate_function_settings_1.buildGenerateFunctionSettingsCLI)(options);
|
|
24
|
+
return (0, create_function_1.create)(generateFunctionSettings);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
if (e instanceof types_1.ValidationError) {
|
|
28
|
+
console.error(e.message);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.error(e);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
13
34
|
};
|
|
14
35
|
exports.generateFunction = {
|
|
15
36
|
interactive,
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InvalidTemplateError = exports.HTTPResponseError = void 0;
|
|
3
|
+
exports.ValidationError = exports.InvalidTemplateError = exports.HTTPResponseError = void 0;
|
|
4
4
|
class HTTPResponseError extends Error {
|
|
5
5
|
}
|
|
6
6
|
exports.HTTPResponseError = HTTPResponseError;
|
|
7
7
|
class InvalidTemplateError extends Error {
|
|
8
8
|
}
|
|
9
9
|
exports.InvalidTemplateError = InvalidTemplateError;
|
|
10
|
+
class ValidationError extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "ValidationError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.ValidationError = ValidationError;
|
package/lib/types.d.ts
CHANGED
|
@@ -82,21 +82,9 @@ export interface BuildFunctionsOptions {
|
|
|
82
82
|
esbuildConfig?: string;
|
|
83
83
|
watch?: boolean;
|
|
84
84
|
}
|
|
85
|
-
export type SourceType = 'template' | 'example';
|
|
86
85
|
export type Language = 'javascript' | 'typescript';
|
|
87
|
-
export type AcceptedFunctionExamples = 'appevent-handler';
|
|
88
|
-
export type SourceName = Language | AcceptedFunctionExamples;
|
|
89
86
|
export interface GenerateFunctionSettings {
|
|
90
87
|
name: string;
|
|
91
|
-
|
|
92
|
-
sourceName: SourceName;
|
|
88
|
+
example: string;
|
|
93
89
|
language: Language;
|
|
94
90
|
}
|
|
95
|
-
export type GenerateFunctionOptions = {
|
|
96
|
-
name: string;
|
|
97
|
-
} & ({
|
|
98
|
-
example: AcceptedFunctionExamples;
|
|
99
|
-
language: Language;
|
|
100
|
-
} | {
|
|
101
|
-
template: Language;
|
|
102
|
-
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/app-scripts",
|
|
3
|
-
"version": "1.33.
|
|
3
|
+
"version": "1.33.2",
|
|
4
4
|
"description": "A collection of scripts for building Contentful Apps",
|
|
5
5
|
"author": "Contentful GmbH",
|
|
6
6
|
"license": "MIT",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"commander": "12.1.0",
|
|
58
58
|
"contentful-management": "11.47.2",
|
|
59
59
|
"dotenv": "16.4.7",
|
|
60
|
-
"esbuild": "^0.25.
|
|
60
|
+
"esbuild": "^0.25.1",
|
|
61
61
|
"ignore": "7.0.3",
|
|
62
62
|
"inquirer": "8.2.6",
|
|
63
63
|
"lodash": "4.17.21",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"tiged": "^2.12.7",
|
|
68
68
|
"zod": "^3.24.1"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "16080d23910b9db1ed499202123da3ba1c975d3a",
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/adm-zip": "0.5.7",
|
|
73
73
|
"@types/analytics-node": "3.1.14",
|