zapier-platform-cli 15.18.1 → 15.19.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.
- package/oclif.manifest.json +1 -1
- package/package.json +5 -2
- package/scaffold/create.template.ts +64 -0
- package/scaffold/resource.template.ts +119 -0
- package/scaffold/search.template.ts +63 -0
- package/scaffold/test.template.ts +18 -0
- package/scaffold/trigger.template.ts +58 -0
- package/src/oclif/commands/scaffold.js +98 -90
- package/src/utils/ast.js +105 -4
- package/src/utils/scaffold.js +290 -37
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import zapier from 'zapier-platform-core';
|
|
3
|
+
|
|
4
|
+
import App from '../../index';
|
|
5
|
+
|
|
6
|
+
const appTester = zapier.createAppTester(App);
|
|
7
|
+
// read the `.env` file into the environment, if available
|
|
8
|
+
zapier.tools.env.inject();
|
|
9
|
+
|
|
10
|
+
describe('<%= ACTION_PLURAL %>.<%= KEY %>', () => {
|
|
11
|
+
it('should run', async () => {
|
|
12
|
+
const bundle = { inputData: {} };
|
|
13
|
+
|
|
14
|
+
const results = await appTester(App.<%= ACTION_PLURAL %>['<%= KEY %>'].<%= MAYBE_RESOURCE %>operation.perform, bundle);
|
|
15
|
+
expect(results).toBeDefined();
|
|
16
|
+
// TODO: add more assertions
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { PerformFunction, Trigger } from 'zapier-platform-core';
|
|
2
|
+
|
|
3
|
+
// triggers on a new <%= LOWER_NOUN %> with a certain tag
|
|
4
|
+
const perform: PerformFunction = async (z, bundle) => {
|
|
5
|
+
const response = await z.request({
|
|
6
|
+
url: 'https://jsonplaceholder.typicode.com/posts',
|
|
7
|
+
params: {
|
|
8
|
+
tag: bundle.inputData.tagName,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
// this should return an array of objects
|
|
12
|
+
return response.data;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
// see here for a full list of available properties:
|
|
17
|
+
// https://github.com/zapier/zapier-platform/blob/main/packages/schema/docs/build/schema.md#triggerschema
|
|
18
|
+
key: '<%= KEY %>' as const,
|
|
19
|
+
noun: '<%= NOUN %>',
|
|
20
|
+
|
|
21
|
+
display: {
|
|
22
|
+
label: 'New <%= NOUN %>',
|
|
23
|
+
description: 'Triggers when a new <%= LOWER_NOUN %> is created.',
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
operation: {
|
|
27
|
+
type: 'polling',
|
|
28
|
+
perform,
|
|
29
|
+
|
|
30
|
+
<%= INCLUDE_INTRO_COMMENTS ? [
|
|
31
|
+
'// `inputFields` defines the fields a user could provide',
|
|
32
|
+
'// Zapier will pass them in as `bundle.inputData` later. They\'re optional.'
|
|
33
|
+
].join('\n ') : '' %>
|
|
34
|
+
inputFields: [],
|
|
35
|
+
|
|
36
|
+
<%= INCLUDE_INTRO_COMMENTS ? [
|
|
37
|
+
'// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example',
|
|
38
|
+
'// from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of',
|
|
39
|
+
'// returned records, and have obvious placeholder values that we can show to any user.'
|
|
40
|
+
].join('\n ') : '' %>
|
|
41
|
+
sample: {
|
|
42
|
+
id: 1,
|
|
43
|
+
name: 'Test',
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
<%= INCLUDE_INTRO_COMMENTS ? [
|
|
47
|
+
'// If fields are custom to each user (like spreadsheet columns), `outputFields` can create human labels',
|
|
48
|
+
'// For a more complete example of using dynamic fields see',
|
|
49
|
+
'// https://github.com/zapier/zapier-platform/tree/main/packages/cli#customdynamic-fields',
|
|
50
|
+
'// Alternatively, a static field definition can be provided, to specify labels for the fields'
|
|
51
|
+
].join('\n ') : '' %>
|
|
52
|
+
outputFields: [
|
|
53
|
+
// these are placeholders to match the example `perform` above
|
|
54
|
+
// {key: 'id', label: 'Person ID'},
|
|
55
|
+
// {key: 'name', label: 'Person Name'}
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
} satisfies Trigger;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
// @ts-check
|
|
3
|
+
|
|
1
4
|
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
2
6
|
|
|
3
7
|
const { flags } = require('@oclif/command');
|
|
4
8
|
|
|
@@ -6,8 +10,7 @@ const BaseCommand = require('../ZapierBaseCommand');
|
|
|
6
10
|
const { buildFlags } = require('../buildFlags');
|
|
7
11
|
|
|
8
12
|
const {
|
|
9
|
-
|
|
10
|
-
getRelativeRequirePath,
|
|
13
|
+
createScaffoldingContext,
|
|
11
14
|
plural,
|
|
12
15
|
updateEntryFile,
|
|
13
16
|
isValidEntryFileUpdate,
|
|
@@ -18,126 +21,89 @@ const { isValidAppInstall } = require('../../utils/misc');
|
|
|
18
21
|
const { writeFile } = require('../../utils/files');
|
|
19
22
|
const { ISSUES_URL } = require('../../constants');
|
|
20
23
|
|
|
21
|
-
const getNewFileDirectory = (action, test = false) =>
|
|
22
|
-
path.join(test ? 'test/' : '', plural(action));
|
|
23
|
-
|
|
24
|
-
const getLocalFilePath = (directory, actionKey) =>
|
|
25
|
-
path.join(directory, actionKey);
|
|
26
|
-
/**
|
|
27
|
-
* both the string to `require` and later, the filepath to write to
|
|
28
|
-
*/
|
|
29
|
-
const getFullActionFilePath = (directory, actionKey) =>
|
|
30
|
-
path.join(process.cwd(), getLocalFilePath(directory, actionKey));
|
|
31
|
-
|
|
32
|
-
const getFullActionFilePathWithExtension = (directory, actionKey, isTest) =>
|
|
33
|
-
`${getFullActionFilePath(directory, actionKey)}${isTest ? '.test' : ''}.js`;
|
|
34
|
-
|
|
35
24
|
class ScaffoldCommand extends BaseCommand {
|
|
36
25
|
async perform() {
|
|
37
26
|
const { actionType, noun } = this.args;
|
|
38
|
-
|
|
39
|
-
// TODO: interactive portion here?
|
|
27
|
+
const indexFileLocal = this.flags.entry ?? this.defaultIndexFileLocal();
|
|
40
28
|
const {
|
|
41
|
-
dest:
|
|
42
|
-
|
|
43
|
-
entry = 'index.js',
|
|
29
|
+
dest: actionDirLocal = this.defaultActionDirLocal(indexFileLocal),
|
|
30
|
+
'test-dest': testDirLocal = this.defaultTestDirLocal(indexFileLocal),
|
|
44
31
|
force,
|
|
45
32
|
} = this.flags;
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
// const tsParser = j.withParser('ts')
|
|
49
|
-
// tsParser(codeStr)
|
|
50
|
-
// will have to change logic probably though
|
|
51
|
-
if (entry.endsWith('ts')) {
|
|
52
|
-
this.error(
|
|
53
|
-
`Typescript isn't supported for scaffolding yet. Instead, try copying the example code at https://github.com/zapier/zapier-platform/blob/b8224ec9855be91c66c924b731199a068b1e913a/example-apps/typescript/src/resources/recipe.ts`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
34
|
+
const language = indexFileLocal.endsWith('.ts') ? 'ts' : 'js';
|
|
56
35
|
|
|
57
|
-
const
|
|
58
|
-
const templateContext = createTemplateContext(
|
|
36
|
+
const context = createScaffoldingContext({
|
|
59
37
|
actionType,
|
|
60
38
|
noun,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
39
|
+
language,
|
|
40
|
+
indexFileLocal,
|
|
41
|
+
actionDirLocal,
|
|
42
|
+
testDirLocal,
|
|
43
|
+
includeIntroComments: !this.flags['no-help'],
|
|
44
|
+
preventOverwrite: !force,
|
|
45
|
+
});
|
|
65
46
|
|
|
66
|
-
const preventOverwrite = !force;
|
|
67
47
|
// TODO: read from config file?
|
|
68
48
|
|
|
69
|
-
this.startSpinner(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
actionType,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
49
|
+
this.startSpinner(`Creating new file: ${context.actionFileLocal}`);
|
|
50
|
+
|
|
51
|
+
await writeTemplateFile({
|
|
52
|
+
destinationPath: context.actionFileResolved,
|
|
53
|
+
templateType: context.actionType,
|
|
54
|
+
language: context.language,
|
|
55
|
+
preventOverwrite: context.preventOverwrite,
|
|
56
|
+
templateContext: context.templateContext,
|
|
57
|
+
});
|
|
78
58
|
this.stopSpinner();
|
|
79
59
|
|
|
80
|
-
this.startSpinner(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
templateContext,
|
|
89
|
-
getFullActionFilePathWithExtension(newTestActionDir, actionKey, true),
|
|
90
|
-
preventOverwrite
|
|
91
|
-
);
|
|
60
|
+
this.startSpinner(`Creating new test file: ${context.testFileLocal}`);
|
|
61
|
+
await writeTemplateFile({
|
|
62
|
+
destinationPath: context.testFileResolved,
|
|
63
|
+
templateType: 'test',
|
|
64
|
+
language: context.language,
|
|
65
|
+
preventOverwrite: context.preventOverwrite,
|
|
66
|
+
templateContext: context.templateContext,
|
|
67
|
+
});
|
|
92
68
|
this.stopSpinner();
|
|
93
69
|
|
|
94
70
|
// * rewire the index.js to point to the new file
|
|
95
|
-
this.startSpinner(`Rewriting your ${
|
|
71
|
+
this.startSpinner(`Rewriting your ${context.indexFileLocal}`);
|
|
96
72
|
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
templateContext.VARIABLE,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
templateContext.KEY
|
|
105
|
-
);
|
|
73
|
+
const originalContents = await updateEntryFile({
|
|
74
|
+
language: context.language,
|
|
75
|
+
indexFileResolved: context.indexFileResolved,
|
|
76
|
+
actionRelativeImportPath: context.actionRelativeImportPath,
|
|
77
|
+
actionImportName: context.templateContext.VARIABLE,
|
|
78
|
+
actionType: context.actionType,
|
|
79
|
+
});
|
|
106
80
|
|
|
107
81
|
if (isValidAppInstall().valid) {
|
|
108
82
|
const success = isValidEntryFileUpdate(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
83
|
+
context.language,
|
|
84
|
+
context.indexFileResolved,
|
|
85
|
+
context.actionType,
|
|
86
|
+
context.templateContext.KEY
|
|
112
87
|
);
|
|
113
88
|
|
|
114
89
|
this.stopSpinner({ success });
|
|
115
90
|
|
|
116
91
|
if (!success) {
|
|
117
|
-
const entryName = splitFileFromPath(
|
|
92
|
+
const entryName = splitFileFromPath(context.indexFileResolved)[1];
|
|
118
93
|
|
|
119
94
|
this.startSpinner(
|
|
120
95
|
`Unable to successfully rewrite your ${entryName}. Rolling back...`
|
|
121
96
|
);
|
|
122
|
-
await writeFile(
|
|
97
|
+
await writeFile(context.indexFileResolved, originalContents);
|
|
123
98
|
this.stopSpinner();
|
|
124
99
|
|
|
125
100
|
this.error(
|
|
126
101
|
[
|
|
127
|
-
`\nPlease add the following lines to ${
|
|
128
|
-
` * \`const ${
|
|
129
|
-
|
|
130
|
-
} = require('./${getRelativeRequirePath(
|
|
131
|
-
entryFilePath,
|
|
132
|
-
getFullActionFilePath(newActionDir, actionKey)
|
|
133
|
-
)}');\` at the top-level`,
|
|
134
|
-
` * \`[${templateContext.VARIABLE}.key]: ${
|
|
135
|
-
templateContext.VARIABLE
|
|
136
|
-
}\` in the "${plural(
|
|
137
|
-
actionType
|
|
138
|
-
)}" object in your exported integration definition.`,
|
|
102
|
+
`\nPlease add the following lines to ${context.indexFileResolved}:`,
|
|
103
|
+
` * \`const ${context.templateContext.VARIABLE} = require('./${context.actionRelativeImportPath}');\` at the top-level`,
|
|
104
|
+
` * \`[${context.templateContext.VARIABLE}.key]: ${context.templateContext.VARIABLE}\` in the "${context.actionTypePlural}" object in your exported integration definition.`,
|
|
139
105
|
'',
|
|
140
|
-
`Also, please file an issue at ${ISSUES_URL} with the contents of your ${
|
|
106
|
+
`Also, please file an issue at ${ISSUES_URL} with the contents of your ${context.indexFileResolved}.`,
|
|
141
107
|
].join('\n')
|
|
142
108
|
);
|
|
143
109
|
}
|
|
@@ -146,8 +112,51 @@ class ScaffoldCommand extends BaseCommand {
|
|
|
146
112
|
this.stopSpinner();
|
|
147
113
|
|
|
148
114
|
if (!this.flags.invokedFromAnotherCommand) {
|
|
149
|
-
this.log(`\nAll done! Your new ${actionType} is ready to use.`);
|
|
115
|
+
this.log(`\nAll done! Your new ${context.actionType} is ready to use.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* If `--entry` is not provided, this will determine the path to the
|
|
121
|
+
* root index file. Notably, we'll look for tsconfig.json and
|
|
122
|
+
* src/index.ts first, because even TS apps have a root level plain
|
|
123
|
+
* index.js that we should ignore.
|
|
124
|
+
*
|
|
125
|
+
* @returns {string}
|
|
126
|
+
*/
|
|
127
|
+
defaultIndexFileLocal() {
|
|
128
|
+
const tsConfigPath = path.join(process.cwd(), 'tsconfig.json');
|
|
129
|
+
const srcIndexTsPath = path.join(process.cwd(), 'src', 'index.ts');
|
|
130
|
+
if (fs.existsSync(tsConfigPath) && fs.existsSync(srcIndexTsPath)) {
|
|
131
|
+
this.log('Automatically detected TypeScript project');
|
|
132
|
+
return 'src/index.ts';
|
|
150
133
|
}
|
|
134
|
+
|
|
135
|
+
return 'index.js';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* If `--dest` is not provided, this will determine the directory for
|
|
140
|
+
* the new action file to be created in.
|
|
141
|
+
*
|
|
142
|
+
* @param {string} indexFileLocal - The path to the index file
|
|
143
|
+
* @returns {string}
|
|
144
|
+
*/
|
|
145
|
+
defaultActionDirLocal(indexFileLocal) {
|
|
146
|
+
const parent = path.dirname(indexFileLocal);
|
|
147
|
+
return path.join(parent, plural(this.args.actionType));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* If `--test-dest` is not provided, this will determine the directory
|
|
152
|
+
* for the new test file to be created in.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} indexFileLocal - The path to the index file
|
|
155
|
+
* @returns {string}
|
|
156
|
+
*/
|
|
157
|
+
defaultTestDirLocal(indexFileLocal) {
|
|
158
|
+
const parent = path.dirname(indexFileLocal);
|
|
159
|
+
return path.join(parent, 'test', plural(this.args.actionType));
|
|
151
160
|
}
|
|
152
161
|
}
|
|
153
162
|
|
|
@@ -179,13 +188,12 @@ ScaffoldCommand.flags = buildFlags({
|
|
|
179
188
|
entry: flags.string({
|
|
180
189
|
char: 'e',
|
|
181
190
|
description:
|
|
182
|
-
"Supply the path to your integration's
|
|
183
|
-
default: 'index.js',
|
|
191
|
+
"Supply the path to your integration's entry point (`index.js` or `src/index.ts`). This will try to automatically detect the correct file if not provided.",
|
|
184
192
|
}),
|
|
185
193
|
force: flags.boolean({
|
|
186
194
|
char: 'f',
|
|
187
195
|
description:
|
|
188
|
-
'Should we overwrite an
|
|
196
|
+
'Should we overwrite an existing trigger/search/create file?',
|
|
189
197
|
default: false,
|
|
190
198
|
}),
|
|
191
199
|
'no-help': flags.boolean({
|
package/src/utils/ast.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
//
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
// tools for modifying an AST
|
|
2
4
|
|
|
3
5
|
const j = require('jscodeshift');
|
|
6
|
+
const ts = j.withParser('ts');
|
|
4
7
|
|
|
5
8
|
// simple helper functions used for searching for nodes
|
|
6
9
|
// can't use j.identifier(name) because it has extra properties and we have to have no extras to find nodes
|
|
@@ -21,7 +24,7 @@ const typeHelpers = {
|
|
|
21
24
|
/**
|
|
22
25
|
* adds a `const verName = require(path)` to the root of a codeStr
|
|
23
26
|
*/
|
|
24
|
-
const
|
|
27
|
+
const importActionInJsApp = (codeStr, varName, path) => {
|
|
25
28
|
if (codeStr.match(new RegExp(`${varName} ?= ?require`))) {
|
|
26
29
|
// duplicate identifier, no need to re-add
|
|
27
30
|
// this would fail if they used this variable name for something else; we'd keep going and double-declare that variable
|
|
@@ -61,7 +64,7 @@ const createRootRequire = (codeStr, varName, path) => {
|
|
|
61
64
|
return root.toSource();
|
|
62
65
|
};
|
|
63
66
|
|
|
64
|
-
const
|
|
67
|
+
const registerActionInJsApp = (codeStr, property, varName) => {
|
|
65
68
|
// to play with this, use https://astexplorer.net/#/gist/cb4986b3f1c6eb975339608109a48e7d/0fbf2fabbcf27d0b6ebd8910f979bd5d97dd9404
|
|
66
69
|
|
|
67
70
|
const root = j(codeStr);
|
|
@@ -136,4 +139,102 @@ const addKeyToPropertyOnApp = (codeStr, property, varName) => {
|
|
|
136
139
|
return root.toSource();
|
|
137
140
|
};
|
|
138
141
|
|
|
139
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Adds an import statement to the top of an index.ts file to import a
|
|
144
|
+
* new action, such as `import some_trigger from './triggers/some_trigger';`
|
|
145
|
+
*
|
|
146
|
+
* @param {string} codeStr - The code of the index.ts file to modify.
|
|
147
|
+
* @param {string} identifierName - The name of imported action used as a variable in the code.
|
|
148
|
+
* @param {string} actionRelativeImportPath - The relative path to import the action from
|
|
149
|
+
* @returns {string}
|
|
150
|
+
*/
|
|
151
|
+
const importActionInTsApp = (
|
|
152
|
+
codeStr,
|
|
153
|
+
identifierName,
|
|
154
|
+
actionRelativeImportPath
|
|
155
|
+
) => {
|
|
156
|
+
const root = ts(codeStr);
|
|
157
|
+
|
|
158
|
+
const imports = root.find(ts.ImportDeclaration);
|
|
159
|
+
|
|
160
|
+
const newImportStatement = j.importDeclaration(
|
|
161
|
+
[j.importDefaultSpecifier(j.identifier(identifierName))],
|
|
162
|
+
j.literal(actionRelativeImportPath)
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
if (imports.length) {
|
|
166
|
+
imports.at(-1).insertAfter(newImportStatement);
|
|
167
|
+
} else {
|
|
168
|
+
const body = root.find(ts.Program).get().node.body;
|
|
169
|
+
body.unshift(newImportStatement);
|
|
170
|
+
// Add newline after import?
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return root.toSource({ quote: 'single' });
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
*
|
|
178
|
+
* @param {string} codeStr
|
|
179
|
+
* @param {'creates' | 'searches' | 'triggers'} actionTypePlural - The type of action to register within the app
|
|
180
|
+
* @param {string} identifierName - Name of the action imported to be registered
|
|
181
|
+
* @returns {string}
|
|
182
|
+
*/
|
|
183
|
+
const registerActionInTsApp = (codeStr, actionTypePlural, identifierName) => {
|
|
184
|
+
const root = ts(codeStr);
|
|
185
|
+
|
|
186
|
+
// the `[thing.key]: thing` entry we'd like to insert.
|
|
187
|
+
const newProperty = ts.property.from({
|
|
188
|
+
kind: 'init',
|
|
189
|
+
key: j.memberExpression(j.identifier(identifierName), j.identifier('key')),
|
|
190
|
+
value: j.identifier(identifierName),
|
|
191
|
+
computed: true,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Find the top level app Object; the one with the `platformVersion`
|
|
195
|
+
// key. This is where we'll insert our new property.
|
|
196
|
+
const appObjectCandidates = root
|
|
197
|
+
.find(ts.ObjectExpression)
|
|
198
|
+
.filter((path) =>
|
|
199
|
+
path.value.properties.some(
|
|
200
|
+
(prop) => prop.key && prop.key.name === 'platformVersion'
|
|
201
|
+
)
|
|
202
|
+
);
|
|
203
|
+
if (appObjectCandidates.length !== 1) {
|
|
204
|
+
throw new Error('Unable to find the app definition to modify');
|
|
205
|
+
}
|
|
206
|
+
const appObj = appObjectCandidates.get().node;
|
|
207
|
+
|
|
208
|
+
// Now we have an app object to modify.
|
|
209
|
+
|
|
210
|
+
// Check if this object already has the actionType group inside it.
|
|
211
|
+
const existingProp = appObj.properties.find(
|
|
212
|
+
(props) => props.key.name === actionTypePlural
|
|
213
|
+
);
|
|
214
|
+
if (existingProp) {
|
|
215
|
+
const value = existingProp.value;
|
|
216
|
+
if (value.type !== 'ObjectExpression') {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`Tried to edit the ${actionTypePlural} key, but the value wasn't an object`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
value.properties.push(newProperty);
|
|
222
|
+
} else {
|
|
223
|
+
appObj.properties.push(
|
|
224
|
+
j.property(
|
|
225
|
+
'init',
|
|
226
|
+
j.identifier(actionTypePlural),
|
|
227
|
+
j.objectExpression([newProperty])
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return root.toSource({ quote: 'single' });
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
module.exports = {
|
|
236
|
+
importActionInJsApp,
|
|
237
|
+
registerActionInJsApp,
|
|
238
|
+
importActionInTsApp,
|
|
239
|
+
registerActionInTsApp,
|
|
240
|
+
};
|