@xano/cli 0.0.95-beta.11 → 0.0.95-beta.13
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/dist/commands/sandbox/delete/index.d.ts +12 -0
- package/dist/commands/sandbox/delete/index.js +71 -0
- package/dist/commands/sandbox/env/delete/index.js +2 -0
- package/dist/commands/sandbox/env/get/index.js +2 -0
- package/dist/commands/sandbox/env/get_all/index.js +2 -0
- package/dist/commands/sandbox/env/list/index.js +2 -0
- package/dist/commands/sandbox/env/set/index.js +2 -0
- package/dist/commands/sandbox/env/set_all/index.js +2 -0
- package/dist/commands/sandbox/get/index.js +2 -0
- package/dist/commands/sandbox/license/get/index.js +2 -0
- package/dist/commands/sandbox/license/set/index.js +2 -0
- package/dist/commands/sandbox/pull/index.js +2 -0
- package/dist/commands/sandbox/push/index.d.ts +1 -0
- package/dist/commands/sandbox/push/index.js +21 -1
- package/dist/commands/sandbox/reset/index.js +2 -0
- package/dist/commands/sandbox/review/index.js +2 -0
- package/dist/commands/sandbox/unit_test/list/index.js +2 -0
- package/dist/commands/sandbox/unit_test/run/index.js +2 -0
- package/dist/commands/sandbox/unit_test/run_all/index.js +4 -0
- package/dist/commands/sandbox/workflow_test/delete/index.js +2 -0
- package/dist/commands/sandbox/workflow_test/get/index.js +2 -0
- package/dist/commands/sandbox/workflow_test/list/index.js +2 -0
- package/dist/commands/sandbox/workflow_test/run/index.js +2 -0
- package/dist/commands/sandbox/workflow_test/run_all/index.js +4 -0
- package/dist/commands/workspace/push/index.d.ts +1 -0
- package/dist/commands/workspace/push/index.js +19 -1
- package/dist/utils/reference-checker.d.ts +12 -0
- package/dist/utils/reference-checker.js +97 -2
- package/oclif.manifest.json +1981 -1927
- package/package.json +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import BaseCommand from '../../../base-command.js';
|
|
2
|
+
export default class SandboxDelete extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
private confirm;
|
|
12
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import BaseCommand from '../../../base-command.js';
|
|
3
|
+
export default class SandboxDelete extends BaseCommand {
|
|
4
|
+
static description = 'Delete your sandbox environment completely (debugging only — it will be re-created on next access)';
|
|
5
|
+
static examples = [
|
|
6
|
+
`$ xano sandbox delete
|
|
7
|
+
Are you sure you want to DELETE your sandbox environment? This destroys all data. (y/N) y
|
|
8
|
+
Sandbox environment deleted.
|
|
9
|
+
`,
|
|
10
|
+
`$ xano sandbox delete --force`,
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
...BaseCommand.baseFlags,
|
|
14
|
+
force: Flags.boolean({
|
|
15
|
+
char: 'f',
|
|
16
|
+
default: false,
|
|
17
|
+
description: 'Skip confirmation prompt',
|
|
18
|
+
required: false,
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
async run() {
|
|
22
|
+
const { flags } = await this.parse(SandboxDelete);
|
|
23
|
+
const { profile } = this.resolveProfile(flags);
|
|
24
|
+
if (!flags.force) {
|
|
25
|
+
const confirmed = await this.confirm(`Are you sure you want to DELETE your sandbox environment? This destroys all data and the tenant will be re-created on next access.`);
|
|
26
|
+
if (!confirmed) {
|
|
27
|
+
this.log('Delete cancelled.');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const apiUrl = `${profile.instance_origin}/api:meta/sandbox/me`;
|
|
32
|
+
try {
|
|
33
|
+
const response = await this.verboseFetch(apiUrl, {
|
|
34
|
+
headers: {
|
|
35
|
+
accept: 'application/json',
|
|
36
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
},
|
|
39
|
+
method: 'DELETE',
|
|
40
|
+
}, flags.verbose, profile.access_token);
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
const message = await this.parseApiError(response, 'Failed to delete sandbox environment');
|
|
43
|
+
this.error(message);
|
|
44
|
+
}
|
|
45
|
+
this.log('Sandbox environment deleted.');
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof Error && 'oclif' in error)
|
|
49
|
+
throw error;
|
|
50
|
+
if (error instanceof Error) {
|
|
51
|
+
this.error(`Failed to delete sandbox environment: ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.error(`Failed to delete sandbox environment: ${String(error)}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async confirm(message) {
|
|
59
|
+
const readline = await import('node:readline');
|
|
60
|
+
const rl = readline.createInterface({
|
|
61
|
+
input: process.stdin,
|
|
62
|
+
output: process.stdout,
|
|
63
|
+
});
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
rl.question(`${message} (y/N) `, (answer) => {
|
|
66
|
+
rl.close();
|
|
67
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -65,6 +65,8 @@ Environment variables saved to env_<tenant>.yaml
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
catch (error) {
|
|
68
|
+
if (error instanceof Error && 'oclif' in error)
|
|
69
|
+
throw error;
|
|
68
70
|
if (error instanceof Error) {
|
|
69
71
|
this.error(`Failed to get sandbox environment variables: ${error.message}`);
|
|
70
72
|
}
|
|
@@ -54,6 +54,8 @@ Environment variables for sandbox environment:
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
catch (error) {
|
|
57
|
+
if (error instanceof Error && 'oclif' in error)
|
|
58
|
+
throw error;
|
|
57
59
|
if (error instanceof Error) {
|
|
58
60
|
this.error(`Failed to list sandbox environment variables: ${error.message}`);
|
|
59
61
|
}
|
|
@@ -61,6 +61,8 @@ Pulled 42 documents from sandbox environment to ./my-sandbox
|
|
|
61
61
|
responseText = await response.text();
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
|
+
if (error instanceof Error && 'oclif' in error)
|
|
65
|
+
throw error;
|
|
64
66
|
if (error instanceof Error) {
|
|
65
67
|
this.error(`Failed to fetch multidoc: ${error.message}`);
|
|
66
68
|
}
|
|
@@ -3,7 +3,7 @@ import * as fs from 'node:fs';
|
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import BaseCommand from '../../../base-command.js';
|
|
5
5
|
import { findFilesWithGuid } from '../../../utils/document-parser.js';
|
|
6
|
-
import { checkReferences } from '../../../utils/reference-checker.js';
|
|
6
|
+
import { checkReferences, checkTableIndexes } from '../../../utils/reference-checker.js';
|
|
7
7
|
export default class SandboxPush extends BaseCommand {
|
|
8
8
|
static args = {
|
|
9
9
|
directory: Args.string({
|
|
@@ -72,6 +72,11 @@ Pushed 42 documents to sandbox environment from ./my-workspace
|
|
|
72
72
|
if (badRefs.length > 0) {
|
|
73
73
|
this.renderBadReferences(badRefs);
|
|
74
74
|
}
|
|
75
|
+
// Check for indexes referencing non-existent schema fields
|
|
76
|
+
const badIndexes = checkTableIndexes(documentEntries);
|
|
77
|
+
if (badIndexes.length > 0) {
|
|
78
|
+
this.renderBadIndexes(badIndexes);
|
|
79
|
+
}
|
|
75
80
|
const multidoc = documentEntries.map((d) => d.content).join('\n---\n');
|
|
76
81
|
const queryParams = new URLSearchParams({
|
|
77
82
|
env: flags.env.toString(),
|
|
@@ -124,6 +129,8 @@ Pushed 42 documents to sandbox environment from ./my-workspace
|
|
|
124
129
|
}
|
|
125
130
|
}
|
|
126
131
|
catch (error) {
|
|
132
|
+
if (error instanceof Error && 'oclif' in error)
|
|
133
|
+
throw error;
|
|
127
134
|
if (error instanceof Error) {
|
|
128
135
|
this.error(`Failed to push multidoc: ${error.message}`);
|
|
129
136
|
}
|
|
@@ -148,6 +155,19 @@ Pushed 42 documents to sandbox environment from ./my-workspace
|
|
|
148
155
|
}
|
|
149
156
|
return files.sort();
|
|
150
157
|
}
|
|
158
|
+
renderBadIndexes(badIndexes) {
|
|
159
|
+
this.log('');
|
|
160
|
+
this.log(ux.colorize('red', ux.colorize('bold', '=== CRITICAL: Invalid Indexes ===')));
|
|
161
|
+
this.log('');
|
|
162
|
+
this.log(ux.colorize('red', 'The following tables have indexes referencing fields that do not exist in the schema.'));
|
|
163
|
+
this.log(ux.colorize('red', 'These will cause the import to fail.'));
|
|
164
|
+
this.log('');
|
|
165
|
+
for (const idx of badIndexes) {
|
|
166
|
+
this.log(` ${ux.colorize('red', 'CRITICAL'.padEnd(16))} ${'table'.padEnd(18)} ${idx.table}`);
|
|
167
|
+
this.log(` ${' '.repeat(16)} ${' '.repeat(18)} ${ux.colorize('dim', `${idx.indexType} index → field "${idx.field}" does not exist in schema`)}`);
|
|
168
|
+
}
|
|
169
|
+
this.log('');
|
|
170
|
+
}
|
|
151
171
|
renderBadReferences(badRefs) {
|
|
152
172
|
this.log('');
|
|
153
173
|
this.log(ux.colorize('yellow', ux.colorize('bold', '=== Unresolved References ===')));
|
|
@@ -45,6 +45,8 @@ Sandbox environment has been reset.
|
|
|
45
45
|
this.log('Sandbox environment has been reset.');
|
|
46
46
|
}
|
|
47
47
|
catch (error) {
|
|
48
|
+
if (error instanceof Error && 'oclif' in error)
|
|
49
|
+
throw error;
|
|
48
50
|
if (error instanceof Error) {
|
|
49
51
|
this.error(`Failed to reset sandbox environment: ${error.message}`);
|
|
50
52
|
}
|
|
@@ -128,6 +128,8 @@ Results: 4 passed, 1 failed
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
catch (error) {
|
|
131
|
+
if (error instanceof Error && 'oclif' in error)
|
|
132
|
+
throw error;
|
|
131
133
|
const message = error instanceof Error ? error.message : String(error);
|
|
132
134
|
results.push({
|
|
133
135
|
message,
|
|
@@ -156,6 +158,8 @@ Results: 4 passed, 1 failed
|
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
catch (error) {
|
|
161
|
+
if (error instanceof Error && 'oclif' in error)
|
|
162
|
+
throw error;
|
|
159
163
|
if (error instanceof Error) {
|
|
160
164
|
this.error(`Failed to run unit tests: ${error.message}`);
|
|
161
165
|
}
|
|
@@ -47,6 +47,8 @@ export default class SandboxWorkflowTestGet extends BaseCommand {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
catch (error) {
|
|
50
|
+
if (error instanceof Error && 'oclif' in error)
|
|
51
|
+
throw error;
|
|
50
52
|
if (error instanceof Error) {
|
|
51
53
|
this.error(`Failed to get workflow test: ${error.message}`);
|
|
52
54
|
}
|
|
@@ -116,6 +116,8 @@ Results: 2 passed, 1 failed
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
catch (error) {
|
|
119
|
+
if (error instanceof Error && 'oclif' in error)
|
|
120
|
+
throw error;
|
|
119
121
|
const message = error instanceof Error ? error.message : String(error);
|
|
120
122
|
results.push({
|
|
121
123
|
message,
|
|
@@ -142,6 +144,8 @@ Results: 2 passed, 1 failed
|
|
|
142
144
|
}
|
|
143
145
|
}
|
|
144
146
|
catch (error) {
|
|
147
|
+
if (error instanceof Error && 'oclif' in error)
|
|
148
|
+
throw error;
|
|
145
149
|
if (error instanceof Error) {
|
|
146
150
|
this.error(`Failed to run workflow tests: ${error.message}`);
|
|
147
151
|
}
|
|
@@ -6,7 +6,7 @@ import * as os from 'node:os';
|
|
|
6
6
|
import * as path from 'node:path';
|
|
7
7
|
import BaseCommand from '../../../base-command.js';
|
|
8
8
|
import { buildDocumentKey, findFilesWithGuid, parseDocument } from '../../../utils/document-parser.js';
|
|
9
|
-
import { checkReferences } from '../../../utils/reference-checker.js';
|
|
9
|
+
import { checkReferences, checkTableIndexes } from '../../../utils/reference-checker.js';
|
|
10
10
|
export default class Push extends BaseCommand {
|
|
11
11
|
static args = {
|
|
12
12
|
directory: Args.string({
|
|
@@ -331,6 +331,11 @@ Push functions but exclude test files
|
|
|
331
331
|
if (badRefs.length > 0) {
|
|
332
332
|
this.renderBadReferences(badRefs);
|
|
333
333
|
}
|
|
334
|
+
// Check for indexes referencing non-existent schema fields
|
|
335
|
+
const badIndexes = checkTableIndexes(documentEntries);
|
|
336
|
+
if (badIndexes.length > 0) {
|
|
337
|
+
this.renderBadIndexes(badIndexes);
|
|
338
|
+
}
|
|
334
339
|
// Check for critical errors that must block the push
|
|
335
340
|
const criticalOps = preview.operations.filter((op) => op.details?.includes('exception:') || op.details?.includes('mvp:placeholder'));
|
|
336
341
|
if (criticalOps.length > 0) {
|
|
@@ -751,6 +756,19 @@ Push functions but exclude test files
|
|
|
751
756
|
}
|
|
752
757
|
return files.sort();
|
|
753
758
|
}
|
|
759
|
+
renderBadIndexes(badIndexes) {
|
|
760
|
+
this.log('');
|
|
761
|
+
this.log(ux.colorize('red', ux.colorize('bold', '=== CRITICAL: Invalid Indexes ===')));
|
|
762
|
+
this.log('');
|
|
763
|
+
this.log(ux.colorize('red', 'The following tables have indexes referencing fields that do not exist in the schema.'));
|
|
764
|
+
this.log(ux.colorize('red', 'These will cause the import to fail.'));
|
|
765
|
+
this.log('');
|
|
766
|
+
for (const idx of badIndexes) {
|
|
767
|
+
this.log(` ${ux.colorize('red', 'CRITICAL'.padEnd(16))} ${'table'.padEnd(18)} ${idx.table}`);
|
|
768
|
+
this.log(` ${' '.repeat(16)} ${' '.repeat(18)} ${ux.colorize('dim', `${idx.indexType} index → field "${idx.field}" does not exist in schema`)}`);
|
|
769
|
+
}
|
|
770
|
+
this.log('');
|
|
771
|
+
}
|
|
754
772
|
renderBadReferences(badRefs) {
|
|
755
773
|
this.log(ux.colorize('yellow', ux.colorize('bold', '=== Unresolved References ===')));
|
|
756
774
|
this.log('');
|
|
@@ -43,3 +43,15 @@ export declare function checkReferences(documents: Array<{
|
|
|
43
43
|
name: string;
|
|
44
44
|
type: string;
|
|
45
45
|
}>): BadReference[];
|
|
46
|
+
export interface BadIndex {
|
|
47
|
+
field: string;
|
|
48
|
+
indexType: string;
|
|
49
|
+
table: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check table documents for indexes that reference fields not in the schema.
|
|
53
|
+
* Parses the XanoScript table format to extract schema field names and index field names.
|
|
54
|
+
*/
|
|
55
|
+
export declare function checkTableIndexes(documents: Array<{
|
|
56
|
+
content: string;
|
|
57
|
+
}>): BadIndex[];
|
|
@@ -20,6 +20,14 @@ const REFERENCE_PATTERNS = [
|
|
|
20
20
|
regex: /^\s*workflow_test\.call\s+("(?:[^"\\]|\\.)*"|[^\s{]+)/gm,
|
|
21
21
|
targetType: 'workflow_test',
|
|
22
22
|
},
|
|
23
|
+
// db.* statements reference tables: db.get, db.query, db.add, db.edit, db.add_or_edit, db.delete, db.bulk_add, db.bulk_delete, db.count
|
|
24
|
+
{
|
|
25
|
+
keyword: 'db.*',
|
|
26
|
+
regex: /^\s*db\.(?:get|query|add|edit|add_or_edit|delete|bulk_add|bulk_delete|count)\s+("(?:[^"\\]|\\.)*"|[^\s{]+)/gm,
|
|
27
|
+
targetType: 'table',
|
|
28
|
+
},
|
|
29
|
+
// Schema foreign key references: table = "name" inside field definitions
|
|
30
|
+
{ keyword: 'table (FK)', regex: /\btable\s*=\s*"([^"]*)"/gm, targetType: 'table' },
|
|
23
31
|
];
|
|
24
32
|
/**
|
|
25
33
|
* Strip surrounding quotes from a name if present.
|
|
@@ -116,8 +124,8 @@ export function checkReferences(documents, serverOperations) {
|
|
|
116
124
|
let match;
|
|
117
125
|
while ((match = pattern.regex.exec(doc.content)) !== null) {
|
|
118
126
|
const rawName = stripQuotes(match[1]);
|
|
119
|
-
// Skip empty names
|
|
120
|
-
if (!rawName)
|
|
127
|
+
// Skip empty names only for action.call (valid for integration actions)
|
|
128
|
+
if (!rawName && pattern.keyword === 'action.call')
|
|
121
129
|
continue;
|
|
122
130
|
const { targetType } = pattern;
|
|
123
131
|
const knownNames = registry.get(targetType);
|
|
@@ -135,3 +143,90 @@ export function checkReferences(documents, serverOperations) {
|
|
|
135
143
|
}
|
|
136
144
|
return badRefs;
|
|
137
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Check table documents for indexes that reference fields not in the schema.
|
|
148
|
+
* Parses the XanoScript table format to extract schema field names and index field names.
|
|
149
|
+
*/
|
|
150
|
+
export function checkTableIndexes(documents) {
|
|
151
|
+
const badIndexes = [];
|
|
152
|
+
for (const doc of documents) {
|
|
153
|
+
const parsed = parseDocument(doc.content);
|
|
154
|
+
if (!parsed || parsed.type !== 'table')
|
|
155
|
+
continue;
|
|
156
|
+
const schemaFields = extractSchemaFields(doc.content);
|
|
157
|
+
const indexes = extractIndexes(doc.content);
|
|
158
|
+
for (const idx of indexes) {
|
|
159
|
+
for (const field of idx.fields) {
|
|
160
|
+
if (!schemaFields.has(field)) {
|
|
161
|
+
badIndexes.push({
|
|
162
|
+
field,
|
|
163
|
+
indexType: idx.type,
|
|
164
|
+
table: parsed.name,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return badIndexes;
|
|
171
|
+
}
|
|
172
|
+
function extractSchemaFields(content) {
|
|
173
|
+
// id and created_at are auto-added during import
|
|
174
|
+
const fields = new Set(['id', 'created_at']);
|
|
175
|
+
// Find the schema block by matching braces
|
|
176
|
+
const schemaStart = content.match(/\bschema\s*\{/);
|
|
177
|
+
if (!schemaStart || schemaStart.index === undefined)
|
|
178
|
+
return fields;
|
|
179
|
+
let depth = 0;
|
|
180
|
+
let blockStart = -1;
|
|
181
|
+
let blockEnd = -1;
|
|
182
|
+
for (let i = schemaStart.index; i < content.length; i++) {
|
|
183
|
+
if (content[i] === '{') {
|
|
184
|
+
if (depth === 0)
|
|
185
|
+
blockStart = i + 1;
|
|
186
|
+
depth++;
|
|
187
|
+
}
|
|
188
|
+
else if (content[i] === '}') {
|
|
189
|
+
depth--;
|
|
190
|
+
if (depth === 0) {
|
|
191
|
+
blockEnd = i;
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (blockStart < 0 || blockEnd < 0)
|
|
197
|
+
return fields;
|
|
198
|
+
const schemaBlock = content.slice(blockStart, blockEnd);
|
|
199
|
+
// Match field declarations: "type name" or "type name?" or "type name?=default"
|
|
200
|
+
const fieldRegex = /^\s*\w+\s+(\w+)[?\s{]/gm;
|
|
201
|
+
let match;
|
|
202
|
+
while ((match = fieldRegex.exec(schemaBlock)) !== null) {
|
|
203
|
+
fields.add(match[1]);
|
|
204
|
+
}
|
|
205
|
+
return fields;
|
|
206
|
+
}
|
|
207
|
+
function extractIndexes(content) {
|
|
208
|
+
const indexes = [];
|
|
209
|
+
// Match the index array: index = [ ... ]
|
|
210
|
+
const indexMatch = content.match(/\bindex\s*=\s*\[([\s\S]*?)\n\s*\]/);
|
|
211
|
+
if (!indexMatch)
|
|
212
|
+
return indexes;
|
|
213
|
+
const indexBlock = indexMatch[1];
|
|
214
|
+
// Match each index object: {type: "btree", field: [{name: "col", op: "desc"}]}
|
|
215
|
+
const entryRegex = /\{([^}]+)\}/g;
|
|
216
|
+
let match;
|
|
217
|
+
while ((match = entryRegex.exec(indexBlock)) !== null) {
|
|
218
|
+
const entry = match[1];
|
|
219
|
+
const typeMatch = entry.match(/type:\s*"(\w+)"/);
|
|
220
|
+
const type = typeMatch ? typeMatch[1] : 'unknown';
|
|
221
|
+
const fieldNames = [];
|
|
222
|
+
const nameRegex = /name:\s*"(\w*)"/g;
|
|
223
|
+
let nameMatch;
|
|
224
|
+
while ((nameMatch = nameRegex.exec(entry)) !== null) {
|
|
225
|
+
fieldNames.push(nameMatch[1]);
|
|
226
|
+
}
|
|
227
|
+
if (fieldNames.length > 0) {
|
|
228
|
+
indexes.push({ fields: fieldNames, type });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return indexes;
|
|
232
|
+
}
|